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,
\r
6 * Massachusetts. Enhancements Copyright
\r
7 * 1992-2001,2002,2003,2004,2005,2006,2007,2008,2009 Free Software
\r
10 * XBoard borrows its colors and the bitmaps.xchess bitmap set from XChess,
\r
11 * which was written and is copyrighted by Wayne Christopher.
\r
13 * The following terms apply to Digital Equipment Corporation's copyright
\r
14 * interest in XBoard:
\r
15 * ------------------------------------------------------------------------
\r
16 * All Rights Reserved
\r
18 * Permission to use, copy, modify, and distribute this software and its
\r
19 * documentation for any purpose and without fee is hereby granted,
\r
20 * provided that the above copyright notice appear in all copies and that
\r
21 * both that copyright notice and this permission notice appear in
\r
22 * supporting documentation, and that the name of Digital not be
\r
23 * used in advertising or publicity pertaining to distribution of the
\r
24 * software without specific, written prior permission.
\r
26 * DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
\r
27 * ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
\r
28 * DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
\r
29 * ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
\r
30 * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
\r
31 * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
\r
33 * ------------------------------------------------------------------------
\r
35 * The following terms apply to the enhanced version of XBoard
\r
36 * distributed by the Free Software Foundation:
\r
37 * ------------------------------------------------------------------------
\r
39 * GNU XBoard is free software: you can redistribute it and/or modify
\r
40 * it under the terms of the GNU General Public License as published by
\r
41 * the Free Software Foundation, either version 3 of the License, or (at
\r
42 * your option) any later version.
\r
44 * GNU XBoard is distributed in the hope that it will be useful, but
\r
45 * WITHOUT ANY WARRANTY; without even the implied warranty of
\r
46 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
\r
47 * General Public License for more details.
\r
49 * You should have received a copy of the GNU General Public License
\r
50 * along with this program. If not, see http://www.gnu.org/licenses/. *
\r
52 *------------------------------------------------------------------------
\r
53 ** See the file ChangeLog for a revision history. */
\r
57 #include <windows.h>
\r
58 #include <winuser.h>
\r
59 #include <winsock.h>
\r
60 #include <commctrl.h>
\r
66 #include <sys/stat.h>
\r
69 #include <commdlg.h>
\r
71 #include <richedit.h>
\r
72 #include <mmsystem.h>
\r
81 #include "winboard.h"
\r
82 #include "frontend.h"
\r
83 #include "backend.h"
\r
85 #include "wclipbrd.h"
\r
86 #include "wgamelist.h"
\r
87 #include "wedittags.h"
\r
88 #include "woptions.h"
\r
89 #include "wsockerr.h"
\r
90 #include "defaults.h"
\r
94 //void InitEngineUCI( const char * iniDir, ChessProgramState * cps );
\r
97 void mysrandom(unsigned int seed);
\r
99 extern int whiteFlag, blackFlag;
\r
100 Boolean flipClock = FALSE;
\r
102 void DisplayHoldingsCount(HDC hdc, int x, int y, int align, int copyNumber);
\r
103 VOID NewVariantPopup(HWND hwnd);
\r
104 int FinishMove P((ChessMove moveType, int fromX, int fromY, int toX, int toY,
\r
105 /*char*/int promoChar));
\r
106 void AnimateAtomicCapture(int fromX, int fromY, int toX, int toY, int nFrames);
\r
107 void DisplayMove P((int moveNumber));
\r
108 Boolean ParseFEN P((Board board, int *blackPlaysFirst, char *fen));
\r
110 #include "htmlhelp.h"
\r
112 HWND WINAPI HtmlHelp( HWND hwnd, LPCSTR helpFile, UINT action, DWORD_PTR data );
\r
116 ChessSquare piece;
\r
117 POINT pos; /* window coordinates of current pos */
\r
118 POINT lastpos; /* window coordinates of last pos - used for clipping */
\r
119 POINT from; /* board coordinates of the piece's orig pos */
\r
120 POINT to; /* board coordinates of the piece's new pos */
\r
123 static AnimInfo animInfo = { EmptySquare, {-1,-1}, {-1,-1}, {-1,-1} };
\r
126 POINT start; /* window coordinates of start pos */
\r
127 POINT pos; /* window coordinates of current pos */
\r
128 POINT lastpos; /* window coordinates of last pos - used for clipping */
\r
129 POINT from; /* board coordinates of the piece's orig pos */
\r
132 static DragInfo dragInfo = { {-1,-1}, {-1,-1}, {-1,-1}, {-1,-1} };
\r
135 POINT sq[2]; /* board coordinates of from, to squares */
\r
138 static HighlightInfo highlightInfo = { {{-1, -1}, {-1, -1}} };
\r
139 static HighlightInfo premoveHighlightInfo = { {{-1, -1}, {-1, -1}} };
\r
141 typedef struct { // [HGM] atomic
\r
142 int fromX, fromY, toX, toY, radius;
\r
145 static ExplodeInfo explodeInfo;
\r
147 /* Window class names */
\r
148 char szAppName[] = "WinBoard";
\r
149 char szConsoleName[] = "WBConsole";
\r
151 /* Title bar text */
\r
152 char szTitle[] = "WinBoard";
\r
153 char szConsoleTitle[] = "I C S Interaction";
\r
156 char *settingsFileName;
\r
157 BOOLEAN saveSettingsOnExit;
\r
158 char installDir[MSG_SIZ];
\r
160 BoardSize boardSize;
\r
161 BOOLEAN chessProgram;
\r
162 static int boardX, boardY;
\r
163 int minX, minY; // [HGM] placement: volatile limits on upper-left corner
\r
164 static int squareSize, lineGap, minorSize;
\r
165 static int winWidth, winHeight, winW, winH;
\r
166 static RECT messageRect, whiteRect, blackRect, leftLogoRect, rightLogoRect; // [HGM] logo
\r
167 static int logoHeight = 0;
\r
168 static char messageText[MESSAGE_TEXT_MAX];
\r
169 static int clockTimerEvent = 0;
\r
170 static int loadGameTimerEvent = 0;
\r
171 static int analysisTimerEvent = 0;
\r
172 static DelayedEventCallback delayedTimerCallback;
\r
173 static int delayedTimerEvent = 0;
\r
174 static int buttonCount = 2;
\r
175 char *icsTextMenuString;
\r
177 char *firstChessProgramNames;
\r
178 char *secondChessProgramNames;
\r
180 #define ARG_MAX 128*1024 /* [AS] For Roger Brown's very long list! */
\r
182 #define PALETTESIZE 256
\r
184 HINSTANCE hInst; /* current instance */
\r
185 HWND hwndMain = NULL; /* root window*/
\r
186 HWND hwndConsole = NULL;
\r
187 BOOLEAN alwaysOnTop = FALSE;
\r
189 COLORREF lightSquareColor, darkSquareColor, whitePieceColor,
\r
190 blackPieceColor, highlightSquareColor, premoveHighlightColor;
\r
192 ColorClass currentColorClass;
\r
194 HWND hCommPort = NULL; /* currently open comm port */
\r
195 static HWND hwndPause; /* pause button */
\r
196 static HBITMAP pieceBitmap[3][(int) BlackPawn]; /* [HGM] nr of bitmaps referred to bP in stead of wK */
\r
197 static HBRUSH lightSquareBrush, darkSquareBrush,
\r
198 blackSquareBrush, /* [HGM] for band between board and holdings */
\r
199 explodeBrush, /* [HGM] atomic */
\r
200 whitePieceBrush, blackPieceBrush, iconBkgndBrush /*, outlineBrush*/;
\r
201 static POINT gridEndpoints[(BOARD_SIZE + 1) * 4];
\r
202 static DWORD gridVertexCounts[(BOARD_SIZE + 1) * 2];
\r
203 static HPEN gridPen = NULL;
\r
204 static HPEN highlightPen = NULL;
\r
205 static HPEN premovePen = NULL;
\r
206 static NPLOGPALETTE pLogPal;
\r
207 static BOOL paletteChanged = FALSE;
\r
208 static HICON iconWhite, iconBlack, iconCurrent;
\r
209 static int doingSizing = FALSE;
\r
210 static int lastSizing = 0;
\r
211 static int prevStderrPort;
\r
212 static HBITMAP userLogo;
\r
214 /* [AS] Support for background textures */
\r
215 #define BACK_TEXTURE_MODE_DISABLED 0
\r
216 #define BACK_TEXTURE_MODE_PLAIN 1
\r
217 #define BACK_TEXTURE_MODE_FULL_RANDOM 2
\r
219 static HBITMAP liteBackTexture = NULL;
\r
220 static HBITMAP darkBackTexture = NULL;
\r
221 static int liteBackTextureMode = BACK_TEXTURE_MODE_PLAIN;
\r
222 static int darkBackTextureMode = BACK_TEXTURE_MODE_PLAIN;
\r
223 static int backTextureSquareSize = 0;
\r
224 static struct { int x; int y; int mode; } backTextureSquareInfo[BOARD_SIZE][BOARD_SIZE];
\r
226 #if __GNUC__ && !defined(_winmajor)
\r
227 #define oldDialog 0 /* cygwin doesn't define _winmajor; mingw does */
\r
229 #define oldDialog (_winmajor < 4)
\r
232 char *defaultTextAttribs[] =
\r
234 COLOR_SHOUT, COLOR_SSHOUT, COLOR_CHANNEL1, COLOR_CHANNEL, COLOR_KIBITZ,
\r
235 COLOR_TELL, COLOR_CHALLENGE, COLOR_REQUEST, COLOR_SEEK, COLOR_NORMAL,
\r
245 int cliWidth, cliHeight;
\r
248 SizeInfo sizeInfo[] =
\r
250 { "tiny", 21, 0, 1, 1, 0, 0 },
\r
251 { "teeny", 25, 1, 1, 1, 0, 0 },
\r
252 { "dinky", 29, 1, 1, 1, 0, 0 },
\r
253 { "petite", 33, 1, 1, 1, 0, 0 },
\r
254 { "slim", 37, 2, 1, 0, 0, 0 },
\r
255 { "small", 40, 2, 1, 0, 0, 0 },
\r
256 { "mediocre", 45, 2, 1, 0, 0, 0 },
\r
257 { "middling", 49, 2, 0, 0, 0, 0 },
\r
258 { "average", 54, 2, 0, 0, 0, 0 },
\r
259 { "moderate", 58, 3, 0, 0, 0, 0 },
\r
260 { "medium", 64, 3, 0, 0, 0, 0 },
\r
261 { "bulky", 72, 3, 0, 0, 0, 0 },
\r
262 { "large", 80, 3, 0, 0, 0, 0 },
\r
263 { "big", 87, 3, 0, 0, 0, 0 },
\r
264 { "huge", 95, 3, 0, 0, 0, 0 },
\r
265 { "giant", 108, 3, 0, 0, 0, 0 },
\r
266 { "colossal", 116, 4, 0, 0, 0, 0 },
\r
267 { "titanic", 129, 4, 0, 0, 0, 0 },
\r
268 { NULL, 0, 0, 0, 0, 0, 0 }
\r
271 #define MF(x) {x, {{0,}, 0. }, {0, }, 0}
\r
272 MyFont fontRec[NUM_SIZES][NUM_FONTS] =
\r
274 { 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
275 { 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
276 { 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
277 { 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
278 { 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
279 { 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
280 { 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
281 { 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
282 { 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
283 { 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
284 { 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
285 { 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
286 { 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
287 { 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
288 { 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
289 { 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
290 { 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
291 { 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
294 MyFont *font[NUM_SIZES][NUM_FONTS];
\r
303 #define BUTTON_WIDTH (tinyLayout ? 16 : 32)
\r
304 #define N_BUTTONS 5
\r
306 MyButtonDesc buttonDesc[N_BUTTONS] =
\r
308 {"<<", IDM_ToStart, NULL, NULL},
\r
309 {"<", IDM_Backward, NULL, NULL},
\r
310 {"P", IDM_Pause, NULL, NULL},
\r
311 {">", IDM_Forward, NULL, NULL},
\r
312 {">>", IDM_ToEnd, NULL, NULL},
\r
315 int tinyLayout = 0, smallLayout = 0;
\r
316 #define MENU_BAR_ITEMS 6
\r
317 char *menuBarText[2][MENU_BAR_ITEMS+1] = {
\r
318 { "&File", "&Mode", "&Action", "&Step", "&Options", "&Help", NULL },
\r
319 { "&F", "&M", "&A", "&S", "&O", "&H", NULL },
\r
323 MySound sounds[(int)NSoundClasses];
\r
324 MyTextAttribs textAttribs[(int)NColorClasses];
\r
326 MyColorizeAttribs colorizeAttribs[] = {
\r
327 { (COLORREF)0, 0, "Shout Text" },
\r
328 { (COLORREF)0, 0, "SShout/CShout" },
\r
329 { (COLORREF)0, 0, "Channel 1 Text" },
\r
330 { (COLORREF)0, 0, "Channel Text" },
\r
331 { (COLORREF)0, 0, "Kibitz Text" },
\r
332 { (COLORREF)0, 0, "Tell Text" },
\r
333 { (COLORREF)0, 0, "Challenge Text" },
\r
334 { (COLORREF)0, 0, "Request Text" },
\r
335 { (COLORREF)0, 0, "Seek Text" },
\r
336 { (COLORREF)0, 0, "Normal Text" },
\r
337 { (COLORREF)0, 0, "None" }
\r
342 static char *commentTitle;
\r
343 static char *commentText;
\r
344 static int commentIndex;
\r
345 static Boolean editComment = FALSE;
\r
346 HWND commentDialog = NULL;
\r
347 BOOLEAN commentDialogUp = FALSE;
\r
348 static int commentX, commentY, commentH, commentW;
\r
350 static char *analysisTitle;
\r
351 static char *analysisText;
\r
352 HWND analysisDialog = NULL;
\r
353 BOOLEAN analysisDialogUp = FALSE;
\r
354 static int analysisX, analysisY, analysisH, analysisW;
\r
356 char errorTitle[MSG_SIZ];
\r
357 char errorMessage[2*MSG_SIZ];
\r
358 HWND errorDialog = NULL;
\r
359 BOOLEAN moveErrorMessageUp = FALSE;
\r
360 BOOLEAN consoleEcho = TRUE;
\r
361 CHARFORMAT consoleCF;
\r
362 COLORREF consoleBackgroundColor;
\r
364 char *programVersion;
\r
370 typedef int CPKind;
\r
379 SOCKET sock2; /* stderr socket for OpenRcmd */
\r
382 #define INPUT_SOURCE_BUF_SIZE 4096
\r
384 typedef struct _InputSource {
\r
391 char buf[INPUT_SOURCE_BUF_SIZE];
\r
395 InputCallback func;
\r
396 struct _InputSource *second; /* for stderr thread on CPRcmd */
\r
400 InputSource *consoleInputSource;
\r
405 VOID ConsoleOutput(char* data, int length, int forceVisible);
\r
406 VOID ConsoleCreate();
\r
408 ConsoleWndProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);
\r
409 VOID ColorizeTextPopup(HWND hwnd, ColorClass cc);
\r
410 VOID PrintCommSettings(FILE *f, char *name, DCB *dcb);
\r
411 VOID ParseCommSettings(char *arg, DCB *dcb);
\r
413 StartupDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);
\r
414 VOID APIENTRY MenuPopup(HWND hwnd, POINT pt, HMENU hmenu, UINT def);
\r
415 void ParseIcsTextMenu(char *icsTextMenuString);
\r
416 VOID PopUpMoveDialog(char firstchar);
\r
417 VOID PopUpNameDialog(char firstchar);
\r
418 VOID UpdateSampleText(HWND hDlg, int id, MyColorizeAttribs *mca);
\r
422 int GameListOptions();
\r
424 HWND moveHistoryDialog = NULL;
\r
425 BOOLEAN moveHistoryDialogUp = FALSE;
\r
427 WindowPlacement wpMoveHistory;
\r
429 HWND evalGraphDialog = NULL;
\r
430 BOOLEAN evalGraphDialogUp = FALSE;
\r
432 WindowPlacement wpEvalGraph;
\r
434 HWND engineOutputDialog = NULL;
\r
435 BOOLEAN engineOutputDialogUp = FALSE;
\r
437 WindowPlacement wpEngineOutput;
\r
438 WindowPlacement wpGameList;
\r
439 WindowPlacement wpConsole;
\r
441 VOID MoveHistoryPopUp();
\r
442 VOID MoveHistoryPopDown();
\r
443 VOID MoveHistorySet( char movelist[][2*MOVE_LEN], int first, int last, int current, ChessProgramStats_Move * pvInfo );
\r
444 BOOL MoveHistoryIsUp();
\r
446 VOID EvalGraphSet( int first, int last, int current, ChessProgramStats_Move * pvInfo );
\r
447 VOID EvalGraphPopUp();
\r
448 VOID EvalGraphPopDown();
\r
449 BOOL EvalGraphIsUp();
\r
451 VOID EngineOutputPopUp();
\r
452 VOID EngineOutputPopDown();
\r
453 BOOL EngineOutputIsUp();
\r
454 VOID EngineOutputUpdate( FrontEndProgramStats * stats );
\r
456 VOID GothicPopUp(char *title, VariantClass variant);
\r
458 * Setting "frozen" should disable all user input other than deleting
\r
459 * the window. We do this while engines are initializing themselves.
\r
461 static int frozen = 0;
\r
462 static int oldMenuItemState[MENU_BAR_ITEMS];
\r
468 if (frozen) return;
\r
470 hmenu = GetMenu(hwndMain);
\r
471 for (i=0; i<MENU_BAR_ITEMS; i++) {
\r
472 oldMenuItemState[i] = EnableMenuItem(hmenu, i, MF_BYPOSITION|MF_GRAYED);
\r
474 DrawMenuBar(hwndMain);
\r
477 /* Undo a FreezeUI */
\r
483 if (!frozen) return;
\r
485 hmenu = GetMenu(hwndMain);
\r
486 for (i=0; i<MENU_BAR_ITEMS; i++) {
\r
487 EnableMenuItem(hmenu, i, MF_BYPOSITION|oldMenuItemState[i]);
\r
489 DrawMenuBar(hwndMain);
\r
492 static int fromX = -1, fromY = -1, toX, toY; // [HGM] moved upstream, so JAWS can use them
\r
494 /* JAWS preparation patch (WinBoard for the sight impaired). Define required insertions as empty */
\r
499 #define JAWS_ALT_INTERCEPT
\r
500 #define JAWS_KB_NAVIGATION
\r
501 #define JAWS_MENU_ITEMS
\r
502 #define JAWS_SILENCE
\r
503 #define JAWS_REPLAY
\r
504 #define JAWS_DELETE(X) X
\r
505 #define SAYMACHINEMOVE()
\r
509 /*---------------------------------------------------------------------------*\
\r
513 \*---------------------------------------------------------------------------*/
\r
516 WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
\r
517 LPSTR lpCmdLine, int nCmdShow)
\r
520 HANDLE hAccelMain, hAccelNoAlt, hAccelNoICS;
\r
521 // INITCOMMONCONTROLSEX ex;
\r
525 LoadLibrary("RICHED32.DLL");
\r
526 consoleCF.cbSize = sizeof(CHARFORMAT);
\r
528 if (!InitApplication(hInstance)) {
\r
531 if (!InitInstance(hInstance, nCmdShow, lpCmdLine)) {
\r
537 // InitCommonControlsEx(&ex);
\r
538 InitCommonControls();
\r
540 hAccelMain = LoadAccelerators (hInstance, szAppName);
\r
541 hAccelNoAlt = LoadAccelerators (hInstance, "NO_ALT");
\r
542 hAccelNoICS = LoadAccelerators( hInstance, "NO_ICS"); /* [AS] No Ctrl-V on ICS!!! */
\r
544 /* Acquire and dispatch messages until a WM_QUIT message is received. */
\r
546 while (GetMessage(&msg, /* message structure */
\r
547 NULL, /* handle of window receiving the message */
\r
548 0, /* lowest message to examine */
\r
549 0)) /* highest message to examine */
\r
552 if(msg.message == WM_CHAR && msg.wParam == '\t') {
\r
553 // [HGM] navigate: switch between all windows with tab
\r
554 HWND e1 = NULL, e2 = NULL, mh = NULL, hInput = NULL, hText = NULL;
\r
555 int i, currentElement = 0;
\r
557 // first determine what element of the chain we come from (if any)
\r
558 if(appData.icsActive) {
\r
559 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
560 hText = GetDlgItem(hwndConsole, OPT_ConsoleText);
\r
562 if(engineOutputDialog && EngineOutputIsUp()) {
\r
563 e1 = GetDlgItem(engineOutputDialog, IDC_EngineMemo1);
\r
564 e2 = GetDlgItem(engineOutputDialog, IDC_EngineMemo2);
\r
566 if(moveHistoryDialog && MoveHistoryIsUp()) {
\r
567 mh = GetDlgItem(moveHistoryDialog, IDC_MoveHistory);
\r
569 if(msg.hwnd == hwndMain) currentElement = 7 ; else
\r
570 if(msg.hwnd == engineOutputDialog) currentElement = 2; else
\r
571 if(msg.hwnd == e1) currentElement = 2; else
\r
572 if(msg.hwnd == e2) currentElement = 3; else
\r
573 if(msg.hwnd == moveHistoryDialog) currentElement = 4; else
\r
574 if(msg.hwnd == mh) currentElement = 4; else
\r
575 if(msg.hwnd == evalGraphDialog) currentElement = 7; else
\r
576 if(msg.hwnd == hText) currentElement = 5; else
\r
577 if(msg.hwnd == hInput) currentElement = 6; else
\r
578 for (i = 0; i < N_BUTTONS; i++) {
\r
579 if (buttonDesc[i].hwnd == msg.hwnd) { currentElement = 1; break; }
\r
582 // determine where to go to
\r
583 if(currentElement) { HWND h = NULL; int direction = GetKeyState(VK_SHIFT) < 0 ? -1 : 1;
\r
585 currentElement = (currentElement + direction) % 7;
\r
586 switch(currentElement) {
\r
588 h = hwndMain; break; // passing this case always makes the loop exit
\r
590 h = buttonDesc[0].hwnd; break; // could be NULL
\r
592 if(!EngineOutputIsUp()) continue; // skip closed auxiliary windows
\r
595 if(!EngineOutputIsUp()) continue;
\r
598 if(!MoveHistoryIsUp()) continue;
\r
600 // case 5: // input to eval graph does not seem to get here!
\r
601 // if(!EvalGraphIsUp()) continue;
\r
602 // h = evalGraphDialog; break;
\r
604 if(!appData.icsActive) continue;
\r
608 if(!appData.icsActive) continue;
\r
614 if(currentElement > 4 && IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
615 if(currentElement < 5 && IsIconic(hwndMain)) ShowWindow(hwndMain, SW_RESTORE); // all open together
\r
618 continue; // this message now has been processed
\r
622 if (!(commentDialog && IsDialogMessage(commentDialog, &msg)) &&
\r
623 !(moveHistoryDialog && IsDialogMessage(moveHistoryDialog, &msg)) &&
\r
624 !(evalGraphDialog && IsDialogMessage(evalGraphDialog, &msg)) &&
\r
625 !(engineOutputDialog && IsDialogMessage(engineOutputDialog, &msg)) &&
\r
626 !(editTagsDialog && IsDialogMessage(editTagsDialog, &msg)) &&
\r
627 !(gameListDialog && IsDialogMessage(gameListDialog, &msg)) &&
\r
628 !(errorDialog && IsDialogMessage(errorDialog, &msg)) &&
\r
629 !(!frozen && TranslateAccelerator(hwndMain, hAccelMain, &msg)) &&
\r
630 !(!hwndConsole && TranslateAccelerator(hwndMain, hAccelNoICS, &msg)) &&
\r
631 !(!hwndConsole && TranslateAccelerator(hwndMain, hAccelNoAlt, &msg))) {
\r
632 TranslateMessage(&msg); /* Translates virtual key codes */
\r
633 DispatchMessage(&msg); /* Dispatches message to window */
\r
638 return (msg.wParam); /* Returns the value from PostQuitMessage */
\r
641 /*---------------------------------------------------------------------------*\
\r
643 * Initialization functions
\r
645 \*---------------------------------------------------------------------------*/
\r
649 { // update user logo if necessary
\r
650 static char oldUserName[MSG_SIZ], *curName;
\r
652 if(appData.autoLogo) {
\r
653 curName = UserName();
\r
654 if(strcmp(curName, oldUserName)) {
\r
655 sprintf(oldUserName, "logos\\%s.bmp", curName);
\r
656 userLogo = LoadImage( 0, oldUserName, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
657 strcpy(oldUserName, curName);
\r
663 InitApplication(HINSTANCE hInstance)
\r
667 /* Fill in window class structure with parameters that describe the */
\r
670 wc.style = CS_HREDRAW | CS_VREDRAW; /* Class style(s). */
\r
671 wc.lpfnWndProc = (WNDPROC)WndProc; /* Window Procedure */
\r
672 wc.cbClsExtra = 0; /* No per-class extra data. */
\r
673 wc.cbWndExtra = 0; /* No per-window extra data. */
\r
674 wc.hInstance = hInstance; /* Owner of this class */
\r
675 wc.hIcon = LoadIcon(hInstance, "icon_white");
\r
676 wc.hCursor = LoadCursor(NULL, IDC_ARROW); /* Cursor */
\r
677 wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1); /* Default color */
\r
678 wc.lpszMenuName = szAppName; /* Menu name from .RC */
\r
679 wc.lpszClassName = szAppName; /* Name to register as */
\r
681 /* Register the window class and return success/failure code. */
\r
682 if (!RegisterClass(&wc)) return FALSE;
\r
684 wc.style = CS_HREDRAW | CS_VREDRAW;
\r
685 wc.lpfnWndProc = (WNDPROC)ConsoleWndProc;
\r
687 wc.cbWndExtra = DLGWINDOWEXTRA;
\r
688 wc.hInstance = hInstance;
\r
689 wc.hIcon = LoadIcon(hInstance, "icon_white");
\r
690 wc.hCursor = LoadCursor(NULL, IDC_ARROW);
\r
691 wc.hbrBackground = (HBRUSH)(COLOR_MENU+1);
\r
692 wc.lpszMenuName = NULL;
\r
693 wc.lpszClassName = szConsoleName;
\r
695 if (!RegisterClass(&wc)) return FALSE;
\r
700 /* Set by InitInstance, used by EnsureOnScreen */
\r
701 int screenHeight, screenWidth;
\r
704 EnsureOnScreen(int *x, int *y, int minX, int minY)
\r
706 // int gap = GetSystemMetrics(SM_CYFRAME) + GetSystemMetrics(SM_CYCAPTION);
\r
707 /* Be sure window at (x,y) is not off screen (or even mostly off screen) */
\r
708 if (*x > screenWidth - 32) *x = 0;
\r
709 if (*y > screenHeight - 32) *y = 0;
\r
710 if (*x < minX) *x = minX;
\r
711 if (*y < minY) *y = minY;
\r
715 InitInstance(HINSTANCE hInstance, int nCmdShow, LPSTR lpCmdLine)
\r
717 HWND hwnd; /* Main window handle. */
\r
719 WINDOWPLACEMENT wp;
\r
722 hInst = hInstance; /* Store instance handle in our global variable */
\r
724 if (SearchPath(NULL, "WinBoard.exe", NULL, MSG_SIZ, installDir, &filepart)) {
\r
725 *filepart = NULLCHAR;
\r
727 GetCurrentDirectory(MSG_SIZ, installDir);
\r
729 gameInfo.boardWidth = gameInfo.boardHeight = 8; // [HGM] won't have open window otherwise
\r
730 screenWidth = screenHeight = 1000; // [HGM] placement: kludge to allow calling EnsureOnScreen from InitAppData
\r
731 InitAppData(lpCmdLine); /* Get run-time parameters */
\r
732 if (appData.debugMode) {
\r
733 debugFP = fopen(appData.nameOfDebugFile, "w");
\r
734 setbuf(debugFP, NULL);
\r
739 // InitEngineUCI( installDir, &first ); // [HGM] incorporated in InitBackEnd1()
\r
740 // InitEngineUCI( installDir, &second );
\r
742 /* Create a main window for this application instance. */
\r
743 hwnd = CreateWindow(szAppName, szTitle,
\r
744 (WS_OVERLAPPEDWINDOW & ~WS_MAXIMIZEBOX),
\r
745 CW_USEDEFAULT, 0, CW_USEDEFAULT, 0,
\r
746 NULL, NULL, hInstance, NULL);
\r
749 /* If window could not be created, return "failure" */
\r
754 /* [HGM] logo: Load logos if specified (must be done before InitDrawingSizes) */
\r
755 if( appData.firstLogo && appData.firstLogo[0] != NULLCHAR) {
\r
756 first.programLogo = LoadImage( 0, appData.firstLogo, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
758 if (first.programLogo == NULL && appData.debugMode) {
\r
759 fprintf( debugFP, "Unable to load logo bitmap '%s'\n", appData.firstLogo );
\r
761 } else if(appData.autoLogo) {
\r
762 if(appData.firstDirectory && appData.firstDirectory[0]) {
\r
764 sprintf(buf, "%s/logo.bmp", appData.firstDirectory);
\r
765 first.programLogo = LoadImage( 0, buf, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
769 if( appData.secondLogo && appData.secondLogo[0] != NULLCHAR) {
\r
770 second.programLogo = LoadImage( 0, appData.secondLogo, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
772 if (second.programLogo == NULL && appData.debugMode) {
\r
773 fprintf( debugFP, "Unable to load logo bitmap '%s'\n", appData.secondLogo );
\r
775 } else if(appData.autoLogo) {
\r
777 if(appData.icsActive) { // [HGM] logo: in ICS mode second can be used for ICS
\r
778 sprintf(buf, "logos\\%s.bmp", appData.icsHost);
\r
779 second.programLogo = LoadImage( 0, buf, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
781 if(appData.secondDirectory && appData.secondDirectory[0]) {
\r
782 sprintf(buf, "%s\\logo.bmp", appData.secondDirectory);
\r
783 second.programLogo = LoadImage( 0, buf, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
789 iconWhite = LoadIcon(hInstance, "icon_white");
\r
790 iconBlack = LoadIcon(hInstance, "icon_black");
\r
791 iconCurrent = iconWhite;
\r
792 InitDrawingColors();
\r
793 screenHeight = GetSystemMetrics(SM_CYSCREEN);
\r
794 screenWidth = GetSystemMetrics(SM_CXSCREEN);
\r
795 for (ibs = (int) NUM_SIZES - 1; ibs >= 0; ibs--) {
\r
796 /* Compute window size for each board size, and use the largest
\r
797 size that fits on this screen as the default. */
\r
798 InitDrawingSizes((BoardSize)(ibs+1000), 0);
\r
799 if (boardSize == (BoardSize)-1 &&
\r
800 winH <= screenHeight
\r
801 - GetSystemMetrics(SM_CYFRAME) - GetSystemMetrics(SM_CYCAPTION) - 10
\r
802 && winW <= screenWidth) {
\r
803 boardSize = (BoardSize)ibs;
\r
807 InitDrawingSizes(boardSize, 0);
\r
809 buttonCount = GetSystemMetrics(SM_CMOUSEBUTTONS);
\r
811 /* [AS] Load textures if specified */
\r
812 ZeroMemory( &backTextureSquareInfo, sizeof(backTextureSquareInfo) );
\r
814 if( appData.liteBackTextureFile && appData.liteBackTextureFile[0] != NULLCHAR && appData.liteBackTextureFile[0] != '*' ) {
\r
815 liteBackTexture = LoadImage( 0, appData.liteBackTextureFile, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
816 liteBackTextureMode = appData.liteBackTextureMode;
\r
818 if (liteBackTexture == NULL && appData.debugMode) {
\r
819 fprintf( debugFP, "Unable to load lite texture bitmap '%s'\n", appData.liteBackTextureFile );
\r
823 if( appData.darkBackTextureFile && appData.darkBackTextureFile[0] != NULLCHAR && appData.darkBackTextureFile[0] != '*' ) {
\r
824 darkBackTexture = LoadImage( 0, appData.darkBackTextureFile, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
825 darkBackTextureMode = appData.darkBackTextureMode;
\r
827 if (darkBackTexture == NULL && appData.debugMode) {
\r
828 fprintf( debugFP, "Unable to load dark texture bitmap '%s'\n", appData.darkBackTextureFile );
\r
832 mysrandom( (unsigned) time(NULL) );
\r
834 /* [AS] Restore layout */
\r
835 if( wpMoveHistory.visible ) {
\r
836 MoveHistoryPopUp();
\r
839 if( wpEvalGraph.visible ) {
\r
843 if( wpEngineOutput.visible ) {
\r
844 EngineOutputPopUp();
\r
849 /* Make the window visible; update its client area; and return "success" */
\r
850 EnsureOnScreen(&boardX, &boardY, minX, minY);
\r
851 wp.length = sizeof(WINDOWPLACEMENT);
\r
853 wp.showCmd = nCmdShow;
\r
854 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
855 wp.rcNormalPosition.left = boardX;
\r
856 wp.rcNormalPosition.right = boardX + winWidth;
\r
857 wp.rcNormalPosition.top = boardY;
\r
858 wp.rcNormalPosition.bottom = boardY + winHeight;
\r
859 SetWindowPlacement(hwndMain, &wp);
\r
861 SetWindowPos(hwndMain, alwaysOnTop ? HWND_TOPMOST : HWND_NOTOPMOST,
\r
862 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE);
\r
866 SetWindowPos(hwndConsole, alwaysOnTop ? HWND_TOPMOST : HWND_NOTOPMOST,
\r
867 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE);
\r
869 ShowWindow(hwndConsole, nCmdShow);
\r
871 UpdateWindow(hwnd);
\r
879 ArgString, ArgInt, ArgFloat, ArgBoolean, ArgTrue, ArgFalse, ArgNone,
\r
880 ArgColor, ArgAttribs, ArgFilename, ArgBoardSize, ArgFont, ArgCommSettings,
\r
881 ArgSettingsFilename,
\r
882 ArgX, ArgY, ArgZ // [HGM] placement: for window-placement options stored relative to main window
\r
890 String *pString; // ArgString
\r
891 int *pInt; // ArgInt
\r
892 float *pFloat; // ArgFloat
\r
893 Boolean *pBoolean; // ArgBoolean
\r
894 COLORREF *pColor; // ArgColor
\r
895 ColorClass cc; // ArgAttribs
\r
896 String *pFilename; // ArgFilename
\r
897 BoardSize *pBoardSize; // ArgBoardSize
\r
898 int whichFont; // ArgFont
\r
899 DCB *pDCB; // ArgCommSettings
\r
900 String *pFilename; // ArgSettingsFilename
\r
908 ArgDescriptor argDescriptors[] = {
\r
909 /* positional arguments */
\r
910 { "loadGameFile", ArgFilename, (LPVOID) &appData.loadGameFile, FALSE },
\r
911 { "", ArgNone, NULL },
\r
912 /* keyword arguments */
\r
913 { "whitePieceColor", ArgColor, (LPVOID) &whitePieceColor, TRUE },
\r
914 { "wpc", ArgColor, (LPVOID) &whitePieceColor, FALSE },
\r
915 { "blackPieceColor", ArgColor, (LPVOID) &blackPieceColor, TRUE },
\r
916 { "bpc", ArgColor, (LPVOID) &blackPieceColor, FALSE },
\r
917 { "lightSquareColor", ArgColor, (LPVOID) &lightSquareColor, TRUE },
\r
918 { "lsc", ArgColor, (LPVOID) &lightSquareColor, FALSE },
\r
919 { "darkSquareColor", ArgColor, (LPVOID) &darkSquareColor, TRUE },
\r
920 { "dsc", ArgColor, (LPVOID) &darkSquareColor, FALSE },
\r
921 { "highlightSquareColor", ArgColor, (LPVOID) &highlightSquareColor, TRUE },
\r
922 { "hsc", ArgColor, (LPVOID) &highlightSquareColor, FALSE },
\r
923 { "premoveHighlightColor", ArgColor, (LPVOID) &premoveHighlightColor, TRUE },
\r
924 { "phc", ArgColor, (LPVOID) &premoveHighlightColor, FALSE },
\r
925 { "movesPerSession", ArgInt, (LPVOID) &appData.movesPerSession, TRUE },
\r
926 { "mps", ArgInt, (LPVOID) &appData.movesPerSession, FALSE },
\r
927 { "initString", ArgString, (LPVOID) &appData.initString, FALSE },
\r
928 { "firstInitString", ArgString, (LPVOID) &appData.initString, FALSE },
\r
929 { "secondInitString", ArgString, (LPVOID) &appData.secondInitString, FALSE },
\r
930 { "firstComputerString", ArgString, (LPVOID) &appData.firstComputerString,
\r
932 { "secondComputerString", ArgString, (LPVOID) &appData.secondComputerString,
\r
934 { "firstChessProgram", ArgFilename, (LPVOID) &appData.firstChessProgram,
\r
936 { "fcp", ArgFilename, (LPVOID) &appData.firstChessProgram, FALSE },
\r
937 { "secondChessProgram", ArgFilename, (LPVOID) &appData.secondChessProgram,
\r
939 { "scp", ArgFilename, (LPVOID) &appData.secondChessProgram, FALSE },
\r
940 { "firstPlaysBlack", ArgBoolean, (LPVOID) &appData.firstPlaysBlack, FALSE },
\r
941 { "fb", ArgTrue, (LPVOID) &appData.firstPlaysBlack, FALSE },
\r
942 { "xfb", ArgFalse, (LPVOID) &appData.firstPlaysBlack, FALSE },
\r
943 { "-fb", ArgFalse, (LPVOID) &appData.firstPlaysBlack, FALSE },
\r
944 { "noChessProgram", ArgBoolean, (LPVOID) &appData.noChessProgram, FALSE },
\r
945 { "ncp", ArgTrue, (LPVOID) &appData.noChessProgram, FALSE },
\r
946 { "xncp", ArgFalse, (LPVOID) &appData.noChessProgram, FALSE },
\r
947 { "-ncp", ArgFalse, (LPVOID) &appData.noChessProgram, FALSE },
\r
948 { "firstHost", ArgString, (LPVOID) &appData.firstHost, FALSE },
\r
949 { "fh", ArgString, (LPVOID) &appData.firstHost, FALSE },
\r
950 { "secondHost", ArgString, (LPVOID) &appData.secondHost, FALSE },
\r
951 { "sh", ArgString, (LPVOID) &appData.secondHost, FALSE },
\r
952 { "firstDirectory", ArgFilename, (LPVOID) &appData.firstDirectory, FALSE },
\r
953 { "fd", ArgFilename, (LPVOID) &appData.firstDirectory, FALSE },
\r
954 { "secondDirectory", ArgFilename, (LPVOID) &appData.secondDirectory, FALSE },
\r
955 { "sd", ArgFilename, (LPVOID) &appData.secondDirectory, FALSE },
\r
956 /*!!bitmapDirectory?*/
\r
957 { "remoteShell", ArgFilename, (LPVOID) &appData.remoteShell, FALSE },
\r
958 { "rsh", ArgFilename, (LPVOID) &appData.remoteShell, FALSE },
\r
959 { "remoteUser", ArgString, (LPVOID) &appData.remoteUser, FALSE },
\r
960 { "ruser", ArgString, (LPVOID) &appData.remoteUser, FALSE },
\r
961 { "timeDelay", ArgFloat, (LPVOID) &appData.timeDelay, TRUE },
\r
962 { "td", ArgFloat, (LPVOID) &appData.timeDelay, FALSE },
\r
963 { "timeControl", ArgString, (LPVOID) &appData.timeControl, TRUE },
\r
964 { "tc", ArgString, (LPVOID) &appData.timeControl, FALSE },
\r
965 { "timeIncrement", ArgInt, (LPVOID) &appData.timeIncrement, TRUE },
\r
966 { "inc", ArgInt, (LPVOID) &appData.timeIncrement, FALSE },
\r
967 { "internetChessServerMode", ArgBoolean, (LPVOID) &appData.icsActive, FALSE },
\r
968 { "ics", ArgTrue, (LPVOID) &appData.icsActive, FALSE },
\r
969 { "xics", ArgFalse, (LPVOID) &appData.icsActive, FALSE },
\r
970 { "-ics", ArgFalse, (LPVOID) &appData.icsActive, FALSE },
\r
971 { "internetChessServerHost", ArgString, (LPVOID) &appData.icsHost, FALSE },
\r
972 { "icshost", ArgString, (LPVOID) &appData.icsHost, FALSE },
\r
973 { "internetChessServerPort", ArgString, (LPVOID) &appData.icsPort, FALSE },
\r
974 { "icsport", ArgString, (LPVOID) &appData.icsPort, FALSE },
\r
975 { "internetChessServerCommPort", ArgString, (LPVOID) &appData.icsCommPort, FALSE },
\r
976 { "icscomm", ArgString, (LPVOID) &appData.icsCommPort, FALSE },
\r
977 { "internetChessServerComPort", ArgString, (LPVOID) &appData.icsCommPort, FALSE },
\r
978 { "icscom", ArgString, (LPVOID) &appData.icsCommPort, FALSE },
\r
979 { "internetChessServerLogonScript", ArgFilename, (LPVOID) &appData.icsLogon, FALSE },
\r
980 { "icslogon", ArgFilename, (LPVOID) &appData.icsLogon, FALSE },
\r
981 { "useTelnet", ArgBoolean, (LPVOID) &appData.useTelnet, FALSE },
\r
982 { "telnet", ArgTrue, (LPVOID) &appData.useTelnet, FALSE },
\r
983 { "xtelnet", ArgFalse, (LPVOID) &appData.useTelnet, FALSE },
\r
984 { "-telnet", ArgFalse, (LPVOID) &appData.useTelnet, FALSE },
\r
985 { "telnetProgram", ArgFilename, (LPVOID) &appData.telnetProgram, FALSE },
\r
986 { "icshelper", ArgFilename, (LPVOID) &appData.icsHelper, FALSE },
\r
987 { "gateway", ArgString, (LPVOID) &appData.gateway, FALSE },
\r
988 { "loadGameFile", ArgFilename, (LPVOID) &appData.loadGameFile, FALSE },
\r
989 { "lgf", ArgFilename, (LPVOID) &appData.loadGameFile, FALSE },
\r
990 { "loadGameIndex", ArgInt, (LPVOID) &appData.loadGameIndex, FALSE },
\r
991 { "lgi", ArgInt, (LPVOID) &appData.loadGameIndex, FALSE },
\r
992 { "saveGameFile", ArgFilename, (LPVOID) &appData.saveGameFile, TRUE },
\r
993 { "sgf", ArgFilename, (LPVOID) &appData.saveGameFile, FALSE },
\r
994 { "autoSaveGames", ArgBoolean, (LPVOID) &appData.autoSaveGames, TRUE },
\r
995 { "autosave", ArgTrue, (LPVOID) &appData.autoSaveGames, FALSE },
\r
996 { "xautosave", ArgFalse, (LPVOID) &appData.autoSaveGames, FALSE },
\r
997 { "-autosave", ArgFalse, (LPVOID) &appData.autoSaveGames, FALSE },
\r
998 { "loadPositionFile", ArgFilename, (LPVOID) &appData.loadPositionFile, FALSE },
\r
999 { "lpf", ArgFilename, (LPVOID) &appData.loadPositionFile, FALSE },
\r
1000 { "loadPositionIndex", ArgInt, (LPVOID) &appData.loadPositionIndex, FALSE },
\r
1001 { "lpi", ArgInt, (LPVOID) &appData.loadPositionIndex, FALSE },
\r
1002 { "savePositionFile", ArgFilename, (LPVOID) &appData.savePositionFile, FALSE },
\r
1003 { "spf", ArgFilename, (LPVOID) &appData.savePositionFile, FALSE },
\r
1004 { "matchMode", ArgBoolean, (LPVOID) &appData.matchMode, FALSE },
\r
1005 { "mm", ArgTrue, (LPVOID) &appData.matchMode, FALSE },
\r
1006 { "xmm", ArgFalse, (LPVOID) &appData.matchMode, FALSE },
\r
1007 { "-mm", ArgFalse, (LPVOID) &appData.matchMode, FALSE },
\r
1008 { "matchGames", ArgInt, (LPVOID) &appData.matchGames, FALSE },
\r
1009 { "mg", ArgInt, (LPVOID) &appData.matchGames, FALSE },
\r
1010 { "monoMode", ArgBoolean, (LPVOID) &appData.monoMode, TRUE },
\r
1011 { "mono", ArgTrue, (LPVOID) &appData.monoMode, FALSE },
\r
1012 { "xmono", ArgFalse, (LPVOID) &appData.monoMode, FALSE },
\r
1013 { "-mono", ArgFalse, (LPVOID) &appData.monoMode, FALSE },
\r
1014 { "debugMode", ArgBoolean, (LPVOID) &appData.debugMode, FALSE },
\r
1015 { "debug", ArgTrue, (LPVOID) &appData.debugMode, FALSE },
\r
1016 { "xdebug", ArgFalse, (LPVOID) &appData.debugMode, FALSE },
\r
1017 { "-debug", ArgFalse, (LPVOID) &appData.debugMode, FALSE },
\r
1018 { "clockMode", ArgBoolean, (LPVOID) &appData.clockMode, FALSE },
\r
1019 { "clock", ArgTrue, (LPVOID) &appData.clockMode, FALSE },
\r
1020 { "xclock", ArgFalse, (LPVOID) &appData.clockMode, FALSE },
\r
1021 { "-clock", ArgFalse, (LPVOID) &appData.clockMode, FALSE },
\r
1022 { "searchTime", ArgString, (LPVOID) &appData.searchTime, FALSE },
\r
1023 { "st", ArgString, (LPVOID) &appData.searchTime, FALSE },
\r
1024 { "searchDepth", ArgInt, (LPVOID) &appData.searchDepth, FALSE },
\r
1025 { "depth", ArgInt, (LPVOID) &appData.searchDepth, FALSE },
\r
1026 { "showCoords", ArgBoolean, (LPVOID) &appData.showCoords, TRUE },
\r
1027 { "coords", ArgTrue, (LPVOID) &appData.showCoords, FALSE },
\r
1028 { "xcoords", ArgFalse, (LPVOID) &appData.showCoords, FALSE },
\r
1029 { "-coords", ArgFalse, (LPVOID) &appData.showCoords, FALSE },
\r
1030 { "showThinking", ArgBoolean, (LPVOID) &appData.showThinking, TRUE },
\r
1031 { "thinking", ArgTrue, (LPVOID) &appData.showThinking, FALSE },
\r
1032 { "xthinking", ArgFalse, (LPVOID) &appData.showThinking, FALSE },
\r
1033 { "-thinking", ArgFalse, (LPVOID) &appData.showThinking, FALSE },
\r
1034 { "ponderNextMove", ArgBoolean, (LPVOID) &appData.ponderNextMove, TRUE },
\r
1035 { "ponder", ArgTrue, (LPVOID) &appData.ponderNextMove, FALSE },
\r
1036 { "xponder", ArgFalse, (LPVOID) &appData.ponderNextMove, FALSE },
\r
1037 { "-ponder", ArgFalse, (LPVOID) &appData.ponderNextMove, FALSE },
\r
1038 { "periodicUpdates", ArgBoolean, (LPVOID) &appData.periodicUpdates, TRUE },
\r
1039 { "periodic", ArgTrue, (LPVOID) &appData.periodicUpdates, FALSE },
\r
1040 { "xperiodic", ArgFalse, (LPVOID) &appData.periodicUpdates, FALSE },
\r
1041 { "-periodic", ArgFalse, (LPVOID) &appData.periodicUpdates, FALSE },
\r
1042 { "popupExitMessage", ArgBoolean, (LPVOID) &appData.popupExitMessage, TRUE },
\r
1043 { "exit", ArgTrue, (LPVOID) &appData.popupExitMessage, FALSE },
\r
1044 { "xexit", ArgFalse, (LPVOID) &appData.popupExitMessage, FALSE },
\r
1045 { "-exit", ArgFalse, (LPVOID) &appData.popupExitMessage, FALSE },
\r
1046 { "popupMoveErrors", ArgBoolean, (LPVOID) &appData.popupMoveErrors, TRUE },
\r
1047 { "popup", ArgTrue, (LPVOID) &appData.popupMoveErrors, FALSE },
\r
1048 { "xpopup", ArgFalse, (LPVOID) &appData.popupMoveErrors, FALSE },
\r
1049 { "-popup", ArgFalse, (LPVOID) &appData.popupMoveErrors, FALSE },
\r
1050 { "popUpErrors", ArgBoolean, (LPVOID) &appData.popupMoveErrors,
\r
1051 FALSE }, /* only so that old WinBoard.ini files from betas can be read */
\r
1052 { "clockFont", ArgFont, (LPVOID) CLOCK_FONT, TRUE },
\r
1053 { "messageFont", ArgFont, (LPVOID) MESSAGE_FONT, TRUE },
\r
1054 { "coordFont", ArgFont, (LPVOID) COORD_FONT, TRUE },
\r
1055 { "tagsFont", ArgFont, (LPVOID) EDITTAGS_FONT, TRUE },
\r
1056 { "commentFont", ArgFont, (LPVOID) COMMENT_FONT, TRUE },
\r
1057 { "icsFont", ArgFont, (LPVOID) CONSOLE_FONT, TRUE },
\r
1058 { "moveHistoryFont", ArgFont, (LPVOID) MOVEHISTORY_FONT, TRUE }, /* [AS] */
\r
1059 { "boardSize", ArgBoardSize, (LPVOID) &boardSize,
\r
1060 TRUE }, /* must come after all fonts */
\r
1061 { "size", ArgBoardSize, (LPVOID) &boardSize, FALSE },
\r
1062 { "ringBellAfterMoves", ArgBoolean, (LPVOID) &appData.ringBellAfterMoves,
\r
1063 FALSE }, /* historical; kept only so old winboard.ini files will parse */
\r
1064 { "alwaysOnTop", ArgBoolean, (LPVOID) &alwaysOnTop, TRUE },
\r
1065 { "top", ArgTrue, (LPVOID) &alwaysOnTop, FALSE },
\r
1066 { "xtop", ArgFalse, (LPVOID) &alwaysOnTop, FALSE },
\r
1067 { "-top", ArgFalse, (LPVOID) &alwaysOnTop, FALSE },
\r
1068 { "autoCallFlag", ArgBoolean, (LPVOID) &appData.autoCallFlag, TRUE },
\r
1069 { "autoflag", ArgTrue, (LPVOID) &appData.autoCallFlag, FALSE },
\r
1070 { "xautoflag", ArgFalse, (LPVOID) &appData.autoCallFlag, FALSE },
\r
1071 { "-autoflag", ArgFalse, (LPVOID) &appData.autoCallFlag, FALSE },
\r
1072 { "autoComment", ArgBoolean, (LPVOID) &appData.autoComment, TRUE },
\r
1073 { "autocomm", ArgTrue, (LPVOID) &appData.autoComment, FALSE },
\r
1074 { "xautocomm", ArgFalse, (LPVOID) &appData.autoComment, FALSE },
\r
1075 { "-autocomm", ArgFalse, (LPVOID) &appData.autoComment, FALSE },
\r
1076 { "autoObserve", ArgBoolean, (LPVOID) &appData.autoObserve, TRUE },
\r
1077 { "autobs", ArgTrue, (LPVOID) &appData.autoObserve, FALSE },
\r
1078 { "xautobs", ArgFalse, (LPVOID) &appData.autoObserve, FALSE },
\r
1079 { "-autobs", ArgFalse, (LPVOID) &appData.autoObserve, FALSE },
\r
1080 { "flipView", ArgBoolean, (LPVOID) &appData.flipView, FALSE },
\r
1081 { "flip", ArgTrue, (LPVOID) &appData.flipView, FALSE },
\r
1082 { "xflip", ArgFalse, (LPVOID) &appData.flipView, FALSE },
\r
1083 { "-flip", ArgFalse, (LPVOID) &appData.flipView, FALSE },
\r
1084 { "autoFlipView", ArgBoolean, (LPVOID) &appData.autoFlipView, TRUE },
\r
1085 { "autoflip", ArgTrue, (LPVOID) &appData.autoFlipView, FALSE },
\r
1086 { "xautoflip", ArgFalse, (LPVOID) &appData.autoFlipView, FALSE },
\r
1087 { "-autoflip", ArgFalse, (LPVOID) &appData.autoFlipView, FALSE },
\r
1088 { "autoRaiseBoard", ArgBoolean, (LPVOID) &appData.autoRaiseBoard, TRUE },
\r
1089 { "autoraise", ArgTrue, (LPVOID) &appData.autoRaiseBoard, FALSE },
\r
1090 { "xautoraise", ArgFalse, (LPVOID) &appData.autoRaiseBoard, FALSE },
\r
1091 { "-autoraise", ArgFalse, (LPVOID) &appData.autoRaiseBoard, FALSE },
\r
1093 { "cmailGameName", ArgString, (LPVOID) &appData.cmailGameName, FALSE },
\r
1094 { "cmail", ArgString, (LPVOID) &appData.cmailGameName, FALSE },
\r
1096 { "alwaysPromoteToQueen", ArgBoolean, (LPVOID) &appData.alwaysPromoteToQueen, TRUE },
\r
1097 { "queen", ArgTrue, (LPVOID) &appData.alwaysPromoteToQueen, FALSE },
\r
1098 { "xqueen", ArgFalse, (LPVOID) &appData.alwaysPromoteToQueen, FALSE },
\r
1099 { "-queen", ArgFalse, (LPVOID) &appData.alwaysPromoteToQueen, FALSE },
\r
1100 { "oldSaveStyle", ArgBoolean, (LPVOID) &appData.oldSaveStyle, TRUE },
\r
1101 { "oldsave", ArgTrue, (LPVOID) &appData.oldSaveStyle, FALSE },
\r
1102 { "xoldsave", ArgFalse, (LPVOID) &appData.oldSaveStyle, FALSE },
\r
1103 { "-oldsave", ArgFalse, (LPVOID) &appData.oldSaveStyle, FALSE },
\r
1104 { "quietPlay", ArgBoolean, (LPVOID) &appData.quietPlay, TRUE },
\r
1105 { "quiet", ArgTrue, (LPVOID) &appData.quietPlay, FALSE },
\r
1106 { "xquiet", ArgFalse, (LPVOID) &appData.quietPlay, FALSE },
\r
1107 { "-quiet", ArgFalse, (LPVOID) &appData.quietPlay, FALSE },
\r
1108 { "getMoveList", ArgBoolean, (LPVOID) &appData.getMoveList, TRUE },
\r
1109 { "moves", ArgTrue, (LPVOID) &appData.getMoveList, FALSE },
\r
1110 { "xmoves", ArgFalse, (LPVOID) &appData.getMoveList, FALSE },
\r
1111 { "-moves", ArgFalse, (LPVOID) &appData.getMoveList, FALSE },
\r
1112 { "testLegality", ArgBoolean, (LPVOID) &appData.testLegality, TRUE },
\r
1113 { "legal", ArgTrue, (LPVOID) &appData.testLegality, FALSE },
\r
1114 { "xlegal", ArgFalse, (LPVOID) &appData.testLegality, FALSE },
\r
1115 { "-legal", ArgFalse, (LPVOID) &appData.testLegality, FALSE },
\r
1116 { "premove", ArgBoolean, (LPVOID) &appData.premove, TRUE },
\r
1117 { "pre", ArgTrue, (LPVOID) &appData.premove, FALSE },
\r
1118 { "xpre", ArgFalse, (LPVOID) &appData.premove, FALSE },
\r
1119 { "-pre", ArgFalse, (LPVOID) &appData.premove, FALSE },
\r
1120 { "premoveWhite", ArgBoolean, (LPVOID) &appData.premoveWhite, TRUE },
\r
1121 { "prewhite", ArgTrue, (LPVOID) &appData.premoveWhite, FALSE },
\r
1122 { "xprewhite", ArgFalse, (LPVOID) &appData.premoveWhite, FALSE },
\r
1123 { "-prewhite", ArgFalse, (LPVOID) &appData.premoveWhite, FALSE },
\r
1124 { "premoveWhiteText", ArgString, (LPVOID) &appData.premoveWhiteText, TRUE },
\r
1125 { "premoveBlack", ArgBoolean, (LPVOID) &appData.premoveBlack, TRUE },
\r
1126 { "preblack", ArgTrue, (LPVOID) &appData.premoveBlack, FALSE },
\r
1127 { "xpreblack", ArgFalse, (LPVOID) &appData.premoveBlack, FALSE },
\r
1128 { "-preblack", ArgFalse, (LPVOID) &appData.premoveBlack, FALSE },
\r
1129 { "premoveBlackText", ArgString, (LPVOID) &appData.premoveBlackText, TRUE },
\r
1130 { "icsAlarm", ArgBoolean, (LPVOID) &appData.icsAlarm, TRUE},
\r
1131 { "alarm", ArgTrue, (LPVOID) &appData.icsAlarm, FALSE},
\r
1132 { "xalarm", ArgFalse, (LPVOID) &appData.icsAlarm, FALSE},
\r
1133 { "-alarm", ArgFalse, (LPVOID) &appData.icsAlarm, FALSE},
\r
1134 { "icsAlarmTime", ArgInt, (LPVOID) &appData.icsAlarmTime, TRUE},
\r
1135 { "localLineEditing", ArgBoolean, (LPVOID) &appData.localLineEditing, FALSE},
\r
1136 { "localLineEditing", ArgBoolean, (LPVOID) &appData.localLineEditing, FALSE},
\r
1137 { "edit", ArgTrue, (LPVOID) &appData.localLineEditing, FALSE },
\r
1138 { "xedit", ArgFalse, (LPVOID) &appData.localLineEditing, FALSE },
\r
1139 { "-edit", ArgFalse, (LPVOID) &appData.localLineEditing, FALSE },
\r
1140 { "animateMoving", ArgBoolean, (LPVOID) &appData.animate, TRUE },
\r
1141 { "animate", ArgTrue, (LPVOID) &appData.animate, FALSE },
\r
1142 { "xanimate", ArgFalse, (LPVOID) &appData.animate, FALSE },
\r
1143 { "-animate", ArgFalse, (LPVOID) &appData.animate, FALSE },
\r
1144 { "animateSpeed", ArgInt, (LPVOID) &appData.animSpeed, TRUE },
\r
1145 { "animateDragging", ArgBoolean, (LPVOID) &appData.animateDragging, TRUE },
\r
1146 { "drag", ArgTrue, (LPVOID) &appData.animateDragging, FALSE },
\r
1147 { "xdrag", ArgFalse, (LPVOID) &appData.animateDragging, FALSE },
\r
1148 { "-drag", ArgFalse, (LPVOID) &appData.animateDragging, FALSE },
\r
1149 { "blindfold", ArgBoolean, (LPVOID) &appData.blindfold, TRUE },
\r
1150 { "blind", ArgTrue, (LPVOID) &appData.blindfold, FALSE },
\r
1151 { "xblind", ArgFalse, (LPVOID) &appData.blindfold, FALSE },
\r
1152 { "-blind", ArgFalse, (LPVOID) &appData.blindfold, FALSE },
\r
1153 { "highlightLastMove", ArgBoolean,
\r
1154 (LPVOID) &appData.highlightLastMove, TRUE },
\r
1155 { "highlight", ArgTrue, (LPVOID) &appData.highlightLastMove, FALSE },
\r
1156 { "xhighlight", ArgFalse, (LPVOID) &appData.highlightLastMove, FALSE },
\r
1157 { "-highlight", ArgFalse, (LPVOID) &appData.highlightLastMove, FALSE },
\r
1158 { "highlightDragging", ArgBoolean,
\r
1159 (LPVOID) &appData.highlightDragging, TRUE },
\r
1160 { "highdrag", ArgTrue, (LPVOID) &appData.highlightDragging, FALSE },
\r
1161 { "xhighdrag", ArgFalse, (LPVOID) &appData.highlightDragging, FALSE },
\r
1162 { "-highdrag", ArgFalse, (LPVOID) &appData.highlightDragging, FALSE },
\r
1163 { "colorizeMessages", ArgBoolean, (LPVOID) &appData.colorize, TRUE },
\r
1164 { "colorize", ArgTrue, (LPVOID) &appData.colorize, FALSE },
\r
1165 { "xcolorize", ArgFalse, (LPVOID) &appData.colorize, FALSE },
\r
1166 { "-colorize", ArgFalse, (LPVOID) &appData.colorize, FALSE },
\r
1167 { "colorShout", ArgAttribs, (LPVOID) ColorShout, TRUE },
\r
1168 { "colorSShout", ArgAttribs, (LPVOID) ColorSShout, TRUE },
\r
1169 { "colorChannel1", ArgAttribs, (LPVOID) ColorChannel1, TRUE },
\r
1170 { "colorChannel", ArgAttribs, (LPVOID) ColorChannel, TRUE },
\r
1171 { "colorKibitz", ArgAttribs, (LPVOID) ColorKibitz, TRUE },
\r
1172 { "colorTell", ArgAttribs, (LPVOID) ColorTell, TRUE },
\r
1173 { "colorChallenge", ArgAttribs, (LPVOID) ColorChallenge, TRUE },
\r
1174 { "colorRequest", ArgAttribs, (LPVOID) ColorRequest, TRUE },
\r
1175 { "colorSeek", ArgAttribs, (LPVOID) ColorSeek, TRUE },
\r
1176 { "colorNormal", ArgAttribs, (LPVOID) ColorNormal, TRUE },
\r
1177 { "colorBackground", ArgColor, (LPVOID) &consoleBackgroundColor, TRUE },
\r
1178 { "soundShout", ArgFilename,
\r
1179 (LPVOID) &textAttribs[ColorShout].sound.name, TRUE },
\r
1180 { "soundSShout", ArgFilename,
\r
1181 (LPVOID) &textAttribs[ColorSShout].sound.name, TRUE },
\r
1182 { "soundChannel1", ArgFilename,
\r
1183 (LPVOID) &textAttribs[ColorChannel1].sound.name, TRUE },
\r
1184 { "soundChannel", ArgFilename,
\r
1185 (LPVOID) &textAttribs[ColorChannel].sound.name, TRUE },
\r
1186 { "soundKibitz", ArgFilename,
\r
1187 (LPVOID) &textAttribs[ColorKibitz].sound.name, TRUE },
\r
1188 { "soundTell", ArgFilename,
\r
1189 (LPVOID) &textAttribs[ColorTell].sound.name, TRUE },
\r
1190 { "soundChallenge", ArgFilename,
\r
1191 (LPVOID) &textAttribs[ColorChallenge].sound.name, TRUE },
\r
1192 { "soundRequest", ArgFilename,
\r
1193 (LPVOID) &textAttribs[ColorRequest].sound.name, TRUE },
\r
1194 { "soundSeek", ArgFilename,
\r
1195 (LPVOID) &textAttribs[ColorSeek].sound.name, TRUE },
\r
1196 { "soundMove", ArgFilename, (LPVOID) &sounds[(int)SoundMove].name, TRUE },
\r
1197 { "soundBell", ArgFilename, (LPVOID) &sounds[(int)SoundBell].name, TRUE },
\r
1198 { "soundIcsWin", ArgFilename, (LPVOID) &sounds[(int)SoundIcsWin].name,TRUE },
\r
1199 { "soundIcsLoss", ArgFilename,
\r
1200 (LPVOID) &sounds[(int)SoundIcsLoss].name, TRUE },
\r
1201 { "soundIcsDraw", ArgFilename,
\r
1202 (LPVOID) &sounds[(int)SoundIcsDraw].name, TRUE },
\r
1203 { "soundIcsUnfinished", ArgFilename,
\r
1204 (LPVOID) &sounds[(int)SoundIcsUnfinished].name, TRUE},
\r
1205 { "soundIcsAlarm", ArgFilename,
\r
1206 (LPVOID) &sounds[(int)SoundAlarm].name, TRUE },
\r
1207 { "reuseFirst", ArgBoolean, (LPVOID) &appData.reuseFirst, FALSE },
\r
1208 { "reuse", ArgTrue, (LPVOID) &appData.reuseFirst, FALSE },
\r
1209 { "xreuse", ArgFalse, (LPVOID) &appData.reuseFirst, FALSE },
\r
1210 { "-reuse", ArgFalse, (LPVOID) &appData.reuseFirst, FALSE },
\r
1211 { "reuseChessPrograms", ArgBoolean,
\r
1212 (LPVOID) &appData.reuseFirst, FALSE }, /* backward compat only */
\r
1213 { "reuseSecond", ArgBoolean, (LPVOID) &appData.reuseSecond, FALSE },
\r
1214 { "reuse2", ArgTrue, (LPVOID) &appData.reuseSecond, FALSE },
\r
1215 { "xreuse2", ArgFalse, (LPVOID) &appData.reuseSecond, FALSE },
\r
1216 { "-reuse2", ArgFalse, (LPVOID) &appData.reuseSecond, FALSE },
\r
1217 { "comPortSettings", ArgCommSettings, (LPVOID) &dcb, TRUE },
\r
1218 { "settingsFile", ArgSettingsFilename, (LPVOID) &settingsFileName, FALSE },
\r
1219 { "ini", ArgSettingsFilename, (LPVOID) &settingsFileName, FALSE },
\r
1220 { "saveSettingsOnExit", ArgBoolean, (LPVOID) &saveSettingsOnExit, TRUE },
\r
1221 { "chessProgram", ArgBoolean, (LPVOID) &chessProgram, FALSE },
\r
1222 { "cp", ArgTrue, (LPVOID) &chessProgram, FALSE },
\r
1223 { "xcp", ArgFalse, (LPVOID) &chessProgram, FALSE },
\r
1224 { "-cp", ArgFalse, (LPVOID) &chessProgram, FALSE },
\r
1225 { "icsMenu", ArgString, (LPVOID) &icsTextMenuString, TRUE },
\r
1226 { "icsNames", ArgString, (LPVOID) &icsNames, TRUE },
\r
1227 { "firstChessProgramNames", ArgString, (LPVOID) &firstChessProgramNames,
\r
1229 { "secondChessProgramNames", ArgString, (LPVOID) &secondChessProgramNames,
\r
1231 { "initialMode", ArgString, (LPVOID) &appData.initialMode, FALSE },
\r
1232 { "mode", ArgString, (LPVOID) &appData.initialMode, FALSE },
\r
1233 { "variant", ArgString, (LPVOID) &appData.variant, FALSE },
\r
1234 { "firstProtocolVersion", ArgInt, (LPVOID) &appData.firstProtocolVersion, FALSE },
\r
1235 { "secondProtocolVersion", ArgInt, (LPVOID) &appData.secondProtocolVersion,FALSE },
\r
1236 { "showButtonBar", ArgBoolean, (LPVOID) &appData.showButtonBar, TRUE },
\r
1237 { "buttons", ArgTrue, (LPVOID) &appData.showButtonBar, FALSE },
\r
1238 { "xbuttons", ArgFalse, (LPVOID) &appData.showButtonBar, FALSE },
\r
1239 { "-buttons", ArgFalse, (LPVOID) &appData.showButtonBar, FALSE },
\r
1240 /* [AS] New features */
\r
1241 { "firstScoreAbs", ArgBoolean, (LPVOID) &appData.firstScoreIsAbsolute, FALSE },
\r
1242 { "secondScoreAbs", ArgBoolean, (LPVOID) &appData.secondScoreIsAbsolute, FALSE },
\r
1243 { "pgnExtendedInfo", ArgBoolean, (LPVOID) &appData.saveExtendedInfoInPGN, TRUE },
\r
1244 { "hideThinkingFromHuman", ArgBoolean, (LPVOID) &appData.hideThinkingFromHuman, TRUE },
\r
1245 { "liteBackTextureFile", ArgString, (LPVOID) &appData.liteBackTextureFile, TRUE },
\r
1246 { "darkBackTextureFile", ArgString, (LPVOID) &appData.darkBackTextureFile, TRUE },
\r
1247 { "liteBackTextureMode", ArgInt, (LPVOID) &appData.liteBackTextureMode, TRUE },
\r
1248 { "darkBackTextureMode", ArgInt, (LPVOID) &appData.darkBackTextureMode, TRUE },
\r
1249 { "renderPiecesWithFont", ArgString, (LPVOID) &appData.renderPiecesWithFont, TRUE },
\r
1250 { "fontPieceToCharTable", ArgString, (LPVOID) &appData.fontToPieceTable, TRUE },
\r
1251 { "fontPieceBackColorWhite", ArgColor, (LPVOID) &appData.fontBackColorWhite, TRUE },
\r
1252 { "fontPieceForeColorWhite", ArgColor, (LPVOID) &appData.fontForeColorWhite, TRUE },
\r
1253 { "fontPieceBackColorBlack", ArgColor, (LPVOID) &appData.fontBackColorBlack, TRUE },
\r
1254 { "fontPieceForeColorBlack", ArgColor, (LPVOID) &appData.fontForeColorBlack, TRUE },
\r
1255 { "fontPieceSize", ArgInt, (LPVOID) &appData.fontPieceSize, TRUE },
\r
1256 { "overrideLineGap", ArgInt, (LPVOID) &appData.overrideLineGap, TRUE },
\r
1257 { "adjudicateLossThreshold", ArgInt, (LPVOID) &appData.adjudicateLossThreshold, TRUE },
\r
1258 { "delayBeforeQuit", ArgInt, (LPVOID) &appData.delayBeforeQuit, TRUE },
\r
1259 { "delayAfterQuit", ArgInt, (LPVOID) &appData.delayAfterQuit, TRUE },
\r
1260 { "nameOfDebugFile", ArgFilename, (LPVOID) &appData.nameOfDebugFile, FALSE },
\r
1261 { "debugfile", ArgFilename, (LPVOID) &appData.nameOfDebugFile, FALSE },
\r
1262 { "pgnEventHeader", ArgString, (LPVOID) &appData.pgnEventHeader, TRUE },
\r
1263 { "defaultFrcPosition", ArgInt, (LPVOID) &appData.defaultFrcPosition, TRUE },
\r
1264 { "gameListTags", ArgString, (LPVOID) &appData.gameListTags, TRUE },
\r
1265 { "saveOutOfBookInfo", ArgBoolean, (LPVOID) &appData.saveOutOfBookInfo, TRUE },
\r
1266 { "showEvalInMoveHistory", ArgBoolean, (LPVOID) &appData.showEvalInMoveHistory, TRUE },
\r
1267 { "evalHistColorWhite", ArgColor, (LPVOID) &appData.evalHistColorWhite, TRUE },
\r
1268 { "evalHistColorBlack", ArgColor, (LPVOID) &appData.evalHistColorBlack, TRUE },
\r
1269 { "highlightMoveWithArrow", ArgBoolean, (LPVOID) &appData.highlightMoveWithArrow, TRUE },
\r
1270 { "highlightArrowColor", ArgColor, (LPVOID) &appData.highlightArrowColor, TRUE },
\r
1271 { "stickyWindows", ArgBoolean, (LPVOID) &appData.useStickyWindows, TRUE },
\r
1272 { "adjudicateDrawMoves", ArgInt, (LPVOID) &appData.adjudicateDrawMoves, TRUE },
\r
1273 { "autoDisplayComment", ArgBoolean, (LPVOID) &appData.autoDisplayComment, TRUE },
\r
1274 { "autoDisplayTags", ArgBoolean, (LPVOID) &appData.autoDisplayTags, TRUE },
\r
1275 { "firstIsUCI", ArgBoolean, (LPVOID) &appData.firstIsUCI, FALSE },
\r
1276 { "fUCI", ArgTrue, (LPVOID) &appData.firstIsUCI, FALSE },
\r
1277 { "secondIsUCI", ArgBoolean, (LPVOID) &appData.secondIsUCI, FALSE },
\r
1278 { "sUCI", ArgTrue, (LPVOID) &appData.secondIsUCI, FALSE },
\r
1279 { "firstHasOwnBookUCI", ArgBoolean, (LPVOID) &appData.firstHasOwnBookUCI, FALSE },
\r
1280 { "fNoOwnBookUCI", ArgFalse, (LPVOID) &appData.firstHasOwnBookUCI, FALSE },
\r
1281 { "firstXBook", ArgFalse, (LPVOID) &appData.firstHasOwnBookUCI, FALSE },
\r
1282 { "secondHasOwnBookUCI", ArgBoolean, (LPVOID) &appData.secondHasOwnBookUCI, FALSE },
\r
1283 { "sNoOwnBookUCI", ArgFalse, (LPVOID) &appData.secondHasOwnBookUCI, FALSE },
\r
1284 { "secondXBook", ArgFalse, (LPVOID) &appData.secondHasOwnBookUCI, FALSE },
\r
1285 { "polyglotDir", ArgFilename, (LPVOID) &appData.polyglotDir, TRUE },
\r
1286 { "usePolyglotBook", ArgBoolean, (LPVOID) &appData.usePolyglotBook, TRUE },
\r
1287 { "polyglotBook", ArgFilename, (LPVOID) &appData.polyglotBook, TRUE },
\r
1288 { "defaultHashSize", ArgInt, (LPVOID) &appData.defaultHashSize, TRUE },
\r
1289 { "defaultCacheSizeEGTB", ArgInt, (LPVOID) &appData.defaultCacheSizeEGTB, TRUE },
\r
1290 { "defaultPathEGTB", ArgFilename, (LPVOID) &appData.defaultPathEGTB, TRUE },
\r
1292 /* [HGM] board-size, adjudication and misc. options */
\r
1293 { "boardWidth", ArgInt, (LPVOID) &appData.NrFiles, TRUE },
\r
1294 { "boardHeight", ArgInt, (LPVOID) &appData.NrRanks, TRUE },
\r
1295 { "holdingsSize", ArgInt, (LPVOID) &appData.holdingsSize, TRUE },
\r
1296 { "matchPause", ArgInt, (LPVOID) &appData.matchPause, TRUE },
\r
1297 { "pieceToCharTable", ArgString, (LPVOID) &appData.pieceToCharTable, FALSE },
\r
1298 { "flipBlack", ArgBoolean, (LPVOID) &appData.upsideDown, TRUE },
\r
1299 { "allWhite", ArgBoolean, (LPVOID) &appData.allWhite, TRUE },
\r
1300 { "alphaRank", ArgBoolean, (LPVOID) &appData.alphaRank, FALSE },
\r
1301 { "firstAlphaRank", ArgBoolean, (LPVOID) &first.alphaRank, FALSE },
\r
1302 { "secondAlphaRank", ArgBoolean, (LPVOID) &second.alphaRank, FALSE },
\r
1303 { "testClaims", ArgBoolean, (LPVOID) &appData.testClaims, TRUE },
\r
1304 { "checkMates", ArgBoolean, (LPVOID) &appData.checkMates, TRUE },
\r
1305 { "materialDraws", ArgBoolean, (LPVOID) &appData.materialDraws, TRUE },
\r
1306 { "trivialDraws", ArgBoolean, (LPVOID) &appData.trivialDraws, TRUE },
\r
1307 { "ruleMoves", ArgInt, (LPVOID) &appData.ruleMoves, TRUE },
\r
1308 { "repeatsToDraw", ArgInt, (LPVOID) &appData.drawRepeats, TRUE },
\r
1309 { "autoKibitz", ArgTrue, (LPVOID) &appData.autoKibitz, FALSE },
\r
1310 { "engineDebugOutput", ArgInt, (LPVOID) &appData.engineComments, FALSE },
\r
1311 { "userName", ArgString, (LPVOID) &appData.userName, FALSE },
\r
1312 { "rewindIndex", ArgInt, (LPVOID) &appData.rewindIndex, FALSE },
\r
1313 { "sameColorGames", ArgInt, (LPVOID) &appData.sameColorGames, FALSE },
\r
1314 { "smpCores", ArgInt, (LPVOID) &appData.smpCores, TRUE },
\r
1315 { "egtFormats", ArgString, (LPVOID) &appData.egtFormats, TRUE },
\r
1316 { "niceEngines", ArgInt, (LPVOID) &appData.niceEngines, TRUE },
\r
1317 { "firstLogo", ArgFilename, (LPVOID) &appData.firstLogo, FALSE },
\r
1318 { "secondLogo", ArgFilename, (LPVOID) &appData.secondLogo, FALSE },
\r
1319 { "autoLogo", ArgBoolean, (LPVOID) &appData.autoLogo, TRUE },
\r
1320 { "firstOptions", ArgString, (LPVOID) &appData.firstOptions, FALSE },
\r
1321 { "secondOptions", ArgString, (LPVOID) &appData.secondOptions, FALSE },
\r
1322 { "firstNeedsNoncompliantFEN", ArgString, (LPVOID) &appData.fenOverride1, FALSE },
\r
1323 { "secondNeedsNoncompliantFEN", ArgString, (LPVOID) &appData.fenOverride2, FALSE },
\r
1326 { "zippyTalk", ArgBoolean, (LPVOID) &appData.zippyTalk, FALSE },
\r
1327 { "zt", ArgTrue, (LPVOID) &appData.zippyTalk, FALSE },
\r
1328 { "xzt", ArgFalse, (LPVOID) &appData.zippyTalk, FALSE },
\r
1329 { "-zt", ArgFalse, (LPVOID) &appData.zippyTalk, FALSE },
\r
1330 { "zippyPlay", ArgBoolean, (LPVOID) &appData.zippyPlay, FALSE },
\r
1331 { "zp", ArgTrue, (LPVOID) &appData.zippyPlay, FALSE },
\r
1332 { "xzp", ArgFalse, (LPVOID) &appData.zippyPlay, FALSE },
\r
1333 { "-zp", ArgFalse, (LPVOID) &appData.zippyPlay, FALSE },
\r
1334 { "zippyLines", ArgFilename, (LPVOID) &appData.zippyLines, FALSE },
\r
1335 { "zippyPinhead", ArgString, (LPVOID) &appData.zippyPinhead, FALSE },
\r
1336 { "zippyPassword", ArgString, (LPVOID) &appData.zippyPassword, FALSE },
\r
1337 { "zippyPassword2", ArgString, (LPVOID) &appData.zippyPassword2, FALSE },
\r
1338 { "zippyWrongPassword", ArgString, (LPVOID) &appData.zippyWrongPassword,
\r
1340 { "zippyAcceptOnly", ArgString, (LPVOID) &appData.zippyAcceptOnly, FALSE },
\r
1341 { "zippyUseI", ArgBoolean, (LPVOID) &appData.zippyUseI, FALSE },
\r
1342 { "zui", ArgTrue, (LPVOID) &appData.zippyUseI, FALSE },
\r
1343 { "xzui", ArgFalse, (LPVOID) &appData.zippyUseI, FALSE },
\r
1344 { "-zui", ArgFalse, (LPVOID) &appData.zippyUseI, FALSE },
\r
1345 { "zippyBughouse", ArgInt, (LPVOID) &appData.zippyBughouse, FALSE },
\r
1346 { "zippyNoplayCrafty", ArgBoolean, (LPVOID) &appData.zippyNoplayCrafty,
\r
1348 { "znc", ArgTrue, (LPVOID) &appData.zippyNoplayCrafty, FALSE },
\r
1349 { "xznc", ArgFalse, (LPVOID) &appData.zippyNoplayCrafty, FALSE },
\r
1350 { "-znc", ArgFalse, (LPVOID) &appData.zippyNoplayCrafty, FALSE },
\r
1351 { "zippyGameEnd", ArgString, (LPVOID) &appData.zippyGameEnd, FALSE },
\r
1352 { "zippyGameStart", ArgString, (LPVOID) &appData.zippyGameStart, FALSE },
\r
1353 { "zippyAdjourn", ArgBoolean, (LPVOID) &appData.zippyAdjourn, FALSE },
\r
1354 { "zadj", ArgTrue, (LPVOID) &appData.zippyAdjourn, FALSE },
\r
1355 { "xzadj", ArgFalse, (LPVOID) &appData.zippyAdjourn, FALSE },
\r
1356 { "-zadj", ArgFalse, (LPVOID) &appData.zippyAdjourn, FALSE },
\r
1357 { "zippyAbort", ArgBoolean, (LPVOID) &appData.zippyAbort, FALSE },
\r
1358 { "zab", ArgTrue, (LPVOID) &appData.zippyAbort, FALSE },
\r
1359 { "xzab", ArgFalse, (LPVOID) &appData.zippyAbort, FALSE },
\r
1360 { "-zab", ArgFalse, (LPVOID) &appData.zippyAbort, FALSE },
\r
1361 { "zippyVariants", ArgString, (LPVOID) &appData.zippyVariants, FALSE },
\r
1362 { "zippyMaxGames", ArgInt, (LPVOID)&appData.zippyMaxGames, FALSE },
\r
1363 { "zippyReplayTimeout", ArgInt, (LPVOID)&appData.zippyReplayTimeout, FALSE },
\r
1364 { "zippyShortGame", ArgInt, (LPVOID)&appData.zippyShortGame, FALSE },
\r
1365 /* Kludge to allow winboard.ini files from buggy 4.0.4 to be read: */
\r
1366 { "zippyReplyTimeout", ArgInt, (LPVOID)&junk, FALSE },
\r
1368 /* [HGM] options for broadcasting and time odds */
\r
1369 { "serverMoves", ArgString, (LPVOID) &appData.serverMovesName, FALSE },
\r
1370 { "suppressLoadMoves", ArgBoolean, (LPVOID) &appData.suppressLoadMoves, FALSE },
\r
1371 { "serverPause", ArgInt, (LPVOID) &appData.serverPause, FALSE },
\r
1372 { "firstTimeOdds", ArgInt, (LPVOID) &appData.firstTimeOdds, FALSE },
\r
1373 { "secondTimeOdds", ArgInt, (LPVOID) &appData.secondTimeOdds, FALSE },
\r
1374 { "timeOddsMode", ArgInt, (LPVOID) &appData.timeOddsMode, TRUE },
\r
1375 { "firstAccumulateTC", ArgInt, (LPVOID) &appData.firstAccumulateTC, FALSE },
\r
1376 { "secondAccumulateTC", ArgInt, (LPVOID) &appData.secondAccumulateTC, FALSE },
\r
1377 { "firstNPS", ArgInt, (LPVOID) &appData.firstNPS, FALSE },
\r
1378 { "secondNPS", ArgInt, (LPVOID) &appData.secondNPS, FALSE },
\r
1379 { "noGUI", ArgTrue, (LPVOID) &appData.noGUI, FALSE },
\r
1381 // [HGM] placement: put all window layouts last in ini file, but man X,Y before all others
\r
1382 { "minX", ArgZ, (LPVOID) &minX, FALSE }, // [HGM] placement: to make suer auxialary windows can be placed
\r
1383 { "minY", ArgZ, (LPVOID) &minY, FALSE },
\r
1384 { "winWidth", ArgInt, (LPVOID) &winWidth, TRUE }, // [HGM] placement: dummies to remember right & bottom
\r
1385 { "winHeight", ArgInt, (LPVOID) &winHeight, TRUE }, // for attaching auxiliary windows to them
\r
1386 { "x", ArgInt, (LPVOID) &boardX, TRUE },
\r
1387 { "y", ArgInt, (LPVOID) &boardY, TRUE },
\r
1388 { "icsX", ArgX, (LPVOID) &wpConsole.x, TRUE },
\r
1389 { "icsY", ArgY, (LPVOID) &wpConsole.y, TRUE },
\r
1390 { "icsW", ArgInt, (LPVOID) &wpConsole.width, TRUE },
\r
1391 { "icsH", ArgInt, (LPVOID) &wpConsole.height, TRUE },
\r
1392 { "analysisX", ArgX, (LPVOID) &analysisX, FALSE }, // [HGM] placement: analysis window no longer exists
\r
1393 { "analysisY", ArgY, (LPVOID) &analysisY, FALSE }, // provided for compatibility with old ini files
\r
1394 { "analysisW", ArgInt, (LPVOID) &analysisW, FALSE },
\r
1395 { "analysisH", ArgInt, (LPVOID) &analysisH, FALSE },
\r
1396 { "commentX", ArgX, (LPVOID) &commentX, TRUE },
\r
1397 { "commentY", ArgY, (LPVOID) &commentY, TRUE },
\r
1398 { "commentW", ArgInt, (LPVOID) &commentW, TRUE },
\r
1399 { "commentH", ArgInt, (LPVOID) &commentH, TRUE },
\r
1400 { "tagsX", ArgX, (LPVOID) &editTagsX, TRUE },
\r
1401 { "tagsY", ArgY, (LPVOID) &editTagsY, TRUE },
\r
1402 { "tagsW", ArgInt, (LPVOID) &editTagsW, TRUE },
\r
1403 { "tagsH", ArgInt, (LPVOID) &editTagsH, TRUE },
\r
1404 { "gameListX", ArgX, (LPVOID) &wpGameList.x, TRUE },
\r
1405 { "gameListY", ArgY, (LPVOID) &wpGameList.y, TRUE },
\r
1406 { "gameListW", ArgInt, (LPVOID) &wpGameList.width, TRUE },
\r
1407 { "gameListH", ArgInt, (LPVOID) &wpGameList.height, TRUE },
\r
1408 /* [AS] Layout stuff */
\r
1409 { "moveHistoryUp", ArgBoolean, (LPVOID) &wpMoveHistory.visible, TRUE },
\r
1410 { "moveHistoryX", ArgX, (LPVOID) &wpMoveHistory.x, TRUE },
\r
1411 { "moveHistoryY", ArgY, (LPVOID) &wpMoveHistory.y, TRUE },
\r
1412 { "moveHistoryW", ArgInt, (LPVOID) &wpMoveHistory.width, TRUE },
\r
1413 { "moveHistoryH", ArgInt, (LPVOID) &wpMoveHistory.height, TRUE },
\r
1415 { "evalGraphUp", ArgBoolean, (LPVOID) &wpEvalGraph.visible, TRUE },
\r
1416 { "evalGraphX", ArgX, (LPVOID) &wpEvalGraph.x, TRUE },
\r
1417 { "evalGraphY", ArgY, (LPVOID) &wpEvalGraph.y, TRUE },
\r
1418 { "evalGraphW", ArgInt, (LPVOID) &wpEvalGraph.width, TRUE },
\r
1419 { "evalGraphH", ArgInt, (LPVOID) &wpEvalGraph.height, TRUE },
\r
1421 { "engineOutputUp", ArgBoolean, (LPVOID) &wpEngineOutput.visible, TRUE },
\r
1422 { "engineOutputX", ArgX, (LPVOID) &wpEngineOutput.x, TRUE },
\r
1423 { "engineOutputY", ArgY, (LPVOID) &wpEngineOutput.y, TRUE },
\r
1424 { "engineOutputW", ArgInt, (LPVOID) &wpEngineOutput.width, TRUE },
\r
1425 { "engineOutputH", ArgInt, (LPVOID) &wpEngineOutput.height, TRUE },
\r
1427 { NULL, ArgNone, NULL, FALSE }
\r
1431 /* Kludge for indirection files on command line */
\r
1432 char* lastIndirectionFilename;
\r
1433 ArgDescriptor argDescriptorIndirection =
\r
1434 { "", ArgSettingsFilename, (LPVOID) NULL, FALSE };
\r
1438 ExitArgError(char *msg, char *badArg)
\r
1440 char buf[MSG_SIZ];
\r
1442 sprintf(buf, "%s %s", msg, badArg);
\r
1443 DisplayFatalError(buf, 0, 2);
\r
1447 /* Command line font name parser. NULL name means do nothing.
\r
1448 Syntax like "Courier New:10.0 bi" or "Arial:10" or "Arial:10b"
\r
1449 For backward compatibility, syntax without the colon is also
\r
1450 accepted, but font names with digits in them won't work in that case.
\r
1453 ParseFontName(char *name, MyFontParams *mfp)
\r
1456 if (name == NULL) return;
\r
1458 q = strchr(p, ':');
\r
1460 if (q - p >= sizeof(mfp->faceName))
\r
1461 ExitArgError("Font name too long:", name);
\r
1462 memcpy(mfp->faceName, p, q - p);
\r
1463 mfp->faceName[q - p] = NULLCHAR;
\r
1466 q = mfp->faceName;
\r
1467 while (*p && !isdigit(*p)) {
\r
1469 if (q - mfp->faceName >= sizeof(mfp->faceName))
\r
1470 ExitArgError("Font name too long:", name);
\r
1472 while (q > mfp->faceName && q[-1] == ' ') q--;
\r
1475 if (!*p) ExitArgError("Font point size missing:", name);
\r
1476 mfp->pointSize = (float) atof(p);
\r
1477 mfp->bold = (strchr(p, 'b') != NULL);
\r
1478 mfp->italic = (strchr(p, 'i') != NULL);
\r
1479 mfp->underline = (strchr(p, 'u') != NULL);
\r
1480 mfp->strikeout = (strchr(p, 's') != NULL);
\r
1483 /* Color name parser.
\r
1484 X version accepts X color names, but this one
\r
1485 handles only the #rrggbb form (hex) or rrr,ggg,bbb (decimal) */
\r
1487 ParseColorName(char *name)
\r
1489 int red, green, blue, count;
\r
1490 char buf[MSG_SIZ];
\r
1492 count = sscanf(name, "#%2x%2x%2x", &red, &green, &blue);
\r
1494 count = sscanf(name, "%3d%*[^0-9]%3d%*[^0-9]%3d",
\r
1495 &red, &green, &blue);
\r
1498 sprintf(buf, "Can't parse color name %s", name);
\r
1499 DisplayError(buf, 0);
\r
1500 return RGB(0, 0, 0);
\r
1502 return PALETTERGB(red, green, blue);
\r
1506 void ParseAttribs(COLORREF *color, int *effects, char* argValue)
\r
1508 char *e = argValue;
\r
1512 if (*e == 'b') eff |= CFE_BOLD;
\r
1513 else if (*e == 'i') eff |= CFE_ITALIC;
\r
1514 else if (*e == 'u') eff |= CFE_UNDERLINE;
\r
1515 else if (*e == 's') eff |= CFE_STRIKEOUT;
\r
1516 else if (*e == '#' || isdigit(*e)) break;
\r
1520 *color = ParseColorName(e);
\r
1525 ParseBoardSize(char *name)
\r
1527 BoardSize bs = SizeTiny;
\r
1528 while (sizeInfo[bs].name != NULL) {
\r
1529 if (StrCaseCmp(name, sizeInfo[bs].name) == 0) return bs;
\r
1532 ExitArgError("Unrecognized board size value", name);
\r
1533 return bs; /* not reached */
\r
1538 StringGet(void *getClosure)
\r
1540 char **p = (char **) getClosure;
\r
1545 FileGet(void *getClosure)
\r
1548 FILE* f = (FILE*) getClosure;
\r
1551 if (c == '\r') c = getc(f); // work around DOS format files by bypassing the '\r' completely
\r
1558 /* Parse settings file named "name". If file found, return the
\r
1559 full name in fullname and return TRUE; else return FALSE */
\r
1561 ParseSettingsFile(char *name, char fullname[MSG_SIZ])
\r
1565 int ok; char buf[MSG_SIZ];
\r
1567 ok = SearchPath(installDir, name, NULL, MSG_SIZ, fullname, &dummy);
\r
1568 if(!ok && strchr(name, '.') == NULL) { // [HGM] append default file-name extension '.ini' when needed
\r
1569 sprintf(buf, "%s.ini", name);
\r
1570 ok = SearchPath(installDir, buf, NULL, MSG_SIZ, fullname, &dummy);
\r
1573 f = fopen(fullname, "r");
\r
1575 ParseArgs(FileGet, f);
\r
1584 ParseArgs(GetFunc get, void *cl)
\r
1586 char argName[ARG_MAX];
\r
1587 char argValue[ARG_MAX];
\r
1588 ArgDescriptor *ad;
\r
1597 while (ch == ' ' || ch == '\n' || ch == '\t') ch = get(cl);
\r
1598 if (ch == NULLCHAR) break;
\r
1600 /* Comment to end of line */
\r
1602 while (ch != '\n' && ch != NULLCHAR) ch = get(cl);
\r
1604 } else if (ch == '/' || ch == '-') {
\r
1607 while (ch != ' ' && ch != '=' && ch != ':' && ch != NULLCHAR &&
\r
1608 ch != '\n' && ch != '\t') {
\r
1614 for (ad = argDescriptors; ad->argName != NULL; ad++)
\r
1615 if (strcmp(ad->argName, argName + 1) == 0) break;
\r
1617 if (ad->argName == NULL)
\r
1618 ExitArgError("Unrecognized argument", argName);
\r
1620 } else if (ch == '@') {
\r
1621 /* Indirection file */
\r
1622 ad = &argDescriptorIndirection;
\r
1625 /* Positional argument */
\r
1626 ad = &argDescriptors[posarg++];
\r
1627 strcpy(argName, ad->argName);
\r
1630 if (ad->argType == ArgTrue) {
\r
1631 *(Boolean *) ad->argLoc = TRUE;
\r
1634 if (ad->argType == ArgFalse) {
\r
1635 *(Boolean *) ad->argLoc = FALSE;
\r
1639 while (ch == ' ' || ch == '=' || ch == ':' || ch == '\t') ch = get(cl);
\r
1640 if (ch == NULLCHAR || ch == '\n') {
\r
1641 ExitArgError("No value provided for argument", argName);
\r
1645 // Quoting with { }. No characters have to (or can) be escaped.
\r
1646 // Thus the string cannot contain a '}' character.
\r
1666 } else if (ch == '\'' || ch == '"') {
\r
1667 // Quoting with ' ' or " ", with \ as escape character.
\r
1668 // Inconvenient for long strings that may contain Windows filenames.
\r
1685 if (ch == start) {
\r
1694 if (ad->argType == ArgFilename
\r
1695 || ad->argType == ArgSettingsFilename) {
\r
1701 ExitArgError("Incomplete \\ escape in value for", argName);
\r
1725 for (i = 0; i < 3; i++) {
\r
1726 if (ch >= '0' && ch <= '7') {
\r
1727 octval = octval*8 + (ch - '0');
\r
1734 *q++ = (char) octval;
\r
1745 while (ch != ' ' && ch != NULLCHAR && ch != '\t' && ch != '\n') {
\r
1752 switch (ad->argType) {
\r
1754 *(int *) ad->argLoc = atoi(argValue);
\r
1758 *(int *) ad->argLoc = atoi(argValue) + boardX; // [HGM] placement: translate stored relative to absolute
\r
1762 *(int *) ad->argLoc = atoi(argValue) + boardY; // (this is really kludgey, it should be done where used...)
\r
1766 *(int *) ad->argLoc = atoi(argValue);
\r
1767 EnsureOnScreen(&boardX, &boardY, minX, minY);
\r
1771 *(float *) ad->argLoc = (float) atof(argValue);
\r
1776 *(char **) ad->argLoc = strdup(argValue);
\r
1779 case ArgSettingsFilename:
\r
1781 char fullname[MSG_SIZ];
\r
1782 if (ParseSettingsFile(argValue, fullname)) {
\r
1783 if (ad->argLoc != NULL) {
\r
1784 *(char **) ad->argLoc = strdup(fullname);
\r
1787 if (ad->argLoc != NULL) {
\r
1789 ExitArgError("Failed to open indirection file", argValue);
\r
1796 switch (argValue[0]) {
\r
1799 *(Boolean *) ad->argLoc = TRUE;
\r
1803 *(Boolean *) ad->argLoc = FALSE;
\r
1806 ExitArgError("Unrecognized boolean argument value", argValue);
\r
1812 *(COLORREF *)ad->argLoc = ParseColorName(argValue);
\r
1815 case ArgAttribs: {
\r
1816 ColorClass cc = (ColorClass)ad->argLoc;
\r
1817 ParseAttribs(&textAttribs[cc].color, &textAttribs[cc].effects, argValue);
\r
1821 case ArgBoardSize:
\r
1822 *(BoardSize *)ad->argLoc = ParseBoardSize(argValue);
\r
1826 ParseFontName(argValue, &font[boardSize][(int)ad->argLoc]->mfp);
\r
1829 case ArgCommSettings:
\r
1830 ParseCommSettings(argValue, &dcb);
\r
1834 ExitArgError("Unrecognized argument", argValue);
\r
1843 LFfromMFP(LOGFONT* lf, MyFontParams *mfp)
\r
1845 HDC hdc = CreateDC("DISPLAY", NULL, NULL, NULL);
\r
1846 lf->lfHeight = -(int)(mfp->pointSize * GetDeviceCaps(hdc, LOGPIXELSY) / 72.0 + 0.5);
\r
1849 lf->lfEscapement = 0;
\r
1850 lf->lfOrientation = 0;
\r
1851 lf->lfWeight = mfp->bold ? FW_BOLD : FW_NORMAL;
\r
1852 lf->lfItalic = mfp->italic;
\r
1853 lf->lfUnderline = mfp->underline;
\r
1854 lf->lfStrikeOut = mfp->strikeout;
\r
1855 lf->lfCharSet = DEFAULT_CHARSET;
\r
1856 lf->lfOutPrecision = OUT_DEFAULT_PRECIS;
\r
1857 lf->lfClipPrecision = CLIP_DEFAULT_PRECIS;
\r
1858 lf->lfQuality = DEFAULT_QUALITY;
\r
1859 lf->lfPitchAndFamily = DEFAULT_PITCH|FF_DONTCARE;
\r
1860 strcpy(lf->lfFaceName, mfp->faceName);
\r
1864 CreateFontInMF(MyFont *mf)
\r
1866 LFfromMFP(&mf->lf, &mf->mfp);
\r
1867 if (mf->hf) DeleteObject(mf->hf);
\r
1868 mf->hf = CreateFontIndirect(&mf->lf);
\r
1872 SetDefaultTextAttribs()
\r
1875 for (cc = (ColorClass)0; cc < NColorClasses; cc++) {
\r
1876 ParseAttribs(&textAttribs[cc].color,
\r
1877 &textAttribs[cc].effects,
\r
1878 defaultTextAttribs[cc]);
\r
1883 SetDefaultSounds()
\r
1887 for (cc = (ColorClass)0; cc < NColorClasses; cc++) {
\r
1888 textAttribs[cc].sound.name = strdup("");
\r
1889 textAttribs[cc].sound.data = NULL;
\r
1891 for (sc = (SoundClass)0; sc < NSoundClasses; sc++) {
\r
1892 sounds[sc].name = strdup("");
\r
1893 sounds[sc].data = NULL;
\r
1895 sounds[(int)SoundBell].name = strdup(SOUND_BELL);
\r
1903 for (cc = (ColorClass)0; cc < NColorClasses; cc++) {
\r
1904 MyLoadSound(&textAttribs[cc].sound);
\r
1906 for (sc = (SoundClass)0; sc < NSoundClasses; sc++) {
\r
1907 MyLoadSound(&sounds[sc]);
\r
1912 InitAppData(LPSTR lpCmdLine)
\r
1915 char buf[ARG_MAX], currDir[MSG_SIZ];
\r
1918 programName = szAppName;
\r
1920 /* Initialize to defaults */
\r
1921 lightSquareColor = ParseColorName(LIGHT_SQUARE_COLOR);
\r
1922 darkSquareColor = ParseColorName(DARK_SQUARE_COLOR);
\r
1923 whitePieceColor = ParseColorName(WHITE_PIECE_COLOR);
\r
1924 blackPieceColor = ParseColorName(BLACK_PIECE_COLOR);
\r
1925 highlightSquareColor = ParseColorName(HIGHLIGHT_SQUARE_COLOR);
\r
1926 premoveHighlightColor = ParseColorName(PREMOVE_HIGHLIGHT_COLOR);
\r
1927 consoleBackgroundColor = ParseColorName(COLOR_BKGD);
\r
1928 SetDefaultTextAttribs();
\r
1929 SetDefaultSounds();
\r
1930 appData.movesPerSession = MOVES_PER_SESSION;
\r
1931 appData.initString = INIT_STRING;
\r
1932 appData.secondInitString = INIT_STRING;
\r
1933 appData.firstComputerString = COMPUTER_STRING;
\r
1934 appData.secondComputerString = COMPUTER_STRING;
\r
1935 appData.firstChessProgram = FIRST_CHESS_PROGRAM;
\r
1936 appData.secondChessProgram = SECOND_CHESS_PROGRAM;
\r
1937 appData.firstPlaysBlack = FALSE;
\r
1938 appData.noChessProgram = FALSE;
\r
1939 chessProgram = FALSE;
\r
1940 appData.firstHost = FIRST_HOST;
\r
1941 appData.secondHost = SECOND_HOST;
\r
1942 appData.firstDirectory = FIRST_DIRECTORY;
\r
1943 appData.secondDirectory = SECOND_DIRECTORY;
\r
1944 appData.bitmapDirectory = "";
\r
1945 appData.remoteShell = REMOTE_SHELL;
\r
1946 appData.remoteUser = "";
\r
1947 appData.timeDelay = TIME_DELAY;
\r
1948 appData.timeControl = TIME_CONTROL;
\r
1949 appData.timeIncrement = TIME_INCREMENT;
\r
1950 appData.icsActive = FALSE;
\r
1951 appData.icsHost = "";
\r
1952 appData.icsPort = ICS_PORT;
\r
1953 appData.icsCommPort = ICS_COMM_PORT;
\r
1954 appData.icsLogon = ICS_LOGON;
\r
1955 appData.icsHelper = "";
\r
1956 appData.useTelnet = FALSE;
\r
1957 appData.telnetProgram = TELNET_PROGRAM;
\r
1958 appData.gateway = "";
\r
1959 appData.loadGameFile = "";
\r
1960 appData.loadGameIndex = 0;
\r
1961 appData.saveGameFile = "";
\r
1962 appData.autoSaveGames = FALSE;
\r
1963 appData.loadPositionFile = "";
\r
1964 appData.loadPositionIndex = 1;
\r
1965 appData.savePositionFile = "";
\r
1966 appData.matchMode = FALSE;
\r
1967 appData.matchGames = 0;
\r
1968 appData.monoMode = FALSE;
\r
1969 appData.debugMode = FALSE;
\r
1970 appData.clockMode = TRUE;
\r
1971 boardSize = (BoardSize) -1; /* determine by screen size */
\r
1972 appData.Iconic = FALSE; /*unused*/
\r
1973 appData.searchTime = "";
\r
1974 appData.searchDepth = 0;
\r
1975 appData.showCoords = FALSE;
\r
1976 appData.ringBellAfterMoves = TRUE; /*obsolete in WinBoard*/
\r
1977 appData.autoCallFlag = FALSE;
\r
1978 appData.flipView = FALSE;
\r
1979 appData.autoFlipView = TRUE;
\r
1980 appData.cmailGameName = "";
\r
1981 appData.alwaysPromoteToQueen = FALSE;
\r
1982 appData.oldSaveStyle = FALSE;
\r
1983 appData.quietPlay = FALSE;
\r
1984 appData.showThinking = FALSE;
\r
1985 appData.ponderNextMove = TRUE;
\r
1986 appData.periodicUpdates = TRUE;
\r
1987 appData.popupExitMessage = TRUE;
\r
1988 appData.popupMoveErrors = FALSE;
\r
1989 appData.autoObserve = FALSE;
\r
1990 appData.autoComment = FALSE;
\r
1991 appData.animate = TRUE;
\r
1992 appData.animSpeed = 10;
\r
1993 appData.animateDragging = TRUE;
\r
1994 appData.highlightLastMove = TRUE;
\r
1995 appData.getMoveList = TRUE;
\r
1996 appData.testLegality = TRUE;
\r
1997 appData.premove = TRUE;
\r
1998 appData.premoveWhite = FALSE;
\r
1999 appData.premoveWhiteText = "";
\r
2000 appData.premoveBlack = FALSE;
\r
2001 appData.premoveBlackText = "";
\r
2002 appData.icsAlarm = TRUE;
\r
2003 appData.icsAlarmTime = 5000;
\r
2004 appData.autoRaiseBoard = TRUE;
\r
2005 appData.localLineEditing = TRUE;
\r
2006 appData.colorize = TRUE;
\r
2007 appData.reuseFirst = TRUE;
\r
2008 appData.reuseSecond = TRUE;
\r
2009 appData.blindfold = FALSE;
\r
2010 appData.icsEngineAnalyze = FALSE;
\r
2011 memset(&dcb, 0, sizeof(DCB)); // required by VS 2002 +
\r
2012 dcb.DCBlength = sizeof(DCB);
\r
2013 dcb.BaudRate = 9600;
\r
2014 dcb.fBinary = TRUE;
\r
2015 dcb.fParity = FALSE;
\r
2016 dcb.fOutxCtsFlow = FALSE;
\r
2017 dcb.fOutxDsrFlow = FALSE;
\r
2018 dcb.fDtrControl = DTR_CONTROL_ENABLE;
\r
2019 dcb.fDsrSensitivity = FALSE;
\r
2020 dcb.fTXContinueOnXoff = TRUE;
\r
2021 dcb.fOutX = FALSE;
\r
2023 dcb.fNull = FALSE;
\r
2024 dcb.fRtsControl = RTS_CONTROL_ENABLE;
\r
2025 dcb.fAbortOnError = FALSE;
\r
2027 dcb.Parity = SPACEPARITY;
\r
2028 dcb.StopBits = ONESTOPBIT;
\r
2029 settingsFileName = SETTINGS_FILE;
\r
2030 saveSettingsOnExit = TRUE;
\r
2031 boardX = CW_USEDEFAULT;
\r
2032 boardY = CW_USEDEFAULT;
\r
2033 analysisX = CW_USEDEFAULT;
\r
2034 analysisY = CW_USEDEFAULT;
\r
2035 analysisW = CW_USEDEFAULT;
\r
2036 analysisH = CW_USEDEFAULT;
\r
2037 commentX = CW_USEDEFAULT;
\r
2038 commentY = CW_USEDEFAULT;
\r
2039 commentW = CW_USEDEFAULT;
\r
2040 commentH = CW_USEDEFAULT;
\r
2041 editTagsX = CW_USEDEFAULT;
\r
2042 editTagsY = CW_USEDEFAULT;
\r
2043 editTagsW = CW_USEDEFAULT;
\r
2044 editTagsH = CW_USEDEFAULT;
\r
2045 icsTextMenuString = ICS_TEXT_MENU_DEFAULT;
\r
2046 icsNames = ICS_NAMES;
\r
2047 firstChessProgramNames = FCP_NAMES;
\r
2048 secondChessProgramNames = SCP_NAMES;
\r
2049 appData.initialMode = "";
\r
2050 appData.variant = "normal";
\r
2051 appData.firstProtocolVersion = PROTOVER;
\r
2052 appData.secondProtocolVersion = PROTOVER;
\r
2053 appData.showButtonBar = TRUE;
\r
2055 /* [AS] New properties (see comments in header file) */
\r
2056 appData.firstScoreIsAbsolute = FALSE;
\r
2057 appData.secondScoreIsAbsolute = FALSE;
\r
2058 appData.saveExtendedInfoInPGN = FALSE;
\r
2059 appData.hideThinkingFromHuman = FALSE;
\r
2060 appData.liteBackTextureFile = "";
\r
2061 appData.liteBackTextureMode = BACK_TEXTURE_MODE_PLAIN;
\r
2062 appData.darkBackTextureFile = "";
\r
2063 appData.darkBackTextureMode = BACK_TEXTURE_MODE_PLAIN;
\r
2064 appData.renderPiecesWithFont = "";
\r
2065 appData.fontToPieceTable = "";
\r
2066 appData.fontBackColorWhite = 0;
\r
2067 appData.fontForeColorWhite = 0;
\r
2068 appData.fontBackColorBlack = 0;
\r
2069 appData.fontForeColorBlack = 0;
\r
2070 appData.fontPieceSize = 80;
\r
2071 appData.overrideLineGap = 1;
\r
2072 appData.adjudicateLossThreshold = 0;
\r
2073 appData.delayBeforeQuit = 0;
\r
2074 appData.delayAfterQuit = 0;
\r
2075 appData.nameOfDebugFile = "winboard.debug";
\r
2076 appData.pgnEventHeader = "Computer Chess Game";
\r
2077 appData.defaultFrcPosition = -1;
\r
2078 appData.gameListTags = GLT_DEFAULT_TAGS;
\r
2079 appData.saveOutOfBookInfo = TRUE;
\r
2080 appData.showEvalInMoveHistory = TRUE;
\r
2081 appData.evalHistColorWhite = ParseColorName( "#FFFFB0" );
\r
2082 appData.evalHistColorBlack = ParseColorName( "#AD5D3D" );
\r
2083 appData.highlightMoveWithArrow = FALSE;
\r
2084 appData.highlightArrowColor = ParseColorName( "#FFFF80" );
\r
2085 appData.useStickyWindows = TRUE;
\r
2086 appData.adjudicateDrawMoves = 0;
\r
2087 appData.autoDisplayComment = TRUE;
\r
2088 appData.autoDisplayTags = TRUE;
\r
2089 appData.firstIsUCI = FALSE;
\r
2090 appData.secondIsUCI = FALSE;
\r
2091 appData.firstHasOwnBookUCI = TRUE;
\r
2092 appData.secondHasOwnBookUCI = TRUE;
\r
2093 appData.polyglotDir = "";
\r
2094 appData.usePolyglotBook = FALSE;
\r
2095 appData.polyglotBook = "";
\r
2096 appData.defaultHashSize = 64;
\r
2097 appData.defaultCacheSizeEGTB = 4;
\r
2098 appData.defaultPathEGTB = "c:\\egtb";
\r
2099 appData.firstOptions = "";
\r
2100 appData.secondOptions = "";
\r
2102 InitWindowPlacement( &wpGameList );
\r
2103 InitWindowPlacement( &wpMoveHistory );
\r
2104 InitWindowPlacement( &wpEvalGraph );
\r
2105 InitWindowPlacement( &wpEngineOutput );
\r
2106 InitWindowPlacement( &wpConsole );
\r
2108 /* [HGM] User-selectable board size, adjudication control, miscellaneous */
\r
2109 appData.NrFiles = -1;
\r
2110 appData.NrRanks = -1;
\r
2111 appData.holdingsSize = -1;
\r
2112 appData.testClaims = FALSE;
\r
2113 appData.checkMates = FALSE;
\r
2114 appData.materialDraws= FALSE;
\r
2115 appData.trivialDraws = FALSE;
\r
2116 appData.ruleMoves = 51;
\r
2117 appData.drawRepeats = 6;
\r
2118 appData.matchPause = 10000;
\r
2119 appData.alphaRank = FALSE;
\r
2120 appData.allWhite = FALSE;
\r
2121 appData.upsideDown = FALSE;
\r
2122 appData.serverPause = 15;
\r
2123 appData.serverMovesName = NULL;
\r
2124 appData.suppressLoadMoves = FALSE;
\r
2125 appData.firstTimeOdds = 1;
\r
2126 appData.secondTimeOdds = 1;
\r
2127 appData.firstAccumulateTC = 1; // combine previous and current sessions
\r
2128 appData.secondAccumulateTC = 1;
\r
2129 appData.firstNPS = -1; // [HGM] nps: use wall-clock time
\r
2130 appData.secondNPS = -1;
\r
2131 appData.engineComments = 1;
\r
2132 appData.smpCores = 1; // [HGM] SMP: max nr of cores
\r
2133 appData.egtFormats = "";
\r
2136 appData.zippyTalk = ZIPPY_TALK;
\r
2137 appData.zippyPlay = ZIPPY_PLAY;
\r
2138 appData.zippyLines = ZIPPY_LINES;
\r
2139 appData.zippyPinhead = ZIPPY_PINHEAD;
\r
2140 appData.zippyPassword = ZIPPY_PASSWORD;
\r
2141 appData.zippyPassword2 = ZIPPY_PASSWORD2;
\r
2142 appData.zippyWrongPassword = ZIPPY_WRONG_PASSWORD;
\r
2143 appData.zippyAcceptOnly = ZIPPY_ACCEPT_ONLY;
\r
2144 appData.zippyUseI = ZIPPY_USE_I;
\r
2145 appData.zippyBughouse = ZIPPY_BUGHOUSE;
\r
2146 appData.zippyNoplayCrafty = ZIPPY_NOPLAY_CRAFTY;
\r
2147 appData.zippyGameEnd = ZIPPY_GAME_END;
\r
2148 appData.zippyGameStart = ZIPPY_GAME_START;
\r
2149 appData.zippyAdjourn = ZIPPY_ADJOURN;
\r
2150 appData.zippyAbort = ZIPPY_ABORT;
\r
2151 appData.zippyVariants = ZIPPY_VARIANTS;
\r
2152 appData.zippyMaxGames = ZIPPY_MAX_GAMES;
\r
2153 appData.zippyReplayTimeout = ZIPPY_REPLAY_TIMEOUT;
\r
2156 /* Point font array elements to structures and
\r
2157 parse default font names */
\r
2158 for (i=0; i<NUM_FONTS; i++) {
\r
2159 for (j=0; j<NUM_SIZES; j++) {
\r
2160 font[j][i] = &fontRec[j][i];
\r
2161 ParseFontName(font[j][i]->def, &font[j][i]->mfp);
\r
2165 /* Parse default settings file if any */
\r
2166 if (ParseSettingsFile(settingsFileName, buf)) {
\r
2167 settingsFileName = strdup(buf);
\r
2170 /* Parse command line */
\r
2171 ParseArgs(StringGet, &lpCmdLine);
\r
2173 /* [HGM] make sure board size is acceptable */
\r
2174 if(appData.NrFiles > BOARD_SIZE ||
\r
2175 appData.NrRanks > BOARD_SIZE )
\r
2176 DisplayFatalError("Recompile with BOARD_SIZE > 12, to support this size", 0, 2);
\r
2178 /* [HGM] After parsing the options from the .ini file, and overruling them
\r
2179 * with options from the command line, we now make an even higher priority
\r
2180 * overrule by WB options attached to the engine command line. This so that
\r
2181 * tournament managers can use WB options (such as /timeOdds) that follow
\r
2184 if(appData.firstChessProgram != NULL) {
\r
2185 char *p = StrStr(appData.firstChessProgram, "WBopt");
\r
2186 static char *f = "first";
\r
2187 char buf[MSG_SIZ], *q = buf;
\r
2188 if(p != NULL) { // engine command line contains WinBoard options
\r
2189 sprintf(buf, p+6, f, f, f, f, f, f, f, f, f, f); // replace %s in them by "first"
\r
2190 ParseArgs(StringGet, &q);
\r
2191 p[-1] = 0; // cut them offengine command line
\r
2194 // now do same for second chess program
\r
2195 if(appData.secondChessProgram != NULL) {
\r
2196 char *p = StrStr(appData.secondChessProgram, "WBopt");
\r
2197 static char *s = "second";
\r
2198 char buf[MSG_SIZ], *q = buf;
\r
2199 if(p != NULL) { // engine command line contains WinBoard options
\r
2200 sprintf(buf, p+6, s, s, s, s, s, s, s, s, s, s); // replace %s in them by "first"
\r
2201 ParseArgs(StringGet, &q);
\r
2202 p[-1] = 0; // cut them offengine command line
\r
2207 /* Propagate options that affect others */
\r
2208 if (appData.matchMode || appData.matchGames) chessProgram = TRUE;
\r
2209 if (appData.icsActive || appData.noChessProgram) {
\r
2210 chessProgram = FALSE; /* not local chess program mode */
\r
2213 /* Open startup dialog if needed */
\r
2214 if ((!appData.noChessProgram && !chessProgram && !appData.icsActive) ||
\r
2215 (appData.icsActive && *appData.icsHost == NULLCHAR) ||
\r
2216 (chessProgram && (*appData.firstChessProgram == NULLCHAR ||
\r
2217 *appData.secondChessProgram == NULLCHAR))) {
\r
2220 lpProc = MakeProcInstance((FARPROC)StartupDialog, hInst);
\r
2221 DialogBox(hInst, MAKEINTRESOURCE(DLG_Startup), NULL, (DLGPROC)lpProc);
\r
2222 FreeProcInstance(lpProc);
\r
2225 /* Make sure save files land in the right (?) directory */
\r
2226 if (GetFullPathName(appData.saveGameFile, MSG_SIZ, buf, &dummy)) {
\r
2227 appData.saveGameFile = strdup(buf);
\r
2229 if (GetFullPathName(appData.savePositionFile, MSG_SIZ, buf, &dummy)) {
\r
2230 appData.savePositionFile = strdup(buf);
\r
2233 /* Finish initialization for fonts and sounds */
\r
2234 for (i=0; i<NUM_FONTS; i++) {
\r
2235 for (j=0; j<NUM_SIZES; j++) {
\r
2236 CreateFontInMF(font[j][i]);
\r
2239 /* xboard, and older WinBoards, controlled the move sound with the
\r
2240 appData.ringBellAfterMoves option. In the current WinBoard, we
\r
2241 always turn the option on (so that the backend will call us),
\r
2242 then let the user turn the sound off by setting it to silence if
\r
2243 desired. To accommodate old winboard.ini files saved by old
\r
2244 versions of WinBoard, we also turn off the sound if the option
\r
2245 was initially set to false. */
\r
2246 if (!appData.ringBellAfterMoves) {
\r
2247 sounds[(int)SoundMove].name = strdup("");
\r
2248 appData.ringBellAfterMoves = TRUE;
\r
2250 GetCurrentDirectory(MSG_SIZ, currDir);
\r
2251 SetCurrentDirectory(installDir);
\r
2253 SetCurrentDirectory(currDir);
\r
2255 p = icsTextMenuString;
\r
2256 if (p[0] == '@') {
\r
2257 FILE* f = fopen(p + 1, "r");
\r
2259 DisplayFatalError(p + 1, errno, 2);
\r
2262 i = fread(buf, 1, sizeof(buf)-1, f);
\r
2264 buf[i] = NULLCHAR;
\r
2267 ParseIcsTextMenu(strdup(p));
\r
2274 HMENU hmenu = GetMenu(hwndMain);
\r
2276 (void) EnableMenuItem(hmenu, IDM_CommPort,
\r
2277 MF_BYCOMMAND|((appData.icsActive &&
\r
2278 *appData.icsCommPort != NULLCHAR) ?
\r
2279 MF_ENABLED : MF_GRAYED));
\r
2280 (void) CheckMenuItem(hmenu, IDM_SaveSettingsOnExit,
\r
2281 MF_BYCOMMAND|(saveSettingsOnExit ?
\r
2282 MF_CHECKED : MF_UNCHECKED));
\r
2287 SaveSettings(char* name)
\r
2290 ArgDescriptor *ad;
\r
2291 WINDOWPLACEMENT wp;
\r
2292 char dir[MSG_SIZ];
\r
2294 if (!hwndMain) return;
\r
2296 GetCurrentDirectory(MSG_SIZ, dir);
\r
2297 SetCurrentDirectory(installDir);
\r
2298 f = fopen(name, "w");
\r
2299 SetCurrentDirectory(dir);
\r
2301 DisplayError(name, errno);
\r
2304 fprintf(f, ";\n");
\r
2305 fprintf(f, "; %s %s.%s Save Settings file\n", PRODUCT, VERSION, PATCHLEVEL);
\r
2306 fprintf(f, ";\n");
\r
2307 fprintf(f, "; You can edit the values of options that are already set in this file,\n");
\r
2308 fprintf(f, "; but if you add other options, the next Save Settings will not save them.\n");
\r
2309 fprintf(f, "; Use a shortcut, an @indirection file, or a .bat file instead.\n");
\r
2310 fprintf(f, ";\n");
\r
2312 wp.length = sizeof(WINDOWPLACEMENT);
\r
2313 GetWindowPlacement(hwndMain, &wp);
\r
2314 boardX = wp.rcNormalPosition.left;
\r
2315 boardY = wp.rcNormalPosition.top;
\r
2317 if (hwndConsole) {
\r
2318 GetWindowPlacement(hwndConsole, &wp);
\r
2319 wpConsole.x = wp.rcNormalPosition.left;
\r
2320 wpConsole.y = wp.rcNormalPosition.top;
\r
2321 wpConsole.width = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2322 wpConsole.height = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2325 if (analysisDialog) {
\r
2326 GetWindowPlacement(analysisDialog, &wp);
\r
2327 analysisX = wp.rcNormalPosition.left;
\r
2328 analysisY = wp.rcNormalPosition.top;
\r
2329 analysisW = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2330 analysisH = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2333 if (commentDialog) {
\r
2334 GetWindowPlacement(commentDialog, &wp);
\r
2335 commentX = wp.rcNormalPosition.left;
\r
2336 commentY = wp.rcNormalPosition.top;
\r
2337 commentW = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2338 commentH = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2341 if (editTagsDialog) {
\r
2342 GetWindowPlacement(editTagsDialog, &wp);
\r
2343 editTagsX = wp.rcNormalPosition.left;
\r
2344 editTagsY = wp.rcNormalPosition.top;
\r
2345 editTagsW = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2346 editTagsH = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2349 if (gameListDialog) {
\r
2350 GetWindowPlacement(gameListDialog, &wp);
\r
2351 wpGameList.x = wp.rcNormalPosition.left;
\r
2352 wpGameList.y = wp.rcNormalPosition.top;
\r
2353 wpGameList.width = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2354 wpGameList.height = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2357 /* [AS] Move history */
\r
2358 wpMoveHistory.visible = MoveHistoryIsUp();
\r
2360 if( moveHistoryDialog ) {
\r
2361 GetWindowPlacement(moveHistoryDialog, &wp);
\r
2362 wpMoveHistory.x = wp.rcNormalPosition.left;
\r
2363 wpMoveHistory.y = wp.rcNormalPosition.top;
\r
2364 wpMoveHistory.width = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2365 wpMoveHistory.height = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2368 /* [AS] Eval graph */
\r
2369 wpEvalGraph.visible = EvalGraphIsUp();
\r
2371 if( evalGraphDialog ) {
\r
2372 GetWindowPlacement(evalGraphDialog, &wp);
\r
2373 wpEvalGraph.x = wp.rcNormalPosition.left;
\r
2374 wpEvalGraph.y = wp.rcNormalPosition.top;
\r
2375 wpEvalGraph.width = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2376 wpEvalGraph.height = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2379 /* [AS] Engine output */
\r
2380 wpEngineOutput.visible = EngineOutputIsUp();
\r
2382 if( engineOutputDialog ) {
\r
2383 GetWindowPlacement(engineOutputDialog, &wp);
\r
2384 wpEngineOutput.x = wp.rcNormalPosition.left;
\r
2385 wpEngineOutput.y = wp.rcNormalPosition.top;
\r
2386 wpEngineOutput.width = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2387 wpEngineOutput.height = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2390 for (ad = argDescriptors; ad->argName != NULL; ad++) {
\r
2391 if (!ad->save) continue;
\r
2392 switch (ad->argType) {
\r
2395 char *p = *(char **)ad->argLoc;
\r
2396 if ((strchr(p, '\\') || strchr(p, '\n')) && !strchr(p, '}')) {
\r
2397 /* Quote multiline values or \-containing values
\r
2398 with { } if possible */
\r
2399 fprintf(f, "/%s={%s}\n", ad->argName, p);
\r
2401 /* Else quote with " " */
\r
2402 fprintf(f, "/%s=\"", ad->argName);
\r
2404 if (*p == '\n') fprintf(f, "\n");
\r
2405 else if (*p == '\r') fprintf(f, "\\r");
\r
2406 else if (*p == '\t') fprintf(f, "\\t");
\r
2407 else if (*p == '\b') fprintf(f, "\\b");
\r
2408 else if (*p == '\f') fprintf(f, "\\f");
\r
2409 else if (*p < ' ') fprintf(f, "\\%03o", *p);
\r
2410 else if (*p == '\"') fprintf(f, "\\\"");
\r
2411 else if (*p == '\\') fprintf(f, "\\\\");
\r
2415 fprintf(f, "\"\n");
\r
2421 fprintf(f, "/%s=%d\n", ad->argName, *(int *)ad->argLoc);
\r
2424 fprintf(f, "/%s=%d\n", ad->argName, *(int *)ad->argLoc - boardX); // [HGM] placement: stor relative value
\r
2427 fprintf(f, "/%s=%d\n", ad->argName, *(int *)ad->argLoc - boardY);
\r
2430 fprintf(f, "/%s=%g\n", ad->argName, *(float *)ad->argLoc);
\r
2433 fprintf(f, "/%s=%s\n", ad->argName,
\r
2434 (*(Boolean *)ad->argLoc) ? "true" : "false");
\r
2437 if (*(Boolean *)ad->argLoc) fprintf(f, "/%s\n", ad->argName);
\r
2440 if (!*(Boolean *)ad->argLoc) fprintf(f, "/%s\n", ad->argName);
\r
2444 COLORREF color = *(COLORREF *)ad->argLoc;
\r
2445 fprintf(f, "/%s=#%02lx%02lx%02lx\n", ad->argName,
\r
2446 color&0xff, (color>>8)&0xff, (color>>16)&0xff);
\r
2451 MyTextAttribs* ta = &textAttribs[(ColorClass)ad->argLoc];
\r
2452 fprintf(f, "/%s=\"%s%s%s%s%s#%02lx%02lx%02lx\"\n", ad->argName,
\r
2453 (ta->effects & CFE_BOLD) ? "b" : "",
\r
2454 (ta->effects & CFE_ITALIC) ? "i" : "",
\r
2455 (ta->effects & CFE_UNDERLINE) ? "u" : "",
\r
2456 (ta->effects & CFE_STRIKEOUT) ? "s" : "",
\r
2457 (ta->effects) ? " " : "",
\r
2458 ta->color&0xff, (ta->color >> 8)&0xff, (ta->color >> 16)&0xff);
\r
2462 if (strchr(*(char **)ad->argLoc, '\"')) {
\r
2463 fprintf(f, "/%s='%s'\n", ad->argName, *(char **)ad->argLoc);
\r
2465 fprintf(f, "/%s=\"%s\"\n", ad->argName, *(char **)ad->argLoc);
\r
2468 case ArgBoardSize:
\r
2469 fprintf(f, "/%s=%s\n", ad->argName,
\r
2470 sizeInfo[*(BoardSize *)ad->argLoc].name);
\r
2475 for (bs=0; bs<NUM_SIZES; bs++) {
\r
2476 MyFontParams *mfp = &font[bs][(int) ad->argLoc]->mfp;
\r
2477 fprintf(f, "/size=%s ", sizeInfo[bs].name);
\r
2478 fprintf(f, "/%s=\"%s:%g%s%s%s%s%s\"\n",
\r
2479 ad->argName, mfp->faceName, mfp->pointSize,
\r
2480 mfp->bold || mfp->italic || mfp->underline || mfp->strikeout ? " " : "",
\r
2481 mfp->bold ? "b" : "",
\r
2482 mfp->italic ? "i" : "",
\r
2483 mfp->underline ? "u" : "",
\r
2484 mfp->strikeout ? "s" : "");
\r
2488 case ArgCommSettings:
\r
2489 PrintCommSettings(f, ad->argName, (DCB *)ad->argLoc);
\r
2491 case ArgSettingsFilename: ;
\r
2499 /*---------------------------------------------------------------------------*\
\r
2501 * GDI board drawing routines
\r
2503 \*---------------------------------------------------------------------------*/
\r
2505 /* [AS] Draw square using background texture */
\r
2506 static void DrawTile( int dx, int dy, int dw, int dh, HDC dst, HDC src, int mode, int sx, int sy )
\r
2511 return; /* Should never happen! */
\r
2514 SetGraphicsMode( dst, GM_ADVANCED );
\r
2521 /* X reflection */
\r
2526 x.eDx = (FLOAT) dw + dx - 1;
\r
2529 SetWorldTransform( dst, &x );
\r
2532 /* Y reflection */
\r
2538 x.eDy = (FLOAT) dh + dy - 1;
\r
2540 SetWorldTransform( dst, &x );
\r
2548 x.eDx = (FLOAT) dx;
\r
2549 x.eDy = (FLOAT) dy;
\r
2552 SetWorldTransform( dst, &x );
\r
2556 BitBlt( dst, dx, dy, dw, dh, src, sx, sy, SRCCOPY );
\r
2564 SetWorldTransform( dst, &x );
\r
2566 ModifyWorldTransform( dst, 0, MWT_IDENTITY );
\r
2569 /* [AS] [HGM] Make room for more piece types, so all pieces can be different */
\r
2571 PM_WP = (int) WhitePawn,
\r
2572 PM_WN = (int) WhiteKnight,
\r
2573 PM_WB = (int) WhiteBishop,
\r
2574 PM_WR = (int) WhiteRook,
\r
2575 PM_WQ = (int) WhiteQueen,
\r
2576 PM_WF = (int) WhiteFerz,
\r
2577 PM_WW = (int) WhiteWazir,
\r
2578 PM_WE = (int) WhiteAlfil,
\r
2579 PM_WM = (int) WhiteMan,
\r
2580 PM_WO = (int) WhiteCannon,
\r
2581 PM_WU = (int) WhiteUnicorn,
\r
2582 PM_WH = (int) WhiteNightrider,
\r
2583 PM_WA = (int) WhiteAngel,
\r
2584 PM_WC = (int) WhiteMarshall,
\r
2585 PM_WAB = (int) WhiteCardinal,
\r
2586 PM_WD = (int) WhiteDragon,
\r
2587 PM_WL = (int) WhiteLance,
\r
2588 PM_WS = (int) WhiteCobra,
\r
2589 PM_WV = (int) WhiteFalcon,
\r
2590 PM_WSG = (int) WhiteSilver,
\r
2591 PM_WG = (int) WhiteGrasshopper,
\r
2592 PM_WK = (int) WhiteKing,
\r
2593 PM_BP = (int) BlackPawn,
\r
2594 PM_BN = (int) BlackKnight,
\r
2595 PM_BB = (int) BlackBishop,
\r
2596 PM_BR = (int) BlackRook,
\r
2597 PM_BQ = (int) BlackQueen,
\r
2598 PM_BF = (int) BlackFerz,
\r
2599 PM_BW = (int) BlackWazir,
\r
2600 PM_BE = (int) BlackAlfil,
\r
2601 PM_BM = (int) BlackMan,
\r
2602 PM_BO = (int) BlackCannon,
\r
2603 PM_BU = (int) BlackUnicorn,
\r
2604 PM_BH = (int) BlackNightrider,
\r
2605 PM_BA = (int) BlackAngel,
\r
2606 PM_BC = (int) BlackMarshall,
\r
2607 PM_BG = (int) BlackGrasshopper,
\r
2608 PM_BAB = (int) BlackCardinal,
\r
2609 PM_BD = (int) BlackDragon,
\r
2610 PM_BL = (int) BlackLance,
\r
2611 PM_BS = (int) BlackCobra,
\r
2612 PM_BV = (int) BlackFalcon,
\r
2613 PM_BSG = (int) BlackSilver,
\r
2614 PM_BK = (int) BlackKing
\r
2617 static HFONT hPieceFont = NULL;
\r
2618 static HBITMAP hPieceMask[(int) EmptySquare];
\r
2619 static HBITMAP hPieceFace[(int) EmptySquare];
\r
2620 static int fontBitmapSquareSize = 0;
\r
2621 static char pieceToFontChar[(int) EmptySquare] =
\r
2622 { 'p', 'n', 'b', 'r', 'q',
\r
2623 'n', 'b', 'p', 'n', 'b', 'r', 'b', 'r', 'q', 'k',
\r
2624 'k', 'o', 'm', 'v', 't', 'w',
\r
2625 'v', 't', 'o', 'm', 'v', 't', 'v', 't', 'w', 'l',
\r
2628 extern BOOL SetCharTable( char *table, const char * map );
\r
2629 /* [HGM] moved to backend.c */
\r
2631 static void SetPieceBackground( HDC hdc, COLORREF color, int mode )
\r
2634 BYTE r1 = GetRValue( color );
\r
2635 BYTE g1 = GetGValue( color );
\r
2636 BYTE b1 = GetBValue( color );
\r
2642 /* Create a uniform background first */
\r
2643 hbrush = CreateSolidBrush( color );
\r
2644 SetRect( &rc, 0, 0, squareSize, squareSize );
\r
2645 FillRect( hdc, &rc, hbrush );
\r
2646 DeleteObject( hbrush );
\r
2649 /* Vertical gradient, good for pawn, knight and rook, less for queen and king */
\r
2650 int steps = squareSize / 2;
\r
2653 for( i=0; i<steps; i++ ) {
\r
2654 BYTE r = r1 - (r1-r2) * i / steps;
\r
2655 BYTE g = g1 - (g1-g2) * i / steps;
\r
2656 BYTE b = b1 - (b1-b2) * i / steps;
\r
2658 hbrush = CreateSolidBrush( RGB(r,g,b) );
\r
2659 SetRect( &rc, i + squareSize - steps, 0, i + squareSize - steps + 1, squareSize );
\r
2660 FillRect( hdc, &rc, hbrush );
\r
2661 DeleteObject(hbrush);
\r
2664 else if( mode == 2 ) {
\r
2665 /* Diagonal gradient, good more or less for every piece */
\r
2666 POINT triangle[3];
\r
2667 HPEN hpen = SelectObject( hdc, GetStockObject(NULL_PEN) );
\r
2668 HBRUSH hbrush_old;
\r
2669 int steps = squareSize;
\r
2672 triangle[0].x = squareSize - steps;
\r
2673 triangle[0].y = squareSize;
\r
2674 triangle[1].x = squareSize;
\r
2675 triangle[1].y = squareSize;
\r
2676 triangle[2].x = squareSize;
\r
2677 triangle[2].y = squareSize - steps;
\r
2679 for( i=0; i<steps; i++ ) {
\r
2680 BYTE r = r1 - (r1-r2) * i / steps;
\r
2681 BYTE g = g1 - (g1-g2) * i / steps;
\r
2682 BYTE b = b1 - (b1-b2) * i / steps;
\r
2684 hbrush = CreateSolidBrush( RGB(r,g,b) );
\r
2685 hbrush_old = SelectObject( hdc, hbrush );
\r
2686 Polygon( hdc, triangle, 3 );
\r
2687 SelectObject( hdc, hbrush_old );
\r
2688 DeleteObject(hbrush);
\r
2693 SelectObject( hdc, hpen );
\r
2698 [AS] The method I use to create the bitmaps it a bit tricky, but it
\r
2699 seems to work ok. The main problem here is to find the "inside" of a chess
\r
2700 piece: follow the steps as explained below.
\r
2702 static void CreatePieceMaskFromFont( HDC hdc_window, HDC hdc, int index )
\r
2706 COLORREF chroma = RGB(0xFF,0x00,0xFF);
\r
2710 int backColor = whitePieceColor;
\r
2711 int foreColor = blackPieceColor;
\r
2713 if( index < (int)BlackPawn && appData.fontBackColorWhite != appData.fontForeColorWhite ) {
\r
2714 backColor = appData.fontBackColorWhite;
\r
2715 foreColor = appData.fontForeColorWhite;
\r
2717 else if( index >= (int)BlackPawn && appData.fontBackColorBlack != appData.fontForeColorBlack ) {
\r
2718 backColor = appData.fontBackColorBlack;
\r
2719 foreColor = appData.fontForeColorBlack;
\r
2723 hbm = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
\r
2725 hbm_old = SelectObject( hdc, hbm );
\r
2729 rc.right = squareSize;
\r
2730 rc.bottom = squareSize;
\r
2732 /* Step 1: background is now black */
\r
2733 FillRect( hdc, &rc, GetStockObject(BLACK_BRUSH) );
\r
2735 GetTextExtentPoint32( hdc, &pieceToFontChar[index], 1, &sz );
\r
2737 pt.x = (squareSize - sz.cx) / 2;
\r
2738 pt.y = (squareSize - sz.cy) / 2;
\r
2740 SetBkMode( hdc, TRANSPARENT );
\r
2741 SetTextColor( hdc, chroma );
\r
2742 /* Step 2: the piece has been drawn in purple, there are now black and purple in this bitmap */
\r
2743 TextOut( hdc, pt.x, pt.y, &pieceToFontChar[appData.allWhite && index >= (int)BlackPawn ? index - (int)BlackPawn : index], 1 );
\r
2745 SelectObject( hdc, GetStockObject(WHITE_BRUSH) );
\r
2746 /* Step 3: the area outside the piece is filled with white */
\r
2747 // FloodFill( hdc, 0, 0, chroma );
\r
2748 ExtFloodFill( hdc, 0, 0, 0, FLOODFILLSURFACE );
\r
2749 ExtFloodFill( hdc, 0, squareSize-1, 0, FLOODFILLSURFACE ); // [HGM] fill from all 4 corners, for if piece too big
\r
2750 ExtFloodFill( hdc, squareSize-1, 0, 0, FLOODFILLSURFACE );
\r
2751 ExtFloodFill( hdc, squareSize-1, squareSize-1, 0, FLOODFILLSURFACE );
\r
2752 SelectObject( hdc, GetStockObject(BLACK_BRUSH) );
\r
2754 Step 4: this is the tricky part, the area inside the piece is filled with black,
\r
2755 but if the start point is not inside the piece we're lost!
\r
2756 There should be a better way to do this... if we could create a region or path
\r
2757 from the fill operation we would be fine for example.
\r
2759 // FloodFill( hdc, squareSize / 2, squareSize / 2, RGB(0xFF,0xFF,0xFF) );
\r
2760 ExtFloodFill( hdc, squareSize / 2, squareSize / 2, RGB(0xFF,0xFF,0xFF), FLOODFILLBORDER );
\r
2762 { /* [HGM] shave off edges of mask, in an attempt to correct for the fact that FloodFill does not work correctly under Win XP */
\r
2763 HDC dc2 = CreateCompatibleDC( hdc_window );
\r
2764 HBITMAP bm2 = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
\r
2766 SelectObject( dc2, bm2 );
\r
2767 BitBlt( dc2, 0, 0, squareSize, squareSize, hdc, 0, 0, SRCCOPY ); // make copy
\r
2768 BitBlt( hdc, 0, 1, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );
\r
2769 BitBlt( hdc, 2, 1, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );
\r
2770 BitBlt( hdc, 1, 0, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );
\r
2771 BitBlt( hdc, 1, 2, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );
\r
2774 DeleteObject( bm2 );
\r
2777 SetTextColor( hdc, 0 );
\r
2779 Step 5: some fonts have "disconnected" areas that are skipped by the fill:
\r
2780 draw the piece again in black for safety.
\r
2782 TextOut( hdc, pt.x, pt.y, &pieceToFontChar[appData.allWhite && index >= (int)BlackPawn ? index - (int)BlackPawn : index], 1 );
\r
2784 SelectObject( hdc, hbm_old );
\r
2786 if( hPieceMask[index] != NULL ) {
\r
2787 DeleteObject( hPieceMask[index] );
\r
2790 hPieceMask[index] = hbm;
\r
2793 hbm = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
\r
2795 SelectObject( hdc, hbm );
\r
2798 HDC dc1 = CreateCompatibleDC( hdc_window );
\r
2799 HDC dc2 = CreateCompatibleDC( hdc_window );
\r
2800 HBITMAP bm2 = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
\r
2802 SelectObject( dc1, hPieceMask[index] );
\r
2803 SelectObject( dc2, bm2 );
\r
2804 FillRect( dc2, &rc, GetStockObject(WHITE_BRUSH) );
\r
2805 BitBlt( dc2, 0, 0, squareSize, squareSize, dc1, 0, 0, SRCINVERT );
\r
2808 Now dc2 contains the inverse of the piece mask, i.e. a mask that preserves
\r
2809 the piece background and deletes (makes transparent) the rest.
\r
2810 Thanks to that mask, we are free to paint the background with the greates
\r
2811 freedom, as we'll be able to mask off the unwanted parts when finished.
\r
2812 We use this, to make gradients and give the pieces a "roundish" look.
\r
2814 SetPieceBackground( hdc, backColor, 2 );
\r
2815 BitBlt( hdc, 0, 0, squareSize, squareSize, dc2, 0, 0, SRCAND );
\r
2819 DeleteObject( bm2 );
\r
2822 SetTextColor( hdc, foreColor );
\r
2823 TextOut( hdc, pt.x, pt.y, &pieceToFontChar[appData.allWhite && index >= (int)BlackPawn ? index - (int)BlackPawn : index], 1 );
\r
2825 SelectObject( hdc, hbm_old );
\r
2827 if( hPieceFace[index] != NULL ) {
\r
2828 DeleteObject( hPieceFace[index] );
\r
2831 hPieceFace[index] = hbm;
\r
2834 static int TranslatePieceToFontPiece( int piece )
\r
2864 case BlackMarshall:
\r
2868 case BlackNightrider:
\r
2874 case BlackUnicorn:
\r
2878 case BlackGrasshopper:
\r
2890 case BlackCardinal:
\r
2897 case WhiteMarshall:
\r
2901 case WhiteNightrider:
\r
2907 case WhiteUnicorn:
\r
2911 case WhiteGrasshopper:
\r
2923 case WhiteCardinal:
\r
2932 void CreatePiecesFromFont()
\r
2935 HDC hdc_window = NULL;
\r
2941 if( fontBitmapSquareSize < 0 ) {
\r
2942 /* Something went seriously wrong in the past: do not try to recreate fonts! */
\r
2946 if( appData.renderPiecesWithFont == NULL || appData.renderPiecesWithFont[0] == NULLCHAR || appData.renderPiecesWithFont[0] == '*' ) {
\r
2947 fontBitmapSquareSize = -1;
\r
2951 if( fontBitmapSquareSize != squareSize ) {
\r
2952 hdc_window = GetDC( hwndMain );
\r
2953 hdc = CreateCompatibleDC( hdc_window );
\r
2955 if( hPieceFont != NULL ) {
\r
2956 DeleteObject( hPieceFont );
\r
2959 for( i=0; i<=(int)BlackKing; i++ ) {
\r
2960 hPieceMask[i] = NULL;
\r
2961 hPieceFace[i] = NULL;
\r
2967 if( appData.fontPieceSize >= 50 && appData.fontPieceSize <= 150 ) {
\r
2968 fontHeight = appData.fontPieceSize;
\r
2971 fontHeight = (fontHeight * squareSize) / 100;
\r
2973 lf.lfHeight = -MulDiv( fontHeight, GetDeviceCaps(hdc, LOGPIXELSY), 72 );
\r
2975 lf.lfEscapement = 0;
\r
2976 lf.lfOrientation = 0;
\r
2977 lf.lfWeight = FW_NORMAL;
\r
2979 lf.lfUnderline = 0;
\r
2980 lf.lfStrikeOut = 0;
\r
2981 lf.lfCharSet = DEFAULT_CHARSET;
\r
2982 lf.lfOutPrecision = OUT_DEFAULT_PRECIS;
\r
2983 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
\r
2984 lf.lfQuality = PROOF_QUALITY;
\r
2985 lf.lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;
\r
2986 strncpy( lf.lfFaceName, appData.renderPiecesWithFont, sizeof(lf.lfFaceName) );
\r
2987 lf.lfFaceName[ sizeof(lf.lfFaceName) - 1 ] = '\0';
\r
2989 hPieceFont = CreateFontIndirect( &lf );
\r
2991 if( hPieceFont == NULL ) {
\r
2992 fontBitmapSquareSize = -2;
\r
2995 /* Setup font-to-piece character table */
\r
2996 if( ! SetCharTable(pieceToFontChar, appData.fontToPieceTable) ) {
\r
2997 /* No (or wrong) global settings, try to detect the font */
\r
2998 if( strstr(lf.lfFaceName,"Alpha") != NULL ) {
\r
3000 SetCharTable(pieceToFontChar, "phbrqkojntwl");
\r
3002 else if( strstr(lf.lfFaceName,"DiagramTT") != NULL ) {
\r
3003 /* DiagramTT* family */
\r
3004 SetCharTable(pieceToFontChar, "PNLRQKpnlrqk");
\r
3006 else if( strstr(lf.lfFaceName,"WinboardF") != NULL ) {
\r
3007 /* Fairy symbols */
\r
3008 SetCharTable(pieceToFontChar, "PNBRQFEACWMOHIJGDVSLUKpnbrqfeacwmohijgdvsluk");
\r
3010 else if( strstr(lf.lfFaceName,"GC2004D") != NULL ) {
\r
3011 /* Good Companion (Some characters get warped as literal :-( */
\r
3012 char s[] = "1cmWG0ñueOS¯®oYI23wgQU";
\r
3013 s[0]=0xB9; s[1]=0xA9; s[6]=0xB1; s[11]=0xBB; s[12]=0xAB; s[17]=0xB3;
\r
3014 SetCharTable(pieceToFontChar, s);
\r
3017 /* Cases, Condal, Leipzig, Lucena, Marroquin, Merida, Usual */
\r
3018 SetCharTable(pieceToFontChar, "pnbrqkomvtwl");
\r
3022 /* Create bitmaps */
\r
3023 hfont_old = SelectObject( hdc, hPieceFont );
\r
3025 CreatePieceMaskFromFont( hdc_window, hdc, PM_WP );
\r
3026 CreatePieceMaskFromFont( hdc_window, hdc, PM_WN );
\r
3027 CreatePieceMaskFromFont( hdc_window, hdc, PM_WB );
\r
3028 CreatePieceMaskFromFont( hdc_window, hdc, PM_WR );
\r
3029 CreatePieceMaskFromFont( hdc_window, hdc, PM_WQ );
\r
3030 CreatePieceMaskFromFont( hdc_window, hdc, PM_WK );
\r
3031 CreatePieceMaskFromFont( hdc_window, hdc, PM_BP );
\r
3032 CreatePieceMaskFromFont( hdc_window, hdc, PM_BN );
\r
3033 CreatePieceMaskFromFont( hdc_window, hdc, PM_BB );
\r
3034 CreatePieceMaskFromFont( hdc_window, hdc, PM_BR );
\r
3035 CreatePieceMaskFromFont( hdc_window, hdc, PM_BQ );
\r
3036 CreatePieceMaskFromFont( hdc_window, hdc, PM_BK );
\r
3038 CreatePieceMaskFromFont( hdc_window, hdc, PM_WA );
\r
3039 CreatePieceMaskFromFont( hdc_window, hdc, PM_WC );
\r
3040 CreatePieceMaskFromFont( hdc_window, hdc, PM_WF );
\r
3041 CreatePieceMaskFromFont( hdc_window, hdc, PM_WH );
\r
3042 CreatePieceMaskFromFont( hdc_window, hdc, PM_WE );
\r
3043 CreatePieceMaskFromFont( hdc_window, hdc, PM_WW );
\r
3044 CreatePieceMaskFromFont( hdc_window, hdc, PM_WU );
\r
3045 CreatePieceMaskFromFont( hdc_window, hdc, PM_WO );
\r
3046 CreatePieceMaskFromFont( hdc_window, hdc, PM_WG );
\r
3047 CreatePieceMaskFromFont( hdc_window, hdc, PM_WM );
\r
3048 CreatePieceMaskFromFont( hdc_window, hdc, PM_WSG );
\r
3049 CreatePieceMaskFromFont( hdc_window, hdc, PM_WV );
\r
3050 CreatePieceMaskFromFont( hdc_window, hdc, PM_WAB );
\r
3051 CreatePieceMaskFromFont( hdc_window, hdc, PM_WD );
\r
3052 CreatePieceMaskFromFont( hdc_window, hdc, PM_WL );
\r
3053 CreatePieceMaskFromFont( hdc_window, hdc, PM_WS );
\r
3054 CreatePieceMaskFromFont( hdc_window, hdc, PM_BA );
\r
3055 CreatePieceMaskFromFont( hdc_window, hdc, PM_BC );
\r
3056 CreatePieceMaskFromFont( hdc_window, hdc, PM_BF );
\r
3057 CreatePieceMaskFromFont( hdc_window, hdc, PM_BH );
\r
3058 CreatePieceMaskFromFont( hdc_window, hdc, PM_BE );
\r
3059 CreatePieceMaskFromFont( hdc_window, hdc, PM_BW );
\r
3060 CreatePieceMaskFromFont( hdc_window, hdc, PM_BU );
\r
3061 CreatePieceMaskFromFont( hdc_window, hdc, PM_BO );
\r
3062 CreatePieceMaskFromFont( hdc_window, hdc, PM_BG );
\r
3063 CreatePieceMaskFromFont( hdc_window, hdc, PM_BM );
\r
3064 CreatePieceMaskFromFont( hdc_window, hdc, PM_BSG );
\r
3065 CreatePieceMaskFromFont( hdc_window, hdc, PM_BV );
\r
3066 CreatePieceMaskFromFont( hdc_window, hdc, PM_BAB );
\r
3067 CreatePieceMaskFromFont( hdc_window, hdc, PM_BD );
\r
3068 CreatePieceMaskFromFont( hdc_window, hdc, PM_BL );
\r
3069 CreatePieceMaskFromFont( hdc_window, hdc, PM_BS );
\r
3071 for(i=(int)WhitePawn; i<(int)EmptySquare; i++) /* [HGM] made a loop for this */
\r
3072 if(PieceToChar((ChessSquare)i) != '.') /* skip unused pieces */
\r
3073 CreatePieceMaskFromFont( hdc_window, hdc, i );
\r
3075 SelectObject( hdc, hfont_old );
\r
3077 fontBitmapSquareSize = squareSize;
\r
3081 if( hdc != NULL ) {
\r
3085 if( hdc_window != NULL ) {
\r
3086 ReleaseDC( hwndMain, hdc_window );
\r
3091 DoLoadBitmap(HINSTANCE hinst, char *piece, int squareSize, char *suffix)
\r
3095 sprintf(name, "%s%d%s", piece, squareSize, suffix);
\r
3096 if (gameInfo.event &&
\r
3097 strcmp(gameInfo.event, "Easter Egg Hunt") == 0 &&
\r
3098 strcmp(name, "k80s") == 0) {
\r
3099 strcpy(name, "tim");
\r
3101 return LoadBitmap(hinst, name);
\r
3105 /* Insert a color into the program's logical palette
\r
3106 structure. This code assumes the given color is
\r
3107 the result of the RGB or PALETTERGB macro, and it
\r
3108 knows how those macros work (which is documented).
\r
3111 InsertInPalette(COLORREF color)
\r
3113 LPPALETTEENTRY pe = &(pLogPal->palPalEntry[pLogPal->palNumEntries]);
\r
3115 if (pLogPal->palNumEntries++ >= PALETTESIZE) {
\r
3116 DisplayFatalError("Too many colors", 0, 1);
\r
3117 pLogPal->palNumEntries--;
\r
3121 pe->peFlags = (char) 0;
\r
3122 pe->peRed = (char) (0xFF & color);
\r
3123 pe->peGreen = (char) (0xFF & (color >> 8));
\r
3124 pe->peBlue = (char) (0xFF & (color >> 16));
\r
3130 InitDrawingColors()
\r
3132 if (pLogPal == NULL) {
\r
3133 /* Allocate enough memory for a logical palette with
\r
3134 * PALETTESIZE entries and set the size and version fields
\r
3135 * of the logical palette structure.
\r
3137 pLogPal = (NPLOGPALETTE)
\r
3138 LocalAlloc(LMEM_FIXED, (sizeof(LOGPALETTE) +
\r
3139 (sizeof(PALETTEENTRY) * (PALETTESIZE))));
\r
3140 pLogPal->palVersion = 0x300;
\r
3142 pLogPal->palNumEntries = 0;
\r
3144 InsertInPalette(lightSquareColor);
\r
3145 InsertInPalette(darkSquareColor);
\r
3146 InsertInPalette(whitePieceColor);
\r
3147 InsertInPalette(blackPieceColor);
\r
3148 InsertInPalette(highlightSquareColor);
\r
3149 InsertInPalette(premoveHighlightColor);
\r
3151 /* create a logical color palette according the information
\r
3152 * in the LOGPALETTE structure.
\r
3154 hPal = CreatePalette((LPLOGPALETTE) pLogPal);
\r
3156 lightSquareBrush = CreateSolidBrush(lightSquareColor);
\r
3157 blackSquareBrush = CreateSolidBrush(blackPieceColor);
\r
3158 darkSquareBrush = CreateSolidBrush(darkSquareColor);
\r
3159 whitePieceBrush = CreateSolidBrush(whitePieceColor);
\r
3160 blackPieceBrush = CreateSolidBrush(blackPieceColor);
\r
3161 iconBkgndBrush = CreateSolidBrush(GetSysColor(COLOR_BACKGROUND));
\r
3162 explodeBrush = CreateSolidBrush(highlightSquareColor); // [HGM] atomic
\r
3163 /* [AS] Force rendering of the font-based pieces */
\r
3164 if( fontBitmapSquareSize > 0 ) {
\r
3165 fontBitmapSquareSize = 0;
\r
3171 BoardWidth(int boardSize, int n)
\r
3172 { /* [HGM] argument n added to allow different width and height */
\r
3173 int lineGap = sizeInfo[boardSize].lineGap;
\r
3175 if( appData.overrideLineGap >= 0 && appData.overrideLineGap <= 5 ) {
\r
3176 lineGap = appData.overrideLineGap;
\r
3179 return (n + 1) * lineGap +
\r
3180 n * sizeInfo[boardSize].squareSize;
\r
3183 /* Respond to board resize by dragging edge */
\r
3185 ResizeBoard(int newSizeX, int newSizeY, int flags)
\r
3187 BoardSize newSize = NUM_SIZES - 1;
\r
3188 static int recurse = 0;
\r
3189 if (IsIconic(hwndMain)) return;
\r
3190 if (recurse > 0) return;
\r
3192 while (newSize > 0) {
\r
3193 InitDrawingSizes(newSize+1000, 0); // [HGM] kludge to update sizeInfo without visible effects
\r
3194 if(newSizeX >= sizeInfo[newSize].cliWidth &&
\r
3195 newSizeY >= sizeInfo[newSize].cliHeight) break;
\r
3198 boardSize = newSize;
\r
3199 InitDrawingSizes(boardSize, flags);
\r
3206 InitDrawingSizes(BoardSize boardSize, int flags)
\r
3208 int i, boardWidth, boardHeight; /* [HGM] height treated separately */
\r
3209 ChessSquare piece;
\r
3210 static int oldBoardSize = -1, oldTinyLayout = 0;
\r
3212 SIZE clockSize, messageSize;
\r
3214 char buf[MSG_SIZ];
\r
3216 HMENU hmenu = GetMenu(hwndMain);
\r
3217 RECT crect, wrect, oldRect;
\r
3219 LOGBRUSH logbrush;
\r
3221 int suppressVisibleEffects = 0; // [HGM] kludge to request updating sizeInfo only
\r
3222 if((int)boardSize >= 1000 ) { boardSize -= 1000; suppressVisibleEffects = 1; }
\r
3224 /* [HGM] call with -2 uses old size (for if nr of files, ranks changes) */
\r
3225 if(boardSize == (BoardSize)(-2) ) boardSize = oldBoardSize;
\r
3227 oldRect.left = boardX; //[HGM] placement: remember previous window params
\r
3228 oldRect.top = boardY;
\r
3229 oldRect.right = boardX + winWidth;
\r
3230 oldRect.bottom = boardY + winHeight;
\r
3232 tinyLayout = sizeInfo[boardSize].tinyLayout;
\r
3233 smallLayout = sizeInfo[boardSize].smallLayout;
\r
3234 squareSize = sizeInfo[boardSize].squareSize;
\r
3235 lineGap = sizeInfo[boardSize].lineGap;
\r
3236 minorSize = 0; /* [HGM] Kludge to see if demagnified pieces need to be shifted */
\r
3238 if( appData.overrideLineGap >= 0 && appData.overrideLineGap <= 5 ) {
\r
3239 lineGap = appData.overrideLineGap;
\r
3242 if (tinyLayout != oldTinyLayout) {
\r
3243 long style = GetWindowLong(hwndMain, GWL_STYLE);
\r
3245 style &= ~WS_SYSMENU;
\r
3246 InsertMenu(hmenu, IDM_Exit, MF_BYCOMMAND, IDM_Minimize,
\r
3247 "&Minimize\tCtrl+F4");
\r
3249 style |= WS_SYSMENU;
\r
3250 RemoveMenu(hmenu, IDM_Minimize, MF_BYCOMMAND);
\r
3252 SetWindowLong(hwndMain, GWL_STYLE, style);
\r
3254 for (i=0; menuBarText[tinyLayout][i]; i++) {
\r
3255 ModifyMenu(hmenu, i, MF_STRING|MF_BYPOSITION|MF_POPUP,
\r
3256 (UINT)GetSubMenu(hmenu, i), menuBarText[tinyLayout][i]);
\r
3258 DrawMenuBar(hwndMain);
\r
3261 boardWidth = BoardWidth(boardSize, BOARD_WIDTH);
\r
3262 boardHeight = BoardWidth(boardSize, BOARD_HEIGHT);
\r
3264 /* Get text area sizes */
\r
3265 hdc = GetDC(hwndMain);
\r
3266 if (appData.clockMode) {
\r
3267 sprintf(buf, "White: %s", TimeString(23*60*60*1000L));
\r
3269 sprintf(buf, "White");
\r
3271 oldFont = SelectObject(hdc, font[boardSize][CLOCK_FONT]->hf);
\r
3272 GetTextExtentPoint(hdc, buf, strlen(buf), &clockSize);
\r
3273 SelectObject(hdc, font[boardSize][MESSAGE_FONT]->hf);
\r
3274 str = "We only care about the height here";
\r
3275 GetTextExtentPoint(hdc, str, strlen(str), &messageSize);
\r
3276 SelectObject(hdc, oldFont);
\r
3277 ReleaseDC(hwndMain, hdc);
\r
3279 /* Compute where everything goes */
\r
3280 if((first.programLogo || second.programLogo) && !tinyLayout) {
\r
3281 /* [HGM] logo: if either logo is on, reserve space for it */
\r
3282 logoHeight = 2*clockSize.cy;
\r
3283 leftLogoRect.left = OUTER_MARGIN;
\r
3284 leftLogoRect.right = leftLogoRect.left + 4*clockSize.cy;
\r
3285 leftLogoRect.top = OUTER_MARGIN;
\r
3286 leftLogoRect.bottom = OUTER_MARGIN + logoHeight;
\r
3288 rightLogoRect.right = OUTER_MARGIN + boardWidth;
\r
3289 rightLogoRect.left = rightLogoRect.right - 4*clockSize.cy;
\r
3290 rightLogoRect.top = OUTER_MARGIN;
\r
3291 rightLogoRect.bottom = OUTER_MARGIN + logoHeight;
\r
3294 whiteRect.left = leftLogoRect.right;
\r
3295 whiteRect.right = OUTER_MARGIN + boardWidth/2 - INNER_MARGIN/2;
\r
3296 whiteRect.top = OUTER_MARGIN;
\r
3297 whiteRect.bottom = whiteRect.top + logoHeight;
\r
3299 blackRect.right = rightLogoRect.left;
\r
3300 blackRect.left = whiteRect.right + INNER_MARGIN;
\r
3301 blackRect.top = whiteRect.top;
\r
3302 blackRect.bottom = whiteRect.bottom;
\r
3304 whiteRect.left = OUTER_MARGIN;
\r
3305 whiteRect.right = whiteRect.left + boardWidth/2 - INNER_MARGIN/2;
\r
3306 whiteRect.top = OUTER_MARGIN;
\r
3307 whiteRect.bottom = whiteRect.top + clockSize.cy;
\r
3309 blackRect.left = whiteRect.right + INNER_MARGIN;
\r
3310 blackRect.right = blackRect.left + boardWidth/2 - 1;
\r
3311 blackRect.top = whiteRect.top;
\r
3312 blackRect.bottom = whiteRect.bottom;
\r
3315 messageRect.left = OUTER_MARGIN + MESSAGE_LINE_LEFTMARGIN;
\r
3316 if (appData.showButtonBar) {
\r
3317 messageRect.right = OUTER_MARGIN + boardWidth // [HGM] logo: expressed independent of clock placement
\r
3318 - N_BUTTONS*BUTTON_WIDTH - MESSAGE_LINE_LEFTMARGIN;
\r
3320 messageRect.right = OUTER_MARGIN + boardWidth;
\r
3322 messageRect.top = whiteRect.bottom + INNER_MARGIN;
\r
3323 messageRect.bottom = messageRect.top + messageSize.cy;
\r
3325 boardRect.left = OUTER_MARGIN;
\r
3326 boardRect.right = boardRect.left + boardWidth;
\r
3327 boardRect.top = messageRect.bottom + INNER_MARGIN;
\r
3328 boardRect.bottom = boardRect.top + boardHeight;
\r
3330 sizeInfo[boardSize].cliWidth = boardRect.right + OUTER_MARGIN;
\r
3331 sizeInfo[boardSize].cliHeight = boardRect.bottom + OUTER_MARGIN;
\r
3332 oldBoardSize = boardSize;
\r
3333 oldTinyLayout = tinyLayout;
\r
3334 winW = 2 * GetSystemMetrics(SM_CXFRAME) + boardRect.right + OUTER_MARGIN;
\r
3335 winH = 2 * GetSystemMetrics(SM_CYFRAME) + GetSystemMetrics(SM_CYMENU) +
\r
3336 GetSystemMetrics(SM_CYCAPTION) + boardRect.bottom + OUTER_MARGIN;
\r
3337 if(suppressVisibleEffects) return; // [HGM] when called for filling sizeInfo only
\r
3338 winWidth = winW; // [HGM] placement: set through temporary which can used by initial sizing choice
\r
3339 winHeight = winH; // without disturbing window attachments
\r
3340 GetWindowRect(hwndMain, &wrect);
\r
3341 SetWindowPos(hwndMain, NULL, 0, 0, winWidth, winHeight,
\r
3342 SWP_NOCOPYBITS|SWP_NOZORDER|SWP_NOMOVE);
\r
3344 // [HGM] placement: let attached windows follow size change.
\r
3345 ReattachAfterSize( &oldRect, winWidth, winHeight, moveHistoryDialog, &wpMoveHistory );
\r
3346 ReattachAfterSize( &oldRect, winWidth, winHeight, evalGraphDialog, &wpEvalGraph );
\r
3347 ReattachAfterSize( &oldRect, winWidth, winHeight, engineOutputDialog, &wpEngineOutput );
\r
3348 ReattachAfterSize( &oldRect, winWidth, winHeight, gameListDialog, &wpGameList );
\r
3349 ReattachAfterSize( &oldRect, winWidth, winHeight, hwndConsole, &wpConsole );
\r
3351 /* compensate if menu bar wrapped */
\r
3352 GetClientRect(hwndMain, &crect);
\r
3353 offby = boardRect.bottom + OUTER_MARGIN - crect.bottom;
\r
3354 winHeight += offby;
\r
3356 case WMSZ_TOPLEFT:
\r
3357 SetWindowPos(hwndMain, NULL,
\r
3358 wrect.right - winWidth, wrect.bottom - winHeight,
\r
3359 winWidth, winHeight, SWP_NOCOPYBITS|SWP_NOZORDER);
\r
3362 case WMSZ_TOPRIGHT:
\r
3364 SetWindowPos(hwndMain, NULL,
\r
3365 wrect.left, wrect.bottom - winHeight,
\r
3366 winWidth, winHeight, SWP_NOCOPYBITS|SWP_NOZORDER);
\r
3369 case WMSZ_BOTTOMLEFT:
\r
3371 SetWindowPos(hwndMain, NULL,
\r
3372 wrect.right - winWidth, wrect.top,
\r
3373 winWidth, winHeight, SWP_NOCOPYBITS|SWP_NOZORDER);
\r
3376 case WMSZ_BOTTOMRIGHT:
\r
3380 SetWindowPos(hwndMain, NULL, 0, 0, winWidth, winHeight,
\r
3381 SWP_NOCOPYBITS|SWP_NOZORDER|SWP_NOMOVE);
\r
3386 for (i = 0; i < N_BUTTONS; i++) {
\r
3387 if (buttonDesc[i].hwnd != NULL) {
\r
3388 DestroyWindow(buttonDesc[i].hwnd);
\r
3389 buttonDesc[i].hwnd = NULL;
\r
3391 if (appData.showButtonBar) {
\r
3392 buttonDesc[i].hwnd =
\r
3393 CreateWindow("BUTTON", buttonDesc[i].label,
\r
3394 WS_VISIBLE | WS_CHILD | BS_PUSHBUTTON,
\r
3395 boardRect.right - BUTTON_WIDTH*(N_BUTTONS-i),
\r
3396 messageRect.top, BUTTON_WIDTH, messageSize.cy, hwndMain,
\r
3397 (HMENU) buttonDesc[i].id,
\r
3398 (HINSTANCE) GetWindowLong(hwndMain, GWL_HINSTANCE), NULL);
\r
3400 SendMessage(buttonDesc[i].hwnd, WM_SETFONT,
\r
3401 (WPARAM)font[boardSize][MESSAGE_FONT]->hf,
\r
3402 MAKELPARAM(FALSE, 0));
\r
3404 if (buttonDesc[i].id == IDM_Pause)
\r
3405 hwndPause = buttonDesc[i].hwnd;
\r
3406 buttonDesc[i].wndproc = (WNDPROC)
\r
3407 SetWindowLong(buttonDesc[i].hwnd, GWL_WNDPROC, (LONG) ButtonProc);
\r
3410 if (gridPen != NULL) DeleteObject(gridPen);
\r
3411 if (highlightPen != NULL) DeleteObject(highlightPen);
\r
3412 if (premovePen != NULL) DeleteObject(premovePen);
\r
3413 if (lineGap != 0) {
\r
3414 logbrush.lbStyle = BS_SOLID;
\r
3415 logbrush.lbColor = RGB(0, 0, 0); /* grid pen color = black */
\r
3417 ExtCreatePen(PS_GEOMETRIC|PS_SOLID|PS_ENDCAP_FLAT|PS_JOIN_MITER,
\r
3418 lineGap, &logbrush, 0, NULL);
\r
3419 logbrush.lbColor = highlightSquareColor;
\r
3421 ExtCreatePen(PS_GEOMETRIC|PS_SOLID|PS_ENDCAP_FLAT|PS_JOIN_MITER,
\r
3422 lineGap, &logbrush, 0, NULL);
\r
3424 logbrush.lbColor = premoveHighlightColor;
\r
3426 ExtCreatePen(PS_GEOMETRIC|PS_SOLID|PS_ENDCAP_FLAT|PS_JOIN_MITER,
\r
3427 lineGap, &logbrush, 0, NULL);
\r
3429 /* [HGM] Loop had to be split in part for vert. and hor. lines */
\r
3430 for (i = 0; i < BOARD_HEIGHT + 1; i++) {
\r
3431 gridEndpoints[i*2].x = boardRect.left + lineGap / 2;
\r
3432 gridEndpoints[i*2].y = gridEndpoints[i*2 + 1].y =
\r
3433 boardRect.top + lineGap / 2 + (i * (squareSize + lineGap));
\r
3434 gridEndpoints[i*2 + 1].x = boardRect.left + lineGap / 2 +
\r
3435 BOARD_WIDTH * (squareSize + lineGap);
\r
3436 gridVertexCounts[i*2] = gridVertexCounts[i*2 + 1] = 2;
\r
3438 for (i = 0; i < BOARD_WIDTH + 1; i++) {
\r
3439 gridEndpoints[i*2 + BOARD_HEIGHT*2 + 2].y = boardRect.top + lineGap / 2;
\r
3440 gridEndpoints[i*2 + BOARD_HEIGHT*2 + 2].x =
\r
3441 gridEndpoints[i*2 + 1 + BOARD_HEIGHT*2 + 2].x = boardRect.left +
\r
3442 lineGap / 2 + (i * (squareSize + lineGap));
\r
3443 gridEndpoints[i*2 + 1 + BOARD_HEIGHT*2 + 2].y =
\r
3444 boardRect.top + BOARD_HEIGHT * (squareSize + lineGap);
\r
3445 gridVertexCounts[i*2] = gridVertexCounts[i*2 + 1] = 2;
\r
3449 /* [HGM] Licensing requirement */
\r
3451 if(gameInfo.variant == VariantGothic) GothicPopUp( GOTHIC, VariantGothic); else
\r
3454 if(gameInfo.variant == VariantFalcon) GothicPopUp( FALCON, VariantFalcon); else
\r
3456 GothicPopUp( "", VariantNormal);
\r
3459 /* if (boardSize == oldBoardSize) return; [HGM] variant might have changed */
\r
3461 /* Load piece bitmaps for this board size */
\r
3462 for (i=0; i<=2; i++) {
\r
3463 for (piece = WhitePawn;
\r
3464 (int) piece < (int) BlackPawn;
\r
3465 piece = (ChessSquare) ((int) piece + 1)) {
\r
3466 if (pieceBitmap[i][piece] != NULL)
\r
3467 DeleteObject(pieceBitmap[i][piece]);
\r
3471 fontBitmapSquareSize = 0; /* [HGM] render: make sure pieces will be recreated, as we might need others now */
\r
3472 // Orthodox Chess pieces
\r
3473 pieceBitmap[0][WhitePawn] = DoLoadBitmap(hInst, "p", squareSize, "s");
\r
3474 pieceBitmap[0][WhiteKnight] = DoLoadBitmap(hInst, "n", squareSize, "s");
\r
3475 pieceBitmap[0][WhiteBishop] = DoLoadBitmap(hInst, "b", squareSize, "s");
\r
3476 pieceBitmap[0][WhiteRook] = DoLoadBitmap(hInst, "r", squareSize, "s");
\r
3477 pieceBitmap[0][WhiteKing] = DoLoadBitmap(hInst, "k", squareSize, "s");
\r
3478 pieceBitmap[1][WhitePawn] = DoLoadBitmap(hInst, "p", squareSize, "o");
\r
3479 pieceBitmap[1][WhiteKnight] = DoLoadBitmap(hInst, "n", squareSize, "o");
\r
3480 pieceBitmap[1][WhiteBishop] = DoLoadBitmap(hInst, "b", squareSize, "o");
\r
3481 pieceBitmap[1][WhiteRook] = DoLoadBitmap(hInst, "r", squareSize, "o");
\r
3482 pieceBitmap[1][WhiteKing] = DoLoadBitmap(hInst, "k", squareSize, "o");
\r
3483 pieceBitmap[2][WhitePawn] = DoLoadBitmap(hInst, "p", squareSize, "w");
\r
3484 pieceBitmap[2][WhiteKnight] = DoLoadBitmap(hInst, "n", squareSize, "w");
\r
3485 pieceBitmap[2][WhiteBishop] = DoLoadBitmap(hInst, "b", squareSize, "w");
\r
3486 pieceBitmap[2][WhiteRook] = DoLoadBitmap(hInst, "r", squareSize, "w");
\r
3487 pieceBitmap[2][WhiteKing] = DoLoadBitmap(hInst, "k", squareSize, "w");
\r
3488 if( !strcmp(appData.variant, "shogi") && (squareSize==72 || squareSize==49)) {
\r
3489 // in Shogi, Hijack the unused Queen for Lance
\r
3490 pieceBitmap[0][WhiteQueen] = DoLoadBitmap(hInst, "l", squareSize, "s");
\r
3491 pieceBitmap[1][WhiteQueen] = DoLoadBitmap(hInst, "l", squareSize, "o");
\r
3492 pieceBitmap[2][WhiteQueen] = DoLoadBitmap(hInst, "l", squareSize, "w");
\r
3494 pieceBitmap[0][WhiteQueen] = DoLoadBitmap(hInst, "q", squareSize, "s");
\r
3495 pieceBitmap[1][WhiteQueen] = DoLoadBitmap(hInst, "q", squareSize, "o");
\r
3496 pieceBitmap[2][WhiteQueen] = DoLoadBitmap(hInst, "q", squareSize, "w");
\r
3499 if(squareSize <= 72 && squareSize >= 33) {
\r
3500 /* A & C are available in most sizes now */
\r
3501 if(squareSize != 49 && squareSize != 72 && squareSize != 33) { // Vortex-like
\r
3502 pieceBitmap[0][WhiteAngel] = DoLoadBitmap(hInst, "a", squareSize, "s");
\r
3503 pieceBitmap[1][WhiteAngel] = DoLoadBitmap(hInst, "a", squareSize, "o");
\r
3504 pieceBitmap[2][WhiteAngel] = DoLoadBitmap(hInst, "a", squareSize, "w");
\r
3505 pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "s");
\r
3506 pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "o");
\r
3507 pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "w");
\r
3508 pieceBitmap[0][WhiteCobra] = DoLoadBitmap(hInst, "cv", squareSize, "s");
\r
3509 pieceBitmap[1][WhiteCobra] = DoLoadBitmap(hInst, "cv", squareSize, "o");
\r
3510 pieceBitmap[2][WhiteCobra] = DoLoadBitmap(hInst, "cv", squareSize, "w");
\r
3511 pieceBitmap[0][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "s");
\r
3512 pieceBitmap[1][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "o");
\r
3513 pieceBitmap[2][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "w");
\r
3514 } else { // Smirf-like
\r
3515 pieceBitmap[0][WhiteAngel] = DoLoadBitmap(hInst, "aa", squareSize, "s");
\r
3516 pieceBitmap[1][WhiteAngel] = DoLoadBitmap(hInst, "aa", squareSize, "o");
\r
3517 pieceBitmap[2][WhiteAngel] = DoLoadBitmap(hInst, "aa", squareSize, "w");
\r
3519 if(gameInfo.variant == VariantGothic) { // Vortex-like
\r
3520 pieceBitmap[0][WhiteMarshall] = DoLoadBitmap(hInst, "cv", squareSize, "s");
\r
3521 pieceBitmap[1][WhiteMarshall] = DoLoadBitmap(hInst, "cv", squareSize, "o");
\r
3522 pieceBitmap[2][WhiteMarshall] = DoLoadBitmap(hInst, "cv", squareSize, "w");
\r
3523 } else { // WinBoard standard
\r
3524 pieceBitmap[0][WhiteMarshall] = DoLoadBitmap(hInst, "c", squareSize, "s");
\r
3525 pieceBitmap[1][WhiteMarshall] = DoLoadBitmap(hInst, "c", squareSize, "o");
\r
3526 pieceBitmap[2][WhiteMarshall] = DoLoadBitmap(hInst, "c", squareSize, "w");
\r
3531 if(squareSize==72 || squareSize==49 || squareSize==33) { /* experiment with some home-made bitmaps */
\r
3532 pieceBitmap[0][WhiteFerz] = DoLoadBitmap(hInst, "f", squareSize, "s");
\r
3533 pieceBitmap[1][WhiteFerz] = DoLoadBitmap(hInst, "f", squareSize, "o");
\r
3534 pieceBitmap[2][WhiteFerz] = DoLoadBitmap(hInst, "f", squareSize, "w");
\r
3535 pieceBitmap[0][WhiteWazir] = DoLoadBitmap(hInst, "w", squareSize, "s");
\r
3536 pieceBitmap[1][WhiteWazir] = DoLoadBitmap(hInst, "w", squareSize, "o");
\r
3537 pieceBitmap[2][WhiteWazir] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
3538 pieceBitmap[0][WhiteAlfil] = DoLoadBitmap(hInst, "e", squareSize, "s");
\r
3539 pieceBitmap[1][WhiteAlfil] = DoLoadBitmap(hInst, "e", squareSize, "o");
\r
3540 pieceBitmap[2][WhiteAlfil] = DoLoadBitmap(hInst, "e", squareSize, "w");
\r
3541 pieceBitmap[0][WhiteMan] = DoLoadBitmap(hInst, "m", squareSize, "s");
\r
3542 pieceBitmap[1][WhiteMan] = DoLoadBitmap(hInst, "m", squareSize, "o");
\r
3543 pieceBitmap[2][WhiteMan] = DoLoadBitmap(hInst, "m", squareSize, "w");
\r
3544 pieceBitmap[0][WhiteCardinal] = DoLoadBitmap(hInst, "a", squareSize, "s");
\r
3545 pieceBitmap[1][WhiteCardinal] = DoLoadBitmap(hInst, "a", squareSize, "o");
\r
3546 pieceBitmap[2][WhiteCardinal] = DoLoadBitmap(hInst, "a", squareSize, "w");
\r
3547 pieceBitmap[0][WhiteDragon] = DoLoadBitmap(hInst, "dk", squareSize, "s");
\r
3548 pieceBitmap[1][WhiteDragon] = DoLoadBitmap(hInst, "dk", squareSize, "o");
\r
3549 pieceBitmap[2][WhiteDragon] = DoLoadBitmap(hInst, "dk", squareSize, "w");
\r
3550 pieceBitmap[0][WhiteFalcon] = DoLoadBitmap(hInst, "v", squareSize, "s");
\r
3551 pieceBitmap[1][WhiteFalcon] = DoLoadBitmap(hInst, "v", squareSize, "o");
\r
3552 pieceBitmap[2][WhiteFalcon] = DoLoadBitmap(hInst, "v", squareSize, "w");
\r
3553 pieceBitmap[0][WhiteCobra] = DoLoadBitmap(hInst, "s", squareSize, "s");
\r
3554 pieceBitmap[1][WhiteCobra] = DoLoadBitmap(hInst, "s", squareSize, "o");
\r
3555 pieceBitmap[2][WhiteCobra] = DoLoadBitmap(hInst, "s", squareSize, "w");
\r
3556 pieceBitmap[0][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "s");
\r
3557 pieceBitmap[1][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "o");
\r
3558 pieceBitmap[2][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "w");
\r
3559 pieceBitmap[0][WhiteUnicorn] = DoLoadBitmap(hInst, "u", squareSize, "s");
\r
3560 pieceBitmap[1][WhiteUnicorn] = DoLoadBitmap(hInst, "u", squareSize, "o");
\r
3561 pieceBitmap[2][WhiteUnicorn] = DoLoadBitmap(hInst, "u", squareSize, "w");
\r
3563 if(gameInfo.variant == VariantShogi) { /* promoted Gold represemtations */
\r
3564 pieceBitmap[0][WhiteCannon] = DoLoadBitmap(hInst, "wp", squareSize, "s");
\r
3565 pieceBitmap[1][WhiteCannon] = DoLoadBitmap(hInst, "wp", squareSize, "o");
\r
3566 pieceBitmap[2][WhiteCannon] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
3567 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "wn", squareSize, "s");
\r
3568 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "wn", squareSize, "o");
\r
3569 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
3570 pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "ws", squareSize, "s");
\r
3571 pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "ws", squareSize, "o");
\r
3572 pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
3573 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "wl", squareSize, "s");
\r
3574 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "wl", squareSize, "o");
\r
3575 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
3577 pieceBitmap[0][WhiteCannon] = DoLoadBitmap(hInst, "o", squareSize, "s");
\r
3578 pieceBitmap[1][WhiteCannon] = DoLoadBitmap(hInst, "o", squareSize, "o");
\r
3579 pieceBitmap[2][WhiteCannon] = DoLoadBitmap(hInst, "o", squareSize, "w");
\r
3580 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "h", squareSize, "s");
\r
3581 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "h", squareSize, "o");
\r
3582 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "h", squareSize, "w");
\r
3583 pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "s");
\r
3584 pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "o");
\r
3585 pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "w");
\r
3586 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "g", squareSize, "s");
\r
3587 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "g", squareSize, "o");
\r
3588 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "g", squareSize, "w");
\r
3591 } else { /* other size, no special bitmaps available. Use smaller symbols */
\r
3592 if((int)boardSize < 2) minorSize = sizeInfo[0].squareSize;
\r
3593 else minorSize = sizeInfo[(int)boardSize - 2].squareSize;
\r
3594 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "n", minorSize, "s");
\r
3595 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "n", minorSize, "o");
\r
3596 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "n", minorSize, "w");
\r
3597 pieceBitmap[0][WhiteCardinal] = DoLoadBitmap(hInst, "b", minorSize, "s");
\r
3598 pieceBitmap[1][WhiteCardinal] = DoLoadBitmap(hInst, "b", minorSize, "o");
\r
3599 pieceBitmap[2][WhiteCardinal] = DoLoadBitmap(hInst, "b", minorSize, "w");
\r
3600 pieceBitmap[0][WhiteDragon] = DoLoadBitmap(hInst, "r", minorSize, "s");
\r
3601 pieceBitmap[1][WhiteDragon] = DoLoadBitmap(hInst, "r", minorSize, "o");
\r
3602 pieceBitmap[2][WhiteDragon] = DoLoadBitmap(hInst, "r", minorSize, "w");
\r
3603 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "q", minorSize, "s");
\r
3604 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "q", minorSize, "o");
\r
3605 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "q", minorSize, "w");
\r
3609 if(gameInfo.variant == VariantShogi && squareSize == 58)
\r
3610 /* special Shogi support in this size */
\r
3611 { for (i=0; i<=2; i++) { /* replace all bitmaps */
\r
3612 for (piece = WhitePawn;
\r
3613 (int) piece < (int) BlackPawn;
\r
3614 piece = (ChessSquare) ((int) piece + 1)) {
\r
3615 if (pieceBitmap[i][piece] != NULL)
\r
3616 DeleteObject(pieceBitmap[i][piece]);
\r
3619 pieceBitmap[0][WhitePawn] = DoLoadBitmap(hInst, "sp", squareSize, "o");
\r
3620 pieceBitmap[0][WhiteKnight] = DoLoadBitmap(hInst, "sn", squareSize, "o");
\r
3621 pieceBitmap[0][WhiteBishop] = DoLoadBitmap(hInst, "sb", squareSize, "o");
\r
3622 pieceBitmap[0][WhiteRook] = DoLoadBitmap(hInst, "sr", squareSize, "o");
\r
3623 pieceBitmap[0][WhiteQueen] = DoLoadBitmap(hInst, "sl", squareSize, "o");
\r
3624 pieceBitmap[0][WhiteKing] = DoLoadBitmap(hInst, "sk", squareSize, "o");
\r
3625 pieceBitmap[0][WhiteFerz] = DoLoadBitmap(hInst, "sf", squareSize, "o");
\r
3626 pieceBitmap[0][WhiteWazir] = DoLoadBitmap(hInst, "sw", squareSize, "o");
\r
3627 pieceBitmap[0][WhiteCannon] = DoLoadBitmap(hInst, "su", squareSize, "o");
\r
3628 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "sh", squareSize, "o");
\r
3629 pieceBitmap[0][WhiteCardinal] = DoLoadBitmap(hInst, "sa", squareSize, "o");
\r
3630 pieceBitmap[0][WhiteDragon] = DoLoadBitmap(hInst, "sc", squareSize, "o");
\r
3631 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "sg", squareSize, "o");
\r
3632 pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "ss", squareSize, "o");
\r
3633 pieceBitmap[1][WhitePawn] = DoLoadBitmap(hInst, "sp", squareSize, "o");
\r
3634 pieceBitmap[1][WhiteKnight] = DoLoadBitmap(hInst, "sn", squareSize, "o");
\r
3635 pieceBitmap[1][WhiteBishop] = DoLoadBitmap(hInst, "sb", squareSize, "o");
\r
3636 pieceBitmap[1][WhiteRook] = DoLoadBitmap(hInst, "sr", squareSize, "o");
\r
3637 pieceBitmap[1][WhiteQueen] = DoLoadBitmap(hInst, "sl", squareSize, "o");
\r
3638 pieceBitmap[1][WhiteKing] = DoLoadBitmap(hInst, "sk", squareSize, "o");
\r
3639 pieceBitmap[1][WhiteFerz] = DoLoadBitmap(hInst, "sf", squareSize, "o");
\r
3640 pieceBitmap[1][WhiteWazir] = DoLoadBitmap(hInst, "sw", squareSize, "o");
\r
3641 pieceBitmap[1][WhiteCannon] = DoLoadBitmap(hInst, "su", squareSize, "o");
\r
3642 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "sh", squareSize, "o");
\r
3643 pieceBitmap[1][WhiteCardinal] = DoLoadBitmap(hInst, "sa", squareSize, "o");
\r
3644 pieceBitmap[1][WhiteDragon] = DoLoadBitmap(hInst, "sc", squareSize, "o");
\r
3645 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "sg", squareSize, "o");
\r
3646 pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "ss", squareSize, "o");
\r
3647 pieceBitmap[2][WhitePawn] = DoLoadBitmap(hInst, "sp", squareSize, "w");
\r
3648 pieceBitmap[2][WhiteKnight] = DoLoadBitmap(hInst, "sn", squareSize, "w");
\r
3649 pieceBitmap[2][WhiteBishop] = DoLoadBitmap(hInst, "sr", squareSize, "w");
\r
3650 pieceBitmap[2][WhiteRook] = DoLoadBitmap(hInst, "sr", squareSize, "w");
\r
3651 pieceBitmap[2][WhiteQueen] = DoLoadBitmap(hInst, "sl", squareSize, "w");
\r
3652 pieceBitmap[2][WhiteKing] = DoLoadBitmap(hInst, "sk", squareSize, "w");
\r
3653 pieceBitmap[2][WhiteFerz] = DoLoadBitmap(hInst, "sw", squareSize, "w");
\r
3654 pieceBitmap[2][WhiteWazir] = DoLoadBitmap(hInst, "sw", squareSize, "w");
\r
3655 pieceBitmap[2][WhiteCannon] = DoLoadBitmap(hInst, "sp", squareSize, "w");
\r
3656 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "sn", squareSize, "w");
\r
3657 pieceBitmap[2][WhiteCardinal] = DoLoadBitmap(hInst, "sr", squareSize, "w");
\r
3658 pieceBitmap[2][WhiteDragon] = DoLoadBitmap(hInst, "sr", squareSize, "w");
\r
3659 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "sl", squareSize, "w");
\r
3660 pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "sw", squareSize, "w");
\r
3666 PieceBitmap(ChessSquare p, int kind)
\r
3668 if ((int) p >= (int) BlackPawn)
\r
3669 p = (ChessSquare) ((int) p - (int) BlackPawn + (int) WhitePawn);
\r
3671 return pieceBitmap[kind][(int) p];
\r
3674 /***************************************************************/
\r
3676 #define MIN(a,b) (((a) < (b)) ? (a) : (b))
\r
3677 #define MAX(a,b) (((a) > (b)) ? (a) : (b))
\r
3679 #define MIN3(a,b,c) (((a) < (b) && (a) < (c)) ? (a) : (((b) < (a) && (b) < (c)) ? (b) : (c)))
\r
3680 #define MAX3(a,b,c) (((a) > (b) && (a) > (c)) ? (a) : (((b) > (a) && (b) > (c)) ? (b) : (c)))
\r
3684 SquareToPos(int row, int column, int * x, int * y)
\r
3687 *x = boardRect.left + lineGap + ((BOARD_WIDTH-1)-column) * (squareSize + lineGap);
\r
3688 *y = boardRect.top + lineGap + row * (squareSize + lineGap);
\r
3690 *x = boardRect.left + lineGap + column * (squareSize + lineGap);
\r
3691 *y = boardRect.top + lineGap + ((BOARD_HEIGHT-1)-row) * (squareSize + lineGap);
\r
3696 DrawCoordsOnDC(HDC hdc)
\r
3698 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
3699 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
3700 char str[2] = { NULLCHAR, NULLCHAR };
\r
3701 int oldMode, oldAlign, x, y, start, i;
\r
3705 if (!appData.showCoords)
\r
3708 start = flipView ? 1-(ONE!='1') : 23+(ONE!='1')-BOARD_HEIGHT;
\r
3710 oldBrush = SelectObject(hdc, GetStockObject(BLACK_BRUSH));
\r
3711 oldMode = SetBkMode(hdc, (appData.monoMode ? OPAQUE : TRANSPARENT));
\r
3712 oldAlign = GetTextAlign(hdc);
\r
3713 oldFont = SelectObject(hdc, font[boardSize][COORD_FONT]->hf);
\r
3715 y = boardRect.top + lineGap;
\r
3716 x = boardRect.left + lineGap + gameInfo.holdingsWidth*(squareSize + lineGap);
\r
3718 SetTextAlign(hdc, TA_LEFT|TA_TOP);
\r
3719 for (i = 0; i < BOARD_HEIGHT; i++) {
\r
3720 str[0] = files[start + i];
\r
3721 ExtTextOut(hdc, x + 2, y + 1, 0, NULL, str, 1, NULL);
\r
3722 y += squareSize + lineGap;
\r
3725 start = flipView ? 12-(BOARD_RGHT-BOARD_LEFT) : 12;
\r
3727 SetTextAlign(hdc, TA_RIGHT|TA_BOTTOM);
\r
3728 for (i = 0; i < BOARD_RGHT - BOARD_LEFT; i++) {
\r
3729 str[0] = ranks[start + i];
\r
3730 ExtTextOut(hdc, x + squareSize - 2, y - 1, 0, NULL, str, 1, NULL);
\r
3731 x += squareSize + lineGap;
\r
3734 SelectObject(hdc, oldBrush);
\r
3735 SetBkMode(hdc, oldMode);
\r
3736 SetTextAlign(hdc, oldAlign);
\r
3737 SelectObject(hdc, oldFont);
\r
3741 DrawGridOnDC(HDC hdc)
\r
3745 if (lineGap != 0) {
\r
3746 oldPen = SelectObject(hdc, gridPen);
\r
3747 PolyPolyline(hdc, gridEndpoints, gridVertexCounts, BOARD_WIDTH+BOARD_HEIGHT + 2);
\r
3748 SelectObject(hdc, oldPen);
\r
3752 #define HIGHLIGHT_PEN 0
\r
3753 #define PREMOVE_PEN 1
\r
3756 DrawHighlightOnDC(HDC hdc, BOOLEAN on, int x, int y, int pen)
\r
3759 HPEN oldPen, hPen;
\r
3760 if (lineGap == 0) return;
\r
3762 x1 = boardRect.left +
\r
3763 lineGap/2 + ((BOARD_WIDTH-1)-x) * (squareSize + lineGap);
\r
3764 y1 = boardRect.top +
\r
3765 lineGap/2 + y * (squareSize + lineGap);
\r
3767 x1 = boardRect.left +
\r
3768 lineGap/2 + x * (squareSize + lineGap);
\r
3769 y1 = boardRect.top +
\r
3770 lineGap/2 + ((BOARD_HEIGHT-1)-y) * (squareSize + lineGap);
\r
3772 hPen = pen ? premovePen : highlightPen;
\r
3773 oldPen = SelectObject(hdc, on ? hPen : gridPen);
\r
3774 MoveToEx(hdc, x1, y1, NULL);
\r
3775 LineTo(hdc, x1 + squareSize + lineGap, y1);
\r
3776 LineTo(hdc, x1 + squareSize + lineGap, y1 + squareSize + lineGap);
\r
3777 LineTo(hdc, x1, y1 + squareSize + lineGap);
\r
3778 LineTo(hdc, x1, y1);
\r
3779 SelectObject(hdc, oldPen);
\r
3783 DrawHighlightsOnDC(HDC hdc)
\r
3786 for (i=0; i<2; i++) {
\r
3787 if (highlightInfo.sq[i].x >= 0 && highlightInfo.sq[i].y >= 0)
\r
3788 DrawHighlightOnDC(hdc, TRUE,
\r
3789 highlightInfo.sq[i].x, highlightInfo.sq[i].y,
\r
3792 for (i=0; i<2; i++) {
\r
3793 if (premoveHighlightInfo.sq[i].x >= 0 &&
\r
3794 premoveHighlightInfo.sq[i].y >= 0) {
\r
3795 DrawHighlightOnDC(hdc, TRUE,
\r
3796 premoveHighlightInfo.sq[i].x,
\r
3797 premoveHighlightInfo.sq[i].y,
\r
3803 /* Note: sqcolor is used only in monoMode */
\r
3804 /* Note that this code is largely duplicated in woptions.c,
\r
3805 function DrawSampleSquare, so that needs to be updated too */
\r
3807 DrawPieceOnDC(HDC hdc, ChessSquare piece, int color, int sqcolor, int x, int y, HDC tmphdc)
\r
3809 HBITMAP oldBitmap;
\r
3813 if (appData.blindfold) return;
\r
3815 /* [AS] Use font-based pieces if needed */
\r
3816 if( fontBitmapSquareSize >= 0 && squareSize > 32 ) {
\r
3817 /* Create piece bitmaps, or do nothing if piece set is up to date */
\r
3818 CreatePiecesFromFont();
\r
3820 if( fontBitmapSquareSize == squareSize ) {
\r
3821 int index = TranslatePieceToFontPiece(piece);
\r
3823 SelectObject( tmphdc, hPieceMask[ index ] );
\r
3827 squareSize, squareSize,
\r
3832 SelectObject( tmphdc, hPieceFace[ index ] );
\r
3836 squareSize, squareSize,
\r
3845 if (appData.monoMode) {
\r
3846 SelectObject(tmphdc, PieceBitmap(piece,
\r
3847 color == sqcolor ? OUTLINE_PIECE : SOLID_PIECE));
\r
3848 BitBlt(hdc, x, y, squareSize, squareSize, tmphdc, 0, 0,
\r
3849 sqcolor ? SRCCOPY : NOTSRCCOPY);
\r
3851 tmpSize = squareSize;
\r
3853 ((piece >= (int)WhiteNightrider && piece <= WhiteGrasshopper) ||
\r
3854 (piece >= (int)BlackNightrider && piece <= BlackGrasshopper)) ) {
\r
3855 /* [HGM] no bitmap available for promoted pieces in Crazyhouse */
\r
3856 /* Bitmaps of smaller size are substituted, but we have to align them */
\r
3857 x += (squareSize - minorSize)>>1;
\r
3858 y += squareSize - minorSize - 2;
\r
3859 tmpSize = minorSize;
\r
3861 if (color || appData.allWhite ) {
\r
3862 oldBitmap = SelectObject(tmphdc, PieceBitmap(piece, WHITE_PIECE));
\r
3864 oldBrush = SelectObject(hdc, whitePieceBrush);
\r
3865 else oldBrush = SelectObject(hdc, blackPieceBrush);
\r
3866 if(appData.upsideDown && color==flipView)
\r
3867 StretchBlt(hdc, x+tmpSize, y+tmpSize, -tmpSize, -tmpSize, tmphdc, 0, 0, tmpSize, tmpSize, 0x00B8074A);
\r
3869 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, 0x00B8074A);
\r
3871 /* Use black piece color for outline of white pieces */
\r
3872 /* Not sure this looks really good (though xboard does it).
\r
3873 Maybe better to have another selectable color, default black */
\r
3874 SelectObject(hdc, blackPieceBrush); /* could have own brush */
\r
3875 SelectObject(tmphdc, PieceBitmap(piece, OUTLINE_PIECE));
\r
3876 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, 0x00B8074A);
\r
3878 /* Use black for outline of white pieces */
\r
3879 SelectObject(tmphdc, PieceBitmap(piece, OUTLINE_PIECE));
\r
3880 if(appData.upsideDown && color==flipView)
\r
3881 StretchBlt(hdc, x+tmpSize, y+tmpSize, -tmpSize, -tmpSize, tmphdc, 0, 0, tmpSize, tmpSize, SRCAND);
\r
3883 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, SRCAND);
\r
3887 /* Use white piece color for details of black pieces */
\r
3888 /* Requires filled-in solid bitmaps (BLACK_PIECE class); the
\r
3889 WHITE_PIECE ones aren't always the right shape. */
\r
3890 /* Not sure this looks really good (though xboard does it).
\r
3891 Maybe better to have another selectable color, default medium gray? */
\r
3892 oldBitmap = SelectObject(tmphdc, PieceBitmap(piece, BLACK_PIECE));
\r
3893 oldBrush = SelectObject(hdc, whitePieceBrush); /* could have own brush */
\r
3894 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, 0x00B8074A);
\r
3895 SelectObject(tmphdc, PieceBitmap(piece, SOLID_PIECE));
\r
3896 SelectObject(hdc, blackPieceBrush);
\r
3897 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, 0x00B8074A);
\r
3899 /* Use square color for details of black pieces */
\r
3900 oldBitmap = SelectObject(tmphdc, PieceBitmap(piece, SOLID_PIECE));
\r
3901 oldBrush = SelectObject(hdc, blackPieceBrush);
\r
3902 if(appData.upsideDown && !flipView)
\r
3903 StretchBlt(hdc, x+tmpSize, y+tmpSize, -tmpSize, -tmpSize, tmphdc, 0, 0, tmpSize, tmpSize, 0x00B8074A);
\r
3905 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, 0x00B8074A);
\r
3908 SelectObject(hdc, oldBrush);
\r
3909 SelectObject(tmphdc, oldBitmap);
\r
3913 /* [AS] Compute a drawing mode for a square, based on specified settings (see DrawTile) */
\r
3914 int GetBackTextureMode( int algo )
\r
3916 int result = BACK_TEXTURE_MODE_DISABLED;
\r
3920 case BACK_TEXTURE_MODE_PLAIN:
\r
3921 result = 1; /* Always use identity map */
\r
3923 case BACK_TEXTURE_MODE_FULL_RANDOM:
\r
3924 result = 1 + (myrandom() % 3); /* Pick a transformation at random */
\r
3932 [AS] Compute and save texture drawing info, otherwise we may not be able
\r
3933 to handle redraws cleanly (as random numbers would always be different).
\r
3935 VOID RebuildTextureSquareInfo()
\r
3945 ZeroMemory( &backTextureSquareInfo, sizeof(backTextureSquareInfo) );
\r
3947 if( liteBackTexture != NULL ) {
\r
3948 if( GetObject( liteBackTexture, sizeof(bi), &bi ) > 0 ) {
\r
3949 lite_w = bi.bmWidth;
\r
3950 lite_h = bi.bmHeight;
\r
3954 if( darkBackTexture != NULL ) {
\r
3955 if( GetObject( darkBackTexture, sizeof(bi), &bi ) > 0 ) {
\r
3956 dark_w = bi.bmWidth;
\r
3957 dark_h = bi.bmHeight;
\r
3961 for( row=0; row<BOARD_HEIGHT; row++ ) {
\r
3962 for( col=0; col<BOARD_WIDTH; col++ ) {
\r
3963 if( (col + row) & 1 ) {
\r
3965 if( lite_w >= squareSize && lite_h >= squareSize ) {
\r
3966 backTextureSquareInfo[row][col].x = col * (lite_w - squareSize) / (BOARD_WIDTH-1); /* [HGM] divide by size-1 in stead of size! */
\r
3967 backTextureSquareInfo[row][col].y = (BOARD_HEIGHT-1-row) * (lite_h - squareSize) / (BOARD_HEIGHT-1);
\r
3968 backTextureSquareInfo[row][col].mode = GetBackTextureMode(liteBackTextureMode);
\r
3973 if( dark_w >= squareSize && dark_h >= squareSize ) {
\r
3974 backTextureSquareInfo[row][col].x = col * (dark_w - squareSize) / (BOARD_WIDTH-1);
\r
3975 backTextureSquareInfo[row][col].y = (BOARD_HEIGHT-1-row) * (dark_h - squareSize) / (BOARD_HEIGHT-1);
\r
3976 backTextureSquareInfo[row][col].mode = GetBackTextureMode(darkBackTextureMode);
\r
3983 /* [AS] Arrow highlighting support */
\r
3985 static int A_WIDTH = 5; /* Width of arrow body */
\r
3987 #define A_HEIGHT_FACTOR 6 /* Length of arrow "point", relative to body width */
\r
3988 #define A_WIDTH_FACTOR 3 /* Width of arrow "point", relative to body width */
\r
3990 static double Sqr( double x )
\r
3995 static int Round( double x )
\r
3997 return (int) (x + 0.5);
\r
4000 /* Draw an arrow between two points using current settings */
\r
4001 VOID DrawArrowBetweenPoints( HDC hdc, int s_x, int s_y, int d_x, int d_y )
\r
4004 double dx, dy, j, k, x, y;
\r
4006 if( d_x == s_x ) {
\r
4007 int h = (d_y > s_y) ? +A_WIDTH*A_HEIGHT_FACTOR : -A_WIDTH*A_HEIGHT_FACTOR;
\r
4009 arrow[0].x = s_x + A_WIDTH;
\r
4012 arrow[1].x = s_x + A_WIDTH;
\r
4013 arrow[1].y = d_y - h;
\r
4015 arrow[2].x = s_x + A_WIDTH*A_WIDTH_FACTOR;
\r
4016 arrow[2].y = d_y - h;
\r
4021 arrow[4].x = s_x - A_WIDTH*A_WIDTH_FACTOR;
\r
4022 arrow[4].y = d_y - h;
\r
4024 arrow[5].x = s_x - A_WIDTH;
\r
4025 arrow[5].y = d_y - h;
\r
4027 arrow[6].x = s_x - A_WIDTH;
\r
4030 else if( d_y == s_y ) {
\r
4031 int w = (d_x > s_x) ? +A_WIDTH*A_HEIGHT_FACTOR : -A_WIDTH*A_HEIGHT_FACTOR;
\r
4034 arrow[0].y = s_y + A_WIDTH;
\r
4036 arrow[1].x = d_x - w;
\r
4037 arrow[1].y = s_y + A_WIDTH;
\r
4039 arrow[2].x = d_x - w;
\r
4040 arrow[2].y = s_y + A_WIDTH*A_WIDTH_FACTOR;
\r
4045 arrow[4].x = d_x - w;
\r
4046 arrow[4].y = s_y - A_WIDTH*A_WIDTH_FACTOR;
\r
4048 arrow[5].x = d_x - w;
\r
4049 arrow[5].y = s_y - A_WIDTH;
\r
4052 arrow[6].y = s_y - A_WIDTH;
\r
4055 /* [AS] Needed a lot of paper for this! :-) */
\r
4056 dy = (double) (d_y - s_y) / (double) (d_x - s_x);
\r
4057 dx = (double) (s_x - d_x) / (double) (s_y - d_y);
\r
4059 j = sqrt( Sqr(A_WIDTH) / (1.0 + Sqr(dx)) );
\r
4061 k = sqrt( Sqr(A_WIDTH*A_HEIGHT_FACTOR) / (1.0 + Sqr(dy)) );
\r
4066 arrow[0].x = Round(x - j);
\r
4067 arrow[0].y = Round(y + j*dx);
\r
4069 arrow[1].x = Round(x + j);
\r
4070 arrow[1].y = Round(y - j*dx);
\r
4073 x = (double) d_x - k;
\r
4074 y = (double) d_y - k*dy;
\r
4077 x = (double) d_x + k;
\r
4078 y = (double) d_y + k*dy;
\r
4081 arrow[2].x = Round(x + j);
\r
4082 arrow[2].y = Round(y - j*dx);
\r
4084 arrow[3].x = Round(x + j*A_WIDTH_FACTOR);
\r
4085 arrow[3].y = Round(y - j*A_WIDTH_FACTOR*dx);
\r
4090 arrow[5].x = Round(x - j*A_WIDTH_FACTOR);
\r
4091 arrow[5].y = Round(y + j*A_WIDTH_FACTOR*dx);
\r
4093 arrow[6].x = Round(x - j);
\r
4094 arrow[6].y = Round(y + j*dx);
\r
4097 Polygon( hdc, arrow, 7 );
\r
4100 /* [AS] Draw an arrow between two squares */
\r
4101 VOID DrawArrowBetweenSquares( HDC hdc, int s_col, int s_row, int d_col, int d_row )
\r
4103 int s_x, s_y, d_x, d_y;
\r
4110 if( s_col == d_col && s_row == d_row ) {
\r
4114 /* Get source and destination points */
\r
4115 SquareToPos( s_row, s_col, &s_x, &s_y);
\r
4116 SquareToPos( d_row, d_col, &d_x, &d_y);
\r
4119 d_y += squareSize / 4;
\r
4121 else if( d_y < s_y ) {
\r
4122 d_y += 3 * squareSize / 4;
\r
4125 d_y += squareSize / 2;
\r
4129 d_x += squareSize / 4;
\r
4131 else if( d_x < s_x ) {
\r
4132 d_x += 3 * squareSize / 4;
\r
4135 d_x += squareSize / 2;
\r
4138 s_x += squareSize / 2;
\r
4139 s_y += squareSize / 2;
\r
4141 /* Adjust width */
\r
4142 A_WIDTH = squareSize / 14;
\r
4145 stLB.lbStyle = BS_SOLID;
\r
4146 stLB.lbColor = appData.highlightArrowColor;
\r
4149 hpen = CreatePen( PS_SOLID, 2, RGB(0x00,0x00,0x00) );
\r
4150 holdpen = SelectObject( hdc, hpen );
\r
4151 hbrush = CreateBrushIndirect( &stLB );
\r
4152 holdbrush = SelectObject( hdc, hbrush );
\r
4154 DrawArrowBetweenPoints( hdc, s_x, s_y, d_x, d_y );
\r
4156 SelectObject( hdc, holdpen );
\r
4157 SelectObject( hdc, holdbrush );
\r
4158 DeleteObject( hpen );
\r
4159 DeleteObject( hbrush );
\r
4162 BOOL HasHighlightInfo()
\r
4164 BOOL result = FALSE;
\r
4166 if( highlightInfo.sq[0].x >= 0 && highlightInfo.sq[0].y >= 0 &&
\r
4167 highlightInfo.sq[1].x >= 0 && highlightInfo.sq[1].y >= 0 )
\r
4175 BOOL IsDrawArrowEnabled()
\r
4177 BOOL result = FALSE;
\r
4179 if( appData.highlightMoveWithArrow && squareSize >= 32 ) {
\r
4186 VOID DrawArrowHighlight( HDC hdc )
\r
4188 if( IsDrawArrowEnabled() && HasHighlightInfo() ) {
\r
4189 DrawArrowBetweenSquares( hdc,
\r
4190 highlightInfo.sq[0].x, highlightInfo.sq[0].y,
\r
4191 highlightInfo.sq[1].x, highlightInfo.sq[1].y );
\r
4195 HRGN GetArrowHighlightClipRegion( HDC hdc )
\r
4197 HRGN result = NULL;
\r
4199 if( HasHighlightInfo() ) {
\r
4200 int x1, y1, x2, y2;
\r
4201 int sx, sy, dx, dy;
\r
4203 SquareToPos(highlightInfo.sq[0].y, highlightInfo.sq[0].x, &x1, &y1 );
\r
4204 SquareToPos(highlightInfo.sq[1].y, highlightInfo.sq[1].x, &x2, &y2 );
\r
4206 sx = MIN( x1, x2 );
\r
4207 sy = MIN( y1, y2 );
\r
4208 dx = MAX( x1, x2 ) + squareSize;
\r
4209 dy = MAX( y1, y2 ) + squareSize;
\r
4211 result = CreateRectRgn( sx, sy, dx, dy );
\r
4218 Warning: this function modifies the behavior of several other functions.
\r
4220 Basically, Winboard is optimized to avoid drawing the whole board if not strictly
\r
4221 needed. Unfortunately, the decision whether or not to perform a full or partial
\r
4222 repaint is scattered all over the place, which is not good for features such as
\r
4223 "arrow highlighting" that require a full repaint of the board.
\r
4225 So, I've tried to patch the code where I thought it made sense (e.g. after or during
\r
4226 user interaction, when speed is not so important) but especially to avoid errors
\r
4227 in the displayed graphics.
\r
4229 In such patched places, I always try refer to this function so there is a single
\r
4230 place to maintain knowledge.
\r
4232 To restore the original behavior, just return FALSE unconditionally.
\r
4234 BOOL IsFullRepaintPreferrable()
\r
4236 BOOL result = FALSE;
\r
4238 if( (appData.highlightLastMove || appData.highlightDragging) && IsDrawArrowEnabled() ) {
\r
4239 /* Arrow may appear on the board */
\r
4247 This function is called by DrawPosition to know whether a full repaint must
\r
4250 Only DrawPosition may directly call this function, which makes use of
\r
4251 some state information. Other function should call DrawPosition specifying
\r
4252 the repaint flag, and can use IsFullRepaintPreferrable if needed.
\r
4254 BOOL DrawPositionNeedsFullRepaint()
\r
4256 BOOL result = FALSE;
\r
4259 Probably a slightly better policy would be to trigger a full repaint
\r
4260 when animInfo.piece changes state (i.e. empty -> non-empty and viceversa),
\r
4261 but animation is fast enough that it's difficult to notice.
\r
4263 if( animInfo.piece == EmptySquare ) {
\r
4264 if( (appData.highlightLastMove || appData.highlightDragging) && IsDrawArrowEnabled() && HasHighlightInfo() ) {
\r
4273 DrawBoardOnDC(HDC hdc, Board board, HDC tmphdc)
\r
4275 int row, column, x, y, square_color, piece_color;
\r
4276 ChessSquare piece;
\r
4278 HDC texture_hdc = NULL;
\r
4280 /* [AS] Initialize background textures if needed */
\r
4281 if( liteBackTexture != NULL || darkBackTexture != NULL ) {
\r
4282 static int backTextureBoardSize; /* [HGM] boardsize: also new texture if board format changed */
\r
4283 if( backTextureSquareSize != squareSize
\r
4284 || backTextureBoardSize != BOARD_WIDTH+BOARD_SIZE*BOARD_HEIGHT) {
\r
4285 backTextureBoardSize = BOARD_WIDTH+BOARD_SIZE*BOARD_HEIGHT;
\r
4286 backTextureSquareSize = squareSize;
\r
4287 RebuildTextureSquareInfo();
\r
4290 texture_hdc = CreateCompatibleDC( hdc );
\r
4293 for (row = 0; row < BOARD_HEIGHT; row++) {
\r
4294 for (column = 0; column < BOARD_WIDTH; column++) {
\r
4296 SquareToPos(row, column, &x, &y);
\r
4298 piece = board[row][column];
\r
4300 square_color = ((column + row) % 2) == 1;
\r
4301 if( gameInfo.variant == VariantXiangqi ) {
\r
4302 square_color = !InPalace(row, column);
\r
4303 if(BOARD_HEIGHT&1) { if(row==BOARD_HEIGHT/2) square_color ^= 1; }
\r
4304 else if(row < BOARD_HEIGHT/2) square_color ^= 1;
\r
4306 piece_color = (int) piece < (int) BlackPawn;
\r
4309 /* [HGM] holdings file: light square or black */
\r
4310 if(column == BOARD_LEFT-2) {
\r
4311 if( row > BOARD_HEIGHT - gameInfo.holdingsSize - 1 )
\r
4314 DisplayHoldingsCount(hdc, x, y, 0, 0); /* black out */
\r
4318 if(column == BOARD_RGHT + 1 ) {
\r
4319 if( row < gameInfo.holdingsSize )
\r
4322 DisplayHoldingsCount(hdc, x, y, 0, 0);
\r
4326 if(column == BOARD_LEFT-1 ) /* left align */
\r
4327 DisplayHoldingsCount(hdc, x, y, flipView, (int) board[row][column]);
\r
4328 else if( column == BOARD_RGHT) /* right align */
\r
4329 DisplayHoldingsCount(hdc, x, y, !flipView, (int) board[row][column]);
\r
4331 if (appData.monoMode) {
\r
4332 if (piece == EmptySquare) {
\r
4333 BitBlt(hdc, x, y, squareSize, squareSize, 0, 0, 0,
\r
4334 square_color ? WHITENESS : BLACKNESS);
\r
4336 DrawPieceOnDC(hdc, piece, piece_color, square_color, x, y, tmphdc);
\r
4339 else if( backTextureSquareInfo[row][column].mode > 0 ) {
\r
4340 /* [AS] Draw the square using a texture bitmap */
\r
4341 HBITMAP hbm = SelectObject( texture_hdc, square_color ? liteBackTexture : darkBackTexture );
\r
4342 int r = row, c = column; // [HGM] do not flip board in flipView
\r
4343 if(flipView) { r = BOARD_HEIGHT-1 - r; c = BOARD_WIDTH-1 - c; }
\r
4346 squareSize, squareSize,
\r
4349 backTextureSquareInfo[r][c].mode,
\r
4350 backTextureSquareInfo[r][c].x,
\r
4351 backTextureSquareInfo[r][c].y );
\r
4353 SelectObject( texture_hdc, hbm );
\r
4355 if (piece != EmptySquare) {
\r
4356 DrawPieceOnDC(hdc, piece, piece_color, -1, x, y, tmphdc);
\r
4360 HBRUSH brush = square_color ? lightSquareBrush : darkSquareBrush;
\r
4362 oldBrush = SelectObject(hdc, brush );
\r
4363 BitBlt(hdc, x, y, squareSize, squareSize, 0, 0, 0, PATCOPY);
\r
4364 SelectObject(hdc, oldBrush);
\r
4365 if (piece != EmptySquare)
\r
4366 DrawPieceOnDC(hdc, piece, piece_color, -1, x, y, tmphdc);
\r
4371 if( texture_hdc != NULL ) {
\r
4372 DeleteDC( texture_hdc );
\r
4376 int saveDiagFlag = 0; FILE *diagFile; // [HGM] diag
\r
4377 void fputDW(FILE *f, int x)
\r
4379 fputc(x & 255, f);
\r
4380 fputc(x>>8 & 255, f);
\r
4381 fputc(x>>16 & 255, f);
\r
4382 fputc(x>>24 & 255, f);
\r
4385 #define MAX_CLIPS 200 /* more than enough */
\r
4388 DrawLogoOnDC(HDC hdc, RECT logoRect, HBITMAP logo)
\r
4390 // HBITMAP bufferBitmap;
\r
4395 int w = 100, h = 50;
\r
4397 if(logo == NULL) return;
\r
4398 // GetClientRect(hwndMain, &Rect);
\r
4399 // bufferBitmap = CreateCompatibleBitmap(hdc, Rect.right-Rect.left+1,
\r
4400 // Rect.bottom-Rect.top+1);
\r
4401 tmphdc = CreateCompatibleDC(hdc);
\r
4402 hbm = SelectObject(tmphdc, logo);
\r
4403 if( GetObject( logo, sizeof(bi), &bi ) > 0 ) {
\r
4407 StretchBlt(hdc, logoRect.left, logoRect.top, logoRect.right - logoRect.left,
\r
4408 logoRect.bottom - logoRect.top, tmphdc, 0, 0, w, h, SRCCOPY);
\r
4409 SelectObject(tmphdc, hbm);
\r
4414 HDCDrawPosition(HDC hdc, BOOLEAN repaint, Board board)
\r
4416 static Board lastReq, lastDrawn;
\r
4417 static HighlightInfo lastDrawnHighlight, lastDrawnPremove;
\r
4418 static int lastDrawnFlipView = 0;
\r
4419 static int lastReqValid = 0, lastDrawnValid = 0;
\r
4420 int releaseDC, x, y, x2, y2, row, column, num_clips = 0, i;
\r
4423 HBITMAP bufferBitmap;
\r
4424 HBITMAP oldBitmap;
\r
4426 HRGN clips[MAX_CLIPS];
\r
4427 ChessSquare dragged_piece = EmptySquare;
\r
4429 /* I'm undecided on this - this function figures out whether a full
\r
4430 * repaint is necessary on its own, so there's no real reason to have the
\r
4431 * caller tell it that. I think this can safely be set to FALSE - but
\r
4432 * if we trust the callers not to request full repaints unnessesarily, then
\r
4433 * we could skip some clipping work. In other words, only request a full
\r
4434 * redraw when the majority of pieces have changed positions (ie. flip,
\r
4435 * gamestart and similar) --Hawk
\r
4437 Boolean fullrepaint = repaint;
\r
4439 if( DrawPositionNeedsFullRepaint() ) {
\r
4440 fullrepaint = TRUE;
\r
4444 if( fullrepaint ) {
\r
4445 static int repaint_count = 0;
\r
4449 sprintf( buf, "FULL repaint: %d\n", repaint_count );
\r
4450 OutputDebugString( buf );
\r
4454 if (board == NULL) {
\r
4455 if (!lastReqValid) {
\r
4460 CopyBoard(lastReq, board);
\r
4464 if (doingSizing) {
\r
4468 if (IsIconic(hwndMain)) {
\r
4472 if (hdc == NULL) {
\r
4473 hdc = GetDC(hwndMain);
\r
4474 if (!appData.monoMode) {
\r
4475 SelectPalette(hdc, hPal, FALSE);
\r
4476 RealizePalette(hdc);
\r
4480 releaseDC = FALSE;
\r
4484 fprintf(debugFP, "*******************************\n"
\r
4486 "dragInfo.from (%d,%d)\n"
\r
4487 "dragInfo.start (%d,%d)\n"
\r
4488 "dragInfo.pos (%d,%d)\n"
\r
4489 "dragInfo.lastpos (%d,%d)\n",
\r
4490 repaint ? "TRUE" : "FALSE",
\r
4491 dragInfo.from.x, dragInfo.from.y,
\r
4492 dragInfo.start.x, dragInfo.start.y,
\r
4493 dragInfo.pos.x, dragInfo.pos.y,
\r
4494 dragInfo.lastpos.x, dragInfo.lastpos.y);
\r
4495 fprintf(debugFP, "prev: ");
\r
4496 for (row = 0; row < BOARD_HEIGHT; row++) {
\r
4497 for (column = 0; column < BOARD_WIDTH; column++) {
\r
4498 fprintf(debugFP, "%d ", lastDrawn[row][column]);
\r
4501 fprintf(debugFP, "\n");
\r
4502 fprintf(debugFP, "board: ");
\r
4503 for (row = 0; row < BOARD_HEIGHT; row++) {
\r
4504 for (column = 0; column < BOARD_WIDTH; column++) {
\r
4505 fprintf(debugFP, "%d ", board[row][column]);
\r
4508 fprintf(debugFP, "\n");
\r
4512 /* Create some work-DCs */
\r
4513 hdcmem = CreateCompatibleDC(hdc);
\r
4514 tmphdc = CreateCompatibleDC(hdc);
\r
4516 /* If dragging is in progress, we temporarely remove the piece */
\r
4517 /* [HGM] or temporarily decrease count if stacked */
\r
4518 /* !! Moved to before board compare !! */
\r
4519 if (dragInfo.from.x >= 0 && dragInfo.pos.x >= 0) {
\r
4520 dragged_piece = board[dragInfo.from.y][dragInfo.from.x];
\r
4521 if(dragInfo.from.x == BOARD_LEFT-2 ) {
\r
4522 if(--board[dragInfo.from.y][dragInfo.from.x+1] == 0 )
\r
4523 board[dragInfo.from.y][dragInfo.from.x] = EmptySquare;
\r
4525 if(dragInfo.from.x == BOARD_RGHT+1) {
\r
4526 if(--board[dragInfo.from.y][dragInfo.from.x-1] == 0 )
\r
4527 board[dragInfo.from.y][dragInfo.from.x] = EmptySquare;
\r
4529 board[dragInfo.from.y][dragInfo.from.x] = EmptySquare;
\r
4532 /* Figure out which squares need updating by comparing the
\r
4533 * newest board with the last drawn board and checking if
\r
4534 * flipping has changed.
\r
4536 if (!fullrepaint && lastDrawnValid && lastDrawnFlipView == flipView) {
\r
4537 for (row = 0; row < BOARD_HEIGHT; row++) { /* [HGM] true size, not 8 */
\r
4538 for (column = 0; column < BOARD_WIDTH; column++) {
\r
4539 if (lastDrawn[row][column] != board[row][column]) {
\r
4540 SquareToPos(row, column, &x, &y);
\r
4541 clips[num_clips++] =
\r
4542 CreateRectRgn(x, y, x + squareSize, y + squareSize);
\r
4546 for (i=0; i<2; i++) {
\r
4547 if (lastDrawnHighlight.sq[i].x != highlightInfo.sq[i].x ||
\r
4548 lastDrawnHighlight.sq[i].y != highlightInfo.sq[i].y) {
\r
4549 if (lastDrawnHighlight.sq[i].x >= 0 &&
\r
4550 lastDrawnHighlight.sq[i].y >= 0) {
\r
4551 SquareToPos(lastDrawnHighlight.sq[i].y,
\r
4552 lastDrawnHighlight.sq[i].x, &x, &y);
\r
4553 clips[num_clips++] =
\r
4554 CreateRectRgn(x - lineGap, y - lineGap,
\r
4555 x + squareSize + lineGap, y + squareSize + lineGap);
\r
4557 if (highlightInfo.sq[i].x >= 0 && highlightInfo.sq[i].y >= 0) {
\r
4558 SquareToPos(highlightInfo.sq[i].y, highlightInfo.sq[i].x, &x, &y);
\r
4559 clips[num_clips++] =
\r
4560 CreateRectRgn(x - lineGap, y - lineGap,
\r
4561 x + squareSize + lineGap, y + squareSize + lineGap);
\r
4565 for (i=0; i<2; i++) {
\r
4566 if (lastDrawnPremove.sq[i].x != premoveHighlightInfo.sq[i].x ||
\r
4567 lastDrawnPremove.sq[i].y != premoveHighlightInfo.sq[i].y) {
\r
4568 if (lastDrawnPremove.sq[i].x >= 0 &&
\r
4569 lastDrawnPremove.sq[i].y >= 0) {
\r
4570 SquareToPos(lastDrawnPremove.sq[i].y,
\r
4571 lastDrawnPremove.sq[i].x, &x, &y);
\r
4572 clips[num_clips++] =
\r
4573 CreateRectRgn(x - lineGap, y - lineGap,
\r
4574 x + squareSize + lineGap, y + squareSize + lineGap);
\r
4576 if (premoveHighlightInfo.sq[i].x >= 0 &&
\r
4577 premoveHighlightInfo.sq[i].y >= 0) {
\r
4578 SquareToPos(premoveHighlightInfo.sq[i].y,
\r
4579 premoveHighlightInfo.sq[i].x, &x, &y);
\r
4580 clips[num_clips++] =
\r
4581 CreateRectRgn(x - lineGap, y - lineGap,
\r
4582 x + squareSize + lineGap, y + squareSize + lineGap);
\r
4587 fullrepaint = TRUE;
\r
4590 /* Create a buffer bitmap - this is the actual bitmap
\r
4591 * being written to. When all the work is done, we can
\r
4592 * copy it to the real DC (the screen). This avoids
\r
4593 * the problems with flickering.
\r
4595 GetClientRect(hwndMain, &Rect);
\r
4596 bufferBitmap = CreateCompatibleBitmap(hdc, Rect.right-Rect.left+1,
\r
4597 Rect.bottom-Rect.top+1);
\r
4598 oldBitmap = SelectObject(hdcmem, bufferBitmap);
\r
4599 if (!appData.monoMode) {
\r
4600 SelectPalette(hdcmem, hPal, FALSE);
\r
4603 /* Create clips for dragging */
\r
4604 if (!fullrepaint) {
\r
4605 if (dragInfo.from.x >= 0) {
\r
4606 SquareToPos(dragInfo.from.y, dragInfo.from.x, &x, &y);
\r
4607 clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);
\r
4609 if (dragInfo.start.x >= 0) {
\r
4610 SquareToPos(dragInfo.start.y, dragInfo.start.x, &x, &y);
\r
4611 clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);
\r
4613 if (dragInfo.pos.x >= 0) {
\r
4614 x = dragInfo.pos.x - squareSize / 2;
\r
4615 y = dragInfo.pos.y - squareSize / 2;
\r
4616 clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);
\r
4618 if (dragInfo.lastpos.x >= 0) {
\r
4619 x = dragInfo.lastpos.x - squareSize / 2;
\r
4620 y = dragInfo.lastpos.y - squareSize / 2;
\r
4621 clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);
\r
4625 /* Are we animating a move?
\r
4627 * - remove the piece from the board (temporarely)
\r
4628 * - calculate the clipping region
\r
4630 if (!fullrepaint) {
\r
4631 if (animInfo.piece != EmptySquare) {
\r
4632 board[animInfo.from.y][animInfo.from.x] = EmptySquare;
\r
4633 x = boardRect.left + animInfo.lastpos.x;
\r
4634 y = boardRect.top + animInfo.lastpos.y;
\r
4635 x2 = boardRect.left + animInfo.pos.x;
\r
4636 y2 = boardRect.top + animInfo.pos.y;
\r
4637 clips[num_clips++] = CreateRectRgn(MIN(x,x2), MIN(y,y2), MAX(x,x2)+squareSize, MAX(y,y2)+squareSize);
\r
4638 /* Slight kludge. The real problem is that after AnimateMove is
\r
4639 done, the position on the screen does not match lastDrawn.
\r
4640 This currently causes trouble only on e.p. captures in
\r
4641 atomic, where the piece moves to an empty square and then
\r
4642 explodes. The old and new positions both had an empty square
\r
4643 at the destination, but animation has drawn a piece there and
\r
4644 we have to remember to erase it. [HGM] moved until after setting lastDrawn */
\r
4645 lastDrawn[animInfo.to.y][animInfo.to.x] = animInfo.piece;
\r
4649 /* No clips? Make sure we have fullrepaint set to TRUE */
\r
4650 if (num_clips == 0)
\r
4651 fullrepaint = TRUE;
\r
4653 /* Set clipping on the memory DC */
\r
4654 if (!fullrepaint) {
\r
4655 SelectClipRgn(hdcmem, clips[0]);
\r
4656 for (x = 1; x < num_clips; x++) {
\r
4657 if (ExtSelectClipRgn(hdcmem, clips[x], RGN_OR) == ERROR)
\r
4658 abort(); // this should never ever happen!
\r
4662 /* Do all the drawing to the memory DC */
\r
4663 if(explodeInfo.radius) { // [HGM] atomic
\r
4665 int x, y, r=(explodeInfo.radius * squareSize)/100;
\r
4666 board[explodeInfo.fromY][explodeInfo.fromX] = EmptySquare; // suppress display of capturer
\r
4667 SquareToPos(explodeInfo.toY, explodeInfo.toX, &x, &y);
\r
4668 x += squareSize/2;
\r
4669 y += squareSize/2;
\r
4670 if(!fullrepaint) {
\r
4671 clips[num_clips] = CreateRectRgn(x-r, y-r, x+r, y+r);
\r
4672 ExtSelectClipRgn(hdcmem, clips[num_clips++], RGN_OR);
\r
4674 DrawGridOnDC(hdcmem);
\r
4675 DrawHighlightsOnDC(hdcmem);
\r
4676 DrawBoardOnDC(hdcmem, board, tmphdc);
\r
4677 oldBrush = SelectObject(hdcmem, explodeBrush);
\r
4678 Ellipse(hdcmem, x-r, y-r, x+r, y+r);
\r
4679 SelectObject(hdcmem, oldBrush);
\r
4681 DrawGridOnDC(hdcmem);
\r
4682 DrawHighlightsOnDC(hdcmem);
\r
4683 DrawBoardOnDC(hdcmem, board, tmphdc);
\r
4686 HBITMAP whiteLogo = (HBITMAP) first.programLogo, blackLogo = (HBITMAP) second.programLogo;
\r
4687 if(appData.autoLogo) {
\r
4689 switch(gameMode) { // pick logos based on game mode
\r
4690 case IcsObserving:
\r
4691 whiteLogo = second.programLogo; // ICS logo
\r
4692 blackLogo = second.programLogo;
\r
4695 case IcsPlayingWhite:
\r
4696 if(!appData.zippyPlay) whiteLogo = userLogo;
\r
4697 blackLogo = second.programLogo; // ICS logo
\r
4699 case IcsPlayingBlack:
\r
4700 whiteLogo = second.programLogo; // ICS logo
\r
4701 blackLogo = appData.zippyPlay ? first.programLogo : userLogo;
\r
4703 case TwoMachinesPlay:
\r
4704 if(first.twoMachinesColor[0] == 'b') {
\r
4705 whiteLogo = second.programLogo;
\r
4706 blackLogo = first.programLogo;
\r
4709 case MachinePlaysWhite:
\r
4710 blackLogo = userLogo;
\r
4712 case MachinePlaysBlack:
\r
4713 whiteLogo = userLogo;
\r
4714 blackLogo = first.programLogo;
\r
4717 DrawLogoOnDC(hdc, leftLogoRect, flipClock ? blackLogo : whiteLogo);
\r
4718 DrawLogoOnDC(hdc, rightLogoRect, flipClock ? whiteLogo : blackLogo);
\r
4721 if( appData.highlightMoveWithArrow ) {
\r
4722 DrawArrowHighlight(hdcmem);
\r
4725 DrawCoordsOnDC(hdcmem);
\r
4727 CopyBoard(lastDrawn, board); /* [HGM] Moved to here from end of routine, */
\r
4728 /* to make sure lastDrawn contains what is actually drawn */
\r
4730 /* Put the dragged piece back into place and draw it (out of place!) */
\r
4731 if (dragged_piece != EmptySquare) {
\r
4732 /* [HGM] or restack */
\r
4733 if(dragInfo.from.x == BOARD_LEFT-2 )
\r
4734 board[dragInfo.from.y][dragInfo.from.x+1]++;
\r
4736 if(dragInfo.from.x == BOARD_RGHT+1 )
\r
4737 board[dragInfo.from.y][dragInfo.from.x-1]++;
\r
4738 board[dragInfo.from.y][dragInfo.from.x] = dragged_piece;
\r
4739 x = dragInfo.pos.x - squareSize / 2;
\r
4740 y = dragInfo.pos.y - squareSize / 2;
\r
4741 DrawPieceOnDC(hdcmem, dragged_piece,
\r
4742 ((int) dragged_piece < (int) BlackPawn),
\r
4743 (dragInfo.from.y + dragInfo.from.x) % 2, x, y, tmphdc);
\r
4746 /* Put the animated piece back into place and draw it */
\r
4747 if (animInfo.piece != EmptySquare) {
\r
4748 board[animInfo.from.y][animInfo.from.x] = animInfo.piece;
\r
4749 x = boardRect.left + animInfo.pos.x;
\r
4750 y = boardRect.top + animInfo.pos.y;
\r
4751 DrawPieceOnDC(hdcmem, animInfo.piece,
\r
4752 ((int) animInfo.piece < (int) BlackPawn),
\r
4753 (animInfo.from.y + animInfo.from.x) % 2, x, y, tmphdc);
\r
4756 /* Release the bufferBitmap by selecting in the old bitmap
\r
4757 * and delete the memory DC
\r
4759 SelectObject(hdcmem, oldBitmap);
\r
4762 /* Set clipping on the target DC */
\r
4763 if (!fullrepaint) {
\r
4764 SelectClipRgn(hdc, clips[0]);
\r
4765 for (x = 1; x < num_clips; x++) {
\r
4766 if (ExtSelectClipRgn(hdc, clips[x], RGN_OR) == ERROR)
\r
4767 abort(); // this should never ever happen!
\r
4771 /* Copy the new bitmap onto the screen in one go.
\r
4772 * This way we avoid any flickering
\r
4774 oldBitmap = SelectObject(tmphdc, bufferBitmap);
\r
4775 BitBlt(hdc, boardRect.left, boardRect.top,
\r
4776 boardRect.right - boardRect.left,
\r
4777 boardRect.bottom - boardRect.top,
\r
4778 tmphdc, boardRect.left, boardRect.top, SRCCOPY);
\r
4779 if(saveDiagFlag) {
\r
4780 BITMAP b; int i, j=0, m, w, wb, fac=0; char pData[1000000];
\r
4781 BITMAPINFOHEADER bih; int color[16], nrColors=0;
\r
4783 GetObject(bufferBitmap, sizeof(b), &b);
\r
4784 if(b.bmWidthBytes*b.bmHeight <= 990000) {
\r
4785 bih.biSize = sizeof(BITMAPINFOHEADER);
\r
4786 bih.biWidth = b.bmWidth;
\r
4787 bih.biHeight = b.bmHeight;
\r
4789 bih.biBitCount = b.bmBitsPixel;
\r
4790 bih.biCompression = 0;
\r
4791 bih.biSizeImage = b.bmWidthBytes*b.bmHeight;
\r
4792 bih.biXPelsPerMeter = 0;
\r
4793 bih.biYPelsPerMeter = 0;
\r
4794 bih.biClrUsed = 0;
\r
4795 bih.biClrImportant = 0;
\r
4796 // fprintf(diagFile, "t=%d\nw=%d\nh=%d\nB=%d\nP=%d\nX=%d\n",
\r
4797 // b.bmType, b.bmWidth, b.bmHeight, b.bmWidthBytes, b.bmPlanes, b.bmBitsPixel);
\r
4798 GetDIBits(tmphdc,bufferBitmap,0,b.bmHeight,pData,(BITMAPINFO*)&bih,DIB_RGB_COLORS);
\r
4799 // fprintf(diagFile, "%8x\n", (int) pData);
\r
4802 wb = b.bmWidthBytes;
\r
4804 for(i=0; i<wb*(b.bmHeight - boardRect.top + OUTER_MARGIN)>>2; i++) {
\r
4805 int k = ((int*) pData)[i];
\r
4806 for(j=0; j<nrColors; j++) if(color[j] == k) break;
\r
4807 if(j >= 16) break;
\r
4809 if(j >= nrColors) nrColors = j+1;
\r
4811 if(j<16) { // 16 colors is enough. Compress to 4 bits per pixel
\r
4813 for(i=0; i<b.bmHeight - boardRect.top + OUTER_MARGIN; i++) {
\r
4814 for(w=0; w<(wb>>2); w+=2) {
\r
4815 int k = ((int*) pData)[(wb*i>>2) + w];
\r
4816 for(j=0; j<nrColors; j++) if(color[j] == k) break;
\r
4817 k = ((int*) pData)[(wb*i>>2) + w + 1];
\r
4818 for(m=0; m<nrColors; m++) if(color[m] == k) break;
\r
4819 pData[p++] = m | j<<4;
\r
4821 while(p&3) pData[p++] = 0;
\r
4824 wb = ((wb+31)>>5)<<2;
\r
4826 // write BITMAPFILEHEADER
\r
4827 fprintf(diagFile, "BM");
\r
4828 fputDW(diagFile, wb*(b.bmHeight - boardRect.top + OUTER_MARGIN)+0x36 + (fac?64:0));
\r
4829 fputDW(diagFile, 0);
\r
4830 fputDW(diagFile, 0x36 + (fac?64:0));
\r
4831 // write BITMAPINFOHEADER
\r
4832 fputDW(diagFile, 40);
\r
4833 fputDW(diagFile, b.bmWidth);
\r
4834 fputDW(diagFile, b.bmHeight - boardRect.top + OUTER_MARGIN);
\r
4835 if(fac) fputDW(diagFile, 0x040001); // planes and bits/pixel
\r
4836 else fputDW(diagFile, 0x200001); // planes and bits/pixel
\r
4837 fputDW(diagFile, 0);
\r
4838 fputDW(diagFile, 0);
\r
4839 fputDW(diagFile, 0);
\r
4840 fputDW(diagFile, 0);
\r
4841 fputDW(diagFile, 0);
\r
4842 fputDW(diagFile, 0);
\r
4843 // write color table
\r
4845 for(i=0; i<16; i++) fputDW(diagFile, color[i]);
\r
4846 // write bitmap data
\r
4847 for(i=0; i<wb*(b.bmHeight - boardRect.top + OUTER_MARGIN); i++)
\r
4848 fputc(pData[i], diagFile);
\r
4853 SelectObject(tmphdc, oldBitmap);
\r
4855 /* Massive cleanup */
\r
4856 for (x = 0; x < num_clips; x++)
\r
4857 DeleteObject(clips[x]);
\r
4860 DeleteObject(bufferBitmap);
\r
4863 ReleaseDC(hwndMain, hdc);
\r
4865 if (lastDrawnFlipView != flipView) {
\r
4867 CheckMenuItem(GetMenu(hwndMain),IDM_FlipView, MF_BYCOMMAND|MF_CHECKED);
\r
4869 CheckMenuItem(GetMenu(hwndMain),IDM_FlipView, MF_BYCOMMAND|MF_UNCHECKED);
\r
4872 /* CopyBoard(lastDrawn, board);*/
\r
4873 lastDrawnHighlight = highlightInfo;
\r
4874 lastDrawnPremove = premoveHighlightInfo;
\r
4875 lastDrawnFlipView = flipView;
\r
4876 lastDrawnValid = 1;
\r
4879 /* [HGM] diag: Save the current board display to the given open file and close the file */
\r
4884 saveDiagFlag = 1; diagFile = f;
\r
4885 HDCDrawPosition(NULL, TRUE, NULL);
\r
4889 // if(f != NULL) fprintf(f, "Sorry, but this feature is still in preparation\n");
\r
4896 /*---------------------------------------------------------------------------*\
\r
4897 | CLIENT PAINT PROCEDURE
\r
4898 | This is the main event-handler for the WM_PAINT message.
\r
4900 \*---------------------------------------------------------------------------*/
\r
4902 PaintProc(HWND hwnd)
\r
4908 if((hdc = BeginPaint(hwnd, &ps))) {
\r
4909 if (IsIconic(hwnd)) {
\r
4910 DrawIcon(hdc, 2, 2, iconCurrent);
\r
4912 if (!appData.monoMode) {
\r
4913 SelectPalette(hdc, hPal, FALSE);
\r
4914 RealizePalette(hdc);
\r
4916 HDCDrawPosition(hdc, 1, NULL);
\r
4918 SelectObject(hdc, font[boardSize][MESSAGE_FONT]->hf);
\r
4919 ExtTextOut(hdc, messageRect.left, messageRect.top,
\r
4920 ETO_CLIPPED|ETO_OPAQUE,
\r
4921 &messageRect, messageText, strlen(messageText), NULL);
\r
4922 SelectObject(hdc, oldFont);
\r
4923 DisplayBothClocks();
\r
4925 EndPaint(hwnd,&ps);
\r
4933 * If the user selects on a border boundary, return -1; if off the board,
\r
4934 * return -2. Otherwise map the event coordinate to the square.
\r
4935 * The offset boardRect.left or boardRect.top must already have been
\r
4936 * subtracted from x.
\r
4939 EventToSquare(int x)
\r
4946 if ((x % (squareSize + lineGap)) >= squareSize)
\r
4948 x /= (squareSize + lineGap);
\r
4949 if (x >= BOARD_SIZE)
\r
4960 DropEnable dropEnables[] = {
\r
4961 { 'P', DP_Pawn, "Pawn" },
\r
4962 { 'N', DP_Knight, "Knight" },
\r
4963 { 'B', DP_Bishop, "Bishop" },
\r
4964 { 'R', DP_Rook, "Rook" },
\r
4965 { 'Q', DP_Queen, "Queen" },
\r
4969 SetupDropMenu(HMENU hmenu)
\r
4971 int i, count, enable;
\r
4973 extern char white_holding[], black_holding[];
\r
4974 char item[MSG_SIZ];
\r
4976 for (i=0; i<sizeof(dropEnables)/sizeof(DropEnable); i++) {
\r
4977 p = strchr(gameMode == IcsPlayingWhite ? white_holding : black_holding,
\r
4978 dropEnables[i].piece);
\r
4980 while (p && *p++ == dropEnables[i].piece) count++;
\r
4981 sprintf(item, "%s %d", dropEnables[i].name, count);
\r
4982 enable = count > 0 || !appData.testLegality
\r
4983 /*!!temp:*/ || (gameInfo.variant == VariantCrazyhouse
\r
4984 && !appData.icsActive);
\r
4985 ModifyMenu(hmenu, dropEnables[i].command,
\r
4986 MF_BYCOMMAND | (enable ? MF_ENABLED : MF_GRAYED) | MF_STRING,
\r
4987 dropEnables[i].command, item);
\r
4991 /* Event handler for mouse messages */
\r
4993 MouseEvent(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
4997 static int recursive = 0;
\r
4999 // BOOLEAN needsRedraw = FALSE;
\r
5000 BOOLEAN saveAnimate;
\r
5001 BOOLEAN forceFullRepaint = IsFullRepaintPreferrable(); /* [AS] */
\r
5002 static BOOLEAN sameAgain = FALSE, promotionChoice = FALSE;
\r
5003 ChessMove moveType;
\r
5006 if (message == WM_MBUTTONUP) {
\r
5007 /* Hideous kludge to fool TrackPopupMenu into paying attention
\r
5008 to the middle button: we simulate pressing the left button too!
\r
5010 PostMessage(hwnd, WM_LBUTTONDOWN, wParam, lParam);
\r
5011 PostMessage(hwnd, WM_LBUTTONUP, wParam, lParam);
\r
5017 pt.x = LOWORD(lParam);
\r
5018 pt.y = HIWORD(lParam);
\r
5019 x = EventToSquare(pt.x - boardRect.left);
\r
5020 y = EventToSquare(pt.y - boardRect.top);
\r
5021 if (!flipView && y >= 0) {
\r
5022 y = BOARD_HEIGHT - 1 - y;
\r
5024 if (flipView && x >= 0) {
\r
5025 x = BOARD_WIDTH - 1 - x;
\r
5028 switch (message) {
\r
5029 case WM_LBUTTONDOWN:
\r
5030 if(promotionChoice) { // we are waiting for a click to indicate promotion piece
\r
5031 promotionChoice = FALSE; // only one chance: if click not OK it is interpreted as cancel
\r
5032 if(appData.debugMode) fprintf(debugFP, "promotion click, x=%d, y=%d\n", x, y);
\r
5033 if(gameInfo.holdingsWidth &&
\r
5034 (WhiteOnMove(currentMove)
\r
5035 ? x == BOARD_WIDTH-1 && y < gameInfo.holdingsSize && y > 0
\r
5036 : x == 0 && y >= BOARD_HEIGHT - gameInfo.holdingsSize && y < BOARD_HEIGHT-1) ) {
\r
5037 // click in right holdings, for determining promotion piece
\r
5038 ChessSquare p = boards[currentMove][y][x];
\r
5039 if(appData.debugMode) fprintf(debugFP, "square contains %d\n", (int)p);
\r
5040 if(p != EmptySquare) {
\r
5041 FinishMove(WhitePromotionQueen, fromX, fromY, toX, toY, ToLower(PieceToChar(p)));
\r
5042 fromX = fromY = -1;
\r
5046 DrawPosition(FALSE, boards[currentMove]);
\r
5050 sameAgain = FALSE;
\r
5052 /* Downclick vertically off board; check if on clock */
\r
5053 if (PtInRect((LPRECT) &whiteRect, pt)) {
\r
5054 if (gameMode == EditPosition) {
\r
5055 SetWhiteToPlayEvent();
\r
5056 } else if (gameMode == IcsPlayingBlack ||
\r
5057 gameMode == MachinePlaysWhite) {
\r
5059 } else if (gameMode == EditGame) {
\r
5060 AdjustClock(flipClock, -1);
\r
5062 } else if (PtInRect((LPRECT) &blackRect, pt)) {
\r
5063 if (gameMode == EditPosition) {
\r
5064 SetBlackToPlayEvent();
\r
5065 } else if (gameMode == IcsPlayingWhite ||
\r
5066 gameMode == MachinePlaysBlack) {
\r
5068 } else if (gameMode == EditGame) {
\r
5069 AdjustClock(!flipClock, -1);
\r
5072 if (!appData.highlightLastMove) {
\r
5073 ClearHighlights();
\r
5074 DrawPosition((int) (forceFullRepaint || FALSE), NULL);
\r
5076 fromX = fromY = -1;
\r
5077 dragInfo.start.x = dragInfo.start.y = -1;
\r
5078 dragInfo.from = dragInfo.start;
\r
5080 } else if (x < 0 || y < 0
\r
5081 /* [HGM] block clicks between board and holdings */
\r
5082 || x == BOARD_LEFT-1 || x == BOARD_RGHT
\r
5083 || (x == BOARD_LEFT-2 && y < BOARD_HEIGHT-gameInfo.holdingsSize)
\r
5084 || (x == BOARD_RGHT+1 && y >= gameInfo.holdingsSize)
\r
5085 /* EditPosition, empty square, or different color piece;
\r
5086 click-click move is possible */
\r
5089 } else if (fromX == x && fromY == y) {
\r
5090 /* Downclick on same square again */
\r
5091 ClearHighlights();
\r
5092 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
5093 sameAgain = TRUE;
\r
5094 } else if (fromX != -1 &&
\r
5095 x != BOARD_LEFT-2 && x != BOARD_RGHT+1
\r
5097 /* Downclick on different square. */
\r
5098 /* [HGM] if on holdings file, should count as new first click ! */
\r
5099 { /* [HGM] <sameColor> now always do UserMoveTest(), and check colors there */
\r
5102 /* [HGM] <popupFix> UserMoveEvent requires two calls now,
\r
5103 to make sure move is legal before showing promotion popup */
\r
5104 moveType = UserMoveTest(fromX, fromY, toX, toY, NULLCHAR);
\r
5105 if(moveType == AmbiguousMove) { /* [HGM] Edit-Position move executed */
\r
5106 fromX = fromY = -1;
\r
5107 ClearHighlights();
\r
5108 DrawPosition(FALSE, boards[currentMove]);
\r
5111 if(moveType != ImpossibleMove) {
\r
5112 /* [HGM] We use PromotionToKnight in Shogi to indicate frorced promotion */
\r
5113 if (moveType == WhitePromotionKnight || moveType == BlackPromotionKnight ||
\r
5114 ((moveType == WhitePromotionQueen || moveType == BlackPromotionQueen) &&
\r
5115 appData.alwaysPromoteToQueen)) {
\r
5116 FinishMove(moveType, fromX, fromY, toX, toY, 'q');
\r
5117 if (!appData.highlightLastMove) {
\r
5118 ClearHighlights();
\r
5119 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
5122 if (moveType == WhitePromotionQueen || moveType == BlackPromotionQueen ) {
\r
5123 SetHighlights(fromX, fromY, toX, toY);
\r
5124 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
5125 /* [HGM] <popupFix> Popup calls FinishMove now.
\r
5126 If promotion to Q is legal, all are legal! */
\r
5127 if(gameInfo.variant == VariantSuper || gameInfo.variant == VariantGreat)
\r
5128 { ChessSquare p = boards[currentMove][fromY][fromX], q = boards[currentMove][toY][toX];
\r
5129 // kludge to temporarily execute move on display, wthout promotng yet
\r
5130 promotionChoice = TRUE;
\r
5131 boards[currentMove][fromY][fromX] = EmptySquare; // move Pawn to 8th rank
\r
5132 boards[currentMove][toY][toX] = p;
\r
5133 DrawPosition(FALSE, boards[currentMove]);
\r
5134 boards[currentMove][fromY][fromX] = p; // take back, but display stays
\r
5135 boards[currentMove][toY][toX] = q;
\r
5137 PromotionPopup(hwnd);
\r
5138 } else { /* not a promotion */
\r
5139 if (appData.animate || appData.highlightLastMove) {
\r
5140 SetHighlights(fromX, fromY, toX, toY);
\r
5142 ClearHighlights();
\r
5144 FinishMove(moveType, fromX, fromY, toX, toY, NULLCHAR);
\r
5145 fromX = fromY = -1;
\r
5146 if (appData.animate && !appData.highlightLastMove) {
\r
5147 ClearHighlights();
\r
5148 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
5154 /* [HGM] it seemed that braces were missing here */
\r
5155 SetPremoveHighlights(fromX, fromY, toX, toY);
\r
5156 fromX = fromY = -1;
\r
5160 ClearHighlights();
\r
5161 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
5163 /* First downclick, or restart on a square with same color piece */
\r
5164 if (!frozen && OKToStartUserMove(x, y)) {
\r
5167 dragInfo.lastpos = pt;
\r
5168 dragInfo.from.x = fromX;
\r
5169 dragInfo.from.y = fromY;
\r
5170 dragInfo.start = dragInfo.from;
\r
5171 SetCapture(hwndMain);
\r
5173 fromX = fromY = -1;
\r
5174 dragInfo.start.x = dragInfo.start.y = -1;
\r
5175 dragInfo.from = dragInfo.start;
\r
5176 DrawPosition(forceFullRepaint || FALSE, NULL); /* [AS] */
\r
5180 case WM_LBUTTONUP:
\r
5182 if (fromX == -1) break;
\r
5183 if (x == fromX && y == fromY) {
\r
5184 dragInfo.from.x = dragInfo.from.y = -1;
\r
5185 /* Upclick on same square */
\r
5187 /* Clicked same square twice: abort click-click move */
\r
5188 fromX = fromY = -1;
\r
5190 ClearPremoveHighlights();
\r
5192 /* First square clicked: start click-click move */
\r
5193 SetHighlights(fromX, fromY, -1, -1);
\r
5195 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
5196 } else if (dragInfo.from.x < 0 || dragInfo.from.y < 0) {
\r
5197 /* Errant click; ignore */
\r
5200 /* Finish drag move. */
\r
5201 if (appData.debugMode) {
\r
5202 fprintf(debugFP, "release\n");
\r
5204 dragInfo.from.x = dragInfo.from.y = -1;
\r
5207 saveAnimate = appData.animate; /* sorry, Hawk :) */
\r
5208 appData.animate = appData.animate && !appData.animateDragging;
\r
5209 moveType = UserMoveTest(fromX, fromY, toX, toY, NULLCHAR);
\r
5210 if(moveType == AmbiguousMove) { /* [HGM] Edit-Position move executed */
\r
5211 fromX = fromY = -1;
\r
5212 ClearHighlights();
\r
5213 DrawPosition(FALSE, boards[currentMove]);
\r
5214 appData.animate = saveAnimate;
\r
5217 if(moveType != ImpossibleMove) {
\r
5218 /* [HGM] use move type to determine if move is promotion.
\r
5219 Knight is Shogi kludge for mandatory promotion, Queen means choice */
\r
5220 if (moveType == WhitePromotionKnight || moveType == BlackPromotionKnight ||
\r
5221 ((moveType == WhitePromotionQueen || moveType == BlackPromotionQueen) &&
\r
5222 appData.alwaysPromoteToQueen))
\r
5223 FinishMove(moveType, fromX, fromY, toX, toY, 'q');
\r
5225 if (moveType == WhitePromotionQueen || moveType == BlackPromotionQueen ) {
\r
5226 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
5227 if(gameInfo.variant == VariantSuper || gameInfo.variant == VariantGreat)
\r
5228 { ChessSquare p = boards[currentMove][fromY][fromX], q = boards[currentMove][toY][toX];
\r
5229 // kludge to temporarily execute move on display, wthout promotng yet
\r
5230 promotionChoice = TRUE;
\r
5231 boards[currentMove][fromY][fromX] = EmptySquare; // move Pawn to 8th rank
\r
5232 boards[currentMove][toY][toX] = p;
\r
5233 DrawPosition(FALSE, boards[currentMove]);
\r
5234 boards[currentMove][fromY][fromX] = p; // take back, but display stays
\r
5235 boards[currentMove][toY][toX] = q;
\r
5236 appData.animate = saveAnimate;
\r
5239 PromotionPopup(hwnd); /* [HGM] Popup now calls FinishMove */
\r
5241 if(saveAnimate /* ^$!%@#$!$ */ && gameInfo.variant == VariantAtomic
\r
5242 && (boards[currentMove][toY][toX] != EmptySquare ||
\r
5243 moveType == WhiteCapturesEnPassant ||
\r
5244 moveType == BlackCapturesEnPassant ) )
\r
5245 AnimateAtomicCapture(fromX, fromY, toX, toY, 20);
\r
5246 FinishMove(moveType, fromX, fromY, toX, toY, NULLCHAR);
\r
5249 if (gotPremove) SetPremoveHighlights(fromX, fromY, toX, toY);
\r
5250 appData.animate = saveAnimate;
\r
5251 fromX = fromY = -1;
\r
5252 if (appData.highlightDragging && !appData.highlightLastMove) {
\r
5253 ClearHighlights();
\r
5255 if (appData.animate || appData.animateDragging ||
\r
5256 appData.highlightDragging || gotPremove) {
\r
5257 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
5260 dragInfo.start.x = dragInfo.start.y = -1;
\r
5261 dragInfo.pos = dragInfo.lastpos = dragInfo.start;
\r
5264 case WM_MOUSEMOVE:
\r
5265 if ((appData.animateDragging || appData.highlightDragging)
\r
5266 && (wParam & MK_LBUTTON)
\r
5267 && dragInfo.from.x >= 0)
\r
5269 BOOL full_repaint = FALSE;
\r
5271 sameAgain = FALSE; /* [HGM] if we drag something around, do keep square selected */
\r
5272 if (appData.animateDragging) {
\r
5273 dragInfo.pos = pt;
\r
5275 if (appData.highlightDragging) {
\r
5276 SetHighlights(fromX, fromY, x, y);
\r
5277 if( IsDrawArrowEnabled() && (x < 0 || x >= BOARD_WIDTH || y < 0 || y >= BOARD_HEIGHT) ) {
\r
5278 full_repaint = TRUE;
\r
5282 DrawPosition( full_repaint, NULL);
\r
5284 dragInfo.lastpos = dragInfo.pos;
\r
5288 case WM_MOUSEWHEEL: // [DM]
\r
5289 { static int lastDir = 0; // [HGM] build in some hysteresis to avoid spurious events
\r
5290 /* Mouse Wheel is being rolled forward
\r
5291 * Play moves forward
\r
5293 if((short)HIWORD(wParam) > 0 && currentMove < forwardMostMove)
\r
5294 { if(lastDir == 1) ForwardEvent(); else lastDir = 1; } // [HGM] suppress first event in direction
\r
5295 /* Mouse Wheel is being rolled backward
\r
5296 * Play moves backward
\r
5298 if((short)HIWORD(wParam) < 0 && currentMove > backwardMostMove)
\r
5299 { if(lastDir == -1) BackwardEvent(); else lastDir = -1; }
\r
5303 case WM_MBUTTONDOWN:
\r
5304 case WM_RBUTTONDOWN:
\r
5307 fromX = fromY = -1;
\r
5308 dragInfo.pos.x = dragInfo.pos.y = -1;
\r
5309 dragInfo.start.x = dragInfo.start.y = -1;
\r
5310 dragInfo.from = dragInfo.start;
\r
5311 dragInfo.lastpos = dragInfo.pos;
\r
5312 if (appData.highlightDragging) {
\r
5313 ClearHighlights();
\r
5316 /* [HGM] right mouse button in clock area edit-game mode ups clock */
\r
5317 if (PtInRect((LPRECT) &whiteRect, pt)) {
\r
5318 if (gameMode == EditGame) AdjustClock(flipClock, 1);
\r
5319 } else if (PtInRect((LPRECT) &blackRect, pt)) {
\r
5320 if (gameMode == EditGame) AdjustClock(!flipClock, 1);
\r
5323 DrawPosition(TRUE, NULL);
\r
5325 switch (gameMode) {
\r
5326 case EditPosition:
\r
5327 case IcsExamining:
\r
5328 if (x < 0 || y < 0) break;
\r
5331 if (message == WM_MBUTTONDOWN) {
\r
5332 buttonCount = 3; /* even if system didn't think so */
\r
5333 if (wParam & MK_SHIFT)
\r
5334 MenuPopup(hwnd, pt, LoadMenu(hInst, "BlackPieceMenu"), -1);
\r
5336 MenuPopup(hwnd, pt, LoadMenu(hInst, "WhitePieceMenu"), -1);
\r
5337 } else { /* message == WM_RBUTTONDOWN */
\r
5339 if (buttonCount == 3) {
\r
5340 if (wParam & MK_SHIFT)
\r
5341 MenuPopup(hwnd, pt, LoadMenu(hInst, "WhitePieceMenu"), -1);
\r
5343 MenuPopup(hwnd, pt, LoadMenu(hInst, "BlackPieceMenu"), -1);
\r
5345 MenuPopup(hwnd, pt, LoadMenu(hInst, "PieceMenu"), -1);
\r
5348 /* Just have one menu, on the right button. Windows users don't
\r
5349 think to try the middle one, and sometimes other software steals
\r
5350 it, or it doesn't really exist. */
\r
5351 if(gameInfo.variant != VariantShogi)
\r
5352 MenuPopup(hwnd, pt, LoadMenu(hInst, "PieceMenu"), -1);
\r
5354 MenuPopup(hwnd, pt, LoadMenu(hInst, "ShogiPieceMenu"), -1);
\r
5358 case IcsPlayingWhite:
\r
5359 case IcsPlayingBlack:
\r
5361 case MachinePlaysWhite:
\r
5362 case MachinePlaysBlack:
\r
5363 if (appData.testLegality &&
\r
5364 gameInfo.variant != VariantBughouse &&
\r
5365 gameInfo.variant != VariantCrazyhouse) break;
\r
5366 if (x < 0 || y < 0) break;
\r
5369 hmenu = LoadMenu(hInst, "DropPieceMenu");
\r
5370 SetupDropMenu(hmenu);
\r
5371 MenuPopup(hwnd, pt, hmenu, -1);
\r
5382 /* Preprocess messages for buttons in main window */
\r
5384 ButtonProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
5386 int id = GetWindowLong(hwnd, GWL_ID);
\r
5389 for (i=0; i<N_BUTTONS; i++) {
\r
5390 if (buttonDesc[i].id == id) break;
\r
5392 if (i == N_BUTTONS) return 0;
\r
5393 switch (message) {
\r
5398 dir = (wParam == VK_LEFT) ? -1 : 1;
\r
5399 SetFocus(buttonDesc[(i + dir + N_BUTTONS) % N_BUTTONS].hwnd);
\r
5406 SendMessage(hwndMain, WM_COMMAND, MAKEWPARAM(buttonDesc[i].id, 0), 0);
\r
5409 if (appData.icsActive && (isalpha((char)wParam) || wParam == '0')) {
\r
5410 // [HGM] movenum: only letters or leading zero should go to ICS input
\r
5411 HWND h = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
5412 if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
5414 SendMessage(h, WM_CHAR, wParam, lParam);
\r
5416 } else if (isalpha((char)wParam) || isdigit((char)wParam)){
\r
5417 PopUpMoveDialog((char)wParam);
\r
5423 return CallWindowProc(buttonDesc[i].wndproc, hwnd, message, wParam, lParam);
\r
5426 /* Process messages for Promotion dialog box */
\r
5428 Promotion(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
5432 switch (message) {
\r
5433 case WM_INITDIALOG: /* message: initialize dialog box */
\r
5434 /* Center the dialog over the application window */
\r
5435 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
5436 ShowWindow(GetDlgItem(hDlg, PB_King),
\r
5437 (!appData.testLegality || gameInfo.variant == VariantSuicide ||
\r
5438 gameInfo.variant == VariantGiveaway || gameInfo.variant == VariantSuper ) ?
\r
5439 SW_SHOW : SW_HIDE);
\r
5440 /* [HGM] Only allow C & A promotions if these pieces are defined */
\r
5441 ShowWindow(GetDlgItem(hDlg, PB_Archbishop),
\r
5442 ((PieceToChar(WhiteAngel) >= 'A' &&
\r
5443 PieceToChar(WhiteAngel) != '~') ||
\r
5444 (PieceToChar(BlackAngel) >= 'A' &&
\r
5445 PieceToChar(BlackAngel) != '~') ) ?
\r
5446 SW_SHOW : SW_HIDE);
\r
5447 ShowWindow(GetDlgItem(hDlg, PB_Chancellor),
\r
5448 ((PieceToChar(WhiteMarshall) >= 'A' &&
\r
5449 PieceToChar(WhiteMarshall) != '~') ||
\r
5450 (PieceToChar(BlackMarshall) >= 'A' &&
\r
5451 PieceToChar(BlackMarshall) != '~') ) ?
\r
5452 SW_SHOW : SW_HIDE);
\r
5453 /* [HGM] Hide B & R button in Shogi, use Q as promote, N as defer */
\r
5454 ShowWindow(GetDlgItem(hDlg, PB_Rook),
\r
5455 gameInfo.variant != VariantShogi ?
\r
5456 SW_SHOW : SW_HIDE);
\r
5457 ShowWindow(GetDlgItem(hDlg, PB_Bishop),
\r
5458 gameInfo.variant != VariantShogi ?
\r
5459 SW_SHOW : SW_HIDE);
\r
5460 ShowWindow(GetDlgItem(hDlg, IDC_Yes),
\r
5461 gameInfo.variant == VariantShogi ?
\r
5462 SW_SHOW : SW_HIDE);
\r
5463 ShowWindow(GetDlgItem(hDlg, IDC_No),
\r
5464 gameInfo.variant == VariantShogi ?
\r
5465 SW_SHOW : SW_HIDE);
\r
5466 ShowWindow(GetDlgItem(hDlg, IDC_Centaur),
\r
5467 gameInfo.variant == VariantSuper ?
\r
5468 SW_SHOW : SW_HIDE);
\r
5471 case WM_COMMAND: /* message: received a command */
\r
5472 switch (LOWORD(wParam)) {
\r
5474 EndDialog(hDlg, TRUE); /* Exit the dialog */
\r
5475 ClearHighlights();
\r
5476 DrawPosition(FALSE, NULL);
\r
5479 promoChar = gameInfo.variant == VariantSuper ? PieceToChar(BlackSilver) : PieceToChar(BlackKing);
\r
5482 promoChar = gameInfo.variant == VariantShogi ? '+' : PieceToChar(BlackQueen);
\r
5485 promoChar = PieceToChar(BlackRook);
\r
5488 promoChar = PieceToChar(BlackBishop);
\r
5490 case PB_Chancellor:
\r
5491 promoChar = PieceToChar(BlackMarshall);
\r
5493 case PB_Archbishop:
\r
5494 promoChar = PieceToChar(BlackAngel);
\r
5497 promoChar = gameInfo.variant == VariantShogi ? '=' : PieceToChar(BlackKnight);
\r
5502 EndDialog(hDlg, TRUE); /* Exit the dialog */
\r
5503 /* [HGM] <popupFix> Call FinishMove rather than UserMoveEvent, as we
\r
5504 only show the popup when we are already sure the move is valid or
\r
5505 legal. We pass a faulty move type, but the kludge is that FinishMove
\r
5506 will figure out it is a promotion from the promoChar. */
\r
5507 FinishMove(NormalMove, fromX, fromY, toX, toY, promoChar);
\r
5508 if (!appData.highlightLastMove) {
\r
5509 ClearHighlights();
\r
5510 DrawPosition(FALSE, NULL);
\r
5517 /* Pop up promotion dialog */
\r
5519 PromotionPopup(HWND hwnd)
\r
5523 lpProc = MakeProcInstance((FARPROC)Promotion, hInst);
\r
5524 DialogBox(hInst, MAKEINTRESOURCE(DLG_PromotionKing),
\r
5525 hwnd, (DLGPROC)lpProc);
\r
5526 FreeProcInstance(lpProc);
\r
5529 /* Toggle ShowThinking */
\r
5531 ToggleShowThinking()
\r
5533 appData.showThinking = !appData.showThinking;
\r
5534 ShowThinkingEvent();
\r
5538 LoadGameDialog(HWND hwnd, char* title)
\r
5542 char fileTitle[MSG_SIZ];
\r
5543 f = OpenFileDialog(hwnd, "rb", "",
\r
5544 appData.oldSaveStyle ? "gam" : "pgn",
\r
5546 title, &number, fileTitle, NULL);
\r
5548 cmailMsgLoaded = FALSE;
\r
5549 if (number == 0) {
\r
5550 int error = GameListBuild(f);
\r
5552 DisplayError("Cannot build game list", error);
\r
5553 } else if (!ListEmpty(&gameList) &&
\r
5554 ((ListGame *) gameList.tailPred)->number > 1) {
\r
5555 GameListPopUp(f, fileTitle);
\r
5558 GameListDestroy();
\r
5561 LoadGame(f, number, fileTitle, FALSE);
\r
5566 ChangedConsoleFont()
\r
5569 CHARRANGE tmpsel, sel;
\r
5570 MyFont *f = font[boardSize][CONSOLE_FONT];
\r
5571 HWND hText = GetDlgItem(hwndConsole, OPT_ConsoleText);
\r
5572 HWND hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
5575 cfmt.cbSize = sizeof(CHARFORMAT);
\r
5576 cfmt.dwMask = CFM_FACE|CFM_SIZE|CFM_CHARSET;
\r
5577 strcpy(cfmt.szFaceName, font[boardSize][CONSOLE_FONT]->mfp.faceName);
\r
5578 /* yHeight is expressed in twips. A twip is 1/20 of a font's point
\r
5579 * size. This was undocumented in the version of MSVC++ that I had
\r
5580 * when I wrote the code, but is apparently documented now.
\r
5582 cfmt.yHeight = (int)(f->mfp.pointSize * 20.0 + 0.5);
\r
5583 cfmt.bCharSet = f->lf.lfCharSet;
\r
5584 cfmt.bPitchAndFamily = f->lf.lfPitchAndFamily;
\r
5585 SendMessage(hText, EM_SETCHARFORMAT, SCF_ALL, (LPARAM) &cfmt);
\r
5586 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM) &cfmt);
\r
5587 /* Why are the following seemingly needed too? */
\r
5588 SendMessage(hText, EM_SETCHARFORMAT, SCF_DEFAULT, (LPARAM) &cfmt);
\r
5589 SendMessage(hInput, EM_SETCHARFORMAT, SCF_DEFAULT, (LPARAM) &cfmt);
\r
5590 SendMessage(hText, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
5592 tmpsel.cpMax = -1; /*999999?*/
\r
5593 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&tmpsel);
\r
5594 SendMessage(hText, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM) &cfmt);
\r
5595 /* Trying putting this here too. It still seems to tickle a RichEdit
\r
5596 * bug: sometimes RichEdit indents the first line of a paragraph too.
\r
5598 paraf.cbSize = sizeof(paraf);
\r
5599 paraf.dwMask = PFM_OFFSET | PFM_STARTINDENT;
\r
5600 paraf.dxStartIndent = 0;
\r
5601 paraf.dxOffset = WRAP_INDENT;
\r
5602 SendMessage(hText, EM_SETPARAFORMAT, 0, (LPARAM) ¶f);
\r
5603 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
5606 /*---------------------------------------------------------------------------*\
\r
5608 * Window Proc for main window
\r
5610 \*---------------------------------------------------------------------------*/
\r
5612 /* Process messages for main window, etc. */
\r
5614 WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
5617 int wmId, wmEvent;
\r
5621 char fileTitle[MSG_SIZ];
\r
5622 char buf[MSG_SIZ];
\r
5623 static SnapData sd;
\r
5625 switch (message) {
\r
5627 case WM_PAINT: /* message: repaint portion of window */
\r
5631 case WM_ERASEBKGND:
\r
5632 if (IsIconic(hwnd)) {
\r
5633 /* Cheat; change the message */
\r
5634 return (DefWindowProc(hwnd, WM_ICONERASEBKGND, wParam, lParam));
\r
5636 return (DefWindowProc(hwnd, message, wParam, lParam));
\r
5640 case WM_LBUTTONDOWN:
\r
5641 case WM_MBUTTONDOWN:
\r
5642 case WM_RBUTTONDOWN:
\r
5643 case WM_LBUTTONUP:
\r
5644 case WM_MBUTTONUP:
\r
5645 case WM_RBUTTONUP:
\r
5646 case WM_MOUSEMOVE:
\r
5647 case WM_MOUSEWHEEL:
\r
5648 MouseEvent(hwnd, message, wParam, lParam);
\r
5651 JAWS_KB_NAVIGATION
\r
5655 JAWS_ALT_INTERCEPT
\r
5657 if (appData.icsActive && (isalpha((char)wParam) || wParam == '0')) {
\r
5658 // [HGM] movenum: for non-zero digits we always do type-in dialog
\r
5659 HWND h = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
5660 if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
5662 SendMessage(h, message, wParam, lParam);
\r
5663 } else if(lParam != KF_REPEAT) {
\r
5664 if (isalpha((char)wParam) || isdigit((char)wParam)) {
\r
5665 PopUpMoveDialog((char)wParam);
\r
5671 case WM_PALETTECHANGED:
\r
5672 if (hwnd != (HWND)wParam && !appData.monoMode) {
\r
5674 HDC hdc = GetDC(hwndMain);
\r
5675 SelectPalette(hdc, hPal, TRUE);
\r
5676 nnew = RealizePalette(hdc);
\r
5678 paletteChanged = TRUE;
\r
5680 UpdateColors(hdc);
\r
5682 InvalidateRect(hwnd, &boardRect, FALSE);/*faster!*/
\r
5685 ReleaseDC(hwnd, hdc);
\r
5689 case WM_QUERYNEWPALETTE:
\r
5690 if (!appData.monoMode /*&& paletteChanged*/) {
\r
5692 HDC hdc = GetDC(hwndMain);
\r
5693 paletteChanged = FALSE;
\r
5694 SelectPalette(hdc, hPal, FALSE);
\r
5695 nnew = RealizePalette(hdc);
\r
5697 InvalidateRect(hwnd, &boardRect, FALSE);
\r
5699 ReleaseDC(hwnd, hdc);
\r
5704 case WM_COMMAND: /* message: command from application menu */
\r
5705 wmId = LOWORD(wParam);
\r
5706 wmEvent = HIWORD(wParam);
\r
5711 AnalysisPopDown();
\r
5712 SAY("new game enter a move to play against the computer with white");
\r
5715 case IDM_NewGameFRC:
\r
5716 if( NewGameFRC() == 0 ) {
\r
5718 AnalysisPopDown();
\r
5722 case IDM_NewVariant:
\r
5723 NewVariantPopup(hwnd);
\r
5726 case IDM_LoadGame:
\r
5727 LoadGameDialog(hwnd, "Load Game from File");
\r
5730 case IDM_LoadNextGame:
\r
5734 case IDM_LoadPrevGame:
\r
5738 case IDM_ReloadGame:
\r
5742 case IDM_LoadPosition:
\r
5743 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile) {
\r
5744 Reset(FALSE, TRUE);
\r
5747 f = OpenFileDialog(hwnd, "rb", "",
\r
5748 appData.oldSaveStyle ? "pos" : "fen",
\r
5750 "Load Position from File", &number, fileTitle, NULL);
\r
5752 LoadPosition(f, number, fileTitle);
\r
5756 case IDM_LoadNextPosition:
\r
5757 ReloadPosition(1);
\r
5760 case IDM_LoadPrevPosition:
\r
5761 ReloadPosition(-1);
\r
5764 case IDM_ReloadPosition:
\r
5765 ReloadPosition(0);
\r
5768 case IDM_SaveGame:
\r
5769 defName = DefaultFileName(appData.oldSaveStyle ? "gam" : "pgn");
\r
5770 f = OpenFileDialog(hwnd, "a", defName,
\r
5771 appData.oldSaveStyle ? "gam" : "pgn",
\r
5773 "Save Game to File", NULL, fileTitle, NULL);
\r
5775 SaveGame(f, 0, "");
\r
5779 case IDM_SavePosition:
\r
5780 defName = DefaultFileName(appData.oldSaveStyle ? "pos" : "fen");
\r
5781 f = OpenFileDialog(hwnd, "a", defName,
\r
5782 appData.oldSaveStyle ? "pos" : "fen",
\r
5784 "Save Position to File", NULL, fileTitle, NULL);
\r
5786 SavePosition(f, 0, "");
\r
5790 case IDM_SaveDiagram:
\r
5791 defName = "diagram";
\r
5792 f = OpenFileDialog(hwnd, "wb", defName,
\r
5795 "Save Diagram to File", NULL, fileTitle, NULL);
\r
5801 case IDM_CopyGame:
\r
5802 CopyGameToClipboard();
\r
5805 case IDM_PasteGame:
\r
5806 PasteGameFromClipboard();
\r
5809 case IDM_CopyGameListToClipboard:
\r
5810 CopyGameListToClipboard();
\r
5813 /* [AS] Autodetect FEN or PGN data */
\r
5814 case IDM_PasteAny:
\r
5815 PasteGameOrFENFromClipboard();
\r
5818 /* [AS] Move history */
\r
5819 case IDM_ShowMoveHistory:
\r
5820 if( MoveHistoryIsUp() ) {
\r
5821 MoveHistoryPopDown();
\r
5824 MoveHistoryPopUp();
\r
5828 /* [AS] Eval graph */
\r
5829 case IDM_ShowEvalGraph:
\r
5830 if( EvalGraphIsUp() ) {
\r
5831 EvalGraphPopDown();
\r
5835 SetFocus(hwndMain);
\r
5839 /* [AS] Engine output */
\r
5840 case IDM_ShowEngineOutput:
\r
5841 if( EngineOutputIsUp() ) {
\r
5842 EngineOutputPopDown();
\r
5845 EngineOutputPopUp();
\r
5849 /* [AS] User adjudication */
\r
5850 case IDM_UserAdjudication_White:
\r
5851 UserAdjudicationEvent( +1 );
\r
5854 case IDM_UserAdjudication_Black:
\r
5855 UserAdjudicationEvent( -1 );
\r
5858 case IDM_UserAdjudication_Draw:
\r
5859 UserAdjudicationEvent( 0 );
\r
5862 /* [AS] Game list options dialog */
\r
5863 case IDM_GameListOptions:
\r
5864 GameListOptions();
\r
5867 case IDM_CopyPosition:
\r
5868 CopyFENToClipboard();
\r
5871 case IDM_PastePosition:
\r
5872 PasteFENFromClipboard();
\r
5875 case IDM_MailMove:
\r
5879 case IDM_ReloadCMailMsg:
\r
5880 Reset(TRUE, TRUE);
\r
5881 ReloadCmailMsgEvent(FALSE);
\r
5884 case IDM_Minimize:
\r
5885 ShowWindow(hwnd, SW_MINIMIZE);
\r
5892 case IDM_MachineWhite:
\r
5893 MachineWhiteEvent();
\r
5895 * refresh the tags dialog only if it's visible
\r
5897 if (gameMode == MachinePlaysWhite && IsWindowVisible(editTagsDialog)) {
\r
5899 tags = PGNTags(&gameInfo);
\r
5900 TagsPopUp(tags, CmailMsg());
\r
5903 SAY("computer starts playing white");
\r
5906 case IDM_MachineBlack:
\r
5907 MachineBlackEvent();
\r
5909 * refresh the tags dialog only if it's visible
\r
5911 if (gameMode == MachinePlaysBlack && IsWindowVisible(editTagsDialog)) {
\r
5913 tags = PGNTags(&gameInfo);
\r
5914 TagsPopUp(tags, CmailMsg());
\r
5917 SAY("computer starts playing black");
\r
5920 case IDM_TwoMachines:
\r
5921 TwoMachinesEvent();
\r
5923 * refresh the tags dialog only if it's visible
\r
5925 if (gameMode == TwoMachinesPlay && IsWindowVisible(editTagsDialog)) {
\r
5927 tags = PGNTags(&gameInfo);
\r
5928 TagsPopUp(tags, CmailMsg());
\r
5931 SAY("programs start playing each other");
\r
5934 case IDM_AnalysisMode:
\r
5935 if (!first.analysisSupport) {
\r
5936 sprintf(buf, "%s does not support analysis", first.tidy);
\r
5937 DisplayError(buf, 0);
\r
5939 SAY("analyzing current position");
\r
5940 /* [DM] icsEngineAnlyze [HGM] Why is this front-end??? */
\r
5941 if (appData.icsActive) {
\r
5942 if (gameMode != IcsObserving) {
\r
5943 sprintf(buf, "You are not observing a game");
\r
5944 DisplayError(buf, 0);
\r
5945 /* secure check */
\r
5946 if (appData.icsEngineAnalyze) {
\r
5947 if (appData.debugMode)
\r
5948 fprintf(debugFP, "Found unexpected active ICS engine analyze \n");
\r
5949 ExitAnalyzeMode();
\r
5955 /* if enable, user want disable icsEngineAnalyze */
\r
5956 if (appData.icsEngineAnalyze) {
\r
5957 ExitAnalyzeMode();
\r
5961 appData.icsEngineAnalyze = TRUE;
\r
5962 if (appData.debugMode) fprintf(debugFP, "ICS engine analyze starting...\n");
\r
5965 if (!appData.showThinking) ToggleShowThinking();
\r
5966 AnalyzeModeEvent();
\r
5970 case IDM_AnalyzeFile:
\r
5971 if (!first.analysisSupport) {
\r
5972 char buf[MSG_SIZ];
\r
5973 sprintf(buf, "%s does not support analysis", first.tidy);
\r
5974 DisplayError(buf, 0);
\r
5976 if (!appData.showThinking) ToggleShowThinking();
\r
5977 AnalyzeFileEvent();
\r
5978 LoadGameDialog(hwnd, "Analyze Game from File");
\r
5979 AnalysisPeriodicEvent(1);
\r
5983 case IDM_IcsClient:
\r
5987 case IDM_EditGame:
\r
5992 case IDM_EditPosition:
\r
5993 EditPositionEvent();
\r
5994 SAY("to set up a position type a FEN");
\r
5997 case IDM_Training:
\r
6001 case IDM_ShowGameList:
\r
6002 ShowGameListProc();
\r
6005 case IDM_EditTags:
\r
6009 case IDM_EditComment:
\r
6010 if (commentDialogUp && editComment) {
\r
6013 EditCommentEvent();
\r
6033 case IDM_CallFlag:
\r
6053 case IDM_StopObserving:
\r
6054 StopObservingEvent();
\r
6057 case IDM_StopExamining:
\r
6058 StopExaminingEvent();
\r
6061 case IDM_TypeInMove:
\r
6062 PopUpMoveDialog('\000');
\r
6065 case IDM_TypeInName:
\r
6066 PopUpNameDialog('\000');
\r
6069 case IDM_Backward:
\r
6071 SetFocus(hwndMain);
\r
6078 SetFocus(hwndMain);
\r
6083 SetFocus(hwndMain);
\r
6088 SetFocus(hwndMain);
\r
6095 case IDM_TruncateGame:
\r
6096 TruncateGameEvent();
\r
6103 case IDM_RetractMove:
\r
6104 RetractMoveEvent();
\r
6107 case IDM_FlipView:
\r
6108 flipView = !flipView;
\r
6109 DrawPosition(FALSE, NULL);
\r
6112 case IDM_FlipClock:
\r
6113 flipClock = !flipClock;
\r
6114 DisplayBothClocks();
\r
6115 DrawPosition(FALSE, NULL);
\r
6118 case IDM_GeneralOptions:
\r
6119 GeneralOptionsPopup(hwnd);
\r
6120 DrawPosition(TRUE, NULL);
\r
6123 case IDM_BoardOptions:
\r
6124 BoardOptionsPopup(hwnd);
\r
6127 case IDM_EnginePlayOptions:
\r
6128 EnginePlayOptionsPopup(hwnd);
\r
6131 case IDM_OptionsUCI:
\r
6132 UciOptionsPopup(hwnd);
\r
6135 case IDM_IcsOptions:
\r
6136 IcsOptionsPopup(hwnd);
\r
6140 FontsOptionsPopup(hwnd);
\r
6144 SoundOptionsPopup(hwnd);
\r
6147 case IDM_CommPort:
\r
6148 CommPortOptionsPopup(hwnd);
\r
6151 case IDM_LoadOptions:
\r
6152 LoadOptionsPopup(hwnd);
\r
6155 case IDM_SaveOptions:
\r
6156 SaveOptionsPopup(hwnd);
\r
6159 case IDM_TimeControl:
\r
6160 TimeControlOptionsPopup(hwnd);
\r
6163 case IDM_SaveSettings:
\r
6164 SaveSettings(settingsFileName);
\r
6167 case IDM_SaveSettingsOnExit:
\r
6168 saveSettingsOnExit = !saveSettingsOnExit;
\r
6169 (void) CheckMenuItem(GetMenu(hwndMain), IDM_SaveSettingsOnExit,
\r
6170 MF_BYCOMMAND|(saveSettingsOnExit ?
\r
6171 MF_CHECKED : MF_UNCHECKED));
\r
6182 case IDM_AboutGame:
\r
6187 appData.debugMode = !appData.debugMode;
\r
6188 if (appData.debugMode) {
\r
6189 char dir[MSG_SIZ];
\r
6190 GetCurrentDirectory(MSG_SIZ, dir);
\r
6191 SetCurrentDirectory(installDir);
\r
6192 debugFP = fopen(appData.nameOfDebugFile, "w");
\r
6193 SetCurrentDirectory(dir);
\r
6194 setbuf(debugFP, NULL);
\r
6201 case IDM_HELPCONTENTS:
\r
6202 if (!MyHelp (hwnd, "winboard.hlp", HELP_KEY,(DWORD)(LPSTR)"CONTENTS") &&
\r
6203 !HtmlHelp(hwnd, "winboard.chm", 0, 0) ) {
\r
6204 MessageBox (GetFocus(),
\r
6205 "Unable to activate help",
\r
6206 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
6210 case IDM_HELPSEARCH:
\r
6211 if (!MyHelp (hwnd, "winboard.hlp", HELP_PARTIALKEY, (DWORD)(LPSTR)"") &&
\r
6212 !HtmlHelp(hwnd, "winboard.chm", 0, 0) ) {
\r
6213 MessageBox (GetFocus(),
\r
6214 "Unable to activate help",
\r
6215 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
6219 case IDM_HELPHELP:
\r
6220 if(!WinHelp(hwnd, (LPSTR)NULL, HELP_HELPONHELP, 0)) {
\r
6221 MessageBox (GetFocus(),
\r
6222 "Unable to activate help",
\r
6223 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
6228 lpProc = MakeProcInstance((FARPROC)About, hInst);
\r
6230 (gameInfo.event && strcmp(gameInfo.event, "Easter Egg Hunt") == 0) ?
\r
6231 "AboutBox2" : "AboutBox", hwnd, (DLGPROC)lpProc);
\r
6232 FreeProcInstance(lpProc);
\r
6235 case IDM_DirectCommand1:
\r
6236 AskQuestionEvent("Direct Command",
\r
6237 "Send to chess program:", "", "1");
\r
6239 case IDM_DirectCommand2:
\r
6240 AskQuestionEvent("Direct Command",
\r
6241 "Send to second chess program:", "", "2");
\r
6244 case EP_WhitePawn:
\r
6245 EditPositionMenuEvent(WhitePawn, fromX, fromY);
\r
6246 fromX = fromY = -1;
\r
6249 case EP_WhiteKnight:
\r
6250 EditPositionMenuEvent(WhiteKnight, fromX, fromY);
\r
6251 fromX = fromY = -1;
\r
6254 case EP_WhiteBishop:
\r
6255 EditPositionMenuEvent(WhiteBishop, fromX, fromY);
\r
6256 fromX = fromY = -1;
\r
6259 case EP_WhiteRook:
\r
6260 EditPositionMenuEvent(WhiteRook, fromX, fromY);
\r
6261 fromX = fromY = -1;
\r
6264 case EP_WhiteQueen:
\r
6265 EditPositionMenuEvent(WhiteQueen, fromX, fromY);
\r
6266 fromX = fromY = -1;
\r
6269 case EP_WhiteFerz:
\r
6270 EditPositionMenuEvent(WhiteFerz, fromX, fromY);
\r
6271 fromX = fromY = -1;
\r
6274 case EP_WhiteWazir:
\r
6275 EditPositionMenuEvent(WhiteWazir, fromX, fromY);
\r
6276 fromX = fromY = -1;
\r
6279 case EP_WhiteAlfil:
\r
6280 EditPositionMenuEvent(WhiteAlfil, fromX, fromY);
\r
6281 fromX = fromY = -1;
\r
6284 case EP_WhiteCannon:
\r
6285 EditPositionMenuEvent(WhiteCannon, fromX, fromY);
\r
6286 fromX = fromY = -1;
\r
6289 case EP_WhiteCardinal:
\r
6290 EditPositionMenuEvent(WhiteAngel, fromX, fromY);
\r
6291 fromX = fromY = -1;
\r
6294 case EP_WhiteMarshall:
\r
6295 EditPositionMenuEvent(WhiteMarshall, fromX, fromY);
\r
6296 fromX = fromY = -1;
\r
6299 case EP_WhiteKing:
\r
6300 EditPositionMenuEvent(WhiteKing, fromX, fromY);
\r
6301 fromX = fromY = -1;
\r
6304 case EP_BlackPawn:
\r
6305 EditPositionMenuEvent(BlackPawn, fromX, fromY);
\r
6306 fromX = fromY = -1;
\r
6309 case EP_BlackKnight:
\r
6310 EditPositionMenuEvent(BlackKnight, fromX, fromY);
\r
6311 fromX = fromY = -1;
\r
6314 case EP_BlackBishop:
\r
6315 EditPositionMenuEvent(BlackBishop, fromX, fromY);
\r
6316 fromX = fromY = -1;
\r
6319 case EP_BlackRook:
\r
6320 EditPositionMenuEvent(BlackRook, fromX, fromY);
\r
6321 fromX = fromY = -1;
\r
6324 case EP_BlackQueen:
\r
6325 EditPositionMenuEvent(BlackQueen, fromX, fromY);
\r
6326 fromX = fromY = -1;
\r
6329 case EP_BlackFerz:
\r
6330 EditPositionMenuEvent(BlackFerz, fromX, fromY);
\r
6331 fromX = fromY = -1;
\r
6334 case EP_BlackWazir:
\r
6335 EditPositionMenuEvent(BlackWazir, fromX, fromY);
\r
6336 fromX = fromY = -1;
\r
6339 case EP_BlackAlfil:
\r
6340 EditPositionMenuEvent(BlackAlfil, fromX, fromY);
\r
6341 fromX = fromY = -1;
\r
6344 case EP_BlackCannon:
\r
6345 EditPositionMenuEvent(BlackCannon, fromX, fromY);
\r
6346 fromX = fromY = -1;
\r
6349 case EP_BlackCardinal:
\r
6350 EditPositionMenuEvent(BlackAngel, fromX, fromY);
\r
6351 fromX = fromY = -1;
\r
6354 case EP_BlackMarshall:
\r
6355 EditPositionMenuEvent(BlackMarshall, fromX, fromY);
\r
6356 fromX = fromY = -1;
\r
6359 case EP_BlackKing:
\r
6360 EditPositionMenuEvent(BlackKing, fromX, fromY);
\r
6361 fromX = fromY = -1;
\r
6364 case EP_EmptySquare:
\r
6365 EditPositionMenuEvent(EmptySquare, fromX, fromY);
\r
6366 fromX = fromY = -1;
\r
6369 case EP_ClearBoard:
\r
6370 EditPositionMenuEvent(ClearBoard, fromX, fromY);
\r
6371 fromX = fromY = -1;
\r
6375 EditPositionMenuEvent(WhitePlay, fromX, fromY);
\r
6376 fromX = fromY = -1;
\r
6380 EditPositionMenuEvent(BlackPlay, fromX, fromY);
\r
6381 fromX = fromY = -1;
\r
6385 EditPositionMenuEvent(PromotePiece, fromX, fromY);
\r
6386 fromX = fromY = -1;
\r
6390 EditPositionMenuEvent(DemotePiece, fromX, fromY);
\r
6391 fromX = fromY = -1;
\r
6395 DropMenuEvent(WhitePawn, fromX, fromY);
\r
6396 fromX = fromY = -1;
\r
6400 DropMenuEvent(WhiteKnight, fromX, fromY);
\r
6401 fromX = fromY = -1;
\r
6405 DropMenuEvent(WhiteBishop, fromX, fromY);
\r
6406 fromX = fromY = -1;
\r
6410 DropMenuEvent(WhiteRook, fromX, fromY);
\r
6411 fromX = fromY = -1;
\r
6415 DropMenuEvent(WhiteQueen, fromX, fromY);
\r
6416 fromX = fromY = -1;
\r
6420 return (DefWindowProc(hwnd, message, wParam, lParam));
\r
6426 case CLOCK_TIMER_ID:
\r
6427 KillTimer(hwnd, clockTimerEvent); /* Simulate one-shot timer as in X */
\r
6428 clockTimerEvent = 0;
\r
6429 DecrementClocks(); /* call into back end */
\r
6431 case LOAD_GAME_TIMER_ID:
\r
6432 KillTimer(hwnd, loadGameTimerEvent); /* Simulate one-shot timer as in X*/
\r
6433 loadGameTimerEvent = 0;
\r
6434 AutoPlayGameLoop(); /* call into back end */
\r
6436 case ANALYSIS_TIMER_ID:
\r
6437 if ((gameMode == AnalyzeMode || gameMode == AnalyzeFile
\r
6438 || appData.icsEngineAnalyze) && appData.periodicUpdates) {
\r
6439 AnalysisPeriodicEvent(0);
\r
6441 KillTimer(hwnd, analysisTimerEvent);
\r
6442 analysisTimerEvent = 0;
\r
6445 case DELAYED_TIMER_ID:
\r
6446 KillTimer(hwnd, delayedTimerEvent);
\r
6447 delayedTimerEvent = 0;
\r
6448 delayedTimerCallback();
\r
6453 case WM_USER_Input:
\r
6454 InputEvent(hwnd, message, wParam, lParam);
\r
6457 /* [AS] Also move "attached" child windows */
\r
6458 case WM_WINDOWPOSCHANGING:
\r
6460 if( hwnd == hwndMain && appData.useStickyWindows ) {
\r
6461 LPWINDOWPOS lpwp = (LPWINDOWPOS) lParam;
\r
6463 if( ((lpwp->flags & SWP_NOMOVE) == 0) && ((lpwp->flags & SWP_NOSIZE) != 0) ) {
\r
6464 /* Window is moving */
\r
6467 // GetWindowRect( hwnd, &rcMain ); //[HGM] sticky: in XP this returned new position, not old
\r
6468 rcMain.left = boardX; // replace by these 4 lines to reconstruct old rect
\r
6469 rcMain.right = boardX + winWidth;
\r
6470 rcMain.top = boardY;
\r
6471 rcMain.bottom = boardY + winHeight;
\r
6473 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, moveHistoryDialog, &wpMoveHistory );
\r
6474 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, evalGraphDialog, &wpEvalGraph );
\r
6475 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, engineOutputDialog, &wpEngineOutput );
\r
6476 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, gameListDialog, &wpGameList );
\r
6477 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, hwndConsole, &wpConsole );
\r
6484 /* [AS] Snapping */
\r
6485 case WM_ENTERSIZEMOVE:
\r
6486 if(appData.debugMode) { fprintf(debugFP, "size-move\n"); }
\r
6487 if (hwnd == hwndMain) {
\r
6488 doingSizing = TRUE;
\r
6491 return OnEnterSizeMove( &sd, hwnd, wParam, lParam );
\r
6495 if(appData.debugMode) { fprintf(debugFP, "sizing\n"); }
\r
6496 if (hwnd == hwndMain) {
\r
6497 lastSizing = wParam;
\r
6502 if(appData.debugMode) { fprintf(debugFP, "moving\n"); }
\r
6503 return OnMoving( &sd, hwnd, wParam, lParam );
\r
6505 case WM_EXITSIZEMOVE:
\r
6506 if(appData.debugMode) { fprintf(debugFP, "exit size-move, size = %d\n", squareSize); }
\r
6507 if (hwnd == hwndMain) {
\r
6509 doingSizing = FALSE;
\r
6510 InvalidateRect(hwnd, &boardRect, FALSE);
\r
6511 GetClientRect(hwnd, &client);
\r
6512 ResizeBoard(client.right, client.bottom, lastSizing);
\r
6514 if(appData.debugMode) { fprintf(debugFP, "square size = %d\n", squareSize); }
\r
6516 return OnExitSizeMove( &sd, hwnd, wParam, lParam );
\r
6519 case WM_DESTROY: /* message: window being destroyed */
\r
6520 PostQuitMessage(0);
\r
6524 if (hwnd == hwndMain) {
\r
6529 default: /* Passes it on if unprocessed */
\r
6530 return (DefWindowProc(hwnd, message, wParam, lParam));
\r
6535 /*---------------------------------------------------------------------------*\
\r
6537 * Misc utility routines
\r
6539 \*---------------------------------------------------------------------------*/
\r
6542 * Decent random number generator, at least not as bad as Windows
\r
6543 * standard rand, which returns a value in the range 0 to 0x7fff.
\r
6545 unsigned int randstate;
\r
6550 randstate = randstate * 1664525 + 1013904223;
\r
6551 return (int) randstate & 0x7fffffff;
\r
6555 mysrandom(unsigned int seed)
\r
6562 * returns TRUE if user selects a different color, FALSE otherwise
\r
6566 ChangeColor(HWND hwnd, COLORREF *which)
\r
6568 static BOOL firstTime = TRUE;
\r
6569 static DWORD customColors[16];
\r
6571 COLORREF newcolor;
\r
6576 /* Make initial colors in use available as custom colors */
\r
6577 /* Should we put the compiled-in defaults here instead? */
\r
6579 customColors[i++] = lightSquareColor & 0xffffff;
\r
6580 customColors[i++] = darkSquareColor & 0xffffff;
\r
6581 customColors[i++] = whitePieceColor & 0xffffff;
\r
6582 customColors[i++] = blackPieceColor & 0xffffff;
\r
6583 customColors[i++] = highlightSquareColor & 0xffffff;
\r
6584 customColors[i++] = premoveHighlightColor & 0xffffff;
\r
6586 for (ccl = (ColorClass) 0; ccl < NColorClasses && i < 16; ccl++) {
\r
6587 customColors[i++] = textAttribs[ccl].color;
\r
6589 while (i < 16) customColors[i++] = RGB(255, 255, 255);
\r
6590 firstTime = FALSE;
\r
6593 cc.lStructSize = sizeof(cc);
\r
6594 cc.hwndOwner = hwnd;
\r
6595 cc.hInstance = NULL;
\r
6596 cc.rgbResult = (DWORD) (*which & 0xffffff);
\r
6597 cc.lpCustColors = (LPDWORD) customColors;
\r
6598 cc.Flags = CC_RGBINIT|CC_FULLOPEN;
\r
6600 if (!ChooseColor(&cc)) return FALSE;
\r
6602 newcolor = (COLORREF) (0x2000000 | cc.rgbResult);
\r
6603 if (newcolor == *which) return FALSE;
\r
6604 *which = newcolor;
\r
6608 InitDrawingColors();
\r
6609 InvalidateRect(hwnd, &boardRect, FALSE);
\r
6614 MyLoadSound(MySound *ms)
\r
6620 if (ms->data) free(ms->data);
\r
6623 switch (ms->name[0]) {
\r
6629 /* System sound from Control Panel. Don't preload here. */
\r
6633 if (ms->name[1] == NULLCHAR) {
\r
6634 /* "!" alone = silence */
\r
6637 /* Builtin wave resource. Error if not found. */
\r
6638 HANDLE h = FindResource(hInst, ms->name + 1, "WAVE");
\r
6639 if (h == NULL) break;
\r
6640 ms->data = (void *)LoadResource(hInst, h);
\r
6641 if (h == NULL) break;
\r
6646 /* .wav file. Error if not found. */
\r
6647 f = fopen(ms->name, "rb");
\r
6648 if (f == NULL) break;
\r
6649 if (fstat(fileno(f), &st) < 0) break;
\r
6650 ms->data = malloc(st.st_size);
\r
6651 if (fread(ms->data, st.st_size, 1, f) < 1) break;
\r
6657 char buf[MSG_SIZ];
\r
6658 sprintf(buf, "Error loading sound %s", ms->name);
\r
6659 DisplayError(buf, GetLastError());
\r
6665 MyPlaySound(MySound *ms)
\r
6667 BOOLEAN ok = FALSE;
\r
6668 if(appData.debugMode) fprintf(debugFP, "make sound %s %x %d\n", ms->name, ms, ms->name[0]);
\r
6669 switch (ms->name[0]) {
\r
6671 if(appData.debugMode) fprintf(debugFP, "silence\n");
\r
6676 /* System sound from Control Panel (deprecated feature).
\r
6677 "$" alone or an unset sound name gets default beep (still in use). */
\r
6678 if (ms->name[1]) {
\r
6679 ok = PlaySound(ms->name + 1, NULL, SND_ALIAS|SND_ASYNC);
\r
6681 if (!ok) ok = MessageBeep(MB_OK);
\r
6684 /* Builtin wave resource, or "!" alone for silence */
\r
6685 if (ms->name[1]) {
\r
6686 if (ms->data == NULL) return FALSE;
\r
6687 ok = PlaySound(ms->data, NULL, SND_MEMORY|SND_ASYNC);
\r
6693 /* .wav file. Error if not found. */
\r
6694 if (ms->data == NULL) return FALSE;
\r
6695 ok = PlaySound(ms->data, NULL, SND_MEMORY|SND_ASYNC);
\r
6698 /* Don't print an error: this can happen innocently if the sound driver
\r
6699 is busy; for instance, if another instance of WinBoard is playing
\r
6700 a sound at about the same time. */
\r
6703 char buf[MSG_SIZ];
\r
6704 sprintf(buf, "Error playing sound %s", ms->name);
\r
6705 DisplayError(buf, GetLastError());
\r
6713 OldOpenFileHook(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
6716 OPENFILENAME *ofn;
\r
6717 static UINT *number; /* gross that this is static */
\r
6719 switch (message) {
\r
6720 case WM_INITDIALOG: /* message: initialize dialog box */
\r
6721 /* Center the dialog over the application window */
\r
6722 ofn = (OPENFILENAME *) lParam;
\r
6723 if (ofn->Flags & OFN_ENABLETEMPLATE) {
\r
6724 number = (UINT *) ofn->lCustData;
\r
6725 SendMessage(GetDlgItem(hDlg, edt2), WM_SETTEXT, 0, (LPARAM) "");
\r
6729 CenterWindow (hDlg, GetWindow (hDlg, GW_OWNER));
\r
6730 return FALSE; /* Allow for further processing */
\r
6733 if ((LOWORD(wParam) == IDOK) && (number != NULL)) {
\r
6734 *number = GetDlgItemInt(hDlg, OPT_IndexNumberOld, &ok, FALSE);
\r
6736 return FALSE; /* Allow for further processing */
\r
6742 OpenFileHook(HWND hdlg, UINT uiMsg, WPARAM wParam, LPARAM lParam)
\r
6744 static UINT *number;
\r
6745 OPENFILENAME *ofname;
\r
6748 case WM_INITDIALOG:
\r
6749 ofname = (OPENFILENAME *)lParam;
\r
6750 number = (UINT *)(ofname->lCustData);
\r
6753 ofnot = (OFNOTIFY *)lParam;
\r
6754 if (ofnot->hdr.code == CDN_FILEOK) {
\r
6755 *number = GetDlgItemInt(hdlg, OPT_IndexNumber, NULL, FALSE);
\r
6764 OpenFileDialog(HWND hwnd, char *write, char *defName, char *defExt, // [HGM] diag: type of 'write' now string
\r
6765 char *nameFilt, char *dlgTitle, UINT *number,
\r
6766 char fileTitle[MSG_SIZ], char fileName[MSG_SIZ])
\r
6768 OPENFILENAME openFileName;
\r
6769 char buf1[MSG_SIZ];
\r
6772 if (fileName == NULL) fileName = buf1;
\r
6773 if (defName == NULL) {
\r
6774 strcpy(fileName, "*.");
\r
6775 strcat(fileName, defExt);
\r
6777 strcpy(fileName, defName);
\r
6779 if (fileTitle) strcpy(fileTitle, "");
\r
6780 if (number) *number = 0;
\r
6782 openFileName.lStructSize = sizeof(OPENFILENAME);
\r
6783 openFileName.hwndOwner = hwnd;
\r
6784 openFileName.hInstance = (HANDLE) hInst;
\r
6785 openFileName.lpstrFilter = nameFilt;
\r
6786 openFileName.lpstrCustomFilter = (LPSTR) NULL;
\r
6787 openFileName.nMaxCustFilter = 0L;
\r
6788 openFileName.nFilterIndex = 1L;
\r
6789 openFileName.lpstrFile = fileName;
\r
6790 openFileName.nMaxFile = MSG_SIZ;
\r
6791 openFileName.lpstrFileTitle = fileTitle;
\r
6792 openFileName.nMaxFileTitle = fileTitle ? MSG_SIZ : 0;
\r
6793 openFileName.lpstrInitialDir = NULL;
\r
6794 openFileName.lpstrTitle = dlgTitle;
\r
6795 openFileName.Flags = OFN_PATHMUSTEXIST | OFN_HIDEREADONLY
\r
6796 | (write[0] != 'r' ? 0 : OFN_FILEMUSTEXIST)
\r
6797 | (number ? OFN_ENABLETEMPLATE | OFN_ENABLEHOOK: 0)
\r
6798 | (oldDialog ? 0 : OFN_EXPLORER);
\r
6799 openFileName.nFileOffset = 0;
\r
6800 openFileName.nFileExtension = 0;
\r
6801 openFileName.lpstrDefExt = defExt;
\r
6802 openFileName.lCustData = (LONG) number;
\r
6803 openFileName.lpfnHook = oldDialog ?
\r
6804 (LPOFNHOOKPROC) OldOpenFileHook : (LPOFNHOOKPROC) OpenFileHook;
\r
6805 openFileName.lpTemplateName = (LPSTR)(oldDialog ? 1536 : DLG_IndexNumber);
\r
6807 if (write[0] != 'r' ? GetSaveFileName(&openFileName) :
\r
6808 GetOpenFileName(&openFileName)) {
\r
6809 /* open the file */
\r
6810 f = fopen(openFileName.lpstrFile, write);
\r
6812 MessageBox(hwnd, "File open failed", NULL,
\r
6813 MB_OK|MB_ICONEXCLAMATION);
\r
6817 int err = CommDlgExtendedError();
\r
6818 if (err != 0) DisplayError("Internal error in file dialog box", err);
\r
6827 MenuPopup(HWND hwnd, POINT pt, HMENU hmenu, UINT def)
\r
6829 HMENU hmenuTrackPopup; /* floating pop-up menu */
\r
6832 * Get the first pop-up menu in the menu template. This is the
\r
6833 * menu that TrackPopupMenu displays.
\r
6835 hmenuTrackPopup = GetSubMenu(hmenu, 0);
\r
6837 SetMenuDefaultItem(hmenuTrackPopup, def, FALSE);
\r
6840 * TrackPopup uses screen coordinates, so convert the
\r
6841 * coordinates of the mouse click to screen coordinates.
\r
6843 ClientToScreen(hwnd, (LPPOINT) &pt);
\r
6845 /* Draw and track the floating pop-up menu. */
\r
6846 TrackPopupMenu(hmenuTrackPopup, TPM_CENTERALIGN | TPM_RIGHTBUTTON,
\r
6847 pt.x, pt.y, 0, hwnd, NULL);
\r
6849 /* Destroy the menu.*/
\r
6850 DestroyMenu(hmenu);
\r
6855 int sizeX, sizeY, newSizeX, newSizeY;
\r
6857 } ResizeEditPlusButtonsClosure;
\r
6860 ResizeEditPlusButtonsCallback(HWND hChild, LPARAM lparam)
\r
6862 ResizeEditPlusButtonsClosure *cl = (ResizeEditPlusButtonsClosure *)lparam;
\r
6866 if (hChild == cl->hText) return TRUE;
\r
6867 GetWindowRect(hChild, &rect); /* gives screen coords */
\r
6868 pt.x = rect.left + (cl->newSizeX - cl->sizeX)/2;
\r
6869 pt.y = rect.top + cl->newSizeY - cl->sizeY;
\r
6870 ScreenToClient(cl->hDlg, &pt);
\r
6871 cl->hdwp = DeferWindowPos(cl->hdwp, hChild, NULL,
\r
6872 pt.x, pt.y, rect.right - rect.left, rect.bottom - rect.top, SWP_NOZORDER);
\r
6876 /* Resize a dialog that has a (rich) edit field filling most of
\r
6877 the top, with a row of buttons below */
\r
6879 ResizeEditPlusButtons(HWND hDlg, HWND hText, int sizeX, int sizeY, int newSizeX, int newSizeY)
\r
6882 int newTextHeight, newTextWidth;
\r
6883 ResizeEditPlusButtonsClosure cl;
\r
6885 /*if (IsIconic(hDlg)) return;*/
\r
6886 if (newSizeX == sizeX && newSizeY == sizeY) return;
\r
6888 cl.hdwp = BeginDeferWindowPos(8);
\r
6890 GetWindowRect(hText, &rectText); /* gives screen coords */
\r
6891 newTextWidth = rectText.right - rectText.left + newSizeX - sizeX;
\r
6892 newTextHeight = rectText.bottom - rectText.top + newSizeY - sizeY;
\r
6893 if (newTextHeight < 0) {
\r
6894 newSizeY += -newTextHeight;
\r
6895 newTextHeight = 0;
\r
6897 cl.hdwp = DeferWindowPos(cl.hdwp, hText, NULL, 0, 0,
\r
6898 newTextWidth, newTextHeight, SWP_NOZORDER|SWP_NOMOVE);
\r
6904 cl.newSizeX = newSizeX;
\r
6905 cl.newSizeY = newSizeY;
\r
6906 EnumChildWindows(hDlg, ResizeEditPlusButtonsCallback, (LPARAM)&cl);
\r
6908 EndDeferWindowPos(cl.hdwp);
\r
6911 BOOL CenterWindowEx(HWND hwndChild, HWND hwndParent, int mode)
\r
6913 RECT rChild, rParent;
\r
6914 int wChild, hChild, wParent, hParent;
\r
6915 int wScreen, hScreen, xNew, yNew;
\r
6918 /* Get the Height and Width of the child window */
\r
6919 GetWindowRect (hwndChild, &rChild);
\r
6920 wChild = rChild.right - rChild.left;
\r
6921 hChild = rChild.bottom - rChild.top;
\r
6923 /* Get the Height and Width of the parent window */
\r
6924 GetWindowRect (hwndParent, &rParent);
\r
6925 wParent = rParent.right - rParent.left;
\r
6926 hParent = rParent.bottom - rParent.top;
\r
6928 /* Get the display limits */
\r
6929 hdc = GetDC (hwndChild);
\r
6930 wScreen = GetDeviceCaps (hdc, HORZRES);
\r
6931 hScreen = GetDeviceCaps (hdc, VERTRES);
\r
6932 ReleaseDC(hwndChild, hdc);
\r
6934 /* Calculate new X position, then adjust for screen */
\r
6935 xNew = rParent.left + ((wParent - wChild) /2);
\r
6938 } else if ((xNew+wChild) > wScreen) {
\r
6939 xNew = wScreen - wChild;
\r
6942 /* Calculate new Y position, then adjust for screen */
\r
6944 yNew = rParent.top + ((hParent - hChild) /2);
\r
6947 yNew = rParent.top + GetSystemMetrics( SM_CYCAPTION ) * 2 / 3;
\r
6952 } else if ((yNew+hChild) > hScreen) {
\r
6953 yNew = hScreen - hChild;
\r
6956 /* Set it, and return */
\r
6957 return SetWindowPos (hwndChild, NULL,
\r
6958 xNew, yNew, 0, 0, SWP_NOSIZE | SWP_NOZORDER);
\r
6961 /* Center one window over another */
\r
6962 BOOL CenterWindow (HWND hwndChild, HWND hwndParent)
\r
6964 return CenterWindowEx( hwndChild, hwndParent, 0 );
\r
6967 /*---------------------------------------------------------------------------*\
\r
6969 * Startup Dialog functions
\r
6971 \*---------------------------------------------------------------------------*/
\r
6973 InitComboStrings(HANDLE hwndCombo, char **cd)
\r
6975 SendMessage(hwndCombo, CB_RESETCONTENT, 0, 0);
\r
6977 while (*cd != NULL) {
\r
6978 SendMessage(hwndCombo, CB_ADDSTRING, 0, (LPARAM) *cd);
\r
6984 InitComboStringsFromOption(HANDLE hwndCombo, char *str)
\r
6986 char buf1[ARG_MAX];
\r
6989 if (str[0] == '@') {
\r
6990 FILE* f = fopen(str + 1, "r");
\r
6992 DisplayFatalError(str + 1, errno, 2);
\r
6995 len = fread(buf1, 1, sizeof(buf1)-1, f);
\r
6997 buf1[len] = NULLCHAR;
\r
7001 SendMessage(hwndCombo, CB_RESETCONTENT, 0, 0);
\r
7004 char buf[MSG_SIZ];
\r
7005 char *end = strchr(str, '\n');
\r
7006 if (end == NULL) return;
\r
7007 memcpy(buf, str, end - str);
\r
7008 buf[end - str] = NULLCHAR;
\r
7009 SendMessage(hwndCombo, CB_ADDSTRING, 0, (LPARAM) buf);
\r
7015 SetStartupDialogEnables(HWND hDlg)
\r
7017 EnableWindow(GetDlgItem(hDlg, OPT_ChessEngineName),
\r
7018 IsDlgButtonChecked(hDlg, OPT_ChessEngine) ||
\r
7019 (appData.zippyPlay && IsDlgButtonChecked(hDlg, OPT_ChessServer)));
\r
7020 EnableWindow(GetDlgItem(hDlg, OPT_SecondChessEngineName),
\r
7021 IsDlgButtonChecked(hDlg, OPT_ChessEngine));
\r
7022 EnableWindow(GetDlgItem(hDlg, OPT_ChessServerName),
\r
7023 IsDlgButtonChecked(hDlg, OPT_ChessServer));
\r
7024 EnableWindow(GetDlgItem(hDlg, OPT_AdditionalOptions),
\r
7025 IsDlgButtonChecked(hDlg, OPT_AnyAdditional));
\r
7026 EnableWindow(GetDlgItem(hDlg, IDOK),
\r
7027 IsDlgButtonChecked(hDlg, OPT_ChessEngine) ||
\r
7028 IsDlgButtonChecked(hDlg, OPT_ChessServer) ||
\r
7029 IsDlgButtonChecked(hDlg, OPT_View));
\r
7033 QuoteForFilename(char *filename)
\r
7035 int dquote, space;
\r
7036 dquote = strchr(filename, '"') != NULL;
\r
7037 space = strchr(filename, ' ') != NULL;
\r
7038 if (dquote || space) {
\r
7050 InitEngineBox(HWND hDlg, HWND hwndCombo, char* nthcp, char* nthd, char* nthdir, char *nthnames)
\r
7052 char buf[MSG_SIZ];
\r
7055 InitComboStringsFromOption(hwndCombo, nthnames);
\r
7056 q = QuoteForFilename(nthcp);
\r
7057 sprintf(buf, "%s%s%s", q, nthcp, q);
\r
7058 if (*nthdir != NULLCHAR) {
\r
7059 q = QuoteForFilename(nthdir);
\r
7060 sprintf(buf + strlen(buf), " /%s=%s%s%s", nthd, q, nthdir, q);
\r
7062 if (*nthcp == NULLCHAR) {
\r
7063 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) 0, (LPARAM) 0);
\r
7064 } else if (SendMessage(hwndCombo, CB_SELECTSTRING, (WPARAM) -1, (LPARAM) buf) == CB_ERR) {
\r
7065 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) -1, (LPARAM) 0);
\r
7066 SendMessage(hwndCombo, WM_SETTEXT, (WPARAM) 0, (LPARAM) buf);
\r
7071 StartupDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7073 char buf[MSG_SIZ];
\r
7077 switch (message) {
\r
7078 case WM_INITDIALOG:
\r
7079 /* Center the dialog */
\r
7080 CenterWindow (hDlg, GetDesktopWindow());
\r
7081 /* Initialize the dialog items */
\r
7082 InitEngineBox(hDlg, GetDlgItem(hDlg, OPT_ChessEngineName),
\r
7083 appData.firstChessProgram, "fd", appData.firstDirectory,
\r
7084 firstChessProgramNames);
\r
7085 InitEngineBox(hDlg, GetDlgItem(hDlg, OPT_SecondChessEngineName),
\r
7086 appData.secondChessProgram, "sd", appData.secondDirectory,
\r
7087 secondChessProgramNames);
\r
7088 hwndCombo = GetDlgItem(hDlg, OPT_ChessServerName);
\r
7089 InitComboStringsFromOption(hwndCombo, icsNames);
\r
7090 sprintf(buf, "%s /icsport=%s", appData.icsHost, appData.icsPort);
\r
7091 if (*appData.icsHelper != NULLCHAR) {
\r
7092 char *q = QuoteForFilename(appData.icsHelper);
\r
7093 sprintf(buf + strlen(buf), " /icshelper=%s%s%s", q, appData.icsHelper, q);
\r
7095 if (*appData.icsHost == NULLCHAR) {
\r
7096 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) 0, (LPARAM) 0);
\r
7097 /*SendMessage(hwndCombo, CB_SHOWDROPDOWN, (WPARAM) TRUE, (LPARAM) 0); !!too soon */
\r
7098 } else if (SendMessage(hwndCombo, CB_SELECTSTRING, (WPARAM) -1, (LPARAM) buf) == CB_ERR) {
\r
7099 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) -1, (LPARAM) 0);
\r
7100 SendMessage(hwndCombo, WM_SETTEXT, (WPARAM) 0, (LPARAM) buf);
\r
7103 if (appData.icsActive) {
\r
7104 CheckDlgButton(hDlg, OPT_ChessServer, BST_CHECKED);
\r
7106 else if (appData.noChessProgram) {
\r
7107 CheckDlgButton(hDlg, OPT_View, BST_CHECKED);
\r
7110 CheckDlgButton(hDlg, OPT_ChessEngine, BST_CHECKED);
\r
7113 SetStartupDialogEnables(hDlg);
\r
7117 switch (LOWORD(wParam)) {
\r
7119 if (IsDlgButtonChecked(hDlg, OPT_ChessEngine)) {
\r
7120 strcpy(buf, "/fcp=");
\r
7121 GetDlgItemText(hDlg, OPT_ChessEngineName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
7123 ParseArgs(StringGet, &p);
\r
7124 strcpy(buf, "/scp=");
\r
7125 GetDlgItemText(hDlg, OPT_SecondChessEngineName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
7127 ParseArgs(StringGet, &p);
\r
7128 appData.noChessProgram = FALSE;
\r
7129 appData.icsActive = FALSE;
\r
7130 } else if (IsDlgButtonChecked(hDlg, OPT_ChessServer)) {
\r
7131 strcpy(buf, "/ics /icshost=");
\r
7132 GetDlgItemText(hDlg, OPT_ChessServerName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
7134 ParseArgs(StringGet, &p);
\r
7135 if (appData.zippyPlay) {
\r
7136 strcpy(buf, "/fcp=");
\r
7137 GetDlgItemText(hDlg, OPT_ChessEngineName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
7139 ParseArgs(StringGet, &p);
\r
7141 } else if (IsDlgButtonChecked(hDlg, OPT_View)) {
\r
7142 appData.noChessProgram = TRUE;
\r
7143 appData.icsActive = FALSE;
\r
7145 MessageBox(hDlg, "Choose an option, or cancel to exit",
\r
7146 "Option Error", MB_OK|MB_ICONEXCLAMATION);
\r
7149 if (IsDlgButtonChecked(hDlg, OPT_AnyAdditional)) {
\r
7150 GetDlgItemText(hDlg, OPT_AdditionalOptions, buf, sizeof(buf));
\r
7152 ParseArgs(StringGet, &p);
\r
7154 EndDialog(hDlg, TRUE);
\r
7161 case IDM_HELPCONTENTS:
\r
7162 if (!WinHelp (hDlg, "winboard.hlp", HELP_KEY,(DWORD)(LPSTR)"CONTENTS")) {
\r
7163 MessageBox (GetFocus(),
\r
7164 "Unable to activate help",
\r
7165 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
7170 SetStartupDialogEnables(hDlg);
\r
7178 /*---------------------------------------------------------------------------*\
\r
7180 * About box dialog functions
\r
7182 \*---------------------------------------------------------------------------*/
\r
7184 /* Process messages for "About" dialog box */
\r
7186 About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7188 switch (message) {
\r
7189 case WM_INITDIALOG: /* message: initialize dialog box */
\r
7190 /* Center the dialog over the application window */
\r
7191 CenterWindow (hDlg, GetWindow (hDlg, GW_OWNER));
\r
7192 SetDlgItemText(hDlg, ABOUTBOX_Version, programVersion);
\r
7195 case WM_COMMAND: /* message: received a command */
\r
7196 if (LOWORD(wParam) == IDOK /* "OK" box selected? */
\r
7197 || LOWORD(wParam) == IDCANCEL) { /* System menu close command? */
\r
7198 EndDialog(hDlg, TRUE); /* Exit the dialog */
\r
7206 /*---------------------------------------------------------------------------*\
\r
7208 * Comment Dialog functions
\r
7210 \*---------------------------------------------------------------------------*/
\r
7213 CommentDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7215 static HANDLE hwndText = NULL;
\r
7216 int len, newSizeX, newSizeY, flags;
\r
7217 static int sizeX, sizeY;
\r
7222 switch (message) {
\r
7223 case WM_INITDIALOG: /* message: initialize dialog box */
\r
7224 /* Initialize the dialog items */
\r
7225 hwndText = GetDlgItem(hDlg, OPT_CommentText);
\r
7226 SetDlgItemText(hDlg, OPT_CommentText, commentText);
\r
7227 EnableWindow(GetDlgItem(hDlg, OPT_CancelComment), editComment);
\r
7228 EnableWindow(GetDlgItem(hDlg, OPT_ClearComment), editComment);
\r
7229 EnableWindow(GetDlgItem(hDlg, OPT_EditComment), !editComment);
\r
7230 SendMessage(hwndText, EM_SETREADONLY, !editComment, 0);
\r
7231 SetWindowText(hDlg, commentTitle);
\r
7232 if (editComment) {
\r
7233 SetFocus(hwndText);
\r
7235 SetFocus(GetDlgItem(hDlg, IDOK));
\r
7237 SendMessage(GetDlgItem(hDlg, OPT_CommentText),
\r
7238 WM_SETFONT, (WPARAM)font[boardSize][COMMENT_FONT]->hf,
\r
7239 MAKELPARAM(FALSE, 0));
\r
7240 /* Size and position the dialog */
\r
7241 if (!commentDialog) {
\r
7242 commentDialog = hDlg;
\r
7243 flags = SWP_NOZORDER;
\r
7244 GetClientRect(hDlg, &rect);
\r
7245 sizeX = rect.right;
\r
7246 sizeY = rect.bottom;
\r
7247 if (commentX != CW_USEDEFAULT && commentY != CW_USEDEFAULT &&
\r
7248 commentW != CW_USEDEFAULT && commentH != CW_USEDEFAULT) {
\r
7249 WINDOWPLACEMENT wp;
\r
7250 EnsureOnScreen(&commentX, &commentY, 0, 0);
\r
7251 wp.length = sizeof(WINDOWPLACEMENT);
\r
7253 wp.showCmd = SW_SHOW;
\r
7254 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
7255 wp.rcNormalPosition.left = commentX;
\r
7256 wp.rcNormalPosition.right = commentX + commentW;
\r
7257 wp.rcNormalPosition.top = commentY;
\r
7258 wp.rcNormalPosition.bottom = commentY + commentH;
\r
7259 SetWindowPlacement(hDlg, &wp);
\r
7261 GetClientRect(hDlg, &rect);
\r
7262 newSizeX = rect.right;
\r
7263 newSizeY = rect.bottom;
\r
7264 ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY,
\r
7265 newSizeX, newSizeY);
\r
7272 case WM_COMMAND: /* message: received a command */
\r
7273 switch (LOWORD(wParam)) {
\r
7275 if (editComment) {
\r
7277 /* Read changed options from the dialog box */
\r
7278 hwndText = GetDlgItem(hDlg, OPT_CommentText);
\r
7279 len = GetWindowTextLength(hwndText);
\r
7280 str = (char *) malloc(len + 1);
\r
7281 GetWindowText(hwndText, str, len + 1);
\r
7290 ReplaceComment(commentIndex, str);
\r
7297 case OPT_CancelComment:
\r
7301 case OPT_ClearComment:
\r
7302 SetDlgItemText(hDlg, OPT_CommentText, "");
\r
7305 case OPT_EditComment:
\r
7306 EditCommentEvent();
\r
7315 newSizeX = LOWORD(lParam);
\r
7316 newSizeY = HIWORD(lParam);
\r
7317 ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY, newSizeX, newSizeY);
\r
7322 case WM_GETMINMAXINFO:
\r
7323 /* Prevent resizing window too small */
\r
7324 mmi = (MINMAXINFO *) lParam;
\r
7325 mmi->ptMinTrackSize.x = 100;
\r
7326 mmi->ptMinTrackSize.y = 100;
\r
7333 EitherCommentPopUp(int index, char *title, char *str, BOOLEAN edit)
\r
7338 CheckMenuItem(GetMenu(hwndMain), IDM_EditComment, edit ? MF_CHECKED : MF_UNCHECKED);
\r
7340 if (str == NULL) str = "";
\r
7341 p = (char *) malloc(2 * strlen(str) + 2);
\r
7344 if (*str == '\n') *q++ = '\r';
\r
7348 if (commentText != NULL) free(commentText);
\r
7350 commentIndex = index;
\r
7351 commentTitle = title;
\r
7353 editComment = edit;
\r
7355 if (commentDialog) {
\r
7356 SendMessage(commentDialog, WM_INITDIALOG, 0, 0);
\r
7357 if (!commentDialogUp) ShowWindow(commentDialog, SW_SHOW);
\r
7359 lpProc = MakeProcInstance((FARPROC)CommentDialog, hInst);
\r
7360 CreateDialog(hInst, MAKEINTRESOURCE(DLG_EditComment),
\r
7361 hwndMain, (DLGPROC)lpProc);
\r
7362 FreeProcInstance(lpProc);
\r
7364 commentDialogUp = TRUE;
\r
7368 /*---------------------------------------------------------------------------*\
\r
7370 * Type-in move dialog functions
\r
7372 \*---------------------------------------------------------------------------*/
\r
7375 TypeInMoveDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7377 char move[MSG_SIZ];
\r
7379 ChessMove moveType;
\r
7380 int fromX, fromY, toX, toY;
\r
7383 switch (message) {
\r
7384 case WM_INITDIALOG:
\r
7385 move[0] = (char) lParam;
\r
7386 move[1] = NULLCHAR;
\r
7387 CenterWindowEx(hDlg, GetWindow(hDlg, GW_OWNER), 1 );
\r
7388 hInput = GetDlgItem(hDlg, OPT_Move);
\r
7389 SetWindowText(hInput, move);
\r
7391 SendMessage(hInput, EM_SETSEL, (WPARAM)9999, (LPARAM)9999);
\r
7395 switch (LOWORD(wParam)) {
\r
7397 GetDlgItemText(hDlg, OPT_Move, move, sizeof(move));
\r
7398 { int n; Board board;
\r
7400 if(gameMode == EditPosition && ParseFEN(board, &n, move) ) {
\r
7401 EditPositionPasteFEN(move);
\r
7402 EndDialog(hDlg, TRUE);
\r
7405 // [HGM] movenum: allow move number to be typed in any mode
\r
7406 if(sscanf(move, "%d", &n) == 1 && n != 0 ) {
\r
7407 currentMove = 2*n-1;
\r
7408 if(currentMove > forwardMostMove) currentMove = forwardMostMove;
\r
7409 if(currentMove < backwardMostMove) currentMove = backwardMostMove;
\r
7410 EndDialog(hDlg, TRUE);
\r
7411 DrawPosition(TRUE, boards[currentMove]);
\r
7412 if(currentMove > backwardMostMove) DisplayMove(currentMove - 1);
\r
7413 else DisplayMessage("", "");
\r
7417 if (gameMode != EditGame && currentMove != forwardMostMove &&
\r
7418 gameMode != Training) {
\r
7419 DisplayMoveError("Displayed move is not current");
\r
7421 // GetDlgItemText(hDlg, OPT_Move, move, sizeof(move)); // moved upstream
\r
7422 int ok = ParseOneMove(move, gameMode == EditPosition ? blackPlaysFirst : currentMove,
\r
7423 &moveType, &fromX, &fromY, &toX, &toY, &promoChar);
\r
7424 if(!ok && move[0] >= 'a') { move[0] += 'A' - 'a'; ok = 2; } // [HGM] try also capitalized
\r
7425 if (ok==1 || ok && ParseOneMove(move, gameMode == EditPosition ? blackPlaysFirst : currentMove,
\r
7426 &moveType, &fromX, &fromY, &toX, &toY, &promoChar)) {
\r
7427 if (gameMode != Training)
\r
7428 forwardMostMove = currentMove;
\r
7429 UserMoveEvent(fromX, fromY, toX, toY, promoChar);
\r
7431 DisplayMoveError("Could not parse move");
\r
7434 EndDialog(hDlg, TRUE);
\r
7437 EndDialog(hDlg, FALSE);
\r
7448 PopUpMoveDialog(char firstchar)
\r
7452 if ((gameMode == BeginningOfGame && !appData.icsActive) ||
\r
7453 gameMode == MachinePlaysWhite || gameMode == MachinePlaysBlack ||
\r
7454 gameMode == AnalyzeMode || gameMode == EditGame ||
\r
7455 gameMode == EditPosition || gameMode == IcsExamining ||
\r
7456 gameMode == IcsPlayingWhite || gameMode == IcsPlayingBlack ||
\r
7457 isdigit(firstchar) && // [HGM] movenum: allow typing in of move nr in 'passive' modes
\r
7458 ( gameMode == AnalyzeFile || gameMode == PlayFromGameFile ||
\r
7459 gameMode == IcsObserving || gameMode == TwoMachinesPlay ) ||
\r
7460 gameMode == Training) {
\r
7461 lpProc = MakeProcInstance((FARPROC)TypeInMoveDialog, hInst);
\r
7462 DialogBoxParam(hInst, MAKEINTRESOURCE(DLG_TypeInMove),
\r
7463 hwndMain, (DLGPROC)lpProc, (LPARAM)firstchar);
\r
7464 FreeProcInstance(lpProc);
\r
7468 /*---------------------------------------------------------------------------*\
\r
7470 * Type-in name dialog functions
\r
7472 \*---------------------------------------------------------------------------*/
\r
7475 TypeInNameDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7477 char move[MSG_SIZ];
\r
7480 switch (message) {
\r
7481 case WM_INITDIALOG:
\r
7482 move[0] = (char) lParam;
\r
7483 move[1] = NULLCHAR;
\r
7484 CenterWindowEx(hDlg, GetWindow(hDlg, GW_OWNER), 1 );
\r
7485 hInput = GetDlgItem(hDlg, OPT_Name);
\r
7486 SetWindowText(hInput, move);
\r
7488 SendMessage(hInput, EM_SETSEL, (WPARAM)9999, (LPARAM)9999);
\r
7492 switch (LOWORD(wParam)) {
\r
7494 GetDlgItemText(hDlg, OPT_Name, move, sizeof(move));
\r
7495 appData.userName = strdup(move);
\r
7498 EndDialog(hDlg, TRUE);
\r
7501 EndDialog(hDlg, FALSE);
\r
7512 PopUpNameDialog(char firstchar)
\r
7516 lpProc = MakeProcInstance((FARPROC)TypeInNameDialog, hInst);
\r
7517 DialogBoxParam(hInst, MAKEINTRESOURCE(DLG_TypeInName),
\r
7518 hwndMain, (DLGPROC)lpProc, (LPARAM)firstchar);
\r
7519 FreeProcInstance(lpProc);
\r
7522 /*---------------------------------------------------------------------------*\
\r
7526 \*---------------------------------------------------------------------------*/
\r
7528 /* Nonmodal error box */
\r
7529 LRESULT CALLBACK ErrorDialog(HWND hDlg, UINT message,
\r
7530 WPARAM wParam, LPARAM lParam);
\r
7533 ErrorPopUp(char *title, char *content)
\r
7537 BOOLEAN modal = hwndMain == NULL;
\r
7555 strncpy(errorTitle, title, sizeof(errorTitle));
\r
7556 errorTitle[sizeof(errorTitle) - 1] = '\0';
\r
7559 MessageBox(NULL, errorMessage, errorTitle, MB_OK|MB_ICONEXCLAMATION);
\r
7561 lpProc = MakeProcInstance((FARPROC)ErrorDialog, hInst);
\r
7562 CreateDialog(hInst, MAKEINTRESOURCE(DLG_Error),
\r
7563 hwndMain, (DLGPROC)lpProc);
\r
7564 FreeProcInstance(lpProc);
\r
7571 if (!appData.popupMoveErrors && moveErrorMessageUp) DisplayMessage("", "");
\r
7572 if (errorDialog == NULL) return;
\r
7573 DestroyWindow(errorDialog);
\r
7574 errorDialog = NULL;
\r
7578 ErrorDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7583 switch (message) {
\r
7584 case WM_INITDIALOG:
\r
7585 GetWindowRect(hDlg, &rChild);
\r
7588 SetWindowPos(hDlg, NULL, rChild.left,
\r
7589 rChild.top + boardRect.top - (rChild.bottom - rChild.top),
\r
7590 0, 0, SWP_NOZORDER|SWP_NOSIZE);
\r
7594 [AS] It seems that the above code wants to move the dialog up in the "caption
\r
7595 area" of the main window, but it uses the dialog height as an hard-coded constant,
\r
7596 and it doesn't work when you resize the dialog.
\r
7597 For now, just give it a default position.
\r
7599 SetWindowPos(hDlg, NULL, boardRect.left+8, boardRect.top+8, 0, 0, SWP_NOZORDER|SWP_NOSIZE);
\r
7601 errorDialog = hDlg;
\r
7602 SetWindowText(hDlg, errorTitle);
\r
7603 hwndText = GetDlgItem(hDlg, OPT_ErrorText);
\r
7604 SetDlgItemText(hDlg, OPT_ErrorText, errorMessage);
\r
7608 switch (LOWORD(wParam)) {
\r
7611 if (errorDialog == hDlg) errorDialog = NULL;
\r
7612 DestroyWindow(hDlg);
\r
7624 HWND gothicDialog = NULL;
\r
7627 GothicDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7631 int height = GetSystemMetrics(SM_CYCAPTION)+GetSystemMetrics(SM_CYFRAME);
\r
7633 switch (message) {
\r
7634 case WM_INITDIALOG:
\r
7635 GetWindowRect(hDlg, &rChild);
\r
7637 SetWindowPos(hDlg, NULL, boardX, boardY-height, winWidth, height,
\r
7641 [AS] It seems that the above code wants to move the dialog up in the "caption
\r
7642 area" of the main window, but it uses the dialog height as an hard-coded constant,
\r
7643 and it doesn't work when you resize the dialog.
\r
7644 For now, just give it a default position.
\r
7646 gothicDialog = hDlg;
\r
7647 SetWindowText(hDlg, errorTitle);
\r
7648 hwndText = GetDlgItem(hDlg, OPT_ErrorText);
\r
7649 SetDlgItemText(hDlg, OPT_ErrorText, errorMessage);
\r
7653 switch (LOWORD(wParam)) {
\r
7656 if (errorDialog == hDlg) errorDialog = NULL;
\r
7657 DestroyWindow(hDlg);
\r
7669 GothicPopUp(char *title, VariantClass variant)
\r
7672 static char *lastTitle;
\r
7674 strncpy(errorTitle, title, sizeof(errorTitle));
\r
7675 errorTitle[sizeof(errorTitle) - 1] = '\0';
\r
7677 if(lastTitle != title && gothicDialog != NULL) {
\r
7678 DestroyWindow(gothicDialog);
\r
7679 gothicDialog = NULL;
\r
7681 if(variant != VariantNormal && gothicDialog == NULL) {
\r
7682 title = lastTitle;
\r
7683 lpProc = MakeProcInstance((FARPROC)GothicDialog, hInst);
\r
7684 CreateDialog(hInst, MAKEINTRESOURCE(DLG_Error),
\r
7685 hwndMain, (DLGPROC)lpProc);
\r
7686 FreeProcInstance(lpProc);
\r
7691 /*---------------------------------------------------------------------------*\
\r
7693 * Ics Interaction console functions
\r
7695 \*---------------------------------------------------------------------------*/
\r
7697 #define HISTORY_SIZE 64
\r
7698 static char *history[HISTORY_SIZE];
\r
7699 int histIn = 0, histP = 0;
\r
7702 SaveInHistory(char *cmd)
\r
7704 if (history[histIn] != NULL) {
\r
7705 free(history[histIn]);
\r
7706 history[histIn] = NULL;
\r
7708 if (*cmd == NULLCHAR) return;
\r
7709 history[histIn] = StrSave(cmd);
\r
7710 histIn = (histIn + 1) % HISTORY_SIZE;
\r
7711 if (history[histIn] != NULL) {
\r
7712 free(history[histIn]);
\r
7713 history[histIn] = NULL;
\r
7719 PrevInHistory(char *cmd)
\r
7722 if (histP == histIn) {
\r
7723 if (history[histIn] != NULL) free(history[histIn]);
\r
7724 history[histIn] = StrSave(cmd);
\r
7726 newhp = (histP - 1 + HISTORY_SIZE) % HISTORY_SIZE;
\r
7727 if (newhp == histIn || history[newhp] == NULL) return NULL;
\r
7729 return history[histP];
\r
7735 if (histP == histIn) return NULL;
\r
7736 histP = (histP + 1) % HISTORY_SIZE;
\r
7737 return history[histP];
\r
7744 BOOLEAN immediate;
\r
7745 } IcsTextMenuEntry;
\r
7746 #define ICS_TEXT_MENU_SIZE (IDM_CommandXLast - IDM_CommandX + 1)
\r
7747 IcsTextMenuEntry icsTextMenuEntry[ICS_TEXT_MENU_SIZE];
\r
7750 ParseIcsTextMenu(char *icsTextMenuString)
\r
7753 IcsTextMenuEntry *e = icsTextMenuEntry;
\r
7754 char *p = icsTextMenuString;
\r
7755 while (e->item != NULL && e < icsTextMenuEntry + ICS_TEXT_MENU_SIZE) {
\r
7758 if (e->command != NULL) {
\r
7760 e->command = NULL;
\r
7764 e = icsTextMenuEntry;
\r
7765 while (*p && e < icsTextMenuEntry + ICS_TEXT_MENU_SIZE) {
\r
7766 if (*p == ';' || *p == '\n') {
\r
7767 e->item = strdup("-");
\r
7768 e->command = NULL;
\r
7770 } else if (*p == '-') {
\r
7771 e->item = strdup("-");
\r
7772 e->command = NULL;
\r
7776 char *q, *r, *s, *t;
\r
7778 q = strchr(p, ',');
\r
7779 if (q == NULL) break;
\r
7781 r = strchr(q + 1, ',');
\r
7782 if (r == NULL) break;
\r
7784 s = strchr(r + 1, ',');
\r
7785 if (s == NULL) break;
\r
7788 t = strchr(s + 1, c);
\r
7791 t = strchr(s + 1, c);
\r
7793 if (t != NULL) *t = NULLCHAR;
\r
7794 e->item = strdup(p);
\r
7795 e->command = strdup(q + 1);
\r
7796 e->getname = *(r + 1) != '0';
\r
7797 e->immediate = *(s + 1) != '0';
\r
7801 if (t == NULL) break;
\r
7810 LoadIcsTextMenu(IcsTextMenuEntry *e)
\r
7814 hmenu = LoadMenu(hInst, "TextMenu");
\r
7815 h = GetSubMenu(hmenu, 0);
\r
7817 if (strcmp(e->item, "-") == 0) {
\r
7818 AppendMenu(h, MF_SEPARATOR, 0, 0);
\r
7820 if (e->item[0] == '|') {
\r
7821 AppendMenu(h, MF_STRING|MF_MENUBARBREAK,
\r
7822 IDM_CommandX + i, &e->item[1]);
\r
7824 AppendMenu(h, MF_STRING, IDM_CommandX + i, e->item);
\r
7833 WNDPROC consoleTextWindowProc;
\r
7836 CommandX(HWND hwnd, char *command, BOOLEAN getname, BOOLEAN immediate)
\r
7838 char buf[MSG_SIZ], name[MSG_SIZ];
\r
7839 HWND hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
7843 SetWindowText(hInput, command);
\r
7845 SendMessage(hInput, WM_CHAR, '\r', 0);
\r
7847 sel.cpMin = 999999;
\r
7848 sel.cpMax = 999999;
\r
7849 SendMessage(hInput, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7854 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
7855 if (sel.cpMin == sel.cpMax) {
\r
7856 /* Expand to surrounding word */
\r
7859 tr.chrg.cpMax = sel.cpMin;
\r
7860 tr.chrg.cpMin = --sel.cpMin;
\r
7861 if (sel.cpMin < 0) break;
\r
7862 tr.lpstrText = name;
\r
7863 SendMessage(hwnd, EM_GETTEXTRANGE, 0, (LPARAM) &tr);
\r
7864 } while (isalpha(name[0]) || isdigit(name[0]) || name[0] == '-');
\r
7868 tr.chrg.cpMin = sel.cpMax;
\r
7869 tr.chrg.cpMax = ++sel.cpMax;
\r
7870 tr.lpstrText = name;
\r
7871 if (SendMessage(hwnd, EM_GETTEXTRANGE, 0, (LPARAM) &tr) < 1) break;
\r
7872 } while (isalpha(name[0]) || isdigit(name[0]) || name[0] == '-');
\r
7875 if (sel.cpMax == sel.cpMin || sel.cpMax - sel.cpMin > MSG_SIZ/2) {
\r
7876 MessageBeep(MB_ICONEXCLAMATION);
\r
7880 tr.lpstrText = name;
\r
7881 SendMessage(hwnd, EM_GETTEXTRANGE, 0, (LPARAM) &tr);
\r
7883 if (sel.cpMax - sel.cpMin > MSG_SIZ/2) {
\r
7884 MessageBeep(MB_ICONEXCLAMATION);
\r
7887 SendMessage(hwnd, EM_GETSELTEXT, 0, (LPARAM) name);
\r
7890 sprintf(buf, "%s %s", command, name);
\r
7891 SetWindowText(hInput, buf);
\r
7892 SendMessage(hInput, WM_CHAR, '\r', 0);
\r
7894 sprintf(buf, "%s %s ", command, name); /* trailing space */
\r
7895 SetWindowText(hInput, buf);
\r
7896 sel.cpMin = 999999;
\r
7897 sel.cpMax = 999999;
\r
7898 SendMessage(hInput, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7904 ConsoleTextSubclass(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
7909 switch (message) {
\r
7911 if (!(GetKeyState(VK_CONTROL) & ~1)) break;
\r
7914 SendMessage(hwnd, EM_LINESCROLL, 0, -999999);
\r
7917 sel.cpMin = 999999;
\r
7918 sel.cpMax = 999999;
\r
7919 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7920 SendMessage(hwnd, EM_SCROLLCARET, 0, 0);
\r
7925 if(wParam != '\022') {
\r
7926 if (wParam == '\t') {
\r
7927 if (GetKeyState(VK_SHIFT) < 0) {
\r
7929 if (IsIconic(hwndMain)) ShowWindow(hwndMain, SW_RESTORE);
\r
7930 if (buttonDesc[0].hwnd) {
\r
7931 SetFocus(buttonDesc[0].hwnd);
\r
7933 SetFocus(hwndMain);
\r
7937 SetFocus(GetDlgItem(hwndConsole, OPT_ConsoleInput));
\r
7940 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
7941 JAWS_DELETE( SetFocus(hInput); )
\r
7942 SendMessage(hInput, message, wParam, lParam);
\r
7945 } // [HGM] navigate: for Ctrl+R, flow into nex case (moved up here) to summon up menu
\r
7946 case WM_RBUTTONUP:
\r
7947 if (GetKeyState(VK_SHIFT) & ~1) {
\r
7948 SendDlgItemMessage(hwndConsole, OPT_ConsoleText,
\r
7949 WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
7952 HMENU hmenu = LoadIcsTextMenu(icsTextMenuEntry);
\r
7953 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
7954 if (sel.cpMin == sel.cpMax) {
\r
7955 EnableMenuItem(hmenu, IDM_Copy, MF_BYCOMMAND|MF_GRAYED);
\r
7956 EnableMenuItem(hmenu, IDM_QuickPaste, MF_BYCOMMAND|MF_GRAYED);
\r
7958 if (!IsClipboardFormatAvailable(CF_TEXT)) {
\r
7959 EnableMenuItem(hmenu, IDM_Paste, MF_BYCOMMAND|MF_GRAYED);
\r
7961 pt.x = LOWORD(lParam);
\r
7962 pt.y = HIWORD(lParam);
\r
7963 MenuPopup(hwnd, pt, hmenu, -1);
\r
7967 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
7969 return SendMessage(hInput, message, wParam, lParam);
\r
7970 case WM_MBUTTONDOWN:
\r
7971 return SendMessage(hwnd, WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
7972 case WM_RBUTTONDOWN:
\r
7973 if (!(GetKeyState(VK_SHIFT) & ~1)) {
\r
7974 /* Move selection here if it was empty */
\r
7976 pt.x = LOWORD(lParam);
\r
7977 pt.y = HIWORD(lParam);
\r
7978 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
7979 if (sel.cpMin == sel.cpMax) {
\r
7980 sel.cpMin = SendMessage(hwnd, EM_CHARFROMPOS, 0, (LPARAM)&pt); /*doc is wrong*/
\r
7981 sel.cpMax = sel.cpMin;
\r
7982 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7984 SendMessage(hwnd, EM_HIDESELECTION, FALSE, FALSE);
\r
7988 switch (LOWORD(wParam)) {
\r
7989 case IDM_QuickPaste:
\r
7991 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
7992 if (sel.cpMin == sel.cpMax) {
\r
7993 MessageBeep(MB_ICONEXCLAMATION);
\r
7996 SendMessage(hwnd, WM_COPY, 0, 0);
\r
7997 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
7998 SendMessage(hInput, WM_PASTE, 0, 0);
\r
8003 SendMessage(hwnd, WM_CUT, 0, 0);
\r
8006 SendMessage(hwnd, WM_PASTE, 0, 0);
\r
8009 SendMessage(hwnd, WM_COPY, 0, 0);
\r
8013 int i = LOWORD(wParam) - IDM_CommandX;
\r
8014 if (i >= 0 && i < ICS_TEXT_MENU_SIZE &&
\r
8015 icsTextMenuEntry[i].command != NULL) {
\r
8016 CommandX(hwnd, icsTextMenuEntry[i].command,
\r
8017 icsTextMenuEntry[i].getname,
\r
8018 icsTextMenuEntry[i].immediate);
\r
8026 return (*consoleTextWindowProc)(hwnd, message, wParam, lParam);
\r
8029 WNDPROC consoleInputWindowProc;
\r
8032 ConsoleInputSubclass(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
8034 char buf[MSG_SIZ];
\r
8036 static BOOL sendNextChar = FALSE;
\r
8037 static BOOL quoteNextChar = FALSE;
\r
8038 InputSource *is = consoleInputSource;
\r
8042 switch (message) {
\r
8044 if (!appData.localLineEditing || sendNextChar) {
\r
8045 is->buf[0] = (CHAR) wParam;
\r
8047 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
8048 sendNextChar = FALSE;
\r
8051 if (quoteNextChar) {
\r
8052 buf[0] = (char) wParam;
\r
8053 buf[1] = NULLCHAR;
\r
8054 SendMessage(hwnd, EM_REPLACESEL, TRUE, (LPARAM) buf);
\r
8055 quoteNextChar = FALSE;
\r
8059 case '\r': /* Enter key */
\r
8060 is->count = GetWindowText(hwnd, is->buf, INPUT_SOURCE_BUF_SIZE-1);
\r
8061 if (consoleEcho) SaveInHistory(is->buf);
\r
8062 is->buf[is->count++] = '\n';
\r
8063 is->buf[is->count] = NULLCHAR;
\r
8064 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
8065 if (consoleEcho) {
\r
8066 ConsoleOutput(is->buf, is->count, TRUE);
\r
8067 } else if (appData.localLineEditing) {
\r
8068 ConsoleOutput("\n", 1, TRUE);
\r
8071 case '\033': /* Escape key */
\r
8072 SetWindowText(hwnd, "");
\r
8073 cf.cbSize = sizeof(CHARFORMAT);
\r
8074 cf.dwMask = CFM_COLOR|CFM_BOLD|CFM_ITALIC|CFM_UNDERLINE|CFM_STRIKEOUT;
\r
8075 if (consoleEcho) {
\r
8076 cf.crTextColor = textAttribs[ColorNormal].color;
\r
8078 cf.crTextColor = COLOR_ECHOOFF;
\r
8080 cf.dwEffects = textAttribs[ColorNormal].effects;
\r
8081 SendMessage(hwnd, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&cf);
\r
8083 case '\t': /* Tab key */
\r
8084 if (GetKeyState(VK_SHIFT) < 0) {
\r
8086 SetFocus(GetDlgItem(hwndConsole, OPT_ConsoleText));
\r
8089 if (IsIconic(hwndMain)) ShowWindow(hwndMain, SW_RESTORE);
\r
8090 if (buttonDesc[0].hwnd) {
\r
8091 SetFocus(buttonDesc[0].hwnd);
\r
8093 SetFocus(hwndMain);
\r
8097 case '\023': /* Ctrl+S */
\r
8098 sendNextChar = TRUE;
\r
8100 case '\021': /* Ctrl+Q */
\r
8101 quoteNextChar = TRUE;
\r
8111 GetWindowText(hwnd, buf, MSG_SIZ);
\r
8112 p = PrevInHistory(buf);
\r
8114 SetWindowText(hwnd, p);
\r
8115 sel.cpMin = 999999;
\r
8116 sel.cpMax = 999999;
\r
8117 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
8122 p = NextInHistory();
\r
8124 SetWindowText(hwnd, p);
\r
8125 sel.cpMin = 999999;
\r
8126 sel.cpMax = 999999;
\r
8127 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
8133 if (!(GetKeyState(VK_CONTROL) & ~1)) break;
\r
8137 SendDlgItemMessage(hwndConsole, OPT_ConsoleText, message, wParam, lParam);
\r
8141 case WM_MBUTTONDOWN:
\r
8142 SendDlgItemMessage(hwndConsole, OPT_ConsoleText,
\r
8143 WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
8145 case WM_RBUTTONUP:
\r
8146 if (GetKeyState(VK_SHIFT) & ~1) {
\r
8147 SendDlgItemMessage(hwndConsole, OPT_ConsoleText,
\r
8148 WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
8152 hmenu = LoadMenu(hInst, "InputMenu");
\r
8153 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
8154 if (sel.cpMin == sel.cpMax) {
\r
8155 EnableMenuItem(hmenu, IDM_Copy, MF_BYCOMMAND|MF_GRAYED);
\r
8156 EnableMenuItem(hmenu, IDM_Cut, MF_BYCOMMAND|MF_GRAYED);
\r
8158 if (!IsClipboardFormatAvailable(CF_TEXT)) {
\r
8159 EnableMenuItem(hmenu, IDM_Paste, MF_BYCOMMAND|MF_GRAYED);
\r
8161 pt.x = LOWORD(lParam);
\r
8162 pt.y = HIWORD(lParam);
\r
8163 MenuPopup(hwnd, pt, hmenu, -1);
\r
8167 switch (LOWORD(wParam)) {
\r
8169 SendMessage(hwnd, EM_UNDO, 0, 0);
\r
8171 case IDM_SelectAll:
\r
8173 sel.cpMax = -1; /*999999?*/
\r
8174 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
8177 SendMessage(hwnd, WM_CUT, 0, 0);
\r
8180 SendMessage(hwnd, WM_PASTE, 0, 0);
\r
8183 SendMessage(hwnd, WM_COPY, 0, 0);
\r
8188 return (*consoleInputWindowProc)(hwnd, message, wParam, lParam);
\r
8191 #define CO_MAX 100000
\r
8192 #define CO_TRIM 1000
\r
8195 ConsoleWndProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
8197 static SnapData sd;
\r
8198 static HWND hText, hInput /*, hFocus*/;
\r
8199 // InputSource *is = consoleInputSource;
\r
8201 static int sizeX, sizeY;
\r
8202 int newSizeX, newSizeY;
\r
8205 switch (message) {
\r
8206 case WM_INITDIALOG: /* message: initialize dialog box */
\r
8207 hwndConsole = hDlg;
\r
8208 hText = GetDlgItem(hDlg, OPT_ConsoleText);
\r
8209 hInput = GetDlgItem(hDlg, OPT_ConsoleInput);
\r
8211 consoleTextWindowProc = (WNDPROC)
\r
8212 SetWindowLong(hText, GWL_WNDPROC, (LONG) ConsoleTextSubclass);
\r
8213 SendMessage(hText, EM_SETBKGNDCOLOR, FALSE, consoleBackgroundColor);
\r
8214 consoleInputWindowProc = (WNDPROC)
\r
8215 SetWindowLong(hInput, GWL_WNDPROC, (LONG) ConsoleInputSubclass);
\r
8216 SendMessage(hInput, EM_SETBKGNDCOLOR, FALSE, consoleBackgroundColor);
\r
8217 Colorize(ColorNormal, TRUE);
\r
8218 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM) &consoleCF);
\r
8219 ChangedConsoleFont();
\r
8220 GetClientRect(hDlg, &rect);
\r
8221 sizeX = rect.right;
\r
8222 sizeY = rect.bottom;
\r
8223 if (wpConsole.x != CW_USEDEFAULT && wpConsole.y != CW_USEDEFAULT &&
\r
8224 wpConsole.width != CW_USEDEFAULT && wpConsole.height != CW_USEDEFAULT) {
\r
8225 WINDOWPLACEMENT wp;
\r
8226 EnsureOnScreen(&wpConsole.x, &wpConsole.y, 0, 0);
\r
8227 wp.length = sizeof(WINDOWPLACEMENT);
\r
8229 wp.showCmd = SW_SHOW;
\r
8230 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
8231 wp.rcNormalPosition.left = wpConsole.x;
\r
8232 wp.rcNormalPosition.right = wpConsole.x + wpConsole.width;
\r
8233 wp.rcNormalPosition.top = wpConsole.y;
\r
8234 wp.rcNormalPosition.bottom = wpConsole.y + wpConsole.height;
\r
8235 SetWindowPlacement(hDlg, &wp);
\r
8238 // [HGM] Chessknight's change 2004-07-13
\r
8239 else { /* Determine Defaults */
\r
8240 WINDOWPLACEMENT wp;
\r
8241 wpConsole.x = winWidth + 1;
\r
8242 wpConsole.y = boardY;
\r
8243 wpConsole.width = screenWidth - winWidth;
\r
8244 wpConsole.height = winHeight;
\r
8245 EnsureOnScreen(&wpConsole.x, &wpConsole.y, 0, 0);
\r
8246 wp.length = sizeof(WINDOWPLACEMENT);
\r
8248 wp.showCmd = SW_SHOW;
\r
8249 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
8250 wp.rcNormalPosition.left = wpConsole.x;
\r
8251 wp.rcNormalPosition.right = wpConsole.x + wpConsole.width;
\r
8252 wp.rcNormalPosition.top = wpConsole.y;
\r
8253 wp.rcNormalPosition.bottom = wpConsole.y + wpConsole.height;
\r
8254 SetWindowPlacement(hDlg, &wp);
\r
8269 if (IsIconic(hDlg)) break;
\r
8270 newSizeX = LOWORD(lParam);
\r
8271 newSizeY = HIWORD(lParam);
\r
8272 if (sizeX != newSizeX || sizeY != newSizeY) {
\r
8273 RECT rectText, rectInput;
\r
8275 int newTextHeight, newTextWidth;
\r
8276 GetWindowRect(hText, &rectText);
\r
8277 newTextWidth = rectText.right - rectText.left + newSizeX - sizeX;
\r
8278 newTextHeight = rectText.bottom - rectText.top + newSizeY - sizeY;
\r
8279 if (newTextHeight < 0) {
\r
8280 newSizeY += -newTextHeight;
\r
8281 newTextHeight = 0;
\r
8283 SetWindowPos(hText, NULL, 0, 0,
\r
8284 newTextWidth, newTextHeight, SWP_NOZORDER|SWP_NOMOVE);
\r
8285 GetWindowRect(hInput, &rectInput); /* gives screen coords */
\r
8286 pt.x = rectInput.left;
\r
8287 pt.y = rectInput.top + newSizeY - sizeY;
\r
8288 ScreenToClient(hDlg, &pt);
\r
8289 SetWindowPos(hInput, NULL,
\r
8290 pt.x, pt.y, /* needs client coords */
\r
8291 rectInput.right - rectInput.left + newSizeX - sizeX,
\r
8292 rectInput.bottom - rectInput.top, SWP_NOZORDER);
\r
8298 case WM_GETMINMAXINFO:
\r
8299 /* Prevent resizing window too small */
\r
8300 mmi = (MINMAXINFO *) lParam;
\r
8301 mmi->ptMinTrackSize.x = 100;
\r
8302 mmi->ptMinTrackSize.y = 100;
\r
8305 /* [AS] Snapping */
\r
8306 case WM_ENTERSIZEMOVE:
\r
8307 return OnEnterSizeMove( &sd, hDlg, wParam, lParam );
\r
8310 return OnSizing( &sd, hDlg, wParam, lParam );
\r
8313 return OnMoving( &sd, hDlg, wParam, lParam );
\r
8315 case WM_EXITSIZEMOVE:
\r
8316 return OnExitSizeMove( &sd, hDlg, wParam, lParam );
\r
8319 return DefWindowProc(hDlg, message, wParam, lParam);
\r
8327 if (hwndConsole) return;
\r
8328 hCons = CreateDialog(hInst, szConsoleName, 0, NULL);
\r
8329 SendMessage(hCons, WM_INITDIALOG, 0, 0);
\r
8334 ConsoleOutput(char* data, int length, int forceVisible)
\r
8339 char buf[CO_MAX+1];
\r
8342 static int delayLF = 0;
\r
8343 CHARRANGE savesel, sel;
\r
8345 if (hwndConsole == NULL || length > CO_MAX-100 || length == 0) return;
\r
8353 while (length--) {
\r
8361 } else if (*p == '\007') {
\r
8362 MyPlaySound(&sounds[(int)SoundBell]);
\r
8369 hText = GetDlgItem(hwndConsole, OPT_ConsoleText);
\r
8370 SendMessage(hText, EM_HIDESELECTION, TRUE, FALSE);
\r
8371 /* Save current selection */
\r
8372 SendMessage(hText, EM_EXGETSEL, 0, (LPARAM)&savesel);
\r
8373 exlen = GetWindowTextLength(hText);
\r
8374 /* Find out whether current end of text is visible */
\r
8375 SendMessage(hText, EM_GETRECT, 0, (LPARAM) &rect);
\r
8376 SendMessage(hText, EM_POSFROMCHAR, (WPARAM) &pEnd, exlen);
\r
8377 /* Trim existing text if it's too long */
\r
8378 if (exlen + (q - buf) > CO_MAX) {
\r
8379 trim = (CO_TRIM > (q - buf)) ? CO_TRIM : (q - buf);
\r
8382 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
8383 SendMessage(hText, EM_REPLACESEL, 0, (LPARAM)"");
\r
8385 savesel.cpMin -= trim;
\r
8386 savesel.cpMax -= trim;
\r
8387 if (exlen < 0) exlen = 0;
\r
8388 if (savesel.cpMin < 0) savesel.cpMin = 0;
\r
8389 if (savesel.cpMax < savesel.cpMin) savesel.cpMax = savesel.cpMin;
\r
8391 /* Append the new text */
\r
8392 sel.cpMin = exlen;
\r
8393 sel.cpMax = exlen;
\r
8394 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
8395 SendMessage(hText, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&consoleCF);
\r
8396 SendMessage(hText, EM_REPLACESEL, 0, (LPARAM) buf);
\r
8397 if (forceVisible || exlen == 0 ||
\r
8398 (rect.left <= pEnd.x && pEnd.x < rect.right &&
\r
8399 rect.top <= pEnd.y && pEnd.y < rect.bottom)) {
\r
8400 /* Scroll to make new end of text visible if old end of text
\r
8401 was visible or new text is an echo of user typein */
\r
8402 sel.cpMin = 9999999;
\r
8403 sel.cpMax = 9999999;
\r
8404 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
8405 SendMessage(hText, EM_HIDESELECTION, FALSE, FALSE);
\r
8406 SendMessage(hText, EM_SCROLLCARET, 0, 0);
\r
8407 SendMessage(hText, EM_HIDESELECTION, TRUE, FALSE);
\r
8409 if (savesel.cpMax == exlen || forceVisible) {
\r
8410 /* Move insert point to new end of text if it was at the old
\r
8411 end of text or if the new text is an echo of user typein */
\r
8412 sel.cpMin = 9999999;
\r
8413 sel.cpMax = 9999999;
\r
8414 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
8416 /* Restore previous selection */
\r
8417 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&savesel);
\r
8419 SendMessage(hText, EM_HIDESELECTION, FALSE, FALSE);
\r
8426 DisplayHoldingsCount(HDC hdc, int x, int y, int rightAlign, int copyNumber)
\r
8430 COLORREF oldFg, oldBg;
\r
8434 if(copyNumber > 1) sprintf(buf, "%d", copyNumber); else buf[0] = 0;
\r
8436 oldFg = SetTextColor(hdc, RGB(255, 255, 255)); /* white */
\r
8437 oldBg = SetBkColor(hdc, RGB(0, 0, 0)); /* black */
\r
8438 oldFont = SelectObject(hdc, font[boardSize][CLOCK_FONT]->hf);
\r
8441 rect.right = x + squareSize;
\r
8443 rect.bottom = y + squareSize;
\r
8446 ExtTextOut(hdc, x + MESSAGE_LINE_LEFTMARGIN
\r
8447 + (rightAlign ? (squareSize*2)/3 : 0),
\r
8448 y, ETO_CLIPPED|ETO_OPAQUE,
\r
8449 &rect, str, strlen(str), NULL);
\r
8451 (void) SetTextColor(hdc, oldFg);
\r
8452 (void) SetBkColor(hdc, oldBg);
\r
8453 (void) SelectObject(hdc, oldFont);
\r
8457 DisplayAClock(HDC hdc, int timeRemaining, int highlight,
\r
8458 RECT *rect, char *color, char *flagFell)
\r
8462 COLORREF oldFg, oldBg;
\r
8465 if (appData.clockMode) {
\r
8467 sprintf(buf, "%c %s %s", color[0], TimeString(timeRemaining), flagFell);
\r
8469 sprintf(buf, "%s:%c%s %s", color, (logoHeight>0 ? 0 : ' '), TimeString(timeRemaining), flagFell);
\r
8476 oldFg = SetTextColor(hdc, RGB(255, 255, 255)); /* white */
\r
8477 oldBg = SetBkColor(hdc, RGB(0, 0, 0)); /* black */
\r
8479 oldFg = SetTextColor(hdc, RGB(0, 0, 0)); /* black */
\r
8480 oldBg = SetBkColor(hdc, RGB(255, 255, 255)); /* white */
\r
8482 oldFont = SelectObject(hdc, font[boardSize][CLOCK_FONT]->hf);
\r
8486 ExtTextOut(hdc, rect->left + MESSAGE_LINE_LEFTMARGIN,
\r
8487 rect->top, ETO_CLIPPED|ETO_OPAQUE,
\r
8488 rect, str, strlen(str), NULL);
\r
8489 if(logoHeight > 0 && appData.clockMode) {
\r
8491 sprintf(buf, "%s %s", buf+7, flagFell);
\r
8492 r.top = rect->top + logoHeight/2;
\r
8493 r.left = rect->left;
\r
8494 r.right = rect->right;
\r
8495 r.bottom = rect->bottom;
\r
8496 ExtTextOut(hdc, rect->left + MESSAGE_LINE_LEFTMARGIN,
\r
8497 r.top, ETO_CLIPPED|ETO_OPAQUE,
\r
8498 &r, str, strlen(str), NULL);
\r
8500 (void) SetTextColor(hdc, oldFg);
\r
8501 (void) SetBkColor(hdc, oldBg);
\r
8502 (void) SelectObject(hdc, oldFont);
\r
8507 DoReadFile(HANDLE hFile, char *buf, int count, DWORD *outCount,
\r
8513 if( count <= 0 ) {
\r
8514 if (appData.debugMode) {
\r
8515 fprintf( debugFP, "DoReadFile: trying to read past end of buffer, overflow = %d\n", count );
\r
8518 return ERROR_INVALID_USER_BUFFER;
\r
8521 ResetEvent(ovl->hEvent);
\r
8522 ovl->Offset = ovl->OffsetHigh = 0;
\r
8523 ok = ReadFile(hFile, buf, count, outCount, ovl);
\r
8527 err = GetLastError();
\r
8528 if (err == ERROR_IO_PENDING) {
\r
8529 ok = GetOverlappedResult(hFile, ovl, outCount, TRUE);
\r
8533 err = GetLastError();
\r
8540 DoWriteFile(HANDLE hFile, char *buf, int count, DWORD *outCount,
\r
8545 ResetEvent(ovl->hEvent);
\r
8546 ovl->Offset = ovl->OffsetHigh = 0;
\r
8547 ok = WriteFile(hFile, buf, count, outCount, ovl);
\r
8551 err = GetLastError();
\r
8552 if (err == ERROR_IO_PENDING) {
\r
8553 ok = GetOverlappedResult(hFile, ovl, outCount, TRUE);
\r
8557 err = GetLastError();
\r
8563 /* [AS] If input is line by line and a line exceed the buffer size, force an error */
\r
8564 void CheckForInputBufferFull( InputSource * is )
\r
8566 if( is->lineByLine && (is->next - is->buf) >= INPUT_SOURCE_BUF_SIZE ) {
\r
8567 /* Look for end of line */
\r
8568 char * p = is->buf;
\r
8570 while( p < is->next && *p != '\n' ) {
\r
8574 if( p >= is->next ) {
\r
8575 if (appData.debugMode) {
\r
8576 fprintf( debugFP, "Input line exceeded buffer size (source id=%lu)\n", is->id );
\r
8579 is->error = ERROR_BROKEN_PIPE; /* [AS] Just any non-successful code! */
\r
8580 is->count = (DWORD) -1;
\r
8581 is->next = is->buf;
\r
8587 InputThread(LPVOID arg)
\r
8592 is = (InputSource *) arg;
\r
8593 ovl.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
\r
8594 ovl.Internal = ovl.InternalHigh = ovl.Offset = ovl.OffsetHigh = 0;
\r
8595 while (is->hThread != NULL) {
\r
8596 is->error = DoReadFile(is->hFile, is->next,
\r
8597 INPUT_SOURCE_BUF_SIZE - (is->next - is->buf),
\r
8598 &is->count, &ovl);
\r
8599 if (is->error == NO_ERROR) {
\r
8600 is->next += is->count;
\r
8602 if (is->error == ERROR_BROKEN_PIPE) {
\r
8603 /* Correct for MS brain damage. EOF reading a pipe is not an error. */
\r
8606 is->count = (DWORD) -1;
\r
8607 /* [AS] The (is->count <= 0) check below is not useful for unsigned values! */
\r
8612 CheckForInputBufferFull( is );
\r
8614 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
8616 if( is->count == ((DWORD) -1) ) break; /* [AS] */
\r
8618 if (is->count <= 0) break; /* Quit on EOF or error */
\r
8621 CloseHandle(ovl.hEvent);
\r
8622 CloseHandle(is->hFile);
\r
8624 if (appData.debugMode) {
\r
8625 fprintf( debugFP, "Input thread terminated (id=%lu, error=%d, count=%ld)\n", is->id, is->error, is->count );
\r
8632 /* Windows 95 beta 2 won't let you do overlapped i/o on a console or pipe */
\r
8634 NonOvlInputThread(LPVOID arg)
\r
8641 is = (InputSource *) arg;
\r
8642 while (is->hThread != NULL) {
\r
8643 is->error = ReadFile(is->hFile, is->next,
\r
8644 INPUT_SOURCE_BUF_SIZE - (is->next - is->buf),
\r
8645 &is->count, NULL) ? NO_ERROR : GetLastError();
\r
8646 if (is->error == NO_ERROR) {
\r
8647 /* Change CRLF to LF */
\r
8648 if (is->next > is->buf) {
\r
8650 i = is->count + 1;
\r
8658 if (prev == '\r' && *p == '\n') {
\r
8670 if (is->error == ERROR_BROKEN_PIPE) {
\r
8671 /* Correct for MS brain damage. EOF reading a pipe is not an error. */
\r
8674 is->count = (DWORD) -1;
\r
8678 CheckForInputBufferFull( is );
\r
8680 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
8682 if( is->count == ((DWORD) -1) ) break; /* [AS] */
\r
8684 if (is->count < 0) break; /* Quit on error */
\r
8686 CloseHandle(is->hFile);
\r
8691 SocketInputThread(LPVOID arg)
\r
8695 is = (InputSource *) arg;
\r
8696 while (is->hThread != NULL) {
\r
8697 is->count = recv(is->sock, is->buf, INPUT_SOURCE_BUF_SIZE, 0);
\r
8698 if ((int)is->count == SOCKET_ERROR) {
\r
8699 is->count = (DWORD) -1;
\r
8700 is->error = WSAGetLastError();
\r
8702 is->error = NO_ERROR;
\r
8703 is->next += is->count;
\r
8704 if (is->count == 0 && is->second == is) {
\r
8705 /* End of file on stderr; quit with no message */
\r
8709 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
8711 if( is->count == ((DWORD) -1) ) break; /* [AS] */
\r
8713 if (is->count <= 0) break; /* Quit on EOF or error */
\r
8719 InputEvent(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
8723 is = (InputSource *) lParam;
\r
8724 if (is->lineByLine) {
\r
8725 /* Feed in lines one by one */
\r
8726 char *p = is->buf;
\r
8728 while (q < is->next) {
\r
8729 if (*q++ == '\n') {
\r
8730 (is->func)(is, is->closure, p, q - p, NO_ERROR);
\r
8735 /* Move any partial line to the start of the buffer */
\r
8737 while (p < is->next) {
\r
8742 if (is->error != NO_ERROR || is->count == 0) {
\r
8743 /* Notify backend of the error. Note: If there was a partial
\r
8744 line at the end, it is not flushed through. */
\r
8745 (is->func)(is, is->closure, is->buf, is->count, is->error);
\r
8748 /* Feed in the whole chunk of input at once */
\r
8749 (is->func)(is, is->closure, is->buf, is->count, is->error);
\r
8750 is->next = is->buf;
\r
8754 /*---------------------------------------------------------------------------*\
\r
8756 * Menu enables. Used when setting various modes.
\r
8758 \*---------------------------------------------------------------------------*/
\r
8766 SetMenuEnables(HMENU hmenu, Enables *enab)
\r
8768 while (enab->item > 0) {
\r
8769 (void) EnableMenuItem(hmenu, enab->item, enab->flags);
\r
8774 Enables gnuEnables[] = {
\r
8775 { IDM_MailMove, MF_BYCOMMAND|MF_GRAYED },
\r
8776 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_GRAYED },
\r
8777 { IDM_IcsClient, MF_BYCOMMAND|MF_GRAYED },
\r
8778 { IDM_Accept, MF_BYCOMMAND|MF_GRAYED },
\r
8779 { IDM_Decline, MF_BYCOMMAND|MF_GRAYED },
\r
8780 { IDM_Rematch, MF_BYCOMMAND|MF_GRAYED },
\r
8781 { IDM_Adjourn, MF_BYCOMMAND|MF_GRAYED },
\r
8782 { IDM_StopExamining, MF_BYCOMMAND|MF_GRAYED },
\r
8783 { IDM_StopObserving, MF_BYCOMMAND|MF_GRAYED },
\r
8784 { IDM_Revert, MF_BYCOMMAND|MF_GRAYED },
\r
8788 Enables icsEnables[] = {
\r
8789 { IDM_MailMove, MF_BYCOMMAND|MF_GRAYED },
\r
8790 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_GRAYED },
\r
8791 { IDM_MachineWhite, MF_BYCOMMAND|MF_GRAYED },
\r
8792 { IDM_MachineBlack, MF_BYCOMMAND|MF_GRAYED },
\r
8793 { IDM_TwoMachines, MF_BYCOMMAND|MF_GRAYED },
\r
8794 { IDM_AnalysisMode, MF_BYCOMMAND|MF_ENABLED },
\r
8795 { IDM_AnalyzeFile, MF_BYCOMMAND|MF_GRAYED },
\r
8796 { IDM_TimeControl, MF_BYCOMMAND|MF_GRAYED },
\r
8797 { IDM_MoveNow, MF_BYCOMMAND|MF_GRAYED },
\r
8798 { IDM_Hint, MF_BYCOMMAND|MF_GRAYED },
\r
8799 { IDM_Book, MF_BYCOMMAND|MF_GRAYED },
\r
8800 { IDM_IcsOptions, MF_BYCOMMAND|MF_ENABLED },
\r
8805 Enables zippyEnables[] = {
\r
8806 { IDM_MoveNow, MF_BYCOMMAND|MF_ENABLED },
\r
8807 { IDM_Hint, MF_BYCOMMAND|MF_ENABLED },
\r
8808 { IDM_Book, MF_BYCOMMAND|MF_ENABLED },
\r
8813 Enables ncpEnables[] = {
\r
8814 { IDM_MailMove, MF_BYCOMMAND|MF_GRAYED },
\r
8815 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_GRAYED },
\r
8816 { IDM_MachineWhite, MF_BYCOMMAND|MF_GRAYED },
\r
8817 { IDM_MachineBlack, MF_BYCOMMAND|MF_GRAYED },
\r
8818 { IDM_TwoMachines, MF_BYCOMMAND|MF_GRAYED },
\r
8819 { IDM_AnalysisMode, MF_BYCOMMAND|MF_GRAYED },
\r
8820 { IDM_AnalyzeFile, MF_BYCOMMAND|MF_GRAYED },
\r
8821 { IDM_IcsClient, MF_BYCOMMAND|MF_GRAYED },
\r
8822 { ACTION_POS, MF_BYPOSITION|MF_GRAYED },
\r
8823 { IDM_Revert, MF_BYCOMMAND|MF_GRAYED },
\r
8824 { IDM_MoveNow, MF_BYCOMMAND|MF_GRAYED },
\r
8825 { IDM_RetractMove, MF_BYCOMMAND|MF_GRAYED },
\r
8826 { IDM_TimeControl, MF_BYCOMMAND|MF_GRAYED },
\r
8827 { IDM_Hint, MF_BYCOMMAND|MF_GRAYED },
\r
8828 { IDM_Book, MF_BYCOMMAND|MF_GRAYED },
\r
8832 Enables trainingOnEnables[] = {
\r
8833 { IDM_EditComment, MF_BYCOMMAND|MF_GRAYED },
\r
8834 { IDM_Pause, MF_BYCOMMAND|MF_GRAYED },
\r
8835 { IDM_Forward, MF_BYCOMMAND|MF_GRAYED },
\r
8836 { IDM_Backward, MF_BYCOMMAND|MF_GRAYED },
\r
8837 { IDM_ToEnd, MF_BYCOMMAND|MF_GRAYED },
\r
8838 { IDM_ToStart, MF_BYCOMMAND|MF_GRAYED },
\r
8839 { IDM_MoveNow, MF_BYCOMMAND|MF_GRAYED },
\r
8840 { IDM_TruncateGame, MF_BYCOMMAND|MF_GRAYED },
\r
8844 Enables trainingOffEnables[] = {
\r
8845 { IDM_EditComment, MF_BYCOMMAND|MF_ENABLED },
\r
8846 { IDM_Pause, MF_BYCOMMAND|MF_ENABLED },
\r
8847 { IDM_Forward, MF_BYCOMMAND|MF_ENABLED },
\r
8848 { IDM_Backward, MF_BYCOMMAND|MF_ENABLED },
\r
8849 { IDM_ToEnd, MF_BYCOMMAND|MF_ENABLED },
\r
8850 { IDM_ToStart, MF_BYCOMMAND|MF_ENABLED },
\r
8851 { IDM_MoveNow, MF_BYCOMMAND|MF_ENABLED },
\r
8852 { IDM_TruncateGame, MF_BYCOMMAND|MF_ENABLED },
\r
8856 /* These modify either ncpEnables or gnuEnables */
\r
8857 Enables cmailEnables[] = {
\r
8858 { IDM_MailMove, MF_BYCOMMAND|MF_ENABLED },
\r
8859 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_ENABLED },
\r
8860 { ACTION_POS, MF_BYPOSITION|MF_ENABLED },
\r
8861 { IDM_CallFlag, MF_BYCOMMAND|MF_GRAYED },
\r
8862 { IDM_Draw, MF_BYCOMMAND|MF_ENABLED },
\r
8863 { IDM_Adjourn, MF_BYCOMMAND|MF_GRAYED },
\r
8864 { IDM_Abort, MF_BYCOMMAND|MF_GRAYED },
\r
8868 Enables machineThinkingEnables[] = {
\r
8869 { IDM_LoadGame, MF_BYCOMMAND|MF_GRAYED },
\r
8870 { IDM_LoadNextGame, MF_BYCOMMAND|MF_GRAYED },
\r
8871 { IDM_LoadPrevGame, MF_BYCOMMAND|MF_GRAYED },
\r
8872 { IDM_ReloadGame, MF_BYCOMMAND|MF_GRAYED },
\r
8873 { IDM_PasteGame, MF_BYCOMMAND|MF_GRAYED },
\r
8874 { IDM_LoadPosition, MF_BYCOMMAND|MF_GRAYED },
\r
8875 { IDM_LoadNextPosition, MF_BYCOMMAND|MF_GRAYED },
\r
8876 { IDM_LoadPrevPosition, MF_BYCOMMAND|MF_GRAYED },
\r
8877 { IDM_ReloadPosition, MF_BYCOMMAND|MF_GRAYED },
\r
8878 { IDM_PastePosition, MF_BYCOMMAND|MF_GRAYED },
\r
8879 { IDM_MachineWhite, MF_BYCOMMAND|MF_GRAYED },
\r
8880 { IDM_MachineBlack, MF_BYCOMMAND|MF_GRAYED },
\r
8881 { IDM_TwoMachines, MF_BYCOMMAND|MF_GRAYED },
\r
8882 { IDM_TypeInMove, MF_BYCOMMAND|MF_GRAYED },
\r
8883 { IDM_RetractMove, MF_BYCOMMAND|MF_GRAYED },
\r
8887 Enables userThinkingEnables[] = {
\r
8888 { IDM_LoadGame, MF_BYCOMMAND|MF_ENABLED },
\r
8889 { IDM_LoadNextGame, MF_BYCOMMAND|MF_ENABLED },
\r
8890 { IDM_LoadPrevGame, MF_BYCOMMAND|MF_ENABLED },
\r
8891 { IDM_ReloadGame, MF_BYCOMMAND|MF_ENABLED },
\r
8892 { IDM_PasteGame, MF_BYCOMMAND|MF_ENABLED },
\r
8893 { IDM_LoadPosition, MF_BYCOMMAND|MF_ENABLED },
\r
8894 { IDM_LoadNextPosition, MF_BYCOMMAND|MF_ENABLED },
\r
8895 { IDM_LoadPrevPosition, MF_BYCOMMAND|MF_ENABLED },
\r
8896 { IDM_ReloadPosition, MF_BYCOMMAND|MF_ENABLED },
\r
8897 { IDM_PastePosition, MF_BYCOMMAND|MF_ENABLED },
\r
8898 { IDM_MachineWhite, MF_BYCOMMAND|MF_ENABLED },
\r
8899 { IDM_MachineBlack, MF_BYCOMMAND|MF_ENABLED },
\r
8900 { IDM_TwoMachines, MF_BYCOMMAND|MF_ENABLED },
\r
8901 { IDM_TypeInMove, MF_BYCOMMAND|MF_ENABLED },
\r
8902 { IDM_RetractMove, MF_BYCOMMAND|MF_ENABLED },
\r
8906 /*---------------------------------------------------------------------------*\
\r
8908 * Front-end interface functions exported by XBoard.
\r
8909 * Functions appear in same order as prototypes in frontend.h.
\r
8911 \*---------------------------------------------------------------------------*/
\r
8915 static UINT prevChecked = 0;
\r
8916 static int prevPausing = 0;
\r
8919 if (pausing != prevPausing) {
\r
8920 prevPausing = pausing;
\r
8921 (void) CheckMenuItem(GetMenu(hwndMain), IDM_Pause,
\r
8922 MF_BYCOMMAND|(pausing ? MF_CHECKED : MF_UNCHECKED));
\r
8923 if (hwndPause) SetWindowText(hwndPause, pausing ? "C" : "P");
\r
8926 switch (gameMode) {
\r
8927 case BeginningOfGame:
\r
8928 if (appData.icsActive)
\r
8929 nowChecked = IDM_IcsClient;
\r
8930 else if (appData.noChessProgram)
\r
8931 nowChecked = IDM_EditGame;
\r
8933 nowChecked = IDM_MachineBlack;
\r
8935 case MachinePlaysBlack:
\r
8936 nowChecked = IDM_MachineBlack;
\r
8938 case MachinePlaysWhite:
\r
8939 nowChecked = IDM_MachineWhite;
\r
8941 case TwoMachinesPlay:
\r
8942 nowChecked = IDM_TwoMachines;
\r
8945 nowChecked = IDM_AnalysisMode;
\r
8948 nowChecked = IDM_AnalyzeFile;
\r
8951 nowChecked = IDM_EditGame;
\r
8953 case PlayFromGameFile:
\r
8954 nowChecked = IDM_LoadGame;
\r
8956 case EditPosition:
\r
8957 nowChecked = IDM_EditPosition;
\r
8960 nowChecked = IDM_Training;
\r
8962 case IcsPlayingWhite:
\r
8963 case IcsPlayingBlack:
\r
8964 case IcsObserving:
\r
8966 nowChecked = IDM_IcsClient;
\r
8973 if (prevChecked != 0)
\r
8974 (void) CheckMenuItem(GetMenu(hwndMain),
\r
8975 prevChecked, MF_BYCOMMAND|MF_UNCHECKED);
\r
8976 if (nowChecked != 0)
\r
8977 (void) CheckMenuItem(GetMenu(hwndMain),
\r
8978 nowChecked, MF_BYCOMMAND|MF_CHECKED);
\r
8980 if (nowChecked == IDM_LoadGame || nowChecked == IDM_Training) {
\r
8981 (void) EnableMenuItem(GetMenu(hwndMain), IDM_Training,
\r
8982 MF_BYCOMMAND|MF_ENABLED);
\r
8984 (void) EnableMenuItem(GetMenu(hwndMain),
\r
8985 IDM_Training, MF_BYCOMMAND|MF_GRAYED);
\r
8988 prevChecked = nowChecked;
\r
8990 /* [DM] icsEngineAnalyze - Do a sceure check too */
\r
8991 if (appData.icsActive) {
\r
8992 if (appData.icsEngineAnalyze) {
\r
8993 (void) CheckMenuItem(GetMenu(hwndMain), IDM_AnalysisMode,
\r
8994 MF_BYCOMMAND|MF_CHECKED);
\r
8996 (void) CheckMenuItem(GetMenu(hwndMain), IDM_AnalysisMode,
\r
8997 MF_BYCOMMAND|MF_UNCHECKED);
\r
9005 HMENU hmenu = GetMenu(hwndMain);
\r
9006 SetMenuEnables(hmenu, icsEnables);
\r
9007 EnableMenuItem(GetSubMenu(hmenu, OPTIONS_POS), ICS_POS,
\r
9008 MF_BYPOSITION|MF_ENABLED);
\r
9010 if (appData.zippyPlay) {
\r
9011 SetMenuEnables(hmenu, zippyEnables);
\r
9012 if (!appData.noChessProgram) /* [DM] icsEngineAnalyze */
\r
9013 (void) EnableMenuItem(GetMenu(hwndMain), IDM_AnalysisMode,
\r
9014 MF_BYCOMMAND|MF_ENABLED);
\r
9022 SetMenuEnables(GetMenu(hwndMain), gnuEnables);
\r
9028 HMENU hmenu = GetMenu(hwndMain);
\r
9029 SetMenuEnables(hmenu, ncpEnables);
\r
9030 EnableMenuItem(GetSubMenu(hmenu, OPTIONS_POS), SOUNDS_POS,
\r
9031 MF_BYPOSITION|MF_GRAYED);
\r
9032 DrawMenuBar(hwndMain);
\r
9038 SetMenuEnables(GetMenu(hwndMain), cmailEnables);
\r
9042 SetTrainingModeOn()
\r
9045 SetMenuEnables(GetMenu(hwndMain), trainingOnEnables);
\r
9046 for (i = 0; i < N_BUTTONS; i++) {
\r
9047 if (buttonDesc[i].hwnd != NULL)
\r
9048 EnableWindow(buttonDesc[i].hwnd, FALSE);
\r
9053 VOID SetTrainingModeOff()
\r
9056 SetMenuEnables(GetMenu(hwndMain), trainingOffEnables);
\r
9057 for (i = 0; i < N_BUTTONS; i++) {
\r
9058 if (buttonDesc[i].hwnd != NULL)
\r
9059 EnableWindow(buttonDesc[i].hwnd, TRUE);
\r
9065 SetUserThinkingEnables()
\r
9067 SetMenuEnables(GetMenu(hwndMain), userThinkingEnables);
\r
9071 SetMachineThinkingEnables()
\r
9073 HMENU hMenu = GetMenu(hwndMain);
\r
9074 int flags = MF_BYCOMMAND|MF_ENABLED;
\r
9076 SetMenuEnables(hMenu, machineThinkingEnables);
\r
9078 if (gameMode == MachinePlaysBlack) {
\r
9079 (void)EnableMenuItem(hMenu, IDM_MachineBlack, flags);
\r
9080 } else if (gameMode == MachinePlaysWhite) {
\r
9081 (void)EnableMenuItem(hMenu, IDM_MachineWhite, flags);
\r
9082 } else if (gameMode == TwoMachinesPlay) {
\r
9083 (void)EnableMenuItem(hMenu, IDM_TwoMachines, flags);
\r
9089 DisplayTitle(char *str)
\r
9091 char title[MSG_SIZ], *host;
\r
9092 if (str[0] != NULLCHAR) {
\r
9093 strcpy(title, str);
\r
9094 } else if (appData.icsActive) {
\r
9095 if (appData.icsCommPort[0] != NULLCHAR)
\r
9098 host = appData.icsHost;
\r
9099 sprintf(title, "%s: %s", szTitle, host);
\r
9100 } else if (appData.noChessProgram) {
\r
9101 strcpy(title, szTitle);
\r
9103 strcpy(title, szTitle);
\r
9104 strcat(title, ": ");
\r
9105 strcat(title, first.tidy);
\r
9107 SetWindowText(hwndMain, title);
\r
9112 DisplayMessage(char *str1, char *str2)
\r
9116 int remain = MESSAGE_TEXT_MAX - 1;
\r
9119 moveErrorMessageUp = FALSE; /* turned on later by caller if needed */
\r
9120 messageText[0] = NULLCHAR;
\r
9122 len = strlen(str1);
\r
9123 if (len > remain) len = remain;
\r
9124 strncpy(messageText, str1, len);
\r
9125 messageText[len] = NULLCHAR;
\r
9128 if (*str2 && remain >= 2) {
\r
9130 strcat(messageText, " ");
\r
9133 len = strlen(str2);
\r
9134 if (len > remain) len = remain;
\r
9135 strncat(messageText, str2, len);
\r
9137 messageText[MESSAGE_TEXT_MAX - 1] = NULLCHAR;
\r
9139 if (hwndMain == NULL || IsIconic(hwndMain)) return;
\r
9143 hdc = GetDC(hwndMain);
\r
9144 oldFont = SelectObject(hdc, font[boardSize][MESSAGE_FONT]->hf);
\r
9145 ExtTextOut(hdc, messageRect.left, messageRect.top, ETO_CLIPPED|ETO_OPAQUE,
\r
9146 &messageRect, messageText, strlen(messageText), NULL);
\r
9147 (void) SelectObject(hdc, oldFont);
\r
9148 (void) ReleaseDC(hwndMain, hdc);
\r
9152 DisplayError(char *str, int error)
\r
9154 char buf[MSG_SIZ*2], buf2[MSG_SIZ];
\r
9160 len = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
\r
9161 NULL, error, LANG_NEUTRAL,
\r
9162 (LPSTR) buf2, MSG_SIZ, NULL);
\r
9164 sprintf(buf, "%s:\n%s", str, buf2);
\r
9166 ErrorMap *em = errmap;
\r
9167 while (em->err != 0 && em->err != error) em++;
\r
9168 if (em->err != 0) {
\r
9169 sprintf(buf, "%s:\n%s", str, em->msg);
\r
9171 sprintf(buf, "%s:\nError code %d", str, error);
\r
9176 ErrorPopUp("Error", buf);
\r
9181 DisplayMoveError(char *str)
\r
9183 fromX = fromY = -1;
\r
9184 ClearHighlights();
\r
9185 DrawPosition(FALSE, NULL);
\r
9186 if (appData.popupMoveErrors) {
\r
9187 ErrorPopUp("Error", str);
\r
9189 DisplayMessage(str, "");
\r
9190 moveErrorMessageUp = TRUE;
\r
9195 DisplayFatalError(char *str, int error, int exitStatus)
\r
9197 char buf[2*MSG_SIZ], buf2[MSG_SIZ];
\r
9199 char *label = exitStatus ? "Fatal Error" : "Exiting";
\r
9202 len = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
\r
9203 NULL, error, LANG_NEUTRAL,
\r
9204 (LPSTR) buf2, MSG_SIZ, NULL);
\r
9206 sprintf(buf, "%s:\n%s", str, buf2);
\r
9208 ErrorMap *em = errmap;
\r
9209 while (em->err != 0 && em->err != error) em++;
\r
9210 if (em->err != 0) {
\r
9211 sprintf(buf, "%s:\n%s", str, em->msg);
\r
9213 sprintf(buf, "%s:\nError code %d", str, error);
\r
9218 if (appData.debugMode) {
\r
9219 fprintf(debugFP, "%s: %s\n", label, str);
\r
9221 if (appData.popupExitMessage) {
\r
9222 (void) MessageBox(hwndMain, str, label, MB_OK|
\r
9223 (exitStatus ? MB_ICONSTOP : MB_ICONINFORMATION));
\r
9225 ExitEvent(exitStatus);
\r
9230 DisplayInformation(char *str)
\r
9232 (void) MessageBox(hwndMain, str, "Information", MB_OK|MB_ICONINFORMATION);
\r
9237 DisplayNote(char *str)
\r
9239 ErrorPopUp("Note", str);
\r
9244 char *title, *question, *replyPrefix;
\r
9249 QuestionDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
9251 static QuestionParams *qp;
\r
9252 char reply[MSG_SIZ];
\r
9255 switch (message) {
\r
9256 case WM_INITDIALOG:
\r
9257 qp = (QuestionParams *) lParam;
\r
9258 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
9259 SetWindowText(hDlg, qp->title);
\r
9260 SetDlgItemText(hDlg, OPT_QuestionText, qp->question);
\r
9261 SetFocus(GetDlgItem(hDlg, OPT_QuestionInput));
\r
9265 switch (LOWORD(wParam)) {
\r
9267 strcpy(reply, qp->replyPrefix);
\r
9268 if (*reply) strcat(reply, " ");
\r
9269 len = strlen(reply);
\r
9270 GetDlgItemText(hDlg, OPT_QuestionInput, reply + len, sizeof(reply) - len);
\r
9271 strcat(reply, "\n");
\r
9272 OutputToProcess(qp->pr, reply, strlen(reply), &err);
\r
9273 EndDialog(hDlg, TRUE);
\r
9274 if (err) DisplayFatalError("Error writing to chess program", err, 1);
\r
9277 EndDialog(hDlg, FALSE);
\r
9288 AskQuestion(char* title, char *question, char *replyPrefix, ProcRef pr)
\r
9290 QuestionParams qp;
\r
9294 qp.question = question;
\r
9295 qp.replyPrefix = replyPrefix;
\r
9297 lpProc = MakeProcInstance((FARPROC)QuestionDialog, hInst);
\r
9298 DialogBoxParam(hInst, MAKEINTRESOURCE(DLG_Question),
\r
9299 hwndMain, (DLGPROC)lpProc, (LPARAM)&qp);
\r
9300 FreeProcInstance(lpProc);
\r
9303 /* [AS] Pick FRC position */
\r
9304 LRESULT CALLBACK NewGameFRC_Proc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
9306 static int * lpIndexFRC;
\r
9312 case WM_INITDIALOG:
\r
9313 lpIndexFRC = (int *) lParam;
\r
9315 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
9317 SendDlgItemMessage( hDlg, IDC_NFG_Edit, EM_SETLIMITTEXT, sizeof(buf)-1, 0 );
\r
9318 SetDlgItemInt( hDlg, IDC_NFG_Edit, *lpIndexFRC, TRUE );
\r
9319 SendDlgItemMessage( hDlg, IDC_NFG_Edit, EM_SETSEL, 0, -1 );
\r
9320 SetFocus(GetDlgItem(hDlg, IDC_NFG_Edit));
\r
9325 switch( LOWORD(wParam) ) {
\r
9327 *lpIndexFRC = GetDlgItemInt(hDlg, IDC_NFG_Edit, &index_is_ok, TRUE );
\r
9328 EndDialog( hDlg, 0 );
\r
9329 shuffleOpenings = TRUE; /* [HGM] shuffle: switch shuffling on for as long as we stay in current variant */
\r
9332 EndDialog( hDlg, 1 );
\r
9334 case IDC_NFG_Edit:
\r
9335 if( HIWORD(wParam) == EN_CHANGE ) {
\r
9336 GetDlgItemInt(hDlg, IDC_NFG_Edit, &index_is_ok, TRUE );
\r
9338 EnableWindow( GetDlgItem(hDlg, IDOK), index_is_ok );
\r
9341 case IDC_NFG_Random:
\r
9342 sprintf( buf, "%d", myrandom() ); /* [HGM] shuffle: no longer limit to 960 */
\r
9343 SetDlgItemText(hDlg, IDC_NFG_Edit, buf );
\r
9356 int index = appData.defaultFrcPosition;
\r
9357 FARPROC lpProc = MakeProcInstance( (FARPROC) NewGameFRC_Proc, hInst );
\r
9359 result = DialogBoxParam( hInst, MAKEINTRESOURCE(DLG_NewGameFRC), hwndMain, (DLGPROC)lpProc, (LPARAM)&index );
\r
9361 if( result == 0 ) {
\r
9362 appData.defaultFrcPosition = index;
\r
9368 /* [AS] Game list options */
\r
9374 static GLT_Item GLT_ItemInfo[] = {
\r
9375 { GLT_EVENT, "Event" },
\r
9376 { GLT_SITE, "Site" },
\r
9377 { GLT_DATE, "Date" },
\r
9378 { GLT_ROUND, "Round" },
\r
9379 { GLT_PLAYERS, "Players" },
\r
9380 { GLT_RESULT, "Result" },
\r
9381 { GLT_WHITE_ELO, "White Rating" },
\r
9382 { GLT_BLACK_ELO, "Black Rating" },
\r
9383 { GLT_TIME_CONTROL,"Time Control" },
\r
9384 { GLT_VARIANT, "Variant" },
\r
9385 { GLT_OUT_OF_BOOK,PGN_OUT_OF_BOOK },
\r
9389 const char * GLT_FindItem( char id )
\r
9391 const char * result = 0;
\r
9393 GLT_Item * list = GLT_ItemInfo;
\r
9395 while( list->id != 0 ) {
\r
9396 if( list->id == id ) {
\r
9397 result = list->name;
\r
9407 void GLT_AddToList( HWND hDlg, int iDlgItem, char id, int index )
\r
9409 const char * name = GLT_FindItem( id );
\r
9412 if( index >= 0 ) {
\r
9413 SendDlgItemMessage( hDlg, iDlgItem, LB_INSERTSTRING, index, (LPARAM) name );
\r
9416 SendDlgItemMessage( hDlg, iDlgItem, LB_ADDSTRING, 0, (LPARAM) name );
\r
9421 void GLT_TagsToList( HWND hDlg, char * tags )
\r
9425 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_RESETCONTENT, 0, 0 );
\r
9428 GLT_AddToList( hDlg, IDC_GameListTags, *pc, -1 );
\r
9432 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_ADDSTRING, 0, (LPARAM) "\t --- Hidden tags ---" );
\r
9434 pc = GLT_ALL_TAGS;
\r
9437 if( strchr( tags, *pc ) == 0 ) {
\r
9438 GLT_AddToList( hDlg, IDC_GameListTags, *pc, -1 );
\r
9443 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_SETCURSEL, 0, 0 );
\r
9446 char GLT_ListItemToTag( HWND hDlg, int index )
\r
9448 char result = '\0';
\r
9451 GLT_Item * list = GLT_ItemInfo;
\r
9453 if( SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETTEXT, index, (LPARAM) name ) != LB_ERR ) {
\r
9454 while( list->id != 0 ) {
\r
9455 if( strcmp( list->name, name ) == 0 ) {
\r
9456 result = list->id;
\r
9467 void GLT_MoveSelection( HWND hDlg, int delta )
\r
9469 int idx1 = (int) SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETCURSEL, 0, 0 );
\r
9470 int idx2 = idx1 + delta;
\r
9471 int count = (int) SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETCOUNT, 0, 0 );
\r
9473 if( idx1 >=0 && idx1 < count && idx2 >= 0 && idx2 < count ) {
\r
9476 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETTEXT, idx1, (LPARAM) buf );
\r
9477 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_DELETESTRING, idx1, 0 );
\r
9478 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_INSERTSTRING, idx2, (LPARAM) buf );
\r
9479 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_SETCURSEL, idx2, 0 );
\r
9483 LRESULT CALLBACK GameListOptions_Proc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
9485 static char glt[64];
\r
9486 static char * lpUserGLT;
\r
9490 case WM_INITDIALOG:
\r
9491 lpUserGLT = (char *) lParam;
\r
9493 strcpy( glt, lpUserGLT );
\r
9495 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
9497 /* Initialize list */
\r
9498 GLT_TagsToList( hDlg, glt );
\r
9500 SetFocus( GetDlgItem(hDlg, IDC_GameListTags) );
\r
9505 switch( LOWORD(wParam) ) {
\r
9508 char * pc = lpUserGLT;
\r
9510 // int cnt = (int) SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETCOUNT, 0, 0 );
\r
9514 id = GLT_ListItemToTag( hDlg, idx );
\r
9518 } while( id != '\0' );
\r
9520 EndDialog( hDlg, 0 );
\r
9523 EndDialog( hDlg, 1 );
\r
9526 case IDC_GLT_Default:
\r
9527 strcpy( glt, GLT_DEFAULT_TAGS );
\r
9528 GLT_TagsToList( hDlg, glt );
\r
9531 case IDC_GLT_Restore:
\r
9532 strcpy( glt, lpUserGLT );
\r
9533 GLT_TagsToList( hDlg, glt );
\r
9537 GLT_MoveSelection( hDlg, -1 );
\r
9540 case IDC_GLT_Down:
\r
9541 GLT_MoveSelection( hDlg, +1 );
\r
9551 int GameListOptions()
\r
9555 FARPROC lpProc = MakeProcInstance( (FARPROC) GameListOptions_Proc, hInst );
\r
9557 strcpy( glt, appData.gameListTags );
\r
9559 result = DialogBoxParam( hInst, MAKEINTRESOURCE(DLG_GameListOptions), hwndMain, (DLGPROC)lpProc, (LPARAM)glt );
\r
9561 if( result == 0 ) {
\r
9562 /* [AS] Memory leak here! */
\r
9563 appData.gameListTags = strdup( glt );
\r
9571 DisplayIcsInteractionTitle(char *str)
\r
9573 char consoleTitle[MSG_SIZ];
\r
9575 sprintf(consoleTitle, "%s: %s", szConsoleTitle, str);
\r
9576 SetWindowText(hwndConsole, consoleTitle);
\r
9580 DrawPosition(int fullRedraw, Board board)
\r
9582 HDCDrawPosition(NULL, (BOOLEAN) fullRedraw, board);
\r
9589 fromX = fromY = -1;
\r
9590 if (dragInfo.pos.x != -1 || dragInfo.pos.y != -1) {
\r
9591 dragInfo.pos.x = dragInfo.pos.y = -1;
\r
9592 dragInfo.pos.x = dragInfo.pos.y = -1;
\r
9593 dragInfo.lastpos = dragInfo.pos;
\r
9594 dragInfo.start.x = dragInfo.start.y = -1;
\r
9595 dragInfo.from = dragInfo.start;
\r
9597 DrawPosition(TRUE, NULL);
\r
9603 CommentPopUp(char *title, char *str)
\r
9605 HWND hwnd = GetActiveWindow();
\r
9606 EitherCommentPopUp(0, title, str, FALSE);
\r
9607 SetActiveWindow(hwnd);
\r
9611 CommentPopDown(void)
\r
9613 CheckMenuItem(GetMenu(hwndMain), IDM_EditComment, MF_UNCHECKED);
\r
9614 if (commentDialog) {
\r
9615 ShowWindow(commentDialog, SW_HIDE);
\r
9617 commentDialogUp = FALSE;
\r
9621 EditCommentPopUp(int index, char *title, char *str)
\r
9623 EitherCommentPopUp(index, title, str, TRUE);
\r
9630 MyPlaySound(&sounds[(int)SoundMove]);
\r
9633 VOID PlayIcsWinSound()
\r
9635 MyPlaySound(&sounds[(int)SoundIcsWin]);
\r
9638 VOID PlayIcsLossSound()
\r
9640 MyPlaySound(&sounds[(int)SoundIcsLoss]);
\r
9643 VOID PlayIcsDrawSound()
\r
9645 MyPlaySound(&sounds[(int)SoundIcsDraw]);
\r
9648 VOID PlayIcsUnfinishedSound()
\r
9650 MyPlaySound(&sounds[(int)SoundIcsUnfinished]);
\r
9656 MyPlaySound(&sounds[(int)SoundAlarm]);
\r
9664 consoleEcho = TRUE;
\r
9665 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
9666 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&consoleCF);
\r
9667 SendMessage(hInput, EM_SETBKGNDCOLOR, FALSE, consoleBackgroundColor);
\r
9676 consoleEcho = FALSE;
\r
9677 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
9678 /* This works OK: set text and background both to the same color */
\r
9680 cf.crTextColor = COLOR_ECHOOFF;
\r
9681 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&cf);
\r
9682 SendMessage(hInput, EM_SETBKGNDCOLOR, FALSE, cf.crTextColor);
\r
9685 /* No Raw()...? */
\r
9687 void Colorize(ColorClass cc, int continuation)
\r
9689 currentColorClass = cc;
\r
9690 consoleCF.dwMask = CFM_COLOR|CFM_BOLD|CFM_ITALIC|CFM_UNDERLINE|CFM_STRIKEOUT;
\r
9691 consoleCF.crTextColor = textAttribs[cc].color;
\r
9692 consoleCF.dwEffects = textAttribs[cc].effects;
\r
9693 if (!continuation) MyPlaySound(&textAttribs[cc].sound);
\r
9699 static char buf[MSG_SIZ];
\r
9700 DWORD bufsiz = MSG_SIZ;
\r
9702 if(appData.userName != NULL && appData.userName[0] != 0) {
\r
9703 return appData.userName; /* [HGM] username: prefer name selected by user over his system login */
\r
9705 if (!GetUserName(buf, &bufsiz)) {
\r
9706 /*DisplayError("Error getting user name", GetLastError());*/
\r
9707 strcpy(buf, "User");
\r
9715 static char buf[MSG_SIZ];
\r
9716 DWORD bufsiz = MSG_SIZ;
\r
9718 if (!GetComputerName(buf, &bufsiz)) {
\r
9719 /*DisplayError("Error getting host name", GetLastError());*/
\r
9720 strcpy(buf, "Unknown");
\r
9727 ClockTimerRunning()
\r
9729 return clockTimerEvent != 0;
\r
9735 if (clockTimerEvent == 0) return FALSE;
\r
9736 KillTimer(hwndMain, clockTimerEvent);
\r
9737 clockTimerEvent = 0;
\r
9742 StartClockTimer(long millisec)
\r
9744 clockTimerEvent = SetTimer(hwndMain, (UINT) CLOCK_TIMER_ID,
\r
9745 (UINT) millisec, NULL);
\r
9749 DisplayWhiteClock(long timeRemaining, int highlight)
\r
9752 char *flag = whiteFlag && gameMode == TwoMachinesPlay ? "(!)" : "";
\r
9754 if(appData.noGUI) return;
\r
9755 hdc = GetDC(hwndMain);
\r
9756 if (!IsIconic(hwndMain)) {
\r
9757 DisplayAClock(hdc, timeRemaining, highlight,
\r
9758 flipClock ? &blackRect : &whiteRect, "White", flag);
\r
9760 if (highlight && iconCurrent == iconBlack) {
\r
9761 iconCurrent = iconWhite;
\r
9762 PostMessage(hwndMain, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
9763 if (IsIconic(hwndMain)) {
\r
9764 DrawIcon(hdc, 2, 2, iconCurrent);
\r
9767 (void) ReleaseDC(hwndMain, hdc);
\r
9769 PostMessage(hwndConsole, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
9773 DisplayBlackClock(long timeRemaining, int highlight)
\r
9776 char *flag = blackFlag && gameMode == TwoMachinesPlay ? "(!)" : "";
\r
9778 if(appData.noGUI) return;
\r
9779 hdc = GetDC(hwndMain);
\r
9780 if (!IsIconic(hwndMain)) {
\r
9781 DisplayAClock(hdc, timeRemaining, highlight,
\r
9782 flipClock ? &whiteRect : &blackRect, "Black", flag);
\r
9784 if (highlight && iconCurrent == iconWhite) {
\r
9785 iconCurrent = iconBlack;
\r
9786 PostMessage(hwndMain, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
9787 if (IsIconic(hwndMain)) {
\r
9788 DrawIcon(hdc, 2, 2, iconCurrent);
\r
9791 (void) ReleaseDC(hwndMain, hdc);
\r
9793 PostMessage(hwndConsole, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
9798 LoadGameTimerRunning()
\r
9800 return loadGameTimerEvent != 0;
\r
9804 StopLoadGameTimer()
\r
9806 if (loadGameTimerEvent == 0) return FALSE;
\r
9807 KillTimer(hwndMain, loadGameTimerEvent);
\r
9808 loadGameTimerEvent = 0;
\r
9813 StartLoadGameTimer(long millisec)
\r
9815 loadGameTimerEvent = SetTimer(hwndMain, (UINT) LOAD_GAME_TIMER_ID,
\r
9816 (UINT) millisec, NULL);
\r
9824 char fileTitle[MSG_SIZ];
\r
9826 defName = DefaultFileName(appData.oldSaveStyle ? "gam" : "pgn");
\r
9827 f = OpenFileDialog(hwndMain, "a", defName,
\r
9828 appData.oldSaveStyle ? "gam" : "pgn",
\r
9830 "Save Game to File", NULL, fileTitle, NULL);
\r
9832 SaveGame(f, 0, "");
\r
9839 ScheduleDelayedEvent(DelayedEventCallback cb, long millisec)
\r
9841 if (delayedTimerEvent != 0) {
\r
9842 if (appData.debugMode) {
\r
9843 fprintf(debugFP, "ScheduleDelayedEvent: event already scheduled\n");
\r
9845 KillTimer(hwndMain, delayedTimerEvent);
\r
9846 delayedTimerEvent = 0;
\r
9847 delayedTimerCallback();
\r
9849 delayedTimerCallback = cb;
\r
9850 delayedTimerEvent = SetTimer(hwndMain, (UINT) DELAYED_TIMER_ID,
\r
9851 (UINT) millisec, NULL);
\r
9854 DelayedEventCallback
\r
9857 if (delayedTimerEvent) {
\r
9858 return delayedTimerCallback;
\r
9865 CancelDelayedEvent()
\r
9867 if (delayedTimerEvent) {
\r
9868 KillTimer(hwndMain, delayedTimerEvent);
\r
9869 delayedTimerEvent = 0;
\r
9873 DWORD GetWin32Priority(int nice)
\r
9874 { // [HGM] nice: translate Unix nice() value to indows priority class. (Code stolen from Polyglot 1.4w11)
\r
9876 REALTIME_PRIORITY_CLASS 0x00000100
\r
9877 HIGH_PRIORITY_CLASS 0x00000080
\r
9878 ABOVE_NORMAL_PRIORITY_CLASS 0x00008000
\r
9879 NORMAL_PRIORITY_CLASS 0x00000020
\r
9880 BELOW_NORMAL_PRIORITY_CLASS 0x00004000
\r
9881 IDLE_PRIORITY_CLASS 0x00000040
\r
9883 if (nice < -15) return 0x00000080;
\r
9884 if (nice < 0) return 0x00008000;
\r
9885 if (nice == 0) return 0x00000020;
\r
9886 if (nice < 15) return 0x00004000;
\r
9887 return 0x00000040;
\r
9890 /* Start a child process running the given program.
\r
9891 The process's standard output can be read from "from", and its
\r
9892 standard input can be written to "to".
\r
9893 Exit with fatal error if anything goes wrong.
\r
9894 Returns an opaque pointer that can be used to destroy the process
\r
9898 StartChildProcess(char *cmdLine, char *dir, ProcRef *pr)
\r
9900 #define BUFSIZE 4096
\r
9902 HANDLE hChildStdinRd, hChildStdinWr,
\r
9903 hChildStdoutRd, hChildStdoutWr;
\r
9904 HANDLE hChildStdinWrDup, hChildStdoutRdDup;
\r
9905 SECURITY_ATTRIBUTES saAttr;
\r
9907 PROCESS_INFORMATION piProcInfo;
\r
9908 STARTUPINFO siStartInfo;
\r
9910 char buf[MSG_SIZ];
\r
9913 if (appData.debugMode) {
\r
9914 fprintf(debugFP, "StartChildProcess (dir=\"%s\") %s\n", dir, cmdLine);
\r
9919 /* Set the bInheritHandle flag so pipe handles are inherited. */
\r
9920 saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
\r
9921 saAttr.bInheritHandle = TRUE;
\r
9922 saAttr.lpSecurityDescriptor = NULL;
\r
9925 * The steps for redirecting child's STDOUT:
\r
9926 * 1. Create anonymous pipe to be STDOUT for child.
\r
9927 * 2. Create a noninheritable duplicate of read handle,
\r
9928 * and close the inheritable read handle.
\r
9931 /* Create a pipe for the child's STDOUT. */
\r
9932 if (! CreatePipe(&hChildStdoutRd, &hChildStdoutWr, &saAttr, 0)) {
\r
9933 return GetLastError();
\r
9936 /* Duplicate the read handle to the pipe, so it is not inherited. */
\r
9937 fSuccess = DuplicateHandle(GetCurrentProcess(), hChildStdoutRd,
\r
9938 GetCurrentProcess(), &hChildStdoutRdDup, 0,
\r
9939 FALSE, /* not inherited */
\r
9940 DUPLICATE_SAME_ACCESS);
\r
9942 return GetLastError();
\r
9944 CloseHandle(hChildStdoutRd);
\r
9947 * The steps for redirecting child's STDIN:
\r
9948 * 1. Create anonymous pipe to be STDIN for child.
\r
9949 * 2. Create a noninheritable duplicate of write handle,
\r
9950 * and close the inheritable write handle.
\r
9953 /* Create a pipe for the child's STDIN. */
\r
9954 if (! CreatePipe(&hChildStdinRd, &hChildStdinWr, &saAttr, 0)) {
\r
9955 return GetLastError();
\r
9958 /* Duplicate the write handle to the pipe, so it is not inherited. */
\r
9959 fSuccess = DuplicateHandle(GetCurrentProcess(), hChildStdinWr,
\r
9960 GetCurrentProcess(), &hChildStdinWrDup, 0,
\r
9961 FALSE, /* not inherited */
\r
9962 DUPLICATE_SAME_ACCESS);
\r
9964 return GetLastError();
\r
9966 CloseHandle(hChildStdinWr);
\r
9968 /* Arrange to (1) look in dir for the child .exe file, and
\r
9969 * (2) have dir be the child's working directory. Interpret
\r
9970 * dir relative to the directory WinBoard loaded from. */
\r
9971 GetCurrentDirectory(MSG_SIZ, buf);
\r
9972 SetCurrentDirectory(installDir);
\r
9973 SetCurrentDirectory(dir);
\r
9975 /* Now create the child process. */
\r
9977 siStartInfo.cb = sizeof(STARTUPINFO);
\r
9978 siStartInfo.lpReserved = NULL;
\r
9979 siStartInfo.lpDesktop = NULL;
\r
9980 siStartInfo.lpTitle = NULL;
\r
9981 siStartInfo.dwFlags = STARTF_USESTDHANDLES;
\r
9982 siStartInfo.cbReserved2 = 0;
\r
9983 siStartInfo.lpReserved2 = NULL;
\r
9984 siStartInfo.hStdInput = hChildStdinRd;
\r
9985 siStartInfo.hStdOutput = hChildStdoutWr;
\r
9986 siStartInfo.hStdError = hChildStdoutWr;
\r
9988 fSuccess = CreateProcess(NULL,
\r
9989 cmdLine, /* command line */
\r
9990 NULL, /* process security attributes */
\r
9991 NULL, /* primary thread security attrs */
\r
9992 TRUE, /* handles are inherited */
\r
9993 DETACHED_PROCESS|CREATE_NEW_PROCESS_GROUP,
\r
9994 NULL, /* use parent's environment */
\r
9996 &siStartInfo, /* STARTUPINFO pointer */
\r
9997 &piProcInfo); /* receives PROCESS_INFORMATION */
\r
9999 err = GetLastError();
\r
10000 SetCurrentDirectory(buf); /* return to prev directory */
\r
10001 if (! fSuccess) {
\r
10005 if (appData.niceEngines){ // [HGM] nice: adjust engine proc priority
\r
10006 if(appData.debugMode) fprintf(debugFP, "nice engine proc to %d\n", appData.niceEngines);
\r
10007 SetPriorityClass(piProcInfo.hProcess, GetWin32Priority(appData.niceEngines));
\r
10010 /* Close the handles we don't need in the parent */
\r
10011 CloseHandle(piProcInfo.hThread);
\r
10012 CloseHandle(hChildStdinRd);
\r
10013 CloseHandle(hChildStdoutWr);
\r
10015 /* Prepare return value */
\r
10016 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
10017 cp->kind = CPReal;
\r
10018 cp->hProcess = piProcInfo.hProcess;
\r
10019 cp->pid = piProcInfo.dwProcessId;
\r
10020 cp->hFrom = hChildStdoutRdDup;
\r
10021 cp->hTo = hChildStdinWrDup;
\r
10023 *pr = (void *) cp;
\r
10025 /* Klaus Friedel says that this Sleep solves a problem under Windows
\r
10026 2000 where engines sometimes don't see the initial command(s)
\r
10027 from WinBoard and hang. I don't understand how that can happen,
\r
10028 but the Sleep is harmless, so I've put it in. Others have also
\r
10029 reported what may be the same problem, so hopefully this will fix
\r
10030 it for them too. */
\r
10038 DestroyChildProcess(ProcRef pr, int/*boolean*/ signal)
\r
10040 ChildProc *cp; int result;
\r
10042 cp = (ChildProc *) pr;
\r
10043 if (cp == NULL) return;
\r
10045 switch (cp->kind) {
\r
10047 /* TerminateProcess is considered harmful, so... */
\r
10048 CloseHandle(cp->hTo); /* Closing this will give the child an EOF and hopefully kill it */
\r
10049 if (cp->hFrom) CloseHandle(cp->hFrom); /* if NULL, InputThread will close it */
\r
10050 /* The following doesn't work because the chess program
\r
10051 doesn't "have the same console" as WinBoard. Maybe
\r
10052 we could arrange for this even though neither WinBoard
\r
10053 nor the chess program uses a console for stdio? */
\r
10054 /*!!if (signal) GenerateConsoleCtrlEvent(CTRL_BREAK_EVENT, cp->pid);*/
\r
10056 /* [AS] Special termination modes for misbehaving programs... */
\r
10057 if( signal == 9 ) {
\r
10058 result = TerminateProcess( cp->hProcess, 0 );
\r
10060 if ( appData.debugMode) {
\r
10061 fprintf( debugFP, "Terminating process %lu, result=%d\n", cp->pid, result );
\r
10064 else if( signal == 10 ) {
\r
10065 DWORD dw = WaitForSingleObject( cp->hProcess, 3*1000 ); // Wait 3 seconds at most
\r
10067 if( dw != WAIT_OBJECT_0 ) {
\r
10068 result = TerminateProcess( cp->hProcess, 0 );
\r
10070 if ( appData.debugMode) {
\r
10071 fprintf( debugFP, "Process %lu still alive after timeout, killing... result=%d\n", cp->pid, result );
\r
10077 CloseHandle(cp->hProcess);
\r
10081 if (cp->hFrom) CloseHandle(cp->hFrom);
\r
10085 closesocket(cp->sock);
\r
10090 if (signal) send(cp->sock2, "\017", 1, 0); /* 017 = 15 = SIGTERM */
\r
10091 closesocket(cp->sock);
\r
10092 closesocket(cp->sock2);
\r
10100 InterruptChildProcess(ProcRef pr)
\r
10104 cp = (ChildProc *) pr;
\r
10105 if (cp == NULL) return;
\r
10106 switch (cp->kind) {
\r
10108 /* The following doesn't work because the chess program
\r
10109 doesn't "have the same console" as WinBoard. Maybe
\r
10110 we could arrange for this even though neither WinBoard
\r
10111 nor the chess program uses a console for stdio */
\r
10112 /*!!GenerateConsoleCtrlEvent(CTRL_C_EVENT, cp->pid);*/
\r
10117 /* Can't interrupt */
\r
10121 send(cp->sock2, "\002", 1, 0); /* 2 = SIGINT */
\r
10128 OpenTelnet(char *host, char *port, ProcRef *pr)
\r
10130 char cmdLine[MSG_SIZ];
\r
10132 if (port[0] == NULLCHAR) {
\r
10133 sprintf(cmdLine, "%s %s", appData.telnetProgram, host);
\r
10135 sprintf(cmdLine, "%s %s %s", appData.telnetProgram, host, port);
\r
10137 return StartChildProcess(cmdLine, "", pr);
\r
10141 /* Code to open TCP sockets */
\r
10144 OpenTCP(char *host, char *port, ProcRef *pr)
\r
10149 struct sockaddr_in sa, mysa;
\r
10150 struct hostent FAR *hp;
\r
10151 unsigned short uport;
\r
10152 WORD wVersionRequested;
\r
10155 /* Initialize socket DLL */
\r
10156 wVersionRequested = MAKEWORD(1, 1);
\r
10157 err = WSAStartup(wVersionRequested, &wsaData);
\r
10158 if (err != 0) return err;
\r
10160 /* Make socket */
\r
10161 if ((s = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
\r
10162 err = WSAGetLastError();
\r
10167 /* Bind local address using (mostly) don't-care values.
\r
10169 memset((char *) &mysa, 0, sizeof(struct sockaddr_in));
\r
10170 mysa.sin_family = AF_INET;
\r
10171 mysa.sin_addr.s_addr = INADDR_ANY;
\r
10172 uport = (unsigned short) 0;
\r
10173 mysa.sin_port = htons(uport);
\r
10174 if (bind(s, (struct sockaddr *) &mysa, sizeof(struct sockaddr_in))
\r
10175 == SOCKET_ERROR) {
\r
10176 err = WSAGetLastError();
\r
10181 /* Resolve remote host name */
\r
10182 memset((char *) &sa, 0, sizeof(struct sockaddr_in));
\r
10183 if (!(hp = gethostbyname(host))) {
\r
10184 unsigned int b0, b1, b2, b3;
\r
10186 err = WSAGetLastError();
\r
10188 if (sscanf(host, "%u.%u.%u.%u", &b0, &b1, &b2, &b3) == 4) {
\r
10189 hp = (struct hostent *) calloc(1, sizeof(struct hostent));
\r
10190 hp->h_addrtype = AF_INET;
\r
10191 hp->h_length = 4;
\r
10192 hp->h_addr_list = (char **) calloc(2, sizeof(char *));
\r
10193 hp->h_addr_list[0] = (char *) malloc(4);
\r
10194 hp->h_addr_list[0][0] = (char) b0;
\r
10195 hp->h_addr_list[0][1] = (char) b1;
\r
10196 hp->h_addr_list[0][2] = (char) b2;
\r
10197 hp->h_addr_list[0][3] = (char) b3;
\r
10203 sa.sin_family = hp->h_addrtype;
\r
10204 uport = (unsigned short) atoi(port);
\r
10205 sa.sin_port = htons(uport);
\r
10206 memcpy((char *) &sa.sin_addr, hp->h_addr, hp->h_length);
\r
10208 /* Make connection */
\r
10209 if (connect(s, (struct sockaddr *) &sa,
\r
10210 sizeof(struct sockaddr_in)) == SOCKET_ERROR) {
\r
10211 err = WSAGetLastError();
\r
10216 /* Prepare return value */
\r
10217 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
10218 cp->kind = CPSock;
\r
10220 *pr = (ProcRef *) cp;
\r
10226 OpenCommPort(char *name, ProcRef *pr)
\r
10231 char fullname[MSG_SIZ];
\r
10233 if (*name != '\\')
\r
10234 sprintf(fullname, "\\\\.\\%s", name);
\r
10236 strcpy(fullname, name);
\r
10238 h = CreateFile(name, GENERIC_READ | GENERIC_WRITE,
\r
10239 0, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
\r
10240 if (h == (HANDLE) -1) {
\r
10241 return GetLastError();
\r
10245 if (!SetCommState(h, (LPDCB) &dcb)) return GetLastError();
\r
10247 /* Accumulate characters until a 100ms pause, then parse */
\r
10248 ct.ReadIntervalTimeout = 100;
\r
10249 ct.ReadTotalTimeoutMultiplier = 0;
\r
10250 ct.ReadTotalTimeoutConstant = 0;
\r
10251 ct.WriteTotalTimeoutMultiplier = 0;
\r
10252 ct.WriteTotalTimeoutConstant = 0;
\r
10253 if (!SetCommTimeouts(h, (LPCOMMTIMEOUTS) &ct)) return GetLastError();
\r
10255 /* Prepare return value */
\r
10256 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
10257 cp->kind = CPComm;
\r
10260 *pr = (ProcRef *) cp;
\r
10266 OpenLoopback(ProcRef *pr)
\r
10268 DisplayFatalError("Not implemented", 0, 1);
\r
10274 OpenRcmd(char* host, char* user, char* cmd, ProcRef* pr)
\r
10278 SOCKET s, s2, s3;
\r
10279 struct sockaddr_in sa, mysa;
\r
10280 struct hostent FAR *hp;
\r
10281 unsigned short uport;
\r
10282 WORD wVersionRequested;
\r
10285 char stderrPortStr[MSG_SIZ];
\r
10287 /* Initialize socket DLL */
\r
10288 wVersionRequested = MAKEWORD(1, 1);
\r
10289 err = WSAStartup(wVersionRequested, &wsaData);
\r
10290 if (err != 0) return err;
\r
10292 /* Resolve remote host name */
\r
10293 memset((char *) &sa, 0, sizeof(struct sockaddr_in));
\r
10294 if (!(hp = gethostbyname(host))) {
\r
10295 unsigned int b0, b1, b2, b3;
\r
10297 err = WSAGetLastError();
\r
10299 if (sscanf(host, "%u.%u.%u.%u", &b0, &b1, &b2, &b3) == 4) {
\r
10300 hp = (struct hostent *) calloc(1, sizeof(struct hostent));
\r
10301 hp->h_addrtype = AF_INET;
\r
10302 hp->h_length = 4;
\r
10303 hp->h_addr_list = (char **) calloc(2, sizeof(char *));
\r
10304 hp->h_addr_list[0] = (char *) malloc(4);
\r
10305 hp->h_addr_list[0][0] = (char) b0;
\r
10306 hp->h_addr_list[0][1] = (char) b1;
\r
10307 hp->h_addr_list[0][2] = (char) b2;
\r
10308 hp->h_addr_list[0][3] = (char) b3;
\r
10314 sa.sin_family = hp->h_addrtype;
\r
10315 uport = (unsigned short) 514;
\r
10316 sa.sin_port = htons(uport);
\r
10317 memcpy((char *) &sa.sin_addr, hp->h_addr, hp->h_length);
\r
10319 /* Bind local socket to unused "privileged" port address
\r
10321 s = INVALID_SOCKET;
\r
10322 memset((char *) &mysa, 0, sizeof(struct sockaddr_in));
\r
10323 mysa.sin_family = AF_INET;
\r
10324 mysa.sin_addr.s_addr = INADDR_ANY;
\r
10325 for (fromPort = 1023;; fromPort--) {
\r
10326 if (fromPort < 0) {
\r
10328 return WSAEADDRINUSE;
\r
10330 if (s == INVALID_SOCKET) {
\r
10331 if ((s = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
\r
10332 err = WSAGetLastError();
\r
10337 uport = (unsigned short) fromPort;
\r
10338 mysa.sin_port = htons(uport);
\r
10339 if (bind(s, (struct sockaddr *) &mysa, sizeof(struct sockaddr_in))
\r
10340 == SOCKET_ERROR) {
\r
10341 err = WSAGetLastError();
\r
10342 if (err == WSAEADDRINUSE) continue;
\r
10346 if (connect(s, (struct sockaddr *) &sa,
\r
10347 sizeof(struct sockaddr_in)) == SOCKET_ERROR) {
\r
10348 err = WSAGetLastError();
\r
10349 if (err == WSAEADDRINUSE) {
\r
10360 /* Bind stderr local socket to unused "privileged" port address
\r
10362 s2 = INVALID_SOCKET;
\r
10363 memset((char *) &mysa, 0, sizeof(struct sockaddr_in));
\r
10364 mysa.sin_family = AF_INET;
\r
10365 mysa.sin_addr.s_addr = INADDR_ANY;
\r
10366 for (fromPort = 1023;; fromPort--) {
\r
10367 if (fromPort == prevStderrPort) continue; // don't reuse port
\r
10368 if (fromPort < 0) {
\r
10369 (void) closesocket(s);
\r
10371 return WSAEADDRINUSE;
\r
10373 if (s2 == INVALID_SOCKET) {
\r
10374 if ((s2 = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
\r
10375 err = WSAGetLastError();
\r
10381 uport = (unsigned short) fromPort;
\r
10382 mysa.sin_port = htons(uport);
\r
10383 if (bind(s2, (struct sockaddr *) &mysa, sizeof(struct sockaddr_in))
\r
10384 == SOCKET_ERROR) {
\r
10385 err = WSAGetLastError();
\r
10386 if (err == WSAEADDRINUSE) continue;
\r
10387 (void) closesocket(s);
\r
10391 if (listen(s2, 1) == SOCKET_ERROR) {
\r
10392 err = WSAGetLastError();
\r
10393 if (err == WSAEADDRINUSE) {
\r
10395 s2 = INVALID_SOCKET;
\r
10398 (void) closesocket(s);
\r
10399 (void) closesocket(s2);
\r
10405 prevStderrPort = fromPort; // remember port used
\r
10406 sprintf(stderrPortStr, "%d", fromPort);
\r
10408 if (send(s, stderrPortStr, strlen(stderrPortStr) + 1, 0) == SOCKET_ERROR) {
\r
10409 err = WSAGetLastError();
\r
10410 (void) closesocket(s);
\r
10411 (void) closesocket(s2);
\r
10416 if (send(s, UserName(), strlen(UserName()) + 1, 0) == SOCKET_ERROR) {
\r
10417 err = WSAGetLastError();
\r
10418 (void) closesocket(s);
\r
10419 (void) closesocket(s2);
\r
10423 if (*user == NULLCHAR) user = UserName();
\r
10424 if (send(s, user, strlen(user) + 1, 0) == SOCKET_ERROR) {
\r
10425 err = WSAGetLastError();
\r
10426 (void) closesocket(s);
\r
10427 (void) closesocket(s2);
\r
10431 if (send(s, cmd, strlen(cmd) + 1, 0) == SOCKET_ERROR) {
\r
10432 err = WSAGetLastError();
\r
10433 (void) closesocket(s);
\r
10434 (void) closesocket(s2);
\r
10439 if ((s3 = accept(s2, NULL, NULL)) == INVALID_SOCKET) {
\r
10440 err = WSAGetLastError();
\r
10441 (void) closesocket(s);
\r
10442 (void) closesocket(s2);
\r
10446 (void) closesocket(s2); /* Stop listening */
\r
10448 /* Prepare return value */
\r
10449 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
10450 cp->kind = CPRcmd;
\r
10453 *pr = (ProcRef *) cp;
\r
10460 AddInputSource(ProcRef pr, int lineByLine,
\r
10461 InputCallback func, VOIDSTAR closure)
\r
10463 InputSource *is, *is2 = NULL;
\r
10464 ChildProc *cp = (ChildProc *) pr;
\r
10466 is = (InputSource *) calloc(1, sizeof(InputSource));
\r
10467 is->lineByLine = lineByLine;
\r
10469 is->closure = closure;
\r
10470 is->second = NULL;
\r
10471 is->next = is->buf;
\r
10472 if (pr == NoProc) {
\r
10473 is->kind = CPReal;
\r
10474 consoleInputSource = is;
\r
10476 is->kind = cp->kind;
\r
10478 [AS] Try to avoid a race condition if the thread is given control too early:
\r
10479 we create all threads suspended so that the is->hThread variable can be
\r
10480 safely assigned, then let the threads start with ResumeThread.
\r
10482 switch (cp->kind) {
\r
10484 is->hFile = cp->hFrom;
\r
10485 cp->hFrom = NULL; /* now owned by InputThread */
\r
10487 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) NonOvlInputThread,
\r
10488 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
10492 is->hFile = cp->hFrom;
\r
10493 cp->hFrom = NULL; /* now owned by InputThread */
\r
10495 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) InputThread,
\r
10496 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
10500 is->sock = cp->sock;
\r
10502 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SocketInputThread,
\r
10503 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
10507 is2 = (InputSource *) calloc(1, sizeof(InputSource));
\r
10509 is->sock = cp->sock;
\r
10510 is->second = is2;
\r
10511 is2->sock = cp->sock2;
\r
10512 is2->second = is2;
\r
10514 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SocketInputThread,
\r
10515 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
10517 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SocketInputThread,
\r
10518 (LPVOID) is2, CREATE_SUSPENDED, &is2->id);
\r
10522 if( is->hThread != NULL ) {
\r
10523 ResumeThread( is->hThread );
\r
10526 if( is2 != NULL && is2->hThread != NULL ) {
\r
10527 ResumeThread( is2->hThread );
\r
10531 return (InputSourceRef) is;
\r
10535 RemoveInputSource(InputSourceRef isr)
\r
10539 is = (InputSource *) isr;
\r
10540 is->hThread = NULL; /* tell thread to stop */
\r
10541 CloseHandle(is->hThread);
\r
10542 if (is->second != NULL) {
\r
10543 is->second->hThread = NULL;
\r
10544 CloseHandle(is->second->hThread);
\r
10550 OutputToProcess(ProcRef pr, char *message, int count, int *outError)
\r
10553 int outCount = SOCKET_ERROR;
\r
10554 ChildProc *cp = (ChildProc *) pr;
\r
10555 static OVERLAPPED ovl;
\r
10557 if (pr == NoProc) {
\r
10558 ConsoleOutput(message, count, FALSE);
\r
10562 if (ovl.hEvent == NULL) {
\r
10563 ovl.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
\r
10565 ovl.Internal = ovl.InternalHigh = ovl.Offset = ovl.OffsetHigh = 0;
\r
10567 switch (cp->kind) {
\r
10570 outCount = send(cp->sock, message, count, 0);
\r
10571 if (outCount == SOCKET_ERROR) {
\r
10572 *outError = WSAGetLastError();
\r
10574 *outError = NO_ERROR;
\r
10579 if (WriteFile(((ChildProc *)pr)->hTo, message, count,
\r
10580 &dOutCount, NULL)) {
\r
10581 *outError = NO_ERROR;
\r
10582 outCount = (int) dOutCount;
\r
10584 *outError = GetLastError();
\r
10589 *outError = DoWriteFile(((ChildProc *)pr)->hTo, message, count,
\r
10590 &dOutCount, &ovl);
\r
10591 if (*outError == NO_ERROR) {
\r
10592 outCount = (int) dOutCount;
\r
10600 OutputToProcessDelayed(ProcRef pr, char *message, int count, int *outError,
\r
10603 /* Ignore delay, not implemented for WinBoard */
\r
10604 return OutputToProcess(pr, message, count, outError);
\r
10609 CmailSigHandlerCallBack(InputSourceRef isr, VOIDSTAR closure,
\r
10610 char *buf, int count, int error)
\r
10612 DisplayFatalError("Not implemented", 0, 1);
\r
10615 /* see wgamelist.c for Game List functions */
\r
10616 /* see wedittags.c for Edit Tags functions */
\r
10623 char buf[MSG_SIZ];
\r
10626 if (SearchPath(installDir, appData.icsLogon, NULL, MSG_SIZ, buf, &dummy)) {
\r
10627 f = fopen(buf, "r");
\r
10629 ProcessICSInitScript(f);
\r
10637 StartAnalysisClock()
\r
10639 if (analysisTimerEvent) return;
\r
10640 analysisTimerEvent = SetTimer(hwndMain, (UINT) ANALYSIS_TIMER_ID,
\r
10641 (UINT) 2000, NULL);
\r
10645 AnalysisDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
10647 static HANDLE hwndText;
\r
10649 static int sizeX, sizeY;
\r
10650 int newSizeX, newSizeY, flags;
\r
10653 switch (message) {
\r
10654 case WM_INITDIALOG: /* message: initialize dialog box */
\r
10655 /* Initialize the dialog items */
\r
10656 hwndText = GetDlgItem(hDlg, OPT_AnalysisText);
\r
10657 SetWindowText(hDlg, analysisTitle);
\r
10658 SetDlgItemText(hDlg, OPT_AnalysisText, analysisText);
\r
10659 /* Size and position the dialog */
\r
10660 if (!analysisDialog) {
\r
10661 analysisDialog = hDlg;
\r
10662 flags = SWP_NOZORDER;
\r
10663 GetClientRect(hDlg, &rect);
\r
10664 sizeX = rect.right;
\r
10665 sizeY = rect.bottom;
\r
10666 if (analysisX != CW_USEDEFAULT && analysisY != CW_USEDEFAULT &&
\r
10667 analysisW != CW_USEDEFAULT && analysisH != CW_USEDEFAULT) {
\r
10668 WINDOWPLACEMENT wp;
\r
10669 EnsureOnScreen(&analysisX, &analysisY, 0, 0);
\r
10670 wp.length = sizeof(WINDOWPLACEMENT);
\r
10672 wp.showCmd = SW_SHOW;
\r
10673 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
10674 wp.rcNormalPosition.left = analysisX;
\r
10675 wp.rcNormalPosition.right = analysisX + analysisW;
\r
10676 wp.rcNormalPosition.top = analysisY;
\r
10677 wp.rcNormalPosition.bottom = analysisY + analysisH;
\r
10678 SetWindowPlacement(hDlg, &wp);
\r
10680 GetClientRect(hDlg, &rect);
\r
10681 newSizeX = rect.right;
\r
10682 newSizeY = rect.bottom;
\r
10683 ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY,
\r
10684 newSizeX, newSizeY);
\r
10685 sizeX = newSizeX;
\r
10686 sizeY = newSizeY;
\r
10691 case WM_COMMAND: /* message: received a command */
\r
10692 switch (LOWORD(wParam)) {
\r
10694 if (appData.icsActive && appData.icsEngineAnalyze) { /* [DM] icsEngineAnalyze */
\r
10695 ExitAnalyzeMode();
\r
10707 newSizeX = LOWORD(lParam);
\r
10708 newSizeY = HIWORD(lParam);
\r
10709 ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY, newSizeX, newSizeY);
\r
10710 sizeX = newSizeX;
\r
10711 sizeY = newSizeY;
\r
10714 case WM_GETMINMAXINFO:
\r
10715 /* Prevent resizing window too small */
\r
10716 mmi = (MINMAXINFO *) lParam;
\r
10717 mmi->ptMinTrackSize.x = 100;
\r
10718 mmi->ptMinTrackSize.y = 100;
\r
10725 AnalysisPopUp(char* title, char* str)
\r
10731 EngineOutputPopUp();
\r
10734 if (str == NULL) str = "";
\r
10735 p = (char *) malloc(2 * strlen(str) + 2);
\r
10738 if (*str == '\n') *q++ = '\r';
\r
10742 if (analysisText != NULL) free(analysisText);
\r
10743 analysisText = p;
\r
10745 if (analysisDialog) {
\r
10746 SetWindowText(analysisDialog, title);
\r
10747 SetDlgItemText(analysisDialog, OPT_AnalysisText, analysisText);
\r
10748 ShowWindow(analysisDialog, SW_SHOW);
\r
10750 analysisTitle = title;
\r
10751 lpProc = MakeProcInstance((FARPROC)AnalysisDialog, hInst);
\r
10752 CreateDialog(hInst, MAKEINTRESOURCE(DLG_Analysis),
\r
10753 hwndMain, (DLGPROC)lpProc);
\r
10754 FreeProcInstance(lpProc);
\r
10756 analysisDialogUp = TRUE;
\r
10760 AnalysisPopDown()
\r
10762 if (analysisDialog) {
\r
10763 ShowWindow(analysisDialog, SW_HIDE);
\r
10765 analysisDialogUp = FALSE;
\r
10770 SetHighlights(int fromX, int fromY, int toX, int toY)
\r
10772 highlightInfo.sq[0].x = fromX;
\r
10773 highlightInfo.sq[0].y = fromY;
\r
10774 highlightInfo.sq[1].x = toX;
\r
10775 highlightInfo.sq[1].y = toY;
\r
10779 ClearHighlights()
\r
10781 highlightInfo.sq[0].x = highlightInfo.sq[0].y =
\r
10782 highlightInfo.sq[1].x = highlightInfo.sq[1].y = -1;
\r
10786 SetPremoveHighlights(int fromX, int fromY, int toX, int toY)
\r
10788 premoveHighlightInfo.sq[0].x = fromX;
\r
10789 premoveHighlightInfo.sq[0].y = fromY;
\r
10790 premoveHighlightInfo.sq[1].x = toX;
\r
10791 premoveHighlightInfo.sq[1].y = toY;
\r
10795 ClearPremoveHighlights()
\r
10797 premoveHighlightInfo.sq[0].x = premoveHighlightInfo.sq[0].y =
\r
10798 premoveHighlightInfo.sq[1].x = premoveHighlightInfo.sq[1].y = -1;
\r
10802 ShutDownFrontEnd()
\r
10804 if (saveSettingsOnExit) SaveSettings(settingsFileName);
\r
10805 DeleteClipboardTempFiles();
\r
10811 if (IsIconic(hwndMain))
\r
10812 ShowWindow(hwndMain, SW_RESTORE);
\r
10814 SetActiveWindow(hwndMain);
\r
10818 * Prototypes for animation support routines
\r
10820 static void ScreenSquare(int column, int row, POINT * pt);
\r
10821 static void Tween( POINT * start, POINT * mid, POINT * finish, int factor,
\r
10822 POINT frames[], int * nFrames);
\r
10826 AnimateAtomicCapture(int fromX, int fromY, int toX, int toY, int nFrames)
\r
10827 { // [HGM] atomic: animate blast wave
\r
10829 if(appData.debugMode) fprintf(debugFP, "exploding (%d,%d)\n", toX, toY);
\r
10830 explodeInfo.fromX = fromX;
\r
10831 explodeInfo.fromY = fromY;
\r
10832 explodeInfo.toX = toX;
\r
10833 explodeInfo.toY = toY;
\r
10834 for(i=1; i<nFrames; i++) {
\r
10835 explodeInfo.radius = (i*180)/(nFrames-1);
\r
10836 DrawPosition(FALSE, NULL);
\r
10837 Sleep(appData.animSpeed);
\r
10839 explodeInfo.radius = 0;
\r
10840 DrawPosition(TRUE, NULL);
\r
10843 #define kFactor 4
\r
10846 AnimateMove(board, fromX, fromY, toX, toY)
\r
10853 ChessSquare piece;
\r
10854 POINT start, finish, mid;
\r
10855 POINT frames[kFactor * 2 + 1];
\r
10858 if (!appData.animate) return;
\r
10859 if (doingSizing) return;
\r
10860 if (fromY < 0 || fromX < 0) return;
\r
10861 piece = board[fromY][fromX];
\r
10862 if (piece >= EmptySquare) return;
\r
10864 ScreenSquare(fromX, fromY, &start);
\r
10865 ScreenSquare(toX, toY, &finish);
\r
10867 /* All pieces except knights move in straight line */
\r
10868 if (piece != WhiteKnight && piece != BlackKnight) {
\r
10869 mid.x = start.x + (finish.x - start.x) / 2;
\r
10870 mid.y = start.y + (finish.y - start.y) / 2;
\r
10872 /* Knight: make diagonal movement then straight */
\r
10873 if (abs(toY - fromY) < abs(toX - fromX)) {
\r
10874 mid.x = start.x + (finish.x - start.x) / 2;
\r
10875 mid.y = finish.y;
\r
10877 mid.x = finish.x;
\r
10878 mid.y = start.y + (finish.y - start.y) / 2;
\r
10882 /* Don't use as many frames for very short moves */
\r
10883 if (abs(toY - fromY) + abs(toX - fromX) <= 2)
\r
10884 Tween(&start, &mid, &finish, kFactor - 1, frames, &nFrames);
\r
10886 Tween(&start, &mid, &finish, kFactor, frames, &nFrames);
\r
10888 animInfo.from.x = fromX;
\r
10889 animInfo.from.y = fromY;
\r
10890 animInfo.to.x = toX;
\r
10891 animInfo.to.y = toY;
\r
10892 animInfo.lastpos = start;
\r
10893 animInfo.piece = piece;
\r
10894 for (n = 0; n < nFrames; n++) {
\r
10895 animInfo.pos = frames[n];
\r
10896 DrawPosition(FALSE, NULL);
\r
10897 animInfo.lastpos = animInfo.pos;
\r
10898 Sleep(appData.animSpeed);
\r
10900 animInfo.pos = finish;
\r
10901 DrawPosition(FALSE, NULL);
\r
10902 animInfo.piece = EmptySquare;
\r
10903 if(gameInfo.variant == VariantAtomic &&
\r
10904 (board[toY][toX] != EmptySquare || fromX != toX && (piece == WhitePawn || piece == BlackPawn) ) )
\r
10905 AnimateAtomicCapture(fromX, fromY, toX, toY, 2*nFrames);
\r
10908 /* Convert board position to corner of screen rect and color */
\r
10911 ScreenSquare(column, row, pt)
\r
10912 int column; int row; POINT * pt;
\r
10915 pt->x = lineGap + ((BOARD_WIDTH-1)-column) * (squareSize + lineGap);
\r
10916 pt->y = lineGap + row * (squareSize + lineGap);
\r
10918 pt->x = lineGap + column * (squareSize + lineGap);
\r
10919 pt->y = lineGap + ((BOARD_HEIGHT-1)-row) * (squareSize + lineGap);
\r
10923 /* Generate a series of frame coords from start->mid->finish.
\r
10924 The movement rate doubles until the half way point is
\r
10925 reached, then halves back down to the final destination,
\r
10926 which gives a nice slow in/out effect. The algorithmn
\r
10927 may seem to generate too many intermediates for short
\r
10928 moves, but remember that the purpose is to attract the
\r
10929 viewers attention to the piece about to be moved and
\r
10930 then to where it ends up. Too few frames would be less
\r
10934 Tween(start, mid, finish, factor, frames, nFrames)
\r
10935 POINT * start; POINT * mid;
\r
10936 POINT * finish; int factor;
\r
10937 POINT frames[]; int * nFrames;
\r
10939 int n, fraction = 1, count = 0;
\r
10941 /* Slow in, stepping 1/16th, then 1/8th, ... */
\r
10942 for (n = 0; n < factor; n++)
\r
10944 for (n = 0; n < factor; n++) {
\r
10945 frames[count].x = start->x + (mid->x - start->x) / fraction;
\r
10946 frames[count].y = start->y + (mid->y - start->y) / fraction;
\r
10948 fraction = fraction / 2;
\r
10952 frames[count] = *mid;
\r
10955 /* Slow out, stepping 1/2, then 1/4, ... */
\r
10957 for (n = 0; n < factor; n++) {
\r
10958 frames[count].x = finish->x - (finish->x - mid->x) / fraction;
\r
10959 frames[count].y = finish->y - (finish->y - mid->y) / fraction;
\r
10961 fraction = fraction * 2;
\r
10963 *nFrames = count;
\r
10967 HistorySet( char movelist[][2*MOVE_LEN], int first, int last, int current )
\r
10972 sprintf( buf, "HistorySet: first=%d, last=%d, current=%d (%s)\n",
\r
10973 first, last, current, current >= 0 ? movelist[current] : "n/a" );
\r
10975 OutputDebugString( buf );
\r
10978 MoveHistorySet( movelist, first, last, current, pvInfoList );
\r
10980 EvalGraphSet( first, last, current, pvInfoList );
\r
10983 void SetProgramStats( FrontEndProgramStats * stats )
\r
10988 sprintf( buf, "SetStats for %d: depth=%d, nodes=%lu, score=%5.2f, time=%5.2f, pv=%s\n",
\r
10989 stats->which, stats->depth, stats->nodes, stats->score / 100.0, stats->time / 100.0, stats->pv == 0 ? "n/a" : stats->pv );
\r
10991 OutputDebugString( buf );
\r
10994 EngineOutputUpdate( stats );
\r