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
5666 } else if((char)wParam == 003) CopyGameToClipboard();
\r
5667 else if((char)wParam == 026) PasteGameOrFENFromClipboard();
\r
5672 case WM_PALETTECHANGED:
\r
5673 if (hwnd != (HWND)wParam && !appData.monoMode) {
\r
5675 HDC hdc = GetDC(hwndMain);
\r
5676 SelectPalette(hdc, hPal, TRUE);
\r
5677 nnew = RealizePalette(hdc);
\r
5679 paletteChanged = TRUE;
\r
5681 UpdateColors(hdc);
\r
5683 InvalidateRect(hwnd, &boardRect, FALSE);/*faster!*/
\r
5686 ReleaseDC(hwnd, hdc);
\r
5690 case WM_QUERYNEWPALETTE:
\r
5691 if (!appData.monoMode /*&& paletteChanged*/) {
\r
5693 HDC hdc = GetDC(hwndMain);
\r
5694 paletteChanged = FALSE;
\r
5695 SelectPalette(hdc, hPal, FALSE);
\r
5696 nnew = RealizePalette(hdc);
\r
5698 InvalidateRect(hwnd, &boardRect, FALSE);
\r
5700 ReleaseDC(hwnd, hdc);
\r
5705 case WM_COMMAND: /* message: command from application menu */
\r
5706 wmId = LOWORD(wParam);
\r
5707 wmEvent = HIWORD(wParam);
\r
5712 AnalysisPopDown();
\r
5713 SAY("new game enter a move to play against the computer with white");
\r
5716 case IDM_NewGameFRC:
\r
5717 if( NewGameFRC() == 0 ) {
\r
5719 AnalysisPopDown();
\r
5723 case IDM_NewVariant:
\r
5724 NewVariantPopup(hwnd);
\r
5727 case IDM_LoadGame:
\r
5728 LoadGameDialog(hwnd, "Load Game from File");
\r
5731 case IDM_LoadNextGame:
\r
5735 case IDM_LoadPrevGame:
\r
5739 case IDM_ReloadGame:
\r
5743 case IDM_LoadPosition:
\r
5744 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile) {
\r
5745 Reset(FALSE, TRUE);
\r
5748 f = OpenFileDialog(hwnd, "rb", "",
\r
5749 appData.oldSaveStyle ? "pos" : "fen",
\r
5751 "Load Position from File", &number, fileTitle, NULL);
\r
5753 LoadPosition(f, number, fileTitle);
\r
5757 case IDM_LoadNextPosition:
\r
5758 ReloadPosition(1);
\r
5761 case IDM_LoadPrevPosition:
\r
5762 ReloadPosition(-1);
\r
5765 case IDM_ReloadPosition:
\r
5766 ReloadPosition(0);
\r
5769 case IDM_SaveGame:
\r
5770 defName = DefaultFileName(appData.oldSaveStyle ? "gam" : "pgn");
\r
5771 f = OpenFileDialog(hwnd, "a", defName,
\r
5772 appData.oldSaveStyle ? "gam" : "pgn",
\r
5774 "Save Game to File", NULL, fileTitle, NULL);
\r
5776 SaveGame(f, 0, "");
\r
5780 case IDM_SavePosition:
\r
5781 defName = DefaultFileName(appData.oldSaveStyle ? "pos" : "fen");
\r
5782 f = OpenFileDialog(hwnd, "a", defName,
\r
5783 appData.oldSaveStyle ? "pos" : "fen",
\r
5785 "Save Position to File", NULL, fileTitle, NULL);
\r
5787 SavePosition(f, 0, "");
\r
5791 case IDM_SaveDiagram:
\r
5792 defName = "diagram";
\r
5793 f = OpenFileDialog(hwnd, "wb", defName,
\r
5796 "Save Diagram to File", NULL, fileTitle, NULL);
\r
5802 case IDM_CopyGame:
\r
5803 CopyGameToClipboard();
\r
5806 case IDM_PasteGame:
\r
5807 PasteGameFromClipboard();
\r
5810 case IDM_CopyGameListToClipboard:
\r
5811 CopyGameListToClipboard();
\r
5814 /* [AS] Autodetect FEN or PGN data */
\r
5815 case IDM_PasteAny:
\r
5816 PasteGameOrFENFromClipboard();
\r
5819 /* [AS] Move history */
\r
5820 case IDM_ShowMoveHistory:
\r
5821 if( MoveHistoryIsUp() ) {
\r
5822 MoveHistoryPopDown();
\r
5825 MoveHistoryPopUp();
\r
5829 /* [AS] Eval graph */
\r
5830 case IDM_ShowEvalGraph:
\r
5831 if( EvalGraphIsUp() ) {
\r
5832 EvalGraphPopDown();
\r
5836 SetFocus(hwndMain);
\r
5840 /* [AS] Engine output */
\r
5841 case IDM_ShowEngineOutput:
\r
5842 if( EngineOutputIsUp() ) {
\r
5843 EngineOutputPopDown();
\r
5846 EngineOutputPopUp();
\r
5850 /* [AS] User adjudication */
\r
5851 case IDM_UserAdjudication_White:
\r
5852 UserAdjudicationEvent( +1 );
\r
5855 case IDM_UserAdjudication_Black:
\r
5856 UserAdjudicationEvent( -1 );
\r
5859 case IDM_UserAdjudication_Draw:
\r
5860 UserAdjudicationEvent( 0 );
\r
5863 /* [AS] Game list options dialog */
\r
5864 case IDM_GameListOptions:
\r
5865 GameListOptions();
\r
5868 case IDM_CopyPosition:
\r
5869 CopyFENToClipboard();
\r
5872 case IDM_PastePosition:
\r
5873 PasteFENFromClipboard();
\r
5876 case IDM_MailMove:
\r
5880 case IDM_ReloadCMailMsg:
\r
5881 Reset(TRUE, TRUE);
\r
5882 ReloadCmailMsgEvent(FALSE);
\r
5885 case IDM_Minimize:
\r
5886 ShowWindow(hwnd, SW_MINIMIZE);
\r
5893 case IDM_MachineWhite:
\r
5894 MachineWhiteEvent();
\r
5896 * refresh the tags dialog only if it's visible
\r
5898 if (gameMode == MachinePlaysWhite && IsWindowVisible(editTagsDialog)) {
\r
5900 tags = PGNTags(&gameInfo);
\r
5901 TagsPopUp(tags, CmailMsg());
\r
5904 SAY("computer starts playing white");
\r
5907 case IDM_MachineBlack:
\r
5908 MachineBlackEvent();
\r
5910 * refresh the tags dialog only if it's visible
\r
5912 if (gameMode == MachinePlaysBlack && IsWindowVisible(editTagsDialog)) {
\r
5914 tags = PGNTags(&gameInfo);
\r
5915 TagsPopUp(tags, CmailMsg());
\r
5918 SAY("computer starts playing black");
\r
5921 case IDM_TwoMachines:
\r
5922 TwoMachinesEvent();
\r
5924 * refresh the tags dialog only if it's visible
\r
5926 if (gameMode == TwoMachinesPlay && IsWindowVisible(editTagsDialog)) {
\r
5928 tags = PGNTags(&gameInfo);
\r
5929 TagsPopUp(tags, CmailMsg());
\r
5932 SAY("programs start playing each other");
\r
5935 case IDM_AnalysisMode:
\r
5936 if (!first.analysisSupport) {
\r
5937 sprintf(buf, "%s does not support analysis", first.tidy);
\r
5938 DisplayError(buf, 0);
\r
5940 SAY("analyzing current position");
\r
5941 /* [DM] icsEngineAnlyze [HGM] Why is this front-end??? */
\r
5942 if (appData.icsActive) {
\r
5943 if (gameMode != IcsObserving) {
\r
5944 sprintf(buf, "You are not observing a game");
\r
5945 DisplayError(buf, 0);
\r
5946 /* secure check */
\r
5947 if (appData.icsEngineAnalyze) {
\r
5948 if (appData.debugMode)
\r
5949 fprintf(debugFP, "Found unexpected active ICS engine analyze \n");
\r
5950 ExitAnalyzeMode();
\r
5956 /* if enable, user want disable icsEngineAnalyze */
\r
5957 if (appData.icsEngineAnalyze) {
\r
5958 ExitAnalyzeMode();
\r
5962 appData.icsEngineAnalyze = TRUE;
\r
5963 if (appData.debugMode) fprintf(debugFP, "ICS engine analyze starting...\n");
\r
5966 if (!appData.showThinking) ToggleShowThinking();
\r
5967 AnalyzeModeEvent();
\r
5971 case IDM_AnalyzeFile:
\r
5972 if (!first.analysisSupport) {
\r
5973 char buf[MSG_SIZ];
\r
5974 sprintf(buf, "%s does not support analysis", first.tidy);
\r
5975 DisplayError(buf, 0);
\r
5977 if (!appData.showThinking) ToggleShowThinking();
\r
5978 AnalyzeFileEvent();
\r
5979 LoadGameDialog(hwnd, "Analyze Game from File");
\r
5980 AnalysisPeriodicEvent(1);
\r
5984 case IDM_IcsClient:
\r
5988 case IDM_EditGame:
\r
5993 case IDM_EditPosition:
\r
5994 EditPositionEvent();
\r
5995 SAY("to set up a position type a FEN");
\r
5998 case IDM_Training:
\r
6002 case IDM_ShowGameList:
\r
6003 ShowGameListProc();
\r
6006 case IDM_EditTags:
\r
6010 case IDM_EditComment:
\r
6011 if (commentDialogUp && editComment) {
\r
6014 EditCommentEvent();
\r
6034 case IDM_CallFlag:
\r
6054 case IDM_StopObserving:
\r
6055 StopObservingEvent();
\r
6058 case IDM_StopExamining:
\r
6059 StopExaminingEvent();
\r
6062 case IDM_TypeInMove:
\r
6063 PopUpMoveDialog('\000');
\r
6066 case IDM_TypeInName:
\r
6067 PopUpNameDialog('\000');
\r
6070 case IDM_Backward:
\r
6072 SetFocus(hwndMain);
\r
6079 SetFocus(hwndMain);
\r
6084 SetFocus(hwndMain);
\r
6089 SetFocus(hwndMain);
\r
6096 case IDM_TruncateGame:
\r
6097 TruncateGameEvent();
\r
6104 case IDM_RetractMove:
\r
6105 RetractMoveEvent();
\r
6108 case IDM_FlipView:
\r
6109 flipView = !flipView;
\r
6110 DrawPosition(FALSE, NULL);
\r
6113 case IDM_FlipClock:
\r
6114 flipClock = !flipClock;
\r
6115 DisplayBothClocks();
\r
6116 DrawPosition(FALSE, NULL);
\r
6119 case IDM_GeneralOptions:
\r
6120 GeneralOptionsPopup(hwnd);
\r
6121 DrawPosition(TRUE, NULL);
\r
6124 case IDM_BoardOptions:
\r
6125 BoardOptionsPopup(hwnd);
\r
6128 case IDM_EnginePlayOptions:
\r
6129 EnginePlayOptionsPopup(hwnd);
\r
6132 case IDM_OptionsUCI:
\r
6133 UciOptionsPopup(hwnd);
\r
6136 case IDM_IcsOptions:
\r
6137 IcsOptionsPopup(hwnd);
\r
6141 FontsOptionsPopup(hwnd);
\r
6145 SoundOptionsPopup(hwnd);
\r
6148 case IDM_CommPort:
\r
6149 CommPortOptionsPopup(hwnd);
\r
6152 case IDM_LoadOptions:
\r
6153 LoadOptionsPopup(hwnd);
\r
6156 case IDM_SaveOptions:
\r
6157 SaveOptionsPopup(hwnd);
\r
6160 case IDM_TimeControl:
\r
6161 TimeControlOptionsPopup(hwnd);
\r
6164 case IDM_SaveSettings:
\r
6165 SaveSettings(settingsFileName);
\r
6168 case IDM_SaveSettingsOnExit:
\r
6169 saveSettingsOnExit = !saveSettingsOnExit;
\r
6170 (void) CheckMenuItem(GetMenu(hwndMain), IDM_SaveSettingsOnExit,
\r
6171 MF_BYCOMMAND|(saveSettingsOnExit ?
\r
6172 MF_CHECKED : MF_UNCHECKED));
\r
6183 case IDM_AboutGame:
\r
6188 appData.debugMode = !appData.debugMode;
\r
6189 if (appData.debugMode) {
\r
6190 char dir[MSG_SIZ];
\r
6191 GetCurrentDirectory(MSG_SIZ, dir);
\r
6192 SetCurrentDirectory(installDir);
\r
6193 debugFP = fopen(appData.nameOfDebugFile, "w");
\r
6194 SetCurrentDirectory(dir);
\r
6195 setbuf(debugFP, NULL);
\r
6202 case IDM_HELPCONTENTS:
\r
6203 if (!MyHelp (hwnd, "winboard.hlp", HELP_KEY,(DWORD)(LPSTR)"CONTENTS") &&
\r
6204 !HtmlHelp(hwnd, "winboard.chm", 0, 0) ) {
\r
6205 MessageBox (GetFocus(),
\r
6206 "Unable to activate help",
\r
6207 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
6211 case IDM_HELPSEARCH:
\r
6212 if (!MyHelp (hwnd, "winboard.hlp", HELP_PARTIALKEY, (DWORD)(LPSTR)"") &&
\r
6213 !HtmlHelp(hwnd, "winboard.chm", 0, 0) ) {
\r
6214 MessageBox (GetFocus(),
\r
6215 "Unable to activate help",
\r
6216 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
6220 case IDM_HELPHELP:
\r
6221 if(!WinHelp(hwnd, (LPSTR)NULL, HELP_HELPONHELP, 0)) {
\r
6222 MessageBox (GetFocus(),
\r
6223 "Unable to activate help",
\r
6224 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
6229 lpProc = MakeProcInstance((FARPROC)About, hInst);
\r
6231 (gameInfo.event && strcmp(gameInfo.event, "Easter Egg Hunt") == 0) ?
\r
6232 "AboutBox2" : "AboutBox", hwnd, (DLGPROC)lpProc);
\r
6233 FreeProcInstance(lpProc);
\r
6236 case IDM_DirectCommand1:
\r
6237 AskQuestionEvent("Direct Command",
\r
6238 "Send to chess program:", "", "1");
\r
6240 case IDM_DirectCommand2:
\r
6241 AskQuestionEvent("Direct Command",
\r
6242 "Send to second chess program:", "", "2");
\r
6245 case EP_WhitePawn:
\r
6246 EditPositionMenuEvent(WhitePawn, fromX, fromY);
\r
6247 fromX = fromY = -1;
\r
6250 case EP_WhiteKnight:
\r
6251 EditPositionMenuEvent(WhiteKnight, fromX, fromY);
\r
6252 fromX = fromY = -1;
\r
6255 case EP_WhiteBishop:
\r
6256 EditPositionMenuEvent(WhiteBishop, fromX, fromY);
\r
6257 fromX = fromY = -1;
\r
6260 case EP_WhiteRook:
\r
6261 EditPositionMenuEvent(WhiteRook, fromX, fromY);
\r
6262 fromX = fromY = -1;
\r
6265 case EP_WhiteQueen:
\r
6266 EditPositionMenuEvent(WhiteQueen, fromX, fromY);
\r
6267 fromX = fromY = -1;
\r
6270 case EP_WhiteFerz:
\r
6271 EditPositionMenuEvent(WhiteFerz, fromX, fromY);
\r
6272 fromX = fromY = -1;
\r
6275 case EP_WhiteWazir:
\r
6276 EditPositionMenuEvent(WhiteWazir, fromX, fromY);
\r
6277 fromX = fromY = -1;
\r
6280 case EP_WhiteAlfil:
\r
6281 EditPositionMenuEvent(WhiteAlfil, fromX, fromY);
\r
6282 fromX = fromY = -1;
\r
6285 case EP_WhiteCannon:
\r
6286 EditPositionMenuEvent(WhiteCannon, fromX, fromY);
\r
6287 fromX = fromY = -1;
\r
6290 case EP_WhiteCardinal:
\r
6291 EditPositionMenuEvent(WhiteAngel, fromX, fromY);
\r
6292 fromX = fromY = -1;
\r
6295 case EP_WhiteMarshall:
\r
6296 EditPositionMenuEvent(WhiteMarshall, fromX, fromY);
\r
6297 fromX = fromY = -1;
\r
6300 case EP_WhiteKing:
\r
6301 EditPositionMenuEvent(WhiteKing, fromX, fromY);
\r
6302 fromX = fromY = -1;
\r
6305 case EP_BlackPawn:
\r
6306 EditPositionMenuEvent(BlackPawn, fromX, fromY);
\r
6307 fromX = fromY = -1;
\r
6310 case EP_BlackKnight:
\r
6311 EditPositionMenuEvent(BlackKnight, fromX, fromY);
\r
6312 fromX = fromY = -1;
\r
6315 case EP_BlackBishop:
\r
6316 EditPositionMenuEvent(BlackBishop, fromX, fromY);
\r
6317 fromX = fromY = -1;
\r
6320 case EP_BlackRook:
\r
6321 EditPositionMenuEvent(BlackRook, fromX, fromY);
\r
6322 fromX = fromY = -1;
\r
6325 case EP_BlackQueen:
\r
6326 EditPositionMenuEvent(BlackQueen, fromX, fromY);
\r
6327 fromX = fromY = -1;
\r
6330 case EP_BlackFerz:
\r
6331 EditPositionMenuEvent(BlackFerz, fromX, fromY);
\r
6332 fromX = fromY = -1;
\r
6335 case EP_BlackWazir:
\r
6336 EditPositionMenuEvent(BlackWazir, fromX, fromY);
\r
6337 fromX = fromY = -1;
\r
6340 case EP_BlackAlfil:
\r
6341 EditPositionMenuEvent(BlackAlfil, fromX, fromY);
\r
6342 fromX = fromY = -1;
\r
6345 case EP_BlackCannon:
\r
6346 EditPositionMenuEvent(BlackCannon, fromX, fromY);
\r
6347 fromX = fromY = -1;
\r
6350 case EP_BlackCardinal:
\r
6351 EditPositionMenuEvent(BlackAngel, fromX, fromY);
\r
6352 fromX = fromY = -1;
\r
6355 case EP_BlackMarshall:
\r
6356 EditPositionMenuEvent(BlackMarshall, fromX, fromY);
\r
6357 fromX = fromY = -1;
\r
6360 case EP_BlackKing:
\r
6361 EditPositionMenuEvent(BlackKing, fromX, fromY);
\r
6362 fromX = fromY = -1;
\r
6365 case EP_EmptySquare:
\r
6366 EditPositionMenuEvent(EmptySquare, fromX, fromY);
\r
6367 fromX = fromY = -1;
\r
6370 case EP_ClearBoard:
\r
6371 EditPositionMenuEvent(ClearBoard, fromX, fromY);
\r
6372 fromX = fromY = -1;
\r
6376 EditPositionMenuEvent(WhitePlay, fromX, fromY);
\r
6377 fromX = fromY = -1;
\r
6381 EditPositionMenuEvent(BlackPlay, fromX, fromY);
\r
6382 fromX = fromY = -1;
\r
6386 EditPositionMenuEvent(PromotePiece, fromX, fromY);
\r
6387 fromX = fromY = -1;
\r
6391 EditPositionMenuEvent(DemotePiece, fromX, fromY);
\r
6392 fromX = fromY = -1;
\r
6396 DropMenuEvent(WhitePawn, fromX, fromY);
\r
6397 fromX = fromY = -1;
\r
6401 DropMenuEvent(WhiteKnight, fromX, fromY);
\r
6402 fromX = fromY = -1;
\r
6406 DropMenuEvent(WhiteBishop, fromX, fromY);
\r
6407 fromX = fromY = -1;
\r
6411 DropMenuEvent(WhiteRook, fromX, fromY);
\r
6412 fromX = fromY = -1;
\r
6416 DropMenuEvent(WhiteQueen, fromX, fromY);
\r
6417 fromX = fromY = -1;
\r
6421 return (DefWindowProc(hwnd, message, wParam, lParam));
\r
6427 case CLOCK_TIMER_ID:
\r
6428 KillTimer(hwnd, clockTimerEvent); /* Simulate one-shot timer as in X */
\r
6429 clockTimerEvent = 0;
\r
6430 DecrementClocks(); /* call into back end */
\r
6432 case LOAD_GAME_TIMER_ID:
\r
6433 KillTimer(hwnd, loadGameTimerEvent); /* Simulate one-shot timer as in X*/
\r
6434 loadGameTimerEvent = 0;
\r
6435 AutoPlayGameLoop(); /* call into back end */
\r
6437 case ANALYSIS_TIMER_ID:
\r
6438 if ((gameMode == AnalyzeMode || gameMode == AnalyzeFile
\r
6439 || appData.icsEngineAnalyze) && appData.periodicUpdates) {
\r
6440 AnalysisPeriodicEvent(0);
\r
6442 KillTimer(hwnd, analysisTimerEvent);
\r
6443 analysisTimerEvent = 0;
\r
6446 case DELAYED_TIMER_ID:
\r
6447 KillTimer(hwnd, delayedTimerEvent);
\r
6448 delayedTimerEvent = 0;
\r
6449 delayedTimerCallback();
\r
6454 case WM_USER_Input:
\r
6455 InputEvent(hwnd, message, wParam, lParam);
\r
6458 /* [AS] Also move "attached" child windows */
\r
6459 case WM_WINDOWPOSCHANGING:
\r
6461 if( hwnd == hwndMain && appData.useStickyWindows ) {
\r
6462 LPWINDOWPOS lpwp = (LPWINDOWPOS) lParam;
\r
6464 if( ((lpwp->flags & SWP_NOMOVE) == 0) && ((lpwp->flags & SWP_NOSIZE) != 0) ) {
\r
6465 /* Window is moving */
\r
6468 // GetWindowRect( hwnd, &rcMain ); //[HGM] sticky: in XP this returned new position, not old
\r
6469 rcMain.left = boardX; // replace by these 4 lines to reconstruct old rect
\r
6470 rcMain.right = boardX + winWidth;
\r
6471 rcMain.top = boardY;
\r
6472 rcMain.bottom = boardY + winHeight;
\r
6474 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, moveHistoryDialog, &wpMoveHistory );
\r
6475 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, evalGraphDialog, &wpEvalGraph );
\r
6476 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, engineOutputDialog, &wpEngineOutput );
\r
6477 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, gameListDialog, &wpGameList );
\r
6478 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, hwndConsole, &wpConsole );
\r
6485 /* [AS] Snapping */
\r
6486 case WM_ENTERSIZEMOVE:
\r
6487 if(appData.debugMode) { fprintf(debugFP, "size-move\n"); }
\r
6488 if (hwnd == hwndMain) {
\r
6489 doingSizing = TRUE;
\r
6492 return OnEnterSizeMove( &sd, hwnd, wParam, lParam );
\r
6496 if(appData.debugMode) { fprintf(debugFP, "sizing\n"); }
\r
6497 if (hwnd == hwndMain) {
\r
6498 lastSizing = wParam;
\r
6503 if(appData.debugMode) { fprintf(debugFP, "moving\n"); }
\r
6504 return OnMoving( &sd, hwnd, wParam, lParam );
\r
6506 case WM_EXITSIZEMOVE:
\r
6507 if(appData.debugMode) { fprintf(debugFP, "exit size-move, size = %d\n", squareSize); }
\r
6508 if (hwnd == hwndMain) {
\r
6510 doingSizing = FALSE;
\r
6511 InvalidateRect(hwnd, &boardRect, FALSE);
\r
6512 GetClientRect(hwnd, &client);
\r
6513 ResizeBoard(client.right, client.bottom, lastSizing);
\r
6515 if(appData.debugMode) { fprintf(debugFP, "square size = %d\n", squareSize); }
\r
6517 return OnExitSizeMove( &sd, hwnd, wParam, lParam );
\r
6520 case WM_DESTROY: /* message: window being destroyed */
\r
6521 PostQuitMessage(0);
\r
6525 if (hwnd == hwndMain) {
\r
6530 default: /* Passes it on if unprocessed */
\r
6531 return (DefWindowProc(hwnd, message, wParam, lParam));
\r
6536 /*---------------------------------------------------------------------------*\
\r
6538 * Misc utility routines
\r
6540 \*---------------------------------------------------------------------------*/
\r
6543 * Decent random number generator, at least not as bad as Windows
\r
6544 * standard rand, which returns a value in the range 0 to 0x7fff.
\r
6546 unsigned int randstate;
\r
6551 randstate = randstate * 1664525 + 1013904223;
\r
6552 return (int) randstate & 0x7fffffff;
\r
6556 mysrandom(unsigned int seed)
\r
6563 * returns TRUE if user selects a different color, FALSE otherwise
\r
6567 ChangeColor(HWND hwnd, COLORREF *which)
\r
6569 static BOOL firstTime = TRUE;
\r
6570 static DWORD customColors[16];
\r
6572 COLORREF newcolor;
\r
6577 /* Make initial colors in use available as custom colors */
\r
6578 /* Should we put the compiled-in defaults here instead? */
\r
6580 customColors[i++] = lightSquareColor & 0xffffff;
\r
6581 customColors[i++] = darkSquareColor & 0xffffff;
\r
6582 customColors[i++] = whitePieceColor & 0xffffff;
\r
6583 customColors[i++] = blackPieceColor & 0xffffff;
\r
6584 customColors[i++] = highlightSquareColor & 0xffffff;
\r
6585 customColors[i++] = premoveHighlightColor & 0xffffff;
\r
6587 for (ccl = (ColorClass) 0; ccl < NColorClasses && i < 16; ccl++) {
\r
6588 customColors[i++] = textAttribs[ccl].color;
\r
6590 while (i < 16) customColors[i++] = RGB(255, 255, 255);
\r
6591 firstTime = FALSE;
\r
6594 cc.lStructSize = sizeof(cc);
\r
6595 cc.hwndOwner = hwnd;
\r
6596 cc.hInstance = NULL;
\r
6597 cc.rgbResult = (DWORD) (*which & 0xffffff);
\r
6598 cc.lpCustColors = (LPDWORD) customColors;
\r
6599 cc.Flags = CC_RGBINIT|CC_FULLOPEN;
\r
6601 if (!ChooseColor(&cc)) return FALSE;
\r
6603 newcolor = (COLORREF) (0x2000000 | cc.rgbResult);
\r
6604 if (newcolor == *which) return FALSE;
\r
6605 *which = newcolor;
\r
6609 InitDrawingColors();
\r
6610 InvalidateRect(hwnd, &boardRect, FALSE);
\r
6615 MyLoadSound(MySound *ms)
\r
6621 if (ms->data) free(ms->data);
\r
6624 switch (ms->name[0]) {
\r
6630 /* System sound from Control Panel. Don't preload here. */
\r
6634 if (ms->name[1] == NULLCHAR) {
\r
6635 /* "!" alone = silence */
\r
6638 /* Builtin wave resource. Error if not found. */
\r
6639 HANDLE h = FindResource(hInst, ms->name + 1, "WAVE");
\r
6640 if (h == NULL) break;
\r
6641 ms->data = (void *)LoadResource(hInst, h);
\r
6642 if (h == NULL) break;
\r
6647 /* .wav file. Error if not found. */
\r
6648 f = fopen(ms->name, "rb");
\r
6649 if (f == NULL) break;
\r
6650 if (fstat(fileno(f), &st) < 0) break;
\r
6651 ms->data = malloc(st.st_size);
\r
6652 if (fread(ms->data, st.st_size, 1, f) < 1) break;
\r
6658 char buf[MSG_SIZ];
\r
6659 sprintf(buf, "Error loading sound %s", ms->name);
\r
6660 DisplayError(buf, GetLastError());
\r
6666 MyPlaySound(MySound *ms)
\r
6668 BOOLEAN ok = FALSE;
\r
6669 if(appData.debugMode) fprintf(debugFP, "make sound %s %x %d\n", ms->name, ms, ms->name[0]);
\r
6670 switch (ms->name[0]) {
\r
6672 if(appData.debugMode) fprintf(debugFP, "silence\n");
\r
6677 /* System sound from Control Panel (deprecated feature).
\r
6678 "$" alone or an unset sound name gets default beep (still in use). */
\r
6679 if (ms->name[1]) {
\r
6680 ok = PlaySound(ms->name + 1, NULL, SND_ALIAS|SND_ASYNC);
\r
6682 if (!ok) ok = MessageBeep(MB_OK);
\r
6685 /* Builtin wave resource, or "!" alone for silence */
\r
6686 if (ms->name[1]) {
\r
6687 if (ms->data == NULL) return FALSE;
\r
6688 ok = PlaySound(ms->data, NULL, SND_MEMORY|SND_ASYNC);
\r
6694 /* .wav file. Error if not found. */
\r
6695 if (ms->data == NULL) return FALSE;
\r
6696 ok = PlaySound(ms->data, NULL, SND_MEMORY|SND_ASYNC);
\r
6699 /* Don't print an error: this can happen innocently if the sound driver
\r
6700 is busy; for instance, if another instance of WinBoard is playing
\r
6701 a sound at about the same time. */
\r
6704 char buf[MSG_SIZ];
\r
6705 sprintf(buf, "Error playing sound %s", ms->name);
\r
6706 DisplayError(buf, GetLastError());
\r
6714 OldOpenFileHook(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
6717 OPENFILENAME *ofn;
\r
6718 static UINT *number; /* gross that this is static */
\r
6720 switch (message) {
\r
6721 case WM_INITDIALOG: /* message: initialize dialog box */
\r
6722 /* Center the dialog over the application window */
\r
6723 ofn = (OPENFILENAME *) lParam;
\r
6724 if (ofn->Flags & OFN_ENABLETEMPLATE) {
\r
6725 number = (UINT *) ofn->lCustData;
\r
6726 SendMessage(GetDlgItem(hDlg, edt2), WM_SETTEXT, 0, (LPARAM) "");
\r
6730 CenterWindow (hDlg, GetWindow (hDlg, GW_OWNER));
\r
6731 return FALSE; /* Allow for further processing */
\r
6734 if ((LOWORD(wParam) == IDOK) && (number != NULL)) {
\r
6735 *number = GetDlgItemInt(hDlg, OPT_IndexNumberOld, &ok, FALSE);
\r
6737 return FALSE; /* Allow for further processing */
\r
6743 OpenFileHook(HWND hdlg, UINT uiMsg, WPARAM wParam, LPARAM lParam)
\r
6745 static UINT *number;
\r
6746 OPENFILENAME *ofname;
\r
6749 case WM_INITDIALOG:
\r
6750 ofname = (OPENFILENAME *)lParam;
\r
6751 number = (UINT *)(ofname->lCustData);
\r
6754 ofnot = (OFNOTIFY *)lParam;
\r
6755 if (ofnot->hdr.code == CDN_FILEOK) {
\r
6756 *number = GetDlgItemInt(hdlg, OPT_IndexNumber, NULL, FALSE);
\r
6765 OpenFileDialog(HWND hwnd, char *write, char *defName, char *defExt, // [HGM] diag: type of 'write' now string
\r
6766 char *nameFilt, char *dlgTitle, UINT *number,
\r
6767 char fileTitle[MSG_SIZ], char fileName[MSG_SIZ])
\r
6769 OPENFILENAME openFileName;
\r
6770 char buf1[MSG_SIZ];
\r
6773 if (fileName == NULL) fileName = buf1;
\r
6774 if (defName == NULL) {
\r
6775 strcpy(fileName, "*.");
\r
6776 strcat(fileName, defExt);
\r
6778 strcpy(fileName, defName);
\r
6780 if (fileTitle) strcpy(fileTitle, "");
\r
6781 if (number) *number = 0;
\r
6783 openFileName.lStructSize = sizeof(OPENFILENAME);
\r
6784 openFileName.hwndOwner = hwnd;
\r
6785 openFileName.hInstance = (HANDLE) hInst;
\r
6786 openFileName.lpstrFilter = nameFilt;
\r
6787 openFileName.lpstrCustomFilter = (LPSTR) NULL;
\r
6788 openFileName.nMaxCustFilter = 0L;
\r
6789 openFileName.nFilterIndex = 1L;
\r
6790 openFileName.lpstrFile = fileName;
\r
6791 openFileName.nMaxFile = MSG_SIZ;
\r
6792 openFileName.lpstrFileTitle = fileTitle;
\r
6793 openFileName.nMaxFileTitle = fileTitle ? MSG_SIZ : 0;
\r
6794 openFileName.lpstrInitialDir = NULL;
\r
6795 openFileName.lpstrTitle = dlgTitle;
\r
6796 openFileName.Flags = OFN_PATHMUSTEXIST | OFN_HIDEREADONLY
\r
6797 | (write[0] != 'r' ? 0 : OFN_FILEMUSTEXIST)
\r
6798 | (number ? OFN_ENABLETEMPLATE | OFN_ENABLEHOOK: 0)
\r
6799 | (oldDialog ? 0 : OFN_EXPLORER);
\r
6800 openFileName.nFileOffset = 0;
\r
6801 openFileName.nFileExtension = 0;
\r
6802 openFileName.lpstrDefExt = defExt;
\r
6803 openFileName.lCustData = (LONG) number;
\r
6804 openFileName.lpfnHook = oldDialog ?
\r
6805 (LPOFNHOOKPROC) OldOpenFileHook : (LPOFNHOOKPROC) OpenFileHook;
\r
6806 openFileName.lpTemplateName = (LPSTR)(oldDialog ? 1536 : DLG_IndexNumber);
\r
6808 if (write[0] != 'r' ? GetSaveFileName(&openFileName) :
\r
6809 GetOpenFileName(&openFileName)) {
\r
6810 /* open the file */
\r
6811 f = fopen(openFileName.lpstrFile, write);
\r
6813 MessageBox(hwnd, "File open failed", NULL,
\r
6814 MB_OK|MB_ICONEXCLAMATION);
\r
6818 int err = CommDlgExtendedError();
\r
6819 if (err != 0) DisplayError("Internal error in file dialog box", err);
\r
6828 MenuPopup(HWND hwnd, POINT pt, HMENU hmenu, UINT def)
\r
6830 HMENU hmenuTrackPopup; /* floating pop-up menu */
\r
6833 * Get the first pop-up menu in the menu template. This is the
\r
6834 * menu that TrackPopupMenu displays.
\r
6836 hmenuTrackPopup = GetSubMenu(hmenu, 0);
\r
6838 SetMenuDefaultItem(hmenuTrackPopup, def, FALSE);
\r
6841 * TrackPopup uses screen coordinates, so convert the
\r
6842 * coordinates of the mouse click to screen coordinates.
\r
6844 ClientToScreen(hwnd, (LPPOINT) &pt);
\r
6846 /* Draw and track the floating pop-up menu. */
\r
6847 TrackPopupMenu(hmenuTrackPopup, TPM_CENTERALIGN | TPM_RIGHTBUTTON,
\r
6848 pt.x, pt.y, 0, hwnd, NULL);
\r
6850 /* Destroy the menu.*/
\r
6851 DestroyMenu(hmenu);
\r
6856 int sizeX, sizeY, newSizeX, newSizeY;
\r
6858 } ResizeEditPlusButtonsClosure;
\r
6861 ResizeEditPlusButtonsCallback(HWND hChild, LPARAM lparam)
\r
6863 ResizeEditPlusButtonsClosure *cl = (ResizeEditPlusButtonsClosure *)lparam;
\r
6867 if (hChild == cl->hText) return TRUE;
\r
6868 GetWindowRect(hChild, &rect); /* gives screen coords */
\r
6869 pt.x = rect.left + (cl->newSizeX - cl->sizeX)/2;
\r
6870 pt.y = rect.top + cl->newSizeY - cl->sizeY;
\r
6871 ScreenToClient(cl->hDlg, &pt);
\r
6872 cl->hdwp = DeferWindowPos(cl->hdwp, hChild, NULL,
\r
6873 pt.x, pt.y, rect.right - rect.left, rect.bottom - rect.top, SWP_NOZORDER);
\r
6877 /* Resize a dialog that has a (rich) edit field filling most of
\r
6878 the top, with a row of buttons below */
\r
6880 ResizeEditPlusButtons(HWND hDlg, HWND hText, int sizeX, int sizeY, int newSizeX, int newSizeY)
\r
6883 int newTextHeight, newTextWidth;
\r
6884 ResizeEditPlusButtonsClosure cl;
\r
6886 /*if (IsIconic(hDlg)) return;*/
\r
6887 if (newSizeX == sizeX && newSizeY == sizeY) return;
\r
6889 cl.hdwp = BeginDeferWindowPos(8);
\r
6891 GetWindowRect(hText, &rectText); /* gives screen coords */
\r
6892 newTextWidth = rectText.right - rectText.left + newSizeX - sizeX;
\r
6893 newTextHeight = rectText.bottom - rectText.top + newSizeY - sizeY;
\r
6894 if (newTextHeight < 0) {
\r
6895 newSizeY += -newTextHeight;
\r
6896 newTextHeight = 0;
\r
6898 cl.hdwp = DeferWindowPos(cl.hdwp, hText, NULL, 0, 0,
\r
6899 newTextWidth, newTextHeight, SWP_NOZORDER|SWP_NOMOVE);
\r
6905 cl.newSizeX = newSizeX;
\r
6906 cl.newSizeY = newSizeY;
\r
6907 EnumChildWindows(hDlg, ResizeEditPlusButtonsCallback, (LPARAM)&cl);
\r
6909 EndDeferWindowPos(cl.hdwp);
\r
6912 BOOL CenterWindowEx(HWND hwndChild, HWND hwndParent, int mode)
\r
6914 RECT rChild, rParent;
\r
6915 int wChild, hChild, wParent, hParent;
\r
6916 int wScreen, hScreen, xNew, yNew;
\r
6919 /* Get the Height and Width of the child window */
\r
6920 GetWindowRect (hwndChild, &rChild);
\r
6921 wChild = rChild.right - rChild.left;
\r
6922 hChild = rChild.bottom - rChild.top;
\r
6924 /* Get the Height and Width of the parent window */
\r
6925 GetWindowRect (hwndParent, &rParent);
\r
6926 wParent = rParent.right - rParent.left;
\r
6927 hParent = rParent.bottom - rParent.top;
\r
6929 /* Get the display limits */
\r
6930 hdc = GetDC (hwndChild);
\r
6931 wScreen = GetDeviceCaps (hdc, HORZRES);
\r
6932 hScreen = GetDeviceCaps (hdc, VERTRES);
\r
6933 ReleaseDC(hwndChild, hdc);
\r
6935 /* Calculate new X position, then adjust for screen */
\r
6936 xNew = rParent.left + ((wParent - wChild) /2);
\r
6939 } else if ((xNew+wChild) > wScreen) {
\r
6940 xNew = wScreen - wChild;
\r
6943 /* Calculate new Y position, then adjust for screen */
\r
6945 yNew = rParent.top + ((hParent - hChild) /2);
\r
6948 yNew = rParent.top + GetSystemMetrics( SM_CYCAPTION ) * 2 / 3;
\r
6953 } else if ((yNew+hChild) > hScreen) {
\r
6954 yNew = hScreen - hChild;
\r
6957 /* Set it, and return */
\r
6958 return SetWindowPos (hwndChild, NULL,
\r
6959 xNew, yNew, 0, 0, SWP_NOSIZE | SWP_NOZORDER);
\r
6962 /* Center one window over another */
\r
6963 BOOL CenterWindow (HWND hwndChild, HWND hwndParent)
\r
6965 return CenterWindowEx( hwndChild, hwndParent, 0 );
\r
6968 /*---------------------------------------------------------------------------*\
\r
6970 * Startup Dialog functions
\r
6972 \*---------------------------------------------------------------------------*/
\r
6974 InitComboStrings(HANDLE hwndCombo, char **cd)
\r
6976 SendMessage(hwndCombo, CB_RESETCONTENT, 0, 0);
\r
6978 while (*cd != NULL) {
\r
6979 SendMessage(hwndCombo, CB_ADDSTRING, 0, (LPARAM) *cd);
\r
6985 InitComboStringsFromOption(HANDLE hwndCombo, char *str)
\r
6987 char buf1[ARG_MAX];
\r
6990 if (str[0] == '@') {
\r
6991 FILE* f = fopen(str + 1, "r");
\r
6993 DisplayFatalError(str + 1, errno, 2);
\r
6996 len = fread(buf1, 1, sizeof(buf1)-1, f);
\r
6998 buf1[len] = NULLCHAR;
\r
7002 SendMessage(hwndCombo, CB_RESETCONTENT, 0, 0);
\r
7005 char buf[MSG_SIZ];
\r
7006 char *end = strchr(str, '\n');
\r
7007 if (end == NULL) return;
\r
7008 memcpy(buf, str, end - str);
\r
7009 buf[end - str] = NULLCHAR;
\r
7010 SendMessage(hwndCombo, CB_ADDSTRING, 0, (LPARAM) buf);
\r
7016 SetStartupDialogEnables(HWND hDlg)
\r
7018 EnableWindow(GetDlgItem(hDlg, OPT_ChessEngineName),
\r
7019 IsDlgButtonChecked(hDlg, OPT_ChessEngine) ||
\r
7020 (appData.zippyPlay && IsDlgButtonChecked(hDlg, OPT_ChessServer)));
\r
7021 EnableWindow(GetDlgItem(hDlg, OPT_SecondChessEngineName),
\r
7022 IsDlgButtonChecked(hDlg, OPT_ChessEngine));
\r
7023 EnableWindow(GetDlgItem(hDlg, OPT_ChessServerName),
\r
7024 IsDlgButtonChecked(hDlg, OPT_ChessServer));
\r
7025 EnableWindow(GetDlgItem(hDlg, OPT_AdditionalOptions),
\r
7026 IsDlgButtonChecked(hDlg, OPT_AnyAdditional));
\r
7027 EnableWindow(GetDlgItem(hDlg, IDOK),
\r
7028 IsDlgButtonChecked(hDlg, OPT_ChessEngine) ||
\r
7029 IsDlgButtonChecked(hDlg, OPT_ChessServer) ||
\r
7030 IsDlgButtonChecked(hDlg, OPT_View));
\r
7034 QuoteForFilename(char *filename)
\r
7036 int dquote, space;
\r
7037 dquote = strchr(filename, '"') != NULL;
\r
7038 space = strchr(filename, ' ') != NULL;
\r
7039 if (dquote || space) {
\r
7051 InitEngineBox(HWND hDlg, HWND hwndCombo, char* nthcp, char* nthd, char* nthdir, char *nthnames)
\r
7053 char buf[MSG_SIZ];
\r
7056 InitComboStringsFromOption(hwndCombo, nthnames);
\r
7057 q = QuoteForFilename(nthcp);
\r
7058 sprintf(buf, "%s%s%s", q, nthcp, q);
\r
7059 if (*nthdir != NULLCHAR) {
\r
7060 q = QuoteForFilename(nthdir);
\r
7061 sprintf(buf + strlen(buf), " /%s=%s%s%s", nthd, q, nthdir, q);
\r
7063 if (*nthcp == NULLCHAR) {
\r
7064 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) 0, (LPARAM) 0);
\r
7065 } else if (SendMessage(hwndCombo, CB_SELECTSTRING, (WPARAM) -1, (LPARAM) buf) == CB_ERR) {
\r
7066 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) -1, (LPARAM) 0);
\r
7067 SendMessage(hwndCombo, WM_SETTEXT, (WPARAM) 0, (LPARAM) buf);
\r
7072 StartupDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7074 char buf[MSG_SIZ];
\r
7078 switch (message) {
\r
7079 case WM_INITDIALOG:
\r
7080 /* Center the dialog */
\r
7081 CenterWindow (hDlg, GetDesktopWindow());
\r
7082 /* Initialize the dialog items */
\r
7083 InitEngineBox(hDlg, GetDlgItem(hDlg, OPT_ChessEngineName),
\r
7084 appData.firstChessProgram, "fd", appData.firstDirectory,
\r
7085 firstChessProgramNames);
\r
7086 InitEngineBox(hDlg, GetDlgItem(hDlg, OPT_SecondChessEngineName),
\r
7087 appData.secondChessProgram, "sd", appData.secondDirectory,
\r
7088 secondChessProgramNames);
\r
7089 hwndCombo = GetDlgItem(hDlg, OPT_ChessServerName);
\r
7090 InitComboStringsFromOption(hwndCombo, icsNames);
\r
7091 sprintf(buf, "%s /icsport=%s", appData.icsHost, appData.icsPort);
\r
7092 if (*appData.icsHelper != NULLCHAR) {
\r
7093 char *q = QuoteForFilename(appData.icsHelper);
\r
7094 sprintf(buf + strlen(buf), " /icshelper=%s%s%s", q, appData.icsHelper, q);
\r
7096 if (*appData.icsHost == NULLCHAR) {
\r
7097 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) 0, (LPARAM) 0);
\r
7098 /*SendMessage(hwndCombo, CB_SHOWDROPDOWN, (WPARAM) TRUE, (LPARAM) 0); !!too soon */
\r
7099 } else if (SendMessage(hwndCombo, CB_SELECTSTRING, (WPARAM) -1, (LPARAM) buf) == CB_ERR) {
\r
7100 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) -1, (LPARAM) 0);
\r
7101 SendMessage(hwndCombo, WM_SETTEXT, (WPARAM) 0, (LPARAM) buf);
\r
7104 if (appData.icsActive) {
\r
7105 CheckDlgButton(hDlg, OPT_ChessServer, BST_CHECKED);
\r
7107 else if (appData.noChessProgram) {
\r
7108 CheckDlgButton(hDlg, OPT_View, BST_CHECKED);
\r
7111 CheckDlgButton(hDlg, OPT_ChessEngine, BST_CHECKED);
\r
7114 SetStartupDialogEnables(hDlg);
\r
7118 switch (LOWORD(wParam)) {
\r
7120 if (IsDlgButtonChecked(hDlg, OPT_ChessEngine)) {
\r
7121 strcpy(buf, "/fcp=");
\r
7122 GetDlgItemText(hDlg, OPT_ChessEngineName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
7124 ParseArgs(StringGet, &p);
\r
7125 strcpy(buf, "/scp=");
\r
7126 GetDlgItemText(hDlg, OPT_SecondChessEngineName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
7128 ParseArgs(StringGet, &p);
\r
7129 appData.noChessProgram = FALSE;
\r
7130 appData.icsActive = FALSE;
\r
7131 } else if (IsDlgButtonChecked(hDlg, OPT_ChessServer)) {
\r
7132 strcpy(buf, "/ics /icshost=");
\r
7133 GetDlgItemText(hDlg, OPT_ChessServerName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
7135 ParseArgs(StringGet, &p);
\r
7136 if (appData.zippyPlay) {
\r
7137 strcpy(buf, "/fcp=");
\r
7138 GetDlgItemText(hDlg, OPT_ChessEngineName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
7140 ParseArgs(StringGet, &p);
\r
7142 } else if (IsDlgButtonChecked(hDlg, OPT_View)) {
\r
7143 appData.noChessProgram = TRUE;
\r
7144 appData.icsActive = FALSE;
\r
7146 MessageBox(hDlg, "Choose an option, or cancel to exit",
\r
7147 "Option Error", MB_OK|MB_ICONEXCLAMATION);
\r
7150 if (IsDlgButtonChecked(hDlg, OPT_AnyAdditional)) {
\r
7151 GetDlgItemText(hDlg, OPT_AdditionalOptions, buf, sizeof(buf));
\r
7153 ParseArgs(StringGet, &p);
\r
7155 EndDialog(hDlg, TRUE);
\r
7162 case IDM_HELPCONTENTS:
\r
7163 if (!WinHelp (hDlg, "winboard.hlp", HELP_KEY,(DWORD)(LPSTR)"CONTENTS")) {
\r
7164 MessageBox (GetFocus(),
\r
7165 "Unable to activate help",
\r
7166 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
7171 SetStartupDialogEnables(hDlg);
\r
7179 /*---------------------------------------------------------------------------*\
\r
7181 * About box dialog functions
\r
7183 \*---------------------------------------------------------------------------*/
\r
7185 /* Process messages for "About" dialog box */
\r
7187 About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7189 switch (message) {
\r
7190 case WM_INITDIALOG: /* message: initialize dialog box */
\r
7191 /* Center the dialog over the application window */
\r
7192 CenterWindow (hDlg, GetWindow (hDlg, GW_OWNER));
\r
7193 SetDlgItemText(hDlg, ABOUTBOX_Version, programVersion);
\r
7196 case WM_COMMAND: /* message: received a command */
\r
7197 if (LOWORD(wParam) == IDOK /* "OK" box selected? */
\r
7198 || LOWORD(wParam) == IDCANCEL) { /* System menu close command? */
\r
7199 EndDialog(hDlg, TRUE); /* Exit the dialog */
\r
7207 /*---------------------------------------------------------------------------*\
\r
7209 * Comment Dialog functions
\r
7211 \*---------------------------------------------------------------------------*/
\r
7214 CommentDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7216 static HANDLE hwndText = NULL;
\r
7217 int len, newSizeX, newSizeY, flags;
\r
7218 static int sizeX, sizeY;
\r
7223 switch (message) {
\r
7224 case WM_INITDIALOG: /* message: initialize dialog box */
\r
7225 /* Initialize the dialog items */
\r
7226 hwndText = GetDlgItem(hDlg, OPT_CommentText);
\r
7227 SetDlgItemText(hDlg, OPT_CommentText, commentText);
\r
7228 EnableWindow(GetDlgItem(hDlg, OPT_CancelComment), editComment);
\r
7229 EnableWindow(GetDlgItem(hDlg, OPT_ClearComment), editComment);
\r
7230 EnableWindow(GetDlgItem(hDlg, OPT_EditComment), !editComment);
\r
7231 SendMessage(hwndText, EM_SETREADONLY, !editComment, 0);
\r
7232 SetWindowText(hDlg, commentTitle);
\r
7233 if (editComment) {
\r
7234 SetFocus(hwndText);
\r
7236 SetFocus(GetDlgItem(hDlg, IDOK));
\r
7238 SendMessage(GetDlgItem(hDlg, OPT_CommentText),
\r
7239 WM_SETFONT, (WPARAM)font[boardSize][COMMENT_FONT]->hf,
\r
7240 MAKELPARAM(FALSE, 0));
\r
7241 /* Size and position the dialog */
\r
7242 if (!commentDialog) {
\r
7243 commentDialog = hDlg;
\r
7244 flags = SWP_NOZORDER;
\r
7245 GetClientRect(hDlg, &rect);
\r
7246 sizeX = rect.right;
\r
7247 sizeY = rect.bottom;
\r
7248 if (commentX != CW_USEDEFAULT && commentY != CW_USEDEFAULT &&
\r
7249 commentW != CW_USEDEFAULT && commentH != CW_USEDEFAULT) {
\r
7250 WINDOWPLACEMENT wp;
\r
7251 EnsureOnScreen(&commentX, &commentY, 0, 0);
\r
7252 wp.length = sizeof(WINDOWPLACEMENT);
\r
7254 wp.showCmd = SW_SHOW;
\r
7255 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
7256 wp.rcNormalPosition.left = commentX;
\r
7257 wp.rcNormalPosition.right = commentX + commentW;
\r
7258 wp.rcNormalPosition.top = commentY;
\r
7259 wp.rcNormalPosition.bottom = commentY + commentH;
\r
7260 SetWindowPlacement(hDlg, &wp);
\r
7262 GetClientRect(hDlg, &rect);
\r
7263 newSizeX = rect.right;
\r
7264 newSizeY = rect.bottom;
\r
7265 ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY,
\r
7266 newSizeX, newSizeY);
\r
7273 case WM_COMMAND: /* message: received a command */
\r
7274 switch (LOWORD(wParam)) {
\r
7276 if (editComment) {
\r
7278 /* Read changed options from the dialog box */
\r
7279 hwndText = GetDlgItem(hDlg, OPT_CommentText);
\r
7280 len = GetWindowTextLength(hwndText);
\r
7281 str = (char *) malloc(len + 1);
\r
7282 GetWindowText(hwndText, str, len + 1);
\r
7291 ReplaceComment(commentIndex, str);
\r
7298 case OPT_CancelComment:
\r
7302 case OPT_ClearComment:
\r
7303 SetDlgItemText(hDlg, OPT_CommentText, "");
\r
7306 case OPT_EditComment:
\r
7307 EditCommentEvent();
\r
7316 newSizeX = LOWORD(lParam);
\r
7317 newSizeY = HIWORD(lParam);
\r
7318 ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY, newSizeX, newSizeY);
\r
7323 case WM_GETMINMAXINFO:
\r
7324 /* Prevent resizing window too small */
\r
7325 mmi = (MINMAXINFO *) lParam;
\r
7326 mmi->ptMinTrackSize.x = 100;
\r
7327 mmi->ptMinTrackSize.y = 100;
\r
7334 EitherCommentPopUp(int index, char *title, char *str, BOOLEAN edit)
\r
7339 CheckMenuItem(GetMenu(hwndMain), IDM_EditComment, edit ? MF_CHECKED : MF_UNCHECKED);
\r
7341 if (str == NULL) str = "";
\r
7342 p = (char *) malloc(2 * strlen(str) + 2);
\r
7345 if (*str == '\n') *q++ = '\r';
\r
7349 if (commentText != NULL) free(commentText);
\r
7351 commentIndex = index;
\r
7352 commentTitle = title;
\r
7354 editComment = edit;
\r
7356 if (commentDialog) {
\r
7357 SendMessage(commentDialog, WM_INITDIALOG, 0, 0);
\r
7358 if (!commentDialogUp) ShowWindow(commentDialog, SW_SHOW);
\r
7360 lpProc = MakeProcInstance((FARPROC)CommentDialog, hInst);
\r
7361 CreateDialog(hInst, MAKEINTRESOURCE(DLG_EditComment),
\r
7362 hwndMain, (DLGPROC)lpProc);
\r
7363 FreeProcInstance(lpProc);
\r
7365 commentDialogUp = TRUE;
\r
7369 /*---------------------------------------------------------------------------*\
\r
7371 * Type-in move dialog functions
\r
7373 \*---------------------------------------------------------------------------*/
\r
7376 TypeInMoveDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7378 char move[MSG_SIZ];
\r
7380 ChessMove moveType;
\r
7381 int fromX, fromY, toX, toY;
\r
7384 switch (message) {
\r
7385 case WM_INITDIALOG:
\r
7386 move[0] = (char) lParam;
\r
7387 move[1] = NULLCHAR;
\r
7388 CenterWindowEx(hDlg, GetWindow(hDlg, GW_OWNER), 1 );
\r
7389 hInput = GetDlgItem(hDlg, OPT_Move);
\r
7390 SetWindowText(hInput, move);
\r
7392 SendMessage(hInput, EM_SETSEL, (WPARAM)9999, (LPARAM)9999);
\r
7396 switch (LOWORD(wParam)) {
\r
7398 GetDlgItemText(hDlg, OPT_Move, move, sizeof(move));
\r
7399 { int n; Board board;
\r
7401 if(gameMode == EditPosition && ParseFEN(board, &n, move) ) {
\r
7402 EditPositionPasteFEN(move);
\r
7403 EndDialog(hDlg, TRUE);
\r
7406 // [HGM] movenum: allow move number to be typed in any mode
\r
7407 if(sscanf(move, "%d", &n) == 1 && n != 0 ) {
\r
7408 currentMove = 2*n-1;
\r
7409 if(currentMove > forwardMostMove) currentMove = forwardMostMove;
\r
7410 if(currentMove < backwardMostMove) currentMove = backwardMostMove;
\r
7411 EndDialog(hDlg, TRUE);
\r
7412 DrawPosition(TRUE, boards[currentMove]);
\r
7413 if(currentMove > backwardMostMove) DisplayMove(currentMove - 1);
\r
7414 else DisplayMessage("", "");
\r
7418 if (gameMode != EditGame && currentMove != forwardMostMove &&
\r
7419 gameMode != Training) {
\r
7420 DisplayMoveError("Displayed move is not current");
\r
7422 // GetDlgItemText(hDlg, OPT_Move, move, sizeof(move)); // moved upstream
\r
7423 int ok = ParseOneMove(move, gameMode == EditPosition ? blackPlaysFirst : currentMove,
\r
7424 &moveType, &fromX, &fromY, &toX, &toY, &promoChar);
\r
7425 if(!ok && move[0] >= 'a') { move[0] += 'A' - 'a'; ok = 2; } // [HGM] try also capitalized
\r
7426 if (ok==1 || ok && ParseOneMove(move, gameMode == EditPosition ? blackPlaysFirst : currentMove,
\r
7427 &moveType, &fromX, &fromY, &toX, &toY, &promoChar)) {
\r
7428 if (gameMode != Training)
\r
7429 forwardMostMove = currentMove;
\r
7430 UserMoveEvent(fromX, fromY, toX, toY, promoChar);
\r
7432 DisplayMoveError("Could not parse move");
\r
7435 EndDialog(hDlg, TRUE);
\r
7438 EndDialog(hDlg, FALSE);
\r
7449 PopUpMoveDialog(char firstchar)
\r
7453 if ((gameMode == BeginningOfGame && !appData.icsActive) ||
\r
7454 gameMode == MachinePlaysWhite || gameMode == MachinePlaysBlack ||
\r
7455 gameMode == AnalyzeMode || gameMode == EditGame ||
\r
7456 gameMode == EditPosition || gameMode == IcsExamining ||
\r
7457 gameMode == IcsPlayingWhite || gameMode == IcsPlayingBlack ||
\r
7458 isdigit(firstchar) && // [HGM] movenum: allow typing in of move nr in 'passive' modes
\r
7459 ( gameMode == AnalyzeFile || gameMode == PlayFromGameFile ||
\r
7460 gameMode == IcsObserving || gameMode == TwoMachinesPlay ) ||
\r
7461 gameMode == Training) {
\r
7462 lpProc = MakeProcInstance((FARPROC)TypeInMoveDialog, hInst);
\r
7463 DialogBoxParam(hInst, MAKEINTRESOURCE(DLG_TypeInMove),
\r
7464 hwndMain, (DLGPROC)lpProc, (LPARAM)firstchar);
\r
7465 FreeProcInstance(lpProc);
\r
7469 /*---------------------------------------------------------------------------*\
\r
7471 * Type-in name dialog functions
\r
7473 \*---------------------------------------------------------------------------*/
\r
7476 TypeInNameDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7478 char move[MSG_SIZ];
\r
7481 switch (message) {
\r
7482 case WM_INITDIALOG:
\r
7483 move[0] = (char) lParam;
\r
7484 move[1] = NULLCHAR;
\r
7485 CenterWindowEx(hDlg, GetWindow(hDlg, GW_OWNER), 1 );
\r
7486 hInput = GetDlgItem(hDlg, OPT_Name);
\r
7487 SetWindowText(hInput, move);
\r
7489 SendMessage(hInput, EM_SETSEL, (WPARAM)9999, (LPARAM)9999);
\r
7493 switch (LOWORD(wParam)) {
\r
7495 GetDlgItemText(hDlg, OPT_Name, move, sizeof(move));
\r
7496 appData.userName = strdup(move);
\r
7499 EndDialog(hDlg, TRUE);
\r
7502 EndDialog(hDlg, FALSE);
\r
7513 PopUpNameDialog(char firstchar)
\r
7517 lpProc = MakeProcInstance((FARPROC)TypeInNameDialog, hInst);
\r
7518 DialogBoxParam(hInst, MAKEINTRESOURCE(DLG_TypeInName),
\r
7519 hwndMain, (DLGPROC)lpProc, (LPARAM)firstchar);
\r
7520 FreeProcInstance(lpProc);
\r
7523 /*---------------------------------------------------------------------------*\
\r
7527 \*---------------------------------------------------------------------------*/
\r
7529 /* Nonmodal error box */
\r
7530 LRESULT CALLBACK ErrorDialog(HWND hDlg, UINT message,
\r
7531 WPARAM wParam, LPARAM lParam);
\r
7534 ErrorPopUp(char *title, char *content)
\r
7538 BOOLEAN modal = hwndMain == NULL;
\r
7556 strncpy(errorTitle, title, sizeof(errorTitle));
\r
7557 errorTitle[sizeof(errorTitle) - 1] = '\0';
\r
7560 MessageBox(NULL, errorMessage, errorTitle, MB_OK|MB_ICONEXCLAMATION);
\r
7562 lpProc = MakeProcInstance((FARPROC)ErrorDialog, hInst);
\r
7563 CreateDialog(hInst, MAKEINTRESOURCE(DLG_Error),
\r
7564 hwndMain, (DLGPROC)lpProc);
\r
7565 FreeProcInstance(lpProc);
\r
7572 if (!appData.popupMoveErrors && moveErrorMessageUp) DisplayMessage("", "");
\r
7573 if (errorDialog == NULL) return;
\r
7574 DestroyWindow(errorDialog);
\r
7575 errorDialog = NULL;
\r
7579 ErrorDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7584 switch (message) {
\r
7585 case WM_INITDIALOG:
\r
7586 GetWindowRect(hDlg, &rChild);
\r
7589 SetWindowPos(hDlg, NULL, rChild.left,
\r
7590 rChild.top + boardRect.top - (rChild.bottom - rChild.top),
\r
7591 0, 0, SWP_NOZORDER|SWP_NOSIZE);
\r
7595 [AS] It seems that the above code wants to move the dialog up in the "caption
\r
7596 area" of the main window, but it uses the dialog height as an hard-coded constant,
\r
7597 and it doesn't work when you resize the dialog.
\r
7598 For now, just give it a default position.
\r
7600 SetWindowPos(hDlg, NULL, boardRect.left+8, boardRect.top+8, 0, 0, SWP_NOZORDER|SWP_NOSIZE);
\r
7602 errorDialog = hDlg;
\r
7603 SetWindowText(hDlg, errorTitle);
\r
7604 hwndText = GetDlgItem(hDlg, OPT_ErrorText);
\r
7605 SetDlgItemText(hDlg, OPT_ErrorText, errorMessage);
\r
7609 switch (LOWORD(wParam)) {
\r
7612 if (errorDialog == hDlg) errorDialog = NULL;
\r
7613 DestroyWindow(hDlg);
\r
7625 HWND gothicDialog = NULL;
\r
7628 GothicDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7632 int height = GetSystemMetrics(SM_CYCAPTION)+GetSystemMetrics(SM_CYFRAME);
\r
7634 switch (message) {
\r
7635 case WM_INITDIALOG:
\r
7636 GetWindowRect(hDlg, &rChild);
\r
7638 SetWindowPos(hDlg, NULL, boardX, boardY-height, winWidth, height,
\r
7642 [AS] It seems that the above code wants to move the dialog up in the "caption
\r
7643 area" of the main window, but it uses the dialog height as an hard-coded constant,
\r
7644 and it doesn't work when you resize the dialog.
\r
7645 For now, just give it a default position.
\r
7647 gothicDialog = hDlg;
\r
7648 SetWindowText(hDlg, errorTitle);
\r
7649 hwndText = GetDlgItem(hDlg, OPT_ErrorText);
\r
7650 SetDlgItemText(hDlg, OPT_ErrorText, errorMessage);
\r
7654 switch (LOWORD(wParam)) {
\r
7657 if (errorDialog == hDlg) errorDialog = NULL;
\r
7658 DestroyWindow(hDlg);
\r
7670 GothicPopUp(char *title, VariantClass variant)
\r
7673 static char *lastTitle;
\r
7675 strncpy(errorTitle, title, sizeof(errorTitle));
\r
7676 errorTitle[sizeof(errorTitle) - 1] = '\0';
\r
7678 if(lastTitle != title && gothicDialog != NULL) {
\r
7679 DestroyWindow(gothicDialog);
\r
7680 gothicDialog = NULL;
\r
7682 if(variant != VariantNormal && gothicDialog == NULL) {
\r
7683 title = lastTitle;
\r
7684 lpProc = MakeProcInstance((FARPROC)GothicDialog, hInst);
\r
7685 CreateDialog(hInst, MAKEINTRESOURCE(DLG_Error),
\r
7686 hwndMain, (DLGPROC)lpProc);
\r
7687 FreeProcInstance(lpProc);
\r
7692 /*---------------------------------------------------------------------------*\
\r
7694 * Ics Interaction console functions
\r
7696 \*---------------------------------------------------------------------------*/
\r
7698 #define HISTORY_SIZE 64
\r
7699 static char *history[HISTORY_SIZE];
\r
7700 int histIn = 0, histP = 0;
\r
7703 SaveInHistory(char *cmd)
\r
7705 if (history[histIn] != NULL) {
\r
7706 free(history[histIn]);
\r
7707 history[histIn] = NULL;
\r
7709 if (*cmd == NULLCHAR) return;
\r
7710 history[histIn] = StrSave(cmd);
\r
7711 histIn = (histIn + 1) % HISTORY_SIZE;
\r
7712 if (history[histIn] != NULL) {
\r
7713 free(history[histIn]);
\r
7714 history[histIn] = NULL;
\r
7720 PrevInHistory(char *cmd)
\r
7723 if (histP == histIn) {
\r
7724 if (history[histIn] != NULL) free(history[histIn]);
\r
7725 history[histIn] = StrSave(cmd);
\r
7727 newhp = (histP - 1 + HISTORY_SIZE) % HISTORY_SIZE;
\r
7728 if (newhp == histIn || history[newhp] == NULL) return NULL;
\r
7730 return history[histP];
\r
7736 if (histP == histIn) return NULL;
\r
7737 histP = (histP + 1) % HISTORY_SIZE;
\r
7738 return history[histP];
\r
7745 BOOLEAN immediate;
\r
7746 } IcsTextMenuEntry;
\r
7747 #define ICS_TEXT_MENU_SIZE (IDM_CommandXLast - IDM_CommandX + 1)
\r
7748 IcsTextMenuEntry icsTextMenuEntry[ICS_TEXT_MENU_SIZE];
\r
7751 ParseIcsTextMenu(char *icsTextMenuString)
\r
7754 IcsTextMenuEntry *e = icsTextMenuEntry;
\r
7755 char *p = icsTextMenuString;
\r
7756 while (e->item != NULL && e < icsTextMenuEntry + ICS_TEXT_MENU_SIZE) {
\r
7759 if (e->command != NULL) {
\r
7761 e->command = NULL;
\r
7765 e = icsTextMenuEntry;
\r
7766 while (*p && e < icsTextMenuEntry + ICS_TEXT_MENU_SIZE) {
\r
7767 if (*p == ';' || *p == '\n') {
\r
7768 e->item = strdup("-");
\r
7769 e->command = NULL;
\r
7771 } else if (*p == '-') {
\r
7772 e->item = strdup("-");
\r
7773 e->command = NULL;
\r
7777 char *q, *r, *s, *t;
\r
7779 q = strchr(p, ',');
\r
7780 if (q == NULL) break;
\r
7782 r = strchr(q + 1, ',');
\r
7783 if (r == NULL) break;
\r
7785 s = strchr(r + 1, ',');
\r
7786 if (s == NULL) break;
\r
7789 t = strchr(s + 1, c);
\r
7792 t = strchr(s + 1, c);
\r
7794 if (t != NULL) *t = NULLCHAR;
\r
7795 e->item = strdup(p);
\r
7796 e->command = strdup(q + 1);
\r
7797 e->getname = *(r + 1) != '0';
\r
7798 e->immediate = *(s + 1) != '0';
\r
7802 if (t == NULL) break;
\r
7811 LoadIcsTextMenu(IcsTextMenuEntry *e)
\r
7815 hmenu = LoadMenu(hInst, "TextMenu");
\r
7816 h = GetSubMenu(hmenu, 0);
\r
7818 if (strcmp(e->item, "-") == 0) {
\r
7819 AppendMenu(h, MF_SEPARATOR, 0, 0);
\r
7821 if (e->item[0] == '|') {
\r
7822 AppendMenu(h, MF_STRING|MF_MENUBARBREAK,
\r
7823 IDM_CommandX + i, &e->item[1]);
\r
7825 AppendMenu(h, MF_STRING, IDM_CommandX + i, e->item);
\r
7834 WNDPROC consoleTextWindowProc;
\r
7837 CommandX(HWND hwnd, char *command, BOOLEAN getname, BOOLEAN immediate)
\r
7839 char buf[MSG_SIZ], name[MSG_SIZ];
\r
7840 HWND hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
7844 SetWindowText(hInput, command);
\r
7846 SendMessage(hInput, WM_CHAR, '\r', 0);
\r
7848 sel.cpMin = 999999;
\r
7849 sel.cpMax = 999999;
\r
7850 SendMessage(hInput, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7855 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
7856 if (sel.cpMin == sel.cpMax) {
\r
7857 /* Expand to surrounding word */
\r
7860 tr.chrg.cpMax = sel.cpMin;
\r
7861 tr.chrg.cpMin = --sel.cpMin;
\r
7862 if (sel.cpMin < 0) break;
\r
7863 tr.lpstrText = name;
\r
7864 SendMessage(hwnd, EM_GETTEXTRANGE, 0, (LPARAM) &tr);
\r
7865 } while (isalpha(name[0]) || isdigit(name[0]) || name[0] == '-');
\r
7869 tr.chrg.cpMin = sel.cpMax;
\r
7870 tr.chrg.cpMax = ++sel.cpMax;
\r
7871 tr.lpstrText = name;
\r
7872 if (SendMessage(hwnd, EM_GETTEXTRANGE, 0, (LPARAM) &tr) < 1) break;
\r
7873 } while (isalpha(name[0]) || isdigit(name[0]) || name[0] == '-');
\r
7876 if (sel.cpMax == sel.cpMin || sel.cpMax - sel.cpMin > MSG_SIZ/2) {
\r
7877 MessageBeep(MB_ICONEXCLAMATION);
\r
7881 tr.lpstrText = name;
\r
7882 SendMessage(hwnd, EM_GETTEXTRANGE, 0, (LPARAM) &tr);
\r
7884 if (sel.cpMax - sel.cpMin > MSG_SIZ/2) {
\r
7885 MessageBeep(MB_ICONEXCLAMATION);
\r
7888 SendMessage(hwnd, EM_GETSELTEXT, 0, (LPARAM) name);
\r
7891 sprintf(buf, "%s %s", command, name);
\r
7892 SetWindowText(hInput, buf);
\r
7893 SendMessage(hInput, WM_CHAR, '\r', 0);
\r
7895 sprintf(buf, "%s %s ", command, name); /* trailing space */
\r
7896 SetWindowText(hInput, buf);
\r
7897 sel.cpMin = 999999;
\r
7898 sel.cpMax = 999999;
\r
7899 SendMessage(hInput, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7905 ConsoleTextSubclass(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
7910 switch (message) {
\r
7912 if (!(GetKeyState(VK_CONTROL) & ~1)) break;
\r
7915 SendMessage(hwnd, EM_LINESCROLL, 0, -999999);
\r
7918 sel.cpMin = 999999;
\r
7919 sel.cpMax = 999999;
\r
7920 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7921 SendMessage(hwnd, EM_SCROLLCARET, 0, 0);
\r
7926 if(wParam != '\022') {
\r
7927 if (wParam == '\t') {
\r
7928 if (GetKeyState(VK_SHIFT) < 0) {
\r
7930 if (IsIconic(hwndMain)) ShowWindow(hwndMain, SW_RESTORE);
\r
7931 if (buttonDesc[0].hwnd) {
\r
7932 SetFocus(buttonDesc[0].hwnd);
\r
7934 SetFocus(hwndMain);
\r
7938 SetFocus(GetDlgItem(hwndConsole, OPT_ConsoleInput));
\r
7941 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
7942 JAWS_DELETE( SetFocus(hInput); )
\r
7943 SendMessage(hInput, message, wParam, lParam);
\r
7946 } // [HGM] navigate: for Ctrl+R, flow into nex case (moved up here) to summon up menu
\r
7947 case WM_RBUTTONUP:
\r
7948 if (GetKeyState(VK_SHIFT) & ~1) {
\r
7949 SendDlgItemMessage(hwndConsole, OPT_ConsoleText,
\r
7950 WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
7953 HMENU hmenu = LoadIcsTextMenu(icsTextMenuEntry);
\r
7954 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
7955 if (sel.cpMin == sel.cpMax) {
\r
7956 EnableMenuItem(hmenu, IDM_Copy, MF_BYCOMMAND|MF_GRAYED);
\r
7957 EnableMenuItem(hmenu, IDM_QuickPaste, MF_BYCOMMAND|MF_GRAYED);
\r
7959 if (!IsClipboardFormatAvailable(CF_TEXT)) {
\r
7960 EnableMenuItem(hmenu, IDM_Paste, MF_BYCOMMAND|MF_GRAYED);
\r
7962 pt.x = LOWORD(lParam);
\r
7963 pt.y = HIWORD(lParam);
\r
7964 MenuPopup(hwnd, pt, hmenu, -1);
\r
7968 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
7970 return SendMessage(hInput, message, wParam, lParam);
\r
7971 case WM_MBUTTONDOWN:
\r
7972 return SendMessage(hwnd, WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
7973 case WM_RBUTTONDOWN:
\r
7974 if (!(GetKeyState(VK_SHIFT) & ~1)) {
\r
7975 /* Move selection here if it was empty */
\r
7977 pt.x = LOWORD(lParam);
\r
7978 pt.y = HIWORD(lParam);
\r
7979 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
7980 if (sel.cpMin == sel.cpMax) {
\r
7981 sel.cpMin = SendMessage(hwnd, EM_CHARFROMPOS, 0, (LPARAM)&pt); /*doc is wrong*/
\r
7982 sel.cpMax = sel.cpMin;
\r
7983 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7985 SendMessage(hwnd, EM_HIDESELECTION, FALSE, FALSE);
\r
7989 switch (LOWORD(wParam)) {
\r
7990 case IDM_QuickPaste:
\r
7992 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
7993 if (sel.cpMin == sel.cpMax) {
\r
7994 MessageBeep(MB_ICONEXCLAMATION);
\r
7997 SendMessage(hwnd, WM_COPY, 0, 0);
\r
7998 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
7999 SendMessage(hInput, WM_PASTE, 0, 0);
\r
8004 SendMessage(hwnd, WM_CUT, 0, 0);
\r
8007 SendMessage(hwnd, WM_PASTE, 0, 0);
\r
8010 SendMessage(hwnd, WM_COPY, 0, 0);
\r
8014 int i = LOWORD(wParam) - IDM_CommandX;
\r
8015 if (i >= 0 && i < ICS_TEXT_MENU_SIZE &&
\r
8016 icsTextMenuEntry[i].command != NULL) {
\r
8017 CommandX(hwnd, icsTextMenuEntry[i].command,
\r
8018 icsTextMenuEntry[i].getname,
\r
8019 icsTextMenuEntry[i].immediate);
\r
8027 return (*consoleTextWindowProc)(hwnd, message, wParam, lParam);
\r
8030 WNDPROC consoleInputWindowProc;
\r
8033 ConsoleInputSubclass(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
8035 char buf[MSG_SIZ];
\r
8037 static BOOL sendNextChar = FALSE;
\r
8038 static BOOL quoteNextChar = FALSE;
\r
8039 InputSource *is = consoleInputSource;
\r
8043 switch (message) {
\r
8045 if (!appData.localLineEditing || sendNextChar) {
\r
8046 is->buf[0] = (CHAR) wParam;
\r
8048 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
8049 sendNextChar = FALSE;
\r
8052 if (quoteNextChar) {
\r
8053 buf[0] = (char) wParam;
\r
8054 buf[1] = NULLCHAR;
\r
8055 SendMessage(hwnd, EM_REPLACESEL, TRUE, (LPARAM) buf);
\r
8056 quoteNextChar = FALSE;
\r
8060 case '\r': /* Enter key */
\r
8061 is->count = GetWindowText(hwnd, is->buf, INPUT_SOURCE_BUF_SIZE-1);
\r
8062 if (consoleEcho) SaveInHistory(is->buf);
\r
8063 is->buf[is->count++] = '\n';
\r
8064 is->buf[is->count] = NULLCHAR;
\r
8065 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
8066 if (consoleEcho) {
\r
8067 ConsoleOutput(is->buf, is->count, TRUE);
\r
8068 } else if (appData.localLineEditing) {
\r
8069 ConsoleOutput("\n", 1, TRUE);
\r
8072 case '\033': /* Escape key */
\r
8073 SetWindowText(hwnd, "");
\r
8074 cf.cbSize = sizeof(CHARFORMAT);
\r
8075 cf.dwMask = CFM_COLOR|CFM_BOLD|CFM_ITALIC|CFM_UNDERLINE|CFM_STRIKEOUT;
\r
8076 if (consoleEcho) {
\r
8077 cf.crTextColor = textAttribs[ColorNormal].color;
\r
8079 cf.crTextColor = COLOR_ECHOOFF;
\r
8081 cf.dwEffects = textAttribs[ColorNormal].effects;
\r
8082 SendMessage(hwnd, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&cf);
\r
8084 case '\t': /* Tab key */
\r
8085 if (GetKeyState(VK_SHIFT) < 0) {
\r
8087 SetFocus(GetDlgItem(hwndConsole, OPT_ConsoleText));
\r
8090 if (IsIconic(hwndMain)) ShowWindow(hwndMain, SW_RESTORE);
\r
8091 if (buttonDesc[0].hwnd) {
\r
8092 SetFocus(buttonDesc[0].hwnd);
\r
8094 SetFocus(hwndMain);
\r
8098 case '\023': /* Ctrl+S */
\r
8099 sendNextChar = TRUE;
\r
8101 case '\021': /* Ctrl+Q */
\r
8102 quoteNextChar = TRUE;
\r
8112 GetWindowText(hwnd, buf, MSG_SIZ);
\r
8113 p = PrevInHistory(buf);
\r
8115 SetWindowText(hwnd, p);
\r
8116 sel.cpMin = 999999;
\r
8117 sel.cpMax = 999999;
\r
8118 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
8123 p = NextInHistory();
\r
8125 SetWindowText(hwnd, p);
\r
8126 sel.cpMin = 999999;
\r
8127 sel.cpMax = 999999;
\r
8128 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
8134 if (!(GetKeyState(VK_CONTROL) & ~1)) break;
\r
8138 SendDlgItemMessage(hwndConsole, OPT_ConsoleText, message, wParam, lParam);
\r
8142 case WM_MBUTTONDOWN:
\r
8143 SendDlgItemMessage(hwndConsole, OPT_ConsoleText,
\r
8144 WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
8146 case WM_RBUTTONUP:
\r
8147 if (GetKeyState(VK_SHIFT) & ~1) {
\r
8148 SendDlgItemMessage(hwndConsole, OPT_ConsoleText,
\r
8149 WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
8153 hmenu = LoadMenu(hInst, "InputMenu");
\r
8154 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
8155 if (sel.cpMin == sel.cpMax) {
\r
8156 EnableMenuItem(hmenu, IDM_Copy, MF_BYCOMMAND|MF_GRAYED);
\r
8157 EnableMenuItem(hmenu, IDM_Cut, MF_BYCOMMAND|MF_GRAYED);
\r
8159 if (!IsClipboardFormatAvailable(CF_TEXT)) {
\r
8160 EnableMenuItem(hmenu, IDM_Paste, MF_BYCOMMAND|MF_GRAYED);
\r
8162 pt.x = LOWORD(lParam);
\r
8163 pt.y = HIWORD(lParam);
\r
8164 MenuPopup(hwnd, pt, hmenu, -1);
\r
8168 switch (LOWORD(wParam)) {
\r
8170 SendMessage(hwnd, EM_UNDO, 0, 0);
\r
8172 case IDM_SelectAll:
\r
8174 sel.cpMax = -1; /*999999?*/
\r
8175 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
8178 SendMessage(hwnd, WM_CUT, 0, 0);
\r
8181 SendMessage(hwnd, WM_PASTE, 0, 0);
\r
8184 SendMessage(hwnd, WM_COPY, 0, 0);
\r
8189 return (*consoleInputWindowProc)(hwnd, message, wParam, lParam);
\r
8192 #define CO_MAX 100000
\r
8193 #define CO_TRIM 1000
\r
8196 ConsoleWndProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
8198 static SnapData sd;
\r
8199 static HWND hText, hInput /*, hFocus*/;
\r
8200 // InputSource *is = consoleInputSource;
\r
8202 static int sizeX, sizeY;
\r
8203 int newSizeX, newSizeY;
\r
8206 switch (message) {
\r
8207 case WM_INITDIALOG: /* message: initialize dialog box */
\r
8208 hwndConsole = hDlg;
\r
8209 hText = GetDlgItem(hDlg, OPT_ConsoleText);
\r
8210 hInput = GetDlgItem(hDlg, OPT_ConsoleInput);
\r
8212 consoleTextWindowProc = (WNDPROC)
\r
8213 SetWindowLong(hText, GWL_WNDPROC, (LONG) ConsoleTextSubclass);
\r
8214 SendMessage(hText, EM_SETBKGNDCOLOR, FALSE, consoleBackgroundColor);
\r
8215 consoleInputWindowProc = (WNDPROC)
\r
8216 SetWindowLong(hInput, GWL_WNDPROC, (LONG) ConsoleInputSubclass);
\r
8217 SendMessage(hInput, EM_SETBKGNDCOLOR, FALSE, consoleBackgroundColor);
\r
8218 Colorize(ColorNormal, TRUE);
\r
8219 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM) &consoleCF);
\r
8220 ChangedConsoleFont();
\r
8221 GetClientRect(hDlg, &rect);
\r
8222 sizeX = rect.right;
\r
8223 sizeY = rect.bottom;
\r
8224 if (wpConsole.x != CW_USEDEFAULT && wpConsole.y != CW_USEDEFAULT &&
\r
8225 wpConsole.width != CW_USEDEFAULT && wpConsole.height != CW_USEDEFAULT) {
\r
8226 WINDOWPLACEMENT wp;
\r
8227 EnsureOnScreen(&wpConsole.x, &wpConsole.y, 0, 0);
\r
8228 wp.length = sizeof(WINDOWPLACEMENT);
\r
8230 wp.showCmd = SW_SHOW;
\r
8231 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
8232 wp.rcNormalPosition.left = wpConsole.x;
\r
8233 wp.rcNormalPosition.right = wpConsole.x + wpConsole.width;
\r
8234 wp.rcNormalPosition.top = wpConsole.y;
\r
8235 wp.rcNormalPosition.bottom = wpConsole.y + wpConsole.height;
\r
8236 SetWindowPlacement(hDlg, &wp);
\r
8239 // [HGM] Chessknight's change 2004-07-13
\r
8240 else { /* Determine Defaults */
\r
8241 WINDOWPLACEMENT wp;
\r
8242 wpConsole.x = winWidth + 1;
\r
8243 wpConsole.y = boardY;
\r
8244 wpConsole.width = screenWidth - winWidth;
\r
8245 wpConsole.height = winHeight;
\r
8246 EnsureOnScreen(&wpConsole.x, &wpConsole.y, 0, 0);
\r
8247 wp.length = sizeof(WINDOWPLACEMENT);
\r
8249 wp.showCmd = SW_SHOW;
\r
8250 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
8251 wp.rcNormalPosition.left = wpConsole.x;
\r
8252 wp.rcNormalPosition.right = wpConsole.x + wpConsole.width;
\r
8253 wp.rcNormalPosition.top = wpConsole.y;
\r
8254 wp.rcNormalPosition.bottom = wpConsole.y + wpConsole.height;
\r
8255 SetWindowPlacement(hDlg, &wp);
\r
8270 if (IsIconic(hDlg)) break;
\r
8271 newSizeX = LOWORD(lParam);
\r
8272 newSizeY = HIWORD(lParam);
\r
8273 if (sizeX != newSizeX || sizeY != newSizeY) {
\r
8274 RECT rectText, rectInput;
\r
8276 int newTextHeight, newTextWidth;
\r
8277 GetWindowRect(hText, &rectText);
\r
8278 newTextWidth = rectText.right - rectText.left + newSizeX - sizeX;
\r
8279 newTextHeight = rectText.bottom - rectText.top + newSizeY - sizeY;
\r
8280 if (newTextHeight < 0) {
\r
8281 newSizeY += -newTextHeight;
\r
8282 newTextHeight = 0;
\r
8284 SetWindowPos(hText, NULL, 0, 0,
\r
8285 newTextWidth, newTextHeight, SWP_NOZORDER|SWP_NOMOVE);
\r
8286 GetWindowRect(hInput, &rectInput); /* gives screen coords */
\r
8287 pt.x = rectInput.left;
\r
8288 pt.y = rectInput.top + newSizeY - sizeY;
\r
8289 ScreenToClient(hDlg, &pt);
\r
8290 SetWindowPos(hInput, NULL,
\r
8291 pt.x, pt.y, /* needs client coords */
\r
8292 rectInput.right - rectInput.left + newSizeX - sizeX,
\r
8293 rectInput.bottom - rectInput.top, SWP_NOZORDER);
\r
8299 case WM_GETMINMAXINFO:
\r
8300 /* Prevent resizing window too small */
\r
8301 mmi = (MINMAXINFO *) lParam;
\r
8302 mmi->ptMinTrackSize.x = 100;
\r
8303 mmi->ptMinTrackSize.y = 100;
\r
8306 /* [AS] Snapping */
\r
8307 case WM_ENTERSIZEMOVE:
\r
8308 return OnEnterSizeMove( &sd, hDlg, wParam, lParam );
\r
8311 return OnSizing( &sd, hDlg, wParam, lParam );
\r
8314 return OnMoving( &sd, hDlg, wParam, lParam );
\r
8316 case WM_EXITSIZEMOVE:
\r
8317 return OnExitSizeMove( &sd, hDlg, wParam, lParam );
\r
8320 return DefWindowProc(hDlg, message, wParam, lParam);
\r
8328 if (hwndConsole) return;
\r
8329 hCons = CreateDialog(hInst, szConsoleName, 0, NULL);
\r
8330 SendMessage(hCons, WM_INITDIALOG, 0, 0);
\r
8335 ConsoleOutput(char* data, int length, int forceVisible)
\r
8340 char buf[CO_MAX+1];
\r
8343 static int delayLF = 0;
\r
8344 CHARRANGE savesel, sel;
\r
8346 if (hwndConsole == NULL || length > CO_MAX-100 || length == 0) return;
\r
8354 while (length--) {
\r
8362 } else if (*p == '\007') {
\r
8363 MyPlaySound(&sounds[(int)SoundBell]);
\r
8370 hText = GetDlgItem(hwndConsole, OPT_ConsoleText);
\r
8371 SendMessage(hText, EM_HIDESELECTION, TRUE, FALSE);
\r
8372 /* Save current selection */
\r
8373 SendMessage(hText, EM_EXGETSEL, 0, (LPARAM)&savesel);
\r
8374 exlen = GetWindowTextLength(hText);
\r
8375 /* Find out whether current end of text is visible */
\r
8376 SendMessage(hText, EM_GETRECT, 0, (LPARAM) &rect);
\r
8377 SendMessage(hText, EM_POSFROMCHAR, (WPARAM) &pEnd, exlen);
\r
8378 /* Trim existing text if it's too long */
\r
8379 if (exlen + (q - buf) > CO_MAX) {
\r
8380 trim = (CO_TRIM > (q - buf)) ? CO_TRIM : (q - buf);
\r
8383 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
8384 SendMessage(hText, EM_REPLACESEL, 0, (LPARAM)"");
\r
8386 savesel.cpMin -= trim;
\r
8387 savesel.cpMax -= trim;
\r
8388 if (exlen < 0) exlen = 0;
\r
8389 if (savesel.cpMin < 0) savesel.cpMin = 0;
\r
8390 if (savesel.cpMax < savesel.cpMin) savesel.cpMax = savesel.cpMin;
\r
8392 /* Append the new text */
\r
8393 sel.cpMin = exlen;
\r
8394 sel.cpMax = exlen;
\r
8395 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
8396 SendMessage(hText, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&consoleCF);
\r
8397 SendMessage(hText, EM_REPLACESEL, 0, (LPARAM) buf);
\r
8398 if (forceVisible || exlen == 0 ||
\r
8399 (rect.left <= pEnd.x && pEnd.x < rect.right &&
\r
8400 rect.top <= pEnd.y && pEnd.y < rect.bottom)) {
\r
8401 /* Scroll to make new end of text visible if old end of text
\r
8402 was visible or new text is an echo of user typein */
\r
8403 sel.cpMin = 9999999;
\r
8404 sel.cpMax = 9999999;
\r
8405 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
8406 SendMessage(hText, EM_HIDESELECTION, FALSE, FALSE);
\r
8407 SendMessage(hText, EM_SCROLLCARET, 0, 0);
\r
8408 SendMessage(hText, EM_HIDESELECTION, TRUE, FALSE);
\r
8410 if (savesel.cpMax == exlen || forceVisible) {
\r
8411 /* Move insert point to new end of text if it was at the old
\r
8412 end of text or if the new text is an echo of user typein */
\r
8413 sel.cpMin = 9999999;
\r
8414 sel.cpMax = 9999999;
\r
8415 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
8417 /* Restore previous selection */
\r
8418 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&savesel);
\r
8420 SendMessage(hText, EM_HIDESELECTION, FALSE, FALSE);
\r
8427 DisplayHoldingsCount(HDC hdc, int x, int y, int rightAlign, int copyNumber)
\r
8431 COLORREF oldFg, oldBg;
\r
8435 if(copyNumber > 1) sprintf(buf, "%d", copyNumber); else buf[0] = 0;
\r
8437 oldFg = SetTextColor(hdc, RGB(255, 255, 255)); /* white */
\r
8438 oldBg = SetBkColor(hdc, RGB(0, 0, 0)); /* black */
\r
8439 oldFont = SelectObject(hdc, font[boardSize][CLOCK_FONT]->hf);
\r
8442 rect.right = x + squareSize;
\r
8444 rect.bottom = y + squareSize;
\r
8447 ExtTextOut(hdc, x + MESSAGE_LINE_LEFTMARGIN
\r
8448 + (rightAlign ? (squareSize*2)/3 : 0),
\r
8449 y, ETO_CLIPPED|ETO_OPAQUE,
\r
8450 &rect, str, strlen(str), NULL);
\r
8452 (void) SetTextColor(hdc, oldFg);
\r
8453 (void) SetBkColor(hdc, oldBg);
\r
8454 (void) SelectObject(hdc, oldFont);
\r
8458 DisplayAClock(HDC hdc, int timeRemaining, int highlight,
\r
8459 RECT *rect, char *color, char *flagFell)
\r
8463 COLORREF oldFg, oldBg;
\r
8466 if (appData.clockMode) {
\r
8468 sprintf(buf, "%c %s %s", color[0], TimeString(timeRemaining), flagFell);
\r
8470 sprintf(buf, "%s:%c%s %s", color, (logoHeight>0 ? 0 : ' '), TimeString(timeRemaining), flagFell);
\r
8477 oldFg = SetTextColor(hdc, RGB(255, 255, 255)); /* white */
\r
8478 oldBg = SetBkColor(hdc, RGB(0, 0, 0)); /* black */
\r
8480 oldFg = SetTextColor(hdc, RGB(0, 0, 0)); /* black */
\r
8481 oldBg = SetBkColor(hdc, RGB(255, 255, 255)); /* white */
\r
8483 oldFont = SelectObject(hdc, font[boardSize][CLOCK_FONT]->hf);
\r
8487 ExtTextOut(hdc, rect->left + MESSAGE_LINE_LEFTMARGIN,
\r
8488 rect->top, ETO_CLIPPED|ETO_OPAQUE,
\r
8489 rect, str, strlen(str), NULL);
\r
8490 if(logoHeight > 0 && appData.clockMode) {
\r
8492 sprintf(buf, "%s %s", buf+7, flagFell);
\r
8493 r.top = rect->top + logoHeight/2;
\r
8494 r.left = rect->left;
\r
8495 r.right = rect->right;
\r
8496 r.bottom = rect->bottom;
\r
8497 ExtTextOut(hdc, rect->left + MESSAGE_LINE_LEFTMARGIN,
\r
8498 r.top, ETO_CLIPPED|ETO_OPAQUE,
\r
8499 &r, str, strlen(str), NULL);
\r
8501 (void) SetTextColor(hdc, oldFg);
\r
8502 (void) SetBkColor(hdc, oldBg);
\r
8503 (void) SelectObject(hdc, oldFont);
\r
8508 DoReadFile(HANDLE hFile, char *buf, int count, DWORD *outCount,
\r
8514 if( count <= 0 ) {
\r
8515 if (appData.debugMode) {
\r
8516 fprintf( debugFP, "DoReadFile: trying to read past end of buffer, overflow = %d\n", count );
\r
8519 return ERROR_INVALID_USER_BUFFER;
\r
8522 ResetEvent(ovl->hEvent);
\r
8523 ovl->Offset = ovl->OffsetHigh = 0;
\r
8524 ok = ReadFile(hFile, buf, count, outCount, ovl);
\r
8528 err = GetLastError();
\r
8529 if (err == ERROR_IO_PENDING) {
\r
8530 ok = GetOverlappedResult(hFile, ovl, outCount, TRUE);
\r
8534 err = GetLastError();
\r
8541 DoWriteFile(HANDLE hFile, char *buf, int count, DWORD *outCount,
\r
8546 ResetEvent(ovl->hEvent);
\r
8547 ovl->Offset = ovl->OffsetHigh = 0;
\r
8548 ok = WriteFile(hFile, buf, count, outCount, ovl);
\r
8552 err = GetLastError();
\r
8553 if (err == ERROR_IO_PENDING) {
\r
8554 ok = GetOverlappedResult(hFile, ovl, outCount, TRUE);
\r
8558 err = GetLastError();
\r
8564 /* [AS] If input is line by line and a line exceed the buffer size, force an error */
\r
8565 void CheckForInputBufferFull( InputSource * is )
\r
8567 if( is->lineByLine && (is->next - is->buf) >= INPUT_SOURCE_BUF_SIZE ) {
\r
8568 /* Look for end of line */
\r
8569 char * p = is->buf;
\r
8571 while( p < is->next && *p != '\n' ) {
\r
8575 if( p >= is->next ) {
\r
8576 if (appData.debugMode) {
\r
8577 fprintf( debugFP, "Input line exceeded buffer size (source id=%lu)\n", is->id );
\r
8580 is->error = ERROR_BROKEN_PIPE; /* [AS] Just any non-successful code! */
\r
8581 is->count = (DWORD) -1;
\r
8582 is->next = is->buf;
\r
8588 InputThread(LPVOID arg)
\r
8593 is = (InputSource *) arg;
\r
8594 ovl.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
\r
8595 ovl.Internal = ovl.InternalHigh = ovl.Offset = ovl.OffsetHigh = 0;
\r
8596 while (is->hThread != NULL) {
\r
8597 is->error = DoReadFile(is->hFile, is->next,
\r
8598 INPUT_SOURCE_BUF_SIZE - (is->next - is->buf),
\r
8599 &is->count, &ovl);
\r
8600 if (is->error == NO_ERROR) {
\r
8601 is->next += is->count;
\r
8603 if (is->error == ERROR_BROKEN_PIPE) {
\r
8604 /* Correct for MS brain damage. EOF reading a pipe is not an error. */
\r
8607 is->count = (DWORD) -1;
\r
8608 /* [AS] The (is->count <= 0) check below is not useful for unsigned values! */
\r
8613 CheckForInputBufferFull( is );
\r
8615 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
8617 if( is->count == ((DWORD) -1) ) break; /* [AS] */
\r
8619 if (is->count <= 0) break; /* Quit on EOF or error */
\r
8622 CloseHandle(ovl.hEvent);
\r
8623 CloseHandle(is->hFile);
\r
8625 if (appData.debugMode) {
\r
8626 fprintf( debugFP, "Input thread terminated (id=%lu, error=%d, count=%ld)\n", is->id, is->error, is->count );
\r
8633 /* Windows 95 beta 2 won't let you do overlapped i/o on a console or pipe */
\r
8635 NonOvlInputThread(LPVOID arg)
\r
8642 is = (InputSource *) arg;
\r
8643 while (is->hThread != NULL) {
\r
8644 is->error = ReadFile(is->hFile, is->next,
\r
8645 INPUT_SOURCE_BUF_SIZE - (is->next - is->buf),
\r
8646 &is->count, NULL) ? NO_ERROR : GetLastError();
\r
8647 if (is->error == NO_ERROR) {
\r
8648 /* Change CRLF to LF */
\r
8649 if (is->next > is->buf) {
\r
8651 i = is->count + 1;
\r
8659 if (prev == '\r' && *p == '\n') {
\r
8671 if (is->error == ERROR_BROKEN_PIPE) {
\r
8672 /* Correct for MS brain damage. EOF reading a pipe is not an error. */
\r
8675 is->count = (DWORD) -1;
\r
8679 CheckForInputBufferFull( is );
\r
8681 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
8683 if( is->count == ((DWORD) -1) ) break; /* [AS] */
\r
8685 if (is->count < 0) break; /* Quit on error */
\r
8687 CloseHandle(is->hFile);
\r
8692 SocketInputThread(LPVOID arg)
\r
8696 is = (InputSource *) arg;
\r
8697 while (is->hThread != NULL) {
\r
8698 is->count = recv(is->sock, is->buf, INPUT_SOURCE_BUF_SIZE, 0);
\r
8699 if ((int)is->count == SOCKET_ERROR) {
\r
8700 is->count = (DWORD) -1;
\r
8701 is->error = WSAGetLastError();
\r
8703 is->error = NO_ERROR;
\r
8704 is->next += is->count;
\r
8705 if (is->count == 0 && is->second == is) {
\r
8706 /* End of file on stderr; quit with no message */
\r
8710 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
8712 if( is->count == ((DWORD) -1) ) break; /* [AS] */
\r
8714 if (is->count <= 0) break; /* Quit on EOF or error */
\r
8720 InputEvent(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
8724 is = (InputSource *) lParam;
\r
8725 if (is->lineByLine) {
\r
8726 /* Feed in lines one by one */
\r
8727 char *p = is->buf;
\r
8729 while (q < is->next) {
\r
8730 if (*q++ == '\n') {
\r
8731 (is->func)(is, is->closure, p, q - p, NO_ERROR);
\r
8736 /* Move any partial line to the start of the buffer */
\r
8738 while (p < is->next) {
\r
8743 if (is->error != NO_ERROR || is->count == 0) {
\r
8744 /* Notify backend of the error. Note: If there was a partial
\r
8745 line at the end, it is not flushed through. */
\r
8746 (is->func)(is, is->closure, is->buf, is->count, is->error);
\r
8749 /* Feed in the whole chunk of input at once */
\r
8750 (is->func)(is, is->closure, is->buf, is->count, is->error);
\r
8751 is->next = is->buf;
\r
8755 /*---------------------------------------------------------------------------*\
\r
8757 * Menu enables. Used when setting various modes.
\r
8759 \*---------------------------------------------------------------------------*/
\r
8767 SetMenuEnables(HMENU hmenu, Enables *enab)
\r
8769 while (enab->item > 0) {
\r
8770 (void) EnableMenuItem(hmenu, enab->item, enab->flags);
\r
8775 Enables gnuEnables[] = {
\r
8776 { IDM_MailMove, MF_BYCOMMAND|MF_GRAYED },
\r
8777 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_GRAYED },
\r
8778 { IDM_IcsClient, MF_BYCOMMAND|MF_GRAYED },
\r
8779 { IDM_Accept, MF_BYCOMMAND|MF_GRAYED },
\r
8780 { IDM_Decline, MF_BYCOMMAND|MF_GRAYED },
\r
8781 { IDM_Rematch, MF_BYCOMMAND|MF_GRAYED },
\r
8782 { IDM_Adjourn, MF_BYCOMMAND|MF_GRAYED },
\r
8783 { IDM_StopExamining, MF_BYCOMMAND|MF_GRAYED },
\r
8784 { IDM_StopObserving, MF_BYCOMMAND|MF_GRAYED },
\r
8785 { IDM_Revert, MF_BYCOMMAND|MF_GRAYED },
\r
8789 Enables icsEnables[] = {
\r
8790 { IDM_MailMove, MF_BYCOMMAND|MF_GRAYED },
\r
8791 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_GRAYED },
\r
8792 { IDM_MachineWhite, MF_BYCOMMAND|MF_GRAYED },
\r
8793 { IDM_MachineBlack, MF_BYCOMMAND|MF_GRAYED },
\r
8794 { IDM_TwoMachines, MF_BYCOMMAND|MF_GRAYED },
\r
8795 { IDM_AnalysisMode, MF_BYCOMMAND|MF_ENABLED },
\r
8796 { IDM_AnalyzeFile, MF_BYCOMMAND|MF_GRAYED },
\r
8797 { IDM_TimeControl, MF_BYCOMMAND|MF_GRAYED },
\r
8798 { IDM_MoveNow, MF_BYCOMMAND|MF_GRAYED },
\r
8799 { IDM_Hint, MF_BYCOMMAND|MF_GRAYED },
\r
8800 { IDM_Book, MF_BYCOMMAND|MF_GRAYED },
\r
8801 { IDM_IcsOptions, MF_BYCOMMAND|MF_ENABLED },
\r
8806 Enables zippyEnables[] = {
\r
8807 { IDM_MoveNow, MF_BYCOMMAND|MF_ENABLED },
\r
8808 { IDM_Hint, MF_BYCOMMAND|MF_ENABLED },
\r
8809 { IDM_Book, MF_BYCOMMAND|MF_ENABLED },
\r
8814 Enables ncpEnables[] = {
\r
8815 { IDM_MailMove, MF_BYCOMMAND|MF_GRAYED },
\r
8816 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_GRAYED },
\r
8817 { IDM_MachineWhite, MF_BYCOMMAND|MF_GRAYED },
\r
8818 { IDM_MachineBlack, MF_BYCOMMAND|MF_GRAYED },
\r
8819 { IDM_TwoMachines, MF_BYCOMMAND|MF_GRAYED },
\r
8820 { IDM_AnalysisMode, MF_BYCOMMAND|MF_GRAYED },
\r
8821 { IDM_AnalyzeFile, MF_BYCOMMAND|MF_GRAYED },
\r
8822 { IDM_IcsClient, MF_BYCOMMAND|MF_GRAYED },
\r
8823 { ACTION_POS, MF_BYPOSITION|MF_GRAYED },
\r
8824 { IDM_Revert, MF_BYCOMMAND|MF_GRAYED },
\r
8825 { IDM_MoveNow, MF_BYCOMMAND|MF_GRAYED },
\r
8826 { IDM_RetractMove, MF_BYCOMMAND|MF_GRAYED },
\r
8827 { IDM_TimeControl, MF_BYCOMMAND|MF_GRAYED },
\r
8828 { IDM_Hint, MF_BYCOMMAND|MF_GRAYED },
\r
8829 { IDM_Book, MF_BYCOMMAND|MF_GRAYED },
\r
8833 Enables trainingOnEnables[] = {
\r
8834 { IDM_EditComment, MF_BYCOMMAND|MF_GRAYED },
\r
8835 { IDM_Pause, MF_BYCOMMAND|MF_GRAYED },
\r
8836 { IDM_Forward, MF_BYCOMMAND|MF_GRAYED },
\r
8837 { IDM_Backward, MF_BYCOMMAND|MF_GRAYED },
\r
8838 { IDM_ToEnd, MF_BYCOMMAND|MF_GRAYED },
\r
8839 { IDM_ToStart, MF_BYCOMMAND|MF_GRAYED },
\r
8840 { IDM_MoveNow, MF_BYCOMMAND|MF_GRAYED },
\r
8841 { IDM_TruncateGame, MF_BYCOMMAND|MF_GRAYED },
\r
8845 Enables trainingOffEnables[] = {
\r
8846 { IDM_EditComment, MF_BYCOMMAND|MF_ENABLED },
\r
8847 { IDM_Pause, MF_BYCOMMAND|MF_ENABLED },
\r
8848 { IDM_Forward, MF_BYCOMMAND|MF_ENABLED },
\r
8849 { IDM_Backward, MF_BYCOMMAND|MF_ENABLED },
\r
8850 { IDM_ToEnd, MF_BYCOMMAND|MF_ENABLED },
\r
8851 { IDM_ToStart, MF_BYCOMMAND|MF_ENABLED },
\r
8852 { IDM_MoveNow, MF_BYCOMMAND|MF_ENABLED },
\r
8853 { IDM_TruncateGame, MF_BYCOMMAND|MF_ENABLED },
\r
8857 /* These modify either ncpEnables or gnuEnables */
\r
8858 Enables cmailEnables[] = {
\r
8859 { IDM_MailMove, MF_BYCOMMAND|MF_ENABLED },
\r
8860 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_ENABLED },
\r
8861 { ACTION_POS, MF_BYPOSITION|MF_ENABLED },
\r
8862 { IDM_CallFlag, MF_BYCOMMAND|MF_GRAYED },
\r
8863 { IDM_Draw, MF_BYCOMMAND|MF_ENABLED },
\r
8864 { IDM_Adjourn, MF_BYCOMMAND|MF_GRAYED },
\r
8865 { IDM_Abort, MF_BYCOMMAND|MF_GRAYED },
\r
8869 Enables machineThinkingEnables[] = {
\r
8870 { IDM_LoadGame, MF_BYCOMMAND|MF_GRAYED },
\r
8871 { IDM_LoadNextGame, MF_BYCOMMAND|MF_GRAYED },
\r
8872 { IDM_LoadPrevGame, MF_BYCOMMAND|MF_GRAYED },
\r
8873 { IDM_ReloadGame, MF_BYCOMMAND|MF_GRAYED },
\r
8874 { IDM_PasteGame, MF_BYCOMMAND|MF_GRAYED },
\r
8875 { IDM_LoadPosition, MF_BYCOMMAND|MF_GRAYED },
\r
8876 { IDM_LoadNextPosition, MF_BYCOMMAND|MF_GRAYED },
\r
8877 { IDM_LoadPrevPosition, MF_BYCOMMAND|MF_GRAYED },
\r
8878 { IDM_ReloadPosition, MF_BYCOMMAND|MF_GRAYED },
\r
8879 { IDM_PastePosition, MF_BYCOMMAND|MF_GRAYED },
\r
8880 { IDM_MachineWhite, MF_BYCOMMAND|MF_GRAYED },
\r
8881 { IDM_MachineBlack, MF_BYCOMMAND|MF_GRAYED },
\r
8882 { IDM_TwoMachines, MF_BYCOMMAND|MF_GRAYED },
\r
8883 { IDM_TypeInMove, MF_BYCOMMAND|MF_GRAYED },
\r
8884 { IDM_RetractMove, MF_BYCOMMAND|MF_GRAYED },
\r
8888 Enables userThinkingEnables[] = {
\r
8889 { IDM_LoadGame, MF_BYCOMMAND|MF_ENABLED },
\r
8890 { IDM_LoadNextGame, MF_BYCOMMAND|MF_ENABLED },
\r
8891 { IDM_LoadPrevGame, MF_BYCOMMAND|MF_ENABLED },
\r
8892 { IDM_ReloadGame, MF_BYCOMMAND|MF_ENABLED },
\r
8893 { IDM_PasteGame, MF_BYCOMMAND|MF_ENABLED },
\r
8894 { IDM_LoadPosition, MF_BYCOMMAND|MF_ENABLED },
\r
8895 { IDM_LoadNextPosition, MF_BYCOMMAND|MF_ENABLED },
\r
8896 { IDM_LoadPrevPosition, MF_BYCOMMAND|MF_ENABLED },
\r
8897 { IDM_ReloadPosition, MF_BYCOMMAND|MF_ENABLED },
\r
8898 { IDM_PastePosition, MF_BYCOMMAND|MF_ENABLED },
\r
8899 { IDM_MachineWhite, MF_BYCOMMAND|MF_ENABLED },
\r
8900 { IDM_MachineBlack, MF_BYCOMMAND|MF_ENABLED },
\r
8901 { IDM_TwoMachines, MF_BYCOMMAND|MF_ENABLED },
\r
8902 { IDM_TypeInMove, MF_BYCOMMAND|MF_ENABLED },
\r
8903 { IDM_RetractMove, MF_BYCOMMAND|MF_ENABLED },
\r
8907 /*---------------------------------------------------------------------------*\
\r
8909 * Front-end interface functions exported by XBoard.
\r
8910 * Functions appear in same order as prototypes in frontend.h.
\r
8912 \*---------------------------------------------------------------------------*/
\r
8916 static UINT prevChecked = 0;
\r
8917 static int prevPausing = 0;
\r
8920 if (pausing != prevPausing) {
\r
8921 prevPausing = pausing;
\r
8922 (void) CheckMenuItem(GetMenu(hwndMain), IDM_Pause,
\r
8923 MF_BYCOMMAND|(pausing ? MF_CHECKED : MF_UNCHECKED));
\r
8924 if (hwndPause) SetWindowText(hwndPause, pausing ? "C" : "P");
\r
8927 switch (gameMode) {
\r
8928 case BeginningOfGame:
\r
8929 if (appData.icsActive)
\r
8930 nowChecked = IDM_IcsClient;
\r
8931 else if (appData.noChessProgram)
\r
8932 nowChecked = IDM_EditGame;
\r
8934 nowChecked = IDM_MachineBlack;
\r
8936 case MachinePlaysBlack:
\r
8937 nowChecked = IDM_MachineBlack;
\r
8939 case MachinePlaysWhite:
\r
8940 nowChecked = IDM_MachineWhite;
\r
8942 case TwoMachinesPlay:
\r
8943 nowChecked = IDM_TwoMachines;
\r
8946 nowChecked = IDM_AnalysisMode;
\r
8949 nowChecked = IDM_AnalyzeFile;
\r
8952 nowChecked = IDM_EditGame;
\r
8954 case PlayFromGameFile:
\r
8955 nowChecked = IDM_LoadGame;
\r
8957 case EditPosition:
\r
8958 nowChecked = IDM_EditPosition;
\r
8961 nowChecked = IDM_Training;
\r
8963 case IcsPlayingWhite:
\r
8964 case IcsPlayingBlack:
\r
8965 case IcsObserving:
\r
8967 nowChecked = IDM_IcsClient;
\r
8974 if (prevChecked != 0)
\r
8975 (void) CheckMenuItem(GetMenu(hwndMain),
\r
8976 prevChecked, MF_BYCOMMAND|MF_UNCHECKED);
\r
8977 if (nowChecked != 0)
\r
8978 (void) CheckMenuItem(GetMenu(hwndMain),
\r
8979 nowChecked, MF_BYCOMMAND|MF_CHECKED);
\r
8981 if (nowChecked == IDM_LoadGame || nowChecked == IDM_Training) {
\r
8982 (void) EnableMenuItem(GetMenu(hwndMain), IDM_Training,
\r
8983 MF_BYCOMMAND|MF_ENABLED);
\r
8985 (void) EnableMenuItem(GetMenu(hwndMain),
\r
8986 IDM_Training, MF_BYCOMMAND|MF_GRAYED);
\r
8989 prevChecked = nowChecked;
\r
8991 /* [DM] icsEngineAnalyze - Do a sceure check too */
\r
8992 if (appData.icsActive) {
\r
8993 if (appData.icsEngineAnalyze) {
\r
8994 (void) CheckMenuItem(GetMenu(hwndMain), IDM_AnalysisMode,
\r
8995 MF_BYCOMMAND|MF_CHECKED);
\r
8997 (void) CheckMenuItem(GetMenu(hwndMain), IDM_AnalysisMode,
\r
8998 MF_BYCOMMAND|MF_UNCHECKED);
\r
9006 HMENU hmenu = GetMenu(hwndMain);
\r
9007 SetMenuEnables(hmenu, icsEnables);
\r
9008 EnableMenuItem(GetSubMenu(hmenu, OPTIONS_POS), ICS_POS,
\r
9009 MF_BYPOSITION|MF_ENABLED);
\r
9011 if (appData.zippyPlay) {
\r
9012 SetMenuEnables(hmenu, zippyEnables);
\r
9013 if (!appData.noChessProgram) /* [DM] icsEngineAnalyze */
\r
9014 (void) EnableMenuItem(GetMenu(hwndMain), IDM_AnalysisMode,
\r
9015 MF_BYCOMMAND|MF_ENABLED);
\r
9023 SetMenuEnables(GetMenu(hwndMain), gnuEnables);
\r
9029 HMENU hmenu = GetMenu(hwndMain);
\r
9030 SetMenuEnables(hmenu, ncpEnables);
\r
9031 EnableMenuItem(GetSubMenu(hmenu, OPTIONS_POS), SOUNDS_POS,
\r
9032 MF_BYPOSITION|MF_GRAYED);
\r
9033 DrawMenuBar(hwndMain);
\r
9039 SetMenuEnables(GetMenu(hwndMain), cmailEnables);
\r
9043 SetTrainingModeOn()
\r
9046 SetMenuEnables(GetMenu(hwndMain), trainingOnEnables);
\r
9047 for (i = 0; i < N_BUTTONS; i++) {
\r
9048 if (buttonDesc[i].hwnd != NULL)
\r
9049 EnableWindow(buttonDesc[i].hwnd, FALSE);
\r
9054 VOID SetTrainingModeOff()
\r
9057 SetMenuEnables(GetMenu(hwndMain), trainingOffEnables);
\r
9058 for (i = 0; i < N_BUTTONS; i++) {
\r
9059 if (buttonDesc[i].hwnd != NULL)
\r
9060 EnableWindow(buttonDesc[i].hwnd, TRUE);
\r
9066 SetUserThinkingEnables()
\r
9068 SetMenuEnables(GetMenu(hwndMain), userThinkingEnables);
\r
9072 SetMachineThinkingEnables()
\r
9074 HMENU hMenu = GetMenu(hwndMain);
\r
9075 int flags = MF_BYCOMMAND|MF_ENABLED;
\r
9077 SetMenuEnables(hMenu, machineThinkingEnables);
\r
9079 if (gameMode == MachinePlaysBlack) {
\r
9080 (void)EnableMenuItem(hMenu, IDM_MachineBlack, flags);
\r
9081 } else if (gameMode == MachinePlaysWhite) {
\r
9082 (void)EnableMenuItem(hMenu, IDM_MachineWhite, flags);
\r
9083 } else if (gameMode == TwoMachinesPlay) {
\r
9084 (void)EnableMenuItem(hMenu, IDM_TwoMachines, flags);
\r
9090 DisplayTitle(char *str)
\r
9092 char title[MSG_SIZ], *host;
\r
9093 if (str[0] != NULLCHAR) {
\r
9094 strcpy(title, str);
\r
9095 } else if (appData.icsActive) {
\r
9096 if (appData.icsCommPort[0] != NULLCHAR)
\r
9099 host = appData.icsHost;
\r
9100 sprintf(title, "%s: %s", szTitle, host);
\r
9101 } else if (appData.noChessProgram) {
\r
9102 strcpy(title, szTitle);
\r
9104 strcpy(title, szTitle);
\r
9105 strcat(title, ": ");
\r
9106 strcat(title, first.tidy);
\r
9108 SetWindowText(hwndMain, title);
\r
9113 DisplayMessage(char *str1, char *str2)
\r
9117 int remain = MESSAGE_TEXT_MAX - 1;
\r
9120 moveErrorMessageUp = FALSE; /* turned on later by caller if needed */
\r
9121 messageText[0] = NULLCHAR;
\r
9123 len = strlen(str1);
\r
9124 if (len > remain) len = remain;
\r
9125 strncpy(messageText, str1, len);
\r
9126 messageText[len] = NULLCHAR;
\r
9129 if (*str2 && remain >= 2) {
\r
9131 strcat(messageText, " ");
\r
9134 len = strlen(str2);
\r
9135 if (len > remain) len = remain;
\r
9136 strncat(messageText, str2, len);
\r
9138 messageText[MESSAGE_TEXT_MAX - 1] = NULLCHAR;
\r
9140 if (hwndMain == NULL || IsIconic(hwndMain)) return;
\r
9144 hdc = GetDC(hwndMain);
\r
9145 oldFont = SelectObject(hdc, font[boardSize][MESSAGE_FONT]->hf);
\r
9146 ExtTextOut(hdc, messageRect.left, messageRect.top, ETO_CLIPPED|ETO_OPAQUE,
\r
9147 &messageRect, messageText, strlen(messageText), NULL);
\r
9148 (void) SelectObject(hdc, oldFont);
\r
9149 (void) ReleaseDC(hwndMain, hdc);
\r
9153 DisplayError(char *str, int error)
\r
9155 char buf[MSG_SIZ*2], buf2[MSG_SIZ];
\r
9161 len = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
\r
9162 NULL, error, LANG_NEUTRAL,
\r
9163 (LPSTR) buf2, MSG_SIZ, NULL);
\r
9165 sprintf(buf, "%s:\n%s", str, buf2);
\r
9167 ErrorMap *em = errmap;
\r
9168 while (em->err != 0 && em->err != error) em++;
\r
9169 if (em->err != 0) {
\r
9170 sprintf(buf, "%s:\n%s", str, em->msg);
\r
9172 sprintf(buf, "%s:\nError code %d", str, error);
\r
9177 ErrorPopUp("Error", buf);
\r
9182 DisplayMoveError(char *str)
\r
9184 fromX = fromY = -1;
\r
9185 ClearHighlights();
\r
9186 DrawPosition(FALSE, NULL);
\r
9187 if (appData.popupMoveErrors) {
\r
9188 ErrorPopUp("Error", str);
\r
9190 DisplayMessage(str, "");
\r
9191 moveErrorMessageUp = TRUE;
\r
9196 DisplayFatalError(char *str, int error, int exitStatus)
\r
9198 char buf[2*MSG_SIZ], buf2[MSG_SIZ];
\r
9200 char *label = exitStatus ? "Fatal Error" : "Exiting";
\r
9203 len = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
\r
9204 NULL, error, LANG_NEUTRAL,
\r
9205 (LPSTR) buf2, MSG_SIZ, NULL);
\r
9207 sprintf(buf, "%s:\n%s", str, buf2);
\r
9209 ErrorMap *em = errmap;
\r
9210 while (em->err != 0 && em->err != error) em++;
\r
9211 if (em->err != 0) {
\r
9212 sprintf(buf, "%s:\n%s", str, em->msg);
\r
9214 sprintf(buf, "%s:\nError code %d", str, error);
\r
9219 if (appData.debugMode) {
\r
9220 fprintf(debugFP, "%s: %s\n", label, str);
\r
9222 if (appData.popupExitMessage) {
\r
9223 (void) MessageBox(hwndMain, str, label, MB_OK|
\r
9224 (exitStatus ? MB_ICONSTOP : MB_ICONINFORMATION));
\r
9226 ExitEvent(exitStatus);
\r
9231 DisplayInformation(char *str)
\r
9233 (void) MessageBox(hwndMain, str, "Information", MB_OK|MB_ICONINFORMATION);
\r
9238 DisplayNote(char *str)
\r
9240 ErrorPopUp("Note", str);
\r
9245 char *title, *question, *replyPrefix;
\r
9250 QuestionDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
9252 static QuestionParams *qp;
\r
9253 char reply[MSG_SIZ];
\r
9256 switch (message) {
\r
9257 case WM_INITDIALOG:
\r
9258 qp = (QuestionParams *) lParam;
\r
9259 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
9260 SetWindowText(hDlg, qp->title);
\r
9261 SetDlgItemText(hDlg, OPT_QuestionText, qp->question);
\r
9262 SetFocus(GetDlgItem(hDlg, OPT_QuestionInput));
\r
9266 switch (LOWORD(wParam)) {
\r
9268 strcpy(reply, qp->replyPrefix);
\r
9269 if (*reply) strcat(reply, " ");
\r
9270 len = strlen(reply);
\r
9271 GetDlgItemText(hDlg, OPT_QuestionInput, reply + len, sizeof(reply) - len);
\r
9272 strcat(reply, "\n");
\r
9273 OutputToProcess(qp->pr, reply, strlen(reply), &err);
\r
9274 EndDialog(hDlg, TRUE);
\r
9275 if (err) DisplayFatalError("Error writing to chess program", err, 1);
\r
9278 EndDialog(hDlg, FALSE);
\r
9289 AskQuestion(char* title, char *question, char *replyPrefix, ProcRef pr)
\r
9291 QuestionParams qp;
\r
9295 qp.question = question;
\r
9296 qp.replyPrefix = replyPrefix;
\r
9298 lpProc = MakeProcInstance((FARPROC)QuestionDialog, hInst);
\r
9299 DialogBoxParam(hInst, MAKEINTRESOURCE(DLG_Question),
\r
9300 hwndMain, (DLGPROC)lpProc, (LPARAM)&qp);
\r
9301 FreeProcInstance(lpProc);
\r
9304 /* [AS] Pick FRC position */
\r
9305 LRESULT CALLBACK NewGameFRC_Proc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
9307 static int * lpIndexFRC;
\r
9313 case WM_INITDIALOG:
\r
9314 lpIndexFRC = (int *) lParam;
\r
9316 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
9318 SendDlgItemMessage( hDlg, IDC_NFG_Edit, EM_SETLIMITTEXT, sizeof(buf)-1, 0 );
\r
9319 SetDlgItemInt( hDlg, IDC_NFG_Edit, *lpIndexFRC, TRUE );
\r
9320 SendDlgItemMessage( hDlg, IDC_NFG_Edit, EM_SETSEL, 0, -1 );
\r
9321 SetFocus(GetDlgItem(hDlg, IDC_NFG_Edit));
\r
9326 switch( LOWORD(wParam) ) {
\r
9328 *lpIndexFRC = GetDlgItemInt(hDlg, IDC_NFG_Edit, &index_is_ok, TRUE );
\r
9329 EndDialog( hDlg, 0 );
\r
9330 shuffleOpenings = TRUE; /* [HGM] shuffle: switch shuffling on for as long as we stay in current variant */
\r
9333 EndDialog( hDlg, 1 );
\r
9335 case IDC_NFG_Edit:
\r
9336 if( HIWORD(wParam) == EN_CHANGE ) {
\r
9337 GetDlgItemInt(hDlg, IDC_NFG_Edit, &index_is_ok, TRUE );
\r
9339 EnableWindow( GetDlgItem(hDlg, IDOK), index_is_ok );
\r
9342 case IDC_NFG_Random:
\r
9343 sprintf( buf, "%d", myrandom() ); /* [HGM] shuffle: no longer limit to 960 */
\r
9344 SetDlgItemText(hDlg, IDC_NFG_Edit, buf );
\r
9357 int index = appData.defaultFrcPosition;
\r
9358 FARPROC lpProc = MakeProcInstance( (FARPROC) NewGameFRC_Proc, hInst );
\r
9360 result = DialogBoxParam( hInst, MAKEINTRESOURCE(DLG_NewGameFRC), hwndMain, (DLGPROC)lpProc, (LPARAM)&index );
\r
9362 if( result == 0 ) {
\r
9363 appData.defaultFrcPosition = index;
\r
9369 /* [AS] Game list options */
\r
9375 static GLT_Item GLT_ItemInfo[] = {
\r
9376 { GLT_EVENT, "Event" },
\r
9377 { GLT_SITE, "Site" },
\r
9378 { GLT_DATE, "Date" },
\r
9379 { GLT_ROUND, "Round" },
\r
9380 { GLT_PLAYERS, "Players" },
\r
9381 { GLT_RESULT, "Result" },
\r
9382 { GLT_WHITE_ELO, "White Rating" },
\r
9383 { GLT_BLACK_ELO, "Black Rating" },
\r
9384 { GLT_TIME_CONTROL,"Time Control" },
\r
9385 { GLT_VARIANT, "Variant" },
\r
9386 { GLT_OUT_OF_BOOK,PGN_OUT_OF_BOOK },
\r
9390 const char * GLT_FindItem( char id )
\r
9392 const char * result = 0;
\r
9394 GLT_Item * list = GLT_ItemInfo;
\r
9396 while( list->id != 0 ) {
\r
9397 if( list->id == id ) {
\r
9398 result = list->name;
\r
9408 void GLT_AddToList( HWND hDlg, int iDlgItem, char id, int index )
\r
9410 const char * name = GLT_FindItem( id );
\r
9413 if( index >= 0 ) {
\r
9414 SendDlgItemMessage( hDlg, iDlgItem, LB_INSERTSTRING, index, (LPARAM) name );
\r
9417 SendDlgItemMessage( hDlg, iDlgItem, LB_ADDSTRING, 0, (LPARAM) name );
\r
9422 void GLT_TagsToList( HWND hDlg, char * tags )
\r
9426 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_RESETCONTENT, 0, 0 );
\r
9429 GLT_AddToList( hDlg, IDC_GameListTags, *pc, -1 );
\r
9433 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_ADDSTRING, 0, (LPARAM) "\t --- Hidden tags ---" );
\r
9435 pc = GLT_ALL_TAGS;
\r
9438 if( strchr( tags, *pc ) == 0 ) {
\r
9439 GLT_AddToList( hDlg, IDC_GameListTags, *pc, -1 );
\r
9444 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_SETCURSEL, 0, 0 );
\r
9447 char GLT_ListItemToTag( HWND hDlg, int index )
\r
9449 char result = '\0';
\r
9452 GLT_Item * list = GLT_ItemInfo;
\r
9454 if( SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETTEXT, index, (LPARAM) name ) != LB_ERR ) {
\r
9455 while( list->id != 0 ) {
\r
9456 if( strcmp( list->name, name ) == 0 ) {
\r
9457 result = list->id;
\r
9468 void GLT_MoveSelection( HWND hDlg, int delta )
\r
9470 int idx1 = (int) SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETCURSEL, 0, 0 );
\r
9471 int idx2 = idx1 + delta;
\r
9472 int count = (int) SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETCOUNT, 0, 0 );
\r
9474 if( idx1 >=0 && idx1 < count && idx2 >= 0 && idx2 < count ) {
\r
9477 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETTEXT, idx1, (LPARAM) buf );
\r
9478 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_DELETESTRING, idx1, 0 );
\r
9479 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_INSERTSTRING, idx2, (LPARAM) buf );
\r
9480 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_SETCURSEL, idx2, 0 );
\r
9484 LRESULT CALLBACK GameListOptions_Proc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
9486 static char glt[64];
\r
9487 static char * lpUserGLT;
\r
9491 case WM_INITDIALOG:
\r
9492 lpUserGLT = (char *) lParam;
\r
9494 strcpy( glt, lpUserGLT );
\r
9496 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
9498 /* Initialize list */
\r
9499 GLT_TagsToList( hDlg, glt );
\r
9501 SetFocus( GetDlgItem(hDlg, IDC_GameListTags) );
\r
9506 switch( LOWORD(wParam) ) {
\r
9509 char * pc = lpUserGLT;
\r
9511 // int cnt = (int) SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETCOUNT, 0, 0 );
\r
9515 id = GLT_ListItemToTag( hDlg, idx );
\r
9519 } while( id != '\0' );
\r
9521 EndDialog( hDlg, 0 );
\r
9524 EndDialog( hDlg, 1 );
\r
9527 case IDC_GLT_Default:
\r
9528 strcpy( glt, GLT_DEFAULT_TAGS );
\r
9529 GLT_TagsToList( hDlg, glt );
\r
9532 case IDC_GLT_Restore:
\r
9533 strcpy( glt, lpUserGLT );
\r
9534 GLT_TagsToList( hDlg, glt );
\r
9538 GLT_MoveSelection( hDlg, -1 );
\r
9541 case IDC_GLT_Down:
\r
9542 GLT_MoveSelection( hDlg, +1 );
\r
9552 int GameListOptions()
\r
9556 FARPROC lpProc = MakeProcInstance( (FARPROC) GameListOptions_Proc, hInst );
\r
9558 strcpy( glt, appData.gameListTags );
\r
9560 result = DialogBoxParam( hInst, MAKEINTRESOURCE(DLG_GameListOptions), hwndMain, (DLGPROC)lpProc, (LPARAM)glt );
\r
9562 if( result == 0 ) {
\r
9563 /* [AS] Memory leak here! */
\r
9564 appData.gameListTags = strdup( glt );
\r
9572 DisplayIcsInteractionTitle(char *str)
\r
9574 char consoleTitle[MSG_SIZ];
\r
9576 sprintf(consoleTitle, "%s: %s", szConsoleTitle, str);
\r
9577 SetWindowText(hwndConsole, consoleTitle);
\r
9581 DrawPosition(int fullRedraw, Board board)
\r
9583 HDCDrawPosition(NULL, (BOOLEAN) fullRedraw, board);
\r
9590 fromX = fromY = -1;
\r
9591 if (dragInfo.pos.x != -1 || dragInfo.pos.y != -1) {
\r
9592 dragInfo.pos.x = dragInfo.pos.y = -1;
\r
9593 dragInfo.pos.x = dragInfo.pos.y = -1;
\r
9594 dragInfo.lastpos = dragInfo.pos;
\r
9595 dragInfo.start.x = dragInfo.start.y = -1;
\r
9596 dragInfo.from = dragInfo.start;
\r
9598 DrawPosition(TRUE, NULL);
\r
9604 CommentPopUp(char *title, char *str)
\r
9606 HWND hwnd = GetActiveWindow();
\r
9607 EitherCommentPopUp(0, title, str, FALSE);
\r
9608 SetActiveWindow(hwnd);
\r
9612 CommentPopDown(void)
\r
9614 CheckMenuItem(GetMenu(hwndMain), IDM_EditComment, MF_UNCHECKED);
\r
9615 if (commentDialog) {
\r
9616 ShowWindow(commentDialog, SW_HIDE);
\r
9618 commentDialogUp = FALSE;
\r
9622 EditCommentPopUp(int index, char *title, char *str)
\r
9624 EitherCommentPopUp(index, title, str, TRUE);
\r
9631 MyPlaySound(&sounds[(int)SoundMove]);
\r
9634 VOID PlayIcsWinSound()
\r
9636 MyPlaySound(&sounds[(int)SoundIcsWin]);
\r
9639 VOID PlayIcsLossSound()
\r
9641 MyPlaySound(&sounds[(int)SoundIcsLoss]);
\r
9644 VOID PlayIcsDrawSound()
\r
9646 MyPlaySound(&sounds[(int)SoundIcsDraw]);
\r
9649 VOID PlayIcsUnfinishedSound()
\r
9651 MyPlaySound(&sounds[(int)SoundIcsUnfinished]);
\r
9657 MyPlaySound(&sounds[(int)SoundAlarm]);
\r
9665 consoleEcho = TRUE;
\r
9666 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
9667 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&consoleCF);
\r
9668 SendMessage(hInput, EM_SETBKGNDCOLOR, FALSE, consoleBackgroundColor);
\r
9677 consoleEcho = FALSE;
\r
9678 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
9679 /* This works OK: set text and background both to the same color */
\r
9681 cf.crTextColor = COLOR_ECHOOFF;
\r
9682 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&cf);
\r
9683 SendMessage(hInput, EM_SETBKGNDCOLOR, FALSE, cf.crTextColor);
\r
9686 /* No Raw()...? */
\r
9688 void Colorize(ColorClass cc, int continuation)
\r
9690 currentColorClass = cc;
\r
9691 consoleCF.dwMask = CFM_COLOR|CFM_BOLD|CFM_ITALIC|CFM_UNDERLINE|CFM_STRIKEOUT;
\r
9692 consoleCF.crTextColor = textAttribs[cc].color;
\r
9693 consoleCF.dwEffects = textAttribs[cc].effects;
\r
9694 if (!continuation) MyPlaySound(&textAttribs[cc].sound);
\r
9700 static char buf[MSG_SIZ];
\r
9701 DWORD bufsiz = MSG_SIZ;
\r
9703 if(appData.userName != NULL && appData.userName[0] != 0) {
\r
9704 return appData.userName; /* [HGM] username: prefer name selected by user over his system login */
\r
9706 if (!GetUserName(buf, &bufsiz)) {
\r
9707 /*DisplayError("Error getting user name", GetLastError());*/
\r
9708 strcpy(buf, "User");
\r
9716 static char buf[MSG_SIZ];
\r
9717 DWORD bufsiz = MSG_SIZ;
\r
9719 if (!GetComputerName(buf, &bufsiz)) {
\r
9720 /*DisplayError("Error getting host name", GetLastError());*/
\r
9721 strcpy(buf, "Unknown");
\r
9728 ClockTimerRunning()
\r
9730 return clockTimerEvent != 0;
\r
9736 if (clockTimerEvent == 0) return FALSE;
\r
9737 KillTimer(hwndMain, clockTimerEvent);
\r
9738 clockTimerEvent = 0;
\r
9743 StartClockTimer(long millisec)
\r
9745 clockTimerEvent = SetTimer(hwndMain, (UINT) CLOCK_TIMER_ID,
\r
9746 (UINT) millisec, NULL);
\r
9750 DisplayWhiteClock(long timeRemaining, int highlight)
\r
9753 char *flag = whiteFlag && gameMode == TwoMachinesPlay ? "(!)" : "";
\r
9755 if(appData.noGUI) return;
\r
9756 hdc = GetDC(hwndMain);
\r
9757 if (!IsIconic(hwndMain)) {
\r
9758 DisplayAClock(hdc, timeRemaining, highlight,
\r
9759 flipClock ? &blackRect : &whiteRect, "White", flag);
\r
9761 if (highlight && iconCurrent == iconBlack) {
\r
9762 iconCurrent = iconWhite;
\r
9763 PostMessage(hwndMain, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
9764 if (IsIconic(hwndMain)) {
\r
9765 DrawIcon(hdc, 2, 2, iconCurrent);
\r
9768 (void) ReleaseDC(hwndMain, hdc);
\r
9770 PostMessage(hwndConsole, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
9774 DisplayBlackClock(long timeRemaining, int highlight)
\r
9777 char *flag = blackFlag && gameMode == TwoMachinesPlay ? "(!)" : "";
\r
9779 if(appData.noGUI) return;
\r
9780 hdc = GetDC(hwndMain);
\r
9781 if (!IsIconic(hwndMain)) {
\r
9782 DisplayAClock(hdc, timeRemaining, highlight,
\r
9783 flipClock ? &whiteRect : &blackRect, "Black", flag);
\r
9785 if (highlight && iconCurrent == iconWhite) {
\r
9786 iconCurrent = iconBlack;
\r
9787 PostMessage(hwndMain, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
9788 if (IsIconic(hwndMain)) {
\r
9789 DrawIcon(hdc, 2, 2, iconCurrent);
\r
9792 (void) ReleaseDC(hwndMain, hdc);
\r
9794 PostMessage(hwndConsole, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
9799 LoadGameTimerRunning()
\r
9801 return loadGameTimerEvent != 0;
\r
9805 StopLoadGameTimer()
\r
9807 if (loadGameTimerEvent == 0) return FALSE;
\r
9808 KillTimer(hwndMain, loadGameTimerEvent);
\r
9809 loadGameTimerEvent = 0;
\r
9814 StartLoadGameTimer(long millisec)
\r
9816 loadGameTimerEvent = SetTimer(hwndMain, (UINT) LOAD_GAME_TIMER_ID,
\r
9817 (UINT) millisec, NULL);
\r
9825 char fileTitle[MSG_SIZ];
\r
9827 defName = DefaultFileName(appData.oldSaveStyle ? "gam" : "pgn");
\r
9828 f = OpenFileDialog(hwndMain, "a", defName,
\r
9829 appData.oldSaveStyle ? "gam" : "pgn",
\r
9831 "Save Game to File", NULL, fileTitle, NULL);
\r
9833 SaveGame(f, 0, "");
\r
9840 ScheduleDelayedEvent(DelayedEventCallback cb, long millisec)
\r
9842 if (delayedTimerEvent != 0) {
\r
9843 if (appData.debugMode) {
\r
9844 fprintf(debugFP, "ScheduleDelayedEvent: event already scheduled\n");
\r
9846 KillTimer(hwndMain, delayedTimerEvent);
\r
9847 delayedTimerEvent = 0;
\r
9848 delayedTimerCallback();
\r
9850 delayedTimerCallback = cb;
\r
9851 delayedTimerEvent = SetTimer(hwndMain, (UINT) DELAYED_TIMER_ID,
\r
9852 (UINT) millisec, NULL);
\r
9855 DelayedEventCallback
\r
9858 if (delayedTimerEvent) {
\r
9859 return delayedTimerCallback;
\r
9866 CancelDelayedEvent()
\r
9868 if (delayedTimerEvent) {
\r
9869 KillTimer(hwndMain, delayedTimerEvent);
\r
9870 delayedTimerEvent = 0;
\r
9874 DWORD GetWin32Priority(int nice)
\r
9875 { // [HGM] nice: translate Unix nice() value to indows priority class. (Code stolen from Polyglot 1.4w11)
\r
9877 REALTIME_PRIORITY_CLASS 0x00000100
\r
9878 HIGH_PRIORITY_CLASS 0x00000080
\r
9879 ABOVE_NORMAL_PRIORITY_CLASS 0x00008000
\r
9880 NORMAL_PRIORITY_CLASS 0x00000020
\r
9881 BELOW_NORMAL_PRIORITY_CLASS 0x00004000
\r
9882 IDLE_PRIORITY_CLASS 0x00000040
\r
9884 if (nice < -15) return 0x00000080;
\r
9885 if (nice < 0) return 0x00008000;
\r
9886 if (nice == 0) return 0x00000020;
\r
9887 if (nice < 15) return 0x00004000;
\r
9888 return 0x00000040;
\r
9891 /* Start a child process running the given program.
\r
9892 The process's standard output can be read from "from", and its
\r
9893 standard input can be written to "to".
\r
9894 Exit with fatal error if anything goes wrong.
\r
9895 Returns an opaque pointer that can be used to destroy the process
\r
9899 StartChildProcess(char *cmdLine, char *dir, ProcRef *pr)
\r
9901 #define BUFSIZE 4096
\r
9903 HANDLE hChildStdinRd, hChildStdinWr,
\r
9904 hChildStdoutRd, hChildStdoutWr;
\r
9905 HANDLE hChildStdinWrDup, hChildStdoutRdDup;
\r
9906 SECURITY_ATTRIBUTES saAttr;
\r
9908 PROCESS_INFORMATION piProcInfo;
\r
9909 STARTUPINFO siStartInfo;
\r
9911 char buf[MSG_SIZ];
\r
9914 if (appData.debugMode) {
\r
9915 fprintf(debugFP, "StartChildProcess (dir=\"%s\") %s\n", dir, cmdLine);
\r
9920 /* Set the bInheritHandle flag so pipe handles are inherited. */
\r
9921 saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
\r
9922 saAttr.bInheritHandle = TRUE;
\r
9923 saAttr.lpSecurityDescriptor = NULL;
\r
9926 * The steps for redirecting child's STDOUT:
\r
9927 * 1. Create anonymous pipe to be STDOUT for child.
\r
9928 * 2. Create a noninheritable duplicate of read handle,
\r
9929 * and close the inheritable read handle.
\r
9932 /* Create a pipe for the child's STDOUT. */
\r
9933 if (! CreatePipe(&hChildStdoutRd, &hChildStdoutWr, &saAttr, 0)) {
\r
9934 return GetLastError();
\r
9937 /* Duplicate the read handle to the pipe, so it is not inherited. */
\r
9938 fSuccess = DuplicateHandle(GetCurrentProcess(), hChildStdoutRd,
\r
9939 GetCurrentProcess(), &hChildStdoutRdDup, 0,
\r
9940 FALSE, /* not inherited */
\r
9941 DUPLICATE_SAME_ACCESS);
\r
9943 return GetLastError();
\r
9945 CloseHandle(hChildStdoutRd);
\r
9948 * The steps for redirecting child's STDIN:
\r
9949 * 1. Create anonymous pipe to be STDIN for child.
\r
9950 * 2. Create a noninheritable duplicate of write handle,
\r
9951 * and close the inheritable write handle.
\r
9954 /* Create a pipe for the child's STDIN. */
\r
9955 if (! CreatePipe(&hChildStdinRd, &hChildStdinWr, &saAttr, 0)) {
\r
9956 return GetLastError();
\r
9959 /* Duplicate the write handle to the pipe, so it is not inherited. */
\r
9960 fSuccess = DuplicateHandle(GetCurrentProcess(), hChildStdinWr,
\r
9961 GetCurrentProcess(), &hChildStdinWrDup, 0,
\r
9962 FALSE, /* not inherited */
\r
9963 DUPLICATE_SAME_ACCESS);
\r
9965 return GetLastError();
\r
9967 CloseHandle(hChildStdinWr);
\r
9969 /* Arrange to (1) look in dir for the child .exe file, and
\r
9970 * (2) have dir be the child's working directory. Interpret
\r
9971 * dir relative to the directory WinBoard loaded from. */
\r
9972 GetCurrentDirectory(MSG_SIZ, buf);
\r
9973 SetCurrentDirectory(installDir);
\r
9974 SetCurrentDirectory(dir);
\r
9976 /* Now create the child process. */
\r
9978 siStartInfo.cb = sizeof(STARTUPINFO);
\r
9979 siStartInfo.lpReserved = NULL;
\r
9980 siStartInfo.lpDesktop = NULL;
\r
9981 siStartInfo.lpTitle = NULL;
\r
9982 siStartInfo.dwFlags = STARTF_USESTDHANDLES;
\r
9983 siStartInfo.cbReserved2 = 0;
\r
9984 siStartInfo.lpReserved2 = NULL;
\r
9985 siStartInfo.hStdInput = hChildStdinRd;
\r
9986 siStartInfo.hStdOutput = hChildStdoutWr;
\r
9987 siStartInfo.hStdError = hChildStdoutWr;
\r
9989 fSuccess = CreateProcess(NULL,
\r
9990 cmdLine, /* command line */
\r
9991 NULL, /* process security attributes */
\r
9992 NULL, /* primary thread security attrs */
\r
9993 TRUE, /* handles are inherited */
\r
9994 DETACHED_PROCESS|CREATE_NEW_PROCESS_GROUP,
\r
9995 NULL, /* use parent's environment */
\r
9997 &siStartInfo, /* STARTUPINFO pointer */
\r
9998 &piProcInfo); /* receives PROCESS_INFORMATION */
\r
10000 err = GetLastError();
\r
10001 SetCurrentDirectory(buf); /* return to prev directory */
\r
10002 if (! fSuccess) {
\r
10006 if (appData.niceEngines){ // [HGM] nice: adjust engine proc priority
\r
10007 if(appData.debugMode) fprintf(debugFP, "nice engine proc to %d\n", appData.niceEngines);
\r
10008 SetPriorityClass(piProcInfo.hProcess, GetWin32Priority(appData.niceEngines));
\r
10011 /* Close the handles we don't need in the parent */
\r
10012 CloseHandle(piProcInfo.hThread);
\r
10013 CloseHandle(hChildStdinRd);
\r
10014 CloseHandle(hChildStdoutWr);
\r
10016 /* Prepare return value */
\r
10017 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
10018 cp->kind = CPReal;
\r
10019 cp->hProcess = piProcInfo.hProcess;
\r
10020 cp->pid = piProcInfo.dwProcessId;
\r
10021 cp->hFrom = hChildStdoutRdDup;
\r
10022 cp->hTo = hChildStdinWrDup;
\r
10024 *pr = (void *) cp;
\r
10026 /* Klaus Friedel says that this Sleep solves a problem under Windows
\r
10027 2000 where engines sometimes don't see the initial command(s)
\r
10028 from WinBoard and hang. I don't understand how that can happen,
\r
10029 but the Sleep is harmless, so I've put it in. Others have also
\r
10030 reported what may be the same problem, so hopefully this will fix
\r
10031 it for them too. */
\r
10039 DestroyChildProcess(ProcRef pr, int/*boolean*/ signal)
\r
10041 ChildProc *cp; int result;
\r
10043 cp = (ChildProc *) pr;
\r
10044 if (cp == NULL) return;
\r
10046 switch (cp->kind) {
\r
10048 /* TerminateProcess is considered harmful, so... */
\r
10049 CloseHandle(cp->hTo); /* Closing this will give the child an EOF and hopefully kill it */
\r
10050 if (cp->hFrom) CloseHandle(cp->hFrom); /* if NULL, InputThread will close it */
\r
10051 /* The following doesn't work because the chess program
\r
10052 doesn't "have the same console" as WinBoard. Maybe
\r
10053 we could arrange for this even though neither WinBoard
\r
10054 nor the chess program uses a console for stdio? */
\r
10055 /*!!if (signal) GenerateConsoleCtrlEvent(CTRL_BREAK_EVENT, cp->pid);*/
\r
10057 /* [AS] Special termination modes for misbehaving programs... */
\r
10058 if( signal == 9 ) {
\r
10059 result = TerminateProcess( cp->hProcess, 0 );
\r
10061 if ( appData.debugMode) {
\r
10062 fprintf( debugFP, "Terminating process %lu, result=%d\n", cp->pid, result );
\r
10065 else if( signal == 10 ) {
\r
10066 DWORD dw = WaitForSingleObject( cp->hProcess, 3*1000 ); // Wait 3 seconds at most
\r
10068 if( dw != WAIT_OBJECT_0 ) {
\r
10069 result = TerminateProcess( cp->hProcess, 0 );
\r
10071 if ( appData.debugMode) {
\r
10072 fprintf( debugFP, "Process %lu still alive after timeout, killing... result=%d\n", cp->pid, result );
\r
10078 CloseHandle(cp->hProcess);
\r
10082 if (cp->hFrom) CloseHandle(cp->hFrom);
\r
10086 closesocket(cp->sock);
\r
10091 if (signal) send(cp->sock2, "\017", 1, 0); /* 017 = 15 = SIGTERM */
\r
10092 closesocket(cp->sock);
\r
10093 closesocket(cp->sock2);
\r
10101 InterruptChildProcess(ProcRef pr)
\r
10105 cp = (ChildProc *) pr;
\r
10106 if (cp == NULL) return;
\r
10107 switch (cp->kind) {
\r
10109 /* The following doesn't work because the chess program
\r
10110 doesn't "have the same console" as WinBoard. Maybe
\r
10111 we could arrange for this even though neither WinBoard
\r
10112 nor the chess program uses a console for stdio */
\r
10113 /*!!GenerateConsoleCtrlEvent(CTRL_C_EVENT, cp->pid);*/
\r
10118 /* Can't interrupt */
\r
10122 send(cp->sock2, "\002", 1, 0); /* 2 = SIGINT */
\r
10129 OpenTelnet(char *host, char *port, ProcRef *pr)
\r
10131 char cmdLine[MSG_SIZ];
\r
10133 if (port[0] == NULLCHAR) {
\r
10134 sprintf(cmdLine, "%s %s", appData.telnetProgram, host);
\r
10136 sprintf(cmdLine, "%s %s %s", appData.telnetProgram, host, port);
\r
10138 return StartChildProcess(cmdLine, "", pr);
\r
10142 /* Code to open TCP sockets */
\r
10145 OpenTCP(char *host, char *port, ProcRef *pr)
\r
10150 struct sockaddr_in sa, mysa;
\r
10151 struct hostent FAR *hp;
\r
10152 unsigned short uport;
\r
10153 WORD wVersionRequested;
\r
10156 /* Initialize socket DLL */
\r
10157 wVersionRequested = MAKEWORD(1, 1);
\r
10158 err = WSAStartup(wVersionRequested, &wsaData);
\r
10159 if (err != 0) return err;
\r
10161 /* Make socket */
\r
10162 if ((s = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
\r
10163 err = WSAGetLastError();
\r
10168 /* Bind local address using (mostly) don't-care values.
\r
10170 memset((char *) &mysa, 0, sizeof(struct sockaddr_in));
\r
10171 mysa.sin_family = AF_INET;
\r
10172 mysa.sin_addr.s_addr = INADDR_ANY;
\r
10173 uport = (unsigned short) 0;
\r
10174 mysa.sin_port = htons(uport);
\r
10175 if (bind(s, (struct sockaddr *) &mysa, sizeof(struct sockaddr_in))
\r
10176 == SOCKET_ERROR) {
\r
10177 err = WSAGetLastError();
\r
10182 /* Resolve remote host name */
\r
10183 memset((char *) &sa, 0, sizeof(struct sockaddr_in));
\r
10184 if (!(hp = gethostbyname(host))) {
\r
10185 unsigned int b0, b1, b2, b3;
\r
10187 err = WSAGetLastError();
\r
10189 if (sscanf(host, "%u.%u.%u.%u", &b0, &b1, &b2, &b3) == 4) {
\r
10190 hp = (struct hostent *) calloc(1, sizeof(struct hostent));
\r
10191 hp->h_addrtype = AF_INET;
\r
10192 hp->h_length = 4;
\r
10193 hp->h_addr_list = (char **) calloc(2, sizeof(char *));
\r
10194 hp->h_addr_list[0] = (char *) malloc(4);
\r
10195 hp->h_addr_list[0][0] = (char) b0;
\r
10196 hp->h_addr_list[0][1] = (char) b1;
\r
10197 hp->h_addr_list[0][2] = (char) b2;
\r
10198 hp->h_addr_list[0][3] = (char) b3;
\r
10204 sa.sin_family = hp->h_addrtype;
\r
10205 uport = (unsigned short) atoi(port);
\r
10206 sa.sin_port = htons(uport);
\r
10207 memcpy((char *) &sa.sin_addr, hp->h_addr, hp->h_length);
\r
10209 /* Make connection */
\r
10210 if (connect(s, (struct sockaddr *) &sa,
\r
10211 sizeof(struct sockaddr_in)) == SOCKET_ERROR) {
\r
10212 err = WSAGetLastError();
\r
10217 /* Prepare return value */
\r
10218 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
10219 cp->kind = CPSock;
\r
10221 *pr = (ProcRef *) cp;
\r
10227 OpenCommPort(char *name, ProcRef *pr)
\r
10232 char fullname[MSG_SIZ];
\r
10234 if (*name != '\\')
\r
10235 sprintf(fullname, "\\\\.\\%s", name);
\r
10237 strcpy(fullname, name);
\r
10239 h = CreateFile(name, GENERIC_READ | GENERIC_WRITE,
\r
10240 0, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
\r
10241 if (h == (HANDLE) -1) {
\r
10242 return GetLastError();
\r
10246 if (!SetCommState(h, (LPDCB) &dcb)) return GetLastError();
\r
10248 /* Accumulate characters until a 100ms pause, then parse */
\r
10249 ct.ReadIntervalTimeout = 100;
\r
10250 ct.ReadTotalTimeoutMultiplier = 0;
\r
10251 ct.ReadTotalTimeoutConstant = 0;
\r
10252 ct.WriteTotalTimeoutMultiplier = 0;
\r
10253 ct.WriteTotalTimeoutConstant = 0;
\r
10254 if (!SetCommTimeouts(h, (LPCOMMTIMEOUTS) &ct)) return GetLastError();
\r
10256 /* Prepare return value */
\r
10257 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
10258 cp->kind = CPComm;
\r
10261 *pr = (ProcRef *) cp;
\r
10267 OpenLoopback(ProcRef *pr)
\r
10269 DisplayFatalError("Not implemented", 0, 1);
\r
10275 OpenRcmd(char* host, char* user, char* cmd, ProcRef* pr)
\r
10279 SOCKET s, s2, s3;
\r
10280 struct sockaddr_in sa, mysa;
\r
10281 struct hostent FAR *hp;
\r
10282 unsigned short uport;
\r
10283 WORD wVersionRequested;
\r
10286 char stderrPortStr[MSG_SIZ];
\r
10288 /* Initialize socket DLL */
\r
10289 wVersionRequested = MAKEWORD(1, 1);
\r
10290 err = WSAStartup(wVersionRequested, &wsaData);
\r
10291 if (err != 0) return err;
\r
10293 /* Resolve remote host name */
\r
10294 memset((char *) &sa, 0, sizeof(struct sockaddr_in));
\r
10295 if (!(hp = gethostbyname(host))) {
\r
10296 unsigned int b0, b1, b2, b3;
\r
10298 err = WSAGetLastError();
\r
10300 if (sscanf(host, "%u.%u.%u.%u", &b0, &b1, &b2, &b3) == 4) {
\r
10301 hp = (struct hostent *) calloc(1, sizeof(struct hostent));
\r
10302 hp->h_addrtype = AF_INET;
\r
10303 hp->h_length = 4;
\r
10304 hp->h_addr_list = (char **) calloc(2, sizeof(char *));
\r
10305 hp->h_addr_list[0] = (char *) malloc(4);
\r
10306 hp->h_addr_list[0][0] = (char) b0;
\r
10307 hp->h_addr_list[0][1] = (char) b1;
\r
10308 hp->h_addr_list[0][2] = (char) b2;
\r
10309 hp->h_addr_list[0][3] = (char) b3;
\r
10315 sa.sin_family = hp->h_addrtype;
\r
10316 uport = (unsigned short) 514;
\r
10317 sa.sin_port = htons(uport);
\r
10318 memcpy((char *) &sa.sin_addr, hp->h_addr, hp->h_length);
\r
10320 /* Bind local socket to unused "privileged" port address
\r
10322 s = INVALID_SOCKET;
\r
10323 memset((char *) &mysa, 0, sizeof(struct sockaddr_in));
\r
10324 mysa.sin_family = AF_INET;
\r
10325 mysa.sin_addr.s_addr = INADDR_ANY;
\r
10326 for (fromPort = 1023;; fromPort--) {
\r
10327 if (fromPort < 0) {
\r
10329 return WSAEADDRINUSE;
\r
10331 if (s == INVALID_SOCKET) {
\r
10332 if ((s = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
\r
10333 err = WSAGetLastError();
\r
10338 uport = (unsigned short) fromPort;
\r
10339 mysa.sin_port = htons(uport);
\r
10340 if (bind(s, (struct sockaddr *) &mysa, sizeof(struct sockaddr_in))
\r
10341 == SOCKET_ERROR) {
\r
10342 err = WSAGetLastError();
\r
10343 if (err == WSAEADDRINUSE) continue;
\r
10347 if (connect(s, (struct sockaddr *) &sa,
\r
10348 sizeof(struct sockaddr_in)) == SOCKET_ERROR) {
\r
10349 err = WSAGetLastError();
\r
10350 if (err == WSAEADDRINUSE) {
\r
10361 /* Bind stderr local socket to unused "privileged" port address
\r
10363 s2 = INVALID_SOCKET;
\r
10364 memset((char *) &mysa, 0, sizeof(struct sockaddr_in));
\r
10365 mysa.sin_family = AF_INET;
\r
10366 mysa.sin_addr.s_addr = INADDR_ANY;
\r
10367 for (fromPort = 1023;; fromPort--) {
\r
10368 if (fromPort == prevStderrPort) continue; // don't reuse port
\r
10369 if (fromPort < 0) {
\r
10370 (void) closesocket(s);
\r
10372 return WSAEADDRINUSE;
\r
10374 if (s2 == INVALID_SOCKET) {
\r
10375 if ((s2 = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
\r
10376 err = WSAGetLastError();
\r
10382 uport = (unsigned short) fromPort;
\r
10383 mysa.sin_port = htons(uport);
\r
10384 if (bind(s2, (struct sockaddr *) &mysa, sizeof(struct sockaddr_in))
\r
10385 == SOCKET_ERROR) {
\r
10386 err = WSAGetLastError();
\r
10387 if (err == WSAEADDRINUSE) continue;
\r
10388 (void) closesocket(s);
\r
10392 if (listen(s2, 1) == SOCKET_ERROR) {
\r
10393 err = WSAGetLastError();
\r
10394 if (err == WSAEADDRINUSE) {
\r
10396 s2 = INVALID_SOCKET;
\r
10399 (void) closesocket(s);
\r
10400 (void) closesocket(s2);
\r
10406 prevStderrPort = fromPort; // remember port used
\r
10407 sprintf(stderrPortStr, "%d", fromPort);
\r
10409 if (send(s, stderrPortStr, strlen(stderrPortStr) + 1, 0) == SOCKET_ERROR) {
\r
10410 err = WSAGetLastError();
\r
10411 (void) closesocket(s);
\r
10412 (void) closesocket(s2);
\r
10417 if (send(s, UserName(), strlen(UserName()) + 1, 0) == SOCKET_ERROR) {
\r
10418 err = WSAGetLastError();
\r
10419 (void) closesocket(s);
\r
10420 (void) closesocket(s2);
\r
10424 if (*user == NULLCHAR) user = UserName();
\r
10425 if (send(s, user, strlen(user) + 1, 0) == SOCKET_ERROR) {
\r
10426 err = WSAGetLastError();
\r
10427 (void) closesocket(s);
\r
10428 (void) closesocket(s2);
\r
10432 if (send(s, cmd, strlen(cmd) + 1, 0) == SOCKET_ERROR) {
\r
10433 err = WSAGetLastError();
\r
10434 (void) closesocket(s);
\r
10435 (void) closesocket(s2);
\r
10440 if ((s3 = accept(s2, NULL, NULL)) == INVALID_SOCKET) {
\r
10441 err = WSAGetLastError();
\r
10442 (void) closesocket(s);
\r
10443 (void) closesocket(s2);
\r
10447 (void) closesocket(s2); /* Stop listening */
\r
10449 /* Prepare return value */
\r
10450 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
10451 cp->kind = CPRcmd;
\r
10454 *pr = (ProcRef *) cp;
\r
10461 AddInputSource(ProcRef pr, int lineByLine,
\r
10462 InputCallback func, VOIDSTAR closure)
\r
10464 InputSource *is, *is2 = NULL;
\r
10465 ChildProc *cp = (ChildProc *) pr;
\r
10467 is = (InputSource *) calloc(1, sizeof(InputSource));
\r
10468 is->lineByLine = lineByLine;
\r
10470 is->closure = closure;
\r
10471 is->second = NULL;
\r
10472 is->next = is->buf;
\r
10473 if (pr == NoProc) {
\r
10474 is->kind = CPReal;
\r
10475 consoleInputSource = is;
\r
10477 is->kind = cp->kind;
\r
10479 [AS] Try to avoid a race condition if the thread is given control too early:
\r
10480 we create all threads suspended so that the is->hThread variable can be
\r
10481 safely assigned, then let the threads start with ResumeThread.
\r
10483 switch (cp->kind) {
\r
10485 is->hFile = cp->hFrom;
\r
10486 cp->hFrom = NULL; /* now owned by InputThread */
\r
10488 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) NonOvlInputThread,
\r
10489 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
10493 is->hFile = cp->hFrom;
\r
10494 cp->hFrom = NULL; /* now owned by InputThread */
\r
10496 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) InputThread,
\r
10497 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
10501 is->sock = cp->sock;
\r
10503 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SocketInputThread,
\r
10504 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
10508 is2 = (InputSource *) calloc(1, sizeof(InputSource));
\r
10510 is->sock = cp->sock;
\r
10511 is->second = is2;
\r
10512 is2->sock = cp->sock2;
\r
10513 is2->second = is2;
\r
10515 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SocketInputThread,
\r
10516 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
10518 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SocketInputThread,
\r
10519 (LPVOID) is2, CREATE_SUSPENDED, &is2->id);
\r
10523 if( is->hThread != NULL ) {
\r
10524 ResumeThread( is->hThread );
\r
10527 if( is2 != NULL && is2->hThread != NULL ) {
\r
10528 ResumeThread( is2->hThread );
\r
10532 return (InputSourceRef) is;
\r
10536 RemoveInputSource(InputSourceRef isr)
\r
10540 is = (InputSource *) isr;
\r
10541 is->hThread = NULL; /* tell thread to stop */
\r
10542 CloseHandle(is->hThread);
\r
10543 if (is->second != NULL) {
\r
10544 is->second->hThread = NULL;
\r
10545 CloseHandle(is->second->hThread);
\r
10551 OutputToProcess(ProcRef pr, char *message, int count, int *outError)
\r
10554 int outCount = SOCKET_ERROR;
\r
10555 ChildProc *cp = (ChildProc *) pr;
\r
10556 static OVERLAPPED ovl;
\r
10558 if (pr == NoProc) {
\r
10559 ConsoleOutput(message, count, FALSE);
\r
10563 if (ovl.hEvent == NULL) {
\r
10564 ovl.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
\r
10566 ovl.Internal = ovl.InternalHigh = ovl.Offset = ovl.OffsetHigh = 0;
\r
10568 switch (cp->kind) {
\r
10571 outCount = send(cp->sock, message, count, 0);
\r
10572 if (outCount == SOCKET_ERROR) {
\r
10573 *outError = WSAGetLastError();
\r
10575 *outError = NO_ERROR;
\r
10580 if (WriteFile(((ChildProc *)pr)->hTo, message, count,
\r
10581 &dOutCount, NULL)) {
\r
10582 *outError = NO_ERROR;
\r
10583 outCount = (int) dOutCount;
\r
10585 *outError = GetLastError();
\r
10590 *outError = DoWriteFile(((ChildProc *)pr)->hTo, message, count,
\r
10591 &dOutCount, &ovl);
\r
10592 if (*outError == NO_ERROR) {
\r
10593 outCount = (int) dOutCount;
\r
10601 OutputToProcessDelayed(ProcRef pr, char *message, int count, int *outError,
\r
10604 /* Ignore delay, not implemented for WinBoard */
\r
10605 return OutputToProcess(pr, message, count, outError);
\r
10610 CmailSigHandlerCallBack(InputSourceRef isr, VOIDSTAR closure,
\r
10611 char *buf, int count, int error)
\r
10613 DisplayFatalError("Not implemented", 0, 1);
\r
10616 /* see wgamelist.c for Game List functions */
\r
10617 /* see wedittags.c for Edit Tags functions */
\r
10624 char buf[MSG_SIZ];
\r
10627 if (SearchPath(installDir, appData.icsLogon, NULL, MSG_SIZ, buf, &dummy)) {
\r
10628 f = fopen(buf, "r");
\r
10630 ProcessICSInitScript(f);
\r
10638 StartAnalysisClock()
\r
10640 if (analysisTimerEvent) return;
\r
10641 analysisTimerEvent = SetTimer(hwndMain, (UINT) ANALYSIS_TIMER_ID,
\r
10642 (UINT) 2000, NULL);
\r
10646 AnalysisDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
10648 static HANDLE hwndText;
\r
10650 static int sizeX, sizeY;
\r
10651 int newSizeX, newSizeY, flags;
\r
10654 switch (message) {
\r
10655 case WM_INITDIALOG: /* message: initialize dialog box */
\r
10656 /* Initialize the dialog items */
\r
10657 hwndText = GetDlgItem(hDlg, OPT_AnalysisText);
\r
10658 SetWindowText(hDlg, analysisTitle);
\r
10659 SetDlgItemText(hDlg, OPT_AnalysisText, analysisText);
\r
10660 /* Size and position the dialog */
\r
10661 if (!analysisDialog) {
\r
10662 analysisDialog = hDlg;
\r
10663 flags = SWP_NOZORDER;
\r
10664 GetClientRect(hDlg, &rect);
\r
10665 sizeX = rect.right;
\r
10666 sizeY = rect.bottom;
\r
10667 if (analysisX != CW_USEDEFAULT && analysisY != CW_USEDEFAULT &&
\r
10668 analysisW != CW_USEDEFAULT && analysisH != CW_USEDEFAULT) {
\r
10669 WINDOWPLACEMENT wp;
\r
10670 EnsureOnScreen(&analysisX, &analysisY, 0, 0);
\r
10671 wp.length = sizeof(WINDOWPLACEMENT);
\r
10673 wp.showCmd = SW_SHOW;
\r
10674 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
10675 wp.rcNormalPosition.left = analysisX;
\r
10676 wp.rcNormalPosition.right = analysisX + analysisW;
\r
10677 wp.rcNormalPosition.top = analysisY;
\r
10678 wp.rcNormalPosition.bottom = analysisY + analysisH;
\r
10679 SetWindowPlacement(hDlg, &wp);
\r
10681 GetClientRect(hDlg, &rect);
\r
10682 newSizeX = rect.right;
\r
10683 newSizeY = rect.bottom;
\r
10684 ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY,
\r
10685 newSizeX, newSizeY);
\r
10686 sizeX = newSizeX;
\r
10687 sizeY = newSizeY;
\r
10692 case WM_COMMAND: /* message: received a command */
\r
10693 switch (LOWORD(wParam)) {
\r
10695 if (appData.icsActive && appData.icsEngineAnalyze) { /* [DM] icsEngineAnalyze */
\r
10696 ExitAnalyzeMode();
\r
10708 newSizeX = LOWORD(lParam);
\r
10709 newSizeY = HIWORD(lParam);
\r
10710 ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY, newSizeX, newSizeY);
\r
10711 sizeX = newSizeX;
\r
10712 sizeY = newSizeY;
\r
10715 case WM_GETMINMAXINFO:
\r
10716 /* Prevent resizing window too small */
\r
10717 mmi = (MINMAXINFO *) lParam;
\r
10718 mmi->ptMinTrackSize.x = 100;
\r
10719 mmi->ptMinTrackSize.y = 100;
\r
10726 AnalysisPopUp(char* title, char* str)
\r
10732 EngineOutputPopUp();
\r
10735 if (str == NULL) str = "";
\r
10736 p = (char *) malloc(2 * strlen(str) + 2);
\r
10739 if (*str == '\n') *q++ = '\r';
\r
10743 if (analysisText != NULL) free(analysisText);
\r
10744 analysisText = p;
\r
10746 if (analysisDialog) {
\r
10747 SetWindowText(analysisDialog, title);
\r
10748 SetDlgItemText(analysisDialog, OPT_AnalysisText, analysisText);
\r
10749 ShowWindow(analysisDialog, SW_SHOW);
\r
10751 analysisTitle = title;
\r
10752 lpProc = MakeProcInstance((FARPROC)AnalysisDialog, hInst);
\r
10753 CreateDialog(hInst, MAKEINTRESOURCE(DLG_Analysis),
\r
10754 hwndMain, (DLGPROC)lpProc);
\r
10755 FreeProcInstance(lpProc);
\r
10757 analysisDialogUp = TRUE;
\r
10761 AnalysisPopDown()
\r
10763 if (analysisDialog) {
\r
10764 ShowWindow(analysisDialog, SW_HIDE);
\r
10766 analysisDialogUp = FALSE;
\r
10771 SetHighlights(int fromX, int fromY, int toX, int toY)
\r
10773 highlightInfo.sq[0].x = fromX;
\r
10774 highlightInfo.sq[0].y = fromY;
\r
10775 highlightInfo.sq[1].x = toX;
\r
10776 highlightInfo.sq[1].y = toY;
\r
10780 ClearHighlights()
\r
10782 highlightInfo.sq[0].x = highlightInfo.sq[0].y =
\r
10783 highlightInfo.sq[1].x = highlightInfo.sq[1].y = -1;
\r
10787 SetPremoveHighlights(int fromX, int fromY, int toX, int toY)
\r
10789 premoveHighlightInfo.sq[0].x = fromX;
\r
10790 premoveHighlightInfo.sq[0].y = fromY;
\r
10791 premoveHighlightInfo.sq[1].x = toX;
\r
10792 premoveHighlightInfo.sq[1].y = toY;
\r
10796 ClearPremoveHighlights()
\r
10798 premoveHighlightInfo.sq[0].x = premoveHighlightInfo.sq[0].y =
\r
10799 premoveHighlightInfo.sq[1].x = premoveHighlightInfo.sq[1].y = -1;
\r
10803 ShutDownFrontEnd()
\r
10805 if (saveSettingsOnExit) SaveSettings(settingsFileName);
\r
10806 DeleteClipboardTempFiles();
\r
10812 if (IsIconic(hwndMain))
\r
10813 ShowWindow(hwndMain, SW_RESTORE);
\r
10815 SetActiveWindow(hwndMain);
\r
10819 * Prototypes for animation support routines
\r
10821 static void ScreenSquare(int column, int row, POINT * pt);
\r
10822 static void Tween( POINT * start, POINT * mid, POINT * finish, int factor,
\r
10823 POINT frames[], int * nFrames);
\r
10827 AnimateAtomicCapture(int fromX, int fromY, int toX, int toY, int nFrames)
\r
10828 { // [HGM] atomic: animate blast wave
\r
10830 if(appData.debugMode) fprintf(debugFP, "exploding (%d,%d)\n", toX, toY);
\r
10831 explodeInfo.fromX = fromX;
\r
10832 explodeInfo.fromY = fromY;
\r
10833 explodeInfo.toX = toX;
\r
10834 explodeInfo.toY = toY;
\r
10835 for(i=1; i<nFrames; i++) {
\r
10836 explodeInfo.radius = (i*180)/(nFrames-1);
\r
10837 DrawPosition(FALSE, NULL);
\r
10838 Sleep(appData.animSpeed);
\r
10840 explodeInfo.radius = 0;
\r
10841 DrawPosition(TRUE, NULL);
\r
10844 #define kFactor 4
\r
10847 AnimateMove(board, fromX, fromY, toX, toY)
\r
10854 ChessSquare piece;
\r
10855 POINT start, finish, mid;
\r
10856 POINT frames[kFactor * 2 + 1];
\r
10859 if (!appData.animate) return;
\r
10860 if (doingSizing) return;
\r
10861 if (fromY < 0 || fromX < 0) return;
\r
10862 piece = board[fromY][fromX];
\r
10863 if (piece >= EmptySquare) return;
\r
10865 ScreenSquare(fromX, fromY, &start);
\r
10866 ScreenSquare(toX, toY, &finish);
\r
10868 /* All pieces except knights move in straight line */
\r
10869 if (piece != WhiteKnight && piece != BlackKnight) {
\r
10870 mid.x = start.x + (finish.x - start.x) / 2;
\r
10871 mid.y = start.y + (finish.y - start.y) / 2;
\r
10873 /* Knight: make diagonal movement then straight */
\r
10874 if (abs(toY - fromY) < abs(toX - fromX)) {
\r
10875 mid.x = start.x + (finish.x - start.x) / 2;
\r
10876 mid.y = finish.y;
\r
10878 mid.x = finish.x;
\r
10879 mid.y = start.y + (finish.y - start.y) / 2;
\r
10883 /* Don't use as many frames for very short moves */
\r
10884 if (abs(toY - fromY) + abs(toX - fromX) <= 2)
\r
10885 Tween(&start, &mid, &finish, kFactor - 1, frames, &nFrames);
\r
10887 Tween(&start, &mid, &finish, kFactor, frames, &nFrames);
\r
10889 animInfo.from.x = fromX;
\r
10890 animInfo.from.y = fromY;
\r
10891 animInfo.to.x = toX;
\r
10892 animInfo.to.y = toY;
\r
10893 animInfo.lastpos = start;
\r
10894 animInfo.piece = piece;
\r
10895 for (n = 0; n < nFrames; n++) {
\r
10896 animInfo.pos = frames[n];
\r
10897 DrawPosition(FALSE, NULL);
\r
10898 animInfo.lastpos = animInfo.pos;
\r
10899 Sleep(appData.animSpeed);
\r
10901 animInfo.pos = finish;
\r
10902 DrawPosition(FALSE, NULL);
\r
10903 animInfo.piece = EmptySquare;
\r
10904 if(gameInfo.variant == VariantAtomic &&
\r
10905 (board[toY][toX] != EmptySquare || fromX != toX && (piece == WhitePawn || piece == BlackPawn) ) )
\r
10906 AnimateAtomicCapture(fromX, fromY, toX, toY, 2*nFrames);
\r
10909 /* Convert board position to corner of screen rect and color */
\r
10912 ScreenSquare(column, row, pt)
\r
10913 int column; int row; POINT * pt;
\r
10916 pt->x = lineGap + ((BOARD_WIDTH-1)-column) * (squareSize + lineGap);
\r
10917 pt->y = lineGap + row * (squareSize + lineGap);
\r
10919 pt->x = lineGap + column * (squareSize + lineGap);
\r
10920 pt->y = lineGap + ((BOARD_HEIGHT-1)-row) * (squareSize + lineGap);
\r
10924 /* Generate a series of frame coords from start->mid->finish.
\r
10925 The movement rate doubles until the half way point is
\r
10926 reached, then halves back down to the final destination,
\r
10927 which gives a nice slow in/out effect. The algorithmn
\r
10928 may seem to generate too many intermediates for short
\r
10929 moves, but remember that the purpose is to attract the
\r
10930 viewers attention to the piece about to be moved and
\r
10931 then to where it ends up. Too few frames would be less
\r
10935 Tween(start, mid, finish, factor, frames, nFrames)
\r
10936 POINT * start; POINT * mid;
\r
10937 POINT * finish; int factor;
\r
10938 POINT frames[]; int * nFrames;
\r
10940 int n, fraction = 1, count = 0;
\r
10942 /* Slow in, stepping 1/16th, then 1/8th, ... */
\r
10943 for (n = 0; n < factor; n++)
\r
10945 for (n = 0; n < factor; n++) {
\r
10946 frames[count].x = start->x + (mid->x - start->x) / fraction;
\r
10947 frames[count].y = start->y + (mid->y - start->y) / fraction;
\r
10949 fraction = fraction / 2;
\r
10953 frames[count] = *mid;
\r
10956 /* Slow out, stepping 1/2, then 1/4, ... */
\r
10958 for (n = 0; n < factor; n++) {
\r
10959 frames[count].x = finish->x - (finish->x - mid->x) / fraction;
\r
10960 frames[count].y = finish->y - (finish->y - mid->y) / fraction;
\r
10962 fraction = fraction * 2;
\r
10964 *nFrames = count;
\r
10968 HistorySet( char movelist[][2*MOVE_LEN], int first, int last, int current )
\r
10973 sprintf( buf, "HistorySet: first=%d, last=%d, current=%d (%s)\n",
\r
10974 first, last, current, current >= 0 ? movelist[current] : "n/a" );
\r
10976 OutputDebugString( buf );
\r
10979 MoveHistorySet( movelist, first, last, current, pvInfoList );
\r
10981 EvalGraphSet( first, last, current, pvInfoList );
\r
10984 void SetProgramStats( FrontEndProgramStats * stats )
\r
10989 sprintf( buf, "SetStats for %d: depth=%d, nodes=%lu, score=%5.2f, time=%5.2f, pv=%s\n",
\r
10990 stats->which, stats->depth, stats->nodes, stats->score / 100.0, stats->time / 100.0, stats->pv == 0 ? "n/a" : stats->pv );
\r
10992 OutputDebugString( buf );
\r
10995 EngineOutputUpdate( stats );
\r