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 ChessSquare piece;
\r
111 POINT pos; /* window coordinates of current pos */
\r
112 POINT lastpos; /* window coordinates of last pos - used for clipping */
\r
113 POINT from; /* board coordinates of the piece's orig pos */
\r
114 POINT to; /* board coordinates of the piece's new pos */
\r
117 static AnimInfo animInfo = { EmptySquare, {-1,-1}, {-1,-1}, {-1,-1} };
\r
120 POINT start; /* window coordinates of start pos */
\r
121 POINT pos; /* window coordinates of current pos */
\r
122 POINT lastpos; /* window coordinates of last pos - used for clipping */
\r
123 POINT from; /* board coordinates of the piece's orig pos */
\r
126 static DragInfo dragInfo = { {-1,-1}, {-1,-1}, {-1,-1}, {-1,-1} };
\r
129 POINT sq[2]; /* board coordinates of from, to squares */
\r
132 static HighlightInfo highlightInfo = { {{-1, -1}, {-1, -1}} };
\r
133 static HighlightInfo premoveHighlightInfo = { {{-1, -1}, {-1, -1}} };
\r
135 typedef struct { // [HGM] atomic
\r
136 int fromX, fromY, toX, toY, radius;
\r
139 static ExplodeInfo explodeInfo;
\r
141 /* Window class names */
\r
142 char szAppName[] = "WinBoard";
\r
143 char szConsoleName[] = "WBConsole";
\r
145 /* Title bar text */
\r
146 char szTitle[] = "WinBoard";
\r
147 char szConsoleTitle[] = "I C S Interaction";
\r
150 char *settingsFileName;
\r
151 BOOLEAN saveSettingsOnExit;
\r
152 char installDir[MSG_SIZ];
\r
154 BoardSize boardSize;
\r
155 BOOLEAN chessProgram;
\r
156 static int boardX, boardY;
\r
157 int minX, minY; // [HGM] placement: volatile limits on upper-left corner
\r
158 static int squareSize, lineGap, minorSize;
\r
159 static int winWidth, winHeight, winW, winH;
\r
160 static RECT messageRect, whiteRect, blackRect, leftLogoRect, rightLogoRect; // [HGM] logo
\r
161 static int logoHeight = 0;
\r
162 static char messageText[MESSAGE_TEXT_MAX];
\r
163 static int clockTimerEvent = 0;
\r
164 static int loadGameTimerEvent = 0;
\r
165 static int analysisTimerEvent = 0;
\r
166 static DelayedEventCallback delayedTimerCallback;
\r
167 static int delayedTimerEvent = 0;
\r
168 static int buttonCount = 2;
\r
169 char *icsTextMenuString;
\r
171 char *firstChessProgramNames;
\r
172 char *secondChessProgramNames;
\r
174 #define ARG_MAX 128*1024 /* [AS] For Roger Brown's very long list! */
\r
176 #define PALETTESIZE 256
\r
178 HINSTANCE hInst; /* current instance */
\r
179 HWND hwndMain = NULL; /* root window*/
\r
180 HWND hwndConsole = NULL;
\r
181 BOOLEAN alwaysOnTop = FALSE;
\r
183 COLORREF lightSquareColor, darkSquareColor, whitePieceColor,
\r
184 blackPieceColor, highlightSquareColor, premoveHighlightColor;
\r
186 ColorClass currentColorClass;
\r
188 HWND hCommPort = NULL; /* currently open comm port */
\r
189 static HWND hwndPause; /* pause button */
\r
190 static HBITMAP pieceBitmap[3][(int) BlackPawn]; /* [HGM] nr of bitmaps referred to bP in stead of wK */
\r
191 static HBRUSH lightSquareBrush, darkSquareBrush,
\r
192 blackSquareBrush, /* [HGM] for band between board and holdings */
\r
193 explodeBrush, /* [HGM] atomic */
\r
194 whitePieceBrush, blackPieceBrush, iconBkgndBrush /*, outlineBrush*/;
\r
195 static POINT gridEndpoints[(BOARD_SIZE + 1) * 4];
\r
196 static DWORD gridVertexCounts[(BOARD_SIZE + 1) * 2];
\r
197 static HPEN gridPen = NULL;
\r
198 static HPEN highlightPen = NULL;
\r
199 static HPEN premovePen = NULL;
\r
200 static NPLOGPALETTE pLogPal;
\r
201 static BOOL paletteChanged = FALSE;
\r
202 static HICON iconWhite, iconBlack, iconCurrent;
\r
203 static int doingSizing = FALSE;
\r
204 static int lastSizing = 0;
\r
205 static int prevStderrPort;
\r
206 static HBITMAP userLogo;
\r
208 /* [AS] Support for background textures */
\r
209 #define BACK_TEXTURE_MODE_DISABLED 0
\r
210 #define BACK_TEXTURE_MODE_PLAIN 1
\r
211 #define BACK_TEXTURE_MODE_FULL_RANDOM 2
\r
213 static HBITMAP liteBackTexture = NULL;
\r
214 static HBITMAP darkBackTexture = NULL;
\r
215 static int liteBackTextureMode = BACK_TEXTURE_MODE_PLAIN;
\r
216 static int darkBackTextureMode = BACK_TEXTURE_MODE_PLAIN;
\r
217 static int backTextureSquareSize = 0;
\r
218 static struct { int x; int y; int mode; } backTextureSquareInfo[BOARD_SIZE][BOARD_SIZE];
\r
220 #if __GNUC__ && !defined(_winmajor)
\r
221 #define oldDialog 0 /* cygwin doesn't define _winmajor; mingw does */
\r
223 #define oldDialog (_winmajor < 4)
\r
226 char *defaultTextAttribs[] =
\r
228 COLOR_SHOUT, COLOR_SSHOUT, COLOR_CHANNEL1, COLOR_CHANNEL, COLOR_KIBITZ,
\r
229 COLOR_TELL, COLOR_CHALLENGE, COLOR_REQUEST, COLOR_SEEK, COLOR_NORMAL,
\r
239 int cliWidth, cliHeight;
\r
242 SizeInfo sizeInfo[] =
\r
244 { "tiny", 21, 0, 1, 1, 0, 0 },
\r
245 { "teeny", 25, 1, 1, 1, 0, 0 },
\r
246 { "dinky", 29, 1, 1, 1, 0, 0 },
\r
247 { "petite", 33, 1, 1, 1, 0, 0 },
\r
248 { "slim", 37, 2, 1, 0, 0, 0 },
\r
249 { "small", 40, 2, 1, 0, 0, 0 },
\r
250 { "mediocre", 45, 2, 1, 0, 0, 0 },
\r
251 { "middling", 49, 2, 0, 0, 0, 0 },
\r
252 { "average", 54, 2, 0, 0, 0, 0 },
\r
253 { "moderate", 58, 3, 0, 0, 0, 0 },
\r
254 { "medium", 64, 3, 0, 0, 0, 0 },
\r
255 { "bulky", 72, 3, 0, 0, 0, 0 },
\r
256 { "large", 80, 3, 0, 0, 0, 0 },
\r
257 { "big", 87, 3, 0, 0, 0, 0 },
\r
258 { "huge", 95, 3, 0, 0, 0, 0 },
\r
259 { "giant", 108, 3, 0, 0, 0, 0 },
\r
260 { "colossal", 116, 4, 0, 0, 0, 0 },
\r
261 { "titanic", 129, 4, 0, 0, 0, 0 },
\r
262 { NULL, 0, 0, 0, 0, 0, 0 }
\r
265 #define MF(x) {x, {{0,}, 0. }, {0, }, 0}
\r
266 MyFont fontRec[NUM_SIZES][NUM_FONTS] =
\r
268 { 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
269 { 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
270 { 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
271 { 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
272 { 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
273 { 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
274 { 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
275 { 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
276 { 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
277 { 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
278 { 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
279 { 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
280 { 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
281 { 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
282 { 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
283 { 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
284 { 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
285 { 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
288 MyFont *font[NUM_SIZES][NUM_FONTS];
\r
297 #define BUTTON_WIDTH (tinyLayout ? 16 : 32)
\r
298 #define N_BUTTONS 5
\r
300 MyButtonDesc buttonDesc[N_BUTTONS] =
\r
302 {"<<", IDM_ToStart, NULL, NULL},
\r
303 {"<", IDM_Backward, NULL, NULL},
\r
304 {"P", IDM_Pause, NULL, NULL},
\r
305 {">", IDM_Forward, NULL, NULL},
\r
306 {">>", IDM_ToEnd, NULL, NULL},
\r
309 int tinyLayout = 0, smallLayout = 0;
\r
310 #define MENU_BAR_ITEMS 6
\r
311 char *menuBarText[2][MENU_BAR_ITEMS+1] = {
\r
312 { "&File", "&Mode", "&Action", "&Step", "&Options", "&Help", NULL },
\r
313 { "&F", "&M", "&A", "&S", "&O", "&H", NULL },
\r
317 MySound sounds[(int)NSoundClasses];
\r
318 MyTextAttribs textAttribs[(int)NColorClasses];
\r
320 MyColorizeAttribs colorizeAttribs[] = {
\r
321 { (COLORREF)0, 0, "Shout Text" },
\r
322 { (COLORREF)0, 0, "SShout/CShout" },
\r
323 { (COLORREF)0, 0, "Channel 1 Text" },
\r
324 { (COLORREF)0, 0, "Channel Text" },
\r
325 { (COLORREF)0, 0, "Kibitz Text" },
\r
326 { (COLORREF)0, 0, "Tell Text" },
\r
327 { (COLORREF)0, 0, "Challenge Text" },
\r
328 { (COLORREF)0, 0, "Request Text" },
\r
329 { (COLORREF)0, 0, "Seek Text" },
\r
330 { (COLORREF)0, 0, "Normal Text" },
\r
331 { (COLORREF)0, 0, "None" }
\r
336 static char *commentTitle;
\r
337 static char *commentText;
\r
338 static int commentIndex;
\r
339 static Boolean editComment = FALSE;
\r
340 HWND commentDialog = NULL;
\r
341 BOOLEAN commentDialogUp = FALSE;
\r
342 static int commentX, commentY, commentH, commentW;
\r
344 static char *analysisTitle;
\r
345 static char *analysisText;
\r
346 HWND analysisDialog = NULL;
\r
347 BOOLEAN analysisDialogUp = FALSE;
\r
348 static int analysisX, analysisY, analysisH, analysisW;
\r
350 char errorTitle[MSG_SIZ];
\r
351 char errorMessage[2*MSG_SIZ];
\r
352 HWND errorDialog = NULL;
\r
353 BOOLEAN moveErrorMessageUp = FALSE;
\r
354 BOOLEAN consoleEcho = TRUE;
\r
355 CHARFORMAT consoleCF;
\r
356 COLORREF consoleBackgroundColor;
\r
358 char *programVersion;
\r
364 typedef int CPKind;
\r
373 SOCKET sock2; /* stderr socket for OpenRcmd */
\r
376 #define INPUT_SOURCE_BUF_SIZE 4096
\r
378 typedef struct _InputSource {
\r
385 char buf[INPUT_SOURCE_BUF_SIZE];
\r
389 InputCallback func;
\r
390 struct _InputSource *second; /* for stderr thread on CPRcmd */
\r
394 InputSource *consoleInputSource;
\r
399 VOID ConsoleOutput(char* data, int length, int forceVisible);
\r
400 VOID ConsoleCreate();
\r
402 ConsoleWndProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);
\r
403 VOID ColorizeTextPopup(HWND hwnd, ColorClass cc);
\r
404 VOID PrintCommSettings(FILE *f, char *name, DCB *dcb);
\r
405 VOID ParseCommSettings(char *arg, DCB *dcb);
\r
407 StartupDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);
\r
408 VOID APIENTRY MenuPopup(HWND hwnd, POINT pt, HMENU hmenu, UINT def);
\r
409 void ParseIcsTextMenu(char *icsTextMenuString);
\r
410 VOID PopUpMoveDialog(char firstchar);
\r
411 VOID PopUpNameDialog(char firstchar);
\r
412 VOID UpdateSampleText(HWND hDlg, int id, MyColorizeAttribs *mca);
\r
416 int GameListOptions();
\r
418 HWND moveHistoryDialog = NULL;
\r
419 BOOLEAN moveHistoryDialogUp = FALSE;
\r
421 WindowPlacement wpMoveHistory;
\r
423 HWND evalGraphDialog = NULL;
\r
424 BOOLEAN evalGraphDialogUp = FALSE;
\r
426 WindowPlacement wpEvalGraph;
\r
428 HWND engineOutputDialog = NULL;
\r
429 BOOLEAN engineOutputDialogUp = FALSE;
\r
431 WindowPlacement wpEngineOutput;
\r
432 WindowPlacement wpGameList;
\r
433 WindowPlacement wpConsole;
\r
435 VOID MoveHistoryPopUp();
\r
436 VOID MoveHistoryPopDown();
\r
437 VOID MoveHistorySet( char movelist[][2*MOVE_LEN], int first, int last, int current, ChessProgramStats_Move * pvInfo );
\r
438 BOOL MoveHistoryIsUp();
\r
440 VOID EvalGraphSet( int first, int last, int current, ChessProgramStats_Move * pvInfo );
\r
441 VOID EvalGraphPopUp();
\r
442 VOID EvalGraphPopDown();
\r
443 BOOL EvalGraphIsUp();
\r
445 VOID EngineOutputPopUp();
\r
446 VOID EngineOutputPopDown();
\r
447 BOOL EngineOutputIsUp();
\r
448 VOID EngineOutputUpdate( FrontEndProgramStats * stats );
\r
450 VOID GothicPopUp(char *title, VariantClass variant);
\r
452 * Setting "frozen" should disable all user input other than deleting
\r
453 * the window. We do this while engines are initializing themselves.
\r
455 static int frozen = 0;
\r
456 static int oldMenuItemState[MENU_BAR_ITEMS];
\r
462 if (frozen) return;
\r
464 hmenu = GetMenu(hwndMain);
\r
465 for (i=0; i<MENU_BAR_ITEMS; i++) {
\r
466 oldMenuItemState[i] = EnableMenuItem(hmenu, i, MF_BYPOSITION|MF_GRAYED);
\r
468 DrawMenuBar(hwndMain);
\r
471 /* Undo a FreezeUI */
\r
477 if (!frozen) return;
\r
479 hmenu = GetMenu(hwndMain);
\r
480 for (i=0; i<MENU_BAR_ITEMS; i++) {
\r
481 EnableMenuItem(hmenu, i, MF_BYPOSITION|oldMenuItemState[i]);
\r
483 DrawMenuBar(hwndMain);
\r
486 static int fromX = -1, fromY = -1, toX, toY; // [HGM] moved upstream, so JAWS can use them
\r
488 /* JAWS preparation patch (WinBoard for the sight impaired). Define required insertions as empty */
\r
493 #define JAWS_ALT_INTERCEPT
\r
494 #define JAWS_KB_NAVIGATION
\r
495 #define JAWS_MENU_ITEMS
\r
496 #define JAWS_SILENCE
\r
497 #define JAWS_REPLAY
\r
498 #define JAWS_DELETE(X) X
\r
499 #define SAYMACHINEMOVE()
\r
503 /*---------------------------------------------------------------------------*\
\r
507 \*---------------------------------------------------------------------------*/
\r
510 WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
\r
511 LPSTR lpCmdLine, int nCmdShow)
\r
514 HANDLE hAccelMain, hAccelNoAlt, hAccelNoICS;
\r
515 // INITCOMMONCONTROLSEX ex;
\r
519 LoadLibrary("RICHED32.DLL");
\r
520 consoleCF.cbSize = sizeof(CHARFORMAT);
\r
522 if (!InitApplication(hInstance)) {
\r
525 if (!InitInstance(hInstance, nCmdShow, lpCmdLine)) {
\r
531 // InitCommonControlsEx(&ex);
\r
532 InitCommonControls();
\r
534 hAccelMain = LoadAccelerators (hInstance, szAppName);
\r
535 hAccelNoAlt = LoadAccelerators (hInstance, "NO_ALT");
\r
536 hAccelNoICS = LoadAccelerators( hInstance, "NO_ICS"); /* [AS] No Ctrl-V on ICS!!! */
\r
538 /* Acquire and dispatch messages until a WM_QUIT message is received. */
\r
540 while (GetMessage(&msg, /* message structure */
\r
541 NULL, /* handle of window receiving the message */
\r
542 0, /* lowest message to examine */
\r
543 0)) /* highest message to examine */
\r
546 if(msg.message == WM_CHAR && msg.wParam == '\t') {
\r
547 // [HGM] navigate: switch between all windows with tab
\r
548 HWND e1 = NULL, e2 = NULL, mh = NULL, hInput = NULL, hText = NULL;
\r
549 int i, currentElement = 0;
\r
551 // first determine what element of the chain we come from (if any)
\r
552 if(appData.icsActive) {
\r
553 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
554 hText = GetDlgItem(hwndConsole, OPT_ConsoleText);
\r
556 if(engineOutputDialog && EngineOutputIsUp()) {
\r
557 e1 = GetDlgItem(engineOutputDialog, IDC_EngineMemo1);
\r
558 e2 = GetDlgItem(engineOutputDialog, IDC_EngineMemo2);
\r
560 if(moveHistoryDialog && MoveHistoryIsUp()) {
\r
561 mh = GetDlgItem(moveHistoryDialog, IDC_MoveHistory);
\r
563 if(msg.hwnd == hwndMain) currentElement = 7 ; else
\r
564 if(msg.hwnd == engineOutputDialog) currentElement = 2; else
\r
565 if(msg.hwnd == e1) currentElement = 2; else
\r
566 if(msg.hwnd == e2) currentElement = 3; else
\r
567 if(msg.hwnd == moveHistoryDialog) currentElement = 4; else
\r
568 if(msg.hwnd == mh) currentElement = 4; else
\r
569 if(msg.hwnd == evalGraphDialog) currentElement = 7; else
\r
570 if(msg.hwnd == hText) currentElement = 5; else
\r
571 if(msg.hwnd == hInput) currentElement = 6; else
\r
572 for (i = 0; i < N_BUTTONS; i++) {
\r
573 if (buttonDesc[i].hwnd == msg.hwnd) { currentElement = 1; break; }
\r
576 // determine where to go to
\r
577 if(currentElement) { HWND h = NULL; int direction = GetKeyState(VK_SHIFT) < 0 ? -1 : 1;
\r
579 currentElement = (currentElement + direction) % 7;
\r
580 switch(currentElement) {
\r
582 h = hwndMain; break; // passing this case always makes the loop exit
\r
584 h = buttonDesc[0].hwnd; break; // could be NULL
\r
586 if(!EngineOutputIsUp()) continue; // skip closed auxiliary windows
\r
589 if(!EngineOutputIsUp()) continue;
\r
592 if(!MoveHistoryIsUp()) continue;
\r
594 // case 5: // input to eval graph does not seem to get here!
\r
595 // if(!EvalGraphIsUp()) continue;
\r
596 // h = evalGraphDialog; break;
\r
598 if(!appData.icsActive) continue;
\r
602 if(!appData.icsActive) continue;
\r
608 if(currentElement > 4 && IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
609 if(currentElement < 5 && IsIconic(hwndMain)) ShowWindow(hwndMain, SW_RESTORE); // all open together
\r
612 continue; // this message now has been processed
\r
616 if (!(commentDialog && IsDialogMessage(commentDialog, &msg)) &&
\r
617 !(moveHistoryDialog && IsDialogMessage(moveHistoryDialog, &msg)) &&
\r
618 !(evalGraphDialog && IsDialogMessage(evalGraphDialog, &msg)) &&
\r
619 !(engineOutputDialog && IsDialogMessage(engineOutputDialog, &msg)) &&
\r
620 !(editTagsDialog && IsDialogMessage(editTagsDialog, &msg)) &&
\r
621 !(gameListDialog && IsDialogMessage(gameListDialog, &msg)) &&
\r
622 !(errorDialog && IsDialogMessage(errorDialog, &msg)) &&
\r
623 !(!frozen && TranslateAccelerator(hwndMain, hAccelMain, &msg)) &&
\r
624 !(!hwndConsole && TranslateAccelerator(hwndMain, hAccelNoICS, &msg)) &&
\r
625 !(!hwndConsole && TranslateAccelerator(hwndMain, hAccelNoAlt, &msg))) {
\r
626 TranslateMessage(&msg); /* Translates virtual key codes */
\r
627 DispatchMessage(&msg); /* Dispatches message to window */
\r
632 return (msg.wParam); /* Returns the value from PostQuitMessage */
\r
635 /*---------------------------------------------------------------------------*\
\r
637 * Initialization functions
\r
639 \*---------------------------------------------------------------------------*/
\r
643 { // update user logo if necessary
\r
644 static char oldUserName[MSG_SIZ], *curName;
\r
646 if(appData.autoLogo) {
\r
647 curName = UserName();
\r
648 if(strcmp(curName, oldUserName)) {
\r
649 sprintf(oldUserName, "logos\\%s.bmp", curName);
\r
650 userLogo = LoadImage( 0, oldUserName, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
651 strcpy(oldUserName, curName);
\r
657 InitApplication(HINSTANCE hInstance)
\r
661 /* Fill in window class structure with parameters that describe the */
\r
664 wc.style = CS_HREDRAW | CS_VREDRAW; /* Class style(s). */
\r
665 wc.lpfnWndProc = (WNDPROC)WndProc; /* Window Procedure */
\r
666 wc.cbClsExtra = 0; /* No per-class extra data. */
\r
667 wc.cbWndExtra = 0; /* No per-window extra data. */
\r
668 wc.hInstance = hInstance; /* Owner of this class */
\r
669 wc.hIcon = LoadIcon(hInstance, "icon_white");
\r
670 wc.hCursor = LoadCursor(NULL, IDC_ARROW); /* Cursor */
\r
671 wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1); /* Default color */
\r
672 wc.lpszMenuName = szAppName; /* Menu name from .RC */
\r
673 wc.lpszClassName = szAppName; /* Name to register as */
\r
675 /* Register the window class and return success/failure code. */
\r
676 if (!RegisterClass(&wc)) return FALSE;
\r
678 wc.style = CS_HREDRAW | CS_VREDRAW;
\r
679 wc.lpfnWndProc = (WNDPROC)ConsoleWndProc;
\r
681 wc.cbWndExtra = DLGWINDOWEXTRA;
\r
682 wc.hInstance = hInstance;
\r
683 wc.hIcon = LoadIcon(hInstance, "icon_white");
\r
684 wc.hCursor = LoadCursor(NULL, IDC_ARROW);
\r
685 wc.hbrBackground = (HBRUSH)(COLOR_MENU+1);
\r
686 wc.lpszMenuName = NULL;
\r
687 wc.lpszClassName = szConsoleName;
\r
689 if (!RegisterClass(&wc)) return FALSE;
\r
694 /* Set by InitInstance, used by EnsureOnScreen */
\r
695 int screenHeight, screenWidth;
\r
698 EnsureOnScreen(int *x, int *y, int minX, int minY)
\r
700 // int gap = GetSystemMetrics(SM_CYFRAME) + GetSystemMetrics(SM_CYCAPTION);
\r
701 /* Be sure window at (x,y) is not off screen (or even mostly off screen) */
\r
702 if (*x > screenWidth - 32) *x = 0;
\r
703 if (*y > screenHeight - 32) *y = 0;
\r
704 if (*x < minX) *x = minX;
\r
705 if (*y < minY) *y = minY;
\r
709 InitInstance(HINSTANCE hInstance, int nCmdShow, LPSTR lpCmdLine)
\r
711 HWND hwnd; /* Main window handle. */
\r
713 WINDOWPLACEMENT wp;
\r
716 hInst = hInstance; /* Store instance handle in our global variable */
\r
718 if (SearchPath(NULL, "WinBoard.exe", NULL, MSG_SIZ, installDir, &filepart)) {
\r
719 *filepart = NULLCHAR;
\r
721 GetCurrentDirectory(MSG_SIZ, installDir);
\r
723 gameInfo.boardWidth = gameInfo.boardHeight = 8; // [HGM] won't have open window otherwise
\r
724 screenWidth = screenHeight = 1000; // [HGM] placement: kludge to allow calling EnsureOnScreen from InitAppData
\r
725 InitAppData(lpCmdLine); /* Get run-time parameters */
\r
726 if (appData.debugMode) {
\r
727 debugFP = fopen(appData.nameOfDebugFile, "w");
\r
728 setbuf(debugFP, NULL);
\r
733 // InitEngineUCI( installDir, &first ); // [HGM] incorporated in InitBackEnd1()
\r
734 // InitEngineUCI( installDir, &second );
\r
736 /* Create a main window for this application instance. */
\r
737 hwnd = CreateWindow(szAppName, szTitle,
\r
738 (WS_OVERLAPPEDWINDOW & ~WS_MAXIMIZEBOX),
\r
739 CW_USEDEFAULT, 0, CW_USEDEFAULT, 0,
\r
740 NULL, NULL, hInstance, NULL);
\r
743 /* If window could not be created, return "failure" */
\r
748 /* [HGM] logo: Load logos if specified (must be done before InitDrawingSizes) */
\r
749 if( appData.firstLogo && appData.firstLogo[0] != NULLCHAR) {
\r
750 first.programLogo = LoadImage( 0, appData.firstLogo, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
752 if (first.programLogo == NULL && appData.debugMode) {
\r
753 fprintf( debugFP, "Unable to load logo bitmap '%s'\n", appData.firstLogo );
\r
755 } else if(appData.autoLogo) {
\r
756 if(appData.firstDirectory && appData.firstDirectory[0]) {
\r
758 sprintf(buf, "%s/logo.bmp", appData.firstDirectory);
\r
759 first.programLogo = LoadImage( 0, buf, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
763 if( appData.secondLogo && appData.secondLogo[0] != NULLCHAR) {
\r
764 second.programLogo = LoadImage( 0, appData.secondLogo, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
766 if (second.programLogo == NULL && appData.debugMode) {
\r
767 fprintf( debugFP, "Unable to load logo bitmap '%s'\n", appData.secondLogo );
\r
769 } else if(appData.autoLogo) {
\r
771 if(appData.icsActive) { // [HGM] logo: in ICS mode second can be used for ICS
\r
772 sprintf(buf, "logos\\%s.bmp", appData.icsHost);
\r
773 second.programLogo = LoadImage( 0, buf, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
775 if(appData.secondDirectory && appData.secondDirectory[0]) {
\r
776 sprintf(buf, "%s\\logo.bmp", appData.secondDirectory);
\r
777 second.programLogo = LoadImage( 0, buf, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
783 iconWhite = LoadIcon(hInstance, "icon_white");
\r
784 iconBlack = LoadIcon(hInstance, "icon_black");
\r
785 iconCurrent = iconWhite;
\r
786 InitDrawingColors();
\r
787 screenHeight = GetSystemMetrics(SM_CYSCREEN);
\r
788 screenWidth = GetSystemMetrics(SM_CXSCREEN);
\r
789 for (ibs = (int) NUM_SIZES - 1; ibs >= 0; ibs--) {
\r
790 /* Compute window size for each board size, and use the largest
\r
791 size that fits on this screen as the default. */
\r
792 InitDrawingSizes((BoardSize)(ibs+1000), 0);
\r
793 if (boardSize == (BoardSize)-1 &&
\r
794 winH <= screenHeight
\r
795 - GetSystemMetrics(SM_CYFRAME) - GetSystemMetrics(SM_CYCAPTION) - 10
\r
796 && winW <= screenWidth) {
\r
797 boardSize = (BoardSize)ibs;
\r
801 InitDrawingSizes(boardSize, 0);
\r
803 buttonCount = GetSystemMetrics(SM_CMOUSEBUTTONS);
\r
805 /* [AS] Load textures if specified */
\r
806 ZeroMemory( &backTextureSquareInfo, sizeof(backTextureSquareInfo) );
\r
808 if( appData.liteBackTextureFile && appData.liteBackTextureFile[0] != NULLCHAR && appData.liteBackTextureFile[0] != '*' ) {
\r
809 liteBackTexture = LoadImage( 0, appData.liteBackTextureFile, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
810 liteBackTextureMode = appData.liteBackTextureMode;
\r
812 if (liteBackTexture == NULL && appData.debugMode) {
\r
813 fprintf( debugFP, "Unable to load lite texture bitmap '%s'\n", appData.liteBackTextureFile );
\r
817 if( appData.darkBackTextureFile && appData.darkBackTextureFile[0] != NULLCHAR && appData.darkBackTextureFile[0] != '*' ) {
\r
818 darkBackTexture = LoadImage( 0, appData.darkBackTextureFile, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
819 darkBackTextureMode = appData.darkBackTextureMode;
\r
821 if (darkBackTexture == NULL && appData.debugMode) {
\r
822 fprintf( debugFP, "Unable to load dark texture bitmap '%s'\n", appData.darkBackTextureFile );
\r
826 mysrandom( (unsigned) time(NULL) );
\r
828 /* [AS] Restore layout */
\r
829 if( wpMoveHistory.visible ) {
\r
830 MoveHistoryPopUp();
\r
833 if( wpEvalGraph.visible ) {
\r
837 if( wpEngineOutput.visible ) {
\r
838 EngineOutputPopUp();
\r
843 /* Make the window visible; update its client area; and return "success" */
\r
844 EnsureOnScreen(&boardX, &boardY, minX, minY);
\r
845 wp.length = sizeof(WINDOWPLACEMENT);
\r
847 wp.showCmd = nCmdShow;
\r
848 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
849 wp.rcNormalPosition.left = boardX;
\r
850 wp.rcNormalPosition.right = boardX + winWidth;
\r
851 wp.rcNormalPosition.top = boardY;
\r
852 wp.rcNormalPosition.bottom = boardY + winHeight;
\r
853 SetWindowPlacement(hwndMain, &wp);
\r
855 SetWindowPos(hwndMain, alwaysOnTop ? HWND_TOPMOST : HWND_NOTOPMOST,
\r
856 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE);
\r
860 SetWindowPos(hwndConsole, alwaysOnTop ? HWND_TOPMOST : HWND_NOTOPMOST,
\r
861 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE);
\r
863 ShowWindow(hwndConsole, nCmdShow);
\r
865 UpdateWindow(hwnd);
\r
873 ArgString, ArgInt, ArgFloat, ArgBoolean, ArgTrue, ArgFalse, ArgNone,
\r
874 ArgColor, ArgAttribs, ArgFilename, ArgBoardSize, ArgFont, ArgCommSettings,
\r
875 ArgSettingsFilename,
\r
876 ArgX, ArgY, ArgZ // [HGM] placement: for window-placement options stored relative to main window
\r
884 String *pString; // ArgString
\r
885 int *pInt; // ArgInt
\r
886 float *pFloat; // ArgFloat
\r
887 Boolean *pBoolean; // ArgBoolean
\r
888 COLORREF *pColor; // ArgColor
\r
889 ColorClass cc; // ArgAttribs
\r
890 String *pFilename; // ArgFilename
\r
891 BoardSize *pBoardSize; // ArgBoardSize
\r
892 int whichFont; // ArgFont
\r
893 DCB *pDCB; // ArgCommSettings
\r
894 String *pFilename; // ArgSettingsFilename
\r
902 ArgDescriptor argDescriptors[] = {
\r
903 /* positional arguments */
\r
904 { "loadGameFile", ArgFilename, (LPVOID) &appData.loadGameFile, FALSE },
\r
905 { "", ArgNone, NULL },
\r
906 /* keyword arguments */
\r
907 { "whitePieceColor", ArgColor, (LPVOID) &whitePieceColor, TRUE },
\r
908 { "wpc", ArgColor, (LPVOID) &whitePieceColor, FALSE },
\r
909 { "blackPieceColor", ArgColor, (LPVOID) &blackPieceColor, TRUE },
\r
910 { "bpc", ArgColor, (LPVOID) &blackPieceColor, FALSE },
\r
911 { "lightSquareColor", ArgColor, (LPVOID) &lightSquareColor, TRUE },
\r
912 { "lsc", ArgColor, (LPVOID) &lightSquareColor, FALSE },
\r
913 { "darkSquareColor", ArgColor, (LPVOID) &darkSquareColor, TRUE },
\r
914 { "dsc", ArgColor, (LPVOID) &darkSquareColor, FALSE },
\r
915 { "highlightSquareColor", ArgColor, (LPVOID) &highlightSquareColor, TRUE },
\r
916 { "hsc", ArgColor, (LPVOID) &highlightSquareColor, FALSE },
\r
917 { "premoveHighlightColor", ArgColor, (LPVOID) &premoveHighlightColor, TRUE },
\r
918 { "phc", ArgColor, (LPVOID) &premoveHighlightColor, FALSE },
\r
919 { "movesPerSession", ArgInt, (LPVOID) &appData.movesPerSession, TRUE },
\r
920 { "mps", ArgInt, (LPVOID) &appData.movesPerSession, FALSE },
\r
921 { "initString", ArgString, (LPVOID) &appData.initString, FALSE },
\r
922 { "firstInitString", ArgString, (LPVOID) &appData.initString, FALSE },
\r
923 { "secondInitString", ArgString, (LPVOID) &appData.secondInitString, FALSE },
\r
924 { "firstComputerString", ArgString, (LPVOID) &appData.firstComputerString,
\r
926 { "secondComputerString", ArgString, (LPVOID) &appData.secondComputerString,
\r
928 { "firstChessProgram", ArgFilename, (LPVOID) &appData.firstChessProgram,
\r
930 { "fcp", ArgFilename, (LPVOID) &appData.firstChessProgram, FALSE },
\r
931 { "secondChessProgram", ArgFilename, (LPVOID) &appData.secondChessProgram,
\r
933 { "scp", ArgFilename, (LPVOID) &appData.secondChessProgram, FALSE },
\r
934 { "firstPlaysBlack", ArgBoolean, (LPVOID) &appData.firstPlaysBlack, FALSE },
\r
935 { "fb", ArgTrue, (LPVOID) &appData.firstPlaysBlack, FALSE },
\r
936 { "xfb", ArgFalse, (LPVOID) &appData.firstPlaysBlack, FALSE },
\r
937 { "-fb", ArgFalse, (LPVOID) &appData.firstPlaysBlack, FALSE },
\r
938 { "noChessProgram", ArgBoolean, (LPVOID) &appData.noChessProgram, FALSE },
\r
939 { "ncp", ArgTrue, (LPVOID) &appData.noChessProgram, FALSE },
\r
940 { "xncp", ArgFalse, (LPVOID) &appData.noChessProgram, FALSE },
\r
941 { "-ncp", ArgFalse, (LPVOID) &appData.noChessProgram, FALSE },
\r
942 { "firstHost", ArgString, (LPVOID) &appData.firstHost, FALSE },
\r
943 { "fh", ArgString, (LPVOID) &appData.firstHost, FALSE },
\r
944 { "secondHost", ArgString, (LPVOID) &appData.secondHost, FALSE },
\r
945 { "sh", ArgString, (LPVOID) &appData.secondHost, FALSE },
\r
946 { "firstDirectory", ArgFilename, (LPVOID) &appData.firstDirectory, FALSE },
\r
947 { "fd", ArgFilename, (LPVOID) &appData.firstDirectory, FALSE },
\r
948 { "secondDirectory", ArgFilename, (LPVOID) &appData.secondDirectory, FALSE },
\r
949 { "sd", ArgFilename, (LPVOID) &appData.secondDirectory, FALSE },
\r
950 /*!!bitmapDirectory?*/
\r
951 { "remoteShell", ArgFilename, (LPVOID) &appData.remoteShell, FALSE },
\r
952 { "rsh", ArgFilename, (LPVOID) &appData.remoteShell, FALSE },
\r
953 { "remoteUser", ArgString, (LPVOID) &appData.remoteUser, FALSE },
\r
954 { "ruser", ArgString, (LPVOID) &appData.remoteUser, FALSE },
\r
955 { "timeDelay", ArgFloat, (LPVOID) &appData.timeDelay, TRUE },
\r
956 { "td", ArgFloat, (LPVOID) &appData.timeDelay, FALSE },
\r
957 { "timeControl", ArgString, (LPVOID) &appData.timeControl, TRUE },
\r
958 { "tc", ArgString, (LPVOID) &appData.timeControl, FALSE },
\r
959 { "timeIncrement", ArgInt, (LPVOID) &appData.timeIncrement, TRUE },
\r
960 { "inc", ArgInt, (LPVOID) &appData.timeIncrement, FALSE },
\r
961 { "internetChessServerMode", ArgBoolean, (LPVOID) &appData.icsActive, FALSE },
\r
962 { "ics", ArgTrue, (LPVOID) &appData.icsActive, FALSE },
\r
963 { "xics", ArgFalse, (LPVOID) &appData.icsActive, FALSE },
\r
964 { "-ics", ArgFalse, (LPVOID) &appData.icsActive, FALSE },
\r
965 { "internetChessServerHost", ArgString, (LPVOID) &appData.icsHost, FALSE },
\r
966 { "icshost", ArgString, (LPVOID) &appData.icsHost, FALSE },
\r
967 { "internetChessServerPort", ArgString, (LPVOID) &appData.icsPort, FALSE },
\r
968 { "icsport", ArgString, (LPVOID) &appData.icsPort, FALSE },
\r
969 { "internetChessServerCommPort", ArgString, (LPVOID) &appData.icsCommPort, FALSE },
\r
970 { "icscomm", ArgString, (LPVOID) &appData.icsCommPort, FALSE },
\r
971 { "internetChessServerComPort", ArgString, (LPVOID) &appData.icsCommPort, FALSE },
\r
972 { "icscom", ArgString, (LPVOID) &appData.icsCommPort, FALSE },
\r
973 { "internetChessServerLogonScript", ArgFilename, (LPVOID) &appData.icsLogon, FALSE },
\r
974 { "icslogon", ArgFilename, (LPVOID) &appData.icsLogon, FALSE },
\r
975 { "useTelnet", ArgBoolean, (LPVOID) &appData.useTelnet, FALSE },
\r
976 { "telnet", ArgTrue, (LPVOID) &appData.useTelnet, FALSE },
\r
977 { "xtelnet", ArgFalse, (LPVOID) &appData.useTelnet, FALSE },
\r
978 { "-telnet", ArgFalse, (LPVOID) &appData.useTelnet, FALSE },
\r
979 { "telnetProgram", ArgFilename, (LPVOID) &appData.telnetProgram, FALSE },
\r
980 { "icshelper", ArgFilename, (LPVOID) &appData.icsHelper, FALSE },
\r
981 { "gateway", ArgString, (LPVOID) &appData.gateway, FALSE },
\r
982 { "loadGameFile", ArgFilename, (LPVOID) &appData.loadGameFile, FALSE },
\r
983 { "lgf", ArgFilename, (LPVOID) &appData.loadGameFile, FALSE },
\r
984 { "loadGameIndex", ArgInt, (LPVOID) &appData.loadGameIndex, FALSE },
\r
985 { "lgi", ArgInt, (LPVOID) &appData.loadGameIndex, FALSE },
\r
986 { "saveGameFile", ArgFilename, (LPVOID) &appData.saveGameFile, TRUE },
\r
987 { "sgf", ArgFilename, (LPVOID) &appData.saveGameFile, FALSE },
\r
988 { "autoSaveGames", ArgBoolean, (LPVOID) &appData.autoSaveGames, TRUE },
\r
989 { "autosave", ArgTrue, (LPVOID) &appData.autoSaveGames, FALSE },
\r
990 { "xautosave", ArgFalse, (LPVOID) &appData.autoSaveGames, FALSE },
\r
991 { "-autosave", ArgFalse, (LPVOID) &appData.autoSaveGames, FALSE },
\r
992 { "loadPositionFile", ArgFilename, (LPVOID) &appData.loadPositionFile, FALSE },
\r
993 { "lpf", ArgFilename, (LPVOID) &appData.loadPositionFile, FALSE },
\r
994 { "loadPositionIndex", ArgInt, (LPVOID) &appData.loadPositionIndex, FALSE },
\r
995 { "lpi", ArgInt, (LPVOID) &appData.loadPositionIndex, FALSE },
\r
996 { "savePositionFile", ArgFilename, (LPVOID) &appData.savePositionFile, FALSE },
\r
997 { "spf", ArgFilename, (LPVOID) &appData.savePositionFile, FALSE },
\r
998 { "matchMode", ArgBoolean, (LPVOID) &appData.matchMode, FALSE },
\r
999 { "mm", ArgTrue, (LPVOID) &appData.matchMode, FALSE },
\r
1000 { "xmm", ArgFalse, (LPVOID) &appData.matchMode, FALSE },
\r
1001 { "-mm", ArgFalse, (LPVOID) &appData.matchMode, FALSE },
\r
1002 { "matchGames", ArgInt, (LPVOID) &appData.matchGames, FALSE },
\r
1003 { "mg", ArgInt, (LPVOID) &appData.matchGames, FALSE },
\r
1004 { "monoMode", ArgBoolean, (LPVOID) &appData.monoMode, TRUE },
\r
1005 { "mono", ArgTrue, (LPVOID) &appData.monoMode, FALSE },
\r
1006 { "xmono", ArgFalse, (LPVOID) &appData.monoMode, FALSE },
\r
1007 { "-mono", ArgFalse, (LPVOID) &appData.monoMode, FALSE },
\r
1008 { "debugMode", ArgBoolean, (LPVOID) &appData.debugMode, FALSE },
\r
1009 { "debug", ArgTrue, (LPVOID) &appData.debugMode, FALSE },
\r
1010 { "xdebug", ArgFalse, (LPVOID) &appData.debugMode, FALSE },
\r
1011 { "-debug", ArgFalse, (LPVOID) &appData.debugMode, FALSE },
\r
1012 { "clockMode", ArgBoolean, (LPVOID) &appData.clockMode, FALSE },
\r
1013 { "clock", ArgTrue, (LPVOID) &appData.clockMode, FALSE },
\r
1014 { "xclock", ArgFalse, (LPVOID) &appData.clockMode, FALSE },
\r
1015 { "-clock", ArgFalse, (LPVOID) &appData.clockMode, FALSE },
\r
1016 { "searchTime", ArgString, (LPVOID) &appData.searchTime, FALSE },
\r
1017 { "st", ArgString, (LPVOID) &appData.searchTime, FALSE },
\r
1018 { "searchDepth", ArgInt, (LPVOID) &appData.searchDepth, FALSE },
\r
1019 { "depth", ArgInt, (LPVOID) &appData.searchDepth, FALSE },
\r
1020 { "showCoords", ArgBoolean, (LPVOID) &appData.showCoords, TRUE },
\r
1021 { "coords", ArgTrue, (LPVOID) &appData.showCoords, FALSE },
\r
1022 { "xcoords", ArgFalse, (LPVOID) &appData.showCoords, FALSE },
\r
1023 { "-coords", ArgFalse, (LPVOID) &appData.showCoords, FALSE },
\r
1024 { "showThinking", ArgBoolean, (LPVOID) &appData.showThinking, TRUE },
\r
1025 { "thinking", ArgTrue, (LPVOID) &appData.showThinking, FALSE },
\r
1026 { "xthinking", ArgFalse, (LPVOID) &appData.showThinking, FALSE },
\r
1027 { "-thinking", ArgFalse, (LPVOID) &appData.showThinking, FALSE },
\r
1028 { "ponderNextMove", ArgBoolean, (LPVOID) &appData.ponderNextMove, TRUE },
\r
1029 { "ponder", ArgTrue, (LPVOID) &appData.ponderNextMove, FALSE },
\r
1030 { "xponder", ArgFalse, (LPVOID) &appData.ponderNextMove, FALSE },
\r
1031 { "-ponder", ArgFalse, (LPVOID) &appData.ponderNextMove, FALSE },
\r
1032 { "periodicUpdates", ArgBoolean, (LPVOID) &appData.periodicUpdates, TRUE },
\r
1033 { "periodic", ArgTrue, (LPVOID) &appData.periodicUpdates, FALSE },
\r
1034 { "xperiodic", ArgFalse, (LPVOID) &appData.periodicUpdates, FALSE },
\r
1035 { "-periodic", ArgFalse, (LPVOID) &appData.periodicUpdates, FALSE },
\r
1036 { "popupExitMessage", ArgBoolean, (LPVOID) &appData.popupExitMessage, TRUE },
\r
1037 { "exit", ArgTrue, (LPVOID) &appData.popupExitMessage, FALSE },
\r
1038 { "xexit", ArgFalse, (LPVOID) &appData.popupExitMessage, FALSE },
\r
1039 { "-exit", ArgFalse, (LPVOID) &appData.popupExitMessage, FALSE },
\r
1040 { "popupMoveErrors", ArgBoolean, (LPVOID) &appData.popupMoveErrors, TRUE },
\r
1041 { "popup", ArgTrue, (LPVOID) &appData.popupMoveErrors, FALSE },
\r
1042 { "xpopup", ArgFalse, (LPVOID) &appData.popupMoveErrors, FALSE },
\r
1043 { "-popup", ArgFalse, (LPVOID) &appData.popupMoveErrors, FALSE },
\r
1044 { "popUpErrors", ArgBoolean, (LPVOID) &appData.popupMoveErrors,
\r
1045 FALSE }, /* only so that old WinBoard.ini files from betas can be read */
\r
1046 { "clockFont", ArgFont, (LPVOID) CLOCK_FONT, TRUE },
\r
1047 { "messageFont", ArgFont, (LPVOID) MESSAGE_FONT, TRUE },
\r
1048 { "coordFont", ArgFont, (LPVOID) COORD_FONT, TRUE },
\r
1049 { "tagsFont", ArgFont, (LPVOID) EDITTAGS_FONT, TRUE },
\r
1050 { "commentFont", ArgFont, (LPVOID) COMMENT_FONT, TRUE },
\r
1051 { "icsFont", ArgFont, (LPVOID) CONSOLE_FONT, TRUE },
\r
1052 { "moveHistoryFont", ArgFont, (LPVOID) MOVEHISTORY_FONT, TRUE }, /* [AS] */
\r
1053 { "boardSize", ArgBoardSize, (LPVOID) &boardSize,
\r
1054 TRUE }, /* must come after all fonts */
\r
1055 { "size", ArgBoardSize, (LPVOID) &boardSize, FALSE },
\r
1056 { "ringBellAfterMoves", ArgBoolean, (LPVOID) &appData.ringBellAfterMoves,
\r
1057 FALSE }, /* historical; kept only so old winboard.ini files will parse */
\r
1058 { "alwaysOnTop", ArgBoolean, (LPVOID) &alwaysOnTop, TRUE },
\r
1059 { "top", ArgTrue, (LPVOID) &alwaysOnTop, FALSE },
\r
1060 { "xtop", ArgFalse, (LPVOID) &alwaysOnTop, FALSE },
\r
1061 { "-top", ArgFalse, (LPVOID) &alwaysOnTop, FALSE },
\r
1062 { "autoCallFlag", ArgBoolean, (LPVOID) &appData.autoCallFlag, TRUE },
\r
1063 { "autoflag", ArgTrue, (LPVOID) &appData.autoCallFlag, FALSE },
\r
1064 { "xautoflag", ArgFalse, (LPVOID) &appData.autoCallFlag, FALSE },
\r
1065 { "-autoflag", ArgFalse, (LPVOID) &appData.autoCallFlag, FALSE },
\r
1066 { "autoComment", ArgBoolean, (LPVOID) &appData.autoComment, TRUE },
\r
1067 { "autocomm", ArgTrue, (LPVOID) &appData.autoComment, FALSE },
\r
1068 { "xautocomm", ArgFalse, (LPVOID) &appData.autoComment, FALSE },
\r
1069 { "-autocomm", ArgFalse, (LPVOID) &appData.autoComment, FALSE },
\r
1070 { "autoObserve", ArgBoolean, (LPVOID) &appData.autoObserve, TRUE },
\r
1071 { "autobs", ArgTrue, (LPVOID) &appData.autoObserve, FALSE },
\r
1072 { "xautobs", ArgFalse, (LPVOID) &appData.autoObserve, FALSE },
\r
1073 { "-autobs", ArgFalse, (LPVOID) &appData.autoObserve, FALSE },
\r
1074 { "flipView", ArgBoolean, (LPVOID) &appData.flipView, FALSE },
\r
1075 { "flip", ArgTrue, (LPVOID) &appData.flipView, FALSE },
\r
1076 { "xflip", ArgFalse, (LPVOID) &appData.flipView, FALSE },
\r
1077 { "-flip", ArgFalse, (LPVOID) &appData.flipView, FALSE },
\r
1078 { "autoFlipView", ArgBoolean, (LPVOID) &appData.autoFlipView, TRUE },
\r
1079 { "autoflip", ArgTrue, (LPVOID) &appData.autoFlipView, FALSE },
\r
1080 { "xautoflip", ArgFalse, (LPVOID) &appData.autoFlipView, FALSE },
\r
1081 { "-autoflip", ArgFalse, (LPVOID) &appData.autoFlipView, FALSE },
\r
1082 { "autoRaiseBoard", ArgBoolean, (LPVOID) &appData.autoRaiseBoard, TRUE },
\r
1083 { "autoraise", ArgTrue, (LPVOID) &appData.autoRaiseBoard, FALSE },
\r
1084 { "xautoraise", ArgFalse, (LPVOID) &appData.autoRaiseBoard, FALSE },
\r
1085 { "-autoraise", ArgFalse, (LPVOID) &appData.autoRaiseBoard, FALSE },
\r
1087 { "cmailGameName", ArgString, (LPVOID) &appData.cmailGameName, FALSE },
\r
1088 { "cmail", ArgString, (LPVOID) &appData.cmailGameName, FALSE },
\r
1090 { "alwaysPromoteToQueen", ArgBoolean, (LPVOID) &appData.alwaysPromoteToQueen, TRUE },
\r
1091 { "queen", ArgTrue, (LPVOID) &appData.alwaysPromoteToQueen, FALSE },
\r
1092 { "xqueen", ArgFalse, (LPVOID) &appData.alwaysPromoteToQueen, FALSE },
\r
1093 { "-queen", ArgFalse, (LPVOID) &appData.alwaysPromoteToQueen, FALSE },
\r
1094 { "oldSaveStyle", ArgBoolean, (LPVOID) &appData.oldSaveStyle, TRUE },
\r
1095 { "oldsave", ArgTrue, (LPVOID) &appData.oldSaveStyle, FALSE },
\r
1096 { "xoldsave", ArgFalse, (LPVOID) &appData.oldSaveStyle, FALSE },
\r
1097 { "-oldsave", ArgFalse, (LPVOID) &appData.oldSaveStyle, FALSE },
\r
1098 { "quietPlay", ArgBoolean, (LPVOID) &appData.quietPlay, TRUE },
\r
1099 { "quiet", ArgTrue, (LPVOID) &appData.quietPlay, FALSE },
\r
1100 { "xquiet", ArgFalse, (LPVOID) &appData.quietPlay, FALSE },
\r
1101 { "-quiet", ArgFalse, (LPVOID) &appData.quietPlay, FALSE },
\r
1102 { "getMoveList", ArgBoolean, (LPVOID) &appData.getMoveList, TRUE },
\r
1103 { "moves", ArgTrue, (LPVOID) &appData.getMoveList, FALSE },
\r
1104 { "xmoves", ArgFalse, (LPVOID) &appData.getMoveList, FALSE },
\r
1105 { "-moves", ArgFalse, (LPVOID) &appData.getMoveList, FALSE },
\r
1106 { "testLegality", ArgBoolean, (LPVOID) &appData.testLegality, TRUE },
\r
1107 { "legal", ArgTrue, (LPVOID) &appData.testLegality, FALSE },
\r
1108 { "xlegal", ArgFalse, (LPVOID) &appData.testLegality, FALSE },
\r
1109 { "-legal", ArgFalse, (LPVOID) &appData.testLegality, FALSE },
\r
1110 { "premove", ArgBoolean, (LPVOID) &appData.premove, TRUE },
\r
1111 { "pre", ArgTrue, (LPVOID) &appData.premove, FALSE },
\r
1112 { "xpre", ArgFalse, (LPVOID) &appData.premove, FALSE },
\r
1113 { "-pre", ArgFalse, (LPVOID) &appData.premove, FALSE },
\r
1114 { "premoveWhite", ArgBoolean, (LPVOID) &appData.premoveWhite, TRUE },
\r
1115 { "prewhite", ArgTrue, (LPVOID) &appData.premoveWhite, FALSE },
\r
1116 { "xprewhite", ArgFalse, (LPVOID) &appData.premoveWhite, FALSE },
\r
1117 { "-prewhite", ArgFalse, (LPVOID) &appData.premoveWhite, FALSE },
\r
1118 { "premoveWhiteText", ArgString, (LPVOID) &appData.premoveWhiteText, TRUE },
\r
1119 { "premoveBlack", ArgBoolean, (LPVOID) &appData.premoveBlack, TRUE },
\r
1120 { "preblack", ArgTrue, (LPVOID) &appData.premoveBlack, FALSE },
\r
1121 { "xpreblack", ArgFalse, (LPVOID) &appData.premoveBlack, FALSE },
\r
1122 { "-preblack", ArgFalse, (LPVOID) &appData.premoveBlack, FALSE },
\r
1123 { "premoveBlackText", ArgString, (LPVOID) &appData.premoveBlackText, TRUE },
\r
1124 { "icsAlarm", ArgBoolean, (LPVOID) &appData.icsAlarm, TRUE},
\r
1125 { "alarm", ArgTrue, (LPVOID) &appData.icsAlarm, FALSE},
\r
1126 { "xalarm", ArgFalse, (LPVOID) &appData.icsAlarm, FALSE},
\r
1127 { "-alarm", ArgFalse, (LPVOID) &appData.icsAlarm, FALSE},
\r
1128 { "icsAlarmTime", ArgInt, (LPVOID) &appData.icsAlarmTime, TRUE},
\r
1129 { "localLineEditing", ArgBoolean, (LPVOID) &appData.localLineEditing, FALSE},
\r
1130 { "localLineEditing", ArgBoolean, (LPVOID) &appData.localLineEditing, FALSE},
\r
1131 { "edit", ArgTrue, (LPVOID) &appData.localLineEditing, FALSE },
\r
1132 { "xedit", ArgFalse, (LPVOID) &appData.localLineEditing, FALSE },
\r
1133 { "-edit", ArgFalse, (LPVOID) &appData.localLineEditing, FALSE },
\r
1134 { "animateMoving", ArgBoolean, (LPVOID) &appData.animate, TRUE },
\r
1135 { "animate", ArgTrue, (LPVOID) &appData.animate, FALSE },
\r
1136 { "xanimate", ArgFalse, (LPVOID) &appData.animate, FALSE },
\r
1137 { "-animate", ArgFalse, (LPVOID) &appData.animate, FALSE },
\r
1138 { "animateSpeed", ArgInt, (LPVOID) &appData.animSpeed, TRUE },
\r
1139 { "animateDragging", ArgBoolean, (LPVOID) &appData.animateDragging, TRUE },
\r
1140 { "drag", ArgTrue, (LPVOID) &appData.animateDragging, FALSE },
\r
1141 { "xdrag", ArgFalse, (LPVOID) &appData.animateDragging, FALSE },
\r
1142 { "-drag", ArgFalse, (LPVOID) &appData.animateDragging, FALSE },
\r
1143 { "blindfold", ArgBoolean, (LPVOID) &appData.blindfold, TRUE },
\r
1144 { "blind", ArgTrue, (LPVOID) &appData.blindfold, FALSE },
\r
1145 { "xblind", ArgFalse, (LPVOID) &appData.blindfold, FALSE },
\r
1146 { "-blind", ArgFalse, (LPVOID) &appData.blindfold, FALSE },
\r
1147 { "highlightLastMove", ArgBoolean,
\r
1148 (LPVOID) &appData.highlightLastMove, TRUE },
\r
1149 { "highlight", ArgTrue, (LPVOID) &appData.highlightLastMove, FALSE },
\r
1150 { "xhighlight", ArgFalse, (LPVOID) &appData.highlightLastMove, FALSE },
\r
1151 { "-highlight", ArgFalse, (LPVOID) &appData.highlightLastMove, FALSE },
\r
1152 { "highlightDragging", ArgBoolean,
\r
1153 (LPVOID) &appData.highlightDragging, TRUE },
\r
1154 { "highdrag", ArgTrue, (LPVOID) &appData.highlightDragging, FALSE },
\r
1155 { "xhighdrag", ArgFalse, (LPVOID) &appData.highlightDragging, FALSE },
\r
1156 { "-highdrag", ArgFalse, (LPVOID) &appData.highlightDragging, FALSE },
\r
1157 { "colorizeMessages", ArgBoolean, (LPVOID) &appData.colorize, TRUE },
\r
1158 { "colorize", ArgTrue, (LPVOID) &appData.colorize, FALSE },
\r
1159 { "xcolorize", ArgFalse, (LPVOID) &appData.colorize, FALSE },
\r
1160 { "-colorize", ArgFalse, (LPVOID) &appData.colorize, FALSE },
\r
1161 { "colorShout", ArgAttribs, (LPVOID) ColorShout, TRUE },
\r
1162 { "colorSShout", ArgAttribs, (LPVOID) ColorSShout, TRUE },
\r
1163 { "colorChannel1", ArgAttribs, (LPVOID) ColorChannel1, TRUE },
\r
1164 { "colorChannel", ArgAttribs, (LPVOID) ColorChannel, TRUE },
\r
1165 { "colorKibitz", ArgAttribs, (LPVOID) ColorKibitz, TRUE },
\r
1166 { "colorTell", ArgAttribs, (LPVOID) ColorTell, TRUE },
\r
1167 { "colorChallenge", ArgAttribs, (LPVOID) ColorChallenge, TRUE },
\r
1168 { "colorRequest", ArgAttribs, (LPVOID) ColorRequest, TRUE },
\r
1169 { "colorSeek", ArgAttribs, (LPVOID) ColorSeek, TRUE },
\r
1170 { "colorNormal", ArgAttribs, (LPVOID) ColorNormal, TRUE },
\r
1171 { "colorBackground", ArgColor, (LPVOID) &consoleBackgroundColor, TRUE },
\r
1172 { "soundShout", ArgFilename,
\r
1173 (LPVOID) &textAttribs[ColorShout].sound.name, TRUE },
\r
1174 { "soundSShout", ArgFilename,
\r
1175 (LPVOID) &textAttribs[ColorSShout].sound.name, TRUE },
\r
1176 { "soundChannel1", ArgFilename,
\r
1177 (LPVOID) &textAttribs[ColorChannel1].sound.name, TRUE },
\r
1178 { "soundChannel", ArgFilename,
\r
1179 (LPVOID) &textAttribs[ColorChannel].sound.name, TRUE },
\r
1180 { "soundKibitz", ArgFilename,
\r
1181 (LPVOID) &textAttribs[ColorKibitz].sound.name, TRUE },
\r
1182 { "soundTell", ArgFilename,
\r
1183 (LPVOID) &textAttribs[ColorTell].sound.name, TRUE },
\r
1184 { "soundChallenge", ArgFilename,
\r
1185 (LPVOID) &textAttribs[ColorChallenge].sound.name, TRUE },
\r
1186 { "soundRequest", ArgFilename,
\r
1187 (LPVOID) &textAttribs[ColorRequest].sound.name, TRUE },
\r
1188 { "soundSeek", ArgFilename,
\r
1189 (LPVOID) &textAttribs[ColorSeek].sound.name, TRUE },
\r
1190 { "soundMove", ArgFilename, (LPVOID) &sounds[(int)SoundMove].name, TRUE },
\r
1191 { "soundBell", ArgFilename, (LPVOID) &sounds[(int)SoundBell].name, TRUE },
\r
1192 { "soundIcsWin", ArgFilename, (LPVOID) &sounds[(int)SoundIcsWin].name,TRUE },
\r
1193 { "soundIcsLoss", ArgFilename,
\r
1194 (LPVOID) &sounds[(int)SoundIcsLoss].name, TRUE },
\r
1195 { "soundIcsDraw", ArgFilename,
\r
1196 (LPVOID) &sounds[(int)SoundIcsDraw].name, TRUE },
\r
1197 { "soundIcsUnfinished", ArgFilename,
\r
1198 (LPVOID) &sounds[(int)SoundIcsUnfinished].name, TRUE},
\r
1199 { "soundIcsAlarm", ArgFilename,
\r
1200 (LPVOID) &sounds[(int)SoundAlarm].name, TRUE },
\r
1201 { "reuseFirst", ArgBoolean, (LPVOID) &appData.reuseFirst, FALSE },
\r
1202 { "reuse", ArgTrue, (LPVOID) &appData.reuseFirst, FALSE },
\r
1203 { "xreuse", ArgFalse, (LPVOID) &appData.reuseFirst, FALSE },
\r
1204 { "-reuse", ArgFalse, (LPVOID) &appData.reuseFirst, FALSE },
\r
1205 { "reuseChessPrograms", ArgBoolean,
\r
1206 (LPVOID) &appData.reuseFirst, FALSE }, /* backward compat only */
\r
1207 { "reuseSecond", ArgBoolean, (LPVOID) &appData.reuseSecond, FALSE },
\r
1208 { "reuse2", ArgTrue, (LPVOID) &appData.reuseSecond, FALSE },
\r
1209 { "xreuse2", ArgFalse, (LPVOID) &appData.reuseSecond, FALSE },
\r
1210 { "-reuse2", ArgFalse, (LPVOID) &appData.reuseSecond, FALSE },
\r
1211 { "comPortSettings", ArgCommSettings, (LPVOID) &dcb, TRUE },
\r
1212 { "settingsFile", ArgSettingsFilename, (LPVOID) &settingsFileName, FALSE },
\r
1213 { "ini", ArgSettingsFilename, (LPVOID) &settingsFileName, FALSE },
\r
1214 { "saveSettingsOnExit", ArgBoolean, (LPVOID) &saveSettingsOnExit, TRUE },
\r
1215 { "chessProgram", ArgBoolean, (LPVOID) &chessProgram, FALSE },
\r
1216 { "cp", ArgTrue, (LPVOID) &chessProgram, FALSE },
\r
1217 { "xcp", ArgFalse, (LPVOID) &chessProgram, FALSE },
\r
1218 { "-cp", ArgFalse, (LPVOID) &chessProgram, FALSE },
\r
1219 { "icsMenu", ArgString, (LPVOID) &icsTextMenuString, TRUE },
\r
1220 { "icsNames", ArgString, (LPVOID) &icsNames, TRUE },
\r
1221 { "firstChessProgramNames", ArgString, (LPVOID) &firstChessProgramNames,
\r
1223 { "secondChessProgramNames", ArgString, (LPVOID) &secondChessProgramNames,
\r
1225 { "initialMode", ArgString, (LPVOID) &appData.initialMode, FALSE },
\r
1226 { "mode", ArgString, (LPVOID) &appData.initialMode, FALSE },
\r
1227 { "variant", ArgString, (LPVOID) &appData.variant, FALSE },
\r
1228 { "firstProtocolVersion", ArgInt, (LPVOID) &appData.firstProtocolVersion, FALSE },
\r
1229 { "secondProtocolVersion", ArgInt, (LPVOID) &appData.secondProtocolVersion,FALSE },
\r
1230 { "showButtonBar", ArgBoolean, (LPVOID) &appData.showButtonBar, TRUE },
\r
1231 { "buttons", ArgTrue, (LPVOID) &appData.showButtonBar, FALSE },
\r
1232 { "xbuttons", ArgFalse, (LPVOID) &appData.showButtonBar, FALSE },
\r
1233 { "-buttons", ArgFalse, (LPVOID) &appData.showButtonBar, FALSE },
\r
1234 /* [AS] New features */
\r
1235 { "firstScoreAbs", ArgBoolean, (LPVOID) &appData.firstScoreIsAbsolute, FALSE },
\r
1236 { "secondScoreAbs", ArgBoolean, (LPVOID) &appData.secondScoreIsAbsolute, FALSE },
\r
1237 { "pgnExtendedInfo", ArgBoolean, (LPVOID) &appData.saveExtendedInfoInPGN, TRUE },
\r
1238 { "hideThinkingFromHuman", ArgBoolean, (LPVOID) &appData.hideThinkingFromHuman, TRUE },
\r
1239 { "liteBackTextureFile", ArgString, (LPVOID) &appData.liteBackTextureFile, TRUE },
\r
1240 { "darkBackTextureFile", ArgString, (LPVOID) &appData.darkBackTextureFile, TRUE },
\r
1241 { "liteBackTextureMode", ArgInt, (LPVOID) &appData.liteBackTextureMode, TRUE },
\r
1242 { "darkBackTextureMode", ArgInt, (LPVOID) &appData.darkBackTextureMode, TRUE },
\r
1243 { "renderPiecesWithFont", ArgString, (LPVOID) &appData.renderPiecesWithFont, TRUE },
\r
1244 { "fontPieceToCharTable", ArgString, (LPVOID) &appData.fontToPieceTable, TRUE },
\r
1245 { "fontPieceBackColorWhite", ArgColor, (LPVOID) &appData.fontBackColorWhite, TRUE },
\r
1246 { "fontPieceForeColorWhite", ArgColor, (LPVOID) &appData.fontForeColorWhite, TRUE },
\r
1247 { "fontPieceBackColorBlack", ArgColor, (LPVOID) &appData.fontBackColorBlack, TRUE },
\r
1248 { "fontPieceForeColorBlack", ArgColor, (LPVOID) &appData.fontForeColorBlack, TRUE },
\r
1249 { "fontPieceSize", ArgInt, (LPVOID) &appData.fontPieceSize, TRUE },
\r
1250 { "overrideLineGap", ArgInt, (LPVOID) &appData.overrideLineGap, TRUE },
\r
1251 { "adjudicateLossThreshold", ArgInt, (LPVOID) &appData.adjudicateLossThreshold, TRUE },
\r
1252 { "delayBeforeQuit", ArgInt, (LPVOID) &appData.delayBeforeQuit, TRUE },
\r
1253 { "delayAfterQuit", ArgInt, (LPVOID) &appData.delayAfterQuit, TRUE },
\r
1254 { "nameOfDebugFile", ArgFilename, (LPVOID) &appData.nameOfDebugFile, FALSE },
\r
1255 { "debugfile", ArgFilename, (LPVOID) &appData.nameOfDebugFile, FALSE },
\r
1256 { "pgnEventHeader", ArgString, (LPVOID) &appData.pgnEventHeader, TRUE },
\r
1257 { "defaultFrcPosition", ArgInt, (LPVOID) &appData.defaultFrcPosition, TRUE },
\r
1258 { "gameListTags", ArgString, (LPVOID) &appData.gameListTags, TRUE },
\r
1259 { "saveOutOfBookInfo", ArgBoolean, (LPVOID) &appData.saveOutOfBookInfo, TRUE },
\r
1260 { "showEvalInMoveHistory", ArgBoolean, (LPVOID) &appData.showEvalInMoveHistory, TRUE },
\r
1261 { "evalHistColorWhite", ArgColor, (LPVOID) &appData.evalHistColorWhite, TRUE },
\r
1262 { "evalHistColorBlack", ArgColor, (LPVOID) &appData.evalHistColorBlack, TRUE },
\r
1263 { "highlightMoveWithArrow", ArgBoolean, (LPVOID) &appData.highlightMoveWithArrow, TRUE },
\r
1264 { "highlightArrowColor", ArgColor, (LPVOID) &appData.highlightArrowColor, TRUE },
\r
1265 { "stickyWindows", ArgBoolean, (LPVOID) &appData.useStickyWindows, TRUE },
\r
1266 { "adjudicateDrawMoves", ArgInt, (LPVOID) &appData.adjudicateDrawMoves, TRUE },
\r
1267 { "autoDisplayComment", ArgBoolean, (LPVOID) &appData.autoDisplayComment, TRUE },
\r
1268 { "autoDisplayTags", ArgBoolean, (LPVOID) &appData.autoDisplayTags, TRUE },
\r
1269 { "firstIsUCI", ArgBoolean, (LPVOID) &appData.firstIsUCI, FALSE },
\r
1270 { "fUCI", ArgTrue, (LPVOID) &appData.firstIsUCI, FALSE },
\r
1271 { "secondIsUCI", ArgBoolean, (LPVOID) &appData.secondIsUCI, FALSE },
\r
1272 { "sUCI", ArgTrue, (LPVOID) &appData.secondIsUCI, FALSE },
\r
1273 { "firstHasOwnBookUCI", ArgBoolean, (LPVOID) &appData.firstHasOwnBookUCI, FALSE },
\r
1274 { "fNoOwnBookUCI", ArgFalse, (LPVOID) &appData.firstHasOwnBookUCI, FALSE },
\r
1275 { "firstXBook", ArgFalse, (LPVOID) &appData.firstHasOwnBookUCI, FALSE },
\r
1276 { "secondHasOwnBookUCI", ArgBoolean, (LPVOID) &appData.secondHasOwnBookUCI, FALSE },
\r
1277 { "sNoOwnBookUCI", ArgFalse, (LPVOID) &appData.secondHasOwnBookUCI, FALSE },
\r
1278 { "secondXBook", ArgFalse, (LPVOID) &appData.secondHasOwnBookUCI, FALSE },
\r
1279 { "polyglotDir", ArgFilename, (LPVOID) &appData.polyglotDir, TRUE },
\r
1280 { "usePolyglotBook", ArgBoolean, (LPVOID) &appData.usePolyglotBook, TRUE },
\r
1281 { "polyglotBook", ArgFilename, (LPVOID) &appData.polyglotBook, TRUE },
\r
1282 { "defaultHashSize", ArgInt, (LPVOID) &appData.defaultHashSize, TRUE },
\r
1283 { "defaultCacheSizeEGTB", ArgInt, (LPVOID) &appData.defaultCacheSizeEGTB, TRUE },
\r
1284 { "defaultPathEGTB", ArgFilename, (LPVOID) &appData.defaultPathEGTB, TRUE },
\r
1286 /* [HGM] board-size, adjudication and misc. options */
\r
1287 { "boardWidth", ArgInt, (LPVOID) &appData.NrFiles, TRUE },
\r
1288 { "boardHeight", ArgInt, (LPVOID) &appData.NrRanks, TRUE },
\r
1289 { "holdingsSize", ArgInt, (LPVOID) &appData.holdingsSize, TRUE },
\r
1290 { "matchPause", ArgInt, (LPVOID) &appData.matchPause, TRUE },
\r
1291 { "pieceToCharTable", ArgString, (LPVOID) &appData.pieceToCharTable, FALSE },
\r
1292 { "flipBlack", ArgBoolean, (LPVOID) &appData.upsideDown, TRUE },
\r
1293 { "allWhite", ArgBoolean, (LPVOID) &appData.allWhite, TRUE },
\r
1294 { "alphaRank", ArgBoolean, (LPVOID) &appData.alphaRank, FALSE },
\r
1295 { "firstAlphaRank", ArgBoolean, (LPVOID) &first.alphaRank, FALSE },
\r
1296 { "secondAlphaRank", ArgBoolean, (LPVOID) &second.alphaRank, FALSE },
\r
1297 { "testClaims", ArgBoolean, (LPVOID) &appData.testClaims, TRUE },
\r
1298 { "checkMates", ArgBoolean, (LPVOID) &appData.checkMates, TRUE },
\r
1299 { "materialDraws", ArgBoolean, (LPVOID) &appData.materialDraws, TRUE },
\r
1300 { "trivialDraws", ArgBoolean, (LPVOID) &appData.trivialDraws, TRUE },
\r
1301 { "ruleMoves", ArgInt, (LPVOID) &appData.ruleMoves, TRUE },
\r
1302 { "repeatsToDraw", ArgInt, (LPVOID) &appData.drawRepeats, TRUE },
\r
1303 { "autoKibitz", ArgTrue, (LPVOID) &appData.autoKibitz, FALSE },
\r
1304 { "engineDebugOutput", ArgInt, (LPVOID) &appData.engineComments, FALSE },
\r
1305 { "userName", ArgString, (LPVOID) &appData.userName, FALSE },
\r
1306 { "rewindIndex", ArgInt, (LPVOID) &appData.rewindIndex, FALSE },
\r
1307 { "sameColorGames", ArgInt, (LPVOID) &appData.sameColorGames, FALSE },
\r
1308 { "smpCores", ArgInt, (LPVOID) &appData.smpCores, TRUE },
\r
1309 { "egtFormats", ArgString, (LPVOID) &appData.egtFormats, TRUE },
\r
1310 { "niceEngines", ArgInt, (LPVOID) &appData.niceEngines, TRUE },
\r
1311 { "firstLogo", ArgFilename, (LPVOID) &appData.firstLogo, FALSE },
\r
1312 { "secondLogo", ArgFilename, (LPVOID) &appData.secondLogo, FALSE },
\r
1313 { "autoLogo", ArgBoolean, (LPVOID) &appData.autoLogo, TRUE },
\r
1314 { "firstOptions", ArgString, (LPVOID) &appData.firstOptions, FALSE },
\r
1315 { "secondOptions", ArgString, (LPVOID) &appData.secondOptions, FALSE },
\r
1316 { "firstNeedsNoncompliantFEN", ArgString, (LPVOID) &appData.fenOverride1, FALSE },
\r
1317 { "secondNeedsNoncompliantFEN", ArgString, (LPVOID) &appData.fenOverride2, FALSE },
\r
1320 { "zippyTalk", ArgBoolean, (LPVOID) &appData.zippyTalk, FALSE },
\r
1321 { "zt", ArgTrue, (LPVOID) &appData.zippyTalk, FALSE },
\r
1322 { "xzt", ArgFalse, (LPVOID) &appData.zippyTalk, FALSE },
\r
1323 { "-zt", ArgFalse, (LPVOID) &appData.zippyTalk, FALSE },
\r
1324 { "zippyPlay", ArgBoolean, (LPVOID) &appData.zippyPlay, FALSE },
\r
1325 { "zp", ArgTrue, (LPVOID) &appData.zippyPlay, FALSE },
\r
1326 { "xzp", ArgFalse, (LPVOID) &appData.zippyPlay, FALSE },
\r
1327 { "-zp", ArgFalse, (LPVOID) &appData.zippyPlay, FALSE },
\r
1328 { "zippyLines", ArgFilename, (LPVOID) &appData.zippyLines, FALSE },
\r
1329 { "zippyPinhead", ArgString, (LPVOID) &appData.zippyPinhead, FALSE },
\r
1330 { "zippyPassword", ArgString, (LPVOID) &appData.zippyPassword, FALSE },
\r
1331 { "zippyPassword2", ArgString, (LPVOID) &appData.zippyPassword2, FALSE },
\r
1332 { "zippyWrongPassword", ArgString, (LPVOID) &appData.zippyWrongPassword,
\r
1334 { "zippyAcceptOnly", ArgString, (LPVOID) &appData.zippyAcceptOnly, FALSE },
\r
1335 { "zippyUseI", ArgBoolean, (LPVOID) &appData.zippyUseI, FALSE },
\r
1336 { "zui", ArgTrue, (LPVOID) &appData.zippyUseI, FALSE },
\r
1337 { "xzui", ArgFalse, (LPVOID) &appData.zippyUseI, FALSE },
\r
1338 { "-zui", ArgFalse, (LPVOID) &appData.zippyUseI, FALSE },
\r
1339 { "zippyBughouse", ArgInt, (LPVOID) &appData.zippyBughouse, FALSE },
\r
1340 { "zippyNoplayCrafty", ArgBoolean, (LPVOID) &appData.zippyNoplayCrafty,
\r
1342 { "znc", ArgTrue, (LPVOID) &appData.zippyNoplayCrafty, FALSE },
\r
1343 { "xznc", ArgFalse, (LPVOID) &appData.zippyNoplayCrafty, FALSE },
\r
1344 { "-znc", ArgFalse, (LPVOID) &appData.zippyNoplayCrafty, FALSE },
\r
1345 { "zippyGameEnd", ArgString, (LPVOID) &appData.zippyGameEnd, FALSE },
\r
1346 { "zippyGameStart", ArgString, (LPVOID) &appData.zippyGameStart, FALSE },
\r
1347 { "zippyAdjourn", ArgBoolean, (LPVOID) &appData.zippyAdjourn, FALSE },
\r
1348 { "zadj", ArgTrue, (LPVOID) &appData.zippyAdjourn, FALSE },
\r
1349 { "xzadj", ArgFalse, (LPVOID) &appData.zippyAdjourn, FALSE },
\r
1350 { "-zadj", ArgFalse, (LPVOID) &appData.zippyAdjourn, FALSE },
\r
1351 { "zippyAbort", ArgBoolean, (LPVOID) &appData.zippyAbort, FALSE },
\r
1352 { "zab", ArgTrue, (LPVOID) &appData.zippyAbort, FALSE },
\r
1353 { "xzab", ArgFalse, (LPVOID) &appData.zippyAbort, FALSE },
\r
1354 { "-zab", ArgFalse, (LPVOID) &appData.zippyAbort, FALSE },
\r
1355 { "zippyVariants", ArgString, (LPVOID) &appData.zippyVariants, FALSE },
\r
1356 { "zippyMaxGames", ArgInt, (LPVOID)&appData.zippyMaxGames, FALSE },
\r
1357 { "zippyReplayTimeout", ArgInt, (LPVOID)&appData.zippyReplayTimeout, FALSE },
\r
1358 { "zippyShortGame", ArgInt, (LPVOID)&appData.zippyShortGame, FALSE },
\r
1359 /* Kludge to allow winboard.ini files from buggy 4.0.4 to be read: */
\r
1360 { "zippyReplyTimeout", ArgInt, (LPVOID)&junk, FALSE },
\r
1362 /* [HGM] options for broadcasting and time odds */
\r
1363 { "serverMoves", ArgString, (LPVOID) &appData.serverMovesName, FALSE },
\r
1364 { "suppressLoadMoves", ArgBoolean, (LPVOID) &appData.suppressLoadMoves, FALSE },
\r
1365 { "serverPause", ArgInt, (LPVOID) &appData.serverPause, FALSE },
\r
1366 { "firstTimeOdds", ArgInt, (LPVOID) &appData.firstTimeOdds, FALSE },
\r
1367 { "secondTimeOdds", ArgInt, (LPVOID) &appData.secondTimeOdds, FALSE },
\r
1368 { "timeOddsMode", ArgInt, (LPVOID) &appData.timeOddsMode, TRUE },
\r
1369 { "firstAccumulateTC", ArgInt, (LPVOID) &appData.firstAccumulateTC, FALSE },
\r
1370 { "secondAccumulateTC", ArgInt, (LPVOID) &appData.secondAccumulateTC, FALSE },
\r
1371 { "firstNPS", ArgInt, (LPVOID) &appData.firstNPS, FALSE },
\r
1372 { "secondNPS", ArgInt, (LPVOID) &appData.secondNPS, FALSE },
\r
1373 { "noGUI", ArgTrue, (LPVOID) &appData.noGUI, FALSE },
\r
1375 // [HGM] placement: put all window layouts last in ini file, but man X,Y before all others
\r
1376 { "minX", ArgZ, (LPVOID) &minX, FALSE }, // [HGM] placement: to make suer auxialary windows can be placed
\r
1377 { "minY", ArgZ, (LPVOID) &minY, FALSE },
\r
1378 { "winWidth", ArgInt, (LPVOID) &winWidth, TRUE }, // [HGM] placement: dummies to remember right & bottom
\r
1379 { "winHeight", ArgInt, (LPVOID) &winHeight, TRUE }, // for attaching auxiliary windows to them
\r
1380 { "x", ArgInt, (LPVOID) &boardX, TRUE },
\r
1381 { "y", ArgInt, (LPVOID) &boardY, TRUE },
\r
1382 { "icsX", ArgX, (LPVOID) &wpConsole.x, TRUE },
\r
1383 { "icsY", ArgY, (LPVOID) &wpConsole.y, TRUE },
\r
1384 { "icsW", ArgInt, (LPVOID) &wpConsole.width, TRUE },
\r
1385 { "icsH", ArgInt, (LPVOID) &wpConsole.height, TRUE },
\r
1386 { "analysisX", ArgX, (LPVOID) &analysisX, FALSE }, // [HGM] placement: analysis window no longer exists
\r
1387 { "analysisY", ArgY, (LPVOID) &analysisY, FALSE }, // provided for compatibility with old ini files
\r
1388 { "analysisW", ArgInt, (LPVOID) &analysisW, FALSE },
\r
1389 { "analysisH", ArgInt, (LPVOID) &analysisH, FALSE },
\r
1390 { "commentX", ArgX, (LPVOID) &commentX, TRUE },
\r
1391 { "commentY", ArgY, (LPVOID) &commentY, TRUE },
\r
1392 { "commentW", ArgInt, (LPVOID) &commentW, TRUE },
\r
1393 { "commentH", ArgInt, (LPVOID) &commentH, TRUE },
\r
1394 { "tagsX", ArgX, (LPVOID) &editTagsX, TRUE },
\r
1395 { "tagsY", ArgY, (LPVOID) &editTagsY, TRUE },
\r
1396 { "tagsW", ArgInt, (LPVOID) &editTagsW, TRUE },
\r
1397 { "tagsH", ArgInt, (LPVOID) &editTagsH, TRUE },
\r
1398 { "gameListX", ArgX, (LPVOID) &wpGameList.x, TRUE },
\r
1399 { "gameListY", ArgY, (LPVOID) &wpGameList.y, TRUE },
\r
1400 { "gameListW", ArgInt, (LPVOID) &wpGameList.width, TRUE },
\r
1401 { "gameListH", ArgInt, (LPVOID) &wpGameList.height, TRUE },
\r
1402 /* [AS] Layout stuff */
\r
1403 { "moveHistoryUp", ArgBoolean, (LPVOID) &wpMoveHistory.visible, TRUE },
\r
1404 { "moveHistoryX", ArgX, (LPVOID) &wpMoveHistory.x, TRUE },
\r
1405 { "moveHistoryY", ArgY, (LPVOID) &wpMoveHistory.y, TRUE },
\r
1406 { "moveHistoryW", ArgInt, (LPVOID) &wpMoveHistory.width, TRUE },
\r
1407 { "moveHistoryH", ArgInt, (LPVOID) &wpMoveHistory.height, TRUE },
\r
1409 { "evalGraphUp", ArgBoolean, (LPVOID) &wpEvalGraph.visible, TRUE },
\r
1410 { "evalGraphX", ArgX, (LPVOID) &wpEvalGraph.x, TRUE },
\r
1411 { "evalGraphY", ArgY, (LPVOID) &wpEvalGraph.y, TRUE },
\r
1412 { "evalGraphW", ArgInt, (LPVOID) &wpEvalGraph.width, TRUE },
\r
1413 { "evalGraphH", ArgInt, (LPVOID) &wpEvalGraph.height, TRUE },
\r
1415 { "engineOutputUp", ArgBoolean, (LPVOID) &wpEngineOutput.visible, TRUE },
\r
1416 { "engineOutputX", ArgX, (LPVOID) &wpEngineOutput.x, TRUE },
\r
1417 { "engineOutputY", ArgY, (LPVOID) &wpEngineOutput.y, TRUE },
\r
1418 { "engineOutputW", ArgInt, (LPVOID) &wpEngineOutput.width, TRUE },
\r
1419 { "engineOutputH", ArgInt, (LPVOID) &wpEngineOutput.height, TRUE },
\r
1421 { NULL, ArgNone, NULL, FALSE }
\r
1425 /* Kludge for indirection files on command line */
\r
1426 char* lastIndirectionFilename;
\r
1427 ArgDescriptor argDescriptorIndirection =
\r
1428 { "", ArgSettingsFilename, (LPVOID) NULL, FALSE };
\r
1432 ExitArgError(char *msg, char *badArg)
\r
1434 char buf[MSG_SIZ];
\r
1436 sprintf(buf, "%s %s", msg, badArg);
\r
1437 DisplayFatalError(buf, 0, 2);
\r
1441 /* Command line font name parser. NULL name means do nothing.
\r
1442 Syntax like "Courier New:10.0 bi" or "Arial:10" or "Arial:10b"
\r
1443 For backward compatibility, syntax without the colon is also
\r
1444 accepted, but font names with digits in them won't work in that case.
\r
1447 ParseFontName(char *name, MyFontParams *mfp)
\r
1450 if (name == NULL) return;
\r
1452 q = strchr(p, ':');
\r
1454 if (q - p >= sizeof(mfp->faceName))
\r
1455 ExitArgError("Font name too long:", name);
\r
1456 memcpy(mfp->faceName, p, q - p);
\r
1457 mfp->faceName[q - p] = NULLCHAR;
\r
1460 q = mfp->faceName;
\r
1461 while (*p && !isdigit(*p)) {
\r
1463 if (q - mfp->faceName >= sizeof(mfp->faceName))
\r
1464 ExitArgError("Font name too long:", name);
\r
1466 while (q > mfp->faceName && q[-1] == ' ') q--;
\r
1469 if (!*p) ExitArgError("Font point size missing:", name);
\r
1470 mfp->pointSize = (float) atof(p);
\r
1471 mfp->bold = (strchr(p, 'b') != NULL);
\r
1472 mfp->italic = (strchr(p, 'i') != NULL);
\r
1473 mfp->underline = (strchr(p, 'u') != NULL);
\r
1474 mfp->strikeout = (strchr(p, 's') != NULL);
\r
1477 /* Color name parser.
\r
1478 X version accepts X color names, but this one
\r
1479 handles only the #rrggbb form (hex) or rrr,ggg,bbb (decimal) */
\r
1481 ParseColorName(char *name)
\r
1483 int red, green, blue, count;
\r
1484 char buf[MSG_SIZ];
\r
1486 count = sscanf(name, "#%2x%2x%2x", &red, &green, &blue);
\r
1488 count = sscanf(name, "%3d%*[^0-9]%3d%*[^0-9]%3d",
\r
1489 &red, &green, &blue);
\r
1492 sprintf(buf, "Can't parse color name %s", name);
\r
1493 DisplayError(buf, 0);
\r
1494 return RGB(0, 0, 0);
\r
1496 return PALETTERGB(red, green, blue);
\r
1500 void ParseAttribs(COLORREF *color, int *effects, char* argValue)
\r
1502 char *e = argValue;
\r
1506 if (*e == 'b') eff |= CFE_BOLD;
\r
1507 else if (*e == 'i') eff |= CFE_ITALIC;
\r
1508 else if (*e == 'u') eff |= CFE_UNDERLINE;
\r
1509 else if (*e == 's') eff |= CFE_STRIKEOUT;
\r
1510 else if (*e == '#' || isdigit(*e)) break;
\r
1514 *color = ParseColorName(e);
\r
1519 ParseBoardSize(char *name)
\r
1521 BoardSize bs = SizeTiny;
\r
1522 while (sizeInfo[bs].name != NULL) {
\r
1523 if (StrCaseCmp(name, sizeInfo[bs].name) == 0) return bs;
\r
1526 ExitArgError("Unrecognized board size value", name);
\r
1527 return bs; /* not reached */
\r
1532 StringGet(void *getClosure)
\r
1534 char **p = (char **) getClosure;
\r
1539 FileGet(void *getClosure)
\r
1542 FILE* f = (FILE*) getClosure;
\r
1545 if (c == '\r') c = getc(f); // work around DOS format files by bypassing the '\r' completely
\r
1552 /* Parse settings file named "name". If file found, return the
\r
1553 full name in fullname and return TRUE; else return FALSE */
\r
1555 ParseSettingsFile(char *name, char fullname[MSG_SIZ])
\r
1559 int ok; char buf[MSG_SIZ];
\r
1561 ok = SearchPath(installDir, name, NULL, MSG_SIZ, fullname, &dummy);
\r
1562 if(!ok && strchr(name, '.') == NULL) { // [HGM] append default file-name extension '.ini' when needed
\r
1563 sprintf(buf, "%s.ini", name);
\r
1564 ok = SearchPath(installDir, buf, NULL, MSG_SIZ, fullname, &dummy);
\r
1567 f = fopen(fullname, "r");
\r
1569 ParseArgs(FileGet, f);
\r
1578 ParseArgs(GetFunc get, void *cl)
\r
1580 char argName[ARG_MAX];
\r
1581 char argValue[ARG_MAX];
\r
1582 ArgDescriptor *ad;
\r
1591 while (ch == ' ' || ch == '\n' || ch == '\t') ch = get(cl);
\r
1592 if (ch == NULLCHAR) break;
\r
1594 /* Comment to end of line */
\r
1596 while (ch != '\n' && ch != NULLCHAR) ch = get(cl);
\r
1598 } else if (ch == '/' || ch == '-') {
\r
1601 while (ch != ' ' && ch != '=' && ch != ':' && ch != NULLCHAR &&
\r
1602 ch != '\n' && ch != '\t') {
\r
1608 for (ad = argDescriptors; ad->argName != NULL; ad++)
\r
1609 if (strcmp(ad->argName, argName + 1) == 0) break;
\r
1611 if (ad->argName == NULL)
\r
1612 ExitArgError("Unrecognized argument", argName);
\r
1614 } else if (ch == '@') {
\r
1615 /* Indirection file */
\r
1616 ad = &argDescriptorIndirection;
\r
1619 /* Positional argument */
\r
1620 ad = &argDescriptors[posarg++];
\r
1621 strcpy(argName, ad->argName);
\r
1624 if (ad->argType == ArgTrue) {
\r
1625 *(Boolean *) ad->argLoc = TRUE;
\r
1628 if (ad->argType == ArgFalse) {
\r
1629 *(Boolean *) ad->argLoc = FALSE;
\r
1633 while (ch == ' ' || ch == '=' || ch == ':' || ch == '\t') ch = get(cl);
\r
1634 if (ch == NULLCHAR || ch == '\n') {
\r
1635 ExitArgError("No value provided for argument", argName);
\r
1639 // Quoting with { }. No characters have to (or can) be escaped.
\r
1640 // Thus the string cannot contain a '}' character.
\r
1660 } else if (ch == '\'' || ch == '"') {
\r
1661 // Quoting with ' ' or " ", with \ as escape character.
\r
1662 // Inconvenient for long strings that may contain Windows filenames.
\r
1679 if (ch == start) {
\r
1688 if (ad->argType == ArgFilename
\r
1689 || ad->argType == ArgSettingsFilename) {
\r
1695 ExitArgError("Incomplete \\ escape in value for", argName);
\r
1719 for (i = 0; i < 3; i++) {
\r
1720 if (ch >= '0' && ch <= '7') {
\r
1721 octval = octval*8 + (ch - '0');
\r
1728 *q++ = (char) octval;
\r
1739 while (ch != ' ' && ch != NULLCHAR && ch != '\t' && ch != '\n') {
\r
1746 switch (ad->argType) {
\r
1748 *(int *) ad->argLoc = atoi(argValue);
\r
1752 *(int *) ad->argLoc = atoi(argValue) + boardX; // [HGM] placement: translate stored relative to absolute
\r
1756 *(int *) ad->argLoc = atoi(argValue) + boardY; // (this is really kludgey, it should be done where used...)
\r
1760 *(int *) ad->argLoc = atoi(argValue);
\r
1761 EnsureOnScreen(&boardX, &boardY, minX, minY);
\r
1765 *(float *) ad->argLoc = (float) atof(argValue);
\r
1770 *(char **) ad->argLoc = strdup(argValue);
\r
1773 case ArgSettingsFilename:
\r
1775 char fullname[MSG_SIZ];
\r
1776 if (ParseSettingsFile(argValue, fullname)) {
\r
1777 if (ad->argLoc != NULL) {
\r
1778 *(char **) ad->argLoc = strdup(fullname);
\r
1781 if (ad->argLoc != NULL) {
\r
1783 ExitArgError("Failed to open indirection file", argValue);
\r
1790 switch (argValue[0]) {
\r
1793 *(Boolean *) ad->argLoc = TRUE;
\r
1797 *(Boolean *) ad->argLoc = FALSE;
\r
1800 ExitArgError("Unrecognized boolean argument value", argValue);
\r
1806 *(COLORREF *)ad->argLoc = ParseColorName(argValue);
\r
1809 case ArgAttribs: {
\r
1810 ColorClass cc = (ColorClass)ad->argLoc;
\r
1811 ParseAttribs(&textAttribs[cc].color, &textAttribs[cc].effects, argValue);
\r
1815 case ArgBoardSize:
\r
1816 *(BoardSize *)ad->argLoc = ParseBoardSize(argValue);
\r
1820 ParseFontName(argValue, &font[boardSize][(int)ad->argLoc]->mfp);
\r
1823 case ArgCommSettings:
\r
1824 ParseCommSettings(argValue, &dcb);
\r
1828 ExitArgError("Unrecognized argument", argValue);
\r
1837 LFfromMFP(LOGFONT* lf, MyFontParams *mfp)
\r
1839 HDC hdc = CreateDC("DISPLAY", NULL, NULL, NULL);
\r
1840 lf->lfHeight = -(int)(mfp->pointSize * GetDeviceCaps(hdc, LOGPIXELSY) / 72.0 + 0.5);
\r
1843 lf->lfEscapement = 0;
\r
1844 lf->lfOrientation = 0;
\r
1845 lf->lfWeight = mfp->bold ? FW_BOLD : FW_NORMAL;
\r
1846 lf->lfItalic = mfp->italic;
\r
1847 lf->lfUnderline = mfp->underline;
\r
1848 lf->lfStrikeOut = mfp->strikeout;
\r
1849 lf->lfCharSet = DEFAULT_CHARSET;
\r
1850 lf->lfOutPrecision = OUT_DEFAULT_PRECIS;
\r
1851 lf->lfClipPrecision = CLIP_DEFAULT_PRECIS;
\r
1852 lf->lfQuality = DEFAULT_QUALITY;
\r
1853 lf->lfPitchAndFamily = DEFAULT_PITCH|FF_DONTCARE;
\r
1854 strcpy(lf->lfFaceName, mfp->faceName);
\r
1858 CreateFontInMF(MyFont *mf)
\r
1860 LFfromMFP(&mf->lf, &mf->mfp);
\r
1861 if (mf->hf) DeleteObject(mf->hf);
\r
1862 mf->hf = CreateFontIndirect(&mf->lf);
\r
1866 SetDefaultTextAttribs()
\r
1869 for (cc = (ColorClass)0; cc < NColorClasses; cc++) {
\r
1870 ParseAttribs(&textAttribs[cc].color,
\r
1871 &textAttribs[cc].effects,
\r
1872 defaultTextAttribs[cc]);
\r
1877 SetDefaultSounds()
\r
1881 for (cc = (ColorClass)0; cc < NColorClasses; cc++) {
\r
1882 textAttribs[cc].sound.name = strdup("");
\r
1883 textAttribs[cc].sound.data = NULL;
\r
1885 for (sc = (SoundClass)0; sc < NSoundClasses; sc++) {
\r
1886 sounds[sc].name = strdup("");
\r
1887 sounds[sc].data = NULL;
\r
1889 sounds[(int)SoundBell].name = strdup(SOUND_BELL);
\r
1897 for (cc = (ColorClass)0; cc < NColorClasses; cc++) {
\r
1898 MyLoadSound(&textAttribs[cc].sound);
\r
1900 for (sc = (SoundClass)0; sc < NSoundClasses; sc++) {
\r
1901 MyLoadSound(&sounds[sc]);
\r
1906 InitAppData(LPSTR lpCmdLine)
\r
1909 char buf[ARG_MAX], currDir[MSG_SIZ];
\r
1912 programName = szAppName;
\r
1914 /* Initialize to defaults */
\r
1915 lightSquareColor = ParseColorName(LIGHT_SQUARE_COLOR);
\r
1916 darkSquareColor = ParseColorName(DARK_SQUARE_COLOR);
\r
1917 whitePieceColor = ParseColorName(WHITE_PIECE_COLOR);
\r
1918 blackPieceColor = ParseColorName(BLACK_PIECE_COLOR);
\r
1919 highlightSquareColor = ParseColorName(HIGHLIGHT_SQUARE_COLOR);
\r
1920 premoveHighlightColor = ParseColorName(PREMOVE_HIGHLIGHT_COLOR);
\r
1921 consoleBackgroundColor = ParseColorName(COLOR_BKGD);
\r
1922 SetDefaultTextAttribs();
\r
1923 SetDefaultSounds();
\r
1924 appData.movesPerSession = MOVES_PER_SESSION;
\r
1925 appData.initString = INIT_STRING;
\r
1926 appData.secondInitString = INIT_STRING;
\r
1927 appData.firstComputerString = COMPUTER_STRING;
\r
1928 appData.secondComputerString = COMPUTER_STRING;
\r
1929 appData.firstChessProgram = FIRST_CHESS_PROGRAM;
\r
1930 appData.secondChessProgram = SECOND_CHESS_PROGRAM;
\r
1931 appData.firstPlaysBlack = FALSE;
\r
1932 appData.noChessProgram = FALSE;
\r
1933 chessProgram = FALSE;
\r
1934 appData.firstHost = FIRST_HOST;
\r
1935 appData.secondHost = SECOND_HOST;
\r
1936 appData.firstDirectory = FIRST_DIRECTORY;
\r
1937 appData.secondDirectory = SECOND_DIRECTORY;
\r
1938 appData.bitmapDirectory = "";
\r
1939 appData.remoteShell = REMOTE_SHELL;
\r
1940 appData.remoteUser = "";
\r
1941 appData.timeDelay = TIME_DELAY;
\r
1942 appData.timeControl = TIME_CONTROL;
\r
1943 appData.timeIncrement = TIME_INCREMENT;
\r
1944 appData.icsActive = FALSE;
\r
1945 appData.icsHost = "";
\r
1946 appData.icsPort = ICS_PORT;
\r
1947 appData.icsCommPort = ICS_COMM_PORT;
\r
1948 appData.icsLogon = ICS_LOGON;
\r
1949 appData.icsHelper = "";
\r
1950 appData.useTelnet = FALSE;
\r
1951 appData.telnetProgram = TELNET_PROGRAM;
\r
1952 appData.gateway = "";
\r
1953 appData.loadGameFile = "";
\r
1954 appData.loadGameIndex = 0;
\r
1955 appData.saveGameFile = "";
\r
1956 appData.autoSaveGames = FALSE;
\r
1957 appData.loadPositionFile = "";
\r
1958 appData.loadPositionIndex = 1;
\r
1959 appData.savePositionFile = "";
\r
1960 appData.matchMode = FALSE;
\r
1961 appData.matchGames = 0;
\r
1962 appData.monoMode = FALSE;
\r
1963 appData.debugMode = FALSE;
\r
1964 appData.clockMode = TRUE;
\r
1965 boardSize = (BoardSize) -1; /* determine by screen size */
\r
1966 appData.Iconic = FALSE; /*unused*/
\r
1967 appData.searchTime = "";
\r
1968 appData.searchDepth = 0;
\r
1969 appData.showCoords = FALSE;
\r
1970 appData.ringBellAfterMoves = TRUE; /*obsolete in WinBoard*/
\r
1971 appData.autoCallFlag = FALSE;
\r
1972 appData.flipView = FALSE;
\r
1973 appData.autoFlipView = TRUE;
\r
1974 appData.cmailGameName = "";
\r
1975 appData.alwaysPromoteToQueen = FALSE;
\r
1976 appData.oldSaveStyle = FALSE;
\r
1977 appData.quietPlay = FALSE;
\r
1978 appData.showThinking = FALSE;
\r
1979 appData.ponderNextMove = TRUE;
\r
1980 appData.periodicUpdates = TRUE;
\r
1981 appData.popupExitMessage = TRUE;
\r
1982 appData.popupMoveErrors = FALSE;
\r
1983 appData.autoObserve = FALSE;
\r
1984 appData.autoComment = FALSE;
\r
1985 appData.animate = TRUE;
\r
1986 appData.animSpeed = 10;
\r
1987 appData.animateDragging = TRUE;
\r
1988 appData.highlightLastMove = TRUE;
\r
1989 appData.getMoveList = TRUE;
\r
1990 appData.testLegality = TRUE;
\r
1991 appData.premove = TRUE;
\r
1992 appData.premoveWhite = FALSE;
\r
1993 appData.premoveWhiteText = "";
\r
1994 appData.premoveBlack = FALSE;
\r
1995 appData.premoveBlackText = "";
\r
1996 appData.icsAlarm = TRUE;
\r
1997 appData.icsAlarmTime = 5000;
\r
1998 appData.autoRaiseBoard = TRUE;
\r
1999 appData.localLineEditing = TRUE;
\r
2000 appData.colorize = TRUE;
\r
2001 appData.reuseFirst = TRUE;
\r
2002 appData.reuseSecond = TRUE;
\r
2003 appData.blindfold = FALSE;
\r
2004 appData.icsEngineAnalyze = FALSE;
\r
2005 memset(&dcb, 0, sizeof(DCB)); // required by VS 2002 +
\r
2006 dcb.DCBlength = sizeof(DCB);
\r
2007 dcb.BaudRate = 9600;
\r
2008 dcb.fBinary = TRUE;
\r
2009 dcb.fParity = FALSE;
\r
2010 dcb.fOutxCtsFlow = FALSE;
\r
2011 dcb.fOutxDsrFlow = FALSE;
\r
2012 dcb.fDtrControl = DTR_CONTROL_ENABLE;
\r
2013 dcb.fDsrSensitivity = FALSE;
\r
2014 dcb.fTXContinueOnXoff = TRUE;
\r
2015 dcb.fOutX = FALSE;
\r
2017 dcb.fNull = FALSE;
\r
2018 dcb.fRtsControl = RTS_CONTROL_ENABLE;
\r
2019 dcb.fAbortOnError = FALSE;
\r
2021 dcb.Parity = SPACEPARITY;
\r
2022 dcb.StopBits = ONESTOPBIT;
\r
2023 settingsFileName = SETTINGS_FILE;
\r
2024 saveSettingsOnExit = TRUE;
\r
2025 boardX = CW_USEDEFAULT;
\r
2026 boardY = CW_USEDEFAULT;
\r
2027 analysisX = CW_USEDEFAULT;
\r
2028 analysisY = CW_USEDEFAULT;
\r
2029 analysisW = CW_USEDEFAULT;
\r
2030 analysisH = CW_USEDEFAULT;
\r
2031 commentX = CW_USEDEFAULT;
\r
2032 commentY = CW_USEDEFAULT;
\r
2033 commentW = CW_USEDEFAULT;
\r
2034 commentH = CW_USEDEFAULT;
\r
2035 editTagsX = CW_USEDEFAULT;
\r
2036 editTagsY = CW_USEDEFAULT;
\r
2037 editTagsW = CW_USEDEFAULT;
\r
2038 editTagsH = CW_USEDEFAULT;
\r
2039 icsTextMenuString = ICS_TEXT_MENU_DEFAULT;
\r
2040 icsNames = ICS_NAMES;
\r
2041 firstChessProgramNames = FCP_NAMES;
\r
2042 secondChessProgramNames = SCP_NAMES;
\r
2043 appData.initialMode = "";
\r
2044 appData.variant = "normal";
\r
2045 appData.firstProtocolVersion = PROTOVER;
\r
2046 appData.secondProtocolVersion = PROTOVER;
\r
2047 appData.showButtonBar = TRUE;
\r
2049 /* [AS] New properties (see comments in header file) */
\r
2050 appData.firstScoreIsAbsolute = FALSE;
\r
2051 appData.secondScoreIsAbsolute = FALSE;
\r
2052 appData.saveExtendedInfoInPGN = FALSE;
\r
2053 appData.hideThinkingFromHuman = FALSE;
\r
2054 appData.liteBackTextureFile = "";
\r
2055 appData.liteBackTextureMode = BACK_TEXTURE_MODE_PLAIN;
\r
2056 appData.darkBackTextureFile = "";
\r
2057 appData.darkBackTextureMode = BACK_TEXTURE_MODE_PLAIN;
\r
2058 appData.renderPiecesWithFont = "";
\r
2059 appData.fontToPieceTable = "";
\r
2060 appData.fontBackColorWhite = 0;
\r
2061 appData.fontForeColorWhite = 0;
\r
2062 appData.fontBackColorBlack = 0;
\r
2063 appData.fontForeColorBlack = 0;
\r
2064 appData.fontPieceSize = 80;
\r
2065 appData.overrideLineGap = 1;
\r
2066 appData.adjudicateLossThreshold = 0;
\r
2067 appData.delayBeforeQuit = 0;
\r
2068 appData.delayAfterQuit = 0;
\r
2069 appData.nameOfDebugFile = "winboard.debug";
\r
2070 appData.pgnEventHeader = "Computer Chess Game";
\r
2071 appData.defaultFrcPosition = -1;
\r
2072 appData.gameListTags = GLT_DEFAULT_TAGS;
\r
2073 appData.saveOutOfBookInfo = TRUE;
\r
2074 appData.showEvalInMoveHistory = TRUE;
\r
2075 appData.evalHistColorWhite = ParseColorName( "#FFFFB0" );
\r
2076 appData.evalHistColorBlack = ParseColorName( "#AD5D3D" );
\r
2077 appData.highlightMoveWithArrow = FALSE;
\r
2078 appData.highlightArrowColor = ParseColorName( "#FFFF80" );
\r
2079 appData.useStickyWindows = TRUE;
\r
2080 appData.adjudicateDrawMoves = 0;
\r
2081 appData.autoDisplayComment = TRUE;
\r
2082 appData.autoDisplayTags = TRUE;
\r
2083 appData.firstIsUCI = FALSE;
\r
2084 appData.secondIsUCI = FALSE;
\r
2085 appData.firstHasOwnBookUCI = TRUE;
\r
2086 appData.secondHasOwnBookUCI = TRUE;
\r
2087 appData.polyglotDir = "";
\r
2088 appData.usePolyglotBook = FALSE;
\r
2089 appData.polyglotBook = "";
\r
2090 appData.defaultHashSize = 64;
\r
2091 appData.defaultCacheSizeEGTB = 4;
\r
2092 appData.defaultPathEGTB = "c:\\egtb";
\r
2093 appData.firstOptions = "";
\r
2094 appData.secondOptions = "";
\r
2096 InitWindowPlacement( &wpGameList );
\r
2097 InitWindowPlacement( &wpMoveHistory );
\r
2098 InitWindowPlacement( &wpEvalGraph );
\r
2099 InitWindowPlacement( &wpEngineOutput );
\r
2100 InitWindowPlacement( &wpConsole );
\r
2102 /* [HGM] User-selectable board size, adjudication control, miscellaneous */
\r
2103 appData.NrFiles = -1;
\r
2104 appData.NrRanks = -1;
\r
2105 appData.holdingsSize = -1;
\r
2106 appData.testClaims = FALSE;
\r
2107 appData.checkMates = FALSE;
\r
2108 appData.materialDraws= FALSE;
\r
2109 appData.trivialDraws = FALSE;
\r
2110 appData.ruleMoves = 51;
\r
2111 appData.drawRepeats = 6;
\r
2112 appData.matchPause = 10000;
\r
2113 appData.alphaRank = FALSE;
\r
2114 appData.allWhite = FALSE;
\r
2115 appData.upsideDown = FALSE;
\r
2116 appData.serverPause = 15;
\r
2117 appData.serverMovesName = NULL;
\r
2118 appData.suppressLoadMoves = FALSE;
\r
2119 appData.firstTimeOdds = 1;
\r
2120 appData.secondTimeOdds = 1;
\r
2121 appData.firstAccumulateTC = 1; // combine previous and current sessions
\r
2122 appData.secondAccumulateTC = 1;
\r
2123 appData.firstNPS = -1; // [HGM] nps: use wall-clock time
\r
2124 appData.secondNPS = -1;
\r
2125 appData.engineComments = 1;
\r
2126 appData.smpCores = 1; // [HGM] SMP: max nr of cores
\r
2127 appData.egtFormats = "";
\r
2130 appData.zippyTalk = ZIPPY_TALK;
\r
2131 appData.zippyPlay = ZIPPY_PLAY;
\r
2132 appData.zippyLines = ZIPPY_LINES;
\r
2133 appData.zippyPinhead = ZIPPY_PINHEAD;
\r
2134 appData.zippyPassword = ZIPPY_PASSWORD;
\r
2135 appData.zippyPassword2 = ZIPPY_PASSWORD2;
\r
2136 appData.zippyWrongPassword = ZIPPY_WRONG_PASSWORD;
\r
2137 appData.zippyAcceptOnly = ZIPPY_ACCEPT_ONLY;
\r
2138 appData.zippyUseI = ZIPPY_USE_I;
\r
2139 appData.zippyBughouse = ZIPPY_BUGHOUSE;
\r
2140 appData.zippyNoplayCrafty = ZIPPY_NOPLAY_CRAFTY;
\r
2141 appData.zippyGameEnd = ZIPPY_GAME_END;
\r
2142 appData.zippyGameStart = ZIPPY_GAME_START;
\r
2143 appData.zippyAdjourn = ZIPPY_ADJOURN;
\r
2144 appData.zippyAbort = ZIPPY_ABORT;
\r
2145 appData.zippyVariants = ZIPPY_VARIANTS;
\r
2146 appData.zippyMaxGames = ZIPPY_MAX_GAMES;
\r
2147 appData.zippyReplayTimeout = ZIPPY_REPLAY_TIMEOUT;
\r
2150 /* Point font array elements to structures and
\r
2151 parse default font names */
\r
2152 for (i=0; i<NUM_FONTS; i++) {
\r
2153 for (j=0; j<NUM_SIZES; j++) {
\r
2154 font[j][i] = &fontRec[j][i];
\r
2155 ParseFontName(font[j][i]->def, &font[j][i]->mfp);
\r
2159 /* Parse default settings file if any */
\r
2160 if (ParseSettingsFile(settingsFileName, buf)) {
\r
2161 settingsFileName = strdup(buf);
\r
2164 /* Parse command line */
\r
2165 ParseArgs(StringGet, &lpCmdLine);
\r
2167 /* [HGM] make sure board size is acceptable */
\r
2168 if(appData.NrFiles > BOARD_SIZE ||
\r
2169 appData.NrRanks > BOARD_SIZE )
\r
2170 DisplayFatalError("Recompile with BOARD_SIZE > 12, to support this size", 0, 2);
\r
2172 /* [HGM] After parsing the options from the .ini file, and overruling them
\r
2173 * with options from the command line, we now make an even higher priority
\r
2174 * overrule by WB options attached to the engine command line. This so that
\r
2175 * tournament managers can use WB options (such as /timeOdds) that follow
\r
2178 if(appData.firstChessProgram != NULL) {
\r
2179 char *p = StrStr(appData.firstChessProgram, "WBopt");
\r
2180 static char *f = "first";
\r
2181 char buf[MSG_SIZ], *q = buf;
\r
2182 if(p != NULL) { // engine command line contains WinBoard options
\r
2183 sprintf(buf, p+6, f, f, f, f, f, f, f, f, f, f); // replace %s in them by "first"
\r
2184 ParseArgs(StringGet, &q);
\r
2185 p[-1] = 0; // cut them offengine command line
\r
2188 // now do same for second chess program
\r
2189 if(appData.secondChessProgram != NULL) {
\r
2190 char *p = StrStr(appData.secondChessProgram, "WBopt");
\r
2191 static char *s = "second";
\r
2192 char buf[MSG_SIZ], *q = buf;
\r
2193 if(p != NULL) { // engine command line contains WinBoard options
\r
2194 sprintf(buf, p+6, s, s, s, s, s, s, s, s, s, s); // replace %s in them by "first"
\r
2195 ParseArgs(StringGet, &q);
\r
2196 p[-1] = 0; // cut them offengine command line
\r
2201 /* Propagate options that affect others */
\r
2202 if (appData.matchMode || appData.matchGames) chessProgram = TRUE;
\r
2203 if (appData.icsActive || appData.noChessProgram) {
\r
2204 chessProgram = FALSE; /* not local chess program mode */
\r
2207 /* Open startup dialog if needed */
\r
2208 if ((!appData.noChessProgram && !chessProgram && !appData.icsActive) ||
\r
2209 (appData.icsActive && *appData.icsHost == NULLCHAR) ||
\r
2210 (chessProgram && (*appData.firstChessProgram == NULLCHAR ||
\r
2211 *appData.secondChessProgram == NULLCHAR))) {
\r
2214 lpProc = MakeProcInstance((FARPROC)StartupDialog, hInst);
\r
2215 DialogBox(hInst, MAKEINTRESOURCE(DLG_Startup), NULL, (DLGPROC)lpProc);
\r
2216 FreeProcInstance(lpProc);
\r
2219 /* Make sure save files land in the right (?) directory */
\r
2220 if (GetFullPathName(appData.saveGameFile, MSG_SIZ, buf, &dummy)) {
\r
2221 appData.saveGameFile = strdup(buf);
\r
2223 if (GetFullPathName(appData.savePositionFile, MSG_SIZ, buf, &dummy)) {
\r
2224 appData.savePositionFile = strdup(buf);
\r
2227 /* Finish initialization for fonts and sounds */
\r
2228 for (i=0; i<NUM_FONTS; i++) {
\r
2229 for (j=0; j<NUM_SIZES; j++) {
\r
2230 CreateFontInMF(font[j][i]);
\r
2233 /* xboard, and older WinBoards, controlled the move sound with the
\r
2234 appData.ringBellAfterMoves option. In the current WinBoard, we
\r
2235 always turn the option on (so that the backend will call us),
\r
2236 then let the user turn the sound off by setting it to silence if
\r
2237 desired. To accommodate old winboard.ini files saved by old
\r
2238 versions of WinBoard, we also turn off the sound if the option
\r
2239 was initially set to false. */
\r
2240 if (!appData.ringBellAfterMoves) {
\r
2241 sounds[(int)SoundMove].name = strdup("");
\r
2242 appData.ringBellAfterMoves = TRUE;
\r
2244 GetCurrentDirectory(MSG_SIZ, currDir);
\r
2245 SetCurrentDirectory(installDir);
\r
2247 SetCurrentDirectory(currDir);
\r
2249 p = icsTextMenuString;
\r
2250 if (p[0] == '@') {
\r
2251 FILE* f = fopen(p + 1, "r");
\r
2253 DisplayFatalError(p + 1, errno, 2);
\r
2256 i = fread(buf, 1, sizeof(buf)-1, f);
\r
2258 buf[i] = NULLCHAR;
\r
2261 ParseIcsTextMenu(strdup(p));
\r
2268 HMENU hmenu = GetMenu(hwndMain);
\r
2270 (void) EnableMenuItem(hmenu, IDM_CommPort,
\r
2271 MF_BYCOMMAND|((appData.icsActive &&
\r
2272 *appData.icsCommPort != NULLCHAR) ?
\r
2273 MF_ENABLED : MF_GRAYED));
\r
2274 (void) CheckMenuItem(hmenu, IDM_SaveSettingsOnExit,
\r
2275 MF_BYCOMMAND|(saveSettingsOnExit ?
\r
2276 MF_CHECKED : MF_UNCHECKED));
\r
2281 SaveSettings(char* name)
\r
2284 ArgDescriptor *ad;
\r
2285 WINDOWPLACEMENT wp;
\r
2286 char dir[MSG_SIZ];
\r
2288 if (!hwndMain) return;
\r
2290 GetCurrentDirectory(MSG_SIZ, dir);
\r
2291 SetCurrentDirectory(installDir);
\r
2292 f = fopen(name, "w");
\r
2293 SetCurrentDirectory(dir);
\r
2295 DisplayError(name, errno);
\r
2298 fprintf(f, ";\n");
\r
2299 fprintf(f, "; %s %s.%s Save Settings file\n", PRODUCT, VERSION, PATCHLEVEL);
\r
2300 fprintf(f, ";\n");
\r
2301 fprintf(f, "; You can edit the values of options that are already set in this file,\n");
\r
2302 fprintf(f, "; but if you add other options, the next Save Settings will not save them.\n");
\r
2303 fprintf(f, "; Use a shortcut, an @indirection file, or a .bat file instead.\n");
\r
2304 fprintf(f, ";\n");
\r
2306 wp.length = sizeof(WINDOWPLACEMENT);
\r
2307 GetWindowPlacement(hwndMain, &wp);
\r
2308 boardX = wp.rcNormalPosition.left;
\r
2309 boardY = wp.rcNormalPosition.top;
\r
2311 if (hwndConsole) {
\r
2312 GetWindowPlacement(hwndConsole, &wp);
\r
2313 wpConsole.x = wp.rcNormalPosition.left;
\r
2314 wpConsole.y = wp.rcNormalPosition.top;
\r
2315 wpConsole.width = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2316 wpConsole.height = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2319 if (analysisDialog) {
\r
2320 GetWindowPlacement(analysisDialog, &wp);
\r
2321 analysisX = wp.rcNormalPosition.left;
\r
2322 analysisY = wp.rcNormalPosition.top;
\r
2323 analysisW = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2324 analysisH = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2327 if (commentDialog) {
\r
2328 GetWindowPlacement(commentDialog, &wp);
\r
2329 commentX = wp.rcNormalPosition.left;
\r
2330 commentY = wp.rcNormalPosition.top;
\r
2331 commentW = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2332 commentH = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2335 if (editTagsDialog) {
\r
2336 GetWindowPlacement(editTagsDialog, &wp);
\r
2337 editTagsX = wp.rcNormalPosition.left;
\r
2338 editTagsY = wp.rcNormalPosition.top;
\r
2339 editTagsW = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2340 editTagsH = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2343 if (gameListDialog) {
\r
2344 GetWindowPlacement(gameListDialog, &wp);
\r
2345 wpGameList.x = wp.rcNormalPosition.left;
\r
2346 wpGameList.y = wp.rcNormalPosition.top;
\r
2347 wpGameList.width = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2348 wpGameList.height = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2351 /* [AS] Move history */
\r
2352 wpMoveHistory.visible = MoveHistoryIsUp();
\r
2354 if( moveHistoryDialog ) {
\r
2355 GetWindowPlacement(moveHistoryDialog, &wp);
\r
2356 wpMoveHistory.x = wp.rcNormalPosition.left;
\r
2357 wpMoveHistory.y = wp.rcNormalPosition.top;
\r
2358 wpMoveHistory.width = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2359 wpMoveHistory.height = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2362 /* [AS] Eval graph */
\r
2363 wpEvalGraph.visible = EvalGraphIsUp();
\r
2365 if( evalGraphDialog ) {
\r
2366 GetWindowPlacement(evalGraphDialog, &wp);
\r
2367 wpEvalGraph.x = wp.rcNormalPosition.left;
\r
2368 wpEvalGraph.y = wp.rcNormalPosition.top;
\r
2369 wpEvalGraph.width = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2370 wpEvalGraph.height = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2373 /* [AS] Engine output */
\r
2374 wpEngineOutput.visible = EngineOutputIsUp();
\r
2376 if( engineOutputDialog ) {
\r
2377 GetWindowPlacement(engineOutputDialog, &wp);
\r
2378 wpEngineOutput.x = wp.rcNormalPosition.left;
\r
2379 wpEngineOutput.y = wp.rcNormalPosition.top;
\r
2380 wpEngineOutput.width = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2381 wpEngineOutput.height = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2384 for (ad = argDescriptors; ad->argName != NULL; ad++) {
\r
2385 if (!ad->save) continue;
\r
2386 switch (ad->argType) {
\r
2389 char *p = *(char **)ad->argLoc;
\r
2390 if ((strchr(p, '\\') || strchr(p, '\n')) && !strchr(p, '}')) {
\r
2391 /* Quote multiline values or \-containing values
\r
2392 with { } if possible */
\r
2393 fprintf(f, "/%s={%s}\n", ad->argName, p);
\r
2395 /* Else quote with " " */
\r
2396 fprintf(f, "/%s=\"", ad->argName);
\r
2398 if (*p == '\n') fprintf(f, "\n");
\r
2399 else if (*p == '\r') fprintf(f, "\\r");
\r
2400 else if (*p == '\t') fprintf(f, "\\t");
\r
2401 else if (*p == '\b') fprintf(f, "\\b");
\r
2402 else if (*p == '\f') fprintf(f, "\\f");
\r
2403 else if (*p < ' ') fprintf(f, "\\%03o", *p);
\r
2404 else if (*p == '\"') fprintf(f, "\\\"");
\r
2405 else if (*p == '\\') fprintf(f, "\\\\");
\r
2409 fprintf(f, "\"\n");
\r
2415 fprintf(f, "/%s=%d\n", ad->argName, *(int *)ad->argLoc);
\r
2418 fprintf(f, "/%s=%d\n", ad->argName, *(int *)ad->argLoc - boardX); // [HGM] placement: stor relative value
\r
2421 fprintf(f, "/%s=%d\n", ad->argName, *(int *)ad->argLoc - boardY);
\r
2424 fprintf(f, "/%s=%g\n", ad->argName, *(float *)ad->argLoc);
\r
2427 fprintf(f, "/%s=%s\n", ad->argName,
\r
2428 (*(Boolean *)ad->argLoc) ? "true" : "false");
\r
2431 if (*(Boolean *)ad->argLoc) fprintf(f, "/%s\n", ad->argName);
\r
2434 if (!*(Boolean *)ad->argLoc) fprintf(f, "/%s\n", ad->argName);
\r
2438 COLORREF color = *(COLORREF *)ad->argLoc;
\r
2439 fprintf(f, "/%s=#%02lx%02lx%02lx\n", ad->argName,
\r
2440 color&0xff, (color>>8)&0xff, (color>>16)&0xff);
\r
2445 MyTextAttribs* ta = &textAttribs[(ColorClass)ad->argLoc];
\r
2446 fprintf(f, "/%s=\"%s%s%s%s%s#%02lx%02lx%02lx\"\n", ad->argName,
\r
2447 (ta->effects & CFE_BOLD) ? "b" : "",
\r
2448 (ta->effects & CFE_ITALIC) ? "i" : "",
\r
2449 (ta->effects & CFE_UNDERLINE) ? "u" : "",
\r
2450 (ta->effects & CFE_STRIKEOUT) ? "s" : "",
\r
2451 (ta->effects) ? " " : "",
\r
2452 ta->color&0xff, (ta->color >> 8)&0xff, (ta->color >> 16)&0xff);
\r
2456 if (strchr(*(char **)ad->argLoc, '\"')) {
\r
2457 fprintf(f, "/%s='%s'\n", ad->argName, *(char **)ad->argLoc);
\r
2459 fprintf(f, "/%s=\"%s\"\n", ad->argName, *(char **)ad->argLoc);
\r
2462 case ArgBoardSize:
\r
2463 fprintf(f, "/%s=%s\n", ad->argName,
\r
2464 sizeInfo[*(BoardSize *)ad->argLoc].name);
\r
2469 for (bs=0; bs<NUM_SIZES; bs++) {
\r
2470 MyFontParams *mfp = &font[bs][(int) ad->argLoc]->mfp;
\r
2471 fprintf(f, "/size=%s ", sizeInfo[bs].name);
\r
2472 fprintf(f, "/%s=\"%s:%g%s%s%s%s%s\"\n",
\r
2473 ad->argName, mfp->faceName, mfp->pointSize,
\r
2474 mfp->bold || mfp->italic || mfp->underline || mfp->strikeout ? " " : "",
\r
2475 mfp->bold ? "b" : "",
\r
2476 mfp->italic ? "i" : "",
\r
2477 mfp->underline ? "u" : "",
\r
2478 mfp->strikeout ? "s" : "");
\r
2482 case ArgCommSettings:
\r
2483 PrintCommSettings(f, ad->argName, (DCB *)ad->argLoc);
\r
2485 case ArgSettingsFilename: ;
\r
2493 /*---------------------------------------------------------------------------*\
\r
2495 * GDI board drawing routines
\r
2497 \*---------------------------------------------------------------------------*/
\r
2499 /* [AS] Draw square using background texture */
\r
2500 static void DrawTile( int dx, int dy, int dw, int dh, HDC dst, HDC src, int mode, int sx, int sy )
\r
2505 return; /* Should never happen! */
\r
2508 SetGraphicsMode( dst, GM_ADVANCED );
\r
2515 /* X reflection */
\r
2520 x.eDx = (FLOAT) dw + dx - 1;
\r
2523 SetWorldTransform( dst, &x );
\r
2526 /* Y reflection */
\r
2532 x.eDy = (FLOAT) dh + dy - 1;
\r
2534 SetWorldTransform( dst, &x );
\r
2542 x.eDx = (FLOAT) dx;
\r
2543 x.eDy = (FLOAT) dy;
\r
2546 SetWorldTransform( dst, &x );
\r
2550 BitBlt( dst, dx, dy, dw, dh, src, sx, sy, SRCCOPY );
\r
2558 SetWorldTransform( dst, &x );
\r
2560 ModifyWorldTransform( dst, 0, MWT_IDENTITY );
\r
2563 /* [AS] [HGM] Make room for more piece types, so all pieces can be different */
\r
2565 PM_WP = (int) WhitePawn,
\r
2566 PM_WN = (int) WhiteKnight,
\r
2567 PM_WB = (int) WhiteBishop,
\r
2568 PM_WR = (int) WhiteRook,
\r
2569 PM_WQ = (int) WhiteQueen,
\r
2570 PM_WF = (int) WhiteFerz,
\r
2571 PM_WW = (int) WhiteWazir,
\r
2572 PM_WE = (int) WhiteAlfil,
\r
2573 PM_WM = (int) WhiteMan,
\r
2574 PM_WO = (int) WhiteCannon,
\r
2575 PM_WU = (int) WhiteUnicorn,
\r
2576 PM_WH = (int) WhiteNightrider,
\r
2577 PM_WA = (int) WhiteAngel,
\r
2578 PM_WC = (int) WhiteMarshall,
\r
2579 PM_WAB = (int) WhiteCardinal,
\r
2580 PM_WD = (int) WhiteDragon,
\r
2581 PM_WL = (int) WhiteLance,
\r
2582 PM_WS = (int) WhiteCobra,
\r
2583 PM_WV = (int) WhiteFalcon,
\r
2584 PM_WSG = (int) WhiteSilver,
\r
2585 PM_WG = (int) WhiteGrasshopper,
\r
2586 PM_WK = (int) WhiteKing,
\r
2587 PM_BP = (int) BlackPawn,
\r
2588 PM_BN = (int) BlackKnight,
\r
2589 PM_BB = (int) BlackBishop,
\r
2590 PM_BR = (int) BlackRook,
\r
2591 PM_BQ = (int) BlackQueen,
\r
2592 PM_BF = (int) BlackFerz,
\r
2593 PM_BW = (int) BlackWazir,
\r
2594 PM_BE = (int) BlackAlfil,
\r
2595 PM_BM = (int) BlackMan,
\r
2596 PM_BO = (int) BlackCannon,
\r
2597 PM_BU = (int) BlackUnicorn,
\r
2598 PM_BH = (int) BlackNightrider,
\r
2599 PM_BA = (int) BlackAngel,
\r
2600 PM_BC = (int) BlackMarshall,
\r
2601 PM_BG = (int) BlackGrasshopper,
\r
2602 PM_BAB = (int) BlackCardinal,
\r
2603 PM_BD = (int) BlackDragon,
\r
2604 PM_BL = (int) BlackLance,
\r
2605 PM_BS = (int) BlackCobra,
\r
2606 PM_BV = (int) BlackFalcon,
\r
2607 PM_BSG = (int) BlackSilver,
\r
2608 PM_BK = (int) BlackKing
\r
2611 static HFONT hPieceFont = NULL;
\r
2612 static HBITMAP hPieceMask[(int) EmptySquare];
\r
2613 static HBITMAP hPieceFace[(int) EmptySquare];
\r
2614 static int fontBitmapSquareSize = 0;
\r
2615 static char pieceToFontChar[(int) EmptySquare] =
\r
2616 { 'p', 'n', 'b', 'r', 'q',
\r
2617 'n', 'b', 'p', 'n', 'b', 'r', 'b', 'r', 'q', 'k',
\r
2618 'k', 'o', 'm', 'v', 't', 'w',
\r
2619 'v', 't', 'o', 'm', 'v', 't', 'v', 't', 'w', 'l',
\r
2622 extern BOOL SetCharTable( char *table, const char * map );
\r
2623 /* [HGM] moved to backend.c */
\r
2625 static void SetPieceBackground( HDC hdc, COLORREF color, int mode )
\r
2628 BYTE r1 = GetRValue( color );
\r
2629 BYTE g1 = GetGValue( color );
\r
2630 BYTE b1 = GetBValue( color );
\r
2636 /* Create a uniform background first */
\r
2637 hbrush = CreateSolidBrush( color );
\r
2638 SetRect( &rc, 0, 0, squareSize, squareSize );
\r
2639 FillRect( hdc, &rc, hbrush );
\r
2640 DeleteObject( hbrush );
\r
2643 /* Vertical gradient, good for pawn, knight and rook, less for queen and king */
\r
2644 int steps = squareSize / 2;
\r
2647 for( i=0; i<steps; i++ ) {
\r
2648 BYTE r = r1 - (r1-r2) * i / steps;
\r
2649 BYTE g = g1 - (g1-g2) * i / steps;
\r
2650 BYTE b = b1 - (b1-b2) * i / steps;
\r
2652 hbrush = CreateSolidBrush( RGB(r,g,b) );
\r
2653 SetRect( &rc, i + squareSize - steps, 0, i + squareSize - steps + 1, squareSize );
\r
2654 FillRect( hdc, &rc, hbrush );
\r
2655 DeleteObject(hbrush);
\r
2658 else if( mode == 2 ) {
\r
2659 /* Diagonal gradient, good more or less for every piece */
\r
2660 POINT triangle[3];
\r
2661 HPEN hpen = SelectObject( hdc, GetStockObject(NULL_PEN) );
\r
2662 HBRUSH hbrush_old;
\r
2663 int steps = squareSize;
\r
2666 triangle[0].x = squareSize - steps;
\r
2667 triangle[0].y = squareSize;
\r
2668 triangle[1].x = squareSize;
\r
2669 triangle[1].y = squareSize;
\r
2670 triangle[2].x = squareSize;
\r
2671 triangle[2].y = squareSize - steps;
\r
2673 for( i=0; i<steps; i++ ) {
\r
2674 BYTE r = r1 - (r1-r2) * i / steps;
\r
2675 BYTE g = g1 - (g1-g2) * i / steps;
\r
2676 BYTE b = b1 - (b1-b2) * i / steps;
\r
2678 hbrush = CreateSolidBrush( RGB(r,g,b) );
\r
2679 hbrush_old = SelectObject( hdc, hbrush );
\r
2680 Polygon( hdc, triangle, 3 );
\r
2681 SelectObject( hdc, hbrush_old );
\r
2682 DeleteObject(hbrush);
\r
2687 SelectObject( hdc, hpen );
\r
2692 [AS] The method I use to create the bitmaps it a bit tricky, but it
\r
2693 seems to work ok. The main problem here is to find the "inside" of a chess
\r
2694 piece: follow the steps as explained below.
\r
2696 static void CreatePieceMaskFromFont( HDC hdc_window, HDC hdc, int index )
\r
2700 COLORREF chroma = RGB(0xFF,0x00,0xFF);
\r
2704 int backColor = whitePieceColor;
\r
2705 int foreColor = blackPieceColor;
\r
2707 if( index < (int)BlackPawn && appData.fontBackColorWhite != appData.fontForeColorWhite ) {
\r
2708 backColor = appData.fontBackColorWhite;
\r
2709 foreColor = appData.fontForeColorWhite;
\r
2711 else if( index >= (int)BlackPawn && appData.fontBackColorBlack != appData.fontForeColorBlack ) {
\r
2712 backColor = appData.fontBackColorBlack;
\r
2713 foreColor = appData.fontForeColorBlack;
\r
2717 hbm = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
\r
2719 hbm_old = SelectObject( hdc, hbm );
\r
2723 rc.right = squareSize;
\r
2724 rc.bottom = squareSize;
\r
2726 /* Step 1: background is now black */
\r
2727 FillRect( hdc, &rc, GetStockObject(BLACK_BRUSH) );
\r
2729 GetTextExtentPoint32( hdc, &pieceToFontChar[index], 1, &sz );
\r
2731 pt.x = (squareSize - sz.cx) / 2;
\r
2732 pt.y = (squareSize - sz.cy) / 2;
\r
2734 SetBkMode( hdc, TRANSPARENT );
\r
2735 SetTextColor( hdc, chroma );
\r
2736 /* Step 2: the piece has been drawn in purple, there are now black and purple in this bitmap */
\r
2737 TextOut( hdc, pt.x, pt.y, &pieceToFontChar[appData.allWhite && index >= (int)BlackPawn ? index - (int)BlackPawn : index], 1 );
\r
2739 SelectObject( hdc, GetStockObject(WHITE_BRUSH) );
\r
2740 /* Step 3: the area outside the piece is filled with white */
\r
2741 // FloodFill( hdc, 0, 0, chroma );
\r
2742 ExtFloodFill( hdc, 0, 0, 0, FLOODFILLSURFACE );
\r
2743 ExtFloodFill( hdc, 0, squareSize-1, 0, FLOODFILLSURFACE ); // [HGM] fill from all 4 corners, for if piece too big
\r
2744 ExtFloodFill( hdc, squareSize-1, 0, 0, FLOODFILLSURFACE );
\r
2745 ExtFloodFill( hdc, squareSize-1, squareSize-1, 0, FLOODFILLSURFACE );
\r
2746 SelectObject( hdc, GetStockObject(BLACK_BRUSH) );
\r
2748 Step 4: this is the tricky part, the area inside the piece is filled with black,
\r
2749 but if the start point is not inside the piece we're lost!
\r
2750 There should be a better way to do this... if we could create a region or path
\r
2751 from the fill operation we would be fine for example.
\r
2753 // FloodFill( hdc, squareSize / 2, squareSize / 2, RGB(0xFF,0xFF,0xFF) );
\r
2754 ExtFloodFill( hdc, squareSize / 2, squareSize / 2, RGB(0xFF,0xFF,0xFF), FLOODFILLBORDER );
\r
2756 { /* [HGM] shave off edges of mask, in an attempt to correct for the fact that FloodFill does not work correctly under Win XP */
\r
2757 HDC dc2 = CreateCompatibleDC( hdc_window );
\r
2758 HBITMAP bm2 = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
\r
2760 SelectObject( dc2, bm2 );
\r
2761 BitBlt( dc2, 0, 0, squareSize, squareSize, hdc, 0, 0, SRCCOPY ); // make copy
\r
2762 BitBlt( hdc, 0, 1, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );
\r
2763 BitBlt( hdc, 2, 1, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );
\r
2764 BitBlt( hdc, 1, 0, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );
\r
2765 BitBlt( hdc, 1, 2, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );
\r
2768 DeleteObject( bm2 );
\r
2771 SetTextColor( hdc, 0 );
\r
2773 Step 5: some fonts have "disconnected" areas that are skipped by the fill:
\r
2774 draw the piece again in black for safety.
\r
2776 TextOut( hdc, pt.x, pt.y, &pieceToFontChar[appData.allWhite && index >= (int)BlackPawn ? index - (int)BlackPawn : index], 1 );
\r
2778 SelectObject( hdc, hbm_old );
\r
2780 if( hPieceMask[index] != NULL ) {
\r
2781 DeleteObject( hPieceMask[index] );
\r
2784 hPieceMask[index] = hbm;
\r
2787 hbm = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
\r
2789 SelectObject( hdc, hbm );
\r
2792 HDC dc1 = CreateCompatibleDC( hdc_window );
\r
2793 HDC dc2 = CreateCompatibleDC( hdc_window );
\r
2794 HBITMAP bm2 = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
\r
2796 SelectObject( dc1, hPieceMask[index] );
\r
2797 SelectObject( dc2, bm2 );
\r
2798 FillRect( dc2, &rc, GetStockObject(WHITE_BRUSH) );
\r
2799 BitBlt( dc2, 0, 0, squareSize, squareSize, dc1, 0, 0, SRCINVERT );
\r
2802 Now dc2 contains the inverse of the piece mask, i.e. a mask that preserves
\r
2803 the piece background and deletes (makes transparent) the rest.
\r
2804 Thanks to that mask, we are free to paint the background with the greates
\r
2805 freedom, as we'll be able to mask off the unwanted parts when finished.
\r
2806 We use this, to make gradients and give the pieces a "roundish" look.
\r
2808 SetPieceBackground( hdc, backColor, 2 );
\r
2809 BitBlt( hdc, 0, 0, squareSize, squareSize, dc2, 0, 0, SRCAND );
\r
2813 DeleteObject( bm2 );
\r
2816 SetTextColor( hdc, foreColor );
\r
2817 TextOut( hdc, pt.x, pt.y, &pieceToFontChar[appData.allWhite && index >= (int)BlackPawn ? index - (int)BlackPawn : index], 1 );
\r
2819 SelectObject( hdc, hbm_old );
\r
2821 if( hPieceFace[index] != NULL ) {
\r
2822 DeleteObject( hPieceFace[index] );
\r
2825 hPieceFace[index] = hbm;
\r
2828 static int TranslatePieceToFontPiece( int piece )
\r
2858 case BlackMarshall:
\r
2862 case BlackNightrider:
\r
2868 case BlackUnicorn:
\r
2872 case BlackGrasshopper:
\r
2884 case BlackCardinal:
\r
2891 case WhiteMarshall:
\r
2895 case WhiteNightrider:
\r
2901 case WhiteUnicorn:
\r
2905 case WhiteGrasshopper:
\r
2917 case WhiteCardinal:
\r
2926 void CreatePiecesFromFont()
\r
2929 HDC hdc_window = NULL;
\r
2935 if( fontBitmapSquareSize < 0 ) {
\r
2936 /* Something went seriously wrong in the past: do not try to recreate fonts! */
\r
2940 if( appData.renderPiecesWithFont == NULL || appData.renderPiecesWithFont[0] == NULLCHAR || appData.renderPiecesWithFont[0] == '*' ) {
\r
2941 fontBitmapSquareSize = -1;
\r
2945 if( fontBitmapSquareSize != squareSize ) {
\r
2946 hdc_window = GetDC( hwndMain );
\r
2947 hdc = CreateCompatibleDC( hdc_window );
\r
2949 if( hPieceFont != NULL ) {
\r
2950 DeleteObject( hPieceFont );
\r
2953 for( i=0; i<=(int)BlackKing; i++ ) {
\r
2954 hPieceMask[i] = NULL;
\r
2955 hPieceFace[i] = NULL;
\r
2961 if( appData.fontPieceSize >= 50 && appData.fontPieceSize <= 150 ) {
\r
2962 fontHeight = appData.fontPieceSize;
\r
2965 fontHeight = (fontHeight * squareSize) / 100;
\r
2967 lf.lfHeight = -MulDiv( fontHeight, GetDeviceCaps(hdc, LOGPIXELSY), 72 );
\r
2969 lf.lfEscapement = 0;
\r
2970 lf.lfOrientation = 0;
\r
2971 lf.lfWeight = FW_NORMAL;
\r
2973 lf.lfUnderline = 0;
\r
2974 lf.lfStrikeOut = 0;
\r
2975 lf.lfCharSet = DEFAULT_CHARSET;
\r
2976 lf.lfOutPrecision = OUT_DEFAULT_PRECIS;
\r
2977 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
\r
2978 lf.lfQuality = PROOF_QUALITY;
\r
2979 lf.lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;
\r
2980 strncpy( lf.lfFaceName, appData.renderPiecesWithFont, sizeof(lf.lfFaceName) );
\r
2981 lf.lfFaceName[ sizeof(lf.lfFaceName) - 1 ] = '\0';
\r
2983 hPieceFont = CreateFontIndirect( &lf );
\r
2985 if( hPieceFont == NULL ) {
\r
2986 fontBitmapSquareSize = -2;
\r
2989 /* Setup font-to-piece character table */
\r
2990 if( ! SetCharTable(pieceToFontChar, appData.fontToPieceTable) ) {
\r
2991 /* No (or wrong) global settings, try to detect the font */
\r
2992 if( strstr(lf.lfFaceName,"Alpha") != NULL ) {
\r
2994 SetCharTable(pieceToFontChar, "phbrqkojntwl");
\r
2996 else if( strstr(lf.lfFaceName,"DiagramTT") != NULL ) {
\r
2997 /* DiagramTT* family */
\r
2998 SetCharTable(pieceToFontChar, "PNLRQKpnlrqk");
\r
3000 else if( strstr(lf.lfFaceName,"WinboardF") != NULL ) {
\r
3001 /* Fairy symbols */
\r
3002 SetCharTable(pieceToFontChar, "PNBRQFEACWMOHIJGDVSLUKpnbrqfeacwmohijgdvsluk");
\r
3004 else if( strstr(lf.lfFaceName,"GC2004D") != NULL ) {
\r
3005 /* Good Companion (Some characters get warped as literal :-( */
\r
3006 char s[] = "1cmWG0ñueOS¯®oYI23wgQU";
\r
3007 s[0]=0xB9; s[1]=0xA9; s[6]=0xB1; s[11]=0xBB; s[12]=0xAB; s[17]=0xB3;
\r
3008 SetCharTable(pieceToFontChar, s);
\r
3011 /* Cases, Condal, Leipzig, Lucena, Marroquin, Merida, Usual */
\r
3012 SetCharTable(pieceToFontChar, "pnbrqkomvtwl");
\r
3016 /* Create bitmaps */
\r
3017 hfont_old = SelectObject( hdc, hPieceFont );
\r
3019 CreatePieceMaskFromFont( hdc_window, hdc, PM_WP );
\r
3020 CreatePieceMaskFromFont( hdc_window, hdc, PM_WN );
\r
3021 CreatePieceMaskFromFont( hdc_window, hdc, PM_WB );
\r
3022 CreatePieceMaskFromFont( hdc_window, hdc, PM_WR );
\r
3023 CreatePieceMaskFromFont( hdc_window, hdc, PM_WQ );
\r
3024 CreatePieceMaskFromFont( hdc_window, hdc, PM_WK );
\r
3025 CreatePieceMaskFromFont( hdc_window, hdc, PM_BP );
\r
3026 CreatePieceMaskFromFont( hdc_window, hdc, PM_BN );
\r
3027 CreatePieceMaskFromFont( hdc_window, hdc, PM_BB );
\r
3028 CreatePieceMaskFromFont( hdc_window, hdc, PM_BR );
\r
3029 CreatePieceMaskFromFont( hdc_window, hdc, PM_BQ );
\r
3030 CreatePieceMaskFromFont( hdc_window, hdc, PM_BK );
\r
3032 CreatePieceMaskFromFont( hdc_window, hdc, PM_WA );
\r
3033 CreatePieceMaskFromFont( hdc_window, hdc, PM_WC );
\r
3034 CreatePieceMaskFromFont( hdc_window, hdc, PM_WF );
\r
3035 CreatePieceMaskFromFont( hdc_window, hdc, PM_WH );
\r
3036 CreatePieceMaskFromFont( hdc_window, hdc, PM_WE );
\r
3037 CreatePieceMaskFromFont( hdc_window, hdc, PM_WW );
\r
3038 CreatePieceMaskFromFont( hdc_window, hdc, PM_WU );
\r
3039 CreatePieceMaskFromFont( hdc_window, hdc, PM_WO );
\r
3040 CreatePieceMaskFromFont( hdc_window, hdc, PM_WG );
\r
3041 CreatePieceMaskFromFont( hdc_window, hdc, PM_WM );
\r
3042 CreatePieceMaskFromFont( hdc_window, hdc, PM_WSG );
\r
3043 CreatePieceMaskFromFont( hdc_window, hdc, PM_WV );
\r
3044 CreatePieceMaskFromFont( hdc_window, hdc, PM_WAB );
\r
3045 CreatePieceMaskFromFont( hdc_window, hdc, PM_WD );
\r
3046 CreatePieceMaskFromFont( hdc_window, hdc, PM_WL );
\r
3047 CreatePieceMaskFromFont( hdc_window, hdc, PM_WS );
\r
3048 CreatePieceMaskFromFont( hdc_window, hdc, PM_BA );
\r
3049 CreatePieceMaskFromFont( hdc_window, hdc, PM_BC );
\r
3050 CreatePieceMaskFromFont( hdc_window, hdc, PM_BF );
\r
3051 CreatePieceMaskFromFont( hdc_window, hdc, PM_BH );
\r
3052 CreatePieceMaskFromFont( hdc_window, hdc, PM_BE );
\r
3053 CreatePieceMaskFromFont( hdc_window, hdc, PM_BW );
\r
3054 CreatePieceMaskFromFont( hdc_window, hdc, PM_BU );
\r
3055 CreatePieceMaskFromFont( hdc_window, hdc, PM_BO );
\r
3056 CreatePieceMaskFromFont( hdc_window, hdc, PM_BG );
\r
3057 CreatePieceMaskFromFont( hdc_window, hdc, PM_BM );
\r
3058 CreatePieceMaskFromFont( hdc_window, hdc, PM_BSG );
\r
3059 CreatePieceMaskFromFont( hdc_window, hdc, PM_BV );
\r
3060 CreatePieceMaskFromFont( hdc_window, hdc, PM_BAB );
\r
3061 CreatePieceMaskFromFont( hdc_window, hdc, PM_BD );
\r
3062 CreatePieceMaskFromFont( hdc_window, hdc, PM_BL );
\r
3063 CreatePieceMaskFromFont( hdc_window, hdc, PM_BS );
\r
3065 for(i=(int)WhitePawn; i<(int)EmptySquare; i++) /* [HGM] made a loop for this */
\r
3066 if(PieceToChar((ChessSquare)i) != '.') /* skip unused pieces */
\r
3067 CreatePieceMaskFromFont( hdc_window, hdc, i );
\r
3069 SelectObject( hdc, hfont_old );
\r
3071 fontBitmapSquareSize = squareSize;
\r
3075 if( hdc != NULL ) {
\r
3079 if( hdc_window != NULL ) {
\r
3080 ReleaseDC( hwndMain, hdc_window );
\r
3085 DoLoadBitmap(HINSTANCE hinst, char *piece, int squareSize, char *suffix)
\r
3089 sprintf(name, "%s%d%s", piece, squareSize, suffix);
\r
3090 if (gameInfo.event &&
\r
3091 strcmp(gameInfo.event, "Easter Egg Hunt") == 0 &&
\r
3092 strcmp(name, "k80s") == 0) {
\r
3093 strcpy(name, "tim");
\r
3095 return LoadBitmap(hinst, name);
\r
3099 /* Insert a color into the program's logical palette
\r
3100 structure. This code assumes the given color is
\r
3101 the result of the RGB or PALETTERGB macro, and it
\r
3102 knows how those macros work (which is documented).
\r
3105 InsertInPalette(COLORREF color)
\r
3107 LPPALETTEENTRY pe = &(pLogPal->palPalEntry[pLogPal->palNumEntries]);
\r
3109 if (pLogPal->palNumEntries++ >= PALETTESIZE) {
\r
3110 DisplayFatalError("Too many colors", 0, 1);
\r
3111 pLogPal->palNumEntries--;
\r
3115 pe->peFlags = (char) 0;
\r
3116 pe->peRed = (char) (0xFF & color);
\r
3117 pe->peGreen = (char) (0xFF & (color >> 8));
\r
3118 pe->peBlue = (char) (0xFF & (color >> 16));
\r
3124 InitDrawingColors()
\r
3126 if (pLogPal == NULL) {
\r
3127 /* Allocate enough memory for a logical palette with
\r
3128 * PALETTESIZE entries and set the size and version fields
\r
3129 * of the logical palette structure.
\r
3131 pLogPal = (NPLOGPALETTE)
\r
3132 LocalAlloc(LMEM_FIXED, (sizeof(LOGPALETTE) +
\r
3133 (sizeof(PALETTEENTRY) * (PALETTESIZE))));
\r
3134 pLogPal->palVersion = 0x300;
\r
3136 pLogPal->palNumEntries = 0;
\r
3138 InsertInPalette(lightSquareColor);
\r
3139 InsertInPalette(darkSquareColor);
\r
3140 InsertInPalette(whitePieceColor);
\r
3141 InsertInPalette(blackPieceColor);
\r
3142 InsertInPalette(highlightSquareColor);
\r
3143 InsertInPalette(premoveHighlightColor);
\r
3145 /* create a logical color palette according the information
\r
3146 * in the LOGPALETTE structure.
\r
3148 hPal = CreatePalette((LPLOGPALETTE) pLogPal);
\r
3150 lightSquareBrush = CreateSolidBrush(lightSquareColor);
\r
3151 blackSquareBrush = CreateSolidBrush(blackPieceColor);
\r
3152 darkSquareBrush = CreateSolidBrush(darkSquareColor);
\r
3153 whitePieceBrush = CreateSolidBrush(whitePieceColor);
\r
3154 blackPieceBrush = CreateSolidBrush(blackPieceColor);
\r
3155 iconBkgndBrush = CreateSolidBrush(GetSysColor(COLOR_BACKGROUND));
\r
3156 explodeBrush = CreateSolidBrush(highlightSquareColor); // [HGM] atomic
\r
3157 /* [AS] Force rendering of the font-based pieces */
\r
3158 if( fontBitmapSquareSize > 0 ) {
\r
3159 fontBitmapSquareSize = 0;
\r
3165 BoardWidth(int boardSize, int n)
\r
3166 { /* [HGM] argument n added to allow different width and height */
\r
3167 int lineGap = sizeInfo[boardSize].lineGap;
\r
3169 if( appData.overrideLineGap >= 0 && appData.overrideLineGap <= 5 ) {
\r
3170 lineGap = appData.overrideLineGap;
\r
3173 return (n + 1) * lineGap +
\r
3174 n * sizeInfo[boardSize].squareSize;
\r
3177 /* Respond to board resize by dragging edge */
\r
3179 ResizeBoard(int newSizeX, int newSizeY, int flags)
\r
3181 BoardSize newSize = NUM_SIZES - 1;
\r
3182 static int recurse = 0;
\r
3183 if (IsIconic(hwndMain)) return;
\r
3184 if (recurse > 0) return;
\r
3186 while (newSize > 0) {
\r
3187 InitDrawingSizes(newSize+1000, 0); // [HGM] kludge to update sizeInfo without visible effects
\r
3188 if(newSizeX >= sizeInfo[newSize].cliWidth &&
\r
3189 newSizeY >= sizeInfo[newSize].cliHeight) break;
\r
3192 boardSize = newSize;
\r
3193 InitDrawingSizes(boardSize, flags);
\r
3200 InitDrawingSizes(BoardSize boardSize, int flags)
\r
3202 int i, boardWidth, boardHeight; /* [HGM] height treated separately */
\r
3203 ChessSquare piece;
\r
3204 static int oldBoardSize = -1, oldTinyLayout = 0;
\r
3206 SIZE clockSize, messageSize;
\r
3208 char buf[MSG_SIZ];
\r
3210 HMENU hmenu = GetMenu(hwndMain);
\r
3211 RECT crect, wrect, oldRect;
\r
3213 LOGBRUSH logbrush;
\r
3215 int suppressVisibleEffects = 0; // [HGM] kludge to request updating sizeInfo only
\r
3216 if((int)boardSize >= 1000 ) { boardSize -= 1000; suppressVisibleEffects = 1; }
\r
3218 /* [HGM] call with -2 uses old size (for if nr of files, ranks changes) */
\r
3219 if(boardSize == (BoardSize)(-2) ) boardSize = oldBoardSize;
\r
3221 oldRect.left = boardX; //[HGM] placement: remember previous window params
\r
3222 oldRect.top = boardY;
\r
3223 oldRect.right = boardX + winWidth;
\r
3224 oldRect.bottom = boardY + winHeight;
\r
3226 tinyLayout = sizeInfo[boardSize].tinyLayout;
\r
3227 smallLayout = sizeInfo[boardSize].smallLayout;
\r
3228 squareSize = sizeInfo[boardSize].squareSize;
\r
3229 lineGap = sizeInfo[boardSize].lineGap;
\r
3230 minorSize = 0; /* [HGM] Kludge to see if demagnified pieces need to be shifted */
\r
3232 if( appData.overrideLineGap >= 0 && appData.overrideLineGap <= 5 ) {
\r
3233 lineGap = appData.overrideLineGap;
\r
3236 if (tinyLayout != oldTinyLayout) {
\r
3237 long style = GetWindowLong(hwndMain, GWL_STYLE);
\r
3239 style &= ~WS_SYSMENU;
\r
3240 InsertMenu(hmenu, IDM_Exit, MF_BYCOMMAND, IDM_Minimize,
\r
3241 "&Minimize\tCtrl+F4");
\r
3243 style |= WS_SYSMENU;
\r
3244 RemoveMenu(hmenu, IDM_Minimize, MF_BYCOMMAND);
\r
3246 SetWindowLong(hwndMain, GWL_STYLE, style);
\r
3248 for (i=0; menuBarText[tinyLayout][i]; i++) {
\r
3249 ModifyMenu(hmenu, i, MF_STRING|MF_BYPOSITION|MF_POPUP,
\r
3250 (UINT)GetSubMenu(hmenu, i), menuBarText[tinyLayout][i]);
\r
3252 DrawMenuBar(hwndMain);
\r
3255 boardWidth = BoardWidth(boardSize, BOARD_WIDTH);
\r
3256 boardHeight = BoardWidth(boardSize, BOARD_HEIGHT);
\r
3258 /* Get text area sizes */
\r
3259 hdc = GetDC(hwndMain);
\r
3260 if (appData.clockMode) {
\r
3261 sprintf(buf, "White: %s", TimeString(23*60*60*1000L));
\r
3263 sprintf(buf, "White");
\r
3265 oldFont = SelectObject(hdc, font[boardSize][CLOCK_FONT]->hf);
\r
3266 GetTextExtentPoint(hdc, buf, strlen(buf), &clockSize);
\r
3267 SelectObject(hdc, font[boardSize][MESSAGE_FONT]->hf);
\r
3268 str = "We only care about the height here";
\r
3269 GetTextExtentPoint(hdc, str, strlen(str), &messageSize);
\r
3270 SelectObject(hdc, oldFont);
\r
3271 ReleaseDC(hwndMain, hdc);
\r
3273 /* Compute where everything goes */
\r
3274 if((first.programLogo || second.programLogo) && !tinyLayout) {
\r
3275 /* [HGM] logo: if either logo is on, reserve space for it */
\r
3276 logoHeight = 2*clockSize.cy;
\r
3277 leftLogoRect.left = OUTER_MARGIN;
\r
3278 leftLogoRect.right = leftLogoRect.left + 4*clockSize.cy;
\r
3279 leftLogoRect.top = OUTER_MARGIN;
\r
3280 leftLogoRect.bottom = OUTER_MARGIN + logoHeight;
\r
3282 rightLogoRect.right = OUTER_MARGIN + boardWidth;
\r
3283 rightLogoRect.left = rightLogoRect.right - 4*clockSize.cy;
\r
3284 rightLogoRect.top = OUTER_MARGIN;
\r
3285 rightLogoRect.bottom = OUTER_MARGIN + logoHeight;
\r
3288 whiteRect.left = leftLogoRect.right;
\r
3289 whiteRect.right = OUTER_MARGIN + boardWidth/2 - INNER_MARGIN/2;
\r
3290 whiteRect.top = OUTER_MARGIN;
\r
3291 whiteRect.bottom = whiteRect.top + logoHeight;
\r
3293 blackRect.right = rightLogoRect.left;
\r
3294 blackRect.left = whiteRect.right + INNER_MARGIN;
\r
3295 blackRect.top = whiteRect.top;
\r
3296 blackRect.bottom = whiteRect.bottom;
\r
3298 whiteRect.left = OUTER_MARGIN;
\r
3299 whiteRect.right = whiteRect.left + boardWidth/2 - INNER_MARGIN/2;
\r
3300 whiteRect.top = OUTER_MARGIN;
\r
3301 whiteRect.bottom = whiteRect.top + clockSize.cy;
\r
3303 blackRect.left = whiteRect.right + INNER_MARGIN;
\r
3304 blackRect.right = blackRect.left + boardWidth/2 - 1;
\r
3305 blackRect.top = whiteRect.top;
\r
3306 blackRect.bottom = whiteRect.bottom;
\r
3309 messageRect.left = OUTER_MARGIN + MESSAGE_LINE_LEFTMARGIN;
\r
3310 if (appData.showButtonBar) {
\r
3311 messageRect.right = OUTER_MARGIN + boardWidth // [HGM] logo: expressed independent of clock placement
\r
3312 - N_BUTTONS*BUTTON_WIDTH - MESSAGE_LINE_LEFTMARGIN;
\r
3314 messageRect.right = OUTER_MARGIN + boardWidth;
\r
3316 messageRect.top = whiteRect.bottom + INNER_MARGIN;
\r
3317 messageRect.bottom = messageRect.top + messageSize.cy;
\r
3319 boardRect.left = OUTER_MARGIN;
\r
3320 boardRect.right = boardRect.left + boardWidth;
\r
3321 boardRect.top = messageRect.bottom + INNER_MARGIN;
\r
3322 boardRect.bottom = boardRect.top + boardHeight;
\r
3324 sizeInfo[boardSize].cliWidth = boardRect.right + OUTER_MARGIN;
\r
3325 sizeInfo[boardSize].cliHeight = boardRect.bottom + OUTER_MARGIN;
\r
3326 oldBoardSize = boardSize;
\r
3327 oldTinyLayout = tinyLayout;
\r
3328 winW = 2 * GetSystemMetrics(SM_CXFRAME) + boardRect.right + OUTER_MARGIN;
\r
3329 winH = 2 * GetSystemMetrics(SM_CYFRAME) + GetSystemMetrics(SM_CYMENU) +
\r
3330 GetSystemMetrics(SM_CYCAPTION) + boardRect.bottom + OUTER_MARGIN;
\r
3331 if(suppressVisibleEffects) return; // [HGM] when called for filling sizeInfo only
\r
3332 winWidth = winW; // [HGM] placement: set through temporary which can used by initial sizing choice
\r
3333 winHeight = winH; // without disturbing window attachments
\r
3334 GetWindowRect(hwndMain, &wrect);
\r
3335 SetWindowPos(hwndMain, NULL, 0, 0, winWidth, winHeight,
\r
3336 SWP_NOCOPYBITS|SWP_NOZORDER|SWP_NOMOVE);
\r
3338 // [HGM] placement: let attached windows follow size change.
\r
3339 ReattachAfterSize( &oldRect, winWidth, winHeight, moveHistoryDialog, &wpMoveHistory );
\r
3340 ReattachAfterSize( &oldRect, winWidth, winHeight, evalGraphDialog, &wpEvalGraph );
\r
3341 ReattachAfterSize( &oldRect, winWidth, winHeight, engineOutputDialog, &wpEngineOutput );
\r
3342 ReattachAfterSize( &oldRect, winWidth, winHeight, gameListDialog, &wpGameList );
\r
3343 ReattachAfterSize( &oldRect, winWidth, winHeight, hwndConsole, &wpConsole );
\r
3345 /* compensate if menu bar wrapped */
\r
3346 GetClientRect(hwndMain, &crect);
\r
3347 offby = boardRect.bottom + OUTER_MARGIN - crect.bottom;
\r
3348 winHeight += offby;
\r
3350 case WMSZ_TOPLEFT:
\r
3351 SetWindowPos(hwndMain, NULL,
\r
3352 wrect.right - winWidth, wrect.bottom - winHeight,
\r
3353 winWidth, winHeight, SWP_NOCOPYBITS|SWP_NOZORDER);
\r
3356 case WMSZ_TOPRIGHT:
\r
3358 SetWindowPos(hwndMain, NULL,
\r
3359 wrect.left, wrect.bottom - winHeight,
\r
3360 winWidth, winHeight, SWP_NOCOPYBITS|SWP_NOZORDER);
\r
3363 case WMSZ_BOTTOMLEFT:
\r
3365 SetWindowPos(hwndMain, NULL,
\r
3366 wrect.right - winWidth, wrect.top,
\r
3367 winWidth, winHeight, SWP_NOCOPYBITS|SWP_NOZORDER);
\r
3370 case WMSZ_BOTTOMRIGHT:
\r
3374 SetWindowPos(hwndMain, NULL, 0, 0, winWidth, winHeight,
\r
3375 SWP_NOCOPYBITS|SWP_NOZORDER|SWP_NOMOVE);
\r
3380 for (i = 0; i < N_BUTTONS; i++) {
\r
3381 if (buttonDesc[i].hwnd != NULL) {
\r
3382 DestroyWindow(buttonDesc[i].hwnd);
\r
3383 buttonDesc[i].hwnd = NULL;
\r
3385 if (appData.showButtonBar) {
\r
3386 buttonDesc[i].hwnd =
\r
3387 CreateWindow("BUTTON", buttonDesc[i].label,
\r
3388 WS_VISIBLE | WS_CHILD | BS_PUSHBUTTON,
\r
3389 boardRect.right - BUTTON_WIDTH*(N_BUTTONS-i),
\r
3390 messageRect.top, BUTTON_WIDTH, messageSize.cy, hwndMain,
\r
3391 (HMENU) buttonDesc[i].id,
\r
3392 (HINSTANCE) GetWindowLong(hwndMain, GWL_HINSTANCE), NULL);
\r
3394 SendMessage(buttonDesc[i].hwnd, WM_SETFONT,
\r
3395 (WPARAM)font[boardSize][MESSAGE_FONT]->hf,
\r
3396 MAKELPARAM(FALSE, 0));
\r
3398 if (buttonDesc[i].id == IDM_Pause)
\r
3399 hwndPause = buttonDesc[i].hwnd;
\r
3400 buttonDesc[i].wndproc = (WNDPROC)
\r
3401 SetWindowLong(buttonDesc[i].hwnd, GWL_WNDPROC, (LONG) ButtonProc);
\r
3404 if (gridPen != NULL) DeleteObject(gridPen);
\r
3405 if (highlightPen != NULL) DeleteObject(highlightPen);
\r
3406 if (premovePen != NULL) DeleteObject(premovePen);
\r
3407 if (lineGap != 0) {
\r
3408 logbrush.lbStyle = BS_SOLID;
\r
3409 logbrush.lbColor = RGB(0, 0, 0); /* grid pen color = black */
\r
3411 ExtCreatePen(PS_GEOMETRIC|PS_SOLID|PS_ENDCAP_FLAT|PS_JOIN_MITER,
\r
3412 lineGap, &logbrush, 0, NULL);
\r
3413 logbrush.lbColor = highlightSquareColor;
\r
3415 ExtCreatePen(PS_GEOMETRIC|PS_SOLID|PS_ENDCAP_FLAT|PS_JOIN_MITER,
\r
3416 lineGap, &logbrush, 0, NULL);
\r
3418 logbrush.lbColor = premoveHighlightColor;
\r
3420 ExtCreatePen(PS_GEOMETRIC|PS_SOLID|PS_ENDCAP_FLAT|PS_JOIN_MITER,
\r
3421 lineGap, &logbrush, 0, NULL);
\r
3423 /* [HGM] Loop had to be split in part for vert. and hor. lines */
\r
3424 for (i = 0; i < BOARD_HEIGHT + 1; i++) {
\r
3425 gridEndpoints[i*2].x = boardRect.left + lineGap / 2;
\r
3426 gridEndpoints[i*2].y = gridEndpoints[i*2 + 1].y =
\r
3427 boardRect.top + lineGap / 2 + (i * (squareSize + lineGap));
\r
3428 gridEndpoints[i*2 + 1].x = boardRect.left + lineGap / 2 +
\r
3429 BOARD_WIDTH * (squareSize + lineGap);
\r
3430 gridVertexCounts[i*2] = gridVertexCounts[i*2 + 1] = 2;
\r
3432 for (i = 0; i < BOARD_WIDTH + 1; i++) {
\r
3433 gridEndpoints[i*2 + BOARD_HEIGHT*2 + 2].y = boardRect.top + lineGap / 2;
\r
3434 gridEndpoints[i*2 + BOARD_HEIGHT*2 + 2].x =
\r
3435 gridEndpoints[i*2 + 1 + BOARD_HEIGHT*2 + 2].x = boardRect.left +
\r
3436 lineGap / 2 + (i * (squareSize + lineGap));
\r
3437 gridEndpoints[i*2 + 1 + BOARD_HEIGHT*2 + 2].y =
\r
3438 boardRect.top + BOARD_HEIGHT * (squareSize + lineGap);
\r
3439 gridVertexCounts[i*2] = gridVertexCounts[i*2 + 1] = 2;
\r
3443 /* [HGM] Licensing requirement */
\r
3445 if(gameInfo.variant == VariantGothic) GothicPopUp( GOTHIC, VariantGothic); else
\r
3448 if(gameInfo.variant == VariantFalcon) GothicPopUp( FALCON, VariantFalcon); else
\r
3450 GothicPopUp( "", VariantNormal);
\r
3453 /* if (boardSize == oldBoardSize) return; [HGM] variant might have changed */
\r
3455 /* Load piece bitmaps for this board size */
\r
3456 for (i=0; i<=2; i++) {
\r
3457 for (piece = WhitePawn;
\r
3458 (int) piece < (int) BlackPawn;
\r
3459 piece = (ChessSquare) ((int) piece + 1)) {
\r
3460 if (pieceBitmap[i][piece] != NULL)
\r
3461 DeleteObject(pieceBitmap[i][piece]);
\r
3465 fontBitmapSquareSize = 0; /* [HGM] render: make sure pieces will be recreated, as we might need others now */
\r
3466 // Orthodox Chess pieces
\r
3467 pieceBitmap[0][WhitePawn] = DoLoadBitmap(hInst, "p", squareSize, "s");
\r
3468 pieceBitmap[0][WhiteKnight] = DoLoadBitmap(hInst, "n", squareSize, "s");
\r
3469 pieceBitmap[0][WhiteBishop] = DoLoadBitmap(hInst, "b", squareSize, "s");
\r
3470 pieceBitmap[0][WhiteRook] = DoLoadBitmap(hInst, "r", squareSize, "s");
\r
3471 pieceBitmap[0][WhiteKing] = DoLoadBitmap(hInst, "k", squareSize, "s");
\r
3472 pieceBitmap[1][WhitePawn] = DoLoadBitmap(hInst, "p", squareSize, "o");
\r
3473 pieceBitmap[1][WhiteKnight] = DoLoadBitmap(hInst, "n", squareSize, "o");
\r
3474 pieceBitmap[1][WhiteBishop] = DoLoadBitmap(hInst, "b", squareSize, "o");
\r
3475 pieceBitmap[1][WhiteRook] = DoLoadBitmap(hInst, "r", squareSize, "o");
\r
3476 pieceBitmap[1][WhiteKing] = DoLoadBitmap(hInst, "k", squareSize, "o");
\r
3477 pieceBitmap[2][WhitePawn] = DoLoadBitmap(hInst, "p", squareSize, "w");
\r
3478 pieceBitmap[2][WhiteKnight] = DoLoadBitmap(hInst, "n", squareSize, "w");
\r
3479 pieceBitmap[2][WhiteBishop] = DoLoadBitmap(hInst, "b", squareSize, "w");
\r
3480 pieceBitmap[2][WhiteRook] = DoLoadBitmap(hInst, "r", squareSize, "w");
\r
3481 pieceBitmap[2][WhiteKing] = DoLoadBitmap(hInst, "k", squareSize, "w");
\r
3482 if( !strcmp(appData.variant, "shogi") && (squareSize==72 || squareSize==49)) {
\r
3483 // in Shogi, Hijack the unused Queen for Lance
\r
3484 pieceBitmap[0][WhiteQueen] = DoLoadBitmap(hInst, "l", squareSize, "s");
\r
3485 pieceBitmap[1][WhiteQueen] = DoLoadBitmap(hInst, "l", squareSize, "o");
\r
3486 pieceBitmap[2][WhiteQueen] = DoLoadBitmap(hInst, "l", squareSize, "w");
\r
3488 pieceBitmap[0][WhiteQueen] = DoLoadBitmap(hInst, "q", squareSize, "s");
\r
3489 pieceBitmap[1][WhiteQueen] = DoLoadBitmap(hInst, "q", squareSize, "o");
\r
3490 pieceBitmap[2][WhiteQueen] = DoLoadBitmap(hInst, "q", squareSize, "w");
\r
3493 if(squareSize <= 72 && squareSize >= 33) {
\r
3494 /* A & C are available in most sizes now */
\r
3495 if(squareSize != 49 && squareSize != 72 && squareSize != 33) { // Vortex-like
\r
3496 pieceBitmap[0][WhiteAngel] = DoLoadBitmap(hInst, "a", squareSize, "s");
\r
3497 pieceBitmap[1][WhiteAngel] = DoLoadBitmap(hInst, "a", squareSize, "o");
\r
3498 pieceBitmap[2][WhiteAngel] = DoLoadBitmap(hInst, "a", squareSize, "w");
\r
3499 pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "s");
\r
3500 pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "o");
\r
3501 pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "w");
\r
3502 pieceBitmap[0][WhiteCobra] = DoLoadBitmap(hInst, "cv", squareSize, "s");
\r
3503 pieceBitmap[1][WhiteCobra] = DoLoadBitmap(hInst, "cv", squareSize, "o");
\r
3504 pieceBitmap[2][WhiteCobra] = DoLoadBitmap(hInst, "cv", squareSize, "w");
\r
3505 pieceBitmap[0][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "s");
\r
3506 pieceBitmap[1][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "o");
\r
3507 pieceBitmap[2][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "w");
\r
3508 } else { // Smirf-like
\r
3509 pieceBitmap[0][WhiteAngel] = DoLoadBitmap(hInst, "aa", squareSize, "s");
\r
3510 pieceBitmap[1][WhiteAngel] = DoLoadBitmap(hInst, "aa", squareSize, "o");
\r
3511 pieceBitmap[2][WhiteAngel] = DoLoadBitmap(hInst, "aa", squareSize, "w");
\r
3513 if(gameInfo.variant == VariantGothic) { // Vortex-like
\r
3514 pieceBitmap[0][WhiteMarshall] = DoLoadBitmap(hInst, "cv", squareSize, "s");
\r
3515 pieceBitmap[1][WhiteMarshall] = DoLoadBitmap(hInst, "cv", squareSize, "o");
\r
3516 pieceBitmap[2][WhiteMarshall] = DoLoadBitmap(hInst, "cv", squareSize, "w");
\r
3517 } else { // WinBoard standard
\r
3518 pieceBitmap[0][WhiteMarshall] = DoLoadBitmap(hInst, "c", squareSize, "s");
\r
3519 pieceBitmap[1][WhiteMarshall] = DoLoadBitmap(hInst, "c", squareSize, "o");
\r
3520 pieceBitmap[2][WhiteMarshall] = DoLoadBitmap(hInst, "c", squareSize, "w");
\r
3525 if(squareSize==72 || squareSize==49 || squareSize==33) { /* experiment with some home-made bitmaps */
\r
3526 pieceBitmap[0][WhiteFerz] = DoLoadBitmap(hInst, "f", squareSize, "s");
\r
3527 pieceBitmap[1][WhiteFerz] = DoLoadBitmap(hInst, "f", squareSize, "o");
\r
3528 pieceBitmap[2][WhiteFerz] = DoLoadBitmap(hInst, "f", squareSize, "w");
\r
3529 pieceBitmap[0][WhiteWazir] = DoLoadBitmap(hInst, "w", squareSize, "s");
\r
3530 pieceBitmap[1][WhiteWazir] = DoLoadBitmap(hInst, "w", squareSize, "o");
\r
3531 pieceBitmap[2][WhiteWazir] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
3532 pieceBitmap[0][WhiteAlfil] = DoLoadBitmap(hInst, "e", squareSize, "s");
\r
3533 pieceBitmap[1][WhiteAlfil] = DoLoadBitmap(hInst, "e", squareSize, "o");
\r
3534 pieceBitmap[2][WhiteAlfil] = DoLoadBitmap(hInst, "e", squareSize, "w");
\r
3535 pieceBitmap[0][WhiteMan] = DoLoadBitmap(hInst, "m", squareSize, "s");
\r
3536 pieceBitmap[1][WhiteMan] = DoLoadBitmap(hInst, "m", squareSize, "o");
\r
3537 pieceBitmap[2][WhiteMan] = DoLoadBitmap(hInst, "m", squareSize, "w");
\r
3538 pieceBitmap[0][WhiteCardinal] = DoLoadBitmap(hInst, "a", squareSize, "s");
\r
3539 pieceBitmap[1][WhiteCardinal] = DoLoadBitmap(hInst, "a", squareSize, "o");
\r
3540 pieceBitmap[2][WhiteCardinal] = DoLoadBitmap(hInst, "a", squareSize, "w");
\r
3541 pieceBitmap[0][WhiteDragon] = DoLoadBitmap(hInst, "dk", squareSize, "s");
\r
3542 pieceBitmap[1][WhiteDragon] = DoLoadBitmap(hInst, "dk", squareSize, "o");
\r
3543 pieceBitmap[2][WhiteDragon] = DoLoadBitmap(hInst, "dk", squareSize, "w");
\r
3544 pieceBitmap[0][WhiteFalcon] = DoLoadBitmap(hInst, "v", squareSize, "s");
\r
3545 pieceBitmap[1][WhiteFalcon] = DoLoadBitmap(hInst, "v", squareSize, "o");
\r
3546 pieceBitmap[2][WhiteFalcon] = DoLoadBitmap(hInst, "v", squareSize, "w");
\r
3547 pieceBitmap[0][WhiteCobra] = DoLoadBitmap(hInst, "s", squareSize, "s");
\r
3548 pieceBitmap[1][WhiteCobra] = DoLoadBitmap(hInst, "s", squareSize, "o");
\r
3549 pieceBitmap[2][WhiteCobra] = DoLoadBitmap(hInst, "s", squareSize, "w");
\r
3550 pieceBitmap[0][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "s");
\r
3551 pieceBitmap[1][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "o");
\r
3552 pieceBitmap[2][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "w");
\r
3553 pieceBitmap[0][WhiteUnicorn] = DoLoadBitmap(hInst, "u", squareSize, "s");
\r
3554 pieceBitmap[1][WhiteUnicorn] = DoLoadBitmap(hInst, "u", squareSize, "o");
\r
3555 pieceBitmap[2][WhiteUnicorn] = DoLoadBitmap(hInst, "u", squareSize, "w");
\r
3557 if(gameInfo.variant == VariantShogi) { /* promoted Gold represemtations */
\r
3558 pieceBitmap[0][WhiteCannon] = DoLoadBitmap(hInst, "wp", squareSize, "s");
\r
3559 pieceBitmap[1][WhiteCannon] = DoLoadBitmap(hInst, "wp", squareSize, "o");
\r
3560 pieceBitmap[2][WhiteCannon] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
3561 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "wn", squareSize, "s");
\r
3562 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "wn", squareSize, "o");
\r
3563 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
3564 pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "ws", squareSize, "s");
\r
3565 pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "ws", squareSize, "o");
\r
3566 pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
3567 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "wl", squareSize, "s");
\r
3568 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "wl", squareSize, "o");
\r
3569 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
3571 pieceBitmap[0][WhiteCannon] = DoLoadBitmap(hInst, "o", squareSize, "s");
\r
3572 pieceBitmap[1][WhiteCannon] = DoLoadBitmap(hInst, "o", squareSize, "o");
\r
3573 pieceBitmap[2][WhiteCannon] = DoLoadBitmap(hInst, "o", squareSize, "w");
\r
3574 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "h", squareSize, "s");
\r
3575 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "h", squareSize, "o");
\r
3576 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "h", squareSize, "w");
\r
3577 pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "s");
\r
3578 pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "o");
\r
3579 pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "w");
\r
3580 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "g", squareSize, "s");
\r
3581 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "g", squareSize, "o");
\r
3582 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "g", squareSize, "w");
\r
3585 } else { /* other size, no special bitmaps available. Use smaller symbols */
\r
3586 if((int)boardSize < 2) minorSize = sizeInfo[0].squareSize;
\r
3587 else minorSize = sizeInfo[(int)boardSize - 2].squareSize;
\r
3588 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "n", minorSize, "s");
\r
3589 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "n", minorSize, "o");
\r
3590 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "n", minorSize, "w");
\r
3591 pieceBitmap[0][WhiteCardinal] = DoLoadBitmap(hInst, "b", minorSize, "s");
\r
3592 pieceBitmap[1][WhiteCardinal] = DoLoadBitmap(hInst, "b", minorSize, "o");
\r
3593 pieceBitmap[2][WhiteCardinal] = DoLoadBitmap(hInst, "b", minorSize, "w");
\r
3594 pieceBitmap[0][WhiteDragon] = DoLoadBitmap(hInst, "r", minorSize, "s");
\r
3595 pieceBitmap[1][WhiteDragon] = DoLoadBitmap(hInst, "r", minorSize, "o");
\r
3596 pieceBitmap[2][WhiteDragon] = DoLoadBitmap(hInst, "r", minorSize, "w");
\r
3597 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "q", minorSize, "s");
\r
3598 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "q", minorSize, "o");
\r
3599 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "q", minorSize, "w");
\r
3603 if(gameInfo.variant == VariantShogi && squareSize == 58)
\r
3604 /* special Shogi support in this size */
\r
3605 { for (i=0; i<=2; i++) { /* replace all bitmaps */
\r
3606 for (piece = WhitePawn;
\r
3607 (int) piece < (int) BlackPawn;
\r
3608 piece = (ChessSquare) ((int) piece + 1)) {
\r
3609 if (pieceBitmap[i][piece] != NULL)
\r
3610 DeleteObject(pieceBitmap[i][piece]);
\r
3613 pieceBitmap[0][WhitePawn] = DoLoadBitmap(hInst, "sp", squareSize, "o");
\r
3614 pieceBitmap[0][WhiteKnight] = DoLoadBitmap(hInst, "sn", squareSize, "o");
\r
3615 pieceBitmap[0][WhiteBishop] = DoLoadBitmap(hInst, "sb", squareSize, "o");
\r
3616 pieceBitmap[0][WhiteRook] = DoLoadBitmap(hInst, "sr", squareSize, "o");
\r
3617 pieceBitmap[0][WhiteQueen] = DoLoadBitmap(hInst, "sl", squareSize, "o");
\r
3618 pieceBitmap[0][WhiteKing] = DoLoadBitmap(hInst, "sk", squareSize, "o");
\r
3619 pieceBitmap[0][WhiteFerz] = DoLoadBitmap(hInst, "sf", squareSize, "o");
\r
3620 pieceBitmap[0][WhiteWazir] = DoLoadBitmap(hInst, "sw", squareSize, "o");
\r
3621 pieceBitmap[0][WhiteCannon] = DoLoadBitmap(hInst, "su", squareSize, "o");
\r
3622 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "sh", squareSize, "o");
\r
3623 pieceBitmap[0][WhiteCardinal] = DoLoadBitmap(hInst, "sa", squareSize, "o");
\r
3624 pieceBitmap[0][WhiteDragon] = DoLoadBitmap(hInst, "sc", squareSize, "o");
\r
3625 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "sg", squareSize, "o");
\r
3626 pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "ss", squareSize, "o");
\r
3627 pieceBitmap[1][WhitePawn] = DoLoadBitmap(hInst, "sp", squareSize, "o");
\r
3628 pieceBitmap[1][WhiteKnight] = DoLoadBitmap(hInst, "sn", squareSize, "o");
\r
3629 pieceBitmap[1][WhiteBishop] = DoLoadBitmap(hInst, "sb", squareSize, "o");
\r
3630 pieceBitmap[1][WhiteRook] = DoLoadBitmap(hInst, "sr", squareSize, "o");
\r
3631 pieceBitmap[1][WhiteQueen] = DoLoadBitmap(hInst, "sl", squareSize, "o");
\r
3632 pieceBitmap[1][WhiteKing] = DoLoadBitmap(hInst, "sk", squareSize, "o");
\r
3633 pieceBitmap[1][WhiteFerz] = DoLoadBitmap(hInst, "sf", squareSize, "o");
\r
3634 pieceBitmap[1][WhiteWazir] = DoLoadBitmap(hInst, "sw", squareSize, "o");
\r
3635 pieceBitmap[1][WhiteCannon] = DoLoadBitmap(hInst, "su", squareSize, "o");
\r
3636 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "sh", squareSize, "o");
\r
3637 pieceBitmap[1][WhiteCardinal] = DoLoadBitmap(hInst, "sa", squareSize, "o");
\r
3638 pieceBitmap[1][WhiteDragon] = DoLoadBitmap(hInst, "sc", squareSize, "o");
\r
3639 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "sg", squareSize, "o");
\r
3640 pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "ss", squareSize, "o");
\r
3641 pieceBitmap[2][WhitePawn] = DoLoadBitmap(hInst, "sp", squareSize, "w");
\r
3642 pieceBitmap[2][WhiteKnight] = DoLoadBitmap(hInst, "sn", squareSize, "w");
\r
3643 pieceBitmap[2][WhiteBishop] = DoLoadBitmap(hInst, "sr", squareSize, "w");
\r
3644 pieceBitmap[2][WhiteRook] = DoLoadBitmap(hInst, "sr", squareSize, "w");
\r
3645 pieceBitmap[2][WhiteQueen] = DoLoadBitmap(hInst, "sl", squareSize, "w");
\r
3646 pieceBitmap[2][WhiteKing] = DoLoadBitmap(hInst, "sk", squareSize, "w");
\r
3647 pieceBitmap[2][WhiteFerz] = DoLoadBitmap(hInst, "sw", squareSize, "w");
\r
3648 pieceBitmap[2][WhiteWazir] = DoLoadBitmap(hInst, "sw", squareSize, "w");
\r
3649 pieceBitmap[2][WhiteCannon] = DoLoadBitmap(hInst, "sp", squareSize, "w");
\r
3650 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "sn", squareSize, "w");
\r
3651 pieceBitmap[2][WhiteCardinal] = DoLoadBitmap(hInst, "sr", squareSize, "w");
\r
3652 pieceBitmap[2][WhiteDragon] = DoLoadBitmap(hInst, "sr", squareSize, "w");
\r
3653 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "sl", squareSize, "w");
\r
3654 pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "sw", squareSize, "w");
\r
3660 PieceBitmap(ChessSquare p, int kind)
\r
3662 if ((int) p >= (int) BlackPawn)
\r
3663 p = (ChessSquare) ((int) p - (int) BlackPawn + (int) WhitePawn);
\r
3665 return pieceBitmap[kind][(int) p];
\r
3668 /***************************************************************/
\r
3670 #define MIN(a,b) (((a) < (b)) ? (a) : (b))
\r
3671 #define MAX(a,b) (((a) > (b)) ? (a) : (b))
\r
3673 #define MIN3(a,b,c) (((a) < (b) && (a) < (c)) ? (a) : (((b) < (a) && (b) < (c)) ? (b) : (c)))
\r
3674 #define MAX3(a,b,c) (((a) > (b) && (a) > (c)) ? (a) : (((b) > (a) && (b) > (c)) ? (b) : (c)))
\r
3678 SquareToPos(int row, int column, int * x, int * y)
\r
3681 *x = boardRect.left + lineGap + ((BOARD_WIDTH-1)-column) * (squareSize + lineGap);
\r
3682 *y = boardRect.top + lineGap + row * (squareSize + lineGap);
\r
3684 *x = boardRect.left + lineGap + column * (squareSize + lineGap);
\r
3685 *y = boardRect.top + lineGap + ((BOARD_HEIGHT-1)-row) * (squareSize + lineGap);
\r
3690 DrawCoordsOnDC(HDC hdc)
\r
3692 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
3693 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
3694 char str[2] = { NULLCHAR, NULLCHAR };
\r
3695 int oldMode, oldAlign, x, y, start, i;
\r
3699 if (!appData.showCoords)
\r
3702 start = flipView ? 1-(ONE!='1') : 23+(ONE!='1')-BOARD_HEIGHT;
\r
3704 oldBrush = SelectObject(hdc, GetStockObject(BLACK_BRUSH));
\r
3705 oldMode = SetBkMode(hdc, (appData.monoMode ? OPAQUE : TRANSPARENT));
\r
3706 oldAlign = GetTextAlign(hdc);
\r
3707 oldFont = SelectObject(hdc, font[boardSize][COORD_FONT]->hf);
\r
3709 y = boardRect.top + lineGap;
\r
3710 x = boardRect.left + lineGap + gameInfo.holdingsWidth*(squareSize + lineGap);
\r
3712 SetTextAlign(hdc, TA_LEFT|TA_TOP);
\r
3713 for (i = 0; i < BOARD_HEIGHT; i++) {
\r
3714 str[0] = files[start + i];
\r
3715 ExtTextOut(hdc, x + 2, y + 1, 0, NULL, str, 1, NULL);
\r
3716 y += squareSize + lineGap;
\r
3719 start = flipView ? 12-(BOARD_RGHT-BOARD_LEFT) : 12;
\r
3721 SetTextAlign(hdc, TA_RIGHT|TA_BOTTOM);
\r
3722 for (i = 0; i < BOARD_RGHT - BOARD_LEFT; i++) {
\r
3723 str[0] = ranks[start + i];
\r
3724 ExtTextOut(hdc, x + squareSize - 2, y - 1, 0, NULL, str, 1, NULL);
\r
3725 x += squareSize + lineGap;
\r
3728 SelectObject(hdc, oldBrush);
\r
3729 SetBkMode(hdc, oldMode);
\r
3730 SetTextAlign(hdc, oldAlign);
\r
3731 SelectObject(hdc, oldFont);
\r
3735 DrawGridOnDC(HDC hdc)
\r
3739 if (lineGap != 0) {
\r
3740 oldPen = SelectObject(hdc, gridPen);
\r
3741 PolyPolyline(hdc, gridEndpoints, gridVertexCounts, BOARD_WIDTH+BOARD_HEIGHT + 2);
\r
3742 SelectObject(hdc, oldPen);
\r
3746 #define HIGHLIGHT_PEN 0
\r
3747 #define PREMOVE_PEN 1
\r
3750 DrawHighlightOnDC(HDC hdc, BOOLEAN on, int x, int y, int pen)
\r
3753 HPEN oldPen, hPen;
\r
3754 if (lineGap == 0) return;
\r
3756 x1 = boardRect.left +
\r
3757 lineGap/2 + ((BOARD_WIDTH-1)-x) * (squareSize + lineGap);
\r
3758 y1 = boardRect.top +
\r
3759 lineGap/2 + y * (squareSize + lineGap);
\r
3761 x1 = boardRect.left +
\r
3762 lineGap/2 + x * (squareSize + lineGap);
\r
3763 y1 = boardRect.top +
\r
3764 lineGap/2 + ((BOARD_HEIGHT-1)-y) * (squareSize + lineGap);
\r
3766 hPen = pen ? premovePen : highlightPen;
\r
3767 oldPen = SelectObject(hdc, on ? hPen : gridPen);
\r
3768 MoveToEx(hdc, x1, y1, NULL);
\r
3769 LineTo(hdc, x1 + squareSize + lineGap, y1);
\r
3770 LineTo(hdc, x1 + squareSize + lineGap, y1 + squareSize + lineGap);
\r
3771 LineTo(hdc, x1, y1 + squareSize + lineGap);
\r
3772 LineTo(hdc, x1, y1);
\r
3773 SelectObject(hdc, oldPen);
\r
3777 DrawHighlightsOnDC(HDC hdc)
\r
3780 for (i=0; i<2; i++) {
\r
3781 if (highlightInfo.sq[i].x >= 0 && highlightInfo.sq[i].y >= 0)
\r
3782 DrawHighlightOnDC(hdc, TRUE,
\r
3783 highlightInfo.sq[i].x, highlightInfo.sq[i].y,
\r
3786 for (i=0; i<2; i++) {
\r
3787 if (premoveHighlightInfo.sq[i].x >= 0 &&
\r
3788 premoveHighlightInfo.sq[i].y >= 0) {
\r
3789 DrawHighlightOnDC(hdc, TRUE,
\r
3790 premoveHighlightInfo.sq[i].x,
\r
3791 premoveHighlightInfo.sq[i].y,
\r
3797 /* Note: sqcolor is used only in monoMode */
\r
3798 /* Note that this code is largely duplicated in woptions.c,
\r
3799 function DrawSampleSquare, so that needs to be updated too */
\r
3801 DrawPieceOnDC(HDC hdc, ChessSquare piece, int color, int sqcolor, int x, int y, HDC tmphdc)
\r
3803 HBITMAP oldBitmap;
\r
3807 if (appData.blindfold) return;
\r
3809 /* [AS] Use font-based pieces if needed */
\r
3810 if( fontBitmapSquareSize >= 0 && squareSize > 32 ) {
\r
3811 /* Create piece bitmaps, or do nothing if piece set is up to date */
\r
3812 CreatePiecesFromFont();
\r
3814 if( fontBitmapSquareSize == squareSize ) {
\r
3815 int index = TranslatePieceToFontPiece(piece);
\r
3817 SelectObject( tmphdc, hPieceMask[ index ] );
\r
3821 squareSize, squareSize,
\r
3826 SelectObject( tmphdc, hPieceFace[ index ] );
\r
3830 squareSize, squareSize,
\r
3839 if (appData.monoMode) {
\r
3840 SelectObject(tmphdc, PieceBitmap(piece,
\r
3841 color == sqcolor ? OUTLINE_PIECE : SOLID_PIECE));
\r
3842 BitBlt(hdc, x, y, squareSize, squareSize, tmphdc, 0, 0,
\r
3843 sqcolor ? SRCCOPY : NOTSRCCOPY);
\r
3845 tmpSize = squareSize;
\r
3847 ((piece >= (int)WhiteNightrider && piece <= WhiteGrasshopper) ||
\r
3848 (piece >= (int)BlackNightrider && piece <= BlackGrasshopper)) ) {
\r
3849 /* [HGM] no bitmap available for promoted pieces in Crazyhouse */
\r
3850 /* Bitmaps of smaller size are substituted, but we have to align them */
\r
3851 x += (squareSize - minorSize)>>1;
\r
3852 y += squareSize - minorSize - 2;
\r
3853 tmpSize = minorSize;
\r
3855 if (color || appData.allWhite ) {
\r
3856 oldBitmap = SelectObject(tmphdc, PieceBitmap(piece, WHITE_PIECE));
\r
3858 oldBrush = SelectObject(hdc, whitePieceBrush);
\r
3859 else oldBrush = SelectObject(hdc, blackPieceBrush);
\r
3860 if(appData.upsideDown && color==flipView)
\r
3861 StretchBlt(hdc, x+tmpSize, y+tmpSize, -tmpSize, -tmpSize, tmphdc, 0, 0, tmpSize, tmpSize, 0x00B8074A);
\r
3863 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, 0x00B8074A);
\r
3865 /* Use black piece color for outline of white pieces */
\r
3866 /* Not sure this looks really good (though xboard does it).
\r
3867 Maybe better to have another selectable color, default black */
\r
3868 SelectObject(hdc, blackPieceBrush); /* could have own brush */
\r
3869 SelectObject(tmphdc, PieceBitmap(piece, OUTLINE_PIECE));
\r
3870 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, 0x00B8074A);
\r
3872 /* Use black for outline of white pieces */
\r
3873 SelectObject(tmphdc, PieceBitmap(piece, OUTLINE_PIECE));
\r
3874 if(appData.upsideDown && color==flipView)
\r
3875 StretchBlt(hdc, x+tmpSize, y+tmpSize, -tmpSize, -tmpSize, tmphdc, 0, 0, tmpSize, tmpSize, SRCAND);
\r
3877 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, SRCAND);
\r
3881 /* Use white piece color for details of black pieces */
\r
3882 /* Requires filled-in solid bitmaps (BLACK_PIECE class); the
\r
3883 WHITE_PIECE ones aren't always the right shape. */
\r
3884 /* Not sure this looks really good (though xboard does it).
\r
3885 Maybe better to have another selectable color, default medium gray? */
\r
3886 oldBitmap = SelectObject(tmphdc, PieceBitmap(piece, BLACK_PIECE));
\r
3887 oldBrush = SelectObject(hdc, whitePieceBrush); /* could have own brush */
\r
3888 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, 0x00B8074A);
\r
3889 SelectObject(tmphdc, PieceBitmap(piece, SOLID_PIECE));
\r
3890 SelectObject(hdc, blackPieceBrush);
\r
3891 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, 0x00B8074A);
\r
3893 /* Use square color for details of black pieces */
\r
3894 oldBitmap = SelectObject(tmphdc, PieceBitmap(piece, SOLID_PIECE));
\r
3895 oldBrush = SelectObject(hdc, blackPieceBrush);
\r
3896 if(appData.upsideDown && !flipView)
\r
3897 StretchBlt(hdc, x+tmpSize, y+tmpSize, -tmpSize, -tmpSize, tmphdc, 0, 0, tmpSize, tmpSize, 0x00B8074A);
\r
3899 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, 0x00B8074A);
\r
3902 SelectObject(hdc, oldBrush);
\r
3903 SelectObject(tmphdc, oldBitmap);
\r
3907 /* [AS] Compute a drawing mode for a square, based on specified settings (see DrawTile) */
\r
3908 int GetBackTextureMode( int algo )
\r
3910 int result = BACK_TEXTURE_MODE_DISABLED;
\r
3914 case BACK_TEXTURE_MODE_PLAIN:
\r
3915 result = 1; /* Always use identity map */
\r
3917 case BACK_TEXTURE_MODE_FULL_RANDOM:
\r
3918 result = 1 + (myrandom() % 3); /* Pick a transformation at random */
\r
3926 [AS] Compute and save texture drawing info, otherwise we may not be able
\r
3927 to handle redraws cleanly (as random numbers would always be different).
\r
3929 VOID RebuildTextureSquareInfo()
\r
3939 ZeroMemory( &backTextureSquareInfo, sizeof(backTextureSquareInfo) );
\r
3941 if( liteBackTexture != NULL ) {
\r
3942 if( GetObject( liteBackTexture, sizeof(bi), &bi ) > 0 ) {
\r
3943 lite_w = bi.bmWidth;
\r
3944 lite_h = bi.bmHeight;
\r
3948 if( darkBackTexture != NULL ) {
\r
3949 if( GetObject( darkBackTexture, sizeof(bi), &bi ) > 0 ) {
\r
3950 dark_w = bi.bmWidth;
\r
3951 dark_h = bi.bmHeight;
\r
3955 for( row=0; row<BOARD_HEIGHT; row++ ) {
\r
3956 for( col=0; col<BOARD_WIDTH; col++ ) {
\r
3957 if( (col + row) & 1 ) {
\r
3959 if( lite_w >= squareSize && lite_h >= squareSize ) {
\r
3960 backTextureSquareInfo[row][col].x = col * (lite_w - squareSize) / (BOARD_WIDTH-1); /* [HGM] divide by size-1 in stead of size! */
\r
3961 backTextureSquareInfo[row][col].y = (BOARD_HEIGHT-1-row) * (lite_h - squareSize) / (BOARD_HEIGHT-1);
\r
3962 backTextureSquareInfo[row][col].mode = GetBackTextureMode(liteBackTextureMode);
\r
3967 if( dark_w >= squareSize && dark_h >= squareSize ) {
\r
3968 backTextureSquareInfo[row][col].x = col * (dark_w - squareSize) / (BOARD_WIDTH-1);
\r
3969 backTextureSquareInfo[row][col].y = (BOARD_HEIGHT-1-row) * (dark_h - squareSize) / (BOARD_HEIGHT-1);
\r
3970 backTextureSquareInfo[row][col].mode = GetBackTextureMode(darkBackTextureMode);
\r
3977 /* [AS] Arrow highlighting support */
\r
3979 static int A_WIDTH = 5; /* Width of arrow body */
\r
3981 #define A_HEIGHT_FACTOR 6 /* Length of arrow "point", relative to body width */
\r
3982 #define A_WIDTH_FACTOR 3 /* Width of arrow "point", relative to body width */
\r
3984 static double Sqr( double x )
\r
3989 static int Round( double x )
\r
3991 return (int) (x + 0.5);
\r
3994 /* Draw an arrow between two points using current settings */
\r
3995 VOID DrawArrowBetweenPoints( HDC hdc, int s_x, int s_y, int d_x, int d_y )
\r
3998 double dx, dy, j, k, x, y;
\r
4000 if( d_x == s_x ) {
\r
4001 int h = (d_y > s_y) ? +A_WIDTH*A_HEIGHT_FACTOR : -A_WIDTH*A_HEIGHT_FACTOR;
\r
4003 arrow[0].x = s_x + A_WIDTH;
\r
4006 arrow[1].x = s_x + A_WIDTH;
\r
4007 arrow[1].y = d_y - h;
\r
4009 arrow[2].x = s_x + A_WIDTH*A_WIDTH_FACTOR;
\r
4010 arrow[2].y = d_y - h;
\r
4015 arrow[4].x = s_x - A_WIDTH*A_WIDTH_FACTOR;
\r
4016 arrow[4].y = d_y - h;
\r
4018 arrow[5].x = s_x - A_WIDTH;
\r
4019 arrow[5].y = d_y - h;
\r
4021 arrow[6].x = s_x - A_WIDTH;
\r
4024 else if( d_y == s_y ) {
\r
4025 int w = (d_x > s_x) ? +A_WIDTH*A_HEIGHT_FACTOR : -A_WIDTH*A_HEIGHT_FACTOR;
\r
4028 arrow[0].y = s_y + A_WIDTH;
\r
4030 arrow[1].x = d_x - w;
\r
4031 arrow[1].y = s_y + A_WIDTH;
\r
4033 arrow[2].x = d_x - w;
\r
4034 arrow[2].y = s_y + A_WIDTH*A_WIDTH_FACTOR;
\r
4039 arrow[4].x = d_x - w;
\r
4040 arrow[4].y = s_y - A_WIDTH*A_WIDTH_FACTOR;
\r
4042 arrow[5].x = d_x - w;
\r
4043 arrow[5].y = s_y - A_WIDTH;
\r
4046 arrow[6].y = s_y - A_WIDTH;
\r
4049 /* [AS] Needed a lot of paper for this! :-) */
\r
4050 dy = (double) (d_y - s_y) / (double) (d_x - s_x);
\r
4051 dx = (double) (s_x - d_x) / (double) (s_y - d_y);
\r
4053 j = sqrt( Sqr(A_WIDTH) / (1.0 + Sqr(dx)) );
\r
4055 k = sqrt( Sqr(A_WIDTH*A_HEIGHT_FACTOR) / (1.0 + Sqr(dy)) );
\r
4060 arrow[0].x = Round(x - j);
\r
4061 arrow[0].y = Round(y + j*dx);
\r
4063 arrow[1].x = Round(x + j);
\r
4064 arrow[1].y = Round(y - j*dx);
\r
4067 x = (double) d_x - k;
\r
4068 y = (double) d_y - k*dy;
\r
4071 x = (double) d_x + k;
\r
4072 y = (double) d_y + k*dy;
\r
4075 arrow[2].x = Round(x + j);
\r
4076 arrow[2].y = Round(y - j*dx);
\r
4078 arrow[3].x = Round(x + j*A_WIDTH_FACTOR);
\r
4079 arrow[3].y = Round(y - j*A_WIDTH_FACTOR*dx);
\r
4084 arrow[5].x = Round(x - j*A_WIDTH_FACTOR);
\r
4085 arrow[5].y = Round(y + j*A_WIDTH_FACTOR*dx);
\r
4087 arrow[6].x = Round(x - j);
\r
4088 arrow[6].y = Round(y + j*dx);
\r
4091 Polygon( hdc, arrow, 7 );
\r
4094 /* [AS] Draw an arrow between two squares */
\r
4095 VOID DrawArrowBetweenSquares( HDC hdc, int s_col, int s_row, int d_col, int d_row )
\r
4097 int s_x, s_y, d_x, d_y;
\r
4104 if( s_col == d_col && s_row == d_row ) {
\r
4108 /* Get source and destination points */
\r
4109 SquareToPos( s_row, s_col, &s_x, &s_y);
\r
4110 SquareToPos( d_row, d_col, &d_x, &d_y);
\r
4113 d_y += squareSize / 4;
\r
4115 else if( d_y < s_y ) {
\r
4116 d_y += 3 * squareSize / 4;
\r
4119 d_y += squareSize / 2;
\r
4123 d_x += squareSize / 4;
\r
4125 else if( d_x < s_x ) {
\r
4126 d_x += 3 * squareSize / 4;
\r
4129 d_x += squareSize / 2;
\r
4132 s_x += squareSize / 2;
\r
4133 s_y += squareSize / 2;
\r
4135 /* Adjust width */
\r
4136 A_WIDTH = squareSize / 14;
\r
4139 stLB.lbStyle = BS_SOLID;
\r
4140 stLB.lbColor = appData.highlightArrowColor;
\r
4143 hpen = CreatePen( PS_SOLID, 2, RGB(0x00,0x00,0x00) );
\r
4144 holdpen = SelectObject( hdc, hpen );
\r
4145 hbrush = CreateBrushIndirect( &stLB );
\r
4146 holdbrush = SelectObject( hdc, hbrush );
\r
4148 DrawArrowBetweenPoints( hdc, s_x, s_y, d_x, d_y );
\r
4150 SelectObject( hdc, holdpen );
\r
4151 SelectObject( hdc, holdbrush );
\r
4152 DeleteObject( hpen );
\r
4153 DeleteObject( hbrush );
\r
4156 BOOL HasHighlightInfo()
\r
4158 BOOL result = FALSE;
\r
4160 if( highlightInfo.sq[0].x >= 0 && highlightInfo.sq[0].y >= 0 &&
\r
4161 highlightInfo.sq[1].x >= 0 && highlightInfo.sq[1].y >= 0 )
\r
4169 BOOL IsDrawArrowEnabled()
\r
4171 BOOL result = FALSE;
\r
4173 if( appData.highlightMoveWithArrow && squareSize >= 32 ) {
\r
4180 VOID DrawArrowHighlight( HDC hdc )
\r
4182 if( IsDrawArrowEnabled() && HasHighlightInfo() ) {
\r
4183 DrawArrowBetweenSquares( hdc,
\r
4184 highlightInfo.sq[0].x, highlightInfo.sq[0].y,
\r
4185 highlightInfo.sq[1].x, highlightInfo.sq[1].y );
\r
4189 HRGN GetArrowHighlightClipRegion( HDC hdc )
\r
4191 HRGN result = NULL;
\r
4193 if( HasHighlightInfo() ) {
\r
4194 int x1, y1, x2, y2;
\r
4195 int sx, sy, dx, dy;
\r
4197 SquareToPos(highlightInfo.sq[0].y, highlightInfo.sq[0].x, &x1, &y1 );
\r
4198 SquareToPos(highlightInfo.sq[1].y, highlightInfo.sq[1].x, &x2, &y2 );
\r
4200 sx = MIN( x1, x2 );
\r
4201 sy = MIN( y1, y2 );
\r
4202 dx = MAX( x1, x2 ) + squareSize;
\r
4203 dy = MAX( y1, y2 ) + squareSize;
\r
4205 result = CreateRectRgn( sx, sy, dx, dy );
\r
4212 Warning: this function modifies the behavior of several other functions.
\r
4214 Basically, Winboard is optimized to avoid drawing the whole board if not strictly
\r
4215 needed. Unfortunately, the decision whether or not to perform a full or partial
\r
4216 repaint is scattered all over the place, which is not good for features such as
\r
4217 "arrow highlighting" that require a full repaint of the board.
\r
4219 So, I've tried to patch the code where I thought it made sense (e.g. after or during
\r
4220 user interaction, when speed is not so important) but especially to avoid errors
\r
4221 in the displayed graphics.
\r
4223 In such patched places, I always try refer to this function so there is a single
\r
4224 place to maintain knowledge.
\r
4226 To restore the original behavior, just return FALSE unconditionally.
\r
4228 BOOL IsFullRepaintPreferrable()
\r
4230 BOOL result = FALSE;
\r
4232 if( (appData.highlightLastMove || appData.highlightDragging) && IsDrawArrowEnabled() ) {
\r
4233 /* Arrow may appear on the board */
\r
4241 This function is called by DrawPosition to know whether a full repaint must
\r
4244 Only DrawPosition may directly call this function, which makes use of
\r
4245 some state information. Other function should call DrawPosition specifying
\r
4246 the repaint flag, and can use IsFullRepaintPreferrable if needed.
\r
4248 BOOL DrawPositionNeedsFullRepaint()
\r
4250 BOOL result = FALSE;
\r
4253 Probably a slightly better policy would be to trigger a full repaint
\r
4254 when animInfo.piece changes state (i.e. empty -> non-empty and viceversa),
\r
4255 but animation is fast enough that it's difficult to notice.
\r
4257 if( animInfo.piece == EmptySquare ) {
\r
4258 if( (appData.highlightLastMove || appData.highlightDragging) && IsDrawArrowEnabled() && HasHighlightInfo() ) {
\r
4267 DrawBoardOnDC(HDC hdc, Board board, HDC tmphdc)
\r
4269 int row, column, x, y, square_color, piece_color;
\r
4270 ChessSquare piece;
\r
4272 HDC texture_hdc = NULL;
\r
4274 /* [AS] Initialize background textures if needed */
\r
4275 if( liteBackTexture != NULL || darkBackTexture != NULL ) {
\r
4276 static int backTextureBoardSize; /* [HGM] boardsize: also new texture if board format changed */
\r
4277 if( backTextureSquareSize != squareSize
\r
4278 || backTextureBoardSize != BOARD_WIDTH+BOARD_SIZE*BOARD_HEIGHT) {
\r
4279 backTextureBoardSize = BOARD_WIDTH+BOARD_SIZE*BOARD_HEIGHT;
\r
4280 backTextureSquareSize = squareSize;
\r
4281 RebuildTextureSquareInfo();
\r
4284 texture_hdc = CreateCompatibleDC( hdc );
\r
4287 for (row = 0; row < BOARD_HEIGHT; row++) {
\r
4288 for (column = 0; column < BOARD_WIDTH; column++) {
\r
4290 SquareToPos(row, column, &x, &y);
\r
4292 piece = board[row][column];
\r
4294 square_color = ((column + row) % 2) == 1;
\r
4295 if( gameInfo.variant == VariantXiangqi ) {
\r
4296 square_color = !InPalace(row, column);
\r
4297 if(BOARD_HEIGHT&1) { if(row==BOARD_HEIGHT/2) square_color ^= 1; }
\r
4298 else if(row < BOARD_HEIGHT/2) square_color ^= 1;
\r
4300 piece_color = (int) piece < (int) BlackPawn;
\r
4303 /* [HGM] holdings file: light square or black */
\r
4304 if(column == BOARD_LEFT-2) {
\r
4305 if( row > BOARD_HEIGHT - gameInfo.holdingsSize - 1 )
\r
4308 DisplayHoldingsCount(hdc, x, y, 0, 0); /* black out */
\r
4312 if(column == BOARD_RGHT + 1 ) {
\r
4313 if( row < gameInfo.holdingsSize )
\r
4316 DisplayHoldingsCount(hdc, x, y, 0, 0);
\r
4320 if(column == BOARD_LEFT-1 ) /* left align */
\r
4321 DisplayHoldingsCount(hdc, x, y, flipView, (int) board[row][column]);
\r
4322 else if( column == BOARD_RGHT) /* right align */
\r
4323 DisplayHoldingsCount(hdc, x, y, !flipView, (int) board[row][column]);
\r
4325 if (appData.monoMode) {
\r
4326 if (piece == EmptySquare) {
\r
4327 BitBlt(hdc, x, y, squareSize, squareSize, 0, 0, 0,
\r
4328 square_color ? WHITENESS : BLACKNESS);
\r
4330 DrawPieceOnDC(hdc, piece, piece_color, square_color, x, y, tmphdc);
\r
4333 else if( backTextureSquareInfo[row][column].mode > 0 ) {
\r
4334 /* [AS] Draw the square using a texture bitmap */
\r
4335 HBITMAP hbm = SelectObject( texture_hdc, square_color ? liteBackTexture : darkBackTexture );
\r
4336 int r = row, c = column; // [HGM] do not flip board in flipView
\r
4337 if(flipView) { r = BOARD_HEIGHT-1 - r; c = BOARD_WIDTH-1 - c; }
\r
4340 squareSize, squareSize,
\r
4343 backTextureSquareInfo[r][c].mode,
\r
4344 backTextureSquareInfo[r][c].x,
\r
4345 backTextureSquareInfo[r][c].y );
\r
4347 SelectObject( texture_hdc, hbm );
\r
4349 if (piece != EmptySquare) {
\r
4350 DrawPieceOnDC(hdc, piece, piece_color, -1, x, y, tmphdc);
\r
4354 HBRUSH brush = square_color ? lightSquareBrush : darkSquareBrush;
\r
4356 oldBrush = SelectObject(hdc, brush );
\r
4357 BitBlt(hdc, x, y, squareSize, squareSize, 0, 0, 0, PATCOPY);
\r
4358 SelectObject(hdc, oldBrush);
\r
4359 if (piece != EmptySquare)
\r
4360 DrawPieceOnDC(hdc, piece, piece_color, -1, x, y, tmphdc);
\r
4365 if( texture_hdc != NULL ) {
\r
4366 DeleteDC( texture_hdc );
\r
4370 int saveDiagFlag = 0; FILE *diagFile; // [HGM] diag
\r
4371 void fputDW(FILE *f, int x)
\r
4373 fputc(x & 255, f);
\r
4374 fputc(x>>8 & 255, f);
\r
4375 fputc(x>>16 & 255, f);
\r
4376 fputc(x>>24 & 255, f);
\r
4379 #define MAX_CLIPS 200 /* more than enough */
\r
4382 DrawLogoOnDC(HDC hdc, RECT logoRect, HBITMAP logo)
\r
4384 // HBITMAP bufferBitmap;
\r
4389 int w = 100, h = 50;
\r
4391 if(logo == NULL) return;
\r
4392 // GetClientRect(hwndMain, &Rect);
\r
4393 // bufferBitmap = CreateCompatibleBitmap(hdc, Rect.right-Rect.left+1,
\r
4394 // Rect.bottom-Rect.top+1);
\r
4395 tmphdc = CreateCompatibleDC(hdc);
\r
4396 hbm = SelectObject(tmphdc, logo);
\r
4397 if( GetObject( logo, sizeof(bi), &bi ) > 0 ) {
\r
4401 StretchBlt(hdc, logoRect.left, logoRect.top, logoRect.right - logoRect.left,
\r
4402 logoRect.bottom - logoRect.top, tmphdc, 0, 0, w, h, SRCCOPY);
\r
4403 SelectObject(tmphdc, hbm);
\r
4408 HDCDrawPosition(HDC hdc, BOOLEAN repaint, Board board)
\r
4410 static Board lastReq, lastDrawn;
\r
4411 static HighlightInfo lastDrawnHighlight, lastDrawnPremove;
\r
4412 static int lastDrawnFlipView = 0;
\r
4413 static int lastReqValid = 0, lastDrawnValid = 0;
\r
4414 int releaseDC, x, y, x2, y2, row, column, num_clips = 0, i;
\r
4417 HBITMAP bufferBitmap;
\r
4418 HBITMAP oldBitmap;
\r
4420 HRGN clips[MAX_CLIPS];
\r
4421 ChessSquare dragged_piece = EmptySquare;
\r
4423 /* I'm undecided on this - this function figures out whether a full
\r
4424 * repaint is necessary on its own, so there's no real reason to have the
\r
4425 * caller tell it that. I think this can safely be set to FALSE - but
\r
4426 * if we trust the callers not to request full repaints unnessesarily, then
\r
4427 * we could skip some clipping work. In other words, only request a full
\r
4428 * redraw when the majority of pieces have changed positions (ie. flip,
\r
4429 * gamestart and similar) --Hawk
\r
4431 Boolean fullrepaint = repaint;
\r
4433 if( DrawPositionNeedsFullRepaint() ) {
\r
4434 fullrepaint = TRUE;
\r
4438 if( fullrepaint ) {
\r
4439 static int repaint_count = 0;
\r
4443 sprintf( buf, "FULL repaint: %d\n", repaint_count );
\r
4444 OutputDebugString( buf );
\r
4448 if (board == NULL) {
\r
4449 if (!lastReqValid) {
\r
4454 CopyBoard(lastReq, board);
\r
4458 if (doingSizing) {
\r
4462 if (IsIconic(hwndMain)) {
\r
4466 if (hdc == NULL) {
\r
4467 hdc = GetDC(hwndMain);
\r
4468 if (!appData.monoMode) {
\r
4469 SelectPalette(hdc, hPal, FALSE);
\r
4470 RealizePalette(hdc);
\r
4474 releaseDC = FALSE;
\r
4478 fprintf(debugFP, "*******************************\n"
\r
4480 "dragInfo.from (%d,%d)\n"
\r
4481 "dragInfo.start (%d,%d)\n"
\r
4482 "dragInfo.pos (%d,%d)\n"
\r
4483 "dragInfo.lastpos (%d,%d)\n",
\r
4484 repaint ? "TRUE" : "FALSE",
\r
4485 dragInfo.from.x, dragInfo.from.y,
\r
4486 dragInfo.start.x, dragInfo.start.y,
\r
4487 dragInfo.pos.x, dragInfo.pos.y,
\r
4488 dragInfo.lastpos.x, dragInfo.lastpos.y);
\r
4489 fprintf(debugFP, "prev: ");
\r
4490 for (row = 0; row < BOARD_HEIGHT; row++) {
\r
4491 for (column = 0; column < BOARD_WIDTH; column++) {
\r
4492 fprintf(debugFP, "%d ", lastDrawn[row][column]);
\r
4495 fprintf(debugFP, "\n");
\r
4496 fprintf(debugFP, "board: ");
\r
4497 for (row = 0; row < BOARD_HEIGHT; row++) {
\r
4498 for (column = 0; column < BOARD_WIDTH; column++) {
\r
4499 fprintf(debugFP, "%d ", board[row][column]);
\r
4502 fprintf(debugFP, "\n");
\r
4506 /* Create some work-DCs */
\r
4507 hdcmem = CreateCompatibleDC(hdc);
\r
4508 tmphdc = CreateCompatibleDC(hdc);
\r
4510 /* If dragging is in progress, we temporarely remove the piece */
\r
4511 /* [HGM] or temporarily decrease count if stacked */
\r
4512 /* !! Moved to before board compare !! */
\r
4513 if (dragInfo.from.x >= 0 && dragInfo.pos.x >= 0) {
\r
4514 dragged_piece = board[dragInfo.from.y][dragInfo.from.x];
\r
4515 if(dragInfo.from.x == BOARD_LEFT-2 ) {
\r
4516 if(--board[dragInfo.from.y][dragInfo.from.x+1] == 0 )
\r
4517 board[dragInfo.from.y][dragInfo.from.x] = EmptySquare;
\r
4519 if(dragInfo.from.x == BOARD_RGHT+1) {
\r
4520 if(--board[dragInfo.from.y][dragInfo.from.x-1] == 0 )
\r
4521 board[dragInfo.from.y][dragInfo.from.x] = EmptySquare;
\r
4523 board[dragInfo.from.y][dragInfo.from.x] = EmptySquare;
\r
4526 /* Figure out which squares need updating by comparing the
\r
4527 * newest board with the last drawn board and checking if
\r
4528 * flipping has changed.
\r
4530 if (!fullrepaint && lastDrawnValid && lastDrawnFlipView == flipView) {
\r
4531 for (row = 0; row < BOARD_HEIGHT; row++) { /* [HGM] true size, not 8 */
\r
4532 for (column = 0; column < BOARD_WIDTH; column++) {
\r
4533 if (lastDrawn[row][column] != board[row][column]) {
\r
4534 SquareToPos(row, column, &x, &y);
\r
4535 clips[num_clips++] =
\r
4536 CreateRectRgn(x, y, x + squareSize, y + squareSize);
\r
4540 for (i=0; i<2; i++) {
\r
4541 if (lastDrawnHighlight.sq[i].x != highlightInfo.sq[i].x ||
\r
4542 lastDrawnHighlight.sq[i].y != highlightInfo.sq[i].y) {
\r
4543 if (lastDrawnHighlight.sq[i].x >= 0 &&
\r
4544 lastDrawnHighlight.sq[i].y >= 0) {
\r
4545 SquareToPos(lastDrawnHighlight.sq[i].y,
\r
4546 lastDrawnHighlight.sq[i].x, &x, &y);
\r
4547 clips[num_clips++] =
\r
4548 CreateRectRgn(x - lineGap, y - lineGap,
\r
4549 x + squareSize + lineGap, y + squareSize + lineGap);
\r
4551 if (highlightInfo.sq[i].x >= 0 && highlightInfo.sq[i].y >= 0) {
\r
4552 SquareToPos(highlightInfo.sq[i].y, highlightInfo.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
4559 for (i=0; i<2; i++) {
\r
4560 if (lastDrawnPremove.sq[i].x != premoveHighlightInfo.sq[i].x ||
\r
4561 lastDrawnPremove.sq[i].y != premoveHighlightInfo.sq[i].y) {
\r
4562 if (lastDrawnPremove.sq[i].x >= 0 &&
\r
4563 lastDrawnPremove.sq[i].y >= 0) {
\r
4564 SquareToPos(lastDrawnPremove.sq[i].y,
\r
4565 lastDrawnPremove.sq[i].x, &x, &y);
\r
4566 clips[num_clips++] =
\r
4567 CreateRectRgn(x - lineGap, y - lineGap,
\r
4568 x + squareSize + lineGap, y + squareSize + lineGap);
\r
4570 if (premoveHighlightInfo.sq[i].x >= 0 &&
\r
4571 premoveHighlightInfo.sq[i].y >= 0) {
\r
4572 SquareToPos(premoveHighlightInfo.sq[i].y,
\r
4573 premoveHighlightInfo.sq[i].x, &x, &y);
\r
4574 clips[num_clips++] =
\r
4575 CreateRectRgn(x - lineGap, y - lineGap,
\r
4576 x + squareSize + lineGap, y + squareSize + lineGap);
\r
4581 fullrepaint = TRUE;
\r
4584 /* Create a buffer bitmap - this is the actual bitmap
\r
4585 * being written to. When all the work is done, we can
\r
4586 * copy it to the real DC (the screen). This avoids
\r
4587 * the problems with flickering.
\r
4589 GetClientRect(hwndMain, &Rect);
\r
4590 bufferBitmap = CreateCompatibleBitmap(hdc, Rect.right-Rect.left+1,
\r
4591 Rect.bottom-Rect.top+1);
\r
4592 oldBitmap = SelectObject(hdcmem, bufferBitmap);
\r
4593 if (!appData.monoMode) {
\r
4594 SelectPalette(hdcmem, hPal, FALSE);
\r
4597 /* Create clips for dragging */
\r
4598 if (!fullrepaint) {
\r
4599 if (dragInfo.from.x >= 0) {
\r
4600 SquareToPos(dragInfo.from.y, dragInfo.from.x, &x, &y);
\r
4601 clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);
\r
4603 if (dragInfo.start.x >= 0) {
\r
4604 SquareToPos(dragInfo.start.y, dragInfo.start.x, &x, &y);
\r
4605 clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);
\r
4607 if (dragInfo.pos.x >= 0) {
\r
4608 x = dragInfo.pos.x - squareSize / 2;
\r
4609 y = dragInfo.pos.y - squareSize / 2;
\r
4610 clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);
\r
4612 if (dragInfo.lastpos.x >= 0) {
\r
4613 x = dragInfo.lastpos.x - squareSize / 2;
\r
4614 y = dragInfo.lastpos.y - squareSize / 2;
\r
4615 clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);
\r
4619 /* Are we animating a move?
\r
4621 * - remove the piece from the board (temporarely)
\r
4622 * - calculate the clipping region
\r
4624 if (!fullrepaint) {
\r
4625 if (animInfo.piece != EmptySquare) {
\r
4626 board[animInfo.from.y][animInfo.from.x] = EmptySquare;
\r
4627 x = boardRect.left + animInfo.lastpos.x;
\r
4628 y = boardRect.top + animInfo.lastpos.y;
\r
4629 x2 = boardRect.left + animInfo.pos.x;
\r
4630 y2 = boardRect.top + animInfo.pos.y;
\r
4631 clips[num_clips++] = CreateRectRgn(MIN(x,x2), MIN(y,y2), MAX(x,x2)+squareSize, MAX(y,y2)+squareSize);
\r
4632 /* Slight kludge. The real problem is that after AnimateMove is
\r
4633 done, the position on the screen does not match lastDrawn.
\r
4634 This currently causes trouble only on e.p. captures in
\r
4635 atomic, where the piece moves to an empty square and then
\r
4636 explodes. The old and new positions both had an empty square
\r
4637 at the destination, but animation has drawn a piece there and
\r
4638 we have to remember to erase it. [HGM] moved until after setting lastDrawn */
\r
4639 lastDrawn[animInfo.to.y][animInfo.to.x] = animInfo.piece;
\r
4643 /* No clips? Make sure we have fullrepaint set to TRUE */
\r
4644 if (num_clips == 0)
\r
4645 fullrepaint = TRUE;
\r
4647 /* Set clipping on the memory DC */
\r
4648 if (!fullrepaint) {
\r
4649 SelectClipRgn(hdcmem, clips[0]);
\r
4650 for (x = 1; x < num_clips; x++) {
\r
4651 if (ExtSelectClipRgn(hdcmem, clips[x], RGN_OR) == ERROR)
\r
4652 abort(); // this should never ever happen!
\r
4656 /* Do all the drawing to the memory DC */
\r
4657 if(explodeInfo.radius) { // [HGM] atomic
\r
4659 int x, y, r=(explodeInfo.radius * squareSize)/100;
\r
4660 board[explodeInfo.fromY][explodeInfo.fromX] = EmptySquare; // suppress display of capturer
\r
4661 SquareToPos(explodeInfo.toY, explodeInfo.toX, &x, &y);
\r
4662 x += squareSize/2;
\r
4663 y += squareSize/2;
\r
4664 if(!fullrepaint) {
\r
4665 clips[num_clips] = CreateRectRgn(x-r, y-r, x+r, y+r);
\r
4666 ExtSelectClipRgn(hdcmem, clips[num_clips++], RGN_OR);
\r
4668 DrawGridOnDC(hdcmem);
\r
4669 DrawHighlightsOnDC(hdcmem);
\r
4670 DrawBoardOnDC(hdcmem, board, tmphdc);
\r
4671 oldBrush = SelectObject(hdcmem, explodeBrush);
\r
4672 Ellipse(hdcmem, x-r, y-r, x+r, y+r);
\r
4673 SelectObject(hdcmem, oldBrush);
\r
4675 DrawGridOnDC(hdcmem);
\r
4676 DrawHighlightsOnDC(hdcmem);
\r
4677 DrawBoardOnDC(hdcmem, board, tmphdc);
\r
4680 HBITMAP whiteLogo = (HBITMAP) first.programLogo, blackLogo = (HBITMAP) second.programLogo;
\r
4681 if(appData.autoLogo) {
\r
4683 switch(gameMode) { // pick logos based on game mode
\r
4684 case IcsObserving:
\r
4685 whiteLogo = second.programLogo; // ICS logo
\r
4686 blackLogo = second.programLogo;
\r
4689 case IcsPlayingWhite:
\r
4690 if(!appData.zippyPlay) whiteLogo = userLogo;
\r
4691 blackLogo = second.programLogo; // ICS logo
\r
4693 case IcsPlayingBlack:
\r
4694 whiteLogo = second.programLogo; // ICS logo
\r
4695 blackLogo = appData.zippyPlay ? first.programLogo : userLogo;
\r
4697 case TwoMachinesPlay:
\r
4698 if(first.twoMachinesColor[0] == 'b') {
\r
4699 whiteLogo = second.programLogo;
\r
4700 blackLogo = first.programLogo;
\r
4703 case MachinePlaysWhite:
\r
4704 blackLogo = userLogo;
\r
4706 case MachinePlaysBlack:
\r
4707 whiteLogo = userLogo;
\r
4708 blackLogo = first.programLogo;
\r
4711 DrawLogoOnDC(hdc, leftLogoRect, flipClock ? blackLogo : whiteLogo);
\r
4712 DrawLogoOnDC(hdc, rightLogoRect, flipClock ? whiteLogo : blackLogo);
\r
4715 if( appData.highlightMoveWithArrow ) {
\r
4716 DrawArrowHighlight(hdcmem);
\r
4719 DrawCoordsOnDC(hdcmem);
\r
4721 CopyBoard(lastDrawn, board); /* [HGM] Moved to here from end of routine, */
\r
4722 /* to make sure lastDrawn contains what is actually drawn */
\r
4724 /* Put the dragged piece back into place and draw it (out of place!) */
\r
4725 if (dragged_piece != EmptySquare) {
\r
4726 /* [HGM] or restack */
\r
4727 if(dragInfo.from.x == BOARD_LEFT-2 )
\r
4728 board[dragInfo.from.y][dragInfo.from.x+1]++;
\r
4730 if(dragInfo.from.x == BOARD_RGHT+1 )
\r
4731 board[dragInfo.from.y][dragInfo.from.x-1]++;
\r
4732 board[dragInfo.from.y][dragInfo.from.x] = dragged_piece;
\r
4733 x = dragInfo.pos.x - squareSize / 2;
\r
4734 y = dragInfo.pos.y - squareSize / 2;
\r
4735 DrawPieceOnDC(hdcmem, dragged_piece,
\r
4736 ((int) dragged_piece < (int) BlackPawn),
\r
4737 (dragInfo.from.y + dragInfo.from.x) % 2, x, y, tmphdc);
\r
4740 /* Put the animated piece back into place and draw it */
\r
4741 if (animInfo.piece != EmptySquare) {
\r
4742 board[animInfo.from.y][animInfo.from.x] = animInfo.piece;
\r
4743 x = boardRect.left + animInfo.pos.x;
\r
4744 y = boardRect.top + animInfo.pos.y;
\r
4745 DrawPieceOnDC(hdcmem, animInfo.piece,
\r
4746 ((int) animInfo.piece < (int) BlackPawn),
\r
4747 (animInfo.from.y + animInfo.from.x) % 2, x, y, tmphdc);
\r
4750 /* Release the bufferBitmap by selecting in the old bitmap
\r
4751 * and delete the memory DC
\r
4753 SelectObject(hdcmem, oldBitmap);
\r
4756 /* Set clipping on the target DC */
\r
4757 if (!fullrepaint) {
\r
4758 SelectClipRgn(hdc, clips[0]);
\r
4759 for (x = 1; x < num_clips; x++) {
\r
4760 if (ExtSelectClipRgn(hdc, clips[x], RGN_OR) == ERROR)
\r
4761 abort(); // this should never ever happen!
\r
4765 /* Copy the new bitmap onto the screen in one go.
\r
4766 * This way we avoid any flickering
\r
4768 oldBitmap = SelectObject(tmphdc, bufferBitmap);
\r
4769 BitBlt(hdc, boardRect.left, boardRect.top,
\r
4770 boardRect.right - boardRect.left,
\r
4771 boardRect.bottom - boardRect.top,
\r
4772 tmphdc, boardRect.left, boardRect.top, SRCCOPY);
\r
4773 if(saveDiagFlag) {
\r
4774 BITMAP b; int i, j=0, m, w, wb, fac=0; char pData[1000000];
\r
4775 BITMAPINFOHEADER bih; int color[16], nrColors=0;
\r
4777 GetObject(bufferBitmap, sizeof(b), &b);
\r
4778 if(b.bmWidthBytes*b.bmHeight <= 990000) {
\r
4779 bih.biSize = sizeof(BITMAPINFOHEADER);
\r
4780 bih.biWidth = b.bmWidth;
\r
4781 bih.biHeight = b.bmHeight;
\r
4783 bih.biBitCount = b.bmBitsPixel;
\r
4784 bih.biCompression = 0;
\r
4785 bih.biSizeImage = b.bmWidthBytes*b.bmHeight;
\r
4786 bih.biXPelsPerMeter = 0;
\r
4787 bih.biYPelsPerMeter = 0;
\r
4788 bih.biClrUsed = 0;
\r
4789 bih.biClrImportant = 0;
\r
4790 // fprintf(diagFile, "t=%d\nw=%d\nh=%d\nB=%d\nP=%d\nX=%d\n",
\r
4791 // b.bmType, b.bmWidth, b.bmHeight, b.bmWidthBytes, b.bmPlanes, b.bmBitsPixel);
\r
4792 GetDIBits(tmphdc,bufferBitmap,0,b.bmHeight,pData,(BITMAPINFO*)&bih,DIB_RGB_COLORS);
\r
4793 // fprintf(diagFile, "%8x\n", (int) pData);
\r
4796 wb = b.bmWidthBytes;
\r
4798 for(i=0; i<wb*(b.bmHeight - boardRect.top + OUTER_MARGIN)>>2; i++) {
\r
4799 int k = ((int*) pData)[i];
\r
4800 for(j=0; j<nrColors; j++) if(color[j] == k) break;
\r
4801 if(j >= 16) break;
\r
4803 if(j >= nrColors) nrColors = j+1;
\r
4805 if(j<16) { // 16 colors is enough. Compress to 4 bits per pixel
\r
4807 for(i=0; i<b.bmHeight - boardRect.top + OUTER_MARGIN; i++) {
\r
4808 for(w=0; w<(wb>>2); w+=2) {
\r
4809 int k = ((int*) pData)[(wb*i>>2) + w];
\r
4810 for(j=0; j<nrColors; j++) if(color[j] == k) break;
\r
4811 k = ((int*) pData)[(wb*i>>2) + w + 1];
\r
4812 for(m=0; m<nrColors; m++) if(color[m] == k) break;
\r
4813 pData[p++] = m | j<<4;
\r
4815 while(p&3) pData[p++] = 0;
\r
4818 wb = ((wb+31)>>5)<<2;
\r
4820 // write BITMAPFILEHEADER
\r
4821 fprintf(diagFile, "BM");
\r
4822 fputDW(diagFile, wb*(b.bmHeight - boardRect.top + OUTER_MARGIN)+0x36 + (fac?64:0));
\r
4823 fputDW(diagFile, 0);
\r
4824 fputDW(diagFile, 0x36 + (fac?64:0));
\r
4825 // write BITMAPINFOHEADER
\r
4826 fputDW(diagFile, 40);
\r
4827 fputDW(diagFile, b.bmWidth);
\r
4828 fputDW(diagFile, b.bmHeight - boardRect.top + OUTER_MARGIN);
\r
4829 if(fac) fputDW(diagFile, 0x040001); // planes and bits/pixel
\r
4830 else fputDW(diagFile, 0x200001); // planes and bits/pixel
\r
4831 fputDW(diagFile, 0);
\r
4832 fputDW(diagFile, 0);
\r
4833 fputDW(diagFile, 0);
\r
4834 fputDW(diagFile, 0);
\r
4835 fputDW(diagFile, 0);
\r
4836 fputDW(diagFile, 0);
\r
4837 // write color table
\r
4839 for(i=0; i<16; i++) fputDW(diagFile, color[i]);
\r
4840 // write bitmap data
\r
4841 for(i=0; i<wb*(b.bmHeight - boardRect.top + OUTER_MARGIN); i++)
\r
4842 fputc(pData[i], diagFile);
\r
4847 SelectObject(tmphdc, oldBitmap);
\r
4849 /* Massive cleanup */
\r
4850 for (x = 0; x < num_clips; x++)
\r
4851 DeleteObject(clips[x]);
\r
4854 DeleteObject(bufferBitmap);
\r
4857 ReleaseDC(hwndMain, hdc);
\r
4859 if (lastDrawnFlipView != flipView) {
\r
4861 CheckMenuItem(GetMenu(hwndMain),IDM_FlipView, MF_BYCOMMAND|MF_CHECKED);
\r
4863 CheckMenuItem(GetMenu(hwndMain),IDM_FlipView, MF_BYCOMMAND|MF_UNCHECKED);
\r
4866 /* CopyBoard(lastDrawn, board);*/
\r
4867 lastDrawnHighlight = highlightInfo;
\r
4868 lastDrawnPremove = premoveHighlightInfo;
\r
4869 lastDrawnFlipView = flipView;
\r
4870 lastDrawnValid = 1;
\r
4873 /* [HGM] diag: Save the current board display to the given open file and close the file */
\r
4878 saveDiagFlag = 1; diagFile = f;
\r
4879 HDCDrawPosition(NULL, TRUE, NULL);
\r
4883 // if(f != NULL) fprintf(f, "Sorry, but this feature is still in preparation\n");
\r
4890 /*---------------------------------------------------------------------------*\
\r
4891 | CLIENT PAINT PROCEDURE
\r
4892 | This is the main event-handler for the WM_PAINT message.
\r
4894 \*---------------------------------------------------------------------------*/
\r
4896 PaintProc(HWND hwnd)
\r
4902 if((hdc = BeginPaint(hwnd, &ps))) {
\r
4903 if (IsIconic(hwnd)) {
\r
4904 DrawIcon(hdc, 2, 2, iconCurrent);
\r
4906 if (!appData.monoMode) {
\r
4907 SelectPalette(hdc, hPal, FALSE);
\r
4908 RealizePalette(hdc);
\r
4910 HDCDrawPosition(hdc, 1, NULL);
\r
4912 SelectObject(hdc, font[boardSize][MESSAGE_FONT]->hf);
\r
4913 ExtTextOut(hdc, messageRect.left, messageRect.top,
\r
4914 ETO_CLIPPED|ETO_OPAQUE,
\r
4915 &messageRect, messageText, strlen(messageText), NULL);
\r
4916 SelectObject(hdc, oldFont);
\r
4917 DisplayBothClocks();
\r
4919 EndPaint(hwnd,&ps);
\r
4927 * If the user selects on a border boundary, return -1; if off the board,
\r
4928 * return -2. Otherwise map the event coordinate to the square.
\r
4929 * The offset boardRect.left or boardRect.top must already have been
\r
4930 * subtracted from x.
\r
4933 EventToSquare(int x)
\r
4940 if ((x % (squareSize + lineGap)) >= squareSize)
\r
4942 x /= (squareSize + lineGap);
\r
4943 if (x >= BOARD_SIZE)
\r
4954 DropEnable dropEnables[] = {
\r
4955 { 'P', DP_Pawn, "Pawn" },
\r
4956 { 'N', DP_Knight, "Knight" },
\r
4957 { 'B', DP_Bishop, "Bishop" },
\r
4958 { 'R', DP_Rook, "Rook" },
\r
4959 { 'Q', DP_Queen, "Queen" },
\r
4963 SetupDropMenu(HMENU hmenu)
\r
4965 int i, count, enable;
\r
4967 extern char white_holding[], black_holding[];
\r
4968 char item[MSG_SIZ];
\r
4970 for (i=0; i<sizeof(dropEnables)/sizeof(DropEnable); i++) {
\r
4971 p = strchr(gameMode == IcsPlayingWhite ? white_holding : black_holding,
\r
4972 dropEnables[i].piece);
\r
4974 while (p && *p++ == dropEnables[i].piece) count++;
\r
4975 sprintf(item, "%s %d", dropEnables[i].name, count);
\r
4976 enable = count > 0 || !appData.testLegality
\r
4977 /*!!temp:*/ || (gameInfo.variant == VariantCrazyhouse
\r
4978 && !appData.icsActive);
\r
4979 ModifyMenu(hmenu, dropEnables[i].command,
\r
4980 MF_BYCOMMAND | (enable ? MF_ENABLED : MF_GRAYED) | MF_STRING,
\r
4981 dropEnables[i].command, item);
\r
4985 /* Event handler for mouse messages */
\r
4987 MouseEvent(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
4991 static int recursive = 0;
\r
4993 // BOOLEAN needsRedraw = FALSE;
\r
4994 BOOLEAN saveAnimate;
\r
4995 BOOLEAN forceFullRepaint = IsFullRepaintPreferrable(); /* [AS] */
\r
4996 static BOOLEAN sameAgain = FALSE, promotionChoice = FALSE;
\r
4997 ChessMove moveType;
\r
5000 if (message == WM_MBUTTONUP) {
\r
5001 /* Hideous kludge to fool TrackPopupMenu into paying attention
\r
5002 to the middle button: we simulate pressing the left button too!
\r
5004 PostMessage(hwnd, WM_LBUTTONDOWN, wParam, lParam);
\r
5005 PostMessage(hwnd, WM_LBUTTONUP, wParam, lParam);
\r
5011 pt.x = LOWORD(lParam);
\r
5012 pt.y = HIWORD(lParam);
\r
5013 x = EventToSquare(pt.x - boardRect.left);
\r
5014 y = EventToSquare(pt.y - boardRect.top);
\r
5015 if (!flipView && y >= 0) {
\r
5016 y = BOARD_HEIGHT - 1 - y;
\r
5018 if (flipView && x >= 0) {
\r
5019 x = BOARD_WIDTH - 1 - x;
\r
5022 switch (message) {
\r
5023 case WM_LBUTTONDOWN:
\r
5024 if(promotionChoice) { // we are waiting for a click to indicate promotion piece
\r
5025 promotionChoice = FALSE; // only one chance: if click not OK it is interpreted as cancel
\r
5026 if(appData.debugMode) fprintf(debugFP, "promotion click, x=%d, y=%d\n", x, y);
\r
5027 if(gameInfo.holdingsWidth &&
\r
5028 (WhiteOnMove(currentMove)
\r
5029 ? x == BOARD_WIDTH-1 && y < gameInfo.holdingsSize && y > 0
\r
5030 : x == 0 && y >= BOARD_HEIGHT - gameInfo.holdingsSize && y < BOARD_HEIGHT-1) ) {
\r
5031 // click in right holdings, for determining promotion piece
\r
5032 ChessSquare p = boards[currentMove][y][x];
\r
5033 if(appData.debugMode) fprintf(debugFP, "square contains %d\n", (int)p);
\r
5034 if(p != EmptySquare) {
\r
5035 FinishMove(WhitePromotionQueen, fromX, fromY, toX, toY, ToLower(PieceToChar(p)));
\r
5036 fromX = fromY = -1;
\r
5040 DrawPosition(FALSE, boards[currentMove]);
\r
5044 sameAgain = FALSE;
\r
5046 /* Downclick vertically off board; check if on clock */
\r
5047 if (PtInRect((LPRECT) &whiteRect, pt)) {
\r
5048 if (gameMode == EditPosition) {
\r
5049 SetWhiteToPlayEvent();
\r
5050 } else if (gameMode == IcsPlayingBlack ||
\r
5051 gameMode == MachinePlaysWhite) {
\r
5053 } else if (gameMode == EditGame) {
\r
5054 AdjustClock(flipClock, -1);
\r
5056 } else if (PtInRect((LPRECT) &blackRect, pt)) {
\r
5057 if (gameMode == EditPosition) {
\r
5058 SetBlackToPlayEvent();
\r
5059 } else if (gameMode == IcsPlayingWhite ||
\r
5060 gameMode == MachinePlaysBlack) {
\r
5062 } else if (gameMode == EditGame) {
\r
5063 AdjustClock(!flipClock, -1);
\r
5066 if (!appData.highlightLastMove) {
\r
5067 ClearHighlights();
\r
5068 DrawPosition((int) (forceFullRepaint || FALSE), NULL);
\r
5070 fromX = fromY = -1;
\r
5071 dragInfo.start.x = dragInfo.start.y = -1;
\r
5072 dragInfo.from = dragInfo.start;
\r
5074 } else if (x < 0 || y < 0
\r
5075 /* [HGM] block clicks between board and holdings */
\r
5076 || x == BOARD_LEFT-1 || x == BOARD_RGHT
\r
5077 || (x == BOARD_LEFT-2 && y < BOARD_HEIGHT-gameInfo.holdingsSize)
\r
5078 || (x == BOARD_RGHT+1 && y >= gameInfo.holdingsSize)
\r
5079 /* EditPosition, empty square, or different color piece;
\r
5080 click-click move is possible */
\r
5083 } else if (fromX == x && fromY == y) {
\r
5084 /* Downclick on same square again */
\r
5085 ClearHighlights();
\r
5086 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
5087 sameAgain = TRUE;
\r
5088 } else if (fromX != -1 &&
\r
5089 x != BOARD_LEFT-2 && x != BOARD_RGHT+1
\r
5091 /* Downclick on different square. */
\r
5092 /* [HGM] if on holdings file, should count as new first click ! */
\r
5093 { /* [HGM] <sameColor> now always do UserMoveTest(), and check colors there */
\r
5096 /* [HGM] <popupFix> UserMoveEvent requires two calls now,
\r
5097 to make sure move is legal before showing promotion popup */
\r
5098 moveType = UserMoveTest(fromX, fromY, toX, toY, NULLCHAR);
\r
5099 if(moveType == AmbiguousMove) { /* [HGM] Edit-Position move executed */
\r
5100 fromX = fromY = -1;
\r
5101 ClearHighlights();
\r
5102 DrawPosition(FALSE, boards[currentMove]);
\r
5105 if(moveType != ImpossibleMove) {
\r
5106 /* [HGM] We use PromotionToKnight in Shogi to indicate frorced promotion */
\r
5107 if (moveType == WhitePromotionKnight || moveType == BlackPromotionKnight ||
\r
5108 ((moveType == WhitePromotionQueen || moveType == BlackPromotionQueen) &&
\r
5109 appData.alwaysPromoteToQueen)) {
\r
5110 FinishMove(moveType, fromX, fromY, toX, toY, 'q');
\r
5111 if (!appData.highlightLastMove) {
\r
5112 ClearHighlights();
\r
5113 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
5116 if (moveType == WhitePromotionQueen || moveType == BlackPromotionQueen ) {
\r
5117 SetHighlights(fromX, fromY, toX, toY);
\r
5118 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
5119 /* [HGM] <popupFix> Popup calls FinishMove now.
\r
5120 If promotion to Q is legal, all are legal! */
\r
5121 if(gameInfo.variant == VariantSuper || gameInfo.variant == VariantGreat)
\r
5122 { ChessSquare p = boards[currentMove][fromY][fromX], q = boards[currentMove][toY][toX];
\r
5123 // kludge to temporarily execute move on display, wthout promotng yet
\r
5124 promotionChoice = TRUE;
\r
5125 boards[currentMove][fromY][fromX] = EmptySquare; // move Pawn to 8th rank
\r
5126 boards[currentMove][toY][toX] = p;
\r
5127 DrawPosition(FALSE, boards[currentMove]);
\r
5128 boards[currentMove][fromY][fromX] = p; // take back, but display stays
\r
5129 boards[currentMove][toY][toX] = q;
\r
5131 PromotionPopup(hwnd);
\r
5132 } else { /* not a promotion */
\r
5133 if (appData.animate || appData.highlightLastMove) {
\r
5134 SetHighlights(fromX, fromY, toX, toY);
\r
5136 ClearHighlights();
\r
5138 FinishMove(moveType, fromX, fromY, toX, toY, NULLCHAR);
\r
5139 fromX = fromY = -1;
\r
5140 if (appData.animate && !appData.highlightLastMove) {
\r
5141 ClearHighlights();
\r
5142 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
5148 /* [HGM] it seemed that braces were missing here */
\r
5149 SetPremoveHighlights(fromX, fromY, toX, toY);
\r
5150 fromX = fromY = -1;
\r
5154 ClearHighlights();
\r
5155 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
5157 /* First downclick, or restart on a square with same color piece */
\r
5158 if (!frozen && OKToStartUserMove(x, y)) {
\r
5161 dragInfo.lastpos = pt;
\r
5162 dragInfo.from.x = fromX;
\r
5163 dragInfo.from.y = fromY;
\r
5164 dragInfo.start = dragInfo.from;
\r
5165 SetCapture(hwndMain);
\r
5167 fromX = fromY = -1;
\r
5168 dragInfo.start.x = dragInfo.start.y = -1;
\r
5169 dragInfo.from = dragInfo.start;
\r
5170 DrawPosition(forceFullRepaint || FALSE, NULL); /* [AS] */
\r
5174 case WM_LBUTTONUP:
\r
5176 if (fromX == -1) break;
\r
5177 if (x == fromX && y == fromY) {
\r
5178 dragInfo.from.x = dragInfo.from.y = -1;
\r
5179 /* Upclick on same square */
\r
5181 /* Clicked same square twice: abort click-click move */
\r
5182 fromX = fromY = -1;
\r
5184 ClearPremoveHighlights();
\r
5186 /* First square clicked: start click-click move */
\r
5187 SetHighlights(fromX, fromY, -1, -1);
\r
5189 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
5190 } else if (dragInfo.from.x < 0 || dragInfo.from.y < 0) {
\r
5191 /* Errant click; ignore */
\r
5194 /* Finish drag move. */
\r
5195 if (appData.debugMode) {
\r
5196 fprintf(debugFP, "release\n");
\r
5198 dragInfo.from.x = dragInfo.from.y = -1;
\r
5201 saveAnimate = appData.animate; /* sorry, Hawk :) */
\r
5202 appData.animate = appData.animate && !appData.animateDragging;
\r
5203 moveType = UserMoveTest(fromX, fromY, toX, toY, NULLCHAR);
\r
5204 if(moveType == AmbiguousMove) { /* [HGM] Edit-Position move executed */
\r
5205 fromX = fromY = -1;
\r
5206 ClearHighlights();
\r
5207 DrawPosition(FALSE, boards[currentMove]);
\r
5208 appData.animate = saveAnimate;
\r
5211 if(moveType != ImpossibleMove) {
\r
5212 /* [HGM] use move type to determine if move is promotion.
\r
5213 Knight is Shogi kludge for mandatory promotion, Queen means choice */
\r
5214 if (moveType == WhitePromotionKnight || moveType == BlackPromotionKnight ||
\r
5215 ((moveType == WhitePromotionQueen || moveType == BlackPromotionQueen) &&
\r
5216 appData.alwaysPromoteToQueen))
\r
5217 FinishMove(moveType, fromX, fromY, toX, toY, 'q');
\r
5219 if (moveType == WhitePromotionQueen || moveType == BlackPromotionQueen ) {
\r
5220 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
5221 if(gameInfo.variant == VariantSuper || gameInfo.variant == VariantGreat)
\r
5222 { ChessSquare p = boards[currentMove][fromY][fromX], q = boards[currentMove][toY][toX];
\r
5223 // kludge to temporarily execute move on display, wthout promotng yet
\r
5224 promotionChoice = TRUE;
\r
5225 boards[currentMove][fromY][fromX] = EmptySquare; // move Pawn to 8th rank
\r
5226 boards[currentMove][toY][toX] = p;
\r
5227 DrawPosition(FALSE, boards[currentMove]);
\r
5228 boards[currentMove][fromY][fromX] = p; // take back, but display stays
\r
5229 boards[currentMove][toY][toX] = q;
\r
5230 appData.animate = saveAnimate;
\r
5233 PromotionPopup(hwnd); /* [HGM] Popup now calls FinishMove */
\r
5235 if(saveAnimate /* ^$!%@#$!$ */ && gameInfo.variant == VariantAtomic
\r
5236 && (boards[currentMove][toY][toX] != EmptySquare ||
\r
5237 moveType == WhiteCapturesEnPassant ||
\r
5238 moveType == BlackCapturesEnPassant ) )
\r
5239 AnimateAtomicCapture(fromX, fromY, toX, toY, 20);
\r
5240 FinishMove(moveType, fromX, fromY, toX, toY, NULLCHAR);
\r
5243 if (gotPremove) SetPremoveHighlights(fromX, fromY, toX, toY);
\r
5244 appData.animate = saveAnimate;
\r
5245 fromX = fromY = -1;
\r
5246 if (appData.highlightDragging && !appData.highlightLastMove) {
\r
5247 ClearHighlights();
\r
5249 if (appData.animate || appData.animateDragging ||
\r
5250 appData.highlightDragging || gotPremove) {
\r
5251 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
5254 dragInfo.start.x = dragInfo.start.y = -1;
\r
5255 dragInfo.pos = dragInfo.lastpos = dragInfo.start;
\r
5258 case WM_MOUSEMOVE:
\r
5259 if ((appData.animateDragging || appData.highlightDragging)
\r
5260 && (wParam & MK_LBUTTON)
\r
5261 && dragInfo.from.x >= 0)
\r
5263 BOOL full_repaint = FALSE;
\r
5265 sameAgain = FALSE; /* [HGM] if we drag something around, do keep square selected */
\r
5266 if (appData.animateDragging) {
\r
5267 dragInfo.pos = pt;
\r
5269 if (appData.highlightDragging) {
\r
5270 SetHighlights(fromX, fromY, x, y);
\r
5271 if( IsDrawArrowEnabled() && (x < 0 || x >= BOARD_WIDTH || y < 0 || y >= BOARD_HEIGHT) ) {
\r
5272 full_repaint = TRUE;
\r
5276 DrawPosition( full_repaint, NULL);
\r
5278 dragInfo.lastpos = dragInfo.pos;
\r
5282 case WM_MOUSEWHEEL: // [DM]
\r
5283 { static int lastDir = 0; // [HGM] build in some hysteresis to avoid spurious events
\r
5284 /* Mouse Wheel is being rolled forward
\r
5285 * Play moves forward
\r
5287 if((short)HIWORD(wParam) > 0 && currentMove < forwardMostMove)
\r
5288 { if(lastDir == 1) ForwardEvent(); else lastDir = 1; } // [HGM] suppress first event in direction
\r
5289 /* Mouse Wheel is being rolled backward
\r
5290 * Play moves backward
\r
5292 if((short)HIWORD(wParam) < 0 && currentMove > backwardMostMove)
\r
5293 { if(lastDir == -1) BackwardEvent(); else lastDir = -1; }
\r
5297 case WM_MBUTTONDOWN:
\r
5298 case WM_RBUTTONDOWN:
\r
5301 fromX = fromY = -1;
\r
5302 dragInfo.pos.x = dragInfo.pos.y = -1;
\r
5303 dragInfo.start.x = dragInfo.start.y = -1;
\r
5304 dragInfo.from = dragInfo.start;
\r
5305 dragInfo.lastpos = dragInfo.pos;
\r
5306 if (appData.highlightDragging) {
\r
5307 ClearHighlights();
\r
5310 /* [HGM] right mouse button in clock area edit-game mode ups clock */
\r
5311 if (PtInRect((LPRECT) &whiteRect, pt)) {
\r
5312 if (gameMode == EditGame) AdjustClock(flipClock, 1);
\r
5313 } else if (PtInRect((LPRECT) &blackRect, pt)) {
\r
5314 if (gameMode == EditGame) AdjustClock(!flipClock, 1);
\r
5317 DrawPosition(TRUE, NULL);
\r
5319 switch (gameMode) {
\r
5320 case EditPosition:
\r
5321 case IcsExamining:
\r
5322 if (x < 0 || y < 0) break;
\r
5325 if (message == WM_MBUTTONDOWN) {
\r
5326 buttonCount = 3; /* even if system didn't think so */
\r
5327 if (wParam & MK_SHIFT)
\r
5328 MenuPopup(hwnd, pt, LoadMenu(hInst, "BlackPieceMenu"), -1);
\r
5330 MenuPopup(hwnd, pt, LoadMenu(hInst, "WhitePieceMenu"), -1);
\r
5331 } else { /* message == WM_RBUTTONDOWN */
\r
5333 if (buttonCount == 3) {
\r
5334 if (wParam & MK_SHIFT)
\r
5335 MenuPopup(hwnd, pt, LoadMenu(hInst, "WhitePieceMenu"), -1);
\r
5337 MenuPopup(hwnd, pt, LoadMenu(hInst, "BlackPieceMenu"), -1);
\r
5339 MenuPopup(hwnd, pt, LoadMenu(hInst, "PieceMenu"), -1);
\r
5342 /* Just have one menu, on the right button. Windows users don't
\r
5343 think to try the middle one, and sometimes other software steals
\r
5344 it, or it doesn't really exist. */
\r
5345 if(gameInfo.variant != VariantShogi)
\r
5346 MenuPopup(hwnd, pt, LoadMenu(hInst, "PieceMenu"), -1);
\r
5348 MenuPopup(hwnd, pt, LoadMenu(hInst, "ShogiPieceMenu"), -1);
\r
5352 case IcsPlayingWhite:
\r
5353 case IcsPlayingBlack:
\r
5355 case MachinePlaysWhite:
\r
5356 case MachinePlaysBlack:
\r
5357 if (appData.testLegality &&
\r
5358 gameInfo.variant != VariantBughouse &&
\r
5359 gameInfo.variant != VariantCrazyhouse) break;
\r
5360 if (x < 0 || y < 0) break;
\r
5363 hmenu = LoadMenu(hInst, "DropPieceMenu");
\r
5364 SetupDropMenu(hmenu);
\r
5365 MenuPopup(hwnd, pt, hmenu, -1);
\r
5376 /* Preprocess messages for buttons in main window */
\r
5378 ButtonProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
5380 int id = GetWindowLong(hwnd, GWL_ID);
\r
5383 for (i=0; i<N_BUTTONS; i++) {
\r
5384 if (buttonDesc[i].id == id) break;
\r
5386 if (i == N_BUTTONS) return 0;
\r
5387 switch (message) {
\r
5392 dir = (wParam == VK_LEFT) ? -1 : 1;
\r
5393 SetFocus(buttonDesc[(i + dir + N_BUTTONS) % N_BUTTONS].hwnd);
\r
5400 SendMessage(hwndMain, WM_COMMAND, MAKEWPARAM(buttonDesc[i].id, 0), 0);
\r
5403 if (appData.icsActive && (isalpha((char)wParam) || wParam == '0')) {
\r
5404 // [HGM] movenum: only letters or leading zero should go to ICS input
\r
5405 HWND h = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
5406 if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
5408 SendMessage(h, WM_CHAR, wParam, lParam);
\r
5410 } else if (isalpha((char)wParam) || isdigit((char)wParam)){
\r
5411 PopUpMoveDialog((char)wParam);
\r
5417 return CallWindowProc(buttonDesc[i].wndproc, hwnd, message, wParam, lParam);
\r
5420 /* Process messages for Promotion dialog box */
\r
5422 Promotion(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
5426 switch (message) {
\r
5427 case WM_INITDIALOG: /* message: initialize dialog box */
\r
5428 /* Center the dialog over the application window */
\r
5429 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
5430 ShowWindow(GetDlgItem(hDlg, PB_King),
\r
5431 (!appData.testLegality || gameInfo.variant == VariantSuicide ||
\r
5432 gameInfo.variant == VariantGiveaway || gameInfo.variant == VariantSuper ) ?
\r
5433 SW_SHOW : SW_HIDE);
\r
5434 /* [HGM] Only allow C & A promotions if these pieces are defined */
\r
5435 ShowWindow(GetDlgItem(hDlg, PB_Archbishop),
\r
5436 ((PieceToChar(WhiteAngel) >= 'A' &&
\r
5437 PieceToChar(WhiteAngel) != '~') ||
\r
5438 (PieceToChar(BlackAngel) >= 'A' &&
\r
5439 PieceToChar(BlackAngel) != '~') ) ?
\r
5440 SW_SHOW : SW_HIDE);
\r
5441 ShowWindow(GetDlgItem(hDlg, PB_Chancellor),
\r
5442 ((PieceToChar(WhiteMarshall) >= 'A' &&
\r
5443 PieceToChar(WhiteMarshall) != '~') ||
\r
5444 (PieceToChar(BlackMarshall) >= 'A' &&
\r
5445 PieceToChar(BlackMarshall) != '~') ) ?
\r
5446 SW_SHOW : SW_HIDE);
\r
5447 /* [HGM] Hide B & R button in Shogi, use Q as promote, N as defer */
\r
5448 ShowWindow(GetDlgItem(hDlg, PB_Rook),
\r
5449 gameInfo.variant != VariantShogi ?
\r
5450 SW_SHOW : SW_HIDE);
\r
5451 ShowWindow(GetDlgItem(hDlg, PB_Bishop),
\r
5452 gameInfo.variant != VariantShogi ?
\r
5453 SW_SHOW : SW_HIDE);
\r
5454 ShowWindow(GetDlgItem(hDlg, IDC_Yes),
\r
5455 gameInfo.variant == VariantShogi ?
\r
5456 SW_SHOW : SW_HIDE);
\r
5457 ShowWindow(GetDlgItem(hDlg, IDC_No),
\r
5458 gameInfo.variant == VariantShogi ?
\r
5459 SW_SHOW : SW_HIDE);
\r
5460 ShowWindow(GetDlgItem(hDlg, IDC_Centaur),
\r
5461 gameInfo.variant == VariantSuper ?
\r
5462 SW_SHOW : SW_HIDE);
\r
5465 case WM_COMMAND: /* message: received a command */
\r
5466 switch (LOWORD(wParam)) {
\r
5468 EndDialog(hDlg, TRUE); /* Exit the dialog */
\r
5469 ClearHighlights();
\r
5470 DrawPosition(FALSE, NULL);
\r
5473 promoChar = gameInfo.variant == VariantSuper ? PieceToChar(BlackSilver) : PieceToChar(BlackKing);
\r
5476 promoChar = gameInfo.variant == VariantShogi ? '+' : PieceToChar(BlackQueen);
\r
5479 promoChar = PieceToChar(BlackRook);
\r
5482 promoChar = PieceToChar(BlackBishop);
\r
5484 case PB_Chancellor:
\r
5485 promoChar = PieceToChar(BlackMarshall);
\r
5487 case PB_Archbishop:
\r
5488 promoChar = PieceToChar(BlackAngel);
\r
5491 promoChar = gameInfo.variant == VariantShogi ? '=' : PieceToChar(BlackKnight);
\r
5496 EndDialog(hDlg, TRUE); /* Exit the dialog */
\r
5497 /* [HGM] <popupFix> Call FinishMove rather than UserMoveEvent, as we
\r
5498 only show the popup when we are already sure the move is valid or
\r
5499 legal. We pass a faulty move type, but the kludge is that FinishMove
\r
5500 will figure out it is a promotion from the promoChar. */
\r
5501 FinishMove(NormalMove, fromX, fromY, toX, toY, promoChar);
\r
5502 if (!appData.highlightLastMove) {
\r
5503 ClearHighlights();
\r
5504 DrawPosition(FALSE, NULL);
\r
5511 /* Pop up promotion dialog */
\r
5513 PromotionPopup(HWND hwnd)
\r
5517 lpProc = MakeProcInstance((FARPROC)Promotion, hInst);
\r
5518 DialogBox(hInst, MAKEINTRESOURCE(DLG_PromotionKing),
\r
5519 hwnd, (DLGPROC)lpProc);
\r
5520 FreeProcInstance(lpProc);
\r
5523 /* Toggle ShowThinking */
\r
5525 ToggleShowThinking()
\r
5527 appData.showThinking = !appData.showThinking;
\r
5528 ShowThinkingEvent();
\r
5532 LoadGameDialog(HWND hwnd, char* title)
\r
5536 char fileTitle[MSG_SIZ];
\r
5537 f = OpenFileDialog(hwnd, "rb", "",
\r
5538 appData.oldSaveStyle ? "gam" : "pgn",
\r
5540 title, &number, fileTitle, NULL);
\r
5542 cmailMsgLoaded = FALSE;
\r
5543 if (number == 0) {
\r
5544 int error = GameListBuild(f);
\r
5546 DisplayError("Cannot build game list", error);
\r
5547 } else if (!ListEmpty(&gameList) &&
\r
5548 ((ListGame *) gameList.tailPred)->number > 1) {
\r
5549 GameListPopUp(f, fileTitle);
\r
5552 GameListDestroy();
\r
5555 LoadGame(f, number, fileTitle, FALSE);
\r
5560 ChangedConsoleFont()
\r
5563 CHARRANGE tmpsel, sel;
\r
5564 MyFont *f = font[boardSize][CONSOLE_FONT];
\r
5565 HWND hText = GetDlgItem(hwndConsole, OPT_ConsoleText);
\r
5566 HWND hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
5569 cfmt.cbSize = sizeof(CHARFORMAT);
\r
5570 cfmt.dwMask = CFM_FACE|CFM_SIZE|CFM_CHARSET;
\r
5571 strcpy(cfmt.szFaceName, font[boardSize][CONSOLE_FONT]->mfp.faceName);
\r
5572 /* yHeight is expressed in twips. A twip is 1/20 of a font's point
\r
5573 * size. This was undocumented in the version of MSVC++ that I had
\r
5574 * when I wrote the code, but is apparently documented now.
\r
5576 cfmt.yHeight = (int)(f->mfp.pointSize * 20.0 + 0.5);
\r
5577 cfmt.bCharSet = f->lf.lfCharSet;
\r
5578 cfmt.bPitchAndFamily = f->lf.lfPitchAndFamily;
\r
5579 SendMessage(hText, EM_SETCHARFORMAT, SCF_ALL, (LPARAM) &cfmt);
\r
5580 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM) &cfmt);
\r
5581 /* Why are the following seemingly needed too? */
\r
5582 SendMessage(hText, EM_SETCHARFORMAT, SCF_DEFAULT, (LPARAM) &cfmt);
\r
5583 SendMessage(hInput, EM_SETCHARFORMAT, SCF_DEFAULT, (LPARAM) &cfmt);
\r
5584 SendMessage(hText, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
5586 tmpsel.cpMax = -1; /*999999?*/
\r
5587 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&tmpsel);
\r
5588 SendMessage(hText, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM) &cfmt);
\r
5589 /* Trying putting this here too. It still seems to tickle a RichEdit
\r
5590 * bug: sometimes RichEdit indents the first line of a paragraph too.
\r
5592 paraf.cbSize = sizeof(paraf);
\r
5593 paraf.dwMask = PFM_OFFSET | PFM_STARTINDENT;
\r
5594 paraf.dxStartIndent = 0;
\r
5595 paraf.dxOffset = WRAP_INDENT;
\r
5596 SendMessage(hText, EM_SETPARAFORMAT, 0, (LPARAM) ¶f);
\r
5597 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
5600 /*---------------------------------------------------------------------------*\
\r
5602 * Window Proc for main window
\r
5604 \*---------------------------------------------------------------------------*/
\r
5606 /* Process messages for main window, etc. */
\r
5608 WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
5611 int wmId, wmEvent;
\r
5615 char fileTitle[MSG_SIZ];
\r
5616 char buf[MSG_SIZ];
\r
5617 static SnapData sd;
\r
5619 switch (message) {
\r
5621 case WM_PAINT: /* message: repaint portion of window */
\r
5625 case WM_ERASEBKGND:
\r
5626 if (IsIconic(hwnd)) {
\r
5627 /* Cheat; change the message */
\r
5628 return (DefWindowProc(hwnd, WM_ICONERASEBKGND, wParam, lParam));
\r
5630 return (DefWindowProc(hwnd, message, wParam, lParam));
\r
5634 case WM_LBUTTONDOWN:
\r
5635 case WM_MBUTTONDOWN:
\r
5636 case WM_RBUTTONDOWN:
\r
5637 case WM_LBUTTONUP:
\r
5638 case WM_MBUTTONUP:
\r
5639 case WM_RBUTTONUP:
\r
5640 case WM_MOUSEMOVE:
\r
5641 case WM_MOUSEWHEEL:
\r
5642 MouseEvent(hwnd, message, wParam, lParam);
\r
5645 JAWS_KB_NAVIGATION
\r
5649 JAWS_ALT_INTERCEPT
\r
5651 if (appData.icsActive && (isalpha((char)wParam) || wParam == '0')) {
\r
5652 // [HGM] movenum: for non-zero digits we always do type-in dialog
\r
5653 HWND h = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
5654 if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
5656 SendMessage(h, message, wParam, lParam);
\r
5657 } else if(lParam != KF_REPEAT) {
\r
5658 if (isalpha((char)wParam) || isdigit((char)wParam)) {
\r
5659 PopUpMoveDialog((char)wParam);
\r
5660 } else if((char)wParam == 003) CopyGameToClipboard();
\r
5661 else if((char)wParam == 026) PasteGameOrFENFromClipboard();
\r
5666 case WM_PALETTECHANGED:
\r
5667 if (hwnd != (HWND)wParam && !appData.monoMode) {
\r
5669 HDC hdc = GetDC(hwndMain);
\r
5670 SelectPalette(hdc, hPal, TRUE);
\r
5671 nnew = RealizePalette(hdc);
\r
5673 paletteChanged = TRUE;
\r
5675 UpdateColors(hdc);
\r
5677 InvalidateRect(hwnd, &boardRect, FALSE);/*faster!*/
\r
5680 ReleaseDC(hwnd, hdc);
\r
5684 case WM_QUERYNEWPALETTE:
\r
5685 if (!appData.monoMode /*&& paletteChanged*/) {
\r
5687 HDC hdc = GetDC(hwndMain);
\r
5688 paletteChanged = FALSE;
\r
5689 SelectPalette(hdc, hPal, FALSE);
\r
5690 nnew = RealizePalette(hdc);
\r
5692 InvalidateRect(hwnd, &boardRect, FALSE);
\r
5694 ReleaseDC(hwnd, hdc);
\r
5699 case WM_COMMAND: /* message: command from application menu */
\r
5700 wmId = LOWORD(wParam);
\r
5701 wmEvent = HIWORD(wParam);
\r
5706 AnalysisPopDown();
\r
5707 SAY("new game enter a move to play against the computer with white");
\r
5710 case IDM_NewGameFRC:
\r
5711 if( NewGameFRC() == 0 ) {
\r
5713 AnalysisPopDown();
\r
5717 case IDM_NewVariant:
\r
5718 NewVariantPopup(hwnd);
\r
5721 case IDM_LoadGame:
\r
5722 LoadGameDialog(hwnd, "Load Game from File");
\r
5725 case IDM_LoadNextGame:
\r
5729 case IDM_LoadPrevGame:
\r
5733 case IDM_ReloadGame:
\r
5737 case IDM_LoadPosition:
\r
5738 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile) {
\r
5739 Reset(FALSE, TRUE);
\r
5742 f = OpenFileDialog(hwnd, "rb", "",
\r
5743 appData.oldSaveStyle ? "pos" : "fen",
\r
5745 "Load Position from File", &number, fileTitle, NULL);
\r
5747 LoadPosition(f, number, fileTitle);
\r
5751 case IDM_LoadNextPosition:
\r
5752 ReloadPosition(1);
\r
5755 case IDM_LoadPrevPosition:
\r
5756 ReloadPosition(-1);
\r
5759 case IDM_ReloadPosition:
\r
5760 ReloadPosition(0);
\r
5763 case IDM_SaveGame:
\r
5764 defName = DefaultFileName(appData.oldSaveStyle ? "gam" : "pgn");
\r
5765 f = OpenFileDialog(hwnd, "a", defName,
\r
5766 appData.oldSaveStyle ? "gam" : "pgn",
\r
5768 "Save Game to File", NULL, fileTitle, NULL);
\r
5770 SaveGame(f, 0, "");
\r
5774 case IDM_SavePosition:
\r
5775 defName = DefaultFileName(appData.oldSaveStyle ? "pos" : "fen");
\r
5776 f = OpenFileDialog(hwnd, "a", defName,
\r
5777 appData.oldSaveStyle ? "pos" : "fen",
\r
5779 "Save Position to File", NULL, fileTitle, NULL);
\r
5781 SavePosition(f, 0, "");
\r
5785 case IDM_SaveDiagram:
\r
5786 defName = "diagram";
\r
5787 f = OpenFileDialog(hwnd, "wb", defName,
\r
5790 "Save Diagram to File", NULL, fileTitle, NULL);
\r
5796 case IDM_CopyGame:
\r
5797 CopyGameToClipboard();
\r
5800 case IDM_PasteGame:
\r
5801 PasteGameFromClipboard();
\r
5804 case IDM_CopyGameListToClipboard:
\r
5805 CopyGameListToClipboard();
\r
5808 /* [AS] Autodetect FEN or PGN data */
\r
5809 case IDM_PasteAny:
\r
5810 PasteGameOrFENFromClipboard();
\r
5813 /* [AS] Move history */
\r
5814 case IDM_ShowMoveHistory:
\r
5815 if( MoveHistoryIsUp() ) {
\r
5816 MoveHistoryPopDown();
\r
5819 MoveHistoryPopUp();
\r
5823 /* [AS] Eval graph */
\r
5824 case IDM_ShowEvalGraph:
\r
5825 if( EvalGraphIsUp() ) {
\r
5826 EvalGraphPopDown();
\r
5830 SetFocus(hwndMain);
\r
5834 /* [AS] Engine output */
\r
5835 case IDM_ShowEngineOutput:
\r
5836 if( EngineOutputIsUp() ) {
\r
5837 EngineOutputPopDown();
\r
5840 EngineOutputPopUp();
\r
5844 /* [AS] User adjudication */
\r
5845 case IDM_UserAdjudication_White:
\r
5846 UserAdjudicationEvent( +1 );
\r
5849 case IDM_UserAdjudication_Black:
\r
5850 UserAdjudicationEvent( -1 );
\r
5853 case IDM_UserAdjudication_Draw:
\r
5854 UserAdjudicationEvent( 0 );
\r
5857 /* [AS] Game list options dialog */
\r
5858 case IDM_GameListOptions:
\r
5859 GameListOptions();
\r
5862 case IDM_CopyPosition:
\r
5863 CopyFENToClipboard();
\r
5866 case IDM_PastePosition:
\r
5867 PasteFENFromClipboard();
\r
5870 case IDM_MailMove:
\r
5874 case IDM_ReloadCMailMsg:
\r
5875 Reset(TRUE, TRUE);
\r
5876 ReloadCmailMsgEvent(FALSE);
\r
5879 case IDM_Minimize:
\r
5880 ShowWindow(hwnd, SW_MINIMIZE);
\r
5887 case IDM_MachineWhite:
\r
5888 MachineWhiteEvent();
\r
5890 * refresh the tags dialog only if it's visible
\r
5892 if (gameMode == MachinePlaysWhite && IsWindowVisible(editTagsDialog)) {
\r
5894 tags = PGNTags(&gameInfo);
\r
5895 TagsPopUp(tags, CmailMsg());
\r
5898 SAY("computer starts playing white");
\r
5901 case IDM_MachineBlack:
\r
5902 MachineBlackEvent();
\r
5904 * refresh the tags dialog only if it's visible
\r
5906 if (gameMode == MachinePlaysBlack && IsWindowVisible(editTagsDialog)) {
\r
5908 tags = PGNTags(&gameInfo);
\r
5909 TagsPopUp(tags, CmailMsg());
\r
5912 SAY("computer starts playing black");
\r
5915 case IDM_TwoMachines:
\r
5916 TwoMachinesEvent();
\r
5918 * refresh the tags dialog only if it's visible
\r
5920 if (gameMode == TwoMachinesPlay && IsWindowVisible(editTagsDialog)) {
\r
5922 tags = PGNTags(&gameInfo);
\r
5923 TagsPopUp(tags, CmailMsg());
\r
5926 SAY("programs start playing each other");
\r
5929 case IDM_AnalysisMode:
\r
5930 if (!first.analysisSupport) {
\r
5931 sprintf(buf, "%s does not support analysis", first.tidy);
\r
5932 DisplayError(buf, 0);
\r
5934 SAY("analyzing current position");
\r
5935 /* [DM] icsEngineAnlyze [HGM] Why is this front-end??? */
\r
5936 if (appData.icsActive) {
\r
5937 if (gameMode != IcsObserving) {
\r
5938 sprintf(buf, "You are not observing a game");
\r
5939 DisplayError(buf, 0);
\r
5940 /* secure check */
\r
5941 if (appData.icsEngineAnalyze) {
\r
5942 if (appData.debugMode)
\r
5943 fprintf(debugFP, "Found unexpected active ICS engine analyze \n");
\r
5944 ExitAnalyzeMode();
\r
5950 /* if enable, user want disable icsEngineAnalyze */
\r
5951 if (appData.icsEngineAnalyze) {
\r
5952 ExitAnalyzeMode();
\r
5956 appData.icsEngineAnalyze = TRUE;
\r
5957 if (appData.debugMode) fprintf(debugFP, "ICS engine analyze starting...\n");
\r
5960 if (!appData.showThinking) ToggleShowThinking();
\r
5961 AnalyzeModeEvent();
\r
5965 case IDM_AnalyzeFile:
\r
5966 if (!first.analysisSupport) {
\r
5967 char buf[MSG_SIZ];
\r
5968 sprintf(buf, "%s does not support analysis", first.tidy);
\r
5969 DisplayError(buf, 0);
\r
5971 if (!appData.showThinking) ToggleShowThinking();
\r
5972 AnalyzeFileEvent();
\r
5973 LoadGameDialog(hwnd, "Analyze Game from File");
\r
5974 AnalysisPeriodicEvent(1);
\r
5978 case IDM_IcsClient:
\r
5982 case IDM_EditGame:
\r
5987 case IDM_EditPosition:
\r
5988 EditPositionEvent();
\r
5989 SAY("to set up a position type a FEN");
\r
5992 case IDM_Training:
\r
5996 case IDM_ShowGameList:
\r
5997 ShowGameListProc();
\r
6000 case IDM_EditTags:
\r
6004 case IDM_EditComment:
\r
6005 if (commentDialogUp && editComment) {
\r
6008 EditCommentEvent();
\r
6028 case IDM_CallFlag:
\r
6048 case IDM_StopObserving:
\r
6049 StopObservingEvent();
\r
6052 case IDM_StopExamining:
\r
6053 StopExaminingEvent();
\r
6056 case IDM_TypeInMove:
\r
6057 PopUpMoveDialog('\000');
\r
6060 case IDM_TypeInName:
\r
6061 PopUpNameDialog('\000');
\r
6064 case IDM_Backward:
\r
6066 SetFocus(hwndMain);
\r
6073 SetFocus(hwndMain);
\r
6078 SetFocus(hwndMain);
\r
6083 SetFocus(hwndMain);
\r
6090 case IDM_TruncateGame:
\r
6091 TruncateGameEvent();
\r
6098 case IDM_RetractMove:
\r
6099 RetractMoveEvent();
\r
6102 case IDM_FlipView:
\r
6103 flipView = !flipView;
\r
6104 DrawPosition(FALSE, NULL);
\r
6107 case IDM_FlipClock:
\r
6108 flipClock = !flipClock;
\r
6109 DisplayBothClocks();
\r
6110 DrawPosition(FALSE, NULL);
\r
6113 case IDM_GeneralOptions:
\r
6114 GeneralOptionsPopup(hwnd);
\r
6115 DrawPosition(TRUE, NULL);
\r
6118 case IDM_BoardOptions:
\r
6119 BoardOptionsPopup(hwnd);
\r
6122 case IDM_EnginePlayOptions:
\r
6123 EnginePlayOptionsPopup(hwnd);
\r
6126 case IDM_OptionsUCI:
\r
6127 UciOptionsPopup(hwnd);
\r
6130 case IDM_IcsOptions:
\r
6131 IcsOptionsPopup(hwnd);
\r
6135 FontsOptionsPopup(hwnd);
\r
6139 SoundOptionsPopup(hwnd);
\r
6142 case IDM_CommPort:
\r
6143 CommPortOptionsPopup(hwnd);
\r
6146 case IDM_LoadOptions:
\r
6147 LoadOptionsPopup(hwnd);
\r
6150 case IDM_SaveOptions:
\r
6151 SaveOptionsPopup(hwnd);
\r
6154 case IDM_TimeControl:
\r
6155 TimeControlOptionsPopup(hwnd);
\r
6158 case IDM_SaveSettings:
\r
6159 SaveSettings(settingsFileName);
\r
6162 case IDM_SaveSettingsOnExit:
\r
6163 saveSettingsOnExit = !saveSettingsOnExit;
\r
6164 (void) CheckMenuItem(GetMenu(hwndMain), IDM_SaveSettingsOnExit,
\r
6165 MF_BYCOMMAND|(saveSettingsOnExit ?
\r
6166 MF_CHECKED : MF_UNCHECKED));
\r
6177 case IDM_AboutGame:
\r
6182 appData.debugMode = !appData.debugMode;
\r
6183 if (appData.debugMode) {
\r
6184 char dir[MSG_SIZ];
\r
6185 GetCurrentDirectory(MSG_SIZ, dir);
\r
6186 SetCurrentDirectory(installDir);
\r
6187 debugFP = fopen(appData.nameOfDebugFile, "w");
\r
6188 SetCurrentDirectory(dir);
\r
6189 setbuf(debugFP, NULL);
\r
6196 case IDM_HELPCONTENTS:
\r
6197 if (!MyHelp (hwnd, "winboard.hlp", HELP_KEY,(DWORD)(LPSTR)"CONTENTS") &&
\r
6198 !HtmlHelp(hwnd, "winboard.chm", 0, 0) ) {
\r
6199 MessageBox (GetFocus(),
\r
6200 "Unable to activate help",
\r
6201 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
6205 case IDM_HELPSEARCH:
\r
6206 if (!MyHelp (hwnd, "winboard.hlp", HELP_PARTIALKEY, (DWORD)(LPSTR)"") &&
\r
6207 !HtmlHelp(hwnd, "winboard.chm", 0, 0) ) {
\r
6208 MessageBox (GetFocus(),
\r
6209 "Unable to activate help",
\r
6210 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
6214 case IDM_HELPHELP:
\r
6215 if(!WinHelp(hwnd, (LPSTR)NULL, HELP_HELPONHELP, 0)) {
\r
6216 MessageBox (GetFocus(),
\r
6217 "Unable to activate help",
\r
6218 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
6223 lpProc = MakeProcInstance((FARPROC)About, hInst);
\r
6225 (gameInfo.event && strcmp(gameInfo.event, "Easter Egg Hunt") == 0) ?
\r
6226 "AboutBox2" : "AboutBox", hwnd, (DLGPROC)lpProc);
\r
6227 FreeProcInstance(lpProc);
\r
6230 case IDM_DirectCommand1:
\r
6231 AskQuestionEvent("Direct Command",
\r
6232 "Send to chess program:", "", "1");
\r
6234 case IDM_DirectCommand2:
\r
6235 AskQuestionEvent("Direct Command",
\r
6236 "Send to second chess program:", "", "2");
\r
6239 case EP_WhitePawn:
\r
6240 EditPositionMenuEvent(WhitePawn, fromX, fromY);
\r
6241 fromX = fromY = -1;
\r
6244 case EP_WhiteKnight:
\r
6245 EditPositionMenuEvent(WhiteKnight, fromX, fromY);
\r
6246 fromX = fromY = -1;
\r
6249 case EP_WhiteBishop:
\r
6250 EditPositionMenuEvent(WhiteBishop, fromX, fromY);
\r
6251 fromX = fromY = -1;
\r
6254 case EP_WhiteRook:
\r
6255 EditPositionMenuEvent(WhiteRook, fromX, fromY);
\r
6256 fromX = fromY = -1;
\r
6259 case EP_WhiteQueen:
\r
6260 EditPositionMenuEvent(WhiteQueen, fromX, fromY);
\r
6261 fromX = fromY = -1;
\r
6264 case EP_WhiteFerz:
\r
6265 EditPositionMenuEvent(WhiteFerz, fromX, fromY);
\r
6266 fromX = fromY = -1;
\r
6269 case EP_WhiteWazir:
\r
6270 EditPositionMenuEvent(WhiteWazir, fromX, fromY);
\r
6271 fromX = fromY = -1;
\r
6274 case EP_WhiteAlfil:
\r
6275 EditPositionMenuEvent(WhiteAlfil, fromX, fromY);
\r
6276 fromX = fromY = -1;
\r
6279 case EP_WhiteCannon:
\r
6280 EditPositionMenuEvent(WhiteCannon, fromX, fromY);
\r
6281 fromX = fromY = -1;
\r
6284 case EP_WhiteCardinal:
\r
6285 EditPositionMenuEvent(WhiteAngel, fromX, fromY);
\r
6286 fromX = fromY = -1;
\r
6289 case EP_WhiteMarshall:
\r
6290 EditPositionMenuEvent(WhiteMarshall, fromX, fromY);
\r
6291 fromX = fromY = -1;
\r
6294 case EP_WhiteKing:
\r
6295 EditPositionMenuEvent(WhiteKing, fromX, fromY);
\r
6296 fromX = fromY = -1;
\r
6299 case EP_BlackPawn:
\r
6300 EditPositionMenuEvent(BlackPawn, fromX, fromY);
\r
6301 fromX = fromY = -1;
\r
6304 case EP_BlackKnight:
\r
6305 EditPositionMenuEvent(BlackKnight, fromX, fromY);
\r
6306 fromX = fromY = -1;
\r
6309 case EP_BlackBishop:
\r
6310 EditPositionMenuEvent(BlackBishop, fromX, fromY);
\r
6311 fromX = fromY = -1;
\r
6314 case EP_BlackRook:
\r
6315 EditPositionMenuEvent(BlackRook, fromX, fromY);
\r
6316 fromX = fromY = -1;
\r
6319 case EP_BlackQueen:
\r
6320 EditPositionMenuEvent(BlackQueen, fromX, fromY);
\r
6321 fromX = fromY = -1;
\r
6324 case EP_BlackFerz:
\r
6325 EditPositionMenuEvent(BlackFerz, fromX, fromY);
\r
6326 fromX = fromY = -1;
\r
6329 case EP_BlackWazir:
\r
6330 EditPositionMenuEvent(BlackWazir, fromX, fromY);
\r
6331 fromX = fromY = -1;
\r
6334 case EP_BlackAlfil:
\r
6335 EditPositionMenuEvent(BlackAlfil, fromX, fromY);
\r
6336 fromX = fromY = -1;
\r
6339 case EP_BlackCannon:
\r
6340 EditPositionMenuEvent(BlackCannon, fromX, fromY);
\r
6341 fromX = fromY = -1;
\r
6344 case EP_BlackCardinal:
\r
6345 EditPositionMenuEvent(BlackAngel, fromX, fromY);
\r
6346 fromX = fromY = -1;
\r
6349 case EP_BlackMarshall:
\r
6350 EditPositionMenuEvent(BlackMarshall, fromX, fromY);
\r
6351 fromX = fromY = -1;
\r
6354 case EP_BlackKing:
\r
6355 EditPositionMenuEvent(BlackKing, fromX, fromY);
\r
6356 fromX = fromY = -1;
\r
6359 case EP_EmptySquare:
\r
6360 EditPositionMenuEvent(EmptySquare, fromX, fromY);
\r
6361 fromX = fromY = -1;
\r
6364 case EP_ClearBoard:
\r
6365 EditPositionMenuEvent(ClearBoard, fromX, fromY);
\r
6366 fromX = fromY = -1;
\r
6370 EditPositionMenuEvent(WhitePlay, fromX, fromY);
\r
6371 fromX = fromY = -1;
\r
6375 EditPositionMenuEvent(BlackPlay, fromX, fromY);
\r
6376 fromX = fromY = -1;
\r
6380 EditPositionMenuEvent(PromotePiece, fromX, fromY);
\r
6381 fromX = fromY = -1;
\r
6385 EditPositionMenuEvent(DemotePiece, fromX, fromY);
\r
6386 fromX = fromY = -1;
\r
6390 DropMenuEvent(WhitePawn, fromX, fromY);
\r
6391 fromX = fromY = -1;
\r
6395 DropMenuEvent(WhiteKnight, fromX, fromY);
\r
6396 fromX = fromY = -1;
\r
6400 DropMenuEvent(WhiteBishop, fromX, fromY);
\r
6401 fromX = fromY = -1;
\r
6405 DropMenuEvent(WhiteRook, fromX, fromY);
\r
6406 fromX = fromY = -1;
\r
6410 DropMenuEvent(WhiteQueen, fromX, fromY);
\r
6411 fromX = fromY = -1;
\r
6415 return (DefWindowProc(hwnd, message, wParam, lParam));
\r
6421 case CLOCK_TIMER_ID:
\r
6422 KillTimer(hwnd, clockTimerEvent); /* Simulate one-shot timer as in X */
\r
6423 clockTimerEvent = 0;
\r
6424 DecrementClocks(); /* call into back end */
\r
6426 case LOAD_GAME_TIMER_ID:
\r
6427 KillTimer(hwnd, loadGameTimerEvent); /* Simulate one-shot timer as in X*/
\r
6428 loadGameTimerEvent = 0;
\r
6429 AutoPlayGameLoop(); /* call into back end */
\r
6431 case ANALYSIS_TIMER_ID:
\r
6432 if ((gameMode == AnalyzeMode || gameMode == AnalyzeFile
\r
6433 || appData.icsEngineAnalyze) && appData.periodicUpdates) {
\r
6434 AnalysisPeriodicEvent(0);
\r
6436 KillTimer(hwnd, analysisTimerEvent);
\r
6437 analysisTimerEvent = 0;
\r
6440 case DELAYED_TIMER_ID:
\r
6441 KillTimer(hwnd, delayedTimerEvent);
\r
6442 delayedTimerEvent = 0;
\r
6443 delayedTimerCallback();
\r
6448 case WM_USER_Input:
\r
6449 InputEvent(hwnd, message, wParam, lParam);
\r
6452 /* [AS] Also move "attached" child windows */
\r
6453 case WM_WINDOWPOSCHANGING:
\r
6455 if( hwnd == hwndMain && appData.useStickyWindows ) {
\r
6456 LPWINDOWPOS lpwp = (LPWINDOWPOS) lParam;
\r
6458 if( ((lpwp->flags & SWP_NOMOVE) == 0) && ((lpwp->flags & SWP_NOSIZE) != 0) ) {
\r
6459 /* Window is moving */
\r
6462 // GetWindowRect( hwnd, &rcMain ); //[HGM] sticky: in XP this returned new position, not old
\r
6463 rcMain.left = boardX; // replace by these 4 lines to reconstruct old rect
\r
6464 rcMain.right = boardX + winWidth;
\r
6465 rcMain.top = boardY;
\r
6466 rcMain.bottom = boardY + winHeight;
\r
6468 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, moveHistoryDialog, &wpMoveHistory );
\r
6469 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, evalGraphDialog, &wpEvalGraph );
\r
6470 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, engineOutputDialog, &wpEngineOutput );
\r
6471 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, gameListDialog, &wpGameList );
\r
6472 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, hwndConsole, &wpConsole );
\r
6479 /* [AS] Snapping */
\r
6480 case WM_ENTERSIZEMOVE:
\r
6481 if(appData.debugMode) { fprintf(debugFP, "size-move\n"); }
\r
6482 if (hwnd == hwndMain) {
\r
6483 doingSizing = TRUE;
\r
6486 return OnEnterSizeMove( &sd, hwnd, wParam, lParam );
\r
6490 if(appData.debugMode) { fprintf(debugFP, "sizing\n"); }
\r
6491 if (hwnd == hwndMain) {
\r
6492 lastSizing = wParam;
\r
6497 if(appData.debugMode) { fprintf(debugFP, "moving\n"); }
\r
6498 return OnMoving( &sd, hwnd, wParam, lParam );
\r
6500 case WM_EXITSIZEMOVE:
\r
6501 if(appData.debugMode) { fprintf(debugFP, "exit size-move, size = %d\n", squareSize); }
\r
6502 if (hwnd == hwndMain) {
\r
6504 doingSizing = FALSE;
\r
6505 InvalidateRect(hwnd, &boardRect, FALSE);
\r
6506 GetClientRect(hwnd, &client);
\r
6507 ResizeBoard(client.right, client.bottom, lastSizing);
\r
6509 if(appData.debugMode) { fprintf(debugFP, "square size = %d\n", squareSize); }
\r
6511 return OnExitSizeMove( &sd, hwnd, wParam, lParam );
\r
6514 case WM_DESTROY: /* message: window being destroyed */
\r
6515 PostQuitMessage(0);
\r
6519 if (hwnd == hwndMain) {
\r
6524 default: /* Passes it on if unprocessed */
\r
6525 return (DefWindowProc(hwnd, message, wParam, lParam));
\r
6530 /*---------------------------------------------------------------------------*\
\r
6532 * Misc utility routines
\r
6534 \*---------------------------------------------------------------------------*/
\r
6537 * Decent random number generator, at least not as bad as Windows
\r
6538 * standard rand, which returns a value in the range 0 to 0x7fff.
\r
6540 unsigned int randstate;
\r
6545 randstate = randstate * 1664525 + 1013904223;
\r
6546 return (int) randstate & 0x7fffffff;
\r
6550 mysrandom(unsigned int seed)
\r
6557 * returns TRUE if user selects a different color, FALSE otherwise
\r
6561 ChangeColor(HWND hwnd, COLORREF *which)
\r
6563 static BOOL firstTime = TRUE;
\r
6564 static DWORD customColors[16];
\r
6566 COLORREF newcolor;
\r
6571 /* Make initial colors in use available as custom colors */
\r
6572 /* Should we put the compiled-in defaults here instead? */
\r
6574 customColors[i++] = lightSquareColor & 0xffffff;
\r
6575 customColors[i++] = darkSquareColor & 0xffffff;
\r
6576 customColors[i++] = whitePieceColor & 0xffffff;
\r
6577 customColors[i++] = blackPieceColor & 0xffffff;
\r
6578 customColors[i++] = highlightSquareColor & 0xffffff;
\r
6579 customColors[i++] = premoveHighlightColor & 0xffffff;
\r
6581 for (ccl = (ColorClass) 0; ccl < NColorClasses && i < 16; ccl++) {
\r
6582 customColors[i++] = textAttribs[ccl].color;
\r
6584 while (i < 16) customColors[i++] = RGB(255, 255, 255);
\r
6585 firstTime = FALSE;
\r
6588 cc.lStructSize = sizeof(cc);
\r
6589 cc.hwndOwner = hwnd;
\r
6590 cc.hInstance = NULL;
\r
6591 cc.rgbResult = (DWORD) (*which & 0xffffff);
\r
6592 cc.lpCustColors = (LPDWORD) customColors;
\r
6593 cc.Flags = CC_RGBINIT|CC_FULLOPEN;
\r
6595 if (!ChooseColor(&cc)) return FALSE;
\r
6597 newcolor = (COLORREF) (0x2000000 | cc.rgbResult);
\r
6598 if (newcolor == *which) return FALSE;
\r
6599 *which = newcolor;
\r
6603 InitDrawingColors();
\r
6604 InvalidateRect(hwnd, &boardRect, FALSE);
\r
6609 MyLoadSound(MySound *ms)
\r
6615 if (ms->data) free(ms->data);
\r
6618 switch (ms->name[0]) {
\r
6624 /* System sound from Control Panel. Don't preload here. */
\r
6628 if (ms->name[1] == NULLCHAR) {
\r
6629 /* "!" alone = silence */
\r
6632 /* Builtin wave resource. Error if not found. */
\r
6633 HANDLE h = FindResource(hInst, ms->name + 1, "WAVE");
\r
6634 if (h == NULL) break;
\r
6635 ms->data = (void *)LoadResource(hInst, h);
\r
6636 if (h == NULL) break;
\r
6641 /* .wav file. Error if not found. */
\r
6642 f = fopen(ms->name, "rb");
\r
6643 if (f == NULL) break;
\r
6644 if (fstat(fileno(f), &st) < 0) break;
\r
6645 ms->data = malloc(st.st_size);
\r
6646 if (fread(ms->data, st.st_size, 1, f) < 1) break;
\r
6652 char buf[MSG_SIZ];
\r
6653 sprintf(buf, "Error loading sound %s", ms->name);
\r
6654 DisplayError(buf, GetLastError());
\r
6660 MyPlaySound(MySound *ms)
\r
6662 BOOLEAN ok = FALSE;
\r
6663 if(appData.debugMode) fprintf(debugFP, "make sound %s %x %d\n", ms->name, ms, ms->name[0]);
\r
6664 switch (ms->name[0]) {
\r
6666 if(appData.debugMode) fprintf(debugFP, "silence\n");
\r
6671 /* System sound from Control Panel (deprecated feature).
\r
6672 "$" alone or an unset sound name gets default beep (still in use). */
\r
6673 if (ms->name[1]) {
\r
6674 ok = PlaySound(ms->name + 1, NULL, SND_ALIAS|SND_ASYNC);
\r
6676 if (!ok) ok = MessageBeep(MB_OK);
\r
6679 /* Builtin wave resource, or "!" alone for silence */
\r
6680 if (ms->name[1]) {
\r
6681 if (ms->data == NULL) return FALSE;
\r
6682 ok = PlaySound(ms->data, NULL, SND_MEMORY|SND_ASYNC);
\r
6688 /* .wav file. Error if not found. */
\r
6689 if (ms->data == NULL) return FALSE;
\r
6690 ok = PlaySound(ms->data, NULL, SND_MEMORY|SND_ASYNC);
\r
6693 /* Don't print an error: this can happen innocently if the sound driver
\r
6694 is busy; for instance, if another instance of WinBoard is playing
\r
6695 a sound at about the same time. */
\r
6698 char buf[MSG_SIZ];
\r
6699 sprintf(buf, "Error playing sound %s", ms->name);
\r
6700 DisplayError(buf, GetLastError());
\r
6708 OldOpenFileHook(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
6711 OPENFILENAME *ofn;
\r
6712 static UINT *number; /* gross that this is static */
\r
6714 switch (message) {
\r
6715 case WM_INITDIALOG: /* message: initialize dialog box */
\r
6716 /* Center the dialog over the application window */
\r
6717 ofn = (OPENFILENAME *) lParam;
\r
6718 if (ofn->Flags & OFN_ENABLETEMPLATE) {
\r
6719 number = (UINT *) ofn->lCustData;
\r
6720 SendMessage(GetDlgItem(hDlg, edt2), WM_SETTEXT, 0, (LPARAM) "");
\r
6724 CenterWindow (hDlg, GetWindow (hDlg, GW_OWNER));
\r
6725 return FALSE; /* Allow for further processing */
\r
6728 if ((LOWORD(wParam) == IDOK) && (number != NULL)) {
\r
6729 *number = GetDlgItemInt(hDlg, OPT_IndexNumberOld, &ok, FALSE);
\r
6731 return FALSE; /* Allow for further processing */
\r
6737 OpenFileHook(HWND hdlg, UINT uiMsg, WPARAM wParam, LPARAM lParam)
\r
6739 static UINT *number;
\r
6740 OPENFILENAME *ofname;
\r
6743 case WM_INITDIALOG:
\r
6744 ofname = (OPENFILENAME *)lParam;
\r
6745 number = (UINT *)(ofname->lCustData);
\r
6748 ofnot = (OFNOTIFY *)lParam;
\r
6749 if (ofnot->hdr.code == CDN_FILEOK) {
\r
6750 *number = GetDlgItemInt(hdlg, OPT_IndexNumber, NULL, FALSE);
\r
6759 OpenFileDialog(HWND hwnd, char *write, char *defName, char *defExt, // [HGM] diag: type of 'write' now string
\r
6760 char *nameFilt, char *dlgTitle, UINT *number,
\r
6761 char fileTitle[MSG_SIZ], char fileName[MSG_SIZ])
\r
6763 OPENFILENAME openFileName;
\r
6764 char buf1[MSG_SIZ];
\r
6767 if (fileName == NULL) fileName = buf1;
\r
6768 if (defName == NULL) {
\r
6769 strcpy(fileName, "*.");
\r
6770 strcat(fileName, defExt);
\r
6772 strcpy(fileName, defName);
\r
6774 if (fileTitle) strcpy(fileTitle, "");
\r
6775 if (number) *number = 0;
\r
6777 openFileName.lStructSize = sizeof(OPENFILENAME);
\r
6778 openFileName.hwndOwner = hwnd;
\r
6779 openFileName.hInstance = (HANDLE) hInst;
\r
6780 openFileName.lpstrFilter = nameFilt;
\r
6781 openFileName.lpstrCustomFilter = (LPSTR) NULL;
\r
6782 openFileName.nMaxCustFilter = 0L;
\r
6783 openFileName.nFilterIndex = 1L;
\r
6784 openFileName.lpstrFile = fileName;
\r
6785 openFileName.nMaxFile = MSG_SIZ;
\r
6786 openFileName.lpstrFileTitle = fileTitle;
\r
6787 openFileName.nMaxFileTitle = fileTitle ? MSG_SIZ : 0;
\r
6788 openFileName.lpstrInitialDir = NULL;
\r
6789 openFileName.lpstrTitle = dlgTitle;
\r
6790 openFileName.Flags = OFN_PATHMUSTEXIST | OFN_HIDEREADONLY
\r
6791 | (write[0] != 'r' ? 0 : OFN_FILEMUSTEXIST)
\r
6792 | (number ? OFN_ENABLETEMPLATE | OFN_ENABLEHOOK: 0)
\r
6793 | (oldDialog ? 0 : OFN_EXPLORER);
\r
6794 openFileName.nFileOffset = 0;
\r
6795 openFileName.nFileExtension = 0;
\r
6796 openFileName.lpstrDefExt = defExt;
\r
6797 openFileName.lCustData = (LONG) number;
\r
6798 openFileName.lpfnHook = oldDialog ?
\r
6799 (LPOFNHOOKPROC) OldOpenFileHook : (LPOFNHOOKPROC) OpenFileHook;
\r
6800 openFileName.lpTemplateName = (LPSTR)(oldDialog ? 1536 : DLG_IndexNumber);
\r
6802 if (write[0] != 'r' ? GetSaveFileName(&openFileName) :
\r
6803 GetOpenFileName(&openFileName)) {
\r
6804 /* open the file */
\r
6805 f = fopen(openFileName.lpstrFile, write);
\r
6807 MessageBox(hwnd, "File open failed", NULL,
\r
6808 MB_OK|MB_ICONEXCLAMATION);
\r
6812 int err = CommDlgExtendedError();
\r
6813 if (err != 0) DisplayError("Internal error in file dialog box", err);
\r
6822 MenuPopup(HWND hwnd, POINT pt, HMENU hmenu, UINT def)
\r
6824 HMENU hmenuTrackPopup; /* floating pop-up menu */
\r
6827 * Get the first pop-up menu in the menu template. This is the
\r
6828 * menu that TrackPopupMenu displays.
\r
6830 hmenuTrackPopup = GetSubMenu(hmenu, 0);
\r
6832 SetMenuDefaultItem(hmenuTrackPopup, def, FALSE);
\r
6835 * TrackPopup uses screen coordinates, so convert the
\r
6836 * coordinates of the mouse click to screen coordinates.
\r
6838 ClientToScreen(hwnd, (LPPOINT) &pt);
\r
6840 /* Draw and track the floating pop-up menu. */
\r
6841 TrackPopupMenu(hmenuTrackPopup, TPM_CENTERALIGN | TPM_RIGHTBUTTON,
\r
6842 pt.x, pt.y, 0, hwnd, NULL);
\r
6844 /* Destroy the menu.*/
\r
6845 DestroyMenu(hmenu);
\r
6850 int sizeX, sizeY, newSizeX, newSizeY;
\r
6852 } ResizeEditPlusButtonsClosure;
\r
6855 ResizeEditPlusButtonsCallback(HWND hChild, LPARAM lparam)
\r
6857 ResizeEditPlusButtonsClosure *cl = (ResizeEditPlusButtonsClosure *)lparam;
\r
6861 if (hChild == cl->hText) return TRUE;
\r
6862 GetWindowRect(hChild, &rect); /* gives screen coords */
\r
6863 pt.x = rect.left + (cl->newSizeX - cl->sizeX)/2;
\r
6864 pt.y = rect.top + cl->newSizeY - cl->sizeY;
\r
6865 ScreenToClient(cl->hDlg, &pt);
\r
6866 cl->hdwp = DeferWindowPos(cl->hdwp, hChild, NULL,
\r
6867 pt.x, pt.y, rect.right - rect.left, rect.bottom - rect.top, SWP_NOZORDER);
\r
6871 /* Resize a dialog that has a (rich) edit field filling most of
\r
6872 the top, with a row of buttons below */
\r
6874 ResizeEditPlusButtons(HWND hDlg, HWND hText, int sizeX, int sizeY, int newSizeX, int newSizeY)
\r
6877 int newTextHeight, newTextWidth;
\r
6878 ResizeEditPlusButtonsClosure cl;
\r
6880 /*if (IsIconic(hDlg)) return;*/
\r
6881 if (newSizeX == sizeX && newSizeY == sizeY) return;
\r
6883 cl.hdwp = BeginDeferWindowPos(8);
\r
6885 GetWindowRect(hText, &rectText); /* gives screen coords */
\r
6886 newTextWidth = rectText.right - rectText.left + newSizeX - sizeX;
\r
6887 newTextHeight = rectText.bottom - rectText.top + newSizeY - sizeY;
\r
6888 if (newTextHeight < 0) {
\r
6889 newSizeY += -newTextHeight;
\r
6890 newTextHeight = 0;
\r
6892 cl.hdwp = DeferWindowPos(cl.hdwp, hText, NULL, 0, 0,
\r
6893 newTextWidth, newTextHeight, SWP_NOZORDER|SWP_NOMOVE);
\r
6899 cl.newSizeX = newSizeX;
\r
6900 cl.newSizeY = newSizeY;
\r
6901 EnumChildWindows(hDlg, ResizeEditPlusButtonsCallback, (LPARAM)&cl);
\r
6903 EndDeferWindowPos(cl.hdwp);
\r
6906 BOOL CenterWindowEx(HWND hwndChild, HWND hwndParent, int mode)
\r
6908 RECT rChild, rParent;
\r
6909 int wChild, hChild, wParent, hParent;
\r
6910 int wScreen, hScreen, xNew, yNew;
\r
6913 /* Get the Height and Width of the child window */
\r
6914 GetWindowRect (hwndChild, &rChild);
\r
6915 wChild = rChild.right - rChild.left;
\r
6916 hChild = rChild.bottom - rChild.top;
\r
6918 /* Get the Height and Width of the parent window */
\r
6919 GetWindowRect (hwndParent, &rParent);
\r
6920 wParent = rParent.right - rParent.left;
\r
6921 hParent = rParent.bottom - rParent.top;
\r
6923 /* Get the display limits */
\r
6924 hdc = GetDC (hwndChild);
\r
6925 wScreen = GetDeviceCaps (hdc, HORZRES);
\r
6926 hScreen = GetDeviceCaps (hdc, VERTRES);
\r
6927 ReleaseDC(hwndChild, hdc);
\r
6929 /* Calculate new X position, then adjust for screen */
\r
6930 xNew = rParent.left + ((wParent - wChild) /2);
\r
6933 } else if ((xNew+wChild) > wScreen) {
\r
6934 xNew = wScreen - wChild;
\r
6937 /* Calculate new Y position, then adjust for screen */
\r
6939 yNew = rParent.top + ((hParent - hChild) /2);
\r
6942 yNew = rParent.top + GetSystemMetrics( SM_CYCAPTION ) * 2 / 3;
\r
6947 } else if ((yNew+hChild) > hScreen) {
\r
6948 yNew = hScreen - hChild;
\r
6951 /* Set it, and return */
\r
6952 return SetWindowPos (hwndChild, NULL,
\r
6953 xNew, yNew, 0, 0, SWP_NOSIZE | SWP_NOZORDER);
\r
6956 /* Center one window over another */
\r
6957 BOOL CenterWindow (HWND hwndChild, HWND hwndParent)
\r
6959 return CenterWindowEx( hwndChild, hwndParent, 0 );
\r
6962 /*---------------------------------------------------------------------------*\
\r
6964 * Startup Dialog functions
\r
6966 \*---------------------------------------------------------------------------*/
\r
6968 InitComboStrings(HANDLE hwndCombo, char **cd)
\r
6970 SendMessage(hwndCombo, CB_RESETCONTENT, 0, 0);
\r
6972 while (*cd != NULL) {
\r
6973 SendMessage(hwndCombo, CB_ADDSTRING, 0, (LPARAM) *cd);
\r
6979 InitComboStringsFromOption(HANDLE hwndCombo, char *str)
\r
6981 char buf1[ARG_MAX];
\r
6984 if (str[0] == '@') {
\r
6985 FILE* f = fopen(str + 1, "r");
\r
6987 DisplayFatalError(str + 1, errno, 2);
\r
6990 len = fread(buf1, 1, sizeof(buf1)-1, f);
\r
6992 buf1[len] = NULLCHAR;
\r
6996 SendMessage(hwndCombo, CB_RESETCONTENT, 0, 0);
\r
6999 char buf[MSG_SIZ];
\r
7000 char *end = strchr(str, '\n');
\r
7001 if (end == NULL) return;
\r
7002 memcpy(buf, str, end - str);
\r
7003 buf[end - str] = NULLCHAR;
\r
7004 SendMessage(hwndCombo, CB_ADDSTRING, 0, (LPARAM) buf);
\r
7010 SetStartupDialogEnables(HWND hDlg)
\r
7012 EnableWindow(GetDlgItem(hDlg, OPT_ChessEngineName),
\r
7013 IsDlgButtonChecked(hDlg, OPT_ChessEngine) ||
\r
7014 (appData.zippyPlay && IsDlgButtonChecked(hDlg, OPT_ChessServer)));
\r
7015 EnableWindow(GetDlgItem(hDlg, OPT_SecondChessEngineName),
\r
7016 IsDlgButtonChecked(hDlg, OPT_ChessEngine));
\r
7017 EnableWindow(GetDlgItem(hDlg, OPT_ChessServerName),
\r
7018 IsDlgButtonChecked(hDlg, OPT_ChessServer));
\r
7019 EnableWindow(GetDlgItem(hDlg, OPT_AdditionalOptions),
\r
7020 IsDlgButtonChecked(hDlg, OPT_AnyAdditional));
\r
7021 EnableWindow(GetDlgItem(hDlg, IDOK),
\r
7022 IsDlgButtonChecked(hDlg, OPT_ChessEngine) ||
\r
7023 IsDlgButtonChecked(hDlg, OPT_ChessServer) ||
\r
7024 IsDlgButtonChecked(hDlg, OPT_View));
\r
7028 QuoteForFilename(char *filename)
\r
7030 int dquote, space;
\r
7031 dquote = strchr(filename, '"') != NULL;
\r
7032 space = strchr(filename, ' ') != NULL;
\r
7033 if (dquote || space) {
\r
7045 InitEngineBox(HWND hDlg, HWND hwndCombo, char* nthcp, char* nthd, char* nthdir, char *nthnames)
\r
7047 char buf[MSG_SIZ];
\r
7050 InitComboStringsFromOption(hwndCombo, nthnames);
\r
7051 q = QuoteForFilename(nthcp);
\r
7052 sprintf(buf, "%s%s%s", q, nthcp, q);
\r
7053 if (*nthdir != NULLCHAR) {
\r
7054 q = QuoteForFilename(nthdir);
\r
7055 sprintf(buf + strlen(buf), " /%s=%s%s%s", nthd, q, nthdir, q);
\r
7057 if (*nthcp == NULLCHAR) {
\r
7058 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) 0, (LPARAM) 0);
\r
7059 } else if (SendMessage(hwndCombo, CB_SELECTSTRING, (WPARAM) -1, (LPARAM) buf) == CB_ERR) {
\r
7060 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) -1, (LPARAM) 0);
\r
7061 SendMessage(hwndCombo, WM_SETTEXT, (WPARAM) 0, (LPARAM) buf);
\r
7066 StartupDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7068 char buf[MSG_SIZ];
\r
7072 switch (message) {
\r
7073 case WM_INITDIALOG:
\r
7074 /* Center the dialog */
\r
7075 CenterWindow (hDlg, GetDesktopWindow());
\r
7076 /* Initialize the dialog items */
\r
7077 InitEngineBox(hDlg, GetDlgItem(hDlg, OPT_ChessEngineName),
\r
7078 appData.firstChessProgram, "fd", appData.firstDirectory,
\r
7079 firstChessProgramNames);
\r
7080 InitEngineBox(hDlg, GetDlgItem(hDlg, OPT_SecondChessEngineName),
\r
7081 appData.secondChessProgram, "sd", appData.secondDirectory,
\r
7082 secondChessProgramNames);
\r
7083 hwndCombo = GetDlgItem(hDlg, OPT_ChessServerName);
\r
7084 InitComboStringsFromOption(hwndCombo, icsNames);
\r
7085 sprintf(buf, "%s /icsport=%s", appData.icsHost, appData.icsPort);
\r
7086 if (*appData.icsHelper != NULLCHAR) {
\r
7087 char *q = QuoteForFilename(appData.icsHelper);
\r
7088 sprintf(buf + strlen(buf), " /icshelper=%s%s%s", q, appData.icsHelper, q);
\r
7090 if (*appData.icsHost == NULLCHAR) {
\r
7091 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) 0, (LPARAM) 0);
\r
7092 /*SendMessage(hwndCombo, CB_SHOWDROPDOWN, (WPARAM) TRUE, (LPARAM) 0); !!too soon */
\r
7093 } else if (SendMessage(hwndCombo, CB_SELECTSTRING, (WPARAM) -1, (LPARAM) buf) == CB_ERR) {
\r
7094 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) -1, (LPARAM) 0);
\r
7095 SendMessage(hwndCombo, WM_SETTEXT, (WPARAM) 0, (LPARAM) buf);
\r
7098 if (appData.icsActive) {
\r
7099 CheckDlgButton(hDlg, OPT_ChessServer, BST_CHECKED);
\r
7101 else if (appData.noChessProgram) {
\r
7102 CheckDlgButton(hDlg, OPT_View, BST_CHECKED);
\r
7105 CheckDlgButton(hDlg, OPT_ChessEngine, BST_CHECKED);
\r
7108 SetStartupDialogEnables(hDlg);
\r
7112 switch (LOWORD(wParam)) {
\r
7114 if (IsDlgButtonChecked(hDlg, OPT_ChessEngine)) {
\r
7115 strcpy(buf, "/fcp=");
\r
7116 GetDlgItemText(hDlg, OPT_ChessEngineName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
7118 ParseArgs(StringGet, &p);
\r
7119 strcpy(buf, "/scp=");
\r
7120 GetDlgItemText(hDlg, OPT_SecondChessEngineName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
7122 ParseArgs(StringGet, &p);
\r
7123 appData.noChessProgram = FALSE;
\r
7124 appData.icsActive = FALSE;
\r
7125 } else if (IsDlgButtonChecked(hDlg, OPT_ChessServer)) {
\r
7126 strcpy(buf, "/ics /icshost=");
\r
7127 GetDlgItemText(hDlg, OPT_ChessServerName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
7129 ParseArgs(StringGet, &p);
\r
7130 if (appData.zippyPlay) {
\r
7131 strcpy(buf, "/fcp=");
\r
7132 GetDlgItemText(hDlg, OPT_ChessEngineName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
7134 ParseArgs(StringGet, &p);
\r
7136 } else if (IsDlgButtonChecked(hDlg, OPT_View)) {
\r
7137 appData.noChessProgram = TRUE;
\r
7138 appData.icsActive = FALSE;
\r
7140 MessageBox(hDlg, "Choose an option, or cancel to exit",
\r
7141 "Option Error", MB_OK|MB_ICONEXCLAMATION);
\r
7144 if (IsDlgButtonChecked(hDlg, OPT_AnyAdditional)) {
\r
7145 GetDlgItemText(hDlg, OPT_AdditionalOptions, buf, sizeof(buf));
\r
7147 ParseArgs(StringGet, &p);
\r
7149 EndDialog(hDlg, TRUE);
\r
7156 case IDM_HELPCONTENTS:
\r
7157 if (!WinHelp (hDlg, "winboard.hlp", HELP_KEY,(DWORD)(LPSTR)"CONTENTS")) {
\r
7158 MessageBox (GetFocus(),
\r
7159 "Unable to activate help",
\r
7160 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
7165 SetStartupDialogEnables(hDlg);
\r
7173 /*---------------------------------------------------------------------------*\
\r
7175 * About box dialog functions
\r
7177 \*---------------------------------------------------------------------------*/
\r
7179 /* Process messages for "About" dialog box */
\r
7181 About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7183 switch (message) {
\r
7184 case WM_INITDIALOG: /* message: initialize dialog box */
\r
7185 /* Center the dialog over the application window */
\r
7186 CenterWindow (hDlg, GetWindow (hDlg, GW_OWNER));
\r
7187 SetDlgItemText(hDlg, ABOUTBOX_Version, programVersion);
\r
7190 case WM_COMMAND: /* message: received a command */
\r
7191 if (LOWORD(wParam) == IDOK /* "OK" box selected? */
\r
7192 || LOWORD(wParam) == IDCANCEL) { /* System menu close command? */
\r
7193 EndDialog(hDlg, TRUE); /* Exit the dialog */
\r
7201 /*---------------------------------------------------------------------------*\
\r
7203 * Comment Dialog functions
\r
7205 \*---------------------------------------------------------------------------*/
\r
7208 CommentDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7210 static HANDLE hwndText = NULL;
\r
7211 int len, newSizeX, newSizeY, flags;
\r
7212 static int sizeX, sizeY;
\r
7217 switch (message) {
\r
7218 case WM_INITDIALOG: /* message: initialize dialog box */
\r
7219 /* Initialize the dialog items */
\r
7220 hwndText = GetDlgItem(hDlg, OPT_CommentText);
\r
7221 SetDlgItemText(hDlg, OPT_CommentText, commentText);
\r
7222 EnableWindow(GetDlgItem(hDlg, OPT_CancelComment), editComment);
\r
7223 EnableWindow(GetDlgItem(hDlg, OPT_ClearComment), editComment);
\r
7224 EnableWindow(GetDlgItem(hDlg, OPT_EditComment), !editComment);
\r
7225 SendMessage(hwndText, EM_SETREADONLY, !editComment, 0);
\r
7226 SetWindowText(hDlg, commentTitle);
\r
7227 if (editComment) {
\r
7228 SetFocus(hwndText);
\r
7230 SetFocus(GetDlgItem(hDlg, IDOK));
\r
7232 SendMessage(GetDlgItem(hDlg, OPT_CommentText),
\r
7233 WM_SETFONT, (WPARAM)font[boardSize][COMMENT_FONT]->hf,
\r
7234 MAKELPARAM(FALSE, 0));
\r
7235 /* Size and position the dialog */
\r
7236 if (!commentDialog) {
\r
7237 commentDialog = hDlg;
\r
7238 flags = SWP_NOZORDER;
\r
7239 GetClientRect(hDlg, &rect);
\r
7240 sizeX = rect.right;
\r
7241 sizeY = rect.bottom;
\r
7242 if (commentX != CW_USEDEFAULT && commentY != CW_USEDEFAULT &&
\r
7243 commentW != CW_USEDEFAULT && commentH != CW_USEDEFAULT) {
\r
7244 WINDOWPLACEMENT wp;
\r
7245 EnsureOnScreen(&commentX, &commentY, 0, 0);
\r
7246 wp.length = sizeof(WINDOWPLACEMENT);
\r
7248 wp.showCmd = SW_SHOW;
\r
7249 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
7250 wp.rcNormalPosition.left = commentX;
\r
7251 wp.rcNormalPosition.right = commentX + commentW;
\r
7252 wp.rcNormalPosition.top = commentY;
\r
7253 wp.rcNormalPosition.bottom = commentY + commentH;
\r
7254 SetWindowPlacement(hDlg, &wp);
\r
7256 GetClientRect(hDlg, &rect);
\r
7257 newSizeX = rect.right;
\r
7258 newSizeY = rect.bottom;
\r
7259 ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY,
\r
7260 newSizeX, newSizeY);
\r
7267 case WM_COMMAND: /* message: received a command */
\r
7268 switch (LOWORD(wParam)) {
\r
7270 if (editComment) {
\r
7272 /* Read changed options from the dialog box */
\r
7273 hwndText = GetDlgItem(hDlg, OPT_CommentText);
\r
7274 len = GetWindowTextLength(hwndText);
\r
7275 str = (char *) malloc(len + 1);
\r
7276 GetWindowText(hwndText, str, len + 1);
\r
7285 ReplaceComment(commentIndex, str);
\r
7292 case OPT_CancelComment:
\r
7296 case OPT_ClearComment:
\r
7297 SetDlgItemText(hDlg, OPT_CommentText, "");
\r
7300 case OPT_EditComment:
\r
7301 EditCommentEvent();
\r
7310 newSizeX = LOWORD(lParam);
\r
7311 newSizeY = HIWORD(lParam);
\r
7312 ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY, newSizeX, newSizeY);
\r
7317 case WM_GETMINMAXINFO:
\r
7318 /* Prevent resizing window too small */
\r
7319 mmi = (MINMAXINFO *) lParam;
\r
7320 mmi->ptMinTrackSize.x = 100;
\r
7321 mmi->ptMinTrackSize.y = 100;
\r
7328 EitherCommentPopUp(int index, char *title, char *str, BOOLEAN edit)
\r
7333 CheckMenuItem(GetMenu(hwndMain), IDM_EditComment, edit ? MF_CHECKED : MF_UNCHECKED);
\r
7335 if (str == NULL) str = "";
\r
7336 p = (char *) malloc(2 * strlen(str) + 2);
\r
7339 if (*str == '\n') *q++ = '\r';
\r
7343 if (commentText != NULL) free(commentText);
\r
7345 commentIndex = index;
\r
7346 commentTitle = title;
\r
7348 editComment = edit;
\r
7350 if (commentDialog) {
\r
7351 SendMessage(commentDialog, WM_INITDIALOG, 0, 0);
\r
7352 if (!commentDialogUp) ShowWindow(commentDialog, SW_SHOW);
\r
7354 lpProc = MakeProcInstance((FARPROC)CommentDialog, hInst);
\r
7355 CreateDialog(hInst, MAKEINTRESOURCE(DLG_EditComment),
\r
7356 hwndMain, (DLGPROC)lpProc);
\r
7357 FreeProcInstance(lpProc);
\r
7359 commentDialogUp = TRUE;
\r
7363 /*---------------------------------------------------------------------------*\
\r
7365 * Type-in move dialog functions
\r
7367 \*---------------------------------------------------------------------------*/
\r
7370 TypeInMoveDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7372 char move[MSG_SIZ];
\r
7374 ChessMove moveType;
\r
7375 int fromX, fromY, toX, toY;
\r
7378 switch (message) {
\r
7379 case WM_INITDIALOG:
\r
7380 move[0] = (char) lParam;
\r
7381 move[1] = NULLCHAR;
\r
7382 CenterWindowEx(hDlg, GetWindow(hDlg, GW_OWNER), 1 );
\r
7383 hInput = GetDlgItem(hDlg, OPT_Move);
\r
7384 SetWindowText(hInput, move);
\r
7386 SendMessage(hInput, EM_SETSEL, (WPARAM)9999, (LPARAM)9999);
\r
7390 switch (LOWORD(wParam)) {
\r
7392 GetDlgItemText(hDlg, OPT_Move, move, sizeof(move));
\r
7393 { int n; Board board;
\r
7395 if(gameMode == EditPosition && ParseFEN(board, &n, move) ) {
\r
7396 EditPositionPasteFEN(move);
\r
7397 EndDialog(hDlg, TRUE);
\r
7400 // [HGM] movenum: allow move number to be typed in any mode
\r
7401 if(sscanf(move, "%d", &n) == 1 && n != 0 ) {
\r
7402 currentMove = 2*n-1;
\r
7403 if(currentMove > forwardMostMove) currentMove = forwardMostMove;
\r
7404 if(currentMove < backwardMostMove) currentMove = backwardMostMove;
\r
7405 EndDialog(hDlg, TRUE);
\r
7406 DrawPosition(TRUE, boards[currentMove]);
\r
7407 if(currentMove > backwardMostMove) DisplayMove(currentMove - 1);
\r
7408 else DisplayMessage("", "");
\r
7412 if (gameMode != EditGame && currentMove != forwardMostMove &&
\r
7413 gameMode != Training) {
\r
7414 DisplayMoveError("Displayed move is not current");
\r
7416 // GetDlgItemText(hDlg, OPT_Move, move, sizeof(move)); // moved upstream
\r
7417 int ok = ParseOneMove(move, gameMode == EditPosition ? blackPlaysFirst : currentMove,
\r
7418 &moveType, &fromX, &fromY, &toX, &toY, &promoChar);
\r
7419 if(!ok && move[0] >= 'a') { move[0] += 'A' - 'a'; ok = 2; } // [HGM] try also capitalized
\r
7420 if (ok==1 || ok && ParseOneMove(move, gameMode == EditPosition ? blackPlaysFirst : currentMove,
\r
7421 &moveType, &fromX, &fromY, &toX, &toY, &promoChar)) {
\r
7422 if (gameMode != Training)
\r
7423 forwardMostMove = currentMove;
\r
7424 UserMoveEvent(fromX, fromY, toX, toY, promoChar);
\r
7426 DisplayMoveError("Could not parse move");
\r
7429 EndDialog(hDlg, TRUE);
\r
7432 EndDialog(hDlg, FALSE);
\r
7443 PopUpMoveDialog(char firstchar)
\r
7447 if ((gameMode == BeginningOfGame && !appData.icsActive) ||
\r
7448 gameMode == MachinePlaysWhite || gameMode == MachinePlaysBlack ||
\r
7449 gameMode == AnalyzeMode || gameMode == EditGame ||
\r
7450 gameMode == EditPosition || gameMode == IcsExamining ||
\r
7451 gameMode == IcsPlayingWhite || gameMode == IcsPlayingBlack ||
\r
7452 isdigit(firstchar) && // [HGM] movenum: allow typing in of move nr in 'passive' modes
\r
7453 ( gameMode == AnalyzeFile || gameMode == PlayFromGameFile ||
\r
7454 gameMode == IcsObserving || gameMode == TwoMachinesPlay ) ||
\r
7455 gameMode == Training) {
\r
7456 lpProc = MakeProcInstance((FARPROC)TypeInMoveDialog, hInst);
\r
7457 DialogBoxParam(hInst, MAKEINTRESOURCE(DLG_TypeInMove),
\r
7458 hwndMain, (DLGPROC)lpProc, (LPARAM)firstchar);
\r
7459 FreeProcInstance(lpProc);
\r
7463 /*---------------------------------------------------------------------------*\
\r
7465 * Type-in name dialog functions
\r
7467 \*---------------------------------------------------------------------------*/
\r
7470 TypeInNameDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7472 char move[MSG_SIZ];
\r
7475 switch (message) {
\r
7476 case WM_INITDIALOG:
\r
7477 move[0] = (char) lParam;
\r
7478 move[1] = NULLCHAR;
\r
7479 CenterWindowEx(hDlg, GetWindow(hDlg, GW_OWNER), 1 );
\r
7480 hInput = GetDlgItem(hDlg, OPT_Name);
\r
7481 SetWindowText(hInput, move);
\r
7483 SendMessage(hInput, EM_SETSEL, (WPARAM)9999, (LPARAM)9999);
\r
7487 switch (LOWORD(wParam)) {
\r
7489 GetDlgItemText(hDlg, OPT_Name, move, sizeof(move));
\r
7490 appData.userName = strdup(move);
\r
7493 EndDialog(hDlg, TRUE);
\r
7496 EndDialog(hDlg, FALSE);
\r
7507 PopUpNameDialog(char firstchar)
\r
7511 lpProc = MakeProcInstance((FARPROC)TypeInNameDialog, hInst);
\r
7512 DialogBoxParam(hInst, MAKEINTRESOURCE(DLG_TypeInName),
\r
7513 hwndMain, (DLGPROC)lpProc, (LPARAM)firstchar);
\r
7514 FreeProcInstance(lpProc);
\r
7517 /*---------------------------------------------------------------------------*\
\r
7521 \*---------------------------------------------------------------------------*/
\r
7523 /* Nonmodal error box */
\r
7524 LRESULT CALLBACK ErrorDialog(HWND hDlg, UINT message,
\r
7525 WPARAM wParam, LPARAM lParam);
\r
7528 ErrorPopUp(char *title, char *content)
\r
7532 BOOLEAN modal = hwndMain == NULL;
\r
7550 strncpy(errorTitle, title, sizeof(errorTitle));
\r
7551 errorTitle[sizeof(errorTitle) - 1] = '\0';
\r
7554 MessageBox(NULL, errorMessage, errorTitle, MB_OK|MB_ICONEXCLAMATION);
\r
7556 lpProc = MakeProcInstance((FARPROC)ErrorDialog, hInst);
\r
7557 CreateDialog(hInst, MAKEINTRESOURCE(DLG_Error),
\r
7558 hwndMain, (DLGPROC)lpProc);
\r
7559 FreeProcInstance(lpProc);
\r
7566 if (!appData.popupMoveErrors && moveErrorMessageUp) DisplayMessage("", "");
\r
7567 if (errorDialog == NULL) return;
\r
7568 DestroyWindow(errorDialog);
\r
7569 errorDialog = NULL;
\r
7573 ErrorDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7578 switch (message) {
\r
7579 case WM_INITDIALOG:
\r
7580 GetWindowRect(hDlg, &rChild);
\r
7583 SetWindowPos(hDlg, NULL, rChild.left,
\r
7584 rChild.top + boardRect.top - (rChild.bottom - rChild.top),
\r
7585 0, 0, SWP_NOZORDER|SWP_NOSIZE);
\r
7589 [AS] It seems that the above code wants to move the dialog up in the "caption
\r
7590 area" of the main window, but it uses the dialog height as an hard-coded constant,
\r
7591 and it doesn't work when you resize the dialog.
\r
7592 For now, just give it a default position.
\r
7594 SetWindowPos(hDlg, NULL, boardRect.left+8, boardRect.top+8, 0, 0, SWP_NOZORDER|SWP_NOSIZE);
\r
7596 errorDialog = hDlg;
\r
7597 SetWindowText(hDlg, errorTitle);
\r
7598 hwndText = GetDlgItem(hDlg, OPT_ErrorText);
\r
7599 SetDlgItemText(hDlg, OPT_ErrorText, errorMessage);
\r
7603 switch (LOWORD(wParam)) {
\r
7606 if (errorDialog == hDlg) errorDialog = NULL;
\r
7607 DestroyWindow(hDlg);
\r
7619 HWND gothicDialog = NULL;
\r
7622 GothicDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7626 int height = GetSystemMetrics(SM_CYCAPTION)+GetSystemMetrics(SM_CYFRAME);
\r
7628 switch (message) {
\r
7629 case WM_INITDIALOG:
\r
7630 GetWindowRect(hDlg, &rChild);
\r
7632 SetWindowPos(hDlg, NULL, boardX, boardY-height, winWidth, height,
\r
7636 [AS] It seems that the above code wants to move the dialog up in the "caption
\r
7637 area" of the main window, but it uses the dialog height as an hard-coded constant,
\r
7638 and it doesn't work when you resize the dialog.
\r
7639 For now, just give it a default position.
\r
7641 gothicDialog = hDlg;
\r
7642 SetWindowText(hDlg, errorTitle);
\r
7643 hwndText = GetDlgItem(hDlg, OPT_ErrorText);
\r
7644 SetDlgItemText(hDlg, OPT_ErrorText, errorMessage);
\r
7648 switch (LOWORD(wParam)) {
\r
7651 if (errorDialog == hDlg) errorDialog = NULL;
\r
7652 DestroyWindow(hDlg);
\r
7664 GothicPopUp(char *title, VariantClass variant)
\r
7667 static char *lastTitle;
\r
7669 strncpy(errorTitle, title, sizeof(errorTitle));
\r
7670 errorTitle[sizeof(errorTitle) - 1] = '\0';
\r
7672 if(lastTitle != title && gothicDialog != NULL) {
\r
7673 DestroyWindow(gothicDialog);
\r
7674 gothicDialog = NULL;
\r
7676 if(variant != VariantNormal && gothicDialog == NULL) {
\r
7677 title = lastTitle;
\r
7678 lpProc = MakeProcInstance((FARPROC)GothicDialog, hInst);
\r
7679 CreateDialog(hInst, MAKEINTRESOURCE(DLG_Error),
\r
7680 hwndMain, (DLGPROC)lpProc);
\r
7681 FreeProcInstance(lpProc);
\r
7686 /*---------------------------------------------------------------------------*\
\r
7688 * Ics Interaction console functions
\r
7690 \*---------------------------------------------------------------------------*/
\r
7692 #define HISTORY_SIZE 64
\r
7693 static char *history[HISTORY_SIZE];
\r
7694 int histIn = 0, histP = 0;
\r
7697 SaveInHistory(char *cmd)
\r
7699 if (history[histIn] != NULL) {
\r
7700 free(history[histIn]);
\r
7701 history[histIn] = NULL;
\r
7703 if (*cmd == NULLCHAR) return;
\r
7704 history[histIn] = StrSave(cmd);
\r
7705 histIn = (histIn + 1) % HISTORY_SIZE;
\r
7706 if (history[histIn] != NULL) {
\r
7707 free(history[histIn]);
\r
7708 history[histIn] = NULL;
\r
7714 PrevInHistory(char *cmd)
\r
7717 if (histP == histIn) {
\r
7718 if (history[histIn] != NULL) free(history[histIn]);
\r
7719 history[histIn] = StrSave(cmd);
\r
7721 newhp = (histP - 1 + HISTORY_SIZE) % HISTORY_SIZE;
\r
7722 if (newhp == histIn || history[newhp] == NULL) return NULL;
\r
7724 return history[histP];
\r
7730 if (histP == histIn) return NULL;
\r
7731 histP = (histP + 1) % HISTORY_SIZE;
\r
7732 return history[histP];
\r
7739 BOOLEAN immediate;
\r
7740 } IcsTextMenuEntry;
\r
7741 #define ICS_TEXT_MENU_SIZE (IDM_CommandXLast - IDM_CommandX + 1)
\r
7742 IcsTextMenuEntry icsTextMenuEntry[ICS_TEXT_MENU_SIZE];
\r
7745 ParseIcsTextMenu(char *icsTextMenuString)
\r
7748 IcsTextMenuEntry *e = icsTextMenuEntry;
\r
7749 char *p = icsTextMenuString;
\r
7750 while (e->item != NULL && e < icsTextMenuEntry + ICS_TEXT_MENU_SIZE) {
\r
7753 if (e->command != NULL) {
\r
7755 e->command = NULL;
\r
7759 e = icsTextMenuEntry;
\r
7760 while (*p && e < icsTextMenuEntry + ICS_TEXT_MENU_SIZE) {
\r
7761 if (*p == ';' || *p == '\n') {
\r
7762 e->item = strdup("-");
\r
7763 e->command = NULL;
\r
7765 } else if (*p == '-') {
\r
7766 e->item = strdup("-");
\r
7767 e->command = NULL;
\r
7771 char *q, *r, *s, *t;
\r
7773 q = strchr(p, ',');
\r
7774 if (q == NULL) break;
\r
7776 r = strchr(q + 1, ',');
\r
7777 if (r == NULL) break;
\r
7779 s = strchr(r + 1, ',');
\r
7780 if (s == NULL) break;
\r
7783 t = strchr(s + 1, c);
\r
7786 t = strchr(s + 1, c);
\r
7788 if (t != NULL) *t = NULLCHAR;
\r
7789 e->item = strdup(p);
\r
7790 e->command = strdup(q + 1);
\r
7791 e->getname = *(r + 1) != '0';
\r
7792 e->immediate = *(s + 1) != '0';
\r
7796 if (t == NULL) break;
\r
7805 LoadIcsTextMenu(IcsTextMenuEntry *e)
\r
7809 hmenu = LoadMenu(hInst, "TextMenu");
\r
7810 h = GetSubMenu(hmenu, 0);
\r
7812 if (strcmp(e->item, "-") == 0) {
\r
7813 AppendMenu(h, MF_SEPARATOR, 0, 0);
\r
7815 if (e->item[0] == '|') {
\r
7816 AppendMenu(h, MF_STRING|MF_MENUBARBREAK,
\r
7817 IDM_CommandX + i, &e->item[1]);
\r
7819 AppendMenu(h, MF_STRING, IDM_CommandX + i, e->item);
\r
7828 WNDPROC consoleTextWindowProc;
\r
7831 CommandX(HWND hwnd, char *command, BOOLEAN getname, BOOLEAN immediate)
\r
7833 char buf[MSG_SIZ], name[MSG_SIZ];
\r
7834 HWND hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
7838 SetWindowText(hInput, command);
\r
7840 SendMessage(hInput, WM_CHAR, '\r', 0);
\r
7842 sel.cpMin = 999999;
\r
7843 sel.cpMax = 999999;
\r
7844 SendMessage(hInput, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7849 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
7850 if (sel.cpMin == sel.cpMax) {
\r
7851 /* Expand to surrounding word */
\r
7854 tr.chrg.cpMax = sel.cpMin;
\r
7855 tr.chrg.cpMin = --sel.cpMin;
\r
7856 if (sel.cpMin < 0) break;
\r
7857 tr.lpstrText = name;
\r
7858 SendMessage(hwnd, EM_GETTEXTRANGE, 0, (LPARAM) &tr);
\r
7859 } while (isalpha(name[0]) || isdigit(name[0]) || name[0] == '-');
\r
7863 tr.chrg.cpMin = sel.cpMax;
\r
7864 tr.chrg.cpMax = ++sel.cpMax;
\r
7865 tr.lpstrText = name;
\r
7866 if (SendMessage(hwnd, EM_GETTEXTRANGE, 0, (LPARAM) &tr) < 1) break;
\r
7867 } while (isalpha(name[0]) || isdigit(name[0]) || name[0] == '-');
\r
7870 if (sel.cpMax == sel.cpMin || sel.cpMax - sel.cpMin > MSG_SIZ/2) {
\r
7871 MessageBeep(MB_ICONEXCLAMATION);
\r
7875 tr.lpstrText = name;
\r
7876 SendMessage(hwnd, EM_GETTEXTRANGE, 0, (LPARAM) &tr);
\r
7878 if (sel.cpMax - sel.cpMin > MSG_SIZ/2) {
\r
7879 MessageBeep(MB_ICONEXCLAMATION);
\r
7882 SendMessage(hwnd, EM_GETSELTEXT, 0, (LPARAM) name);
\r
7885 sprintf(buf, "%s %s", command, name);
\r
7886 SetWindowText(hInput, buf);
\r
7887 SendMessage(hInput, WM_CHAR, '\r', 0);
\r
7889 sprintf(buf, "%s %s ", command, name); /* trailing space */
\r
7890 SetWindowText(hInput, buf);
\r
7891 sel.cpMin = 999999;
\r
7892 sel.cpMax = 999999;
\r
7893 SendMessage(hInput, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7899 ConsoleTextSubclass(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
7904 switch (message) {
\r
7906 if (!(GetKeyState(VK_CONTROL) & ~1)) break;
\r
7909 SendMessage(hwnd, EM_LINESCROLL, 0, -999999);
\r
7912 sel.cpMin = 999999;
\r
7913 sel.cpMax = 999999;
\r
7914 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7915 SendMessage(hwnd, EM_SCROLLCARET, 0, 0);
\r
7920 if(wParam != '\022') {
\r
7921 if (wParam == '\t') {
\r
7922 if (GetKeyState(VK_SHIFT) < 0) {
\r
7924 if (IsIconic(hwndMain)) ShowWindow(hwndMain, SW_RESTORE);
\r
7925 if (buttonDesc[0].hwnd) {
\r
7926 SetFocus(buttonDesc[0].hwnd);
\r
7928 SetFocus(hwndMain);
\r
7932 SetFocus(GetDlgItem(hwndConsole, OPT_ConsoleInput));
\r
7935 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
7936 JAWS_DELETE( SetFocus(hInput); )
\r
7937 SendMessage(hInput, message, wParam, lParam);
\r
7940 } // [HGM] navigate: for Ctrl+R, flow into nex case (moved up here) to summon up menu
\r
7941 case WM_RBUTTONUP:
\r
7942 if (GetKeyState(VK_SHIFT) & ~1) {
\r
7943 SendDlgItemMessage(hwndConsole, OPT_ConsoleText,
\r
7944 WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
7947 HMENU hmenu = LoadIcsTextMenu(icsTextMenuEntry);
\r
7948 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
7949 if (sel.cpMin == sel.cpMax) {
\r
7950 EnableMenuItem(hmenu, IDM_Copy, MF_BYCOMMAND|MF_GRAYED);
\r
7951 EnableMenuItem(hmenu, IDM_QuickPaste, MF_BYCOMMAND|MF_GRAYED);
\r
7953 if (!IsClipboardFormatAvailable(CF_TEXT)) {
\r
7954 EnableMenuItem(hmenu, IDM_Paste, MF_BYCOMMAND|MF_GRAYED);
\r
7956 pt.x = LOWORD(lParam);
\r
7957 pt.y = HIWORD(lParam);
\r
7958 MenuPopup(hwnd, pt, hmenu, -1);
\r
7962 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
7964 return SendMessage(hInput, message, wParam, lParam);
\r
7965 case WM_MBUTTONDOWN:
\r
7966 return SendMessage(hwnd, WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
7967 case WM_RBUTTONDOWN:
\r
7968 if (!(GetKeyState(VK_SHIFT) & ~1)) {
\r
7969 /* Move selection here if it was empty */
\r
7971 pt.x = LOWORD(lParam);
\r
7972 pt.y = HIWORD(lParam);
\r
7973 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
7974 if (sel.cpMin == sel.cpMax) {
\r
7975 sel.cpMin = SendMessage(hwnd, EM_CHARFROMPOS, 0, (LPARAM)&pt); /*doc is wrong*/
\r
7976 sel.cpMax = sel.cpMin;
\r
7977 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7979 SendMessage(hwnd, EM_HIDESELECTION, FALSE, FALSE);
\r
7983 switch (LOWORD(wParam)) {
\r
7984 case IDM_QuickPaste:
\r
7986 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
7987 if (sel.cpMin == sel.cpMax) {
\r
7988 MessageBeep(MB_ICONEXCLAMATION);
\r
7991 SendMessage(hwnd, WM_COPY, 0, 0);
\r
7992 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
7993 SendMessage(hInput, WM_PASTE, 0, 0);
\r
7998 SendMessage(hwnd, WM_CUT, 0, 0);
\r
8001 SendMessage(hwnd, WM_PASTE, 0, 0);
\r
8004 SendMessage(hwnd, WM_COPY, 0, 0);
\r
8008 int i = LOWORD(wParam) - IDM_CommandX;
\r
8009 if (i >= 0 && i < ICS_TEXT_MENU_SIZE &&
\r
8010 icsTextMenuEntry[i].command != NULL) {
\r
8011 CommandX(hwnd, icsTextMenuEntry[i].command,
\r
8012 icsTextMenuEntry[i].getname,
\r
8013 icsTextMenuEntry[i].immediate);
\r
8021 return (*consoleTextWindowProc)(hwnd, message, wParam, lParam);
\r
8024 WNDPROC consoleInputWindowProc;
\r
8027 ConsoleInputSubclass(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
8029 char buf[MSG_SIZ];
\r
8031 static BOOL sendNextChar = FALSE;
\r
8032 static BOOL quoteNextChar = FALSE;
\r
8033 InputSource *is = consoleInputSource;
\r
8037 switch (message) {
\r
8039 if (!appData.localLineEditing || sendNextChar) {
\r
8040 is->buf[0] = (CHAR) wParam;
\r
8042 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
8043 sendNextChar = FALSE;
\r
8046 if (quoteNextChar) {
\r
8047 buf[0] = (char) wParam;
\r
8048 buf[1] = NULLCHAR;
\r
8049 SendMessage(hwnd, EM_REPLACESEL, TRUE, (LPARAM) buf);
\r
8050 quoteNextChar = FALSE;
\r
8054 case '\r': /* Enter key */
\r
8055 is->count = GetWindowText(hwnd, is->buf, INPUT_SOURCE_BUF_SIZE-1);
\r
8056 if (consoleEcho) SaveInHistory(is->buf);
\r
8057 is->buf[is->count++] = '\n';
\r
8058 is->buf[is->count] = NULLCHAR;
\r
8059 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
8060 if (consoleEcho) {
\r
8061 ConsoleOutput(is->buf, is->count, TRUE);
\r
8062 } else if (appData.localLineEditing) {
\r
8063 ConsoleOutput("\n", 1, TRUE);
\r
8066 case '\033': /* Escape key */
\r
8067 SetWindowText(hwnd, "");
\r
8068 cf.cbSize = sizeof(CHARFORMAT);
\r
8069 cf.dwMask = CFM_COLOR|CFM_BOLD|CFM_ITALIC|CFM_UNDERLINE|CFM_STRIKEOUT;
\r
8070 if (consoleEcho) {
\r
8071 cf.crTextColor = textAttribs[ColorNormal].color;
\r
8073 cf.crTextColor = COLOR_ECHOOFF;
\r
8075 cf.dwEffects = textAttribs[ColorNormal].effects;
\r
8076 SendMessage(hwnd, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&cf);
\r
8078 case '\t': /* Tab key */
\r
8079 if (GetKeyState(VK_SHIFT) < 0) {
\r
8081 SetFocus(GetDlgItem(hwndConsole, OPT_ConsoleText));
\r
8084 if (IsIconic(hwndMain)) ShowWindow(hwndMain, SW_RESTORE);
\r
8085 if (buttonDesc[0].hwnd) {
\r
8086 SetFocus(buttonDesc[0].hwnd);
\r
8088 SetFocus(hwndMain);
\r
8092 case '\023': /* Ctrl+S */
\r
8093 sendNextChar = TRUE;
\r
8095 case '\021': /* Ctrl+Q */
\r
8096 quoteNextChar = TRUE;
\r
8106 GetWindowText(hwnd, buf, MSG_SIZ);
\r
8107 p = PrevInHistory(buf);
\r
8109 SetWindowText(hwnd, p);
\r
8110 sel.cpMin = 999999;
\r
8111 sel.cpMax = 999999;
\r
8112 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
8117 p = NextInHistory();
\r
8119 SetWindowText(hwnd, p);
\r
8120 sel.cpMin = 999999;
\r
8121 sel.cpMax = 999999;
\r
8122 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
8128 if (!(GetKeyState(VK_CONTROL) & ~1)) break;
\r
8132 SendDlgItemMessage(hwndConsole, OPT_ConsoleText, message, wParam, lParam);
\r
8136 case WM_MBUTTONDOWN:
\r
8137 SendDlgItemMessage(hwndConsole, OPT_ConsoleText,
\r
8138 WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
8140 case WM_RBUTTONUP:
\r
8141 if (GetKeyState(VK_SHIFT) & ~1) {
\r
8142 SendDlgItemMessage(hwndConsole, OPT_ConsoleText,
\r
8143 WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
8147 hmenu = LoadMenu(hInst, "InputMenu");
\r
8148 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
8149 if (sel.cpMin == sel.cpMax) {
\r
8150 EnableMenuItem(hmenu, IDM_Copy, MF_BYCOMMAND|MF_GRAYED);
\r
8151 EnableMenuItem(hmenu, IDM_Cut, MF_BYCOMMAND|MF_GRAYED);
\r
8153 if (!IsClipboardFormatAvailable(CF_TEXT)) {
\r
8154 EnableMenuItem(hmenu, IDM_Paste, MF_BYCOMMAND|MF_GRAYED);
\r
8156 pt.x = LOWORD(lParam);
\r
8157 pt.y = HIWORD(lParam);
\r
8158 MenuPopup(hwnd, pt, hmenu, -1);
\r
8162 switch (LOWORD(wParam)) {
\r
8164 SendMessage(hwnd, EM_UNDO, 0, 0);
\r
8166 case IDM_SelectAll:
\r
8168 sel.cpMax = -1; /*999999?*/
\r
8169 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
8172 SendMessage(hwnd, WM_CUT, 0, 0);
\r
8175 SendMessage(hwnd, WM_PASTE, 0, 0);
\r
8178 SendMessage(hwnd, WM_COPY, 0, 0);
\r
8183 return (*consoleInputWindowProc)(hwnd, message, wParam, lParam);
\r
8186 #define CO_MAX 100000
\r
8187 #define CO_TRIM 1000
\r
8190 ConsoleWndProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
8192 static SnapData sd;
\r
8193 static HWND hText, hInput /*, hFocus*/;
\r
8194 // InputSource *is = consoleInputSource;
\r
8196 static int sizeX, sizeY;
\r
8197 int newSizeX, newSizeY;
\r
8200 switch (message) {
\r
8201 case WM_INITDIALOG: /* message: initialize dialog box */
\r
8202 hwndConsole = hDlg;
\r
8203 hText = GetDlgItem(hDlg, OPT_ConsoleText);
\r
8204 hInput = GetDlgItem(hDlg, OPT_ConsoleInput);
\r
8206 consoleTextWindowProc = (WNDPROC)
\r
8207 SetWindowLong(hText, GWL_WNDPROC, (LONG) ConsoleTextSubclass);
\r
8208 SendMessage(hText, EM_SETBKGNDCOLOR, FALSE, consoleBackgroundColor);
\r
8209 consoleInputWindowProc = (WNDPROC)
\r
8210 SetWindowLong(hInput, GWL_WNDPROC, (LONG) ConsoleInputSubclass);
\r
8211 SendMessage(hInput, EM_SETBKGNDCOLOR, FALSE, consoleBackgroundColor);
\r
8212 Colorize(ColorNormal, TRUE);
\r
8213 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM) &consoleCF);
\r
8214 ChangedConsoleFont();
\r
8215 GetClientRect(hDlg, &rect);
\r
8216 sizeX = rect.right;
\r
8217 sizeY = rect.bottom;
\r
8218 if (wpConsole.x != CW_USEDEFAULT && wpConsole.y != CW_USEDEFAULT &&
\r
8219 wpConsole.width != CW_USEDEFAULT && wpConsole.height != CW_USEDEFAULT) {
\r
8220 WINDOWPLACEMENT wp;
\r
8221 EnsureOnScreen(&wpConsole.x, &wpConsole.y, 0, 0);
\r
8222 wp.length = sizeof(WINDOWPLACEMENT);
\r
8224 wp.showCmd = SW_SHOW;
\r
8225 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
8226 wp.rcNormalPosition.left = wpConsole.x;
\r
8227 wp.rcNormalPosition.right = wpConsole.x + wpConsole.width;
\r
8228 wp.rcNormalPosition.top = wpConsole.y;
\r
8229 wp.rcNormalPosition.bottom = wpConsole.y + wpConsole.height;
\r
8230 SetWindowPlacement(hDlg, &wp);
\r
8233 // [HGM] Chessknight's change 2004-07-13
\r
8234 else { /* Determine Defaults */
\r
8235 WINDOWPLACEMENT wp;
\r
8236 wpConsole.x = winWidth + 1;
\r
8237 wpConsole.y = boardY;
\r
8238 wpConsole.width = screenWidth - winWidth;
\r
8239 wpConsole.height = winHeight;
\r
8240 EnsureOnScreen(&wpConsole.x, &wpConsole.y, 0, 0);
\r
8241 wp.length = sizeof(WINDOWPLACEMENT);
\r
8243 wp.showCmd = SW_SHOW;
\r
8244 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
8245 wp.rcNormalPosition.left = wpConsole.x;
\r
8246 wp.rcNormalPosition.right = wpConsole.x + wpConsole.width;
\r
8247 wp.rcNormalPosition.top = wpConsole.y;
\r
8248 wp.rcNormalPosition.bottom = wpConsole.y + wpConsole.height;
\r
8249 SetWindowPlacement(hDlg, &wp);
\r
8264 if (IsIconic(hDlg)) break;
\r
8265 newSizeX = LOWORD(lParam);
\r
8266 newSizeY = HIWORD(lParam);
\r
8267 if (sizeX != newSizeX || sizeY != newSizeY) {
\r
8268 RECT rectText, rectInput;
\r
8270 int newTextHeight, newTextWidth;
\r
8271 GetWindowRect(hText, &rectText);
\r
8272 newTextWidth = rectText.right - rectText.left + newSizeX - sizeX;
\r
8273 newTextHeight = rectText.bottom - rectText.top + newSizeY - sizeY;
\r
8274 if (newTextHeight < 0) {
\r
8275 newSizeY += -newTextHeight;
\r
8276 newTextHeight = 0;
\r
8278 SetWindowPos(hText, NULL, 0, 0,
\r
8279 newTextWidth, newTextHeight, SWP_NOZORDER|SWP_NOMOVE);
\r
8280 GetWindowRect(hInput, &rectInput); /* gives screen coords */
\r
8281 pt.x = rectInput.left;
\r
8282 pt.y = rectInput.top + newSizeY - sizeY;
\r
8283 ScreenToClient(hDlg, &pt);
\r
8284 SetWindowPos(hInput, NULL,
\r
8285 pt.x, pt.y, /* needs client coords */
\r
8286 rectInput.right - rectInput.left + newSizeX - sizeX,
\r
8287 rectInput.bottom - rectInput.top, SWP_NOZORDER);
\r
8293 case WM_GETMINMAXINFO:
\r
8294 /* Prevent resizing window too small */
\r
8295 mmi = (MINMAXINFO *) lParam;
\r
8296 mmi->ptMinTrackSize.x = 100;
\r
8297 mmi->ptMinTrackSize.y = 100;
\r
8300 /* [AS] Snapping */
\r
8301 case WM_ENTERSIZEMOVE:
\r
8302 return OnEnterSizeMove( &sd, hDlg, wParam, lParam );
\r
8305 return OnSizing( &sd, hDlg, wParam, lParam );
\r
8308 return OnMoving( &sd, hDlg, wParam, lParam );
\r
8310 case WM_EXITSIZEMOVE:
\r
8311 return OnExitSizeMove( &sd, hDlg, wParam, lParam );
\r
8314 return DefWindowProc(hDlg, message, wParam, lParam);
\r
8322 if (hwndConsole) return;
\r
8323 hCons = CreateDialog(hInst, szConsoleName, 0, NULL);
\r
8324 SendMessage(hCons, WM_INITDIALOG, 0, 0);
\r
8329 ConsoleOutput(char* data, int length, int forceVisible)
\r
8334 char buf[CO_MAX+1];
\r
8337 static int delayLF = 0;
\r
8338 CHARRANGE savesel, sel;
\r
8340 if (hwndConsole == NULL || length > CO_MAX-100 || length == 0) return;
\r
8348 while (length--) {
\r
8356 } else if (*p == '\007') {
\r
8357 MyPlaySound(&sounds[(int)SoundBell]);
\r
8364 hText = GetDlgItem(hwndConsole, OPT_ConsoleText);
\r
8365 SendMessage(hText, EM_HIDESELECTION, TRUE, FALSE);
\r
8366 /* Save current selection */
\r
8367 SendMessage(hText, EM_EXGETSEL, 0, (LPARAM)&savesel);
\r
8368 exlen = GetWindowTextLength(hText);
\r
8369 /* Find out whether current end of text is visible */
\r
8370 SendMessage(hText, EM_GETRECT, 0, (LPARAM) &rect);
\r
8371 SendMessage(hText, EM_POSFROMCHAR, (WPARAM) &pEnd, exlen);
\r
8372 /* Trim existing text if it's too long */
\r
8373 if (exlen + (q - buf) > CO_MAX) {
\r
8374 trim = (CO_TRIM > (q - buf)) ? CO_TRIM : (q - buf);
\r
8377 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
8378 SendMessage(hText, EM_REPLACESEL, 0, (LPARAM)"");
\r
8380 savesel.cpMin -= trim;
\r
8381 savesel.cpMax -= trim;
\r
8382 if (exlen < 0) exlen = 0;
\r
8383 if (savesel.cpMin < 0) savesel.cpMin = 0;
\r
8384 if (savesel.cpMax < savesel.cpMin) savesel.cpMax = savesel.cpMin;
\r
8386 /* Append the new text */
\r
8387 sel.cpMin = exlen;
\r
8388 sel.cpMax = exlen;
\r
8389 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
8390 SendMessage(hText, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&consoleCF);
\r
8391 SendMessage(hText, EM_REPLACESEL, 0, (LPARAM) buf);
\r
8392 if (forceVisible || exlen == 0 ||
\r
8393 (rect.left <= pEnd.x && pEnd.x < rect.right &&
\r
8394 rect.top <= pEnd.y && pEnd.y < rect.bottom)) {
\r
8395 /* Scroll to make new end of text visible if old end of text
\r
8396 was visible or new text is an echo of user typein */
\r
8397 sel.cpMin = 9999999;
\r
8398 sel.cpMax = 9999999;
\r
8399 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
8400 SendMessage(hText, EM_HIDESELECTION, FALSE, FALSE);
\r
8401 SendMessage(hText, EM_SCROLLCARET, 0, 0);
\r
8402 SendMessage(hText, EM_HIDESELECTION, TRUE, FALSE);
\r
8404 if (savesel.cpMax == exlen || forceVisible) {
\r
8405 /* Move insert point to new end of text if it was at the old
\r
8406 end of text or if the new text is an echo of user typein */
\r
8407 sel.cpMin = 9999999;
\r
8408 sel.cpMax = 9999999;
\r
8409 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
8411 /* Restore previous selection */
\r
8412 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&savesel);
\r
8414 SendMessage(hText, EM_HIDESELECTION, FALSE, FALSE);
\r
8421 DisplayHoldingsCount(HDC hdc, int x, int y, int rightAlign, int copyNumber)
\r
8425 COLORREF oldFg, oldBg;
\r
8429 if(copyNumber > 1) sprintf(buf, "%d", copyNumber); else buf[0] = 0;
\r
8431 oldFg = SetTextColor(hdc, RGB(255, 255, 255)); /* white */
\r
8432 oldBg = SetBkColor(hdc, RGB(0, 0, 0)); /* black */
\r
8433 oldFont = SelectObject(hdc, font[boardSize][CLOCK_FONT]->hf);
\r
8436 rect.right = x + squareSize;
\r
8438 rect.bottom = y + squareSize;
\r
8441 ExtTextOut(hdc, x + MESSAGE_LINE_LEFTMARGIN
\r
8442 + (rightAlign ? (squareSize*2)/3 : 0),
\r
8443 y, ETO_CLIPPED|ETO_OPAQUE,
\r
8444 &rect, str, strlen(str), NULL);
\r
8446 (void) SetTextColor(hdc, oldFg);
\r
8447 (void) SetBkColor(hdc, oldBg);
\r
8448 (void) SelectObject(hdc, oldFont);
\r
8452 DisplayAClock(HDC hdc, int timeRemaining, int highlight,
\r
8453 RECT *rect, char *color, char *flagFell)
\r
8457 COLORREF oldFg, oldBg;
\r
8460 if (appData.clockMode) {
\r
8462 sprintf(buf, "%c %s %s", color[0], TimeString(timeRemaining), flagFell);
\r
8464 sprintf(buf, "%s:%c%s %s", color, (logoHeight>0 ? 0 : ' '), TimeString(timeRemaining), flagFell);
\r
8471 oldFg = SetTextColor(hdc, RGB(255, 255, 255)); /* white */
\r
8472 oldBg = SetBkColor(hdc, RGB(0, 0, 0)); /* black */
\r
8474 oldFg = SetTextColor(hdc, RGB(0, 0, 0)); /* black */
\r
8475 oldBg = SetBkColor(hdc, RGB(255, 255, 255)); /* white */
\r
8477 oldFont = SelectObject(hdc, font[boardSize][CLOCK_FONT]->hf);
\r
8481 ExtTextOut(hdc, rect->left + MESSAGE_LINE_LEFTMARGIN,
\r
8482 rect->top, ETO_CLIPPED|ETO_OPAQUE,
\r
8483 rect, str, strlen(str), NULL);
\r
8484 if(logoHeight > 0 && appData.clockMode) {
\r
8486 sprintf(buf, "%s %s", buf+7, flagFell);
\r
8487 r.top = rect->top + logoHeight/2;
\r
8488 r.left = rect->left;
\r
8489 r.right = rect->right;
\r
8490 r.bottom = rect->bottom;
\r
8491 ExtTextOut(hdc, rect->left + MESSAGE_LINE_LEFTMARGIN,
\r
8492 r.top, ETO_CLIPPED|ETO_OPAQUE,
\r
8493 &r, str, strlen(str), NULL);
\r
8495 (void) SetTextColor(hdc, oldFg);
\r
8496 (void) SetBkColor(hdc, oldBg);
\r
8497 (void) SelectObject(hdc, oldFont);
\r
8502 DoReadFile(HANDLE hFile, char *buf, int count, DWORD *outCount,
\r
8508 if( count <= 0 ) {
\r
8509 if (appData.debugMode) {
\r
8510 fprintf( debugFP, "DoReadFile: trying to read past end of buffer, overflow = %d\n", count );
\r
8513 return ERROR_INVALID_USER_BUFFER;
\r
8516 ResetEvent(ovl->hEvent);
\r
8517 ovl->Offset = ovl->OffsetHigh = 0;
\r
8518 ok = ReadFile(hFile, buf, count, outCount, ovl);
\r
8522 err = GetLastError();
\r
8523 if (err == ERROR_IO_PENDING) {
\r
8524 ok = GetOverlappedResult(hFile, ovl, outCount, TRUE);
\r
8528 err = GetLastError();
\r
8535 DoWriteFile(HANDLE hFile, char *buf, int count, DWORD *outCount,
\r
8540 ResetEvent(ovl->hEvent);
\r
8541 ovl->Offset = ovl->OffsetHigh = 0;
\r
8542 ok = WriteFile(hFile, buf, count, outCount, ovl);
\r
8546 err = GetLastError();
\r
8547 if (err == ERROR_IO_PENDING) {
\r
8548 ok = GetOverlappedResult(hFile, ovl, outCount, TRUE);
\r
8552 err = GetLastError();
\r
8558 /* [AS] If input is line by line and a line exceed the buffer size, force an error */
\r
8559 void CheckForInputBufferFull( InputSource * is )
\r
8561 if( is->lineByLine && (is->next - is->buf) >= INPUT_SOURCE_BUF_SIZE ) {
\r
8562 /* Look for end of line */
\r
8563 char * p = is->buf;
\r
8565 while( p < is->next && *p != '\n' ) {
\r
8569 if( p >= is->next ) {
\r
8570 if (appData.debugMode) {
\r
8571 fprintf( debugFP, "Input line exceeded buffer size (source id=%lu)\n", is->id );
\r
8574 is->error = ERROR_BROKEN_PIPE; /* [AS] Just any non-successful code! */
\r
8575 is->count = (DWORD) -1;
\r
8576 is->next = is->buf;
\r
8582 InputThread(LPVOID arg)
\r
8587 is = (InputSource *) arg;
\r
8588 ovl.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
\r
8589 ovl.Internal = ovl.InternalHigh = ovl.Offset = ovl.OffsetHigh = 0;
\r
8590 while (is->hThread != NULL) {
\r
8591 is->error = DoReadFile(is->hFile, is->next,
\r
8592 INPUT_SOURCE_BUF_SIZE - (is->next - is->buf),
\r
8593 &is->count, &ovl);
\r
8594 if (is->error == NO_ERROR) {
\r
8595 is->next += is->count;
\r
8597 if (is->error == ERROR_BROKEN_PIPE) {
\r
8598 /* Correct for MS brain damage. EOF reading a pipe is not an error. */
\r
8601 is->count = (DWORD) -1;
\r
8602 /* [AS] The (is->count <= 0) check below is not useful for unsigned values! */
\r
8607 CheckForInputBufferFull( is );
\r
8609 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
8611 if( is->count == ((DWORD) -1) ) break; /* [AS] */
\r
8613 if (is->count <= 0) break; /* Quit on EOF or error */
\r
8616 CloseHandle(ovl.hEvent);
\r
8617 CloseHandle(is->hFile);
\r
8619 if (appData.debugMode) {
\r
8620 fprintf( debugFP, "Input thread terminated (id=%lu, error=%d, count=%ld)\n", is->id, is->error, is->count );
\r
8627 /* Windows 95 beta 2 won't let you do overlapped i/o on a console or pipe */
\r
8629 NonOvlInputThread(LPVOID arg)
\r
8636 is = (InputSource *) arg;
\r
8637 while (is->hThread != NULL) {
\r
8638 is->error = ReadFile(is->hFile, is->next,
\r
8639 INPUT_SOURCE_BUF_SIZE - (is->next - is->buf),
\r
8640 &is->count, NULL) ? NO_ERROR : GetLastError();
\r
8641 if (is->error == NO_ERROR) {
\r
8642 /* Change CRLF to LF */
\r
8643 if (is->next > is->buf) {
\r
8645 i = is->count + 1;
\r
8653 if (prev == '\r' && *p == '\n') {
\r
8665 if (is->error == ERROR_BROKEN_PIPE) {
\r
8666 /* Correct for MS brain damage. EOF reading a pipe is not an error. */
\r
8669 is->count = (DWORD) -1;
\r
8673 CheckForInputBufferFull( is );
\r
8675 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
8677 if( is->count == ((DWORD) -1) ) break; /* [AS] */
\r
8679 if (is->count < 0) break; /* Quit on error */
\r
8681 CloseHandle(is->hFile);
\r
8686 SocketInputThread(LPVOID arg)
\r
8690 is = (InputSource *) arg;
\r
8691 while (is->hThread != NULL) {
\r
8692 is->count = recv(is->sock, is->buf, INPUT_SOURCE_BUF_SIZE, 0);
\r
8693 if ((int)is->count == SOCKET_ERROR) {
\r
8694 is->count = (DWORD) -1;
\r
8695 is->error = WSAGetLastError();
\r
8697 is->error = NO_ERROR;
\r
8698 is->next += is->count;
\r
8699 if (is->count == 0 && is->second == is) {
\r
8700 /* End of file on stderr; quit with no message */
\r
8704 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
8706 if( is->count == ((DWORD) -1) ) break; /* [AS] */
\r
8708 if (is->count <= 0) break; /* Quit on EOF or error */
\r
8714 InputEvent(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
8718 is = (InputSource *) lParam;
\r
8719 if (is->lineByLine) {
\r
8720 /* Feed in lines one by one */
\r
8721 char *p = is->buf;
\r
8723 while (q < is->next) {
\r
8724 if (*q++ == '\n') {
\r
8725 (is->func)(is, is->closure, p, q - p, NO_ERROR);
\r
8730 /* Move any partial line to the start of the buffer */
\r
8732 while (p < is->next) {
\r
8737 if (is->error != NO_ERROR || is->count == 0) {
\r
8738 /* Notify backend of the error. Note: If there was a partial
\r
8739 line at the end, it is not flushed through. */
\r
8740 (is->func)(is, is->closure, is->buf, is->count, is->error);
\r
8743 /* Feed in the whole chunk of input at once */
\r
8744 (is->func)(is, is->closure, is->buf, is->count, is->error);
\r
8745 is->next = is->buf;
\r
8749 /*---------------------------------------------------------------------------*\
\r
8751 * Menu enables. Used when setting various modes.
\r
8753 \*---------------------------------------------------------------------------*/
\r
8761 SetMenuEnables(HMENU hmenu, Enables *enab)
\r
8763 while (enab->item > 0) {
\r
8764 (void) EnableMenuItem(hmenu, enab->item, enab->flags);
\r
8769 Enables gnuEnables[] = {
\r
8770 { IDM_MailMove, MF_BYCOMMAND|MF_GRAYED },
\r
8771 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_GRAYED },
\r
8772 { IDM_IcsClient, MF_BYCOMMAND|MF_GRAYED },
\r
8773 { IDM_Accept, MF_BYCOMMAND|MF_GRAYED },
\r
8774 { IDM_Decline, MF_BYCOMMAND|MF_GRAYED },
\r
8775 { IDM_Rematch, MF_BYCOMMAND|MF_GRAYED },
\r
8776 { IDM_Adjourn, MF_BYCOMMAND|MF_GRAYED },
\r
8777 { IDM_StopExamining, MF_BYCOMMAND|MF_GRAYED },
\r
8778 { IDM_StopObserving, MF_BYCOMMAND|MF_GRAYED },
\r
8779 { IDM_Revert, MF_BYCOMMAND|MF_GRAYED },
\r
8783 Enables icsEnables[] = {
\r
8784 { IDM_MailMove, MF_BYCOMMAND|MF_GRAYED },
\r
8785 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_GRAYED },
\r
8786 { IDM_MachineWhite, MF_BYCOMMAND|MF_GRAYED },
\r
8787 { IDM_MachineBlack, MF_BYCOMMAND|MF_GRAYED },
\r
8788 { IDM_TwoMachines, MF_BYCOMMAND|MF_GRAYED },
\r
8789 { IDM_AnalysisMode, MF_BYCOMMAND|MF_ENABLED },
\r
8790 { IDM_AnalyzeFile, MF_BYCOMMAND|MF_GRAYED },
\r
8791 { IDM_TimeControl, MF_BYCOMMAND|MF_GRAYED },
\r
8792 { IDM_MoveNow, MF_BYCOMMAND|MF_GRAYED },
\r
8793 { IDM_Hint, MF_BYCOMMAND|MF_GRAYED },
\r
8794 { IDM_Book, MF_BYCOMMAND|MF_GRAYED },
\r
8795 { IDM_IcsOptions, MF_BYCOMMAND|MF_ENABLED },
\r
8800 Enables zippyEnables[] = {
\r
8801 { IDM_MoveNow, MF_BYCOMMAND|MF_ENABLED },
\r
8802 { IDM_Hint, MF_BYCOMMAND|MF_ENABLED },
\r
8803 { IDM_Book, MF_BYCOMMAND|MF_ENABLED },
\r
8808 Enables ncpEnables[] = {
\r
8809 { IDM_MailMove, MF_BYCOMMAND|MF_GRAYED },
\r
8810 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_GRAYED },
\r
8811 { IDM_MachineWhite, MF_BYCOMMAND|MF_GRAYED },
\r
8812 { IDM_MachineBlack, MF_BYCOMMAND|MF_GRAYED },
\r
8813 { IDM_TwoMachines, MF_BYCOMMAND|MF_GRAYED },
\r
8814 { IDM_AnalysisMode, MF_BYCOMMAND|MF_GRAYED },
\r
8815 { IDM_AnalyzeFile, MF_BYCOMMAND|MF_GRAYED },
\r
8816 { IDM_IcsClient, MF_BYCOMMAND|MF_GRAYED },
\r
8817 { ACTION_POS, MF_BYPOSITION|MF_GRAYED },
\r
8818 { IDM_Revert, MF_BYCOMMAND|MF_GRAYED },
\r
8819 { IDM_MoveNow, MF_BYCOMMAND|MF_GRAYED },
\r
8820 { IDM_RetractMove, MF_BYCOMMAND|MF_GRAYED },
\r
8821 { IDM_TimeControl, MF_BYCOMMAND|MF_GRAYED },
\r
8822 { IDM_Hint, MF_BYCOMMAND|MF_GRAYED },
\r
8823 { IDM_Book, MF_BYCOMMAND|MF_GRAYED },
\r
8827 Enables trainingOnEnables[] = {
\r
8828 { IDM_EditComment, MF_BYCOMMAND|MF_GRAYED },
\r
8829 { IDM_Pause, MF_BYCOMMAND|MF_GRAYED },
\r
8830 { IDM_Forward, MF_BYCOMMAND|MF_GRAYED },
\r
8831 { IDM_Backward, MF_BYCOMMAND|MF_GRAYED },
\r
8832 { IDM_ToEnd, MF_BYCOMMAND|MF_GRAYED },
\r
8833 { IDM_ToStart, MF_BYCOMMAND|MF_GRAYED },
\r
8834 { IDM_MoveNow, MF_BYCOMMAND|MF_GRAYED },
\r
8835 { IDM_TruncateGame, MF_BYCOMMAND|MF_GRAYED },
\r
8839 Enables trainingOffEnables[] = {
\r
8840 { IDM_EditComment, MF_BYCOMMAND|MF_ENABLED },
\r
8841 { IDM_Pause, MF_BYCOMMAND|MF_ENABLED },
\r
8842 { IDM_Forward, MF_BYCOMMAND|MF_ENABLED },
\r
8843 { IDM_Backward, MF_BYCOMMAND|MF_ENABLED },
\r
8844 { IDM_ToEnd, MF_BYCOMMAND|MF_ENABLED },
\r
8845 { IDM_ToStart, MF_BYCOMMAND|MF_ENABLED },
\r
8846 { IDM_MoveNow, MF_BYCOMMAND|MF_ENABLED },
\r
8847 { IDM_TruncateGame, MF_BYCOMMAND|MF_ENABLED },
\r
8851 /* These modify either ncpEnables or gnuEnables */
\r
8852 Enables cmailEnables[] = {
\r
8853 { IDM_MailMove, MF_BYCOMMAND|MF_ENABLED },
\r
8854 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_ENABLED },
\r
8855 { ACTION_POS, MF_BYPOSITION|MF_ENABLED },
\r
8856 { IDM_CallFlag, MF_BYCOMMAND|MF_GRAYED },
\r
8857 { IDM_Draw, MF_BYCOMMAND|MF_ENABLED },
\r
8858 { IDM_Adjourn, MF_BYCOMMAND|MF_GRAYED },
\r
8859 { IDM_Abort, MF_BYCOMMAND|MF_GRAYED },
\r
8863 Enables machineThinkingEnables[] = {
\r
8864 { IDM_LoadGame, MF_BYCOMMAND|MF_GRAYED },
\r
8865 { IDM_LoadNextGame, MF_BYCOMMAND|MF_GRAYED },
\r
8866 { IDM_LoadPrevGame, MF_BYCOMMAND|MF_GRAYED },
\r
8867 { IDM_ReloadGame, MF_BYCOMMAND|MF_GRAYED },
\r
8868 { IDM_PasteGame, MF_BYCOMMAND|MF_GRAYED },
\r
8869 { IDM_LoadPosition, MF_BYCOMMAND|MF_GRAYED },
\r
8870 { IDM_LoadNextPosition, MF_BYCOMMAND|MF_GRAYED },
\r
8871 { IDM_LoadPrevPosition, MF_BYCOMMAND|MF_GRAYED },
\r
8872 { IDM_ReloadPosition, MF_BYCOMMAND|MF_GRAYED },
\r
8873 { IDM_PastePosition, MF_BYCOMMAND|MF_GRAYED },
\r
8874 { IDM_MachineWhite, MF_BYCOMMAND|MF_GRAYED },
\r
8875 { IDM_MachineBlack, MF_BYCOMMAND|MF_GRAYED },
\r
8876 { IDM_TwoMachines, MF_BYCOMMAND|MF_GRAYED },
\r
8877 { IDM_TypeInMove, MF_BYCOMMAND|MF_GRAYED },
\r
8878 { IDM_RetractMove, MF_BYCOMMAND|MF_GRAYED },
\r
8882 Enables userThinkingEnables[] = {
\r
8883 { IDM_LoadGame, MF_BYCOMMAND|MF_ENABLED },
\r
8884 { IDM_LoadNextGame, MF_BYCOMMAND|MF_ENABLED },
\r
8885 { IDM_LoadPrevGame, MF_BYCOMMAND|MF_ENABLED },
\r
8886 { IDM_ReloadGame, MF_BYCOMMAND|MF_ENABLED },
\r
8887 { IDM_PasteGame, MF_BYCOMMAND|MF_ENABLED },
\r
8888 { IDM_LoadPosition, MF_BYCOMMAND|MF_ENABLED },
\r
8889 { IDM_LoadNextPosition, MF_BYCOMMAND|MF_ENABLED },
\r
8890 { IDM_LoadPrevPosition, MF_BYCOMMAND|MF_ENABLED },
\r
8891 { IDM_ReloadPosition, MF_BYCOMMAND|MF_ENABLED },
\r
8892 { IDM_PastePosition, MF_BYCOMMAND|MF_ENABLED },
\r
8893 { IDM_MachineWhite, MF_BYCOMMAND|MF_ENABLED },
\r
8894 { IDM_MachineBlack, MF_BYCOMMAND|MF_ENABLED },
\r
8895 { IDM_TwoMachines, MF_BYCOMMAND|MF_ENABLED },
\r
8896 { IDM_TypeInMove, MF_BYCOMMAND|MF_ENABLED },
\r
8897 { IDM_RetractMove, MF_BYCOMMAND|MF_ENABLED },
\r
8901 /*---------------------------------------------------------------------------*\
\r
8903 * Front-end interface functions exported by XBoard.
\r
8904 * Functions appear in same order as prototypes in frontend.h.
\r
8906 \*---------------------------------------------------------------------------*/
\r
8910 static UINT prevChecked = 0;
\r
8911 static int prevPausing = 0;
\r
8914 if (pausing != prevPausing) {
\r
8915 prevPausing = pausing;
\r
8916 (void) CheckMenuItem(GetMenu(hwndMain), IDM_Pause,
\r
8917 MF_BYCOMMAND|(pausing ? MF_CHECKED : MF_UNCHECKED));
\r
8918 if (hwndPause) SetWindowText(hwndPause, pausing ? "C" : "P");
\r
8921 switch (gameMode) {
\r
8922 case BeginningOfGame:
\r
8923 if (appData.icsActive)
\r
8924 nowChecked = IDM_IcsClient;
\r
8925 else if (appData.noChessProgram)
\r
8926 nowChecked = IDM_EditGame;
\r
8928 nowChecked = IDM_MachineBlack;
\r
8930 case MachinePlaysBlack:
\r
8931 nowChecked = IDM_MachineBlack;
\r
8933 case MachinePlaysWhite:
\r
8934 nowChecked = IDM_MachineWhite;
\r
8936 case TwoMachinesPlay:
\r
8937 nowChecked = IDM_TwoMachines;
\r
8940 nowChecked = IDM_AnalysisMode;
\r
8943 nowChecked = IDM_AnalyzeFile;
\r
8946 nowChecked = IDM_EditGame;
\r
8948 case PlayFromGameFile:
\r
8949 nowChecked = IDM_LoadGame;
\r
8951 case EditPosition:
\r
8952 nowChecked = IDM_EditPosition;
\r
8955 nowChecked = IDM_Training;
\r
8957 case IcsPlayingWhite:
\r
8958 case IcsPlayingBlack:
\r
8959 case IcsObserving:
\r
8961 nowChecked = IDM_IcsClient;
\r
8968 if (prevChecked != 0)
\r
8969 (void) CheckMenuItem(GetMenu(hwndMain),
\r
8970 prevChecked, MF_BYCOMMAND|MF_UNCHECKED);
\r
8971 if (nowChecked != 0)
\r
8972 (void) CheckMenuItem(GetMenu(hwndMain),
\r
8973 nowChecked, MF_BYCOMMAND|MF_CHECKED);
\r
8975 if (nowChecked == IDM_LoadGame || nowChecked == IDM_Training) {
\r
8976 (void) EnableMenuItem(GetMenu(hwndMain), IDM_Training,
\r
8977 MF_BYCOMMAND|MF_ENABLED);
\r
8979 (void) EnableMenuItem(GetMenu(hwndMain),
\r
8980 IDM_Training, MF_BYCOMMAND|MF_GRAYED);
\r
8983 prevChecked = nowChecked;
\r
8985 /* [DM] icsEngineAnalyze - Do a sceure check too */
\r
8986 if (appData.icsActive) {
\r
8987 if (appData.icsEngineAnalyze) {
\r
8988 (void) CheckMenuItem(GetMenu(hwndMain), IDM_AnalysisMode,
\r
8989 MF_BYCOMMAND|MF_CHECKED);
\r
8991 (void) CheckMenuItem(GetMenu(hwndMain), IDM_AnalysisMode,
\r
8992 MF_BYCOMMAND|MF_UNCHECKED);
\r
9000 HMENU hmenu = GetMenu(hwndMain);
\r
9001 SetMenuEnables(hmenu, icsEnables);
\r
9002 EnableMenuItem(GetSubMenu(hmenu, OPTIONS_POS), ICS_POS,
\r
9003 MF_BYPOSITION|MF_ENABLED);
\r
9005 if (appData.zippyPlay) {
\r
9006 SetMenuEnables(hmenu, zippyEnables);
\r
9007 if (!appData.noChessProgram) /* [DM] icsEngineAnalyze */
\r
9008 (void) EnableMenuItem(GetMenu(hwndMain), IDM_AnalysisMode,
\r
9009 MF_BYCOMMAND|MF_ENABLED);
\r
9017 SetMenuEnables(GetMenu(hwndMain), gnuEnables);
\r
9023 HMENU hmenu = GetMenu(hwndMain);
\r
9024 SetMenuEnables(hmenu, ncpEnables);
\r
9025 EnableMenuItem(GetSubMenu(hmenu, OPTIONS_POS), SOUNDS_POS,
\r
9026 MF_BYPOSITION|MF_GRAYED);
\r
9027 DrawMenuBar(hwndMain);
\r
9033 SetMenuEnables(GetMenu(hwndMain), cmailEnables);
\r
9037 SetTrainingModeOn()
\r
9040 SetMenuEnables(GetMenu(hwndMain), trainingOnEnables);
\r
9041 for (i = 0; i < N_BUTTONS; i++) {
\r
9042 if (buttonDesc[i].hwnd != NULL)
\r
9043 EnableWindow(buttonDesc[i].hwnd, FALSE);
\r
9048 VOID SetTrainingModeOff()
\r
9051 SetMenuEnables(GetMenu(hwndMain), trainingOffEnables);
\r
9052 for (i = 0; i < N_BUTTONS; i++) {
\r
9053 if (buttonDesc[i].hwnd != NULL)
\r
9054 EnableWindow(buttonDesc[i].hwnd, TRUE);
\r
9060 SetUserThinkingEnables()
\r
9062 SetMenuEnables(GetMenu(hwndMain), userThinkingEnables);
\r
9066 SetMachineThinkingEnables()
\r
9068 HMENU hMenu = GetMenu(hwndMain);
\r
9069 int flags = MF_BYCOMMAND|MF_ENABLED;
\r
9071 SetMenuEnables(hMenu, machineThinkingEnables);
\r
9073 if (gameMode == MachinePlaysBlack) {
\r
9074 (void)EnableMenuItem(hMenu, IDM_MachineBlack, flags);
\r
9075 } else if (gameMode == MachinePlaysWhite) {
\r
9076 (void)EnableMenuItem(hMenu, IDM_MachineWhite, flags);
\r
9077 } else if (gameMode == TwoMachinesPlay) {
\r
9078 (void)EnableMenuItem(hMenu, IDM_TwoMachines, flags);
\r
9084 DisplayTitle(char *str)
\r
9086 char title[MSG_SIZ], *host;
\r
9087 if (str[0] != NULLCHAR) {
\r
9088 strcpy(title, str);
\r
9089 } else if (appData.icsActive) {
\r
9090 if (appData.icsCommPort[0] != NULLCHAR)
\r
9093 host = appData.icsHost;
\r
9094 sprintf(title, "%s: %s", szTitle, host);
\r
9095 } else if (appData.noChessProgram) {
\r
9096 strcpy(title, szTitle);
\r
9098 strcpy(title, szTitle);
\r
9099 strcat(title, ": ");
\r
9100 strcat(title, first.tidy);
\r
9102 SetWindowText(hwndMain, title);
\r
9107 DisplayMessage(char *str1, char *str2)
\r
9111 int remain = MESSAGE_TEXT_MAX - 1;
\r
9114 moveErrorMessageUp = FALSE; /* turned on later by caller if needed */
\r
9115 messageText[0] = NULLCHAR;
\r
9117 len = strlen(str1);
\r
9118 if (len > remain) len = remain;
\r
9119 strncpy(messageText, str1, len);
\r
9120 messageText[len] = NULLCHAR;
\r
9123 if (*str2 && remain >= 2) {
\r
9125 strcat(messageText, " ");
\r
9128 len = strlen(str2);
\r
9129 if (len > remain) len = remain;
\r
9130 strncat(messageText, str2, len);
\r
9132 messageText[MESSAGE_TEXT_MAX - 1] = NULLCHAR;
\r
9134 if (hwndMain == NULL || IsIconic(hwndMain)) return;
\r
9138 hdc = GetDC(hwndMain);
\r
9139 oldFont = SelectObject(hdc, font[boardSize][MESSAGE_FONT]->hf);
\r
9140 ExtTextOut(hdc, messageRect.left, messageRect.top, ETO_CLIPPED|ETO_OPAQUE,
\r
9141 &messageRect, messageText, strlen(messageText), NULL);
\r
9142 (void) SelectObject(hdc, oldFont);
\r
9143 (void) ReleaseDC(hwndMain, hdc);
\r
9147 DisplayError(char *str, int error)
\r
9149 char buf[MSG_SIZ*2], buf2[MSG_SIZ];
\r
9155 len = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
\r
9156 NULL, error, LANG_NEUTRAL,
\r
9157 (LPSTR) buf2, MSG_SIZ, NULL);
\r
9159 sprintf(buf, "%s:\n%s", str, buf2);
\r
9161 ErrorMap *em = errmap;
\r
9162 while (em->err != 0 && em->err != error) em++;
\r
9163 if (em->err != 0) {
\r
9164 sprintf(buf, "%s:\n%s", str, em->msg);
\r
9166 sprintf(buf, "%s:\nError code %d", str, error);
\r
9171 ErrorPopUp("Error", buf);
\r
9176 DisplayMoveError(char *str)
\r
9178 fromX = fromY = -1;
\r
9179 ClearHighlights();
\r
9180 DrawPosition(FALSE, NULL);
\r
9181 if (appData.popupMoveErrors) {
\r
9182 ErrorPopUp("Error", str);
\r
9184 DisplayMessage(str, "");
\r
9185 moveErrorMessageUp = TRUE;
\r
9190 DisplayFatalError(char *str, int error, int exitStatus)
\r
9192 char buf[2*MSG_SIZ], buf2[MSG_SIZ];
\r
9194 char *label = exitStatus ? "Fatal Error" : "Exiting";
\r
9197 len = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
\r
9198 NULL, error, LANG_NEUTRAL,
\r
9199 (LPSTR) buf2, MSG_SIZ, NULL);
\r
9201 sprintf(buf, "%s:\n%s", str, buf2);
\r
9203 ErrorMap *em = errmap;
\r
9204 while (em->err != 0 && em->err != error) em++;
\r
9205 if (em->err != 0) {
\r
9206 sprintf(buf, "%s:\n%s", str, em->msg);
\r
9208 sprintf(buf, "%s:\nError code %d", str, error);
\r
9213 if (appData.debugMode) {
\r
9214 fprintf(debugFP, "%s: %s\n", label, str);
\r
9216 if (appData.popupExitMessage) {
\r
9217 (void) MessageBox(hwndMain, str, label, MB_OK|
\r
9218 (exitStatus ? MB_ICONSTOP : MB_ICONINFORMATION));
\r
9220 ExitEvent(exitStatus);
\r
9225 DisplayInformation(char *str)
\r
9227 (void) MessageBox(hwndMain, str, "Information", MB_OK|MB_ICONINFORMATION);
\r
9232 DisplayNote(char *str)
\r
9234 ErrorPopUp("Note", str);
\r
9239 char *title, *question, *replyPrefix;
\r
9244 QuestionDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
9246 static QuestionParams *qp;
\r
9247 char reply[MSG_SIZ];
\r
9250 switch (message) {
\r
9251 case WM_INITDIALOG:
\r
9252 qp = (QuestionParams *) lParam;
\r
9253 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
9254 SetWindowText(hDlg, qp->title);
\r
9255 SetDlgItemText(hDlg, OPT_QuestionText, qp->question);
\r
9256 SetFocus(GetDlgItem(hDlg, OPT_QuestionInput));
\r
9260 switch (LOWORD(wParam)) {
\r
9262 strcpy(reply, qp->replyPrefix);
\r
9263 if (*reply) strcat(reply, " ");
\r
9264 len = strlen(reply);
\r
9265 GetDlgItemText(hDlg, OPT_QuestionInput, reply + len, sizeof(reply) - len);
\r
9266 strcat(reply, "\n");
\r
9267 OutputToProcess(qp->pr, reply, strlen(reply), &err);
\r
9268 EndDialog(hDlg, TRUE);
\r
9269 if (err) DisplayFatalError("Error writing to chess program", err, 1);
\r
9272 EndDialog(hDlg, FALSE);
\r
9283 AskQuestion(char* title, char *question, char *replyPrefix, ProcRef pr)
\r
9285 QuestionParams qp;
\r
9289 qp.question = question;
\r
9290 qp.replyPrefix = replyPrefix;
\r
9292 lpProc = MakeProcInstance((FARPROC)QuestionDialog, hInst);
\r
9293 DialogBoxParam(hInst, MAKEINTRESOURCE(DLG_Question),
\r
9294 hwndMain, (DLGPROC)lpProc, (LPARAM)&qp);
\r
9295 FreeProcInstance(lpProc);
\r
9298 /* [AS] Pick FRC position */
\r
9299 LRESULT CALLBACK NewGameFRC_Proc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
9301 static int * lpIndexFRC;
\r
9307 case WM_INITDIALOG:
\r
9308 lpIndexFRC = (int *) lParam;
\r
9310 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
9312 SendDlgItemMessage( hDlg, IDC_NFG_Edit, EM_SETLIMITTEXT, sizeof(buf)-1, 0 );
\r
9313 SetDlgItemInt( hDlg, IDC_NFG_Edit, *lpIndexFRC, TRUE );
\r
9314 SendDlgItemMessage( hDlg, IDC_NFG_Edit, EM_SETSEL, 0, -1 );
\r
9315 SetFocus(GetDlgItem(hDlg, IDC_NFG_Edit));
\r
9320 switch( LOWORD(wParam) ) {
\r
9322 *lpIndexFRC = GetDlgItemInt(hDlg, IDC_NFG_Edit, &index_is_ok, TRUE );
\r
9323 EndDialog( hDlg, 0 );
\r
9324 shuffleOpenings = TRUE; /* [HGM] shuffle: switch shuffling on for as long as we stay in current variant */
\r
9327 EndDialog( hDlg, 1 );
\r
9329 case IDC_NFG_Edit:
\r
9330 if( HIWORD(wParam) == EN_CHANGE ) {
\r
9331 GetDlgItemInt(hDlg, IDC_NFG_Edit, &index_is_ok, TRUE );
\r
9333 EnableWindow( GetDlgItem(hDlg, IDOK), index_is_ok );
\r
9336 case IDC_NFG_Random:
\r
9337 sprintf( buf, "%d", myrandom() ); /* [HGM] shuffle: no longer limit to 960 */
\r
9338 SetDlgItemText(hDlg, IDC_NFG_Edit, buf );
\r
9351 int index = appData.defaultFrcPosition;
\r
9352 FARPROC lpProc = MakeProcInstance( (FARPROC) NewGameFRC_Proc, hInst );
\r
9354 result = DialogBoxParam( hInst, MAKEINTRESOURCE(DLG_NewGameFRC), hwndMain, (DLGPROC)lpProc, (LPARAM)&index );
\r
9356 if( result == 0 ) {
\r
9357 appData.defaultFrcPosition = index;
\r
9363 /* [AS] Game list options */
\r
9369 static GLT_Item GLT_ItemInfo[] = {
\r
9370 { GLT_EVENT, "Event" },
\r
9371 { GLT_SITE, "Site" },
\r
9372 { GLT_DATE, "Date" },
\r
9373 { GLT_ROUND, "Round" },
\r
9374 { GLT_PLAYERS, "Players" },
\r
9375 { GLT_RESULT, "Result" },
\r
9376 { GLT_WHITE_ELO, "White Rating" },
\r
9377 { GLT_BLACK_ELO, "Black Rating" },
\r
9378 { GLT_TIME_CONTROL,"Time Control" },
\r
9379 { GLT_VARIANT, "Variant" },
\r
9380 { GLT_OUT_OF_BOOK,PGN_OUT_OF_BOOK },
\r
9384 const char * GLT_FindItem( char id )
\r
9386 const char * result = 0;
\r
9388 GLT_Item * list = GLT_ItemInfo;
\r
9390 while( list->id != 0 ) {
\r
9391 if( list->id == id ) {
\r
9392 result = list->name;
\r
9402 void GLT_AddToList( HWND hDlg, int iDlgItem, char id, int index )
\r
9404 const char * name = GLT_FindItem( id );
\r
9407 if( index >= 0 ) {
\r
9408 SendDlgItemMessage( hDlg, iDlgItem, LB_INSERTSTRING, index, (LPARAM) name );
\r
9411 SendDlgItemMessage( hDlg, iDlgItem, LB_ADDSTRING, 0, (LPARAM) name );
\r
9416 void GLT_TagsToList( HWND hDlg, char * tags )
\r
9420 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_RESETCONTENT, 0, 0 );
\r
9423 GLT_AddToList( hDlg, IDC_GameListTags, *pc, -1 );
\r
9427 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_ADDSTRING, 0, (LPARAM) "\t --- Hidden tags ---" );
\r
9429 pc = GLT_ALL_TAGS;
\r
9432 if( strchr( tags, *pc ) == 0 ) {
\r
9433 GLT_AddToList( hDlg, IDC_GameListTags, *pc, -1 );
\r
9438 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_SETCURSEL, 0, 0 );
\r
9441 char GLT_ListItemToTag( HWND hDlg, int index )
\r
9443 char result = '\0';
\r
9446 GLT_Item * list = GLT_ItemInfo;
\r
9448 if( SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETTEXT, index, (LPARAM) name ) != LB_ERR ) {
\r
9449 while( list->id != 0 ) {
\r
9450 if( strcmp( list->name, name ) == 0 ) {
\r
9451 result = list->id;
\r
9462 void GLT_MoveSelection( HWND hDlg, int delta )
\r
9464 int idx1 = (int) SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETCURSEL, 0, 0 );
\r
9465 int idx2 = idx1 + delta;
\r
9466 int count = (int) SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETCOUNT, 0, 0 );
\r
9468 if( idx1 >=0 && idx1 < count && idx2 >= 0 && idx2 < count ) {
\r
9471 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETTEXT, idx1, (LPARAM) buf );
\r
9472 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_DELETESTRING, idx1, 0 );
\r
9473 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_INSERTSTRING, idx2, (LPARAM) buf );
\r
9474 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_SETCURSEL, idx2, 0 );
\r
9478 LRESULT CALLBACK GameListOptions_Proc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
9480 static char glt[64];
\r
9481 static char * lpUserGLT;
\r
9485 case WM_INITDIALOG:
\r
9486 lpUserGLT = (char *) lParam;
\r
9488 strcpy( glt, lpUserGLT );
\r
9490 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
9492 /* Initialize list */
\r
9493 GLT_TagsToList( hDlg, glt );
\r
9495 SetFocus( GetDlgItem(hDlg, IDC_GameListTags) );
\r
9500 switch( LOWORD(wParam) ) {
\r
9503 char * pc = lpUserGLT;
\r
9505 // int cnt = (int) SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETCOUNT, 0, 0 );
\r
9509 id = GLT_ListItemToTag( hDlg, idx );
\r
9513 } while( id != '\0' );
\r
9515 EndDialog( hDlg, 0 );
\r
9518 EndDialog( hDlg, 1 );
\r
9521 case IDC_GLT_Default:
\r
9522 strcpy( glt, GLT_DEFAULT_TAGS );
\r
9523 GLT_TagsToList( hDlg, glt );
\r
9526 case IDC_GLT_Restore:
\r
9527 strcpy( glt, lpUserGLT );
\r
9528 GLT_TagsToList( hDlg, glt );
\r
9532 GLT_MoveSelection( hDlg, -1 );
\r
9535 case IDC_GLT_Down:
\r
9536 GLT_MoveSelection( hDlg, +1 );
\r
9546 int GameListOptions()
\r
9550 FARPROC lpProc = MakeProcInstance( (FARPROC) GameListOptions_Proc, hInst );
\r
9552 strcpy( glt, appData.gameListTags );
\r
9554 result = DialogBoxParam( hInst, MAKEINTRESOURCE(DLG_GameListOptions), hwndMain, (DLGPROC)lpProc, (LPARAM)glt );
\r
9556 if( result == 0 ) {
\r
9557 /* [AS] Memory leak here! */
\r
9558 appData.gameListTags = strdup( glt );
\r
9566 DisplayIcsInteractionTitle(char *str)
\r
9568 char consoleTitle[MSG_SIZ];
\r
9570 sprintf(consoleTitle, "%s: %s", szConsoleTitle, str);
\r
9571 SetWindowText(hwndConsole, consoleTitle);
\r
9575 DrawPosition(int fullRedraw, Board board)
\r
9577 HDCDrawPosition(NULL, (BOOLEAN) fullRedraw, board);
\r
9584 fromX = fromY = -1;
\r
9585 if (dragInfo.pos.x != -1 || dragInfo.pos.y != -1) {
\r
9586 dragInfo.pos.x = dragInfo.pos.y = -1;
\r
9587 dragInfo.pos.x = dragInfo.pos.y = -1;
\r
9588 dragInfo.lastpos = dragInfo.pos;
\r
9589 dragInfo.start.x = dragInfo.start.y = -1;
\r
9590 dragInfo.from = dragInfo.start;
\r
9592 DrawPosition(TRUE, NULL);
\r
9598 CommentPopUp(char *title, char *str)
\r
9600 HWND hwnd = GetActiveWindow();
\r
9601 EitherCommentPopUp(0, title, str, FALSE);
\r
9602 SetActiveWindow(hwnd);
\r
9606 CommentPopDown(void)
\r
9608 CheckMenuItem(GetMenu(hwndMain), IDM_EditComment, MF_UNCHECKED);
\r
9609 if (commentDialog) {
\r
9610 ShowWindow(commentDialog, SW_HIDE);
\r
9612 commentDialogUp = FALSE;
\r
9616 EditCommentPopUp(int index, char *title, char *str)
\r
9618 EitherCommentPopUp(index, title, str, TRUE);
\r
9625 MyPlaySound(&sounds[(int)SoundMove]);
\r
9628 VOID PlayIcsWinSound()
\r
9630 MyPlaySound(&sounds[(int)SoundIcsWin]);
\r
9633 VOID PlayIcsLossSound()
\r
9635 MyPlaySound(&sounds[(int)SoundIcsLoss]);
\r
9638 VOID PlayIcsDrawSound()
\r
9640 MyPlaySound(&sounds[(int)SoundIcsDraw]);
\r
9643 VOID PlayIcsUnfinishedSound()
\r
9645 MyPlaySound(&sounds[(int)SoundIcsUnfinished]);
\r
9651 MyPlaySound(&sounds[(int)SoundAlarm]);
\r
9659 consoleEcho = TRUE;
\r
9660 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
9661 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&consoleCF);
\r
9662 SendMessage(hInput, EM_SETBKGNDCOLOR, FALSE, consoleBackgroundColor);
\r
9671 consoleEcho = FALSE;
\r
9672 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
9673 /* This works OK: set text and background both to the same color */
\r
9675 cf.crTextColor = COLOR_ECHOOFF;
\r
9676 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&cf);
\r
9677 SendMessage(hInput, EM_SETBKGNDCOLOR, FALSE, cf.crTextColor);
\r
9680 /* No Raw()...? */
\r
9682 void Colorize(ColorClass cc, int continuation)
\r
9684 currentColorClass = cc;
\r
9685 consoleCF.dwMask = CFM_COLOR|CFM_BOLD|CFM_ITALIC|CFM_UNDERLINE|CFM_STRIKEOUT;
\r
9686 consoleCF.crTextColor = textAttribs[cc].color;
\r
9687 consoleCF.dwEffects = textAttribs[cc].effects;
\r
9688 if (!continuation) MyPlaySound(&textAttribs[cc].sound);
\r
9694 static char buf[MSG_SIZ];
\r
9695 DWORD bufsiz = MSG_SIZ;
\r
9697 if(appData.userName != NULL && appData.userName[0] != 0) {
\r
9698 return appData.userName; /* [HGM] username: prefer name selected by user over his system login */
\r
9700 if (!GetUserName(buf, &bufsiz)) {
\r
9701 /*DisplayError("Error getting user name", GetLastError());*/
\r
9702 strcpy(buf, "User");
\r
9710 static char buf[MSG_SIZ];
\r
9711 DWORD bufsiz = MSG_SIZ;
\r
9713 if (!GetComputerName(buf, &bufsiz)) {
\r
9714 /*DisplayError("Error getting host name", GetLastError());*/
\r
9715 strcpy(buf, "Unknown");
\r
9722 ClockTimerRunning()
\r
9724 return clockTimerEvent != 0;
\r
9730 if (clockTimerEvent == 0) return FALSE;
\r
9731 KillTimer(hwndMain, clockTimerEvent);
\r
9732 clockTimerEvent = 0;
\r
9737 StartClockTimer(long millisec)
\r
9739 clockTimerEvent = SetTimer(hwndMain, (UINT) CLOCK_TIMER_ID,
\r
9740 (UINT) millisec, NULL);
\r
9744 DisplayWhiteClock(long timeRemaining, int highlight)
\r
9747 char *flag = whiteFlag && gameMode == TwoMachinesPlay ? "(!)" : "";
\r
9749 if(appData.noGUI) return;
\r
9750 hdc = GetDC(hwndMain);
\r
9751 if (!IsIconic(hwndMain)) {
\r
9752 DisplayAClock(hdc, timeRemaining, highlight,
\r
9753 flipClock ? &blackRect : &whiteRect, "White", flag);
\r
9755 if (highlight && iconCurrent == iconBlack) {
\r
9756 iconCurrent = iconWhite;
\r
9757 PostMessage(hwndMain, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
9758 if (IsIconic(hwndMain)) {
\r
9759 DrawIcon(hdc, 2, 2, iconCurrent);
\r
9762 (void) ReleaseDC(hwndMain, hdc);
\r
9764 PostMessage(hwndConsole, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
9768 DisplayBlackClock(long timeRemaining, int highlight)
\r
9771 char *flag = blackFlag && gameMode == TwoMachinesPlay ? "(!)" : "";
\r
9773 if(appData.noGUI) return;
\r
9774 hdc = GetDC(hwndMain);
\r
9775 if (!IsIconic(hwndMain)) {
\r
9776 DisplayAClock(hdc, timeRemaining, highlight,
\r
9777 flipClock ? &whiteRect : &blackRect, "Black", flag);
\r
9779 if (highlight && iconCurrent == iconWhite) {
\r
9780 iconCurrent = iconBlack;
\r
9781 PostMessage(hwndMain, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
9782 if (IsIconic(hwndMain)) {
\r
9783 DrawIcon(hdc, 2, 2, iconCurrent);
\r
9786 (void) ReleaseDC(hwndMain, hdc);
\r
9788 PostMessage(hwndConsole, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
9793 LoadGameTimerRunning()
\r
9795 return loadGameTimerEvent != 0;
\r
9799 StopLoadGameTimer()
\r
9801 if (loadGameTimerEvent == 0) return FALSE;
\r
9802 KillTimer(hwndMain, loadGameTimerEvent);
\r
9803 loadGameTimerEvent = 0;
\r
9808 StartLoadGameTimer(long millisec)
\r
9810 loadGameTimerEvent = SetTimer(hwndMain, (UINT) LOAD_GAME_TIMER_ID,
\r
9811 (UINT) millisec, NULL);
\r
9819 char fileTitle[MSG_SIZ];
\r
9821 defName = DefaultFileName(appData.oldSaveStyle ? "gam" : "pgn");
\r
9822 f = OpenFileDialog(hwndMain, "a", defName,
\r
9823 appData.oldSaveStyle ? "gam" : "pgn",
\r
9825 "Save Game to File", NULL, fileTitle, NULL);
\r
9827 SaveGame(f, 0, "");
\r
9834 ScheduleDelayedEvent(DelayedEventCallback cb, long millisec)
\r
9836 if (delayedTimerEvent != 0) {
\r
9837 if (appData.debugMode) {
\r
9838 fprintf(debugFP, "ScheduleDelayedEvent: event already scheduled\n");
\r
9840 KillTimer(hwndMain, delayedTimerEvent);
\r
9841 delayedTimerEvent = 0;
\r
9842 delayedTimerCallback();
\r
9844 delayedTimerCallback = cb;
\r
9845 delayedTimerEvent = SetTimer(hwndMain, (UINT) DELAYED_TIMER_ID,
\r
9846 (UINT) millisec, NULL);
\r
9849 DelayedEventCallback
\r
9852 if (delayedTimerEvent) {
\r
9853 return delayedTimerCallback;
\r
9860 CancelDelayedEvent()
\r
9862 if (delayedTimerEvent) {
\r
9863 KillTimer(hwndMain, delayedTimerEvent);
\r
9864 delayedTimerEvent = 0;
\r
9868 DWORD GetWin32Priority(int nice)
\r
9869 { // [HGM] nice: translate Unix nice() value to indows priority class. (Code stolen from Polyglot 1.4w11)
\r
9871 REALTIME_PRIORITY_CLASS 0x00000100
\r
9872 HIGH_PRIORITY_CLASS 0x00000080
\r
9873 ABOVE_NORMAL_PRIORITY_CLASS 0x00008000
\r
9874 NORMAL_PRIORITY_CLASS 0x00000020
\r
9875 BELOW_NORMAL_PRIORITY_CLASS 0x00004000
\r
9876 IDLE_PRIORITY_CLASS 0x00000040
\r
9878 if (nice < -15) return 0x00000080;
\r
9879 if (nice < 0) return 0x00008000;
\r
9880 if (nice == 0) return 0x00000020;
\r
9881 if (nice < 15) return 0x00004000;
\r
9882 return 0x00000040;
\r
9885 /* Start a child process running the given program.
\r
9886 The process's standard output can be read from "from", and its
\r
9887 standard input can be written to "to".
\r
9888 Exit with fatal error if anything goes wrong.
\r
9889 Returns an opaque pointer that can be used to destroy the process
\r
9893 StartChildProcess(char *cmdLine, char *dir, ProcRef *pr)
\r
9895 #define BUFSIZE 4096
\r
9897 HANDLE hChildStdinRd, hChildStdinWr,
\r
9898 hChildStdoutRd, hChildStdoutWr;
\r
9899 HANDLE hChildStdinWrDup, hChildStdoutRdDup;
\r
9900 SECURITY_ATTRIBUTES saAttr;
\r
9902 PROCESS_INFORMATION piProcInfo;
\r
9903 STARTUPINFO siStartInfo;
\r
9905 char buf[MSG_SIZ];
\r
9908 if (appData.debugMode) {
\r
9909 fprintf(debugFP, "StartChildProcess (dir=\"%s\") %s\n", dir, cmdLine);
\r
9914 /* Set the bInheritHandle flag so pipe handles are inherited. */
\r
9915 saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
\r
9916 saAttr.bInheritHandle = TRUE;
\r
9917 saAttr.lpSecurityDescriptor = NULL;
\r
9920 * The steps for redirecting child's STDOUT:
\r
9921 * 1. Create anonymous pipe to be STDOUT for child.
\r
9922 * 2. Create a noninheritable duplicate of read handle,
\r
9923 * and close the inheritable read handle.
\r
9926 /* Create a pipe for the child's STDOUT. */
\r
9927 if (! CreatePipe(&hChildStdoutRd, &hChildStdoutWr, &saAttr, 0)) {
\r
9928 return GetLastError();
\r
9931 /* Duplicate the read handle to the pipe, so it is not inherited. */
\r
9932 fSuccess = DuplicateHandle(GetCurrentProcess(), hChildStdoutRd,
\r
9933 GetCurrentProcess(), &hChildStdoutRdDup, 0,
\r
9934 FALSE, /* not inherited */
\r
9935 DUPLICATE_SAME_ACCESS);
\r
9937 return GetLastError();
\r
9939 CloseHandle(hChildStdoutRd);
\r
9942 * The steps for redirecting child's STDIN:
\r
9943 * 1. Create anonymous pipe to be STDIN for child.
\r
9944 * 2. Create a noninheritable duplicate of write handle,
\r
9945 * and close the inheritable write handle.
\r
9948 /* Create a pipe for the child's STDIN. */
\r
9949 if (! CreatePipe(&hChildStdinRd, &hChildStdinWr, &saAttr, 0)) {
\r
9950 return GetLastError();
\r
9953 /* Duplicate the write handle to the pipe, so it is not inherited. */
\r
9954 fSuccess = DuplicateHandle(GetCurrentProcess(), hChildStdinWr,
\r
9955 GetCurrentProcess(), &hChildStdinWrDup, 0,
\r
9956 FALSE, /* not inherited */
\r
9957 DUPLICATE_SAME_ACCESS);
\r
9959 return GetLastError();
\r
9961 CloseHandle(hChildStdinWr);
\r
9963 /* Arrange to (1) look in dir for the child .exe file, and
\r
9964 * (2) have dir be the child's working directory. Interpret
\r
9965 * dir relative to the directory WinBoard loaded from. */
\r
9966 GetCurrentDirectory(MSG_SIZ, buf);
\r
9967 SetCurrentDirectory(installDir);
\r
9968 SetCurrentDirectory(dir);
\r
9970 /* Now create the child process. */
\r
9972 siStartInfo.cb = sizeof(STARTUPINFO);
\r
9973 siStartInfo.lpReserved = NULL;
\r
9974 siStartInfo.lpDesktop = NULL;
\r
9975 siStartInfo.lpTitle = NULL;
\r
9976 siStartInfo.dwFlags = STARTF_USESTDHANDLES;
\r
9977 siStartInfo.cbReserved2 = 0;
\r
9978 siStartInfo.lpReserved2 = NULL;
\r
9979 siStartInfo.hStdInput = hChildStdinRd;
\r
9980 siStartInfo.hStdOutput = hChildStdoutWr;
\r
9981 siStartInfo.hStdError = hChildStdoutWr;
\r
9983 fSuccess = CreateProcess(NULL,
\r
9984 cmdLine, /* command line */
\r
9985 NULL, /* process security attributes */
\r
9986 NULL, /* primary thread security attrs */
\r
9987 TRUE, /* handles are inherited */
\r
9988 DETACHED_PROCESS|CREATE_NEW_PROCESS_GROUP,
\r
9989 NULL, /* use parent's environment */
\r
9991 &siStartInfo, /* STARTUPINFO pointer */
\r
9992 &piProcInfo); /* receives PROCESS_INFORMATION */
\r
9994 err = GetLastError();
\r
9995 SetCurrentDirectory(buf); /* return to prev directory */
\r
10000 if (appData.niceEngines){ // [HGM] nice: adjust engine proc priority
\r
10001 if(appData.debugMode) fprintf(debugFP, "nice engine proc to %d\n", appData.niceEngines);
\r
10002 SetPriorityClass(piProcInfo.hProcess, GetWin32Priority(appData.niceEngines));
\r
10005 /* Close the handles we don't need in the parent */
\r
10006 CloseHandle(piProcInfo.hThread);
\r
10007 CloseHandle(hChildStdinRd);
\r
10008 CloseHandle(hChildStdoutWr);
\r
10010 /* Prepare return value */
\r
10011 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
10012 cp->kind = CPReal;
\r
10013 cp->hProcess = piProcInfo.hProcess;
\r
10014 cp->pid = piProcInfo.dwProcessId;
\r
10015 cp->hFrom = hChildStdoutRdDup;
\r
10016 cp->hTo = hChildStdinWrDup;
\r
10018 *pr = (void *) cp;
\r
10020 /* Klaus Friedel says that this Sleep solves a problem under Windows
\r
10021 2000 where engines sometimes don't see the initial command(s)
\r
10022 from WinBoard and hang. I don't understand how that can happen,
\r
10023 but the Sleep is harmless, so I've put it in. Others have also
\r
10024 reported what may be the same problem, so hopefully this will fix
\r
10025 it for them too. */
\r
10033 DestroyChildProcess(ProcRef pr, int/*boolean*/ signal)
\r
10035 ChildProc *cp; int result;
\r
10037 cp = (ChildProc *) pr;
\r
10038 if (cp == NULL) return;
\r
10040 switch (cp->kind) {
\r
10042 /* TerminateProcess is considered harmful, so... */
\r
10043 CloseHandle(cp->hTo); /* Closing this will give the child an EOF and hopefully kill it */
\r
10044 if (cp->hFrom) CloseHandle(cp->hFrom); /* if NULL, InputThread will close it */
\r
10045 /* The following doesn't work because the chess program
\r
10046 doesn't "have the same console" as WinBoard. Maybe
\r
10047 we could arrange for this even though neither WinBoard
\r
10048 nor the chess program uses a console for stdio? */
\r
10049 /*!!if (signal) GenerateConsoleCtrlEvent(CTRL_BREAK_EVENT, cp->pid);*/
\r
10051 /* [AS] Special termination modes for misbehaving programs... */
\r
10052 if( signal == 9 ) {
\r
10053 result = TerminateProcess( cp->hProcess, 0 );
\r
10055 if ( appData.debugMode) {
\r
10056 fprintf( debugFP, "Terminating process %lu, result=%d\n", cp->pid, result );
\r
10059 else if( signal == 10 ) {
\r
10060 DWORD dw = WaitForSingleObject( cp->hProcess, 3*1000 ); // Wait 3 seconds at most
\r
10062 if( dw != WAIT_OBJECT_0 ) {
\r
10063 result = TerminateProcess( cp->hProcess, 0 );
\r
10065 if ( appData.debugMode) {
\r
10066 fprintf( debugFP, "Process %lu still alive after timeout, killing... result=%d\n", cp->pid, result );
\r
10072 CloseHandle(cp->hProcess);
\r
10076 if (cp->hFrom) CloseHandle(cp->hFrom);
\r
10080 closesocket(cp->sock);
\r
10085 if (signal) send(cp->sock2, "\017", 1, 0); /* 017 = 15 = SIGTERM */
\r
10086 closesocket(cp->sock);
\r
10087 closesocket(cp->sock2);
\r
10095 InterruptChildProcess(ProcRef pr)
\r
10099 cp = (ChildProc *) pr;
\r
10100 if (cp == NULL) return;
\r
10101 switch (cp->kind) {
\r
10103 /* The following doesn't work because the chess program
\r
10104 doesn't "have the same console" as WinBoard. Maybe
\r
10105 we could arrange for this even though neither WinBoard
\r
10106 nor the chess program uses a console for stdio */
\r
10107 /*!!GenerateConsoleCtrlEvent(CTRL_C_EVENT, cp->pid);*/
\r
10112 /* Can't interrupt */
\r
10116 send(cp->sock2, "\002", 1, 0); /* 2 = SIGINT */
\r
10123 OpenTelnet(char *host, char *port, ProcRef *pr)
\r
10125 char cmdLine[MSG_SIZ];
\r
10127 if (port[0] == NULLCHAR) {
\r
10128 sprintf(cmdLine, "%s %s", appData.telnetProgram, host);
\r
10130 sprintf(cmdLine, "%s %s %s", appData.telnetProgram, host, port);
\r
10132 return StartChildProcess(cmdLine, "", pr);
\r
10136 /* Code to open TCP sockets */
\r
10139 OpenTCP(char *host, char *port, ProcRef *pr)
\r
10144 struct sockaddr_in sa, mysa;
\r
10145 struct hostent FAR *hp;
\r
10146 unsigned short uport;
\r
10147 WORD wVersionRequested;
\r
10150 /* Initialize socket DLL */
\r
10151 wVersionRequested = MAKEWORD(1, 1);
\r
10152 err = WSAStartup(wVersionRequested, &wsaData);
\r
10153 if (err != 0) return err;
\r
10155 /* Make socket */
\r
10156 if ((s = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
\r
10157 err = WSAGetLastError();
\r
10162 /* Bind local address using (mostly) don't-care values.
\r
10164 memset((char *) &mysa, 0, sizeof(struct sockaddr_in));
\r
10165 mysa.sin_family = AF_INET;
\r
10166 mysa.sin_addr.s_addr = INADDR_ANY;
\r
10167 uport = (unsigned short) 0;
\r
10168 mysa.sin_port = htons(uport);
\r
10169 if (bind(s, (struct sockaddr *) &mysa, sizeof(struct sockaddr_in))
\r
10170 == SOCKET_ERROR) {
\r
10171 err = WSAGetLastError();
\r
10176 /* Resolve remote host name */
\r
10177 memset((char *) &sa, 0, sizeof(struct sockaddr_in));
\r
10178 if (!(hp = gethostbyname(host))) {
\r
10179 unsigned int b0, b1, b2, b3;
\r
10181 err = WSAGetLastError();
\r
10183 if (sscanf(host, "%u.%u.%u.%u", &b0, &b1, &b2, &b3) == 4) {
\r
10184 hp = (struct hostent *) calloc(1, sizeof(struct hostent));
\r
10185 hp->h_addrtype = AF_INET;
\r
10186 hp->h_length = 4;
\r
10187 hp->h_addr_list = (char **) calloc(2, sizeof(char *));
\r
10188 hp->h_addr_list[0] = (char *) malloc(4);
\r
10189 hp->h_addr_list[0][0] = (char) b0;
\r
10190 hp->h_addr_list[0][1] = (char) b1;
\r
10191 hp->h_addr_list[0][2] = (char) b2;
\r
10192 hp->h_addr_list[0][3] = (char) b3;
\r
10198 sa.sin_family = hp->h_addrtype;
\r
10199 uport = (unsigned short) atoi(port);
\r
10200 sa.sin_port = htons(uport);
\r
10201 memcpy((char *) &sa.sin_addr, hp->h_addr, hp->h_length);
\r
10203 /* Make connection */
\r
10204 if (connect(s, (struct sockaddr *) &sa,
\r
10205 sizeof(struct sockaddr_in)) == SOCKET_ERROR) {
\r
10206 err = WSAGetLastError();
\r
10211 /* Prepare return value */
\r
10212 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
10213 cp->kind = CPSock;
\r
10215 *pr = (ProcRef *) cp;
\r
10221 OpenCommPort(char *name, ProcRef *pr)
\r
10226 char fullname[MSG_SIZ];
\r
10228 if (*name != '\\')
\r
10229 sprintf(fullname, "\\\\.\\%s", name);
\r
10231 strcpy(fullname, name);
\r
10233 h = CreateFile(name, GENERIC_READ | GENERIC_WRITE,
\r
10234 0, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
\r
10235 if (h == (HANDLE) -1) {
\r
10236 return GetLastError();
\r
10240 if (!SetCommState(h, (LPDCB) &dcb)) return GetLastError();
\r
10242 /* Accumulate characters until a 100ms pause, then parse */
\r
10243 ct.ReadIntervalTimeout = 100;
\r
10244 ct.ReadTotalTimeoutMultiplier = 0;
\r
10245 ct.ReadTotalTimeoutConstant = 0;
\r
10246 ct.WriteTotalTimeoutMultiplier = 0;
\r
10247 ct.WriteTotalTimeoutConstant = 0;
\r
10248 if (!SetCommTimeouts(h, (LPCOMMTIMEOUTS) &ct)) return GetLastError();
\r
10250 /* Prepare return value */
\r
10251 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
10252 cp->kind = CPComm;
\r
10255 *pr = (ProcRef *) cp;
\r
10261 OpenLoopback(ProcRef *pr)
\r
10263 DisplayFatalError("Not implemented", 0, 1);
\r
10269 OpenRcmd(char* host, char* user, char* cmd, ProcRef* pr)
\r
10273 SOCKET s, s2, s3;
\r
10274 struct sockaddr_in sa, mysa;
\r
10275 struct hostent FAR *hp;
\r
10276 unsigned short uport;
\r
10277 WORD wVersionRequested;
\r
10280 char stderrPortStr[MSG_SIZ];
\r
10282 /* Initialize socket DLL */
\r
10283 wVersionRequested = MAKEWORD(1, 1);
\r
10284 err = WSAStartup(wVersionRequested, &wsaData);
\r
10285 if (err != 0) return err;
\r
10287 /* Resolve remote host name */
\r
10288 memset((char *) &sa, 0, sizeof(struct sockaddr_in));
\r
10289 if (!(hp = gethostbyname(host))) {
\r
10290 unsigned int b0, b1, b2, b3;
\r
10292 err = WSAGetLastError();
\r
10294 if (sscanf(host, "%u.%u.%u.%u", &b0, &b1, &b2, &b3) == 4) {
\r
10295 hp = (struct hostent *) calloc(1, sizeof(struct hostent));
\r
10296 hp->h_addrtype = AF_INET;
\r
10297 hp->h_length = 4;
\r
10298 hp->h_addr_list = (char **) calloc(2, sizeof(char *));
\r
10299 hp->h_addr_list[0] = (char *) malloc(4);
\r
10300 hp->h_addr_list[0][0] = (char) b0;
\r
10301 hp->h_addr_list[0][1] = (char) b1;
\r
10302 hp->h_addr_list[0][2] = (char) b2;
\r
10303 hp->h_addr_list[0][3] = (char) b3;
\r
10309 sa.sin_family = hp->h_addrtype;
\r
10310 uport = (unsigned short) 514;
\r
10311 sa.sin_port = htons(uport);
\r
10312 memcpy((char *) &sa.sin_addr, hp->h_addr, hp->h_length);
\r
10314 /* Bind local socket to unused "privileged" port address
\r
10316 s = INVALID_SOCKET;
\r
10317 memset((char *) &mysa, 0, sizeof(struct sockaddr_in));
\r
10318 mysa.sin_family = AF_INET;
\r
10319 mysa.sin_addr.s_addr = INADDR_ANY;
\r
10320 for (fromPort = 1023;; fromPort--) {
\r
10321 if (fromPort < 0) {
\r
10323 return WSAEADDRINUSE;
\r
10325 if (s == INVALID_SOCKET) {
\r
10326 if ((s = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
\r
10327 err = WSAGetLastError();
\r
10332 uport = (unsigned short) fromPort;
\r
10333 mysa.sin_port = htons(uport);
\r
10334 if (bind(s, (struct sockaddr *) &mysa, sizeof(struct sockaddr_in))
\r
10335 == SOCKET_ERROR) {
\r
10336 err = WSAGetLastError();
\r
10337 if (err == WSAEADDRINUSE) continue;
\r
10341 if (connect(s, (struct sockaddr *) &sa,
\r
10342 sizeof(struct sockaddr_in)) == SOCKET_ERROR) {
\r
10343 err = WSAGetLastError();
\r
10344 if (err == WSAEADDRINUSE) {
\r
10355 /* Bind stderr local socket to unused "privileged" port address
\r
10357 s2 = INVALID_SOCKET;
\r
10358 memset((char *) &mysa, 0, sizeof(struct sockaddr_in));
\r
10359 mysa.sin_family = AF_INET;
\r
10360 mysa.sin_addr.s_addr = INADDR_ANY;
\r
10361 for (fromPort = 1023;; fromPort--) {
\r
10362 if (fromPort == prevStderrPort) continue; // don't reuse port
\r
10363 if (fromPort < 0) {
\r
10364 (void) closesocket(s);
\r
10366 return WSAEADDRINUSE;
\r
10368 if (s2 == INVALID_SOCKET) {
\r
10369 if ((s2 = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
\r
10370 err = WSAGetLastError();
\r
10376 uport = (unsigned short) fromPort;
\r
10377 mysa.sin_port = htons(uport);
\r
10378 if (bind(s2, (struct sockaddr *) &mysa, sizeof(struct sockaddr_in))
\r
10379 == SOCKET_ERROR) {
\r
10380 err = WSAGetLastError();
\r
10381 if (err == WSAEADDRINUSE) continue;
\r
10382 (void) closesocket(s);
\r
10386 if (listen(s2, 1) == SOCKET_ERROR) {
\r
10387 err = WSAGetLastError();
\r
10388 if (err == WSAEADDRINUSE) {
\r
10390 s2 = INVALID_SOCKET;
\r
10393 (void) closesocket(s);
\r
10394 (void) closesocket(s2);
\r
10400 prevStderrPort = fromPort; // remember port used
\r
10401 sprintf(stderrPortStr, "%d", fromPort);
\r
10403 if (send(s, stderrPortStr, strlen(stderrPortStr) + 1, 0) == SOCKET_ERROR) {
\r
10404 err = WSAGetLastError();
\r
10405 (void) closesocket(s);
\r
10406 (void) closesocket(s2);
\r
10411 if (send(s, UserName(), strlen(UserName()) + 1, 0) == SOCKET_ERROR) {
\r
10412 err = WSAGetLastError();
\r
10413 (void) closesocket(s);
\r
10414 (void) closesocket(s2);
\r
10418 if (*user == NULLCHAR) user = UserName();
\r
10419 if (send(s, user, strlen(user) + 1, 0) == SOCKET_ERROR) {
\r
10420 err = WSAGetLastError();
\r
10421 (void) closesocket(s);
\r
10422 (void) closesocket(s2);
\r
10426 if (send(s, cmd, strlen(cmd) + 1, 0) == SOCKET_ERROR) {
\r
10427 err = WSAGetLastError();
\r
10428 (void) closesocket(s);
\r
10429 (void) closesocket(s2);
\r
10434 if ((s3 = accept(s2, NULL, NULL)) == INVALID_SOCKET) {
\r
10435 err = WSAGetLastError();
\r
10436 (void) closesocket(s);
\r
10437 (void) closesocket(s2);
\r
10441 (void) closesocket(s2); /* Stop listening */
\r
10443 /* Prepare return value */
\r
10444 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
10445 cp->kind = CPRcmd;
\r
10448 *pr = (ProcRef *) cp;
\r
10455 AddInputSource(ProcRef pr, int lineByLine,
\r
10456 InputCallback func, VOIDSTAR closure)
\r
10458 InputSource *is, *is2 = NULL;
\r
10459 ChildProc *cp = (ChildProc *) pr;
\r
10461 is = (InputSource *) calloc(1, sizeof(InputSource));
\r
10462 is->lineByLine = lineByLine;
\r
10464 is->closure = closure;
\r
10465 is->second = NULL;
\r
10466 is->next = is->buf;
\r
10467 if (pr == NoProc) {
\r
10468 is->kind = CPReal;
\r
10469 consoleInputSource = is;
\r
10471 is->kind = cp->kind;
\r
10473 [AS] Try to avoid a race condition if the thread is given control too early:
\r
10474 we create all threads suspended so that the is->hThread variable can be
\r
10475 safely assigned, then let the threads start with ResumeThread.
\r
10477 switch (cp->kind) {
\r
10479 is->hFile = cp->hFrom;
\r
10480 cp->hFrom = NULL; /* now owned by InputThread */
\r
10482 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) NonOvlInputThread,
\r
10483 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
10487 is->hFile = cp->hFrom;
\r
10488 cp->hFrom = NULL; /* now owned by InputThread */
\r
10490 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) InputThread,
\r
10491 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
10495 is->sock = cp->sock;
\r
10497 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SocketInputThread,
\r
10498 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
10502 is2 = (InputSource *) calloc(1, sizeof(InputSource));
\r
10504 is->sock = cp->sock;
\r
10505 is->second = is2;
\r
10506 is2->sock = cp->sock2;
\r
10507 is2->second = is2;
\r
10509 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SocketInputThread,
\r
10510 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
10512 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SocketInputThread,
\r
10513 (LPVOID) is2, CREATE_SUSPENDED, &is2->id);
\r
10517 if( is->hThread != NULL ) {
\r
10518 ResumeThread( is->hThread );
\r
10521 if( is2 != NULL && is2->hThread != NULL ) {
\r
10522 ResumeThread( is2->hThread );
\r
10526 return (InputSourceRef) is;
\r
10530 RemoveInputSource(InputSourceRef isr)
\r
10534 is = (InputSource *) isr;
\r
10535 is->hThread = NULL; /* tell thread to stop */
\r
10536 CloseHandle(is->hThread);
\r
10537 if (is->second != NULL) {
\r
10538 is->second->hThread = NULL;
\r
10539 CloseHandle(is->second->hThread);
\r
10545 OutputToProcess(ProcRef pr, char *message, int count, int *outError)
\r
10548 int outCount = SOCKET_ERROR;
\r
10549 ChildProc *cp = (ChildProc *) pr;
\r
10550 static OVERLAPPED ovl;
\r
10552 if (pr == NoProc) {
\r
10553 ConsoleOutput(message, count, FALSE);
\r
10557 if (ovl.hEvent == NULL) {
\r
10558 ovl.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
\r
10560 ovl.Internal = ovl.InternalHigh = ovl.Offset = ovl.OffsetHigh = 0;
\r
10562 switch (cp->kind) {
\r
10565 outCount = send(cp->sock, message, count, 0);
\r
10566 if (outCount == SOCKET_ERROR) {
\r
10567 *outError = WSAGetLastError();
\r
10569 *outError = NO_ERROR;
\r
10574 if (WriteFile(((ChildProc *)pr)->hTo, message, count,
\r
10575 &dOutCount, NULL)) {
\r
10576 *outError = NO_ERROR;
\r
10577 outCount = (int) dOutCount;
\r
10579 *outError = GetLastError();
\r
10584 *outError = DoWriteFile(((ChildProc *)pr)->hTo, message, count,
\r
10585 &dOutCount, &ovl);
\r
10586 if (*outError == NO_ERROR) {
\r
10587 outCount = (int) dOutCount;
\r
10595 OutputToProcessDelayed(ProcRef pr, char *message, int count, int *outError,
\r
10598 /* Ignore delay, not implemented for WinBoard */
\r
10599 return OutputToProcess(pr, message, count, outError);
\r
10604 CmailSigHandlerCallBack(InputSourceRef isr, VOIDSTAR closure,
\r
10605 char *buf, int count, int error)
\r
10607 DisplayFatalError("Not implemented", 0, 1);
\r
10610 /* see wgamelist.c for Game List functions */
\r
10611 /* see wedittags.c for Edit Tags functions */
\r
10618 char buf[MSG_SIZ];
\r
10621 if (SearchPath(installDir, appData.icsLogon, NULL, MSG_SIZ, buf, &dummy)) {
\r
10622 f = fopen(buf, "r");
\r
10624 ProcessICSInitScript(f);
\r
10632 StartAnalysisClock()
\r
10634 if (analysisTimerEvent) return;
\r
10635 analysisTimerEvent = SetTimer(hwndMain, (UINT) ANALYSIS_TIMER_ID,
\r
10636 (UINT) 2000, NULL);
\r
10640 AnalysisDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
10642 static HANDLE hwndText;
\r
10644 static int sizeX, sizeY;
\r
10645 int newSizeX, newSizeY, flags;
\r
10648 switch (message) {
\r
10649 case WM_INITDIALOG: /* message: initialize dialog box */
\r
10650 /* Initialize the dialog items */
\r
10651 hwndText = GetDlgItem(hDlg, OPT_AnalysisText);
\r
10652 SetWindowText(hDlg, analysisTitle);
\r
10653 SetDlgItemText(hDlg, OPT_AnalysisText, analysisText);
\r
10654 /* Size and position the dialog */
\r
10655 if (!analysisDialog) {
\r
10656 analysisDialog = hDlg;
\r
10657 flags = SWP_NOZORDER;
\r
10658 GetClientRect(hDlg, &rect);
\r
10659 sizeX = rect.right;
\r
10660 sizeY = rect.bottom;
\r
10661 if (analysisX != CW_USEDEFAULT && analysisY != CW_USEDEFAULT &&
\r
10662 analysisW != CW_USEDEFAULT && analysisH != CW_USEDEFAULT) {
\r
10663 WINDOWPLACEMENT wp;
\r
10664 EnsureOnScreen(&analysisX, &analysisY, 0, 0);
\r
10665 wp.length = sizeof(WINDOWPLACEMENT);
\r
10667 wp.showCmd = SW_SHOW;
\r
10668 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
10669 wp.rcNormalPosition.left = analysisX;
\r
10670 wp.rcNormalPosition.right = analysisX + analysisW;
\r
10671 wp.rcNormalPosition.top = analysisY;
\r
10672 wp.rcNormalPosition.bottom = analysisY + analysisH;
\r
10673 SetWindowPlacement(hDlg, &wp);
\r
10675 GetClientRect(hDlg, &rect);
\r
10676 newSizeX = rect.right;
\r
10677 newSizeY = rect.bottom;
\r
10678 ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY,
\r
10679 newSizeX, newSizeY);
\r
10680 sizeX = newSizeX;
\r
10681 sizeY = newSizeY;
\r
10686 case WM_COMMAND: /* message: received a command */
\r
10687 switch (LOWORD(wParam)) {
\r
10689 if (appData.icsActive && appData.icsEngineAnalyze) { /* [DM] icsEngineAnalyze */
\r
10690 ExitAnalyzeMode();
\r
10702 newSizeX = LOWORD(lParam);
\r
10703 newSizeY = HIWORD(lParam);
\r
10704 ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY, newSizeX, newSizeY);
\r
10705 sizeX = newSizeX;
\r
10706 sizeY = newSizeY;
\r
10709 case WM_GETMINMAXINFO:
\r
10710 /* Prevent resizing window too small */
\r
10711 mmi = (MINMAXINFO *) lParam;
\r
10712 mmi->ptMinTrackSize.x = 100;
\r
10713 mmi->ptMinTrackSize.y = 100;
\r
10720 AnalysisPopUp(char* title, char* str)
\r
10726 EngineOutputPopUp();
\r
10729 if (str == NULL) str = "";
\r
10730 p = (char *) malloc(2 * strlen(str) + 2);
\r
10733 if (*str == '\n') *q++ = '\r';
\r
10737 if (analysisText != NULL) free(analysisText);
\r
10738 analysisText = p;
\r
10740 if (analysisDialog) {
\r
10741 SetWindowText(analysisDialog, title);
\r
10742 SetDlgItemText(analysisDialog, OPT_AnalysisText, analysisText);
\r
10743 ShowWindow(analysisDialog, SW_SHOW);
\r
10745 analysisTitle = title;
\r
10746 lpProc = MakeProcInstance((FARPROC)AnalysisDialog, hInst);
\r
10747 CreateDialog(hInst, MAKEINTRESOURCE(DLG_Analysis),
\r
10748 hwndMain, (DLGPROC)lpProc);
\r
10749 FreeProcInstance(lpProc);
\r
10751 analysisDialogUp = TRUE;
\r
10755 AnalysisPopDown()
\r
10757 if (analysisDialog) {
\r
10758 ShowWindow(analysisDialog, SW_HIDE);
\r
10760 analysisDialogUp = FALSE;
\r
10765 SetHighlights(int fromX, int fromY, int toX, int toY)
\r
10767 highlightInfo.sq[0].x = fromX;
\r
10768 highlightInfo.sq[0].y = fromY;
\r
10769 highlightInfo.sq[1].x = toX;
\r
10770 highlightInfo.sq[1].y = toY;
\r
10774 ClearHighlights()
\r
10776 highlightInfo.sq[0].x = highlightInfo.sq[0].y =
\r
10777 highlightInfo.sq[1].x = highlightInfo.sq[1].y = -1;
\r
10781 SetPremoveHighlights(int fromX, int fromY, int toX, int toY)
\r
10783 premoveHighlightInfo.sq[0].x = fromX;
\r
10784 premoveHighlightInfo.sq[0].y = fromY;
\r
10785 premoveHighlightInfo.sq[1].x = toX;
\r
10786 premoveHighlightInfo.sq[1].y = toY;
\r
10790 ClearPremoveHighlights()
\r
10792 premoveHighlightInfo.sq[0].x = premoveHighlightInfo.sq[0].y =
\r
10793 premoveHighlightInfo.sq[1].x = premoveHighlightInfo.sq[1].y = -1;
\r
10797 ShutDownFrontEnd()
\r
10799 if (saveSettingsOnExit) SaveSettings(settingsFileName);
\r
10800 DeleteClipboardTempFiles();
\r
10806 if (IsIconic(hwndMain))
\r
10807 ShowWindow(hwndMain, SW_RESTORE);
\r
10809 SetActiveWindow(hwndMain);
\r
10813 * Prototypes for animation support routines
\r
10815 static void ScreenSquare(int column, int row, POINT * pt);
\r
10816 static void Tween( POINT * start, POINT * mid, POINT * finish, int factor,
\r
10817 POINT frames[], int * nFrames);
\r
10821 AnimateAtomicCapture(int fromX, int fromY, int toX, int toY, int nFrames)
\r
10822 { // [HGM] atomic: animate blast wave
\r
10824 if(appData.debugMode) fprintf(debugFP, "exploding (%d,%d)\n", toX, toY);
\r
10825 explodeInfo.fromX = fromX;
\r
10826 explodeInfo.fromY = fromY;
\r
10827 explodeInfo.toX = toX;
\r
10828 explodeInfo.toY = toY;
\r
10829 for(i=1; i<nFrames; i++) {
\r
10830 explodeInfo.radius = (i*180)/(nFrames-1);
\r
10831 DrawPosition(FALSE, NULL);
\r
10832 Sleep(appData.animSpeed);
\r
10834 explodeInfo.radius = 0;
\r
10835 DrawPosition(TRUE, NULL);
\r
10838 #define kFactor 4
\r
10841 AnimateMove(board, fromX, fromY, toX, toY)
\r
10848 ChessSquare piece;
\r
10849 POINT start, finish, mid;
\r
10850 POINT frames[kFactor * 2 + 1];
\r
10853 if (!appData.animate) return;
\r
10854 if (doingSizing) return;
\r
10855 if (fromY < 0 || fromX < 0) return;
\r
10856 piece = board[fromY][fromX];
\r
10857 if (piece >= EmptySquare) return;
\r
10859 ScreenSquare(fromX, fromY, &start);
\r
10860 ScreenSquare(toX, toY, &finish);
\r
10862 /* All pieces except knights move in straight line */
\r
10863 if (piece != WhiteKnight && piece != BlackKnight) {
\r
10864 mid.x = start.x + (finish.x - start.x) / 2;
\r
10865 mid.y = start.y + (finish.y - start.y) / 2;
\r
10867 /* Knight: make diagonal movement then straight */
\r
10868 if (abs(toY - fromY) < abs(toX - fromX)) {
\r
10869 mid.x = start.x + (finish.x - start.x) / 2;
\r
10870 mid.y = finish.y;
\r
10872 mid.x = finish.x;
\r
10873 mid.y = start.y + (finish.y - start.y) / 2;
\r
10877 /* Don't use as many frames for very short moves */
\r
10878 if (abs(toY - fromY) + abs(toX - fromX) <= 2)
\r
10879 Tween(&start, &mid, &finish, kFactor - 1, frames, &nFrames);
\r
10881 Tween(&start, &mid, &finish, kFactor, frames, &nFrames);
\r
10883 animInfo.from.x = fromX;
\r
10884 animInfo.from.y = fromY;
\r
10885 animInfo.to.x = toX;
\r
10886 animInfo.to.y = toY;
\r
10887 animInfo.lastpos = start;
\r
10888 animInfo.piece = piece;
\r
10889 for (n = 0; n < nFrames; n++) {
\r
10890 animInfo.pos = frames[n];
\r
10891 DrawPosition(FALSE, NULL);
\r
10892 animInfo.lastpos = animInfo.pos;
\r
10893 Sleep(appData.animSpeed);
\r
10895 animInfo.pos = finish;
\r
10896 DrawPosition(FALSE, NULL);
\r
10897 animInfo.piece = EmptySquare;
\r
10898 if(gameInfo.variant == VariantAtomic &&
\r
10899 (board[toY][toX] != EmptySquare || fromX != toX && (piece == WhitePawn || piece == BlackPawn) ) )
\r
10900 AnimateAtomicCapture(fromX, fromY, toX, toY, 2*nFrames);
\r
10903 /* Convert board position to corner of screen rect and color */
\r
10906 ScreenSquare(column, row, pt)
\r
10907 int column; int row; POINT * pt;
\r
10910 pt->x = lineGap + ((BOARD_WIDTH-1)-column) * (squareSize + lineGap);
\r
10911 pt->y = lineGap + row * (squareSize + lineGap);
\r
10913 pt->x = lineGap + column * (squareSize + lineGap);
\r
10914 pt->y = lineGap + ((BOARD_HEIGHT-1)-row) * (squareSize + lineGap);
\r
10918 /* Generate a series of frame coords from start->mid->finish.
\r
10919 The movement rate doubles until the half way point is
\r
10920 reached, then halves back down to the final destination,
\r
10921 which gives a nice slow in/out effect. The algorithmn
\r
10922 may seem to generate too many intermediates for short
\r
10923 moves, but remember that the purpose is to attract the
\r
10924 viewers attention to the piece about to be moved and
\r
10925 then to where it ends up. Too few frames would be less
\r
10929 Tween(start, mid, finish, factor, frames, nFrames)
\r
10930 POINT * start; POINT * mid;
\r
10931 POINT * finish; int factor;
\r
10932 POINT frames[]; int * nFrames;
\r
10934 int n, fraction = 1, count = 0;
\r
10936 /* Slow in, stepping 1/16th, then 1/8th, ... */
\r
10937 for (n = 0; n < factor; n++)
\r
10939 for (n = 0; n < factor; n++) {
\r
10940 frames[count].x = start->x + (mid->x - start->x) / fraction;
\r
10941 frames[count].y = start->y + (mid->y - start->y) / fraction;
\r
10943 fraction = fraction / 2;
\r
10947 frames[count] = *mid;
\r
10950 /* Slow out, stepping 1/2, then 1/4, ... */
\r
10952 for (n = 0; n < factor; n++) {
\r
10953 frames[count].x = finish->x - (finish->x - mid->x) / fraction;
\r
10954 frames[count].y = finish->y - (finish->y - mid->y) / fraction;
\r
10956 fraction = fraction * 2;
\r
10958 *nFrames = count;
\r
10962 HistorySet( char movelist[][2*MOVE_LEN], int first, int last, int current )
\r
10967 sprintf( buf, "HistorySet: first=%d, last=%d, current=%d (%s)\n",
\r
10968 first, last, current, current >= 0 ? movelist[current] : "n/a" );
\r
10970 OutputDebugString( buf );
\r
10973 MoveHistorySet( movelist, first, last, current, pvInfoList );
\r
10975 EvalGraphSet( first, last, current, pvInfoList );
\r
10978 void SetProgramStats( FrontEndProgramStats * stats )
\r
10983 sprintf( buf, "SetStats for %d: depth=%d, nodes=%lu, score=%5.2f, time=%5.2f, pv=%s\n",
\r
10984 stats->which, stats->depth, stats->nodes, stats->score / 100.0, stats->time / 100.0, stats->pv == 0 ? "n/a" : stats->pv );
\r
10986 OutputDebugString( buf );
\r
10989 EngineOutputUpdate( stats );
\r