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 toX, int toY, int nFrames);
\r
109 ChessSquare piece;
\r
110 POINT pos; /* window coordinates of current pos */
\r
111 POINT lastpos; /* window coordinates of last pos - used for clipping */
\r
112 POINT from; /* board coordinates of the piece's orig pos */
\r
113 POINT to; /* board coordinates of the piece's new pos */
\r
116 static AnimInfo animInfo = { EmptySquare, {-1,-1}, {-1,-1}, {-1,-1} };
\r
119 POINT start; /* window coordinates of start pos */
\r
120 POINT pos; /* window coordinates of current pos */
\r
121 POINT lastpos; /* window coordinates of last pos - used for clipping */
\r
122 POINT from; /* board coordinates of the piece's orig pos */
\r
125 static DragInfo dragInfo = { {-1,-1}, {-1,-1}, {-1,-1}, {-1,-1} };
\r
128 POINT sq[2]; /* board coordinates of from, to squares */
\r
131 static HighlightInfo highlightInfo = { {{-1, -1}, {-1, -1}} };
\r
132 static HighlightInfo premoveHighlightInfo = { {{-1, -1}, {-1, -1}} };
\r
134 typedef struct { // [HGM] atomic
\r
138 static ExplodeInfo explodeInfo = {0, 0, 0};
\r
140 /* Window class names */
\r
141 char szAppName[] = "WinBoard";
\r
142 char szConsoleName[] = "WBConsole";
\r
144 /* Title bar text */
\r
145 char szTitle[] = "WinBoard";
\r
146 char szConsoleTitle[] = "ICS Interaction";
\r
149 char *settingsFileName;
\r
150 BOOLEAN saveSettingsOnExit;
\r
151 char installDir[MSG_SIZ];
\r
153 BoardSize boardSize;
\r
154 BOOLEAN chessProgram;
\r
155 static int boardX, boardY, consoleX, consoleY, consoleW, consoleH;
\r
156 static int squareSize, lineGap, minorSize;
\r
157 static int winWidth, winHeight;
\r
158 static RECT messageRect, whiteRect, blackRect, leftLogoRect, rightLogoRect; // [HGM] logo
\r
159 static int logoHeight = 0;
\r
160 static char messageText[MESSAGE_TEXT_MAX];
\r
161 static int clockTimerEvent = 0;
\r
162 static int loadGameTimerEvent = 0;
\r
163 static int analysisTimerEvent = 0;
\r
164 static DelayedEventCallback delayedTimerCallback;
\r
165 static int delayedTimerEvent = 0;
\r
166 static int buttonCount = 2;
\r
167 char *icsTextMenuString;
\r
169 char *firstChessProgramNames;
\r
170 char *secondChessProgramNames;
\r
172 #define ARG_MAX 128*1024 /* [AS] For Roger Brown's very long list! */
\r
174 #define PALETTESIZE 256
\r
176 HINSTANCE hInst; /* current instance */
\r
177 HWND hwndMain = NULL; /* root window*/
\r
178 HWND hwndConsole = NULL;
\r
179 BOOLEAN alwaysOnTop = FALSE;
\r
181 COLORREF lightSquareColor, darkSquareColor, whitePieceColor,
\r
182 blackPieceColor, highlightSquareColor, premoveHighlightColor;
\r
184 ColorClass currentColorClass;
\r
186 HWND hCommPort = NULL; /* currently open comm port */
\r
187 static HWND hwndPause; /* pause button */
\r
188 static HBITMAP pieceBitmap[3][(int) BlackPawn]; /* [HGM] nr of bitmaps referred to bP in stead of wK */
\r
189 static HBRUSH lightSquareBrush, darkSquareBrush,
\r
190 blackSquareBrush, /* [HGM] for band between board and holdings */
\r
191 explodeBrush, /* [HGM] atomic */
\r
192 whitePieceBrush, blackPieceBrush, iconBkgndBrush /*, outlineBrush*/;
\r
193 static POINT gridEndpoints[(BOARD_SIZE + 1) * 4];
\r
194 static DWORD gridVertexCounts[(BOARD_SIZE + 1) * 2];
\r
195 static HPEN gridPen = NULL;
\r
196 static HPEN highlightPen = NULL;
\r
197 static HPEN premovePen = NULL;
\r
198 static NPLOGPALETTE pLogPal;
\r
199 static BOOL paletteChanged = FALSE;
\r
200 static HICON iconWhite, iconBlack, iconCurrent;
\r
201 static int doingSizing = FALSE;
\r
202 static int lastSizing = 0;
\r
203 static int prevStderrPort;
\r
205 /* [AS] Support for background textures */
\r
206 #define BACK_TEXTURE_MODE_DISABLED 0
\r
207 #define BACK_TEXTURE_MODE_PLAIN 1
\r
208 #define BACK_TEXTURE_MODE_FULL_RANDOM 2
\r
210 static HBITMAP liteBackTexture = NULL;
\r
211 static HBITMAP darkBackTexture = NULL;
\r
212 static int liteBackTextureMode = BACK_TEXTURE_MODE_PLAIN;
\r
213 static int darkBackTextureMode = BACK_TEXTURE_MODE_PLAIN;
\r
214 static int backTextureSquareSize = 0;
\r
215 static struct { int x; int y; int mode; } backTextureSquareInfo[BOARD_SIZE][BOARD_SIZE];
\r
217 #if __GNUC__ && !defined(_winmajor)
\r
218 #define oldDialog 0 /* cygwin doesn't define _winmajor; mingw does */
\r
220 #define oldDialog (_winmajor < 4)
\r
223 char *defaultTextAttribs[] =
\r
225 COLOR_SHOUT, COLOR_SSHOUT, COLOR_CHANNEL1, COLOR_CHANNEL, COLOR_KIBITZ,
\r
226 COLOR_TELL, COLOR_CHALLENGE, COLOR_REQUEST, COLOR_SEEK, COLOR_NORMAL,
\r
236 int cliWidth, cliHeight;
\r
239 SizeInfo sizeInfo[] =
\r
241 { "tiny", 21, 0, 1, 1, 0, 0 },
\r
242 { "teeny", 25, 1, 1, 1, 0, 0 },
\r
243 { "dinky", 29, 1, 1, 1, 0, 0 },
\r
244 { "petite", 33, 1, 1, 1, 0, 0 },
\r
245 { "slim", 37, 2, 1, 0, 0, 0 },
\r
246 { "small", 40, 2, 1, 0, 0, 0 },
\r
247 { "mediocre", 45, 2, 1, 0, 0, 0 },
\r
248 { "middling", 49, 2, 0, 0, 0, 0 },
\r
249 { "average", 54, 2, 0, 0, 0, 0 },
\r
250 { "moderate", 58, 3, 0, 0, 0, 0 },
\r
251 { "medium", 64, 3, 0, 0, 0, 0 },
\r
252 { "bulky", 72, 3, 0, 0, 0, 0 },
\r
253 { "large", 80, 3, 0, 0, 0, 0 },
\r
254 { "big", 87, 3, 0, 0, 0, 0 },
\r
255 { "huge", 95, 3, 0, 0, 0, 0 },
\r
256 { "giant", 108, 3, 0, 0, 0, 0 },
\r
257 { "colossal", 116, 4, 0, 0, 0, 0 },
\r
258 { "titanic", 129, 4, 0, 0, 0, 0 },
\r
259 { NULL, 0, 0, 0, 0, 0, 0 }
\r
262 #define MF(x) {x, {{0,}, 0. }, {0, }, 0}
\r
263 MyFont fontRec[NUM_SIZES][NUM_FONTS] =
\r
265 { 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
266 { 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
267 { 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
268 { 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
269 { 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
270 { 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
271 { 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
272 { 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
273 { 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
274 { 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
275 { 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
276 { 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
277 { 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
278 { 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
279 { 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
280 { 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
281 { 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
282 { 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
285 MyFont *font[NUM_SIZES][NUM_FONTS];
\r
294 #define BUTTON_WIDTH (tinyLayout ? 16 : 32)
\r
295 #define N_BUTTONS 5
\r
297 MyButtonDesc buttonDesc[N_BUTTONS] =
\r
299 {"<<", IDM_ToStart, NULL, NULL},
\r
300 {"<", IDM_Backward, NULL, NULL},
\r
301 {"P", IDM_Pause, NULL, NULL},
\r
302 {">", IDM_Forward, NULL, NULL},
\r
303 {">>", IDM_ToEnd, NULL, NULL},
\r
306 int tinyLayout = 0, smallLayout = 0;
\r
307 #define MENU_BAR_ITEMS 6
\r
308 char *menuBarText[2][MENU_BAR_ITEMS+1] = {
\r
309 { "&File", "&Mode", "&Action", "&Step", "&Options", "&Help", NULL },
\r
310 { "&F", "&M", "&A", "&S", "&O", "&H", NULL },
\r
314 MySound sounds[(int)NSoundClasses];
\r
315 MyTextAttribs textAttribs[(int)NColorClasses];
\r
317 MyColorizeAttribs colorizeAttribs[] = {
\r
318 { (COLORREF)0, 0, "Shout Text" },
\r
319 { (COLORREF)0, 0, "SShout/CShout" },
\r
320 { (COLORREF)0, 0, "Channel 1 Text" },
\r
321 { (COLORREF)0, 0, "Channel Text" },
\r
322 { (COLORREF)0, 0, "Kibitz Text" },
\r
323 { (COLORREF)0, 0, "Tell Text" },
\r
324 { (COLORREF)0, 0, "Challenge Text" },
\r
325 { (COLORREF)0, 0, "Request Text" },
\r
326 { (COLORREF)0, 0, "Seek Text" },
\r
327 { (COLORREF)0, 0, "Normal Text" },
\r
328 { (COLORREF)0, 0, "None" }
\r
333 static char *commentTitle;
\r
334 static char *commentText;
\r
335 static int commentIndex;
\r
336 static Boolean editComment = FALSE;
\r
337 HWND commentDialog = NULL;
\r
338 BOOLEAN commentDialogUp = FALSE;
\r
339 static int commentX, commentY, commentH, commentW;
\r
341 static char *analysisTitle;
\r
342 static char *analysisText;
\r
343 HWND analysisDialog = NULL;
\r
344 BOOLEAN analysisDialogUp = FALSE;
\r
345 static int analysisX, analysisY, analysisH, analysisW;
\r
347 char errorTitle[MSG_SIZ];
\r
348 char errorMessage[2*MSG_SIZ];
\r
349 HWND errorDialog = NULL;
\r
350 BOOLEAN moveErrorMessageUp = FALSE;
\r
351 BOOLEAN consoleEcho = TRUE;
\r
352 CHARFORMAT consoleCF;
\r
353 COLORREF consoleBackgroundColor;
\r
355 char *programVersion;
\r
361 typedef int CPKind;
\r
370 SOCKET sock2; /* stderr socket for OpenRcmd */
\r
373 #define INPUT_SOURCE_BUF_SIZE 4096
\r
375 typedef struct _InputSource {
\r
382 char buf[INPUT_SOURCE_BUF_SIZE];
\r
386 InputCallback func;
\r
387 struct _InputSource *second; /* for stderr thread on CPRcmd */
\r
391 InputSource *consoleInputSource;
\r
396 VOID ConsoleOutput(char* data, int length, int forceVisible);
\r
397 VOID ConsoleCreate();
\r
399 ConsoleWndProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);
\r
400 VOID ColorizeTextPopup(HWND hwnd, ColorClass cc);
\r
401 VOID PrintCommSettings(FILE *f, char *name, DCB *dcb);
\r
402 VOID ParseCommSettings(char *arg, DCB *dcb);
\r
404 StartupDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);
\r
405 VOID APIENTRY MenuPopup(HWND hwnd, POINT pt, HMENU hmenu, UINT def);
\r
406 void ParseIcsTextMenu(char *icsTextMenuString);
\r
407 VOID PopUpMoveDialog(char firstchar);
\r
408 VOID PopUpNameDialog(char firstchar);
\r
409 VOID UpdateSampleText(HWND hDlg, int id, MyColorizeAttribs *mca);
\r
413 int GameListOptions();
\r
415 HWND moveHistoryDialog = NULL;
\r
416 BOOLEAN moveHistoryDialogUp = FALSE;
\r
418 WindowPlacement wpMoveHistory;
\r
420 HWND evalGraphDialog = NULL;
\r
421 BOOLEAN evalGraphDialogUp = FALSE;
\r
423 WindowPlacement wpEvalGraph;
\r
425 HWND engineOutputDialog = NULL;
\r
426 BOOLEAN engineOutputDialogUp = FALSE;
\r
428 WindowPlacement wpEngineOutput;
\r
430 VOID MoveHistoryPopUp();
\r
431 VOID MoveHistoryPopDown();
\r
432 VOID MoveHistorySet( char movelist[][2*MOVE_LEN], int first, int last, int current, ChessProgramStats_Move * pvInfo );
\r
433 BOOL MoveHistoryIsUp();
\r
435 VOID EvalGraphSet( int first, int last, int current, ChessProgramStats_Move * pvInfo );
\r
436 VOID EvalGraphPopUp();
\r
437 VOID EvalGraphPopDown();
\r
438 BOOL EvalGraphIsUp();
\r
440 VOID EngineOutputPopUp();
\r
441 VOID EngineOutputPopDown();
\r
442 BOOL EngineOutputIsUp();
\r
443 VOID EngineOutputUpdate( FrontEndProgramStats * stats );
\r
445 VOID GothicPopUp(char *title, VariantClass variant);
\r
447 * Setting "frozen" should disable all user input other than deleting
\r
448 * the window. We do this while engines are initializing themselves.
\r
450 static int frozen = 0;
\r
451 static int oldMenuItemState[MENU_BAR_ITEMS];
\r
457 if (frozen) return;
\r
459 hmenu = GetMenu(hwndMain);
\r
460 for (i=0; i<MENU_BAR_ITEMS; i++) {
\r
461 oldMenuItemState[i] = EnableMenuItem(hmenu, i, MF_BYPOSITION|MF_GRAYED);
\r
463 DrawMenuBar(hwndMain);
\r
466 /* Undo a FreezeUI */
\r
472 if (!frozen) return;
\r
474 hmenu = GetMenu(hwndMain);
\r
475 for (i=0; i<MENU_BAR_ITEMS; i++) {
\r
476 EnableMenuItem(hmenu, i, MF_BYPOSITION|oldMenuItemState[i]);
\r
478 DrawMenuBar(hwndMain);
\r
481 /*---------------------------------------------------------------------------*\
\r
485 \*---------------------------------------------------------------------------*/
\r
488 WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
\r
489 LPSTR lpCmdLine, int nCmdShow)
\r
492 HANDLE hAccelMain, hAccelNoAlt, hAccelNoICS;
\r
493 // INITCOMMONCONTROLSEX ex;
\r
497 LoadLibrary("RICHED32.DLL");
\r
498 consoleCF.cbSize = sizeof(CHARFORMAT);
\r
500 if (!InitApplication(hInstance)) {
\r
503 if (!InitInstance(hInstance, nCmdShow, lpCmdLine)) {
\r
507 // InitCommonControlsEx(&ex);
\r
508 InitCommonControls();
\r
510 hAccelMain = LoadAccelerators (hInstance, szAppName);
\r
511 hAccelNoAlt = LoadAccelerators (hInstance, "NO_ALT");
\r
512 hAccelNoICS = LoadAccelerators( hInstance, "NO_ICS"); /* [AS] No Ctrl-V on ICS!!! */
\r
514 /* Acquire and dispatch messages until a WM_QUIT message is received. */
\r
516 while (GetMessage(&msg, /* message structure */
\r
517 NULL, /* handle of window receiving the message */
\r
518 0, /* lowest message to examine */
\r
519 0)) /* highest message to examine */
\r
521 if (!(commentDialog && IsDialogMessage(commentDialog, &msg)) &&
\r
522 !(moveHistoryDialog && IsDialogMessage(moveHistoryDialog, &msg)) &&
\r
523 !(evalGraphDialog && IsDialogMessage(evalGraphDialog, &msg)) &&
\r
524 !(engineOutputDialog && IsDialogMessage(engineOutputDialog, &msg)) &&
\r
525 !(editTagsDialog && IsDialogMessage(editTagsDialog, &msg)) &&
\r
526 !(gameListDialog && IsDialogMessage(gameListDialog, &msg)) &&
\r
527 !(errorDialog && IsDialogMessage(errorDialog, &msg)) &&
\r
528 !(!frozen && TranslateAccelerator(hwndMain, hAccelMain, &msg)) &&
\r
529 !(!hwndConsole && TranslateAccelerator(hwndMain, hAccelNoICS, &msg)) &&
\r
530 !(!hwndConsole && TranslateAccelerator(hwndMain, hAccelNoAlt, &msg))) {
\r
531 TranslateMessage(&msg); /* Translates virtual key codes */
\r
532 DispatchMessage(&msg); /* Dispatches message to window */
\r
537 return (msg.wParam); /* Returns the value from PostQuitMessage */
\r
540 /*---------------------------------------------------------------------------*\
\r
542 * Initialization functions
\r
544 \*---------------------------------------------------------------------------*/
\r
547 InitApplication(HINSTANCE hInstance)
\r
551 /* Fill in window class structure with parameters that describe the */
\r
554 wc.style = CS_HREDRAW | CS_VREDRAW; /* Class style(s). */
\r
555 wc.lpfnWndProc = (WNDPROC)WndProc; /* Window Procedure */
\r
556 wc.cbClsExtra = 0; /* No per-class extra data. */
\r
557 wc.cbWndExtra = 0; /* No per-window extra data. */
\r
558 wc.hInstance = hInstance; /* Owner of this class */
\r
559 wc.hIcon = LoadIcon(hInstance, "icon_white");
\r
560 wc.hCursor = LoadCursor(NULL, IDC_ARROW); /* Cursor */
\r
561 wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1); /* Default color */
\r
562 wc.lpszMenuName = szAppName; /* Menu name from .RC */
\r
563 wc.lpszClassName = szAppName; /* Name to register as */
\r
565 /* Register the window class and return success/failure code. */
\r
566 if (!RegisterClass(&wc)) return FALSE;
\r
568 wc.style = CS_HREDRAW | CS_VREDRAW;
\r
569 wc.lpfnWndProc = (WNDPROC)ConsoleWndProc;
\r
571 wc.cbWndExtra = DLGWINDOWEXTRA;
\r
572 wc.hInstance = hInstance;
\r
573 wc.hIcon = LoadIcon(hInstance, "icon_white");
\r
574 wc.hCursor = LoadCursor(NULL, IDC_ARROW);
\r
575 wc.hbrBackground = (HBRUSH)(COLOR_MENU+1);
\r
576 wc.lpszMenuName = NULL;
\r
577 wc.lpszClassName = szConsoleName;
\r
579 if (!RegisterClass(&wc)) return FALSE;
\r
584 /* Set by InitInstance, used by EnsureOnScreen */
\r
585 int screenHeight, screenWidth;
\r
588 EnsureOnScreen(int *x, int *y)
\r
590 // int gap = GetSystemMetrics(SM_CYFRAME) + GetSystemMetrics(SM_CYCAPTION);
\r
591 /* Be sure window at (x,y) is not off screen (or even mostly off screen) */
\r
592 if (*x > screenWidth - 32) *x = 0;
\r
593 if (*y > screenHeight - 32) *y = 0;
\r
594 if (*x < 0) *x = 0;
\r
595 if (*y < 0) *y = 0;
\r
596 // if (*x < 10) *x = 10;
\r
597 // if (*y < gap) *y = gap;
\r
601 InitInstance(HINSTANCE hInstance, int nCmdShow, LPSTR lpCmdLine)
\r
603 HWND hwnd; /* Main window handle. */
\r
605 WINDOWPLACEMENT wp;
\r
608 hInst = hInstance; /* Store instance handle in our global variable */
\r
610 if (SearchPath(NULL, "WinBoard.exe", NULL, MSG_SIZ, installDir, &filepart)) {
\r
611 *filepart = NULLCHAR;
\r
613 GetCurrentDirectory(MSG_SIZ, installDir);
\r
615 gameInfo.boardWidth = gameInfo.boardHeight = 8; // [HGM] won't have open window otherwise
\r
616 InitAppData(lpCmdLine); /* Get run-time parameters */
\r
617 if (appData.debugMode) {
\r
618 debugFP = fopen(appData.nameOfDebugFile, "w");
\r
619 setbuf(debugFP, NULL);
\r
624 // InitEngineUCI( installDir, &first ); // [HGM] incorporated in InitBackEnd1()
\r
625 // InitEngineUCI( installDir, &second );
\r
627 /* Create a main window for this application instance. */
\r
628 hwnd = CreateWindow(szAppName, szTitle,
\r
629 (WS_OVERLAPPEDWINDOW & ~WS_MAXIMIZEBOX),
\r
630 CW_USEDEFAULT, 0, CW_USEDEFAULT, 0,
\r
631 NULL, NULL, hInstance, NULL);
\r
634 /* If window could not be created, return "failure" */
\r
639 /* [HGM] logo: Load logos if specified (must be done before InitDrawingSizes) */
\r
640 if( appData.firstLogo && appData.firstLogo[0] != NULLCHAR) {
\r
641 first.programLogo = LoadImage( 0, appData.firstLogo, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
643 if (first.programLogo == NULL && appData.debugMode) {
\r
644 fprintf( debugFP, "Unable to load logo bitmap '%s'\n", appData.firstLogo );
\r
646 } else if(appData.autoLogo) {
\r
647 if(appData.firstDirectory && appData.firstDirectory[0]) {
\r
649 sprintf(buf, "%s/logo.bmp", appData.firstDirectory);
\r
650 first.programLogo = LoadImage( 0, buf, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
654 if( appData.secondLogo && appData.secondLogo[0] != NULLCHAR) {
\r
655 second.programLogo = LoadImage( 0, appData.secondLogo, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
657 if (second.programLogo == NULL && appData.debugMode) {
\r
658 fprintf( debugFP, "Unable to load logo bitmap '%s'\n", appData.secondLogo );
\r
660 } else if(appData.autoLogo) {
\r
661 if(appData.secondDirectory && appData.secondDirectory[0]) {
\r
663 sprintf(buf, "%s\\logo.bmp", appData.secondDirectory);
\r
664 second.programLogo = LoadImage( 0, buf, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
668 iconWhite = LoadIcon(hInstance, "icon_white");
\r
669 iconBlack = LoadIcon(hInstance, "icon_black");
\r
670 iconCurrent = iconWhite;
\r
671 InitDrawingColors();
\r
672 screenHeight = GetSystemMetrics(SM_CYSCREEN);
\r
673 screenWidth = GetSystemMetrics(SM_CXSCREEN);
\r
674 for (ibs = (int) NUM_SIZES - 1; ibs >= 0; ibs--) {
\r
675 /* Compute window size for each board size, and use the largest
\r
676 size that fits on this screen as the default. */
\r
677 InitDrawingSizes((BoardSize)ibs, 0);
\r
678 if (boardSize == (BoardSize)-1 &&
\r
679 winHeight <= screenHeight
\r
680 - GetSystemMetrics(SM_CYFRAME) - GetSystemMetrics(SM_CYCAPTION) - 10
\r
681 && winWidth <= screenWidth) {
\r
682 boardSize = (BoardSize)ibs;
\r
686 InitDrawingSizes(boardSize, 0);
\r
688 buttonCount = GetSystemMetrics(SM_CMOUSEBUTTONS);
\r
690 /* [AS] Load textures if specified */
\r
691 ZeroMemory( &backTextureSquareInfo, sizeof(backTextureSquareInfo) );
\r
693 if( appData.liteBackTextureFile && appData.liteBackTextureFile[0] != NULLCHAR && appData.liteBackTextureFile[0] != '*' ) {
\r
694 liteBackTexture = LoadImage( 0, appData.liteBackTextureFile, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
695 liteBackTextureMode = appData.liteBackTextureMode;
\r
697 if (liteBackTexture == NULL && appData.debugMode) {
\r
698 fprintf( debugFP, "Unable to load lite texture bitmap '%s'\n", appData.liteBackTextureFile );
\r
702 if( appData.darkBackTextureFile && appData.darkBackTextureFile[0] != NULLCHAR && appData.darkBackTextureFile[0] != '*' ) {
\r
703 darkBackTexture = LoadImage( 0, appData.darkBackTextureFile, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
704 darkBackTextureMode = appData.darkBackTextureMode;
\r
706 if (darkBackTexture == NULL && appData.debugMode) {
\r
707 fprintf( debugFP, "Unable to load dark texture bitmap '%s'\n", appData.darkBackTextureFile );
\r
711 mysrandom( (unsigned) time(NULL) );
\r
713 /* [AS] Restore layout */
\r
714 if( wpMoveHistory.visible ) {
\r
715 MoveHistoryPopUp();
\r
718 if( wpEvalGraph.visible ) {
\r
722 if( wpEngineOutput.visible ) {
\r
723 EngineOutputPopUp();
\r
728 /* Make the window visible; update its client area; and return "success" */
\r
729 EnsureOnScreen(&boardX, &boardY);
\r
730 wp.length = sizeof(WINDOWPLACEMENT);
\r
732 wp.showCmd = nCmdShow;
\r
733 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
734 wp.rcNormalPosition.left = boardX;
\r
735 wp.rcNormalPosition.right = boardX + winWidth;
\r
736 wp.rcNormalPosition.top = boardY;
\r
737 wp.rcNormalPosition.bottom = boardY + winHeight;
\r
738 SetWindowPlacement(hwndMain, &wp);
\r
740 SetWindowPos(hwndMain, alwaysOnTop ? HWND_TOPMOST : HWND_NOTOPMOST,
\r
741 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE);
\r
744 /* [AS] Disable the FRC stuff if not playing the proper variant */
\r
745 if( gameInfo.variant != VariantFischeRandom ) {
\r
746 EnableMenuItem( GetMenu(hwndMain), IDM_NewGameFRC, MF_GRAYED );
\r
751 SetWindowPos(hwndConsole, alwaysOnTop ? HWND_TOPMOST : HWND_NOTOPMOST,
\r
752 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE);
\r
754 ShowWindow(hwndConsole, nCmdShow);
\r
756 UpdateWindow(hwnd);
\r
764 ArgString, ArgInt, ArgFloat, ArgBoolean, ArgTrue, ArgFalse, ArgNone,
\r
765 ArgColor, ArgAttribs, ArgFilename, ArgBoardSize, ArgFont, ArgCommSettings,
\r
766 ArgSettingsFilename
\r
774 String *pString; // ArgString
\r
775 int *pInt; // ArgInt
\r
776 float *pFloat; // ArgFloat
\r
777 Boolean *pBoolean; // ArgBoolean
\r
778 COLORREF *pColor; // ArgColor
\r
779 ColorClass cc; // ArgAttribs
\r
780 String *pFilename; // ArgFilename
\r
781 BoardSize *pBoardSize; // ArgBoardSize
\r
782 int whichFont; // ArgFont
\r
783 DCB *pDCB; // ArgCommSettings
\r
784 String *pFilename; // ArgSettingsFilename
\r
792 ArgDescriptor argDescriptors[] = {
\r
793 /* positional arguments */
\r
794 { "loadGameFile", ArgFilename, (LPVOID) &appData.loadGameFile, FALSE },
\r
795 { "", ArgNone, NULL },
\r
796 /* keyword arguments */
\r
797 { "whitePieceColor", ArgColor, (LPVOID) &whitePieceColor, TRUE },
\r
798 { "wpc", ArgColor, (LPVOID) &whitePieceColor, FALSE },
\r
799 { "blackPieceColor", ArgColor, (LPVOID) &blackPieceColor, TRUE },
\r
800 { "bpc", ArgColor, (LPVOID) &blackPieceColor, FALSE },
\r
801 { "lightSquareColor", ArgColor, (LPVOID) &lightSquareColor, TRUE },
\r
802 { "lsc", ArgColor, (LPVOID) &lightSquareColor, FALSE },
\r
803 { "darkSquareColor", ArgColor, (LPVOID) &darkSquareColor, TRUE },
\r
804 { "dsc", ArgColor, (LPVOID) &darkSquareColor, FALSE },
\r
805 { "highlightSquareColor", ArgColor, (LPVOID) &highlightSquareColor, TRUE },
\r
806 { "hsc", ArgColor, (LPVOID) &highlightSquareColor, FALSE },
\r
807 { "premoveHighlightColor", ArgColor, (LPVOID) &premoveHighlightColor, TRUE },
\r
808 { "phc", ArgColor, (LPVOID) &premoveHighlightColor, FALSE },
\r
809 { "movesPerSession", ArgInt, (LPVOID) &appData.movesPerSession, TRUE },
\r
810 { "mps", ArgInt, (LPVOID) &appData.movesPerSession, FALSE },
\r
811 { "initString", ArgString, (LPVOID) &appData.initString, FALSE },
\r
812 { "firstInitString", ArgString, (LPVOID) &appData.initString, FALSE },
\r
813 { "secondInitString", ArgString, (LPVOID) &appData.secondInitString, FALSE },
\r
814 { "firstComputerString", ArgString, (LPVOID) &appData.firstComputerString,
\r
816 { "secondComputerString", ArgString, (LPVOID) &appData.secondComputerString,
\r
818 { "firstChessProgram", ArgFilename, (LPVOID) &appData.firstChessProgram,
\r
820 { "fcp", ArgFilename, (LPVOID) &appData.firstChessProgram, FALSE },
\r
821 { "secondChessProgram", ArgFilename, (LPVOID) &appData.secondChessProgram,
\r
823 { "scp", ArgFilename, (LPVOID) &appData.secondChessProgram, FALSE },
\r
824 { "firstPlaysBlack", ArgBoolean, (LPVOID) &appData.firstPlaysBlack, FALSE },
\r
825 { "fb", ArgTrue, (LPVOID) &appData.firstPlaysBlack, FALSE },
\r
826 { "xfb", ArgFalse, (LPVOID) &appData.firstPlaysBlack, FALSE },
\r
827 { "-fb", ArgFalse, (LPVOID) &appData.firstPlaysBlack, FALSE },
\r
828 { "noChessProgram", ArgBoolean, (LPVOID) &appData.noChessProgram, FALSE },
\r
829 { "ncp", ArgTrue, (LPVOID) &appData.noChessProgram, FALSE },
\r
830 { "xncp", ArgFalse, (LPVOID) &appData.noChessProgram, FALSE },
\r
831 { "-ncp", ArgFalse, (LPVOID) &appData.noChessProgram, FALSE },
\r
832 { "firstHost", ArgString, (LPVOID) &appData.firstHost, FALSE },
\r
833 { "fh", ArgString, (LPVOID) &appData.firstHost, FALSE },
\r
834 { "secondHost", ArgString, (LPVOID) &appData.secondHost, FALSE },
\r
835 { "sh", ArgString, (LPVOID) &appData.secondHost, FALSE },
\r
836 { "firstDirectory", ArgFilename, (LPVOID) &appData.firstDirectory, FALSE },
\r
837 { "fd", ArgFilename, (LPVOID) &appData.firstDirectory, FALSE },
\r
838 { "secondDirectory", ArgFilename, (LPVOID) &appData.secondDirectory, FALSE },
\r
839 { "sd", ArgFilename, (LPVOID) &appData.secondDirectory, FALSE },
\r
840 /*!!bitmapDirectory?*/
\r
841 { "remoteShell", ArgFilename, (LPVOID) &appData.remoteShell, FALSE },
\r
842 { "rsh", ArgFilename, (LPVOID) &appData.remoteShell, FALSE },
\r
843 { "remoteUser", ArgString, (LPVOID) &appData.remoteUser, FALSE },
\r
844 { "ruser", ArgString, (LPVOID) &appData.remoteUser, FALSE },
\r
845 { "timeDelay", ArgFloat, (LPVOID) &appData.timeDelay, TRUE },
\r
846 { "td", ArgFloat, (LPVOID) &appData.timeDelay, FALSE },
\r
847 { "timeControl", ArgString, (LPVOID) &appData.timeControl, TRUE },
\r
848 { "tc", ArgString, (LPVOID) &appData.timeControl, FALSE },
\r
849 { "timeIncrement", ArgInt, (LPVOID) &appData.timeIncrement, TRUE },
\r
850 { "inc", ArgInt, (LPVOID) &appData.timeIncrement, FALSE },
\r
851 { "internetChessServerMode", ArgBoolean, (LPVOID) &appData.icsActive, FALSE },
\r
852 { "ics", ArgTrue, (LPVOID) &appData.icsActive, FALSE },
\r
853 { "xics", ArgFalse, (LPVOID) &appData.icsActive, FALSE },
\r
854 { "-ics", ArgFalse, (LPVOID) &appData.icsActive, FALSE },
\r
855 { "internetChessServerHost", ArgString, (LPVOID) &appData.icsHost, FALSE },
\r
856 { "icshost", ArgString, (LPVOID) &appData.icsHost, FALSE },
\r
857 { "internetChessServerPort", ArgString, (LPVOID) &appData.icsPort, FALSE },
\r
858 { "icsport", ArgString, (LPVOID) &appData.icsPort, FALSE },
\r
859 { "internetChessServerCommPort", ArgString, (LPVOID) &appData.icsCommPort, FALSE },
\r
860 { "icscomm", ArgString, (LPVOID) &appData.icsCommPort, FALSE },
\r
861 { "internetChessServerComPort", ArgString, (LPVOID) &appData.icsCommPort, FALSE },
\r
862 { "icscom", ArgString, (LPVOID) &appData.icsCommPort, FALSE },
\r
863 { "internetChessServerLogonScript", ArgFilename, (LPVOID) &appData.icsLogon, FALSE },
\r
864 { "icslogon", ArgFilename, (LPVOID) &appData.icsLogon, FALSE },
\r
865 { "useTelnet", ArgBoolean, (LPVOID) &appData.useTelnet, FALSE },
\r
866 { "telnet", ArgTrue, (LPVOID) &appData.useTelnet, FALSE },
\r
867 { "xtelnet", ArgFalse, (LPVOID) &appData.useTelnet, FALSE },
\r
868 { "-telnet", ArgFalse, (LPVOID) &appData.useTelnet, FALSE },
\r
869 { "telnetProgram", ArgFilename, (LPVOID) &appData.telnetProgram, FALSE },
\r
870 { "icshelper", ArgFilename, (LPVOID) &appData.icsHelper, FALSE },
\r
871 { "gateway", ArgString, (LPVOID) &appData.gateway, FALSE },
\r
872 { "loadGameFile", ArgFilename, (LPVOID) &appData.loadGameFile, FALSE },
\r
873 { "lgf", ArgFilename, (LPVOID) &appData.loadGameFile, FALSE },
\r
874 { "loadGameIndex", ArgInt, (LPVOID) &appData.loadGameIndex, FALSE },
\r
875 { "lgi", ArgInt, (LPVOID) &appData.loadGameIndex, FALSE },
\r
876 { "saveGameFile", ArgFilename, (LPVOID) &appData.saveGameFile, TRUE },
\r
877 { "sgf", ArgFilename, (LPVOID) &appData.saveGameFile, FALSE },
\r
878 { "autoSaveGames", ArgBoolean, (LPVOID) &appData.autoSaveGames, TRUE },
\r
879 { "autosave", ArgTrue, (LPVOID) &appData.autoSaveGames, FALSE },
\r
880 { "xautosave", ArgFalse, (LPVOID) &appData.autoSaveGames, FALSE },
\r
881 { "-autosave", ArgFalse, (LPVOID) &appData.autoSaveGames, FALSE },
\r
882 { "loadPositionFile", ArgFilename, (LPVOID) &appData.loadPositionFile, FALSE },
\r
883 { "lpf", ArgFilename, (LPVOID) &appData.loadPositionFile, FALSE },
\r
884 { "loadPositionIndex", ArgInt, (LPVOID) &appData.loadPositionIndex, FALSE },
\r
885 { "lpi", ArgInt, (LPVOID) &appData.loadPositionIndex, FALSE },
\r
886 { "savePositionFile", ArgFilename, (LPVOID) &appData.savePositionFile, FALSE },
\r
887 { "spf", ArgFilename, (LPVOID) &appData.savePositionFile, FALSE },
\r
888 { "matchMode", ArgBoolean, (LPVOID) &appData.matchMode, FALSE },
\r
889 { "mm", ArgTrue, (LPVOID) &appData.matchMode, FALSE },
\r
890 { "xmm", ArgFalse, (LPVOID) &appData.matchMode, FALSE },
\r
891 { "-mm", ArgFalse, (LPVOID) &appData.matchMode, FALSE },
\r
892 { "matchGames", ArgInt, (LPVOID) &appData.matchGames, FALSE },
\r
893 { "mg", ArgInt, (LPVOID) &appData.matchGames, FALSE },
\r
894 { "monoMode", ArgBoolean, (LPVOID) &appData.monoMode, TRUE },
\r
895 { "mono", ArgTrue, (LPVOID) &appData.monoMode, FALSE },
\r
896 { "xmono", ArgFalse, (LPVOID) &appData.monoMode, FALSE },
\r
897 { "-mono", ArgFalse, (LPVOID) &appData.monoMode, FALSE },
\r
898 { "debugMode", ArgBoolean, (LPVOID) &appData.debugMode, FALSE },
\r
899 { "debug", ArgTrue, (LPVOID) &appData.debugMode, FALSE },
\r
900 { "xdebug", ArgFalse, (LPVOID) &appData.debugMode, FALSE },
\r
901 { "-debug", ArgFalse, (LPVOID) &appData.debugMode, FALSE },
\r
902 { "clockMode", ArgBoolean, (LPVOID) &appData.clockMode, FALSE },
\r
903 { "clock", ArgTrue, (LPVOID) &appData.clockMode, FALSE },
\r
904 { "xclock", ArgFalse, (LPVOID) &appData.clockMode, FALSE },
\r
905 { "-clock", ArgFalse, (LPVOID) &appData.clockMode, FALSE },
\r
906 { "searchTime", ArgString, (LPVOID) &appData.searchTime, FALSE },
\r
907 { "st", ArgString, (LPVOID) &appData.searchTime, FALSE },
\r
908 { "searchDepth", ArgInt, (LPVOID) &appData.searchDepth, FALSE },
\r
909 { "depth", ArgInt, (LPVOID) &appData.searchDepth, FALSE },
\r
910 { "showCoords", ArgBoolean, (LPVOID) &appData.showCoords, TRUE },
\r
911 { "coords", ArgTrue, (LPVOID) &appData.showCoords, FALSE },
\r
912 { "xcoords", ArgFalse, (LPVOID) &appData.showCoords, FALSE },
\r
913 { "-coords", ArgFalse, (LPVOID) &appData.showCoords, FALSE },
\r
914 { "showThinking", ArgBoolean, (LPVOID) &appData.showThinking, TRUE },
\r
915 { "thinking", ArgTrue, (LPVOID) &appData.showThinking, FALSE },
\r
916 { "xthinking", ArgFalse, (LPVOID) &appData.showThinking, FALSE },
\r
917 { "-thinking", ArgFalse, (LPVOID) &appData.showThinking, FALSE },
\r
918 { "ponderNextMove", ArgBoolean, (LPVOID) &appData.ponderNextMove, TRUE },
\r
919 { "ponder", ArgTrue, (LPVOID) &appData.ponderNextMove, FALSE },
\r
920 { "xponder", ArgFalse, (LPVOID) &appData.ponderNextMove, FALSE },
\r
921 { "-ponder", ArgFalse, (LPVOID) &appData.ponderNextMove, FALSE },
\r
922 { "periodicUpdates", ArgBoolean, (LPVOID) &appData.periodicUpdates, TRUE },
\r
923 { "periodic", ArgTrue, (LPVOID) &appData.periodicUpdates, FALSE },
\r
924 { "xperiodic", ArgFalse, (LPVOID) &appData.periodicUpdates, FALSE },
\r
925 { "-periodic", ArgFalse, (LPVOID) &appData.periodicUpdates, FALSE },
\r
926 { "popupExitMessage", ArgBoolean, (LPVOID) &appData.popupExitMessage, TRUE },
\r
927 { "exit", ArgTrue, (LPVOID) &appData.popupExitMessage, FALSE },
\r
928 { "xexit", ArgFalse, (LPVOID) &appData.popupExitMessage, FALSE },
\r
929 { "-exit", ArgFalse, (LPVOID) &appData.popupExitMessage, FALSE },
\r
930 { "popupMoveErrors", ArgBoolean, (LPVOID) &appData.popupMoveErrors, TRUE },
\r
931 { "popup", ArgTrue, (LPVOID) &appData.popupMoveErrors, FALSE },
\r
932 { "xpopup", ArgFalse, (LPVOID) &appData.popupMoveErrors, FALSE },
\r
933 { "-popup", ArgFalse, (LPVOID) &appData.popupMoveErrors, FALSE },
\r
934 { "popUpErrors", ArgBoolean, (LPVOID) &appData.popupMoveErrors,
\r
935 FALSE }, /* only so that old WinBoard.ini files from betas can be read */
\r
936 { "clockFont", ArgFont, (LPVOID) CLOCK_FONT, TRUE },
\r
937 { "messageFont", ArgFont, (LPVOID) MESSAGE_FONT, TRUE },
\r
938 { "coordFont", ArgFont, (LPVOID) COORD_FONT, TRUE },
\r
939 { "tagsFont", ArgFont, (LPVOID) EDITTAGS_FONT, TRUE },
\r
940 { "commentFont", ArgFont, (LPVOID) COMMENT_FONT, TRUE },
\r
941 { "icsFont", ArgFont, (LPVOID) CONSOLE_FONT, TRUE },
\r
942 { "moveHistoryFont", ArgFont, (LPVOID) MOVEHISTORY_FONT, TRUE }, /* [AS] */
\r
943 { "boardSize", ArgBoardSize, (LPVOID) &boardSize,
\r
944 TRUE }, /* must come after all fonts */
\r
945 { "size", ArgBoardSize, (LPVOID) &boardSize, FALSE },
\r
946 { "ringBellAfterMoves", ArgBoolean, (LPVOID) &appData.ringBellAfterMoves,
\r
947 FALSE }, /* historical; kept only so old winboard.ini files will parse */
\r
948 { "alwaysOnTop", ArgBoolean, (LPVOID) &alwaysOnTop, TRUE },
\r
949 { "top", ArgTrue, (LPVOID) &alwaysOnTop, FALSE },
\r
950 { "xtop", ArgFalse, (LPVOID) &alwaysOnTop, FALSE },
\r
951 { "-top", ArgFalse, (LPVOID) &alwaysOnTop, FALSE },
\r
952 { "autoCallFlag", ArgBoolean, (LPVOID) &appData.autoCallFlag, TRUE },
\r
953 { "autoflag", ArgTrue, (LPVOID) &appData.autoCallFlag, FALSE },
\r
954 { "xautoflag", ArgFalse, (LPVOID) &appData.autoCallFlag, FALSE },
\r
955 { "-autoflag", ArgFalse, (LPVOID) &appData.autoCallFlag, FALSE },
\r
956 { "autoComment", ArgBoolean, (LPVOID) &appData.autoComment, TRUE },
\r
957 { "autocomm", ArgTrue, (LPVOID) &appData.autoComment, FALSE },
\r
958 { "xautocomm", ArgFalse, (LPVOID) &appData.autoComment, FALSE },
\r
959 { "-autocomm", ArgFalse, (LPVOID) &appData.autoComment, FALSE },
\r
960 { "autoObserve", ArgBoolean, (LPVOID) &appData.autoObserve, TRUE },
\r
961 { "autobs", ArgTrue, (LPVOID) &appData.autoObserve, FALSE },
\r
962 { "xautobs", ArgFalse, (LPVOID) &appData.autoObserve, FALSE },
\r
963 { "-autobs", ArgFalse, (LPVOID) &appData.autoObserve, FALSE },
\r
964 { "flipView", ArgBoolean, (LPVOID) &appData.flipView, FALSE },
\r
965 { "flip", ArgTrue, (LPVOID) &appData.flipView, FALSE },
\r
966 { "xflip", ArgFalse, (LPVOID) &appData.flipView, FALSE },
\r
967 { "-flip", ArgFalse, (LPVOID) &appData.flipView, FALSE },
\r
968 { "autoFlipView", ArgBoolean, (LPVOID) &appData.autoFlipView, TRUE },
\r
969 { "autoflip", ArgTrue, (LPVOID) &appData.autoFlipView, FALSE },
\r
970 { "xautoflip", ArgFalse, (LPVOID) &appData.autoFlipView, FALSE },
\r
971 { "-autoflip", ArgFalse, (LPVOID) &appData.autoFlipView, FALSE },
\r
972 { "autoRaiseBoard", ArgBoolean, (LPVOID) &appData.autoRaiseBoard, TRUE },
\r
973 { "autoraise", ArgTrue, (LPVOID) &appData.autoRaiseBoard, FALSE },
\r
974 { "xautoraise", ArgFalse, (LPVOID) &appData.autoRaiseBoard, FALSE },
\r
975 { "-autoraise", ArgFalse, (LPVOID) &appData.autoRaiseBoard, FALSE },
\r
977 { "cmailGameName", ArgString, (LPVOID) &appData.cmailGameName, FALSE },
\r
978 { "cmail", ArgString, (LPVOID) &appData.cmailGameName, FALSE },
\r
980 { "alwaysPromoteToQueen", ArgBoolean, (LPVOID) &appData.alwaysPromoteToQueen, TRUE },
\r
981 { "queen", ArgTrue, (LPVOID) &appData.alwaysPromoteToQueen, FALSE },
\r
982 { "xqueen", ArgFalse, (LPVOID) &appData.alwaysPromoteToQueen, FALSE },
\r
983 { "-queen", ArgFalse, (LPVOID) &appData.alwaysPromoteToQueen, FALSE },
\r
984 { "oldSaveStyle", ArgBoolean, (LPVOID) &appData.oldSaveStyle, TRUE },
\r
985 { "oldsave", ArgTrue, (LPVOID) &appData.oldSaveStyle, FALSE },
\r
986 { "xoldsave", ArgFalse, (LPVOID) &appData.oldSaveStyle, FALSE },
\r
987 { "-oldsave", ArgFalse, (LPVOID) &appData.oldSaveStyle, FALSE },
\r
988 { "quietPlay", ArgBoolean, (LPVOID) &appData.quietPlay, TRUE },
\r
989 { "quiet", ArgTrue, (LPVOID) &appData.quietPlay, FALSE },
\r
990 { "xquiet", ArgFalse, (LPVOID) &appData.quietPlay, FALSE },
\r
991 { "-quiet", ArgFalse, (LPVOID) &appData.quietPlay, FALSE },
\r
992 { "getMoveList", ArgBoolean, (LPVOID) &appData.getMoveList, TRUE },
\r
993 { "moves", ArgTrue, (LPVOID) &appData.getMoveList, FALSE },
\r
994 { "xmoves", ArgFalse, (LPVOID) &appData.getMoveList, FALSE },
\r
995 { "-moves", ArgFalse, (LPVOID) &appData.getMoveList, FALSE },
\r
996 { "testLegality", ArgBoolean, (LPVOID) &appData.testLegality, TRUE },
\r
997 { "legal", ArgTrue, (LPVOID) &appData.testLegality, FALSE },
\r
998 { "xlegal", ArgFalse, (LPVOID) &appData.testLegality, FALSE },
\r
999 { "-legal", ArgFalse, (LPVOID) &appData.testLegality, FALSE },
\r
1000 { "premove", ArgBoolean, (LPVOID) &appData.premove, TRUE },
\r
1001 { "pre", ArgTrue, (LPVOID) &appData.premove, FALSE },
\r
1002 { "xpre", ArgFalse, (LPVOID) &appData.premove, FALSE },
\r
1003 { "-pre", ArgFalse, (LPVOID) &appData.premove, FALSE },
\r
1004 { "premoveWhite", ArgBoolean, (LPVOID) &appData.premoveWhite, TRUE },
\r
1005 { "prewhite", ArgTrue, (LPVOID) &appData.premoveWhite, FALSE },
\r
1006 { "xprewhite", ArgFalse, (LPVOID) &appData.premoveWhite, FALSE },
\r
1007 { "-prewhite", ArgFalse, (LPVOID) &appData.premoveWhite, FALSE },
\r
1008 { "premoveWhiteText", ArgString, (LPVOID) &appData.premoveWhiteText, TRUE },
\r
1009 { "premoveBlack", ArgBoolean, (LPVOID) &appData.premoveBlack, TRUE },
\r
1010 { "preblack", ArgTrue, (LPVOID) &appData.premoveBlack, FALSE },
\r
1011 { "xpreblack", ArgFalse, (LPVOID) &appData.premoveBlack, FALSE },
\r
1012 { "-preblack", ArgFalse, (LPVOID) &appData.premoveBlack, FALSE },
\r
1013 { "premoveBlackText", ArgString, (LPVOID) &appData.premoveBlackText, TRUE },
\r
1014 { "icsAlarm", ArgBoolean, (LPVOID) &appData.icsAlarm, TRUE},
\r
1015 { "alarm", ArgTrue, (LPVOID) &appData.icsAlarm, FALSE},
\r
1016 { "xalarm", ArgFalse, (LPVOID) &appData.icsAlarm, FALSE},
\r
1017 { "-alarm", ArgFalse, (LPVOID) &appData.icsAlarm, FALSE},
\r
1018 { "icsAlarmTime", ArgInt, (LPVOID) &appData.icsAlarmTime, TRUE},
\r
1019 { "localLineEditing", ArgBoolean, (LPVOID) &appData.localLineEditing, FALSE},
\r
1020 { "localLineEditing", ArgBoolean, (LPVOID) &appData.localLineEditing, FALSE},
\r
1021 { "edit", ArgTrue, (LPVOID) &appData.localLineEditing, FALSE },
\r
1022 { "xedit", ArgFalse, (LPVOID) &appData.localLineEditing, FALSE },
\r
1023 { "-edit", ArgFalse, (LPVOID) &appData.localLineEditing, FALSE },
\r
1024 { "animateMoving", ArgBoolean, (LPVOID) &appData.animate, TRUE },
\r
1025 { "animate", ArgTrue, (LPVOID) &appData.animate, FALSE },
\r
1026 { "xanimate", ArgFalse, (LPVOID) &appData.animate, FALSE },
\r
1027 { "-animate", ArgFalse, (LPVOID) &appData.animate, FALSE },
\r
1028 { "animateSpeed", ArgInt, (LPVOID) &appData.animSpeed, TRUE },
\r
1029 { "animateDragging", ArgBoolean, (LPVOID) &appData.animateDragging, TRUE },
\r
1030 { "drag", ArgTrue, (LPVOID) &appData.animateDragging, FALSE },
\r
1031 { "xdrag", ArgFalse, (LPVOID) &appData.animateDragging, FALSE },
\r
1032 { "-drag", ArgFalse, (LPVOID) &appData.animateDragging, FALSE },
\r
1033 { "blindfold", ArgBoolean, (LPVOID) &appData.blindfold, TRUE },
\r
1034 { "blind", ArgTrue, (LPVOID) &appData.blindfold, FALSE },
\r
1035 { "xblind", ArgFalse, (LPVOID) &appData.blindfold, FALSE },
\r
1036 { "-blind", ArgFalse, (LPVOID) &appData.blindfold, FALSE },
\r
1037 { "highlightLastMove", ArgBoolean,
\r
1038 (LPVOID) &appData.highlightLastMove, TRUE },
\r
1039 { "highlight", ArgTrue, (LPVOID) &appData.highlightLastMove, FALSE },
\r
1040 { "xhighlight", ArgFalse, (LPVOID) &appData.highlightLastMove, FALSE },
\r
1041 { "-highlight", ArgFalse, (LPVOID) &appData.highlightLastMove, FALSE },
\r
1042 { "highlightDragging", ArgBoolean,
\r
1043 (LPVOID) &appData.highlightDragging, TRUE },
\r
1044 { "highdrag", ArgTrue, (LPVOID) &appData.highlightDragging, FALSE },
\r
1045 { "xhighdrag", ArgFalse, (LPVOID) &appData.highlightDragging, FALSE },
\r
1046 { "-highdrag", ArgFalse, (LPVOID) &appData.highlightDragging, FALSE },
\r
1047 { "colorizeMessages", ArgBoolean, (LPVOID) &appData.colorize, TRUE },
\r
1048 { "colorize", ArgTrue, (LPVOID) &appData.colorize, FALSE },
\r
1049 { "xcolorize", ArgFalse, (LPVOID) &appData.colorize, FALSE },
\r
1050 { "-colorize", ArgFalse, (LPVOID) &appData.colorize, FALSE },
\r
1051 { "colorShout", ArgAttribs, (LPVOID) ColorShout, TRUE },
\r
1052 { "colorSShout", ArgAttribs, (LPVOID) ColorSShout, TRUE },
\r
1053 { "colorChannel1", ArgAttribs, (LPVOID) ColorChannel1, TRUE },
\r
1054 { "colorChannel", ArgAttribs, (LPVOID) ColorChannel, TRUE },
\r
1055 { "colorKibitz", ArgAttribs, (LPVOID) ColorKibitz, TRUE },
\r
1056 { "colorTell", ArgAttribs, (LPVOID) ColorTell, TRUE },
\r
1057 { "colorChallenge", ArgAttribs, (LPVOID) ColorChallenge, TRUE },
\r
1058 { "colorRequest", ArgAttribs, (LPVOID) ColorRequest, TRUE },
\r
1059 { "colorSeek", ArgAttribs, (LPVOID) ColorSeek, TRUE },
\r
1060 { "colorNormal", ArgAttribs, (LPVOID) ColorNormal, TRUE },
\r
1061 { "colorBackground", ArgColor, (LPVOID) &consoleBackgroundColor, TRUE },
\r
1062 { "soundShout", ArgFilename,
\r
1063 (LPVOID) &textAttribs[ColorShout].sound.name, TRUE },
\r
1064 { "soundSShout", ArgFilename,
\r
1065 (LPVOID) &textAttribs[ColorSShout].sound.name, TRUE },
\r
1066 { "soundChannel1", ArgFilename,
\r
1067 (LPVOID) &textAttribs[ColorChannel1].sound.name, TRUE },
\r
1068 { "soundChannel", ArgFilename,
\r
1069 (LPVOID) &textAttribs[ColorChannel].sound.name, TRUE },
\r
1070 { "soundKibitz", ArgFilename,
\r
1071 (LPVOID) &textAttribs[ColorKibitz].sound.name, TRUE },
\r
1072 { "soundTell", ArgFilename,
\r
1073 (LPVOID) &textAttribs[ColorTell].sound.name, TRUE },
\r
1074 { "soundChallenge", ArgFilename,
\r
1075 (LPVOID) &textAttribs[ColorChallenge].sound.name, TRUE },
\r
1076 { "soundRequest", ArgFilename,
\r
1077 (LPVOID) &textAttribs[ColorRequest].sound.name, TRUE },
\r
1078 { "soundSeek", ArgFilename,
\r
1079 (LPVOID) &textAttribs[ColorSeek].sound.name, TRUE },
\r
1080 { "soundMove", ArgFilename, (LPVOID) &sounds[(int)SoundMove].name, TRUE },
\r
1081 { "soundBell", ArgFilename, (LPVOID) &sounds[(int)SoundBell].name, TRUE },
\r
1082 { "soundIcsWin", ArgFilename, (LPVOID) &sounds[(int)SoundIcsWin].name,TRUE },
\r
1083 { "soundIcsLoss", ArgFilename,
\r
1084 (LPVOID) &sounds[(int)SoundIcsLoss].name, TRUE },
\r
1085 { "soundIcsDraw", ArgFilename,
\r
1086 (LPVOID) &sounds[(int)SoundIcsDraw].name, TRUE },
\r
1087 { "soundIcsUnfinished", ArgFilename,
\r
1088 (LPVOID) &sounds[(int)SoundIcsUnfinished].name, TRUE},
\r
1089 { "soundIcsAlarm", ArgFilename,
\r
1090 (LPVOID) &sounds[(int)SoundAlarm].name, TRUE },
\r
1091 { "reuseFirst", ArgBoolean, (LPVOID) &appData.reuseFirst, FALSE },
\r
1092 { "reuse", ArgTrue, (LPVOID) &appData.reuseFirst, FALSE },
\r
1093 { "xreuse", ArgFalse, (LPVOID) &appData.reuseFirst, FALSE },
\r
1094 { "-reuse", ArgFalse, (LPVOID) &appData.reuseFirst, FALSE },
\r
1095 { "reuseChessPrograms", ArgBoolean,
\r
1096 (LPVOID) &appData.reuseFirst, FALSE }, /* backward compat only */
\r
1097 { "reuseSecond", ArgBoolean, (LPVOID) &appData.reuseSecond, FALSE },
\r
1098 { "reuse2", ArgTrue, (LPVOID) &appData.reuseSecond, FALSE },
\r
1099 { "xreuse2", ArgFalse, (LPVOID) &appData.reuseSecond, FALSE },
\r
1100 { "-reuse2", ArgFalse, (LPVOID) &appData.reuseSecond, FALSE },
\r
1101 { "comPortSettings", ArgCommSettings, (LPVOID) &dcb, TRUE },
\r
1102 { "x", ArgInt, (LPVOID) &boardX, TRUE },
\r
1103 { "y", ArgInt, (LPVOID) &boardY, TRUE },
\r
1104 { "icsX", ArgInt, (LPVOID) &consoleX, TRUE },
\r
1105 { "icsY", ArgInt, (LPVOID) &consoleY, TRUE },
\r
1106 { "icsW", ArgInt, (LPVOID) &consoleW, TRUE },
\r
1107 { "icsH", ArgInt, (LPVOID) &consoleH, TRUE },
\r
1108 { "analysisX", ArgInt, (LPVOID) &analysisX, TRUE },
\r
1109 { "analysisY", ArgInt, (LPVOID) &analysisY, TRUE },
\r
1110 { "analysisW", ArgInt, (LPVOID) &analysisW, TRUE },
\r
1111 { "analysisH", ArgInt, (LPVOID) &analysisH, TRUE },
\r
1112 { "commentX", ArgInt, (LPVOID) &commentX, TRUE },
\r
1113 { "commentY", ArgInt, (LPVOID) &commentY, TRUE },
\r
1114 { "commentW", ArgInt, (LPVOID) &commentW, TRUE },
\r
1115 { "commentH", ArgInt, (LPVOID) &commentH, TRUE },
\r
1116 { "tagsX", ArgInt, (LPVOID) &editTagsX, TRUE },
\r
1117 { "tagsY", ArgInt, (LPVOID) &editTagsY, TRUE },
\r
1118 { "tagsW", ArgInt, (LPVOID) &editTagsW, TRUE },
\r
1119 { "tagsH", ArgInt, (LPVOID) &editTagsH, TRUE },
\r
1120 { "gameListX", ArgInt, (LPVOID) &gameListX, TRUE },
\r
1121 { "gameListY", ArgInt, (LPVOID) &gameListY, TRUE },
\r
1122 { "gameListW", ArgInt, (LPVOID) &gameListW, TRUE },
\r
1123 { "gameListH", ArgInt, (LPVOID) &gameListH, TRUE },
\r
1124 { "settingsFile", ArgSettingsFilename, (LPVOID) &settingsFileName, FALSE },
\r
1125 { "ini", ArgSettingsFilename, (LPVOID) &settingsFileName, FALSE },
\r
1126 { "saveSettingsOnExit", ArgBoolean, (LPVOID) &saveSettingsOnExit, TRUE },
\r
1127 { "chessProgram", ArgBoolean, (LPVOID) &chessProgram, FALSE },
\r
1128 { "cp", ArgTrue, (LPVOID) &chessProgram, FALSE },
\r
1129 { "xcp", ArgFalse, (LPVOID) &chessProgram, FALSE },
\r
1130 { "-cp", ArgFalse, (LPVOID) &chessProgram, FALSE },
\r
1131 { "icsMenu", ArgString, (LPVOID) &icsTextMenuString, TRUE },
\r
1132 { "icsNames", ArgString, (LPVOID) &icsNames, TRUE },
\r
1133 { "firstChessProgramNames", ArgString, (LPVOID) &firstChessProgramNames,
\r
1135 { "secondChessProgramNames", ArgString, (LPVOID) &secondChessProgramNames,
\r
1137 { "initialMode", ArgString, (LPVOID) &appData.initialMode, FALSE },
\r
1138 { "mode", ArgString, (LPVOID) &appData.initialMode, FALSE },
\r
1139 { "variant", ArgString, (LPVOID) &appData.variant, FALSE },
\r
1140 { "firstProtocolVersion", ArgInt, (LPVOID) &appData.firstProtocolVersion, FALSE },
\r
1141 { "secondProtocolVersion", ArgInt, (LPVOID) &appData.secondProtocolVersion,FALSE },
\r
1142 { "showButtonBar", ArgBoolean, (LPVOID) &appData.showButtonBar, TRUE },
\r
1143 { "buttons", ArgTrue, (LPVOID) &appData.showButtonBar, FALSE },
\r
1144 { "xbuttons", ArgFalse, (LPVOID) &appData.showButtonBar, FALSE },
\r
1145 { "-buttons", ArgFalse, (LPVOID) &appData.showButtonBar, FALSE },
\r
1146 /* [AS] New features */
\r
1147 { "firstScoreAbs", ArgBoolean, (LPVOID) &appData.firstScoreIsAbsolute, FALSE },
\r
1148 { "secondScoreAbs", ArgBoolean, (LPVOID) &appData.secondScoreIsAbsolute, FALSE },
\r
1149 { "pgnExtendedInfo", ArgBoolean, (LPVOID) &appData.saveExtendedInfoInPGN, TRUE },
\r
1150 { "hideThinkingFromHuman", ArgBoolean, (LPVOID) &appData.hideThinkingFromHuman, TRUE },
\r
1151 { "liteBackTextureFile", ArgString, (LPVOID) &appData.liteBackTextureFile, TRUE },
\r
1152 { "darkBackTextureFile", ArgString, (LPVOID) &appData.darkBackTextureFile, TRUE },
\r
1153 { "liteBackTextureMode", ArgInt, (LPVOID) &appData.liteBackTextureMode, TRUE },
\r
1154 { "darkBackTextureMode", ArgInt, (LPVOID) &appData.darkBackTextureMode, TRUE },
\r
1155 { "renderPiecesWithFont", ArgString, (LPVOID) &appData.renderPiecesWithFont, TRUE },
\r
1156 { "fontPieceToCharTable", ArgString, (LPVOID) &appData.fontToPieceTable, TRUE },
\r
1157 { "fontPieceBackColorWhite", ArgColor, (LPVOID) &appData.fontBackColorWhite, TRUE },
\r
1158 { "fontPieceForeColorWhite", ArgColor, (LPVOID) &appData.fontForeColorWhite, TRUE },
\r
1159 { "fontPieceBackColorBlack", ArgColor, (LPVOID) &appData.fontBackColorBlack, TRUE },
\r
1160 { "fontPieceForeColorBlack", ArgColor, (LPVOID) &appData.fontForeColorBlack, TRUE },
\r
1161 { "fontPieceSize", ArgInt, (LPVOID) &appData.fontPieceSize, TRUE },
\r
1162 { "overrideLineGap", ArgInt, (LPVOID) &appData.overrideLineGap, TRUE },
\r
1163 { "adjudicateLossThreshold", ArgInt, (LPVOID) &appData.adjudicateLossThreshold, TRUE },
\r
1164 { "delayBeforeQuit", ArgInt, (LPVOID) &appData.delayBeforeQuit, TRUE },
\r
1165 { "delayAfterQuit", ArgInt, (LPVOID) &appData.delayAfterQuit, TRUE },
\r
1166 { "nameOfDebugFile", ArgFilename, (LPVOID) &appData.nameOfDebugFile, FALSE },
\r
1167 { "debugfile", ArgFilename, (LPVOID) &appData.nameOfDebugFile, FALSE },
\r
1168 { "pgnEventHeader", ArgString, (LPVOID) &appData.pgnEventHeader, TRUE },
\r
1169 { "defaultFrcPosition", ArgInt, (LPVOID) &appData.defaultFrcPosition, TRUE },
\r
1170 { "gameListTags", ArgString, (LPVOID) &appData.gameListTags, TRUE },
\r
1171 { "saveOutOfBookInfo", ArgBoolean, (LPVOID) &appData.saveOutOfBookInfo, TRUE },
\r
1172 { "showEvalInMoveHistory", ArgBoolean, (LPVOID) &appData.showEvalInMoveHistory, TRUE },
\r
1173 { "evalHistColorWhite", ArgColor, (LPVOID) &appData.evalHistColorWhite, TRUE },
\r
1174 { "evalHistColorBlack", ArgColor, (LPVOID) &appData.evalHistColorBlack, TRUE },
\r
1175 { "highlightMoveWithArrow", ArgBoolean, (LPVOID) &appData.highlightMoveWithArrow, TRUE },
\r
1176 { "highlightArrowColor", ArgColor, (LPVOID) &appData.highlightArrowColor, TRUE },
\r
1177 { "stickyWindows", ArgBoolean, (LPVOID) &appData.useStickyWindows, TRUE },
\r
1178 { "adjudicateDrawMoves", ArgInt, (LPVOID) &appData.adjudicateDrawMoves, TRUE },
\r
1179 { "autoDisplayComment", ArgBoolean, (LPVOID) &appData.autoDisplayComment, TRUE },
\r
1180 { "autoDisplayTags", ArgBoolean, (LPVOID) &appData.autoDisplayTags, TRUE },
\r
1181 { "firstIsUCI", ArgBoolean, (LPVOID) &appData.firstIsUCI, FALSE },
\r
1182 { "fUCI", ArgTrue, (LPVOID) &appData.firstIsUCI, FALSE },
\r
1183 { "secondIsUCI", ArgBoolean, (LPVOID) &appData.secondIsUCI, FALSE },
\r
1184 { "sUCI", ArgTrue, (LPVOID) &appData.secondIsUCI, FALSE },
\r
1185 { "firstHasOwnBookUCI", ArgBoolean, (LPVOID) &appData.firstHasOwnBookUCI, FALSE },
\r
1186 { "fNoOwnBookUCI", ArgFalse, (LPVOID) &appData.firstHasOwnBookUCI, FALSE },
\r
1187 { "firstXBook", ArgFalse, (LPVOID) &appData.firstHasOwnBookUCI, FALSE },
\r
1188 { "secondHasOwnBookUCI", ArgBoolean, (LPVOID) &appData.secondHasOwnBookUCI, FALSE },
\r
1189 { "sNoOwnBookUCI", ArgFalse, (LPVOID) &appData.secondHasOwnBookUCI, FALSE },
\r
1190 { "secondXBook", ArgFalse, (LPVOID) &appData.secondHasOwnBookUCI, FALSE },
\r
1191 { "polyglotDir", ArgFilename, (LPVOID) &appData.polyglotDir, TRUE },
\r
1192 { "usePolyglotBook", ArgBoolean, (LPVOID) &appData.usePolyglotBook, TRUE },
\r
1193 { "polyglotBook", ArgFilename, (LPVOID) &appData.polyglotBook, TRUE },
\r
1194 { "defaultHashSize", ArgInt, (LPVOID) &appData.defaultHashSize, TRUE },
\r
1195 { "defaultCacheSizeEGTB", ArgInt, (LPVOID) &appData.defaultCacheSizeEGTB, TRUE },
\r
1196 { "defaultPathEGTB", ArgFilename, (LPVOID) &appData.defaultPathEGTB, TRUE },
\r
1198 /* [AS] Layout stuff */
\r
1199 { "moveHistoryUp", ArgBoolean, (LPVOID) &wpMoveHistory.visible, TRUE },
\r
1200 { "moveHistoryX", ArgInt, (LPVOID) &wpMoveHistory.x, TRUE },
\r
1201 { "moveHistoryY", ArgInt, (LPVOID) &wpMoveHistory.y, TRUE },
\r
1202 { "moveHistoryW", ArgInt, (LPVOID) &wpMoveHistory.width, TRUE },
\r
1203 { "moveHistoryH", ArgInt, (LPVOID) &wpMoveHistory.height, TRUE },
\r
1205 { "evalGraphUp", ArgBoolean, (LPVOID) &wpEvalGraph.visible, TRUE },
\r
1206 { "evalGraphX", ArgInt, (LPVOID) &wpEvalGraph.x, TRUE },
\r
1207 { "evalGraphY", ArgInt, (LPVOID) &wpEvalGraph.y, TRUE },
\r
1208 { "evalGraphW", ArgInt, (LPVOID) &wpEvalGraph.width, TRUE },
\r
1209 { "evalGraphH", ArgInt, (LPVOID) &wpEvalGraph.height, TRUE },
\r
1211 { "engineOutputUp", ArgBoolean, (LPVOID) &wpEngineOutput.visible, TRUE },
\r
1212 { "engineOutputX", ArgInt, (LPVOID) &wpEngineOutput.x, TRUE },
\r
1213 { "engineOutputY", ArgInt, (LPVOID) &wpEngineOutput.y, TRUE },
\r
1214 { "engineOutputW", ArgInt, (LPVOID) &wpEngineOutput.width, TRUE },
\r
1215 { "engineOutputH", ArgInt, (LPVOID) &wpEngineOutput.height, TRUE },
\r
1217 /* [HGM] board-size, adjudication and misc. options */
\r
1218 { "boardWidth", ArgInt, (LPVOID) &appData.NrFiles, TRUE },
\r
1219 { "boardHeight", ArgInt, (LPVOID) &appData.NrRanks, TRUE },
\r
1220 { "holdingsSize", ArgInt, (LPVOID) &appData.holdingsSize, TRUE },
\r
1221 { "matchPause", ArgInt, (LPVOID) &appData.matchPause, TRUE },
\r
1222 { "pieceToCharTable", ArgString, (LPVOID) &appData.pieceToCharTable, FALSE },
\r
1223 { "flipBlack", ArgBoolean, (LPVOID) &appData.upsideDown, TRUE },
\r
1224 { "allWhite", ArgBoolean, (LPVOID) &appData.allWhite, TRUE },
\r
1225 { "alphaRank", ArgBoolean, (LPVOID) &appData.alphaRank, FALSE },
\r
1226 { "firstAlphaRank", ArgBoolean, (LPVOID) &first.alphaRank, FALSE },
\r
1227 { "secondAlphaRank", ArgBoolean, (LPVOID) &second.alphaRank, FALSE },
\r
1228 { "testClaims", ArgBoolean, (LPVOID) &appData.testClaims, TRUE },
\r
1229 { "checkMates", ArgBoolean, (LPVOID) &appData.checkMates, TRUE },
\r
1230 { "materialDraws", ArgBoolean, (LPVOID) &appData.materialDraws, TRUE },
\r
1231 { "trivialDraws", ArgBoolean, (LPVOID) &appData.trivialDraws, TRUE },
\r
1232 { "ruleMoves", ArgInt, (LPVOID) &appData.ruleMoves, TRUE },
\r
1233 { "repeatsToDraw", ArgInt, (LPVOID) &appData.drawRepeats, TRUE },
\r
1234 { "autoKibitz", ArgTrue, (LPVOID) &appData.autoKibitz, FALSE },
\r
1235 { "engineDebugOutput", ArgInt, (LPVOID) &appData.engineComments, FALSE },
\r
1236 { "userName", ArgString, (LPVOID) &appData.userName, FALSE },
\r
1237 { "rewindIndex", ArgInt, (LPVOID) &appData.rewindIndex, FALSE },
\r
1238 { "sameColorGames", ArgInt, (LPVOID) &appData.sameColorGames, FALSE },
\r
1239 { "smpCores", ArgInt, (LPVOID) &appData.smpCores, TRUE },
\r
1240 { "egtFormats", ArgString, (LPVOID) &appData.egtFormats, TRUE },
\r
1241 { "niceEngines", ArgInt, (LPVOID) &appData.niceEngines, TRUE },
\r
1242 { "firstLogo", ArgFilename, (LPVOID) &appData.firstLogo, FALSE },
\r
1243 { "secondLogo", ArgFilename, (LPVOID) &appData.secondLogo, FALSE },
\r
1244 { "autoLogo", ArgBoolean, (LPVOID) &appData.autoLogo, TRUE },
\r
1245 { "firstOptions", ArgString, (LPVOID) &appData.firstOptions, FALSE },
\r
1246 { "secondOptions", ArgString, (LPVOID) &appData.secondOptions, FALSE },
\r
1249 { "zippyTalk", ArgBoolean, (LPVOID) &appData.zippyTalk, FALSE },
\r
1250 { "zt", ArgTrue, (LPVOID) &appData.zippyTalk, FALSE },
\r
1251 { "xzt", ArgFalse, (LPVOID) &appData.zippyTalk, FALSE },
\r
1252 { "-zt", ArgFalse, (LPVOID) &appData.zippyTalk, FALSE },
\r
1253 { "zippyPlay", ArgBoolean, (LPVOID) &appData.zippyPlay, FALSE },
\r
1254 { "zp", ArgTrue, (LPVOID) &appData.zippyPlay, FALSE },
\r
1255 { "xzp", ArgFalse, (LPVOID) &appData.zippyPlay, FALSE },
\r
1256 { "-zp", ArgFalse, (LPVOID) &appData.zippyPlay, FALSE },
\r
1257 { "zippyLines", ArgFilename, (LPVOID) &appData.zippyLines, FALSE },
\r
1258 { "zippyPinhead", ArgString, (LPVOID) &appData.zippyPinhead, FALSE },
\r
1259 { "zippyPassword", ArgString, (LPVOID) &appData.zippyPassword, FALSE },
\r
1260 { "zippyPassword2", ArgString, (LPVOID) &appData.zippyPassword2, FALSE },
\r
1261 { "zippyWrongPassword", ArgString, (LPVOID) &appData.zippyWrongPassword,
\r
1263 { "zippyAcceptOnly", ArgString, (LPVOID) &appData.zippyAcceptOnly, FALSE },
\r
1264 { "zippyUseI", ArgBoolean, (LPVOID) &appData.zippyUseI, FALSE },
\r
1265 { "zui", ArgTrue, (LPVOID) &appData.zippyUseI, FALSE },
\r
1266 { "xzui", ArgFalse, (LPVOID) &appData.zippyUseI, FALSE },
\r
1267 { "-zui", ArgFalse, (LPVOID) &appData.zippyUseI, FALSE },
\r
1268 { "zippyBughouse", ArgInt, (LPVOID) &appData.zippyBughouse, FALSE },
\r
1269 { "zippyNoplayCrafty", ArgBoolean, (LPVOID) &appData.zippyNoplayCrafty,
\r
1271 { "znc", ArgTrue, (LPVOID) &appData.zippyNoplayCrafty, FALSE },
\r
1272 { "xznc", ArgFalse, (LPVOID) &appData.zippyNoplayCrafty, FALSE },
\r
1273 { "-znc", ArgFalse, (LPVOID) &appData.zippyNoplayCrafty, FALSE },
\r
1274 { "zippyGameEnd", ArgString, (LPVOID) &appData.zippyGameEnd, FALSE },
\r
1275 { "zippyGameStart", ArgString, (LPVOID) &appData.zippyGameStart, FALSE },
\r
1276 { "zippyAdjourn", ArgBoolean, (LPVOID) &appData.zippyAdjourn, FALSE },
\r
1277 { "zadj", ArgTrue, (LPVOID) &appData.zippyAdjourn, FALSE },
\r
1278 { "xzadj", ArgFalse, (LPVOID) &appData.zippyAdjourn, FALSE },
\r
1279 { "-zadj", ArgFalse, (LPVOID) &appData.zippyAdjourn, FALSE },
\r
1280 { "zippyAbort", ArgBoolean, (LPVOID) &appData.zippyAbort, FALSE },
\r
1281 { "zab", ArgTrue, (LPVOID) &appData.zippyAbort, FALSE },
\r
1282 { "xzab", ArgFalse, (LPVOID) &appData.zippyAbort, FALSE },
\r
1283 { "-zab", ArgFalse, (LPVOID) &appData.zippyAbort, FALSE },
\r
1284 { "zippyVariants", ArgString, (LPVOID) &appData.zippyVariants, FALSE },
\r
1285 { "zippyMaxGames", ArgInt, (LPVOID)&appData.zippyMaxGames, FALSE },
\r
1286 { "zippyReplayTimeout", ArgInt, (LPVOID)&appData.zippyReplayTimeout, FALSE },
\r
1287 /* Kludge to allow winboard.ini files from buggy 4.0.4 to be read: */
\r
1288 { "zippyReplyTimeout", ArgInt, (LPVOID)&junk, FALSE },
\r
1290 /* [HGM] options for broadcasting and time odds */
\r
1291 { "serverMoves", ArgString, (LPVOID) &appData.serverMovesName, FALSE },
\r
1292 { "suppressLoadMoves", ArgBoolean, (LPVOID) &appData.suppressLoadMoves, FALSE },
\r
1293 { "serverPause", ArgInt, (LPVOID) &appData.serverPause, FALSE },
\r
1294 { "firstTimeOdds", ArgInt, (LPVOID) &appData.firstTimeOdds, FALSE },
\r
1295 { "secondTimeOdds", ArgInt, (LPVOID) &appData.secondTimeOdds, FALSE },
\r
1296 { "timeOddsMode", ArgInt, (LPVOID) &appData.timeOddsMode, TRUE },
\r
1297 { "firstAccumulateTC", ArgInt, (LPVOID) &appData.firstAccumulateTC, FALSE },
\r
1298 { "secondAccumulateTC", ArgInt, (LPVOID) &appData.secondAccumulateTC, FALSE },
\r
1299 { "firstNPS", ArgInt, (LPVOID) &appData.firstNPS, FALSE },
\r
1300 { "secondNPS", ArgInt, (LPVOID) &appData.secondNPS, FALSE },
\r
1301 { "noGUI", ArgTrue, (LPVOID) &appData.noGUI, FALSE },
\r
1302 { NULL, ArgNone, NULL, FALSE }
\r
1306 /* Kludge for indirection files on command line */
\r
1307 char* lastIndirectionFilename;
\r
1308 ArgDescriptor argDescriptorIndirection =
\r
1309 { "", ArgSettingsFilename, (LPVOID) NULL, FALSE };
\r
1313 ExitArgError(char *msg, char *badArg)
\r
1315 char buf[MSG_SIZ];
\r
1317 sprintf(buf, "%s %s", msg, badArg);
\r
1318 DisplayFatalError(buf, 0, 2);
\r
1322 /* Command line font name parser. NULL name means do nothing.
\r
1323 Syntax like "Courier New:10.0 bi" or "Arial:10" or "Arial:10b"
\r
1324 For backward compatibility, syntax without the colon is also
\r
1325 accepted, but font names with digits in them won't work in that case.
\r
1328 ParseFontName(char *name, MyFontParams *mfp)
\r
1331 if (name == NULL) return;
\r
1333 q = strchr(p, ':');
\r
1335 if (q - p >= sizeof(mfp->faceName))
\r
1336 ExitArgError("Font name too long:", name);
\r
1337 memcpy(mfp->faceName, p, q - p);
\r
1338 mfp->faceName[q - p] = NULLCHAR;
\r
1341 q = mfp->faceName;
\r
1342 while (*p && !isdigit(*p)) {
\r
1344 if (q - mfp->faceName >= sizeof(mfp->faceName))
\r
1345 ExitArgError("Font name too long:", name);
\r
1347 while (q > mfp->faceName && q[-1] == ' ') q--;
\r
1350 if (!*p) ExitArgError("Font point size missing:", name);
\r
1351 mfp->pointSize = (float) atof(p);
\r
1352 mfp->bold = (strchr(p, 'b') != NULL);
\r
1353 mfp->italic = (strchr(p, 'i') != NULL);
\r
1354 mfp->underline = (strchr(p, 'u') != NULL);
\r
1355 mfp->strikeout = (strchr(p, 's') != NULL);
\r
1358 /* Color name parser.
\r
1359 X version accepts X color names, but this one
\r
1360 handles only the #rrggbb form (hex) or rrr,ggg,bbb (decimal) */
\r
1362 ParseColorName(char *name)
\r
1364 int red, green, blue, count;
\r
1365 char buf[MSG_SIZ];
\r
1367 count = sscanf(name, "#%2x%2x%2x", &red, &green, &blue);
\r
1369 count = sscanf(name, "%3d%*[^0-9]%3d%*[^0-9]%3d",
\r
1370 &red, &green, &blue);
\r
1373 sprintf(buf, "Can't parse color name %s", name);
\r
1374 DisplayError(buf, 0);
\r
1375 return RGB(0, 0, 0);
\r
1377 return PALETTERGB(red, green, blue);
\r
1381 void ParseAttribs(COLORREF *color, int *effects, char* argValue)
\r
1383 char *e = argValue;
\r
1387 if (*e == 'b') eff |= CFE_BOLD;
\r
1388 else if (*e == 'i') eff |= CFE_ITALIC;
\r
1389 else if (*e == 'u') eff |= CFE_UNDERLINE;
\r
1390 else if (*e == 's') eff |= CFE_STRIKEOUT;
\r
1391 else if (*e == '#' || isdigit(*e)) break;
\r
1395 *color = ParseColorName(e);
\r
1400 ParseBoardSize(char *name)
\r
1402 BoardSize bs = SizeTiny;
\r
1403 while (sizeInfo[bs].name != NULL) {
\r
1404 if (StrCaseCmp(name, sizeInfo[bs].name) == 0) return bs;
\r
1407 ExitArgError("Unrecognized board size value", name);
\r
1408 return bs; /* not reached */
\r
1413 StringGet(void *getClosure)
\r
1415 char **p = (char **) getClosure;
\r
1420 FileGet(void *getClosure)
\r
1423 FILE* f = (FILE*) getClosure;
\r
1426 if (c == '\r') c = getc(f); // work around DOS format files by bypassing the '\r' completely
\r
1433 /* Parse settings file named "name". If file found, return the
\r
1434 full name in fullname and return TRUE; else return FALSE */
\r
1436 ParseSettingsFile(char *name, char fullname[MSG_SIZ])
\r
1440 int ok; char buf[MSG_SIZ];
\r
1442 ok = SearchPath(installDir, name, NULL, MSG_SIZ, fullname, &dummy);
\r
1443 if(!ok && strchr(name, '.') == NULL) { // [HGM] append default file-name extension '.ini' when needed
\r
1444 sprintf(buf, "%s.ini", name);
\r
1445 ok = SearchPath(installDir, buf, NULL, MSG_SIZ, fullname, &dummy);
\r
1448 f = fopen(fullname, "r");
\r
1450 ParseArgs(FileGet, f);
\r
1459 ParseArgs(GetFunc get, void *cl)
\r
1461 char argName[ARG_MAX];
\r
1462 char argValue[ARG_MAX];
\r
1463 ArgDescriptor *ad;
\r
1472 while (ch == ' ' || ch == '\n' || ch == '\t') ch = get(cl);
\r
1473 if (ch == NULLCHAR) break;
\r
1475 /* Comment to end of line */
\r
1477 while (ch != '\n' && ch != NULLCHAR) ch = get(cl);
\r
1479 } else if (ch == '/' || ch == '-') {
\r
1482 while (ch != ' ' && ch != '=' && ch != ':' && ch != NULLCHAR &&
\r
1483 ch != '\n' && ch != '\t') {
\r
1489 for (ad = argDescriptors; ad->argName != NULL; ad++)
\r
1490 if (strcmp(ad->argName, argName + 1) == 0) break;
\r
1492 if (ad->argName == NULL)
\r
1493 ExitArgError("Unrecognized argument", argName);
\r
1495 } else if (ch == '@') {
\r
1496 /* Indirection file */
\r
1497 ad = &argDescriptorIndirection;
\r
1500 /* Positional argument */
\r
1501 ad = &argDescriptors[posarg++];
\r
1502 strcpy(argName, ad->argName);
\r
1505 if (ad->argType == ArgTrue) {
\r
1506 *(Boolean *) ad->argLoc = TRUE;
\r
1509 if (ad->argType == ArgFalse) {
\r
1510 *(Boolean *) ad->argLoc = FALSE;
\r
1514 while (ch == ' ' || ch == '=' || ch == ':' || ch == '\t') ch = get(cl);
\r
1515 if (ch == NULLCHAR || ch == '\n') {
\r
1516 ExitArgError("No value provided for argument", argName);
\r
1520 // Quoting with { }. No characters have to (or can) be escaped.
\r
1521 // Thus the string cannot contain a '}' character.
\r
1541 } else if (ch == '\'' || ch == '"') {
\r
1542 // Quoting with ' ' or " ", with \ as escape character.
\r
1543 // Inconvenient for long strings that may contain Windows filenames.
\r
1560 if (ch == start) {
\r
1569 if (ad->argType == ArgFilename
\r
1570 || ad->argType == ArgSettingsFilename) {
\r
1576 ExitArgError("Incomplete \\ escape in value for", argName);
\r
1600 for (i = 0; i < 3; i++) {
\r
1601 if (ch >= '0' && ch <= '7') {
\r
1602 octval = octval*8 + (ch - '0');
\r
1609 *q++ = (char) octval;
\r
1620 while (ch != ' ' && ch != NULLCHAR && ch != '\t' && ch != '\n') {
\r
1627 switch (ad->argType) {
\r
1629 *(int *) ad->argLoc = atoi(argValue);
\r
1633 *(float *) ad->argLoc = (float) atof(argValue);
\r
1638 *(char **) ad->argLoc = strdup(argValue);
\r
1641 case ArgSettingsFilename:
\r
1643 char fullname[MSG_SIZ];
\r
1644 if (ParseSettingsFile(argValue, fullname)) {
\r
1645 if (ad->argLoc != NULL) {
\r
1646 *(char **) ad->argLoc = strdup(fullname);
\r
1649 if (ad->argLoc != NULL) {
\r
1651 ExitArgError("Failed to open indirection file", argValue);
\r
1658 switch (argValue[0]) {
\r
1661 *(Boolean *) ad->argLoc = TRUE;
\r
1665 *(Boolean *) ad->argLoc = FALSE;
\r
1668 ExitArgError("Unrecognized boolean argument value", argValue);
\r
1674 *(COLORREF *)ad->argLoc = ParseColorName(argValue);
\r
1677 case ArgAttribs: {
\r
1678 ColorClass cc = (ColorClass)ad->argLoc;
\r
1679 ParseAttribs(&textAttribs[cc].color, &textAttribs[cc].effects, argValue);
\r
1683 case ArgBoardSize:
\r
1684 *(BoardSize *)ad->argLoc = ParseBoardSize(argValue);
\r
1688 ParseFontName(argValue, &font[boardSize][(int)ad->argLoc]->mfp);
\r
1691 case ArgCommSettings:
\r
1692 ParseCommSettings(argValue, &dcb);
\r
1696 ExitArgError("Unrecognized argument", argValue);
\r
1705 LFfromMFP(LOGFONT* lf, MyFontParams *mfp)
\r
1707 HDC hdc = CreateDC("DISPLAY", NULL, NULL, NULL);
\r
1708 lf->lfHeight = -(int)(mfp->pointSize * GetDeviceCaps(hdc, LOGPIXELSY) / 72.0 + 0.5);
\r
1711 lf->lfEscapement = 0;
\r
1712 lf->lfOrientation = 0;
\r
1713 lf->lfWeight = mfp->bold ? FW_BOLD : FW_NORMAL;
\r
1714 lf->lfItalic = mfp->italic;
\r
1715 lf->lfUnderline = mfp->underline;
\r
1716 lf->lfStrikeOut = mfp->strikeout;
\r
1717 lf->lfCharSet = DEFAULT_CHARSET;
\r
1718 lf->lfOutPrecision = OUT_DEFAULT_PRECIS;
\r
1719 lf->lfClipPrecision = CLIP_DEFAULT_PRECIS;
\r
1720 lf->lfQuality = DEFAULT_QUALITY;
\r
1721 lf->lfPitchAndFamily = DEFAULT_PITCH|FF_DONTCARE;
\r
1722 strcpy(lf->lfFaceName, mfp->faceName);
\r
1726 CreateFontInMF(MyFont *mf)
\r
1728 LFfromMFP(&mf->lf, &mf->mfp);
\r
1729 if (mf->hf) DeleteObject(mf->hf);
\r
1730 mf->hf = CreateFontIndirect(&mf->lf);
\r
1734 SetDefaultTextAttribs()
\r
1737 for (cc = (ColorClass)0; cc < NColorClasses; cc++) {
\r
1738 ParseAttribs(&textAttribs[cc].color,
\r
1739 &textAttribs[cc].effects,
\r
1740 defaultTextAttribs[cc]);
\r
1745 SetDefaultSounds()
\r
1749 for (cc = (ColorClass)0; cc < NColorClasses; cc++) {
\r
1750 textAttribs[cc].sound.name = strdup("");
\r
1751 textAttribs[cc].sound.data = NULL;
\r
1753 for (sc = (SoundClass)0; sc < NSoundClasses; sc++) {
\r
1754 sounds[sc].name = strdup("");
\r
1755 sounds[sc].data = NULL;
\r
1757 sounds[(int)SoundBell].name = strdup(SOUND_BELL);
\r
1765 for (cc = (ColorClass)0; cc < NColorClasses; cc++) {
\r
1766 MyLoadSound(&textAttribs[cc].sound);
\r
1768 for (sc = (SoundClass)0; sc < NSoundClasses; sc++) {
\r
1769 MyLoadSound(&sounds[sc]);
\r
1774 InitAppData(LPSTR lpCmdLine)
\r
1777 char buf[ARG_MAX], currDir[MSG_SIZ];
\r
1780 programName = szAppName;
\r
1782 /* Initialize to defaults */
\r
1783 lightSquareColor = ParseColorName(LIGHT_SQUARE_COLOR);
\r
1784 darkSquareColor = ParseColorName(DARK_SQUARE_COLOR);
\r
1785 whitePieceColor = ParseColorName(WHITE_PIECE_COLOR);
\r
1786 blackPieceColor = ParseColorName(BLACK_PIECE_COLOR);
\r
1787 highlightSquareColor = ParseColorName(HIGHLIGHT_SQUARE_COLOR);
\r
1788 premoveHighlightColor = ParseColorName(PREMOVE_HIGHLIGHT_COLOR);
\r
1789 consoleBackgroundColor = ParseColorName(COLOR_BKGD);
\r
1790 SetDefaultTextAttribs();
\r
1791 SetDefaultSounds();
\r
1792 appData.movesPerSession = MOVES_PER_SESSION;
\r
1793 appData.initString = INIT_STRING;
\r
1794 appData.secondInitString = INIT_STRING;
\r
1795 appData.firstComputerString = COMPUTER_STRING;
\r
1796 appData.secondComputerString = COMPUTER_STRING;
\r
1797 appData.firstChessProgram = FIRST_CHESS_PROGRAM;
\r
1798 appData.secondChessProgram = SECOND_CHESS_PROGRAM;
\r
1799 appData.firstPlaysBlack = FALSE;
\r
1800 appData.noChessProgram = FALSE;
\r
1801 chessProgram = FALSE;
\r
1802 appData.firstHost = FIRST_HOST;
\r
1803 appData.secondHost = SECOND_HOST;
\r
1804 appData.firstDirectory = FIRST_DIRECTORY;
\r
1805 appData.secondDirectory = SECOND_DIRECTORY;
\r
1806 appData.bitmapDirectory = "";
\r
1807 appData.remoteShell = REMOTE_SHELL;
\r
1808 appData.remoteUser = "";
\r
1809 appData.timeDelay = TIME_DELAY;
\r
1810 appData.timeControl = TIME_CONTROL;
\r
1811 appData.timeIncrement = TIME_INCREMENT;
\r
1812 appData.icsActive = FALSE;
\r
1813 appData.icsHost = "";
\r
1814 appData.icsPort = ICS_PORT;
\r
1815 appData.icsCommPort = ICS_COMM_PORT;
\r
1816 appData.icsLogon = ICS_LOGON;
\r
1817 appData.icsHelper = "";
\r
1818 appData.useTelnet = FALSE;
\r
1819 appData.telnetProgram = TELNET_PROGRAM;
\r
1820 appData.gateway = "";
\r
1821 appData.loadGameFile = "";
\r
1822 appData.loadGameIndex = 0;
\r
1823 appData.saveGameFile = "";
\r
1824 appData.autoSaveGames = FALSE;
\r
1825 appData.loadPositionFile = "";
\r
1826 appData.loadPositionIndex = 1;
\r
1827 appData.savePositionFile = "";
\r
1828 appData.matchMode = FALSE;
\r
1829 appData.matchGames = 0;
\r
1830 appData.monoMode = FALSE;
\r
1831 appData.debugMode = FALSE;
\r
1832 appData.clockMode = TRUE;
\r
1833 boardSize = (BoardSize) -1; /* determine by screen size */
\r
1834 appData.Iconic = FALSE; /*unused*/
\r
1835 appData.searchTime = "";
\r
1836 appData.searchDepth = 0;
\r
1837 appData.showCoords = FALSE;
\r
1838 appData.ringBellAfterMoves = TRUE; /*obsolete in WinBoard*/
\r
1839 appData.autoCallFlag = FALSE;
\r
1840 appData.flipView = FALSE;
\r
1841 appData.autoFlipView = TRUE;
\r
1842 appData.cmailGameName = "";
\r
1843 appData.alwaysPromoteToQueen = FALSE;
\r
1844 appData.oldSaveStyle = FALSE;
\r
1845 appData.quietPlay = FALSE;
\r
1846 appData.showThinking = FALSE;
\r
1847 appData.ponderNextMove = TRUE;
\r
1848 appData.periodicUpdates = TRUE;
\r
1849 appData.popupExitMessage = TRUE;
\r
1850 appData.popupMoveErrors = FALSE;
\r
1851 appData.autoObserve = FALSE;
\r
1852 appData.autoComment = FALSE;
\r
1853 appData.animate = TRUE;
\r
1854 appData.animSpeed = 10;
\r
1855 appData.animateDragging = TRUE;
\r
1856 appData.highlightLastMove = TRUE;
\r
1857 appData.getMoveList = TRUE;
\r
1858 appData.testLegality = TRUE;
\r
1859 appData.premove = TRUE;
\r
1860 appData.premoveWhite = FALSE;
\r
1861 appData.premoveWhiteText = "";
\r
1862 appData.premoveBlack = FALSE;
\r
1863 appData.premoveBlackText = "";
\r
1864 appData.icsAlarm = TRUE;
\r
1865 appData.icsAlarmTime = 5000;
\r
1866 appData.autoRaiseBoard = TRUE;
\r
1867 appData.localLineEditing = TRUE;
\r
1868 appData.colorize = TRUE;
\r
1869 appData.reuseFirst = TRUE;
\r
1870 appData.reuseSecond = TRUE;
\r
1871 appData.blindfold = FALSE;
\r
1872 appData.icsEngineAnalyze = FALSE;
\r
1873 memset(&dcb, 0, sizeof(DCB)); // required by VS 2002 +
\r
1874 dcb.DCBlength = sizeof(DCB);
\r
1875 dcb.BaudRate = 9600;
\r
1876 dcb.fBinary = TRUE;
\r
1877 dcb.fParity = FALSE;
\r
1878 dcb.fOutxCtsFlow = FALSE;
\r
1879 dcb.fOutxDsrFlow = FALSE;
\r
1880 dcb.fDtrControl = DTR_CONTROL_ENABLE;
\r
1881 dcb.fDsrSensitivity = FALSE;
\r
1882 dcb.fTXContinueOnXoff = TRUE;
\r
1883 dcb.fOutX = FALSE;
\r
1885 dcb.fNull = FALSE;
\r
1886 dcb.fRtsControl = RTS_CONTROL_ENABLE;
\r
1887 dcb.fAbortOnError = FALSE;
\r
1889 dcb.Parity = SPACEPARITY;
\r
1890 dcb.StopBits = ONESTOPBIT;
\r
1891 settingsFileName = SETTINGS_FILE;
\r
1892 saveSettingsOnExit = TRUE;
\r
1893 boardX = CW_USEDEFAULT;
\r
1894 boardY = CW_USEDEFAULT;
\r
1895 consoleX = CW_USEDEFAULT;
\r
1896 consoleY = CW_USEDEFAULT;
\r
1897 consoleW = CW_USEDEFAULT;
\r
1898 consoleH = CW_USEDEFAULT;
\r
1899 analysisX = CW_USEDEFAULT;
\r
1900 analysisY = CW_USEDEFAULT;
\r
1901 analysisW = CW_USEDEFAULT;
\r
1902 analysisH = CW_USEDEFAULT;
\r
1903 commentX = CW_USEDEFAULT;
\r
1904 commentY = CW_USEDEFAULT;
\r
1905 commentW = CW_USEDEFAULT;
\r
1906 commentH = CW_USEDEFAULT;
\r
1907 editTagsX = CW_USEDEFAULT;
\r
1908 editTagsY = CW_USEDEFAULT;
\r
1909 editTagsW = CW_USEDEFAULT;
\r
1910 editTagsH = CW_USEDEFAULT;
\r
1911 gameListX = CW_USEDEFAULT;
\r
1912 gameListY = CW_USEDEFAULT;
\r
1913 gameListW = CW_USEDEFAULT;
\r
1914 gameListH = CW_USEDEFAULT;
\r
1915 icsTextMenuString = ICS_TEXT_MENU_DEFAULT;
\r
1916 icsNames = ICS_NAMES;
\r
1917 firstChessProgramNames = FCP_NAMES;
\r
1918 secondChessProgramNames = SCP_NAMES;
\r
1919 appData.initialMode = "";
\r
1920 appData.variant = "normal";
\r
1921 appData.firstProtocolVersion = PROTOVER;
\r
1922 appData.secondProtocolVersion = PROTOVER;
\r
1923 appData.showButtonBar = TRUE;
\r
1925 /* [AS] New properties (see comments in header file) */
\r
1926 appData.firstScoreIsAbsolute = FALSE;
\r
1927 appData.secondScoreIsAbsolute = FALSE;
\r
1928 appData.saveExtendedInfoInPGN = FALSE;
\r
1929 appData.hideThinkingFromHuman = FALSE;
\r
1930 appData.liteBackTextureFile = "";
\r
1931 appData.liteBackTextureMode = BACK_TEXTURE_MODE_PLAIN;
\r
1932 appData.darkBackTextureFile = "";
\r
1933 appData.darkBackTextureMode = BACK_TEXTURE_MODE_PLAIN;
\r
1934 appData.renderPiecesWithFont = "";
\r
1935 appData.fontToPieceTable = "";
\r
1936 appData.fontBackColorWhite = 0;
\r
1937 appData.fontForeColorWhite = 0;
\r
1938 appData.fontBackColorBlack = 0;
\r
1939 appData.fontForeColorBlack = 0;
\r
1940 appData.fontPieceSize = 80;
\r
1941 appData.overrideLineGap = 1;
\r
1942 appData.adjudicateLossThreshold = 0;
\r
1943 appData.delayBeforeQuit = 0;
\r
1944 appData.delayAfterQuit = 0;
\r
1945 appData.nameOfDebugFile = "winboard.debug";
\r
1946 appData.pgnEventHeader = "Computer Chess Game";
\r
1947 appData.defaultFrcPosition = -1;
\r
1948 appData.gameListTags = GLT_DEFAULT_TAGS;
\r
1949 appData.saveOutOfBookInfo = TRUE;
\r
1950 appData.showEvalInMoveHistory = TRUE;
\r
1951 appData.evalHistColorWhite = ParseColorName( "#FFFFB0" );
\r
1952 appData.evalHistColorBlack = ParseColorName( "#AD5D3D" );
\r
1953 appData.highlightMoveWithArrow = FALSE;
\r
1954 appData.highlightArrowColor = ParseColorName( "#FFFF80" );
\r
1955 appData.useStickyWindows = TRUE;
\r
1956 appData.adjudicateDrawMoves = 0;
\r
1957 appData.autoDisplayComment = TRUE;
\r
1958 appData.autoDisplayTags = TRUE;
\r
1959 appData.firstIsUCI = FALSE;
\r
1960 appData.secondIsUCI = FALSE;
\r
1961 appData.firstHasOwnBookUCI = TRUE;
\r
1962 appData.secondHasOwnBookUCI = TRUE;
\r
1963 appData.polyglotDir = "";
\r
1964 appData.usePolyglotBook = FALSE;
\r
1965 appData.polyglotBook = "";
\r
1966 appData.defaultHashSize = 64;
\r
1967 appData.defaultCacheSizeEGTB = 4;
\r
1968 appData.defaultPathEGTB = "c:\\egtb";
\r
1969 appData.firstOptions = "";
\r
1970 appData.secondOptions = "";
\r
1972 InitWindowPlacement( &wpMoveHistory );
\r
1973 InitWindowPlacement( &wpEvalGraph );
\r
1974 InitWindowPlacement( &wpEngineOutput );
\r
1976 /* [HGM] User-selectable board size, adjudication control, miscellaneous */
\r
1977 appData.NrFiles = -1;
\r
1978 appData.NrRanks = -1;
\r
1979 appData.holdingsSize = -1;
\r
1980 appData.testClaims = FALSE;
\r
1981 appData.checkMates = FALSE;
\r
1982 appData.materialDraws= FALSE;
\r
1983 appData.trivialDraws = FALSE;
\r
1984 appData.ruleMoves = 51;
\r
1985 appData.drawRepeats = 6;
\r
1986 appData.matchPause = 10000;
\r
1987 appData.alphaRank = FALSE;
\r
1988 appData.allWhite = FALSE;
\r
1989 appData.upsideDown = FALSE;
\r
1990 appData.serverPause = 15;
\r
1991 appData.serverMovesName = NULL;
\r
1992 appData.suppressLoadMoves = FALSE;
\r
1993 appData.firstTimeOdds = 1;
\r
1994 appData.secondTimeOdds = 1;
\r
1995 appData.firstAccumulateTC = 1; // combine previous and current sessions
\r
1996 appData.secondAccumulateTC = 1;
\r
1997 appData.firstNPS = -1; // [HGM] nps: use wall-clock time
\r
1998 appData.secondNPS = -1;
\r
1999 appData.engineComments = 1;
\r
2000 appData.smpCores = 1; // [HGM] SMP: max nr of cores
\r
2001 appData.egtFormats = "";
\r
2004 appData.zippyTalk = ZIPPY_TALK;
\r
2005 appData.zippyPlay = ZIPPY_PLAY;
\r
2006 appData.zippyLines = ZIPPY_LINES;
\r
2007 appData.zippyPinhead = ZIPPY_PINHEAD;
\r
2008 appData.zippyPassword = ZIPPY_PASSWORD;
\r
2009 appData.zippyPassword2 = ZIPPY_PASSWORD2;
\r
2010 appData.zippyWrongPassword = ZIPPY_WRONG_PASSWORD;
\r
2011 appData.zippyAcceptOnly = ZIPPY_ACCEPT_ONLY;
\r
2012 appData.zippyUseI = ZIPPY_USE_I;
\r
2013 appData.zippyBughouse = ZIPPY_BUGHOUSE;
\r
2014 appData.zippyNoplayCrafty = ZIPPY_NOPLAY_CRAFTY;
\r
2015 appData.zippyGameEnd = ZIPPY_GAME_END;
\r
2016 appData.zippyGameStart = ZIPPY_GAME_START;
\r
2017 appData.zippyAdjourn = ZIPPY_ADJOURN;
\r
2018 appData.zippyAbort = ZIPPY_ABORT;
\r
2019 appData.zippyVariants = ZIPPY_VARIANTS;
\r
2020 appData.zippyMaxGames = ZIPPY_MAX_GAMES;
\r
2021 appData.zippyReplayTimeout = ZIPPY_REPLAY_TIMEOUT;
\r
2024 /* Point font array elements to structures and
\r
2025 parse default font names */
\r
2026 for (i=0; i<NUM_FONTS; i++) {
\r
2027 for (j=0; j<NUM_SIZES; j++) {
\r
2028 font[j][i] = &fontRec[j][i];
\r
2029 ParseFontName(font[j][i]->def, &font[j][i]->mfp);
\r
2033 /* Parse default settings file if any */
\r
2034 if (ParseSettingsFile(settingsFileName, buf)) {
\r
2035 settingsFileName = strdup(buf);
\r
2038 /* Parse command line */
\r
2039 ParseArgs(StringGet, &lpCmdLine);
\r
2041 /* [HGM] make sure board size is acceptable */
\r
2042 if(appData.NrFiles > BOARD_SIZE ||
\r
2043 appData.NrRanks > BOARD_SIZE )
\r
2044 DisplayFatalError("Recompile with BOARD_SIZE > 12, to support this size", 0, 2);
\r
2046 /* [HGM] After parsing the options from the .ini file, and overruling them
\r
2047 * with options from the command line, we now make an even higher priority
\r
2048 * overrule by WB options attached to the engine command line. This so that
\r
2049 * tournament managers can use WB options (such as /timeOdds) that follow
\r
2052 if(appData.firstChessProgram != NULL) {
\r
2053 char *p = StrStr(appData.firstChessProgram, "WBopt");
\r
2054 static char *f = "first";
\r
2055 char buf[MSG_SIZ], *q = buf;
\r
2056 if(p != NULL) { // engine command line contains WinBoard options
\r
2057 sprintf(buf, p+6, f, f, f, f, f, f, f, f, f, f); // replace %s in them by "first"
\r
2058 ParseArgs(StringGet, &q);
\r
2059 p[-1] = 0; // cut them offengine command line
\r
2062 // now do same for second chess program
\r
2063 if(appData.secondChessProgram != NULL) {
\r
2064 char *p = StrStr(appData.secondChessProgram, "WBopt");
\r
2065 static char *s = "second";
\r
2066 char buf[MSG_SIZ], *q = buf;
\r
2067 if(p != NULL) { // engine command line contains WinBoard options
\r
2068 sprintf(buf, p+6, s, s, s, s, s, s, s, s, s, s); // replace %s in them by "first"
\r
2069 ParseArgs(StringGet, &q);
\r
2070 p[-1] = 0; // cut them offengine command line
\r
2075 /* Propagate options that affect others */
\r
2076 if (appData.matchMode || appData.matchGames) chessProgram = TRUE;
\r
2077 if (appData.icsActive || appData.noChessProgram) {
\r
2078 chessProgram = FALSE; /* not local chess program mode */
\r
2081 /* Open startup dialog if needed */
\r
2082 if ((!appData.noChessProgram && !chessProgram && !appData.icsActive) ||
\r
2083 (appData.icsActive && *appData.icsHost == NULLCHAR) ||
\r
2084 (chessProgram && (*appData.firstChessProgram == NULLCHAR ||
\r
2085 *appData.secondChessProgram == NULLCHAR))) {
\r
2088 lpProc = MakeProcInstance((FARPROC)StartupDialog, hInst);
\r
2089 DialogBox(hInst, MAKEINTRESOURCE(DLG_Startup), NULL, (DLGPROC)lpProc);
\r
2090 FreeProcInstance(lpProc);
\r
2093 /* Make sure save files land in the right (?) directory */
\r
2094 if (GetFullPathName(appData.saveGameFile, MSG_SIZ, buf, &dummy)) {
\r
2095 appData.saveGameFile = strdup(buf);
\r
2097 if (GetFullPathName(appData.savePositionFile, MSG_SIZ, buf, &dummy)) {
\r
2098 appData.savePositionFile = strdup(buf);
\r
2101 /* Finish initialization for fonts and sounds */
\r
2102 for (i=0; i<NUM_FONTS; i++) {
\r
2103 for (j=0; j<NUM_SIZES; j++) {
\r
2104 CreateFontInMF(font[j][i]);
\r
2107 /* xboard, and older WinBoards, controlled the move sound with the
\r
2108 appData.ringBellAfterMoves option. In the current WinBoard, we
\r
2109 always turn the option on (so that the backend will call us),
\r
2110 then let the user turn the sound off by setting it to silence if
\r
2111 desired. To accommodate old winboard.ini files saved by old
\r
2112 versions of WinBoard, we also turn off the sound if the option
\r
2113 was initially set to false. */
\r
2114 if (!appData.ringBellAfterMoves) {
\r
2115 sounds[(int)SoundMove].name = strdup("");
\r
2116 appData.ringBellAfterMoves = TRUE;
\r
2118 GetCurrentDirectory(MSG_SIZ, currDir);
\r
2119 SetCurrentDirectory(installDir);
\r
2121 SetCurrentDirectory(currDir);
\r
2123 p = icsTextMenuString;
\r
2124 if (p[0] == '@') {
\r
2125 FILE* f = fopen(p + 1, "r");
\r
2127 DisplayFatalError(p + 1, errno, 2);
\r
2130 i = fread(buf, 1, sizeof(buf)-1, f);
\r
2132 buf[i] = NULLCHAR;
\r
2135 ParseIcsTextMenu(strdup(p));
\r
2142 HMENU hmenu = GetMenu(hwndMain);
\r
2144 (void) EnableMenuItem(hmenu, IDM_CommPort,
\r
2145 MF_BYCOMMAND|((appData.icsActive &&
\r
2146 *appData.icsCommPort != NULLCHAR) ?
\r
2147 MF_ENABLED : MF_GRAYED));
\r
2148 (void) CheckMenuItem(hmenu, IDM_SaveSettingsOnExit,
\r
2149 MF_BYCOMMAND|(saveSettingsOnExit ?
\r
2150 MF_CHECKED : MF_UNCHECKED));
\r
2155 SaveSettings(char* name)
\r
2158 ArgDescriptor *ad;
\r
2159 WINDOWPLACEMENT wp;
\r
2160 char dir[MSG_SIZ];
\r
2162 if (!hwndMain) return;
\r
2164 GetCurrentDirectory(MSG_SIZ, dir);
\r
2165 SetCurrentDirectory(installDir);
\r
2166 f = fopen(name, "w");
\r
2167 SetCurrentDirectory(dir);
\r
2169 DisplayError(name, errno);
\r
2172 fprintf(f, ";\n");
\r
2173 fprintf(f, "; %s %s.%s Save Settings file\n", PRODUCT, VERSION, PATCHLEVEL);
\r
2174 fprintf(f, ";\n");
\r
2175 fprintf(f, "; You can edit the values of options that are already set in this file,\n");
\r
2176 fprintf(f, "; but if you add other options, the next Save Settings will not save them.\n");
\r
2177 fprintf(f, "; Use a shortcut, an @indirection file, or a .bat file instead.\n");
\r
2178 fprintf(f, ";\n");
\r
2180 wp.length = sizeof(WINDOWPLACEMENT);
\r
2181 GetWindowPlacement(hwndMain, &wp);
\r
2182 boardX = wp.rcNormalPosition.left;
\r
2183 boardY = wp.rcNormalPosition.top;
\r
2185 if (hwndConsole) {
\r
2186 GetWindowPlacement(hwndConsole, &wp);
\r
2187 consoleX = wp.rcNormalPosition.left;
\r
2188 consoleY = wp.rcNormalPosition.top;
\r
2189 consoleW = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2190 consoleH = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2193 if (analysisDialog) {
\r
2194 GetWindowPlacement(analysisDialog, &wp);
\r
2195 analysisX = wp.rcNormalPosition.left;
\r
2196 analysisY = wp.rcNormalPosition.top;
\r
2197 analysisW = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2198 analysisH = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2201 if (commentDialog) {
\r
2202 GetWindowPlacement(commentDialog, &wp);
\r
2203 commentX = wp.rcNormalPosition.left;
\r
2204 commentY = wp.rcNormalPosition.top;
\r
2205 commentW = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2206 commentH = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2209 if (editTagsDialog) {
\r
2210 GetWindowPlacement(editTagsDialog, &wp);
\r
2211 editTagsX = wp.rcNormalPosition.left;
\r
2212 editTagsY = wp.rcNormalPosition.top;
\r
2213 editTagsW = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2214 editTagsH = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2217 if (gameListDialog) {
\r
2218 GetWindowPlacement(gameListDialog, &wp);
\r
2219 gameListX = wp.rcNormalPosition.left;
\r
2220 gameListY = wp.rcNormalPosition.top;
\r
2221 gameListW = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2222 gameListH = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2225 /* [AS] Move history */
\r
2226 wpMoveHistory.visible = MoveHistoryIsUp();
\r
2228 if( moveHistoryDialog ) {
\r
2229 GetWindowPlacement(moveHistoryDialog, &wp);
\r
2230 wpMoveHistory.x = wp.rcNormalPosition.left;
\r
2231 wpMoveHistory.y = wp.rcNormalPosition.top;
\r
2232 wpMoveHistory.width = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2233 wpMoveHistory.height = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2236 /* [AS] Eval graph */
\r
2237 wpEvalGraph.visible = EvalGraphIsUp();
\r
2239 if( evalGraphDialog ) {
\r
2240 GetWindowPlacement(evalGraphDialog, &wp);
\r
2241 wpEvalGraph.x = wp.rcNormalPosition.left;
\r
2242 wpEvalGraph.y = wp.rcNormalPosition.top;
\r
2243 wpEvalGraph.width = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2244 wpEvalGraph.height = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2247 /* [AS] Engine output */
\r
2248 wpEngineOutput.visible = EngineOutputIsUp();
\r
2250 if( engineOutputDialog ) {
\r
2251 GetWindowPlacement(engineOutputDialog, &wp);
\r
2252 wpEngineOutput.x = wp.rcNormalPosition.left;
\r
2253 wpEngineOutput.y = wp.rcNormalPosition.top;
\r
2254 wpEngineOutput.width = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2255 wpEngineOutput.height = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2258 for (ad = argDescriptors; ad->argName != NULL; ad++) {
\r
2259 if (!ad->save) continue;
\r
2260 switch (ad->argType) {
\r
2263 char *p = *(char **)ad->argLoc;
\r
2264 if ((strchr(p, '\\') || strchr(p, '\n')) && !strchr(p, '}')) {
\r
2265 /* Quote multiline values or \-containing values
\r
2266 with { } if possible */
\r
2267 fprintf(f, "/%s={%s}\n", ad->argName, p);
\r
2269 /* Else quote with " " */
\r
2270 fprintf(f, "/%s=\"", ad->argName);
\r
2272 if (*p == '\n') fprintf(f, "\n");
\r
2273 else if (*p == '\r') fprintf(f, "\\r");
\r
2274 else if (*p == '\t') fprintf(f, "\\t");
\r
2275 else if (*p == '\b') fprintf(f, "\\b");
\r
2276 else if (*p == '\f') fprintf(f, "\\f");
\r
2277 else if (*p < ' ') fprintf(f, "\\%03o", *p);
\r
2278 else if (*p == '\"') fprintf(f, "\\\"");
\r
2279 else if (*p == '\\') fprintf(f, "\\\\");
\r
2283 fprintf(f, "\"\n");
\r
2288 fprintf(f, "/%s=%d\n", ad->argName, *(int *)ad->argLoc);
\r
2291 fprintf(f, "/%s=%g\n", ad->argName, *(float *)ad->argLoc);
\r
2294 fprintf(f, "/%s=%s\n", ad->argName,
\r
2295 (*(Boolean *)ad->argLoc) ? "true" : "false");
\r
2298 if (*(Boolean *)ad->argLoc) fprintf(f, "/%s\n", ad->argName);
\r
2301 if (!*(Boolean *)ad->argLoc) fprintf(f, "/%s\n", ad->argName);
\r
2305 COLORREF color = *(COLORREF *)ad->argLoc;
\r
2306 fprintf(f, "/%s=#%02lx%02lx%02lx\n", ad->argName,
\r
2307 color&0xff, (color>>8)&0xff, (color>>16)&0xff);
\r
2312 MyTextAttribs* ta = &textAttribs[(ColorClass)ad->argLoc];
\r
2313 fprintf(f, "/%s=\"%s%s%s%s%s#%02lx%02lx%02lx\"\n", ad->argName,
\r
2314 (ta->effects & CFE_BOLD) ? "b" : "",
\r
2315 (ta->effects & CFE_ITALIC) ? "i" : "",
\r
2316 (ta->effects & CFE_UNDERLINE) ? "u" : "",
\r
2317 (ta->effects & CFE_STRIKEOUT) ? "s" : "",
\r
2318 (ta->effects) ? " " : "",
\r
2319 ta->color&0xff, (ta->color >> 8)&0xff, (ta->color >> 16)&0xff);
\r
2323 if (strchr(*(char **)ad->argLoc, '\"')) {
\r
2324 fprintf(f, "/%s='%s'\n", ad->argName, *(char **)ad->argLoc);
\r
2326 fprintf(f, "/%s=\"%s\"\n", ad->argName, *(char **)ad->argLoc);
\r
2329 case ArgBoardSize:
\r
2330 fprintf(f, "/%s=%s\n", ad->argName,
\r
2331 sizeInfo[*(BoardSize *)ad->argLoc].name);
\r
2336 for (bs=0; bs<NUM_SIZES; bs++) {
\r
2337 MyFontParams *mfp = &font[bs][(int) ad->argLoc]->mfp;
\r
2338 fprintf(f, "/size=%s ", sizeInfo[bs].name);
\r
2339 fprintf(f, "/%s=\"%s:%g%s%s%s%s%s\"\n",
\r
2340 ad->argName, mfp->faceName, mfp->pointSize,
\r
2341 mfp->bold || mfp->italic || mfp->underline || mfp->strikeout ? " " : "",
\r
2342 mfp->bold ? "b" : "",
\r
2343 mfp->italic ? "i" : "",
\r
2344 mfp->underline ? "u" : "",
\r
2345 mfp->strikeout ? "s" : "");
\r
2349 case ArgCommSettings:
\r
2350 PrintCommSettings(f, ad->argName, (DCB *)ad->argLoc);
\r
2352 case ArgSettingsFilename: ;
\r
2360 /*---------------------------------------------------------------------------*\
\r
2362 * GDI board drawing routines
\r
2364 \*---------------------------------------------------------------------------*/
\r
2366 /* [AS] Draw square using background texture */
\r
2367 static void DrawTile( int dx, int dy, int dw, int dh, HDC dst, HDC src, int mode, int sx, int sy )
\r
2372 return; /* Should never happen! */
\r
2375 SetGraphicsMode( dst, GM_ADVANCED );
\r
2382 /* X reflection */
\r
2387 x.eDx = (FLOAT) dw + dx - 1;
\r
2390 SetWorldTransform( dst, &x );
\r
2393 /* Y reflection */
\r
2399 x.eDy = (FLOAT) dh + dy - 1;
\r
2401 SetWorldTransform( dst, &x );
\r
2409 x.eDx = (FLOAT) dx;
\r
2410 x.eDy = (FLOAT) dy;
\r
2413 SetWorldTransform( dst, &x );
\r
2417 BitBlt( dst, dx, dy, dw, dh, src, sx, sy, SRCCOPY );
\r
2425 SetWorldTransform( dst, &x );
\r
2427 ModifyWorldTransform( dst, 0, MWT_IDENTITY );
\r
2430 /* [AS] [HGM] Make room for more piece types, so all pieces can be different */
\r
2432 PM_WP = (int) WhitePawn,
\r
2433 PM_WN = (int) WhiteKnight,
\r
2434 PM_WB = (int) WhiteBishop,
\r
2435 PM_WR = (int) WhiteRook,
\r
2436 PM_WQ = (int) WhiteQueen,
\r
2437 PM_WF = (int) WhiteFerz,
\r
2438 PM_WW = (int) WhiteWazir,
\r
2439 PM_WE = (int) WhiteAlfil,
\r
2440 PM_WM = (int) WhiteMan,
\r
2441 PM_WO = (int) WhiteCannon,
\r
2442 PM_WU = (int) WhiteUnicorn,
\r
2443 PM_WH = (int) WhiteNightrider,
\r
2444 PM_WA = (int) WhiteAngel,
\r
2445 PM_WC = (int) WhiteMarshall,
\r
2446 PM_WAB = (int) WhiteCardinal,
\r
2447 PM_WD = (int) WhiteDragon,
\r
2448 PM_WL = (int) WhiteLance,
\r
2449 PM_WS = (int) WhiteCobra,
\r
2450 PM_WV = (int) WhiteFalcon,
\r
2451 PM_WSG = (int) WhiteSilver,
\r
2452 PM_WG = (int) WhiteGrasshopper,
\r
2453 PM_WK = (int) WhiteKing,
\r
2454 PM_BP = (int) BlackPawn,
\r
2455 PM_BN = (int) BlackKnight,
\r
2456 PM_BB = (int) BlackBishop,
\r
2457 PM_BR = (int) BlackRook,
\r
2458 PM_BQ = (int) BlackQueen,
\r
2459 PM_BF = (int) BlackFerz,
\r
2460 PM_BW = (int) BlackWazir,
\r
2461 PM_BE = (int) BlackAlfil,
\r
2462 PM_BM = (int) BlackMan,
\r
2463 PM_BO = (int) BlackCannon,
\r
2464 PM_BU = (int) BlackUnicorn,
\r
2465 PM_BH = (int) BlackNightrider,
\r
2466 PM_BA = (int) BlackAngel,
\r
2467 PM_BC = (int) BlackMarshall,
\r
2468 PM_BG = (int) BlackGrasshopper,
\r
2469 PM_BAB = (int) BlackCardinal,
\r
2470 PM_BD = (int) BlackDragon,
\r
2471 PM_BL = (int) BlackLance,
\r
2472 PM_BS = (int) BlackCobra,
\r
2473 PM_BV = (int) BlackFalcon,
\r
2474 PM_BSG = (int) BlackSilver,
\r
2475 PM_BK = (int) BlackKing
\r
2478 static HFONT hPieceFont = NULL;
\r
2479 static HBITMAP hPieceMask[(int) EmptySquare];
\r
2480 static HBITMAP hPieceFace[(int) EmptySquare];
\r
2481 static int fontBitmapSquareSize = 0;
\r
2482 static char pieceToFontChar[(int) EmptySquare] =
\r
2483 { 'p', 'n', 'b', 'r', 'q',
\r
2484 'n', 'b', 'p', 'n', 'b', 'r', 'b', 'r', 'q', 'k',
\r
2485 'k', 'o', 'm', 'v', 't', 'w',
\r
2486 'v', 't', 'o', 'm', 'v', 't', 'v', 't', 'w', 'l',
\r
2489 extern BOOL SetCharTable( char *table, const char * map );
\r
2490 /* [HGM] moved to backend.c */
\r
2492 static void SetPieceBackground( HDC hdc, COLORREF color, int mode )
\r
2495 BYTE r1 = GetRValue( color );
\r
2496 BYTE g1 = GetGValue( color );
\r
2497 BYTE b1 = GetBValue( color );
\r
2503 /* Create a uniform background first */
\r
2504 hbrush = CreateSolidBrush( color );
\r
2505 SetRect( &rc, 0, 0, squareSize, squareSize );
\r
2506 FillRect( hdc, &rc, hbrush );
\r
2507 DeleteObject( hbrush );
\r
2510 /* Vertical gradient, good for pawn, knight and rook, less for queen and king */
\r
2511 int steps = squareSize / 2;
\r
2514 for( i=0; i<steps; i++ ) {
\r
2515 BYTE r = r1 - (r1-r2) * i / steps;
\r
2516 BYTE g = g1 - (g1-g2) * i / steps;
\r
2517 BYTE b = b1 - (b1-b2) * i / steps;
\r
2519 hbrush = CreateSolidBrush( RGB(r,g,b) );
\r
2520 SetRect( &rc, i + squareSize - steps, 0, i + squareSize - steps + 1, squareSize );
\r
2521 FillRect( hdc, &rc, hbrush );
\r
2522 DeleteObject(hbrush);
\r
2525 else if( mode == 2 ) {
\r
2526 /* Diagonal gradient, good more or less for every piece */
\r
2527 POINT triangle[3];
\r
2528 HPEN hpen = SelectObject( hdc, GetStockObject(NULL_PEN) );
\r
2529 HBRUSH hbrush_old;
\r
2530 int steps = squareSize;
\r
2533 triangle[0].x = squareSize - steps;
\r
2534 triangle[0].y = squareSize;
\r
2535 triangle[1].x = squareSize;
\r
2536 triangle[1].y = squareSize;
\r
2537 triangle[2].x = squareSize;
\r
2538 triangle[2].y = squareSize - steps;
\r
2540 for( i=0; i<steps; i++ ) {
\r
2541 BYTE r = r1 - (r1-r2) * i / steps;
\r
2542 BYTE g = g1 - (g1-g2) * i / steps;
\r
2543 BYTE b = b1 - (b1-b2) * i / steps;
\r
2545 hbrush = CreateSolidBrush( RGB(r,g,b) );
\r
2546 hbrush_old = SelectObject( hdc, hbrush );
\r
2547 Polygon( hdc, triangle, 3 );
\r
2548 SelectObject( hdc, hbrush_old );
\r
2549 DeleteObject(hbrush);
\r
2554 SelectObject( hdc, hpen );
\r
2559 [AS] The method I use to create the bitmaps it a bit tricky, but it
\r
2560 seems to work ok. The main problem here is to find the "inside" of a chess
\r
2561 piece: follow the steps as explained below.
\r
2563 static void CreatePieceMaskFromFont( HDC hdc_window, HDC hdc, int index )
\r
2567 COLORREF chroma = RGB(0xFF,0x00,0xFF);
\r
2571 int backColor = whitePieceColor;
\r
2572 int foreColor = blackPieceColor;
\r
2574 if( index < (int)BlackPawn && appData.fontBackColorWhite != appData.fontForeColorWhite ) {
\r
2575 backColor = appData.fontBackColorWhite;
\r
2576 foreColor = appData.fontForeColorWhite;
\r
2578 else if( index >= (int)BlackPawn && appData.fontBackColorBlack != appData.fontForeColorBlack ) {
\r
2579 backColor = appData.fontBackColorBlack;
\r
2580 foreColor = appData.fontForeColorBlack;
\r
2584 hbm = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
\r
2586 hbm_old = SelectObject( hdc, hbm );
\r
2590 rc.right = squareSize;
\r
2591 rc.bottom = squareSize;
\r
2593 /* Step 1: background is now black */
\r
2594 FillRect( hdc, &rc, GetStockObject(BLACK_BRUSH) );
\r
2596 GetTextExtentPoint32( hdc, &pieceToFontChar[index], 1, &sz );
\r
2598 pt.x = (squareSize - sz.cx) / 2;
\r
2599 pt.y = (squareSize - sz.cy) / 2;
\r
2601 SetBkMode( hdc, TRANSPARENT );
\r
2602 SetTextColor( hdc, chroma );
\r
2603 /* Step 2: the piece has been drawn in purple, there are now black and purple in this bitmap */
\r
2604 TextOut( hdc, pt.x, pt.y, &pieceToFontChar[appData.allWhite && index >= (int)BlackPawn ? index - (int)BlackPawn : index], 1 );
\r
2606 SelectObject( hdc, GetStockObject(WHITE_BRUSH) );
\r
2607 /* Step 3: the area outside the piece is filled with white */
\r
2608 // FloodFill( hdc, 0, 0, chroma );
\r
2609 ExtFloodFill( hdc, 0, 0, 0, FLOODFILLSURFACE );
\r
2610 ExtFloodFill( hdc, 0, squareSize-1, 0, FLOODFILLSURFACE ); // [HGM] fill from all 4 corners, for if piece too big
\r
2611 ExtFloodFill( hdc, squareSize-1, 0, 0, FLOODFILLSURFACE );
\r
2612 ExtFloodFill( hdc, squareSize-1, squareSize-1, 0, FLOODFILLSURFACE );
\r
2613 SelectObject( hdc, GetStockObject(BLACK_BRUSH) );
\r
2615 Step 4: this is the tricky part, the area inside the piece is filled with black,
\r
2616 but if the start point is not inside the piece we're lost!
\r
2617 There should be a better way to do this... if we could create a region or path
\r
2618 from the fill operation we would be fine for example.
\r
2620 // FloodFill( hdc, squareSize / 2, squareSize / 2, RGB(0xFF,0xFF,0xFF) );
\r
2621 ExtFloodFill( hdc, squareSize / 2, squareSize / 2, RGB(0xFF,0xFF,0xFF), FLOODFILLBORDER );
\r
2623 { /* [HGM] shave off edges of mask, in an attempt to correct for the fact that FloodFill does not work correctly under Win XP */
\r
2624 HDC dc2 = CreateCompatibleDC( hdc_window );
\r
2625 HBITMAP bm2 = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
\r
2627 SelectObject( dc2, bm2 );
\r
2628 BitBlt( dc2, 0, 0, squareSize, squareSize, hdc, 0, 0, SRCCOPY ); // make copy
\r
2629 BitBlt( hdc, 0, 1, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );
\r
2630 BitBlt( hdc, 2, 1, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );
\r
2631 BitBlt( hdc, 1, 0, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );
\r
2632 BitBlt( hdc, 1, 2, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );
\r
2635 DeleteObject( bm2 );
\r
2638 SetTextColor( hdc, 0 );
\r
2640 Step 5: some fonts have "disconnected" areas that are skipped by the fill:
\r
2641 draw the piece again in black for safety.
\r
2643 TextOut( hdc, pt.x, pt.y, &pieceToFontChar[appData.allWhite && index >= (int)BlackPawn ? index - (int)BlackPawn : index], 1 );
\r
2645 SelectObject( hdc, hbm_old );
\r
2647 if( hPieceMask[index] != NULL ) {
\r
2648 DeleteObject( hPieceMask[index] );
\r
2651 hPieceMask[index] = hbm;
\r
2654 hbm = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
\r
2656 SelectObject( hdc, hbm );
\r
2659 HDC dc1 = CreateCompatibleDC( hdc_window );
\r
2660 HDC dc2 = CreateCompatibleDC( hdc_window );
\r
2661 HBITMAP bm2 = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
\r
2663 SelectObject( dc1, hPieceMask[index] );
\r
2664 SelectObject( dc2, bm2 );
\r
2665 FillRect( dc2, &rc, GetStockObject(WHITE_BRUSH) );
\r
2666 BitBlt( dc2, 0, 0, squareSize, squareSize, dc1, 0, 0, SRCINVERT );
\r
2669 Now dc2 contains the inverse of the piece mask, i.e. a mask that preserves
\r
2670 the piece background and deletes (makes transparent) the rest.
\r
2671 Thanks to that mask, we are free to paint the background with the greates
\r
2672 freedom, as we'll be able to mask off the unwanted parts when finished.
\r
2673 We use this, to make gradients and give the pieces a "roundish" look.
\r
2675 SetPieceBackground( hdc, backColor, 2 );
\r
2676 BitBlt( hdc, 0, 0, squareSize, squareSize, dc2, 0, 0, SRCAND );
\r
2680 DeleteObject( bm2 );
\r
2683 SetTextColor( hdc, foreColor );
\r
2684 TextOut( hdc, pt.x, pt.y, &pieceToFontChar[appData.allWhite && index >= (int)BlackPawn ? index - (int)BlackPawn : index], 1 );
\r
2686 SelectObject( hdc, hbm_old );
\r
2688 if( hPieceFace[index] != NULL ) {
\r
2689 DeleteObject( hPieceFace[index] );
\r
2692 hPieceFace[index] = hbm;
\r
2695 static int TranslatePieceToFontPiece( int piece )
\r
2725 case BlackMarshall:
\r
2729 case BlackNightrider:
\r
2735 case BlackUnicorn:
\r
2739 case BlackGrasshopper:
\r
2751 case BlackCardinal:
\r
2758 case WhiteMarshall:
\r
2762 case WhiteNightrider:
\r
2768 case WhiteUnicorn:
\r
2772 case WhiteGrasshopper:
\r
2784 case WhiteCardinal:
\r
2793 void CreatePiecesFromFont()
\r
2796 HDC hdc_window = NULL;
\r
2802 if( fontBitmapSquareSize < 0 ) {
\r
2803 /* Something went seriously wrong in the past: do not try to recreate fonts! */
\r
2807 if( appData.renderPiecesWithFont == NULL || appData.renderPiecesWithFont[0] == NULLCHAR || appData.renderPiecesWithFont[0] == '*' ) {
\r
2808 fontBitmapSquareSize = -1;
\r
2812 if( fontBitmapSquareSize != squareSize ) {
\r
2813 hdc_window = GetDC( hwndMain );
\r
2814 hdc = CreateCompatibleDC( hdc_window );
\r
2816 if( hPieceFont != NULL ) {
\r
2817 DeleteObject( hPieceFont );
\r
2820 for( i=0; i<=(int)BlackKing; i++ ) {
\r
2821 hPieceMask[i] = NULL;
\r
2822 hPieceFace[i] = NULL;
\r
2828 if( appData.fontPieceSize >= 50 && appData.fontPieceSize <= 150 ) {
\r
2829 fontHeight = appData.fontPieceSize;
\r
2832 fontHeight = (fontHeight * squareSize) / 100;
\r
2834 lf.lfHeight = -MulDiv( fontHeight, GetDeviceCaps(hdc, LOGPIXELSY), 72 );
\r
2836 lf.lfEscapement = 0;
\r
2837 lf.lfOrientation = 0;
\r
2838 lf.lfWeight = FW_NORMAL;
\r
2840 lf.lfUnderline = 0;
\r
2841 lf.lfStrikeOut = 0;
\r
2842 lf.lfCharSet = DEFAULT_CHARSET;
\r
2843 lf.lfOutPrecision = OUT_DEFAULT_PRECIS;
\r
2844 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
\r
2845 lf.lfQuality = PROOF_QUALITY;
\r
2846 lf.lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;
\r
2847 strncpy( lf.lfFaceName, appData.renderPiecesWithFont, sizeof(lf.lfFaceName) );
\r
2848 lf.lfFaceName[ sizeof(lf.lfFaceName) - 1 ] = '\0';
\r
2850 hPieceFont = CreateFontIndirect( &lf );
\r
2852 if( hPieceFont == NULL ) {
\r
2853 fontBitmapSquareSize = -2;
\r
2856 /* Setup font-to-piece character table */
\r
2857 if( ! SetCharTable(pieceToFontChar, appData.fontToPieceTable) ) {
\r
2858 /* No (or wrong) global settings, try to detect the font */
\r
2859 if( strstr(lf.lfFaceName,"Alpha") != NULL ) {
\r
2861 SetCharTable(pieceToFontChar, "phbrqkojntwl");
\r
2863 else if( strstr(lf.lfFaceName,"DiagramTT") != NULL ) {
\r
2864 /* DiagramTT* family */
\r
2865 SetCharTable(pieceToFontChar, "PNLRQKpnlrqk");
\r
2867 else if( strstr(lf.lfFaceName,"WinboardF") != NULL ) {
\r
2868 /* Fairy symbols */
\r
2869 SetCharTable(pieceToFontChar, "PNBRQFEACWMOHIJGDVSLUKpnbrqfeacwmohijgdvsluk");
\r
2871 else if( strstr(lf.lfFaceName,"GC2004D") != NULL ) {
\r
2872 /* Good Companion (Some characters get warped as literal :-( */
\r
2873 char s[] = "1cmWG0ñueOS¯®oYI23wgQU";
\r
2874 s[0]=0xB9; s[1]=0xA9; s[6]=0xB1; s[11]=0xBB; s[12]=0xAB; s[17]=0xB3;
\r
2875 SetCharTable(pieceToFontChar, s);
\r
2878 /* Cases, Condal, Leipzig, Lucena, Marroquin, Merida, Usual */
\r
2879 SetCharTable(pieceToFontChar, "pnbrqkomvtwl");
\r
2883 /* Create bitmaps */
\r
2884 hfont_old = SelectObject( hdc, hPieceFont );
\r
2886 CreatePieceMaskFromFont( hdc_window, hdc, PM_WP );
\r
2887 CreatePieceMaskFromFont( hdc_window, hdc, PM_WN );
\r
2888 CreatePieceMaskFromFont( hdc_window, hdc, PM_WB );
\r
2889 CreatePieceMaskFromFont( hdc_window, hdc, PM_WR );
\r
2890 CreatePieceMaskFromFont( hdc_window, hdc, PM_WQ );
\r
2891 CreatePieceMaskFromFont( hdc_window, hdc, PM_WK );
\r
2892 CreatePieceMaskFromFont( hdc_window, hdc, PM_BP );
\r
2893 CreatePieceMaskFromFont( hdc_window, hdc, PM_BN );
\r
2894 CreatePieceMaskFromFont( hdc_window, hdc, PM_BB );
\r
2895 CreatePieceMaskFromFont( hdc_window, hdc, PM_BR );
\r
2896 CreatePieceMaskFromFont( hdc_window, hdc, PM_BQ );
\r
2897 CreatePieceMaskFromFont( hdc_window, hdc, PM_BK );
\r
2899 CreatePieceMaskFromFont( hdc_window, hdc, PM_WA );
\r
2900 CreatePieceMaskFromFont( hdc_window, hdc, PM_WC );
\r
2901 CreatePieceMaskFromFont( hdc_window, hdc, PM_WF );
\r
2902 CreatePieceMaskFromFont( hdc_window, hdc, PM_WH );
\r
2903 CreatePieceMaskFromFont( hdc_window, hdc, PM_WE );
\r
2904 CreatePieceMaskFromFont( hdc_window, hdc, PM_WW );
\r
2905 CreatePieceMaskFromFont( hdc_window, hdc, PM_WU );
\r
2906 CreatePieceMaskFromFont( hdc_window, hdc, PM_WO );
\r
2907 CreatePieceMaskFromFont( hdc_window, hdc, PM_WG );
\r
2908 CreatePieceMaskFromFont( hdc_window, hdc, PM_WM );
\r
2909 CreatePieceMaskFromFont( hdc_window, hdc, PM_WSG );
\r
2910 CreatePieceMaskFromFont( hdc_window, hdc, PM_WV );
\r
2911 CreatePieceMaskFromFont( hdc_window, hdc, PM_WAB );
\r
2912 CreatePieceMaskFromFont( hdc_window, hdc, PM_WD );
\r
2913 CreatePieceMaskFromFont( hdc_window, hdc, PM_WL );
\r
2914 CreatePieceMaskFromFont( hdc_window, hdc, PM_WS );
\r
2915 CreatePieceMaskFromFont( hdc_window, hdc, PM_BA );
\r
2916 CreatePieceMaskFromFont( hdc_window, hdc, PM_BC );
\r
2917 CreatePieceMaskFromFont( hdc_window, hdc, PM_BF );
\r
2918 CreatePieceMaskFromFont( hdc_window, hdc, PM_BH );
\r
2919 CreatePieceMaskFromFont( hdc_window, hdc, PM_BE );
\r
2920 CreatePieceMaskFromFont( hdc_window, hdc, PM_BW );
\r
2921 CreatePieceMaskFromFont( hdc_window, hdc, PM_BU );
\r
2922 CreatePieceMaskFromFont( hdc_window, hdc, PM_BO );
\r
2923 CreatePieceMaskFromFont( hdc_window, hdc, PM_BG );
\r
2924 CreatePieceMaskFromFont( hdc_window, hdc, PM_BM );
\r
2925 CreatePieceMaskFromFont( hdc_window, hdc, PM_BSG );
\r
2926 CreatePieceMaskFromFont( hdc_window, hdc, PM_BV );
\r
2927 CreatePieceMaskFromFont( hdc_window, hdc, PM_BAB );
\r
2928 CreatePieceMaskFromFont( hdc_window, hdc, PM_BD );
\r
2929 CreatePieceMaskFromFont( hdc_window, hdc, PM_BL );
\r
2930 CreatePieceMaskFromFont( hdc_window, hdc, PM_BS );
\r
2932 for(i=(int)WhitePawn; i<(int)EmptySquare; i++) /* [HGM] made a loop for this */
\r
2933 if(PieceToChar((ChessSquare)i) != '.') /* skip unused pieces */
\r
2934 CreatePieceMaskFromFont( hdc_window, hdc, i );
\r
2936 SelectObject( hdc, hfont_old );
\r
2938 fontBitmapSquareSize = squareSize;
\r
2942 if( hdc != NULL ) {
\r
2946 if( hdc_window != NULL ) {
\r
2947 ReleaseDC( hwndMain, hdc_window );
\r
2952 DoLoadBitmap(HINSTANCE hinst, char *piece, int squareSize, char *suffix)
\r
2956 sprintf(name, "%s%d%s", piece, squareSize, suffix);
\r
2957 if (gameInfo.event &&
\r
2958 strcmp(gameInfo.event, "Easter Egg Hunt") == 0 &&
\r
2959 strcmp(name, "k80s") == 0) {
\r
2960 strcpy(name, "tim");
\r
2962 return LoadBitmap(hinst, name);
\r
2966 /* Insert a color into the program's logical palette
\r
2967 structure. This code assumes the given color is
\r
2968 the result of the RGB or PALETTERGB macro, and it
\r
2969 knows how those macros work (which is documented).
\r
2972 InsertInPalette(COLORREF color)
\r
2974 LPPALETTEENTRY pe = &(pLogPal->palPalEntry[pLogPal->palNumEntries]);
\r
2976 if (pLogPal->palNumEntries++ >= PALETTESIZE) {
\r
2977 DisplayFatalError("Too many colors", 0, 1);
\r
2978 pLogPal->palNumEntries--;
\r
2982 pe->peFlags = (char) 0;
\r
2983 pe->peRed = (char) (0xFF & color);
\r
2984 pe->peGreen = (char) (0xFF & (color >> 8));
\r
2985 pe->peBlue = (char) (0xFF & (color >> 16));
\r
2991 InitDrawingColors()
\r
2993 if (pLogPal == NULL) {
\r
2994 /* Allocate enough memory for a logical palette with
\r
2995 * PALETTESIZE entries and set the size and version fields
\r
2996 * of the logical palette structure.
\r
2998 pLogPal = (NPLOGPALETTE)
\r
2999 LocalAlloc(LMEM_FIXED, (sizeof(LOGPALETTE) +
\r
3000 (sizeof(PALETTEENTRY) * (PALETTESIZE))));
\r
3001 pLogPal->palVersion = 0x300;
\r
3003 pLogPal->palNumEntries = 0;
\r
3005 InsertInPalette(lightSquareColor);
\r
3006 InsertInPalette(darkSquareColor);
\r
3007 InsertInPalette(whitePieceColor);
\r
3008 InsertInPalette(blackPieceColor);
\r
3009 InsertInPalette(highlightSquareColor);
\r
3010 InsertInPalette(premoveHighlightColor);
\r
3012 /* create a logical color palette according the information
\r
3013 * in the LOGPALETTE structure.
\r
3015 hPal = CreatePalette((LPLOGPALETTE) pLogPal);
\r
3017 lightSquareBrush = CreateSolidBrush(lightSquareColor);
\r
3018 blackSquareBrush = CreateSolidBrush(blackPieceColor);
\r
3019 darkSquareBrush = CreateSolidBrush(darkSquareColor);
\r
3020 whitePieceBrush = CreateSolidBrush(whitePieceColor);
\r
3021 blackPieceBrush = CreateSolidBrush(blackPieceColor);
\r
3022 iconBkgndBrush = CreateSolidBrush(GetSysColor(COLOR_BACKGROUND));
\r
3023 explodeBrush = CreateSolidBrush(highlightSquareColor); // [HGM] atomic
\r
3024 /* [AS] Force rendering of the font-based pieces */
\r
3025 if( fontBitmapSquareSize > 0 ) {
\r
3026 fontBitmapSquareSize = 0;
\r
3032 BoardWidth(int boardSize, int n)
\r
3033 { /* [HGM] argument n added to allow different width and height */
\r
3034 int lineGap = sizeInfo[boardSize].lineGap;
\r
3036 if( appData.overrideLineGap >= 0 && appData.overrideLineGap <= 5 ) {
\r
3037 lineGap = appData.overrideLineGap;
\r
3040 return (n + 1) * lineGap +
\r
3041 n * sizeInfo[boardSize].squareSize;
\r
3044 /* Respond to board resize by dragging edge */
\r
3046 ResizeBoard(int newSizeX, int newSizeY, int flags)
\r
3048 BoardSize newSize = NUM_SIZES - 1;
\r
3049 static int recurse = 0;
\r
3050 if (IsIconic(hwndMain)) return;
\r
3051 if (recurse > 0) return;
\r
3053 while (newSize > 0) {
\r
3054 InitDrawingSizes(newSize+1000, 0); // [HGM] kludge to update sizeInfo without visible effects
\r
3055 if(newSizeX >= sizeInfo[newSize].cliWidth &&
\r
3056 newSizeY >= sizeInfo[newSize].cliHeight) break;
\r
3059 boardSize = newSize;
\r
3060 InitDrawingSizes(boardSize, flags);
\r
3067 InitDrawingSizes(BoardSize boardSize, int flags)
\r
3069 int i, boardWidth, boardHeight; /* [HGM] height treated separately */
\r
3070 ChessSquare piece;
\r
3071 static int oldBoardSize = -1, oldTinyLayout = 0;
\r
3073 SIZE clockSize, messageSize;
\r
3075 char buf[MSG_SIZ];
\r
3077 HMENU hmenu = GetMenu(hwndMain);
\r
3078 RECT crect, wrect;
\r
3080 LOGBRUSH logbrush;
\r
3082 int suppressVisibleEffects = 0; // [HGM] kludge to request updating sizeInfo only
\r
3083 if((int)boardSize >= 1000 ) { boardSize -= 1000; suppressVisibleEffects = 1; }
\r
3085 /* [HGM] call with -2 uses old size (for if nr of files, ranks changes) */
\r
3086 if(boardSize == (BoardSize)(-2) ) boardSize = oldBoardSize;
\r
3088 tinyLayout = sizeInfo[boardSize].tinyLayout;
\r
3089 smallLayout = sizeInfo[boardSize].smallLayout;
\r
3090 squareSize = sizeInfo[boardSize].squareSize;
\r
3091 lineGap = sizeInfo[boardSize].lineGap;
\r
3092 minorSize = 0; /* [HGM] Kludge to see if demagnified pieces need to be shifted */
\r
3094 if( appData.overrideLineGap >= 0 && appData.overrideLineGap <= 5 ) {
\r
3095 lineGap = appData.overrideLineGap;
\r
3098 if (tinyLayout != oldTinyLayout) {
\r
3099 long style = GetWindowLong(hwndMain, GWL_STYLE);
\r
3101 style &= ~WS_SYSMENU;
\r
3102 InsertMenu(hmenu, IDM_Exit, MF_BYCOMMAND, IDM_Minimize,
\r
3103 "&Minimize\tCtrl+F4");
\r
3105 style |= WS_SYSMENU;
\r
3106 RemoveMenu(hmenu, IDM_Minimize, MF_BYCOMMAND);
\r
3108 SetWindowLong(hwndMain, GWL_STYLE, style);
\r
3110 for (i=0; menuBarText[tinyLayout][i]; i++) {
\r
3111 ModifyMenu(hmenu, i, MF_STRING|MF_BYPOSITION|MF_POPUP,
\r
3112 (UINT)GetSubMenu(hmenu, i), menuBarText[tinyLayout][i]);
\r
3114 DrawMenuBar(hwndMain);
\r
3117 boardWidth = BoardWidth(boardSize, BOARD_WIDTH);
\r
3118 boardHeight = BoardWidth(boardSize, BOARD_HEIGHT);
\r
3120 /* Get text area sizes */
\r
3121 hdc = GetDC(hwndMain);
\r
3122 if (appData.clockMode) {
\r
3123 sprintf(buf, "White: %s", TimeString(23*60*60*1000L));
\r
3125 sprintf(buf, "White");
\r
3127 oldFont = SelectObject(hdc, font[boardSize][CLOCK_FONT]->hf);
\r
3128 GetTextExtentPoint(hdc, buf, strlen(buf), &clockSize);
\r
3129 SelectObject(hdc, font[boardSize][MESSAGE_FONT]->hf);
\r
3130 str = "We only care about the height here";
\r
3131 GetTextExtentPoint(hdc, str, strlen(str), &messageSize);
\r
3132 SelectObject(hdc, oldFont);
\r
3133 ReleaseDC(hwndMain, hdc);
\r
3135 /* Compute where everything goes */
\r
3136 if(first.programLogo || second.programLogo) {
\r
3137 /* [HGM] logo: if either logo is on, reserve space for it */
\r
3138 logoHeight = 2*clockSize.cy;
\r
3139 leftLogoRect.left = OUTER_MARGIN;
\r
3140 leftLogoRect.right = leftLogoRect.left + 4*clockSize.cy;
\r
3141 leftLogoRect.top = OUTER_MARGIN;
\r
3142 leftLogoRect.bottom = OUTER_MARGIN + logoHeight;
\r
3144 rightLogoRect.right = OUTER_MARGIN + boardWidth;
\r
3145 rightLogoRect.left = rightLogoRect.right - 4*clockSize.cy;
\r
3146 rightLogoRect.top = OUTER_MARGIN;
\r
3147 rightLogoRect.bottom = OUTER_MARGIN + logoHeight;
\r
3150 blackRect.left = leftLogoRect.right;
\r
3151 blackRect.right = rightLogoRect.left;
\r
3152 blackRect.top = OUTER_MARGIN;
\r
3153 blackRect.bottom = blackRect.top + clockSize.cy;
\r
3155 whiteRect.left = blackRect.left ;
\r
3156 whiteRect.right = blackRect.right;
\r
3157 whiteRect.top = blackRect.bottom;
\r
3158 whiteRect.bottom = leftLogoRect.bottom;
\r
3160 whiteRect.left = OUTER_MARGIN;
\r
3161 whiteRect.right = whiteRect.left + boardWidth/2 - INNER_MARGIN/2;
\r
3162 whiteRect.top = OUTER_MARGIN + logoHeight;
\r
3163 whiteRect.bottom = whiteRect.top + clockSize.cy;
\r
3165 blackRect.left = whiteRect.right + INNER_MARGIN;
\r
3166 blackRect.right = blackRect.left + boardWidth/2 - 1;
\r
3167 blackRect.top = whiteRect.top;
\r
3168 blackRect.bottom = whiteRect.bottom;
\r
3171 messageRect.left = OUTER_MARGIN + MESSAGE_LINE_LEFTMARGIN;
\r
3172 if (appData.showButtonBar) {
\r
3173 messageRect.right = OUTER_MARGIN + boardWidth // [HGM] logo: expressed independent of clock placement
\r
3174 - N_BUTTONS*BUTTON_WIDTH - MESSAGE_LINE_LEFTMARGIN;
\r
3176 messageRect.right = OUTER_MARGIN + boardWidth;
\r
3178 messageRect.top = whiteRect.bottom + INNER_MARGIN;
\r
3179 messageRect.bottom = messageRect.top + messageSize.cy;
\r
3181 boardRect.left = OUTER_MARGIN;
\r
3182 boardRect.right = boardRect.left + boardWidth;
\r
3183 boardRect.top = messageRect.bottom + INNER_MARGIN;
\r
3184 boardRect.bottom = boardRect.top + boardHeight;
\r
3186 sizeInfo[boardSize].cliWidth = boardRect.right + OUTER_MARGIN;
\r
3187 sizeInfo[boardSize].cliHeight = boardRect.bottom + OUTER_MARGIN;
\r
3188 if(suppressVisibleEffects) return; // [HGM] when called for filling sizeInfo only
\r
3189 winWidth = 2 * GetSystemMetrics(SM_CXFRAME) + boardRect.right + OUTER_MARGIN;
\r
3190 winHeight = 2 * GetSystemMetrics(SM_CYFRAME) + GetSystemMetrics(SM_CYMENU) +
\r
3191 GetSystemMetrics(SM_CYCAPTION) + boardRect.bottom + OUTER_MARGIN;
\r
3192 GetWindowRect(hwndMain, &wrect);
\r
3193 SetWindowPos(hwndMain, NULL, 0, 0, winWidth, winHeight,
\r
3194 SWP_NOCOPYBITS|SWP_NOZORDER|SWP_NOMOVE);
\r
3195 /* compensate if menu bar wrapped */
\r
3196 GetClientRect(hwndMain, &crect);
\r
3197 offby = boardRect.bottom + OUTER_MARGIN - crect.bottom;
\r
3198 winHeight += offby;
\r
3200 case WMSZ_TOPLEFT:
\r
3201 SetWindowPos(hwndMain, NULL,
\r
3202 wrect.right - winWidth, wrect.bottom - winHeight,
\r
3203 winWidth, winHeight, SWP_NOCOPYBITS|SWP_NOZORDER);
\r
3206 case WMSZ_TOPRIGHT:
\r
3208 SetWindowPos(hwndMain, NULL,
\r
3209 wrect.left, wrect.bottom - winHeight,
\r
3210 winWidth, winHeight, SWP_NOCOPYBITS|SWP_NOZORDER);
\r
3213 case WMSZ_BOTTOMLEFT:
\r
3215 SetWindowPos(hwndMain, NULL,
\r
3216 wrect.right - winWidth, wrect.top,
\r
3217 winWidth, winHeight, SWP_NOCOPYBITS|SWP_NOZORDER);
\r
3220 case WMSZ_BOTTOMRIGHT:
\r
3224 SetWindowPos(hwndMain, NULL, 0, 0, winWidth, winHeight,
\r
3225 SWP_NOCOPYBITS|SWP_NOZORDER|SWP_NOMOVE);
\r
3230 for (i = 0; i < N_BUTTONS; i++) {
\r
3231 if (buttonDesc[i].hwnd != NULL) {
\r
3232 DestroyWindow(buttonDesc[i].hwnd);
\r
3233 buttonDesc[i].hwnd = NULL;
\r
3235 if (appData.showButtonBar) {
\r
3236 buttonDesc[i].hwnd =
\r
3237 CreateWindow("BUTTON", buttonDesc[i].label,
\r
3238 WS_VISIBLE | WS_CHILD | BS_PUSHBUTTON,
\r
3239 boardRect.right - BUTTON_WIDTH*(N_BUTTONS-i),
\r
3240 messageRect.top, BUTTON_WIDTH, messageSize.cy, hwndMain,
\r
3241 (HMENU) buttonDesc[i].id,
\r
3242 (HINSTANCE) GetWindowLong(hwndMain, GWL_HINSTANCE), NULL);
\r
3244 SendMessage(buttonDesc[i].hwnd, WM_SETFONT,
\r
3245 (WPARAM)font[boardSize][MESSAGE_FONT]->hf,
\r
3246 MAKELPARAM(FALSE, 0));
\r
3248 if (buttonDesc[i].id == IDM_Pause)
\r
3249 hwndPause = buttonDesc[i].hwnd;
\r
3250 buttonDesc[i].wndproc = (WNDPROC)
\r
3251 SetWindowLong(buttonDesc[i].hwnd, GWL_WNDPROC, (LONG) ButtonProc);
\r
3254 if (gridPen != NULL) DeleteObject(gridPen);
\r
3255 if (highlightPen != NULL) DeleteObject(highlightPen);
\r
3256 if (premovePen != NULL) DeleteObject(premovePen);
\r
3257 if (lineGap != 0) {
\r
3258 logbrush.lbStyle = BS_SOLID;
\r
3259 logbrush.lbColor = RGB(0, 0, 0); /* grid pen color = black */
\r
3261 ExtCreatePen(PS_GEOMETRIC|PS_SOLID|PS_ENDCAP_FLAT|PS_JOIN_MITER,
\r
3262 lineGap, &logbrush, 0, NULL);
\r
3263 logbrush.lbColor = highlightSquareColor;
\r
3265 ExtCreatePen(PS_GEOMETRIC|PS_SOLID|PS_ENDCAP_FLAT|PS_JOIN_MITER,
\r
3266 lineGap, &logbrush, 0, NULL);
\r
3268 logbrush.lbColor = premoveHighlightColor;
\r
3270 ExtCreatePen(PS_GEOMETRIC|PS_SOLID|PS_ENDCAP_FLAT|PS_JOIN_MITER,
\r
3271 lineGap, &logbrush, 0, NULL);
\r
3273 /* [HGM] Loop had to be split in part for vert. and hor. lines */
\r
3274 for (i = 0; i < BOARD_HEIGHT + 1; i++) {
\r
3275 gridEndpoints[i*2].x = boardRect.left + lineGap / 2;
\r
3276 gridEndpoints[i*2].y = gridEndpoints[i*2 + 1].y =
\r
3277 boardRect.top + lineGap / 2 + (i * (squareSize + lineGap));
\r
3278 gridEndpoints[i*2 + 1].x = boardRect.left + lineGap / 2 +
\r
3279 BOARD_WIDTH * (squareSize + lineGap);
\r
3280 gridVertexCounts[i*2] = gridVertexCounts[i*2 + 1] = 2;
\r
3282 for (i = 0; i < BOARD_WIDTH + 1; i++) {
\r
3283 gridEndpoints[i*2 + BOARD_HEIGHT*2 + 2].y = boardRect.top + lineGap / 2;
\r
3284 gridEndpoints[i*2 + BOARD_HEIGHT*2 + 2].x =
\r
3285 gridEndpoints[i*2 + 1 + BOARD_HEIGHT*2 + 2].x = boardRect.left +
\r
3286 lineGap / 2 + (i * (squareSize + lineGap));
\r
3287 gridEndpoints[i*2 + 1 + BOARD_HEIGHT*2 + 2].y =
\r
3288 boardRect.top + BOARD_HEIGHT * (squareSize + lineGap);
\r
3289 gridVertexCounts[i*2] = gridVertexCounts[i*2 + 1] = 2;
\r
3293 /* [HGM] Licensing requirement */
\r
3295 if(gameInfo.variant == VariantGothic) GothicPopUp( GOTHIC, VariantGothic); else
\r
3298 if(gameInfo.variant == VariantFalcon) GothicPopUp( FALCON, VariantFalcon); else
\r
3300 GothicPopUp( "", VariantNormal);
\r
3303 /* if (boardSize == oldBoardSize) return; [HGM] variant might have changed */
\r
3304 oldBoardSize = boardSize;
\r
3305 oldTinyLayout = tinyLayout;
\r
3307 /* Load piece bitmaps for this board size */
\r
3308 for (i=0; i<=2; i++) {
\r
3309 for (piece = WhitePawn;
\r
3310 (int) piece < (int) BlackPawn;
\r
3311 piece = (ChessSquare) ((int) piece + 1)) {
\r
3312 if (pieceBitmap[i][piece] != NULL)
\r
3313 DeleteObject(pieceBitmap[i][piece]);
\r
3317 fontBitmapSquareSize = 0; /* [HGM] render: make sure pieces will be recreated, as we might need others now */
\r
3318 // Orthodox Chess pieces
\r
3319 pieceBitmap[0][WhitePawn] = DoLoadBitmap(hInst, "p", squareSize, "s");
\r
3320 pieceBitmap[0][WhiteKnight] = DoLoadBitmap(hInst, "n", squareSize, "s");
\r
3321 pieceBitmap[0][WhiteBishop] = DoLoadBitmap(hInst, "b", squareSize, "s");
\r
3322 pieceBitmap[0][WhiteRook] = DoLoadBitmap(hInst, "r", squareSize, "s");
\r
3323 pieceBitmap[0][WhiteKing] = DoLoadBitmap(hInst, "k", squareSize, "s");
\r
3324 pieceBitmap[1][WhitePawn] = DoLoadBitmap(hInst, "p", squareSize, "o");
\r
3325 pieceBitmap[1][WhiteKnight] = DoLoadBitmap(hInst, "n", squareSize, "o");
\r
3326 pieceBitmap[1][WhiteBishop] = DoLoadBitmap(hInst, "b", squareSize, "o");
\r
3327 pieceBitmap[1][WhiteRook] = DoLoadBitmap(hInst, "r", squareSize, "o");
\r
3328 pieceBitmap[1][WhiteKing] = DoLoadBitmap(hInst, "k", squareSize, "o");
\r
3329 pieceBitmap[2][WhitePawn] = DoLoadBitmap(hInst, "p", squareSize, "w");
\r
3330 pieceBitmap[2][WhiteKnight] = DoLoadBitmap(hInst, "n", squareSize, "w");
\r
3331 pieceBitmap[2][WhiteBishop] = DoLoadBitmap(hInst, "b", squareSize, "w");
\r
3332 pieceBitmap[2][WhiteRook] = DoLoadBitmap(hInst, "r", squareSize, "w");
\r
3333 pieceBitmap[2][WhiteKing] = DoLoadBitmap(hInst, "k", squareSize, "w");
\r
3334 if( !strcmp(appData.variant, "shogi") && (squareSize==72 || squareSize==49)) {
\r
3335 // in Shogi, Hijack the unused Queen for Lance
\r
3336 pieceBitmap[0][WhiteQueen] = DoLoadBitmap(hInst, "l", squareSize, "s");
\r
3337 pieceBitmap[1][WhiteQueen] = DoLoadBitmap(hInst, "l", squareSize, "o");
\r
3338 pieceBitmap[2][WhiteQueen] = DoLoadBitmap(hInst, "l", squareSize, "w");
\r
3340 pieceBitmap[0][WhiteQueen] = DoLoadBitmap(hInst, "q", squareSize, "s");
\r
3341 pieceBitmap[1][WhiteQueen] = DoLoadBitmap(hInst, "q", squareSize, "o");
\r
3342 pieceBitmap[2][WhiteQueen] = DoLoadBitmap(hInst, "q", squareSize, "w");
\r
3345 if(squareSize <= 72 && squareSize >= 33) {
\r
3346 /* A & C are available in most sizes now */
\r
3347 if(squareSize != 49 && squareSize != 72 && squareSize != 33) { // Vortex-like
\r
3348 pieceBitmap[0][WhiteAngel] = DoLoadBitmap(hInst, "a", squareSize, "s");
\r
3349 pieceBitmap[1][WhiteAngel] = DoLoadBitmap(hInst, "a", squareSize, "o");
\r
3350 pieceBitmap[2][WhiteAngel] = DoLoadBitmap(hInst, "a", squareSize, "w");
\r
3351 pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "s");
\r
3352 pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "o");
\r
3353 pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "w");
\r
3354 pieceBitmap[0][WhiteCobra] = DoLoadBitmap(hInst, "cv", squareSize, "s");
\r
3355 pieceBitmap[1][WhiteCobra] = DoLoadBitmap(hInst, "cv", squareSize, "o");
\r
3356 pieceBitmap[2][WhiteCobra] = DoLoadBitmap(hInst, "cv", squareSize, "w");
\r
3357 pieceBitmap[0][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "s");
\r
3358 pieceBitmap[1][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "o");
\r
3359 pieceBitmap[2][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "w");
\r
3360 } else { // Smirf-like
\r
3361 pieceBitmap[0][WhiteAngel] = DoLoadBitmap(hInst, "aa", squareSize, "s");
\r
3362 pieceBitmap[1][WhiteAngel] = DoLoadBitmap(hInst, "aa", squareSize, "o");
\r
3363 pieceBitmap[2][WhiteAngel] = DoLoadBitmap(hInst, "aa", squareSize, "w");
\r
3365 if(gameInfo.variant == VariantGothic) { // Vortex-like
\r
3366 pieceBitmap[0][WhiteMarshall] = DoLoadBitmap(hInst, "cv", squareSize, "s");
\r
3367 pieceBitmap[1][WhiteMarshall] = DoLoadBitmap(hInst, "cv", squareSize, "o");
\r
3368 pieceBitmap[2][WhiteMarshall] = DoLoadBitmap(hInst, "cv", squareSize, "w");
\r
3369 } else { // WinBoard standard
\r
3370 pieceBitmap[0][WhiteMarshall] = DoLoadBitmap(hInst, "c", squareSize, "s");
\r
3371 pieceBitmap[1][WhiteMarshall] = DoLoadBitmap(hInst, "c", squareSize, "o");
\r
3372 pieceBitmap[2][WhiteMarshall] = DoLoadBitmap(hInst, "c", squareSize, "w");
\r
3377 if(squareSize==72 || squareSize==49 || squareSize==33) { /* experiment with some home-made bitmaps */
\r
3378 pieceBitmap[0][WhiteFerz] = DoLoadBitmap(hInst, "f", squareSize, "s");
\r
3379 pieceBitmap[1][WhiteFerz] = DoLoadBitmap(hInst, "f", squareSize, "o");
\r
3380 pieceBitmap[2][WhiteFerz] = DoLoadBitmap(hInst, "f", squareSize, "w");
\r
3381 pieceBitmap[0][WhiteWazir] = DoLoadBitmap(hInst, "w", squareSize, "s");
\r
3382 pieceBitmap[1][WhiteWazir] = DoLoadBitmap(hInst, "w", squareSize, "o");
\r
3383 pieceBitmap[2][WhiteWazir] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
3384 pieceBitmap[0][WhiteAlfil] = DoLoadBitmap(hInst, "e", squareSize, "s");
\r
3385 pieceBitmap[1][WhiteAlfil] = DoLoadBitmap(hInst, "e", squareSize, "o");
\r
3386 pieceBitmap[2][WhiteAlfil] = DoLoadBitmap(hInst, "e", squareSize, "w");
\r
3387 pieceBitmap[0][WhiteMan] = DoLoadBitmap(hInst, "m", squareSize, "s");
\r
3388 pieceBitmap[1][WhiteMan] = DoLoadBitmap(hInst, "m", squareSize, "o");
\r
3389 pieceBitmap[2][WhiteMan] = DoLoadBitmap(hInst, "m", squareSize, "w");
\r
3390 pieceBitmap[0][WhiteCardinal] = DoLoadBitmap(hInst, "a", squareSize, "s");
\r
3391 pieceBitmap[1][WhiteCardinal] = DoLoadBitmap(hInst, "a", squareSize, "o");
\r
3392 pieceBitmap[2][WhiteCardinal] = DoLoadBitmap(hInst, "a", squareSize, "w");
\r
3393 pieceBitmap[0][WhiteDragon] = DoLoadBitmap(hInst, "dk", squareSize, "s");
\r
3394 pieceBitmap[1][WhiteDragon] = DoLoadBitmap(hInst, "dk", squareSize, "o");
\r
3395 pieceBitmap[2][WhiteDragon] = DoLoadBitmap(hInst, "dk", squareSize, "w");
\r
3396 pieceBitmap[0][WhiteFalcon] = DoLoadBitmap(hInst, "v", squareSize, "s");
\r
3397 pieceBitmap[1][WhiteFalcon] = DoLoadBitmap(hInst, "v", squareSize, "o");
\r
3398 pieceBitmap[2][WhiteFalcon] = DoLoadBitmap(hInst, "v", squareSize, "w");
\r
3399 pieceBitmap[0][WhiteCobra] = DoLoadBitmap(hInst, "s", squareSize, "s");
\r
3400 pieceBitmap[1][WhiteCobra] = DoLoadBitmap(hInst, "s", squareSize, "o");
\r
3401 pieceBitmap[2][WhiteCobra] = DoLoadBitmap(hInst, "s", squareSize, "w");
\r
3402 pieceBitmap[0][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "s");
\r
3403 pieceBitmap[1][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "o");
\r
3404 pieceBitmap[2][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "w");
\r
3405 pieceBitmap[0][WhiteUnicorn] = DoLoadBitmap(hInst, "u", squareSize, "s");
\r
3406 pieceBitmap[1][WhiteUnicorn] = DoLoadBitmap(hInst, "u", squareSize, "o");
\r
3407 pieceBitmap[2][WhiteUnicorn] = DoLoadBitmap(hInst, "u", squareSize, "w");
\r
3409 if(gameInfo.variant == VariantShogi) { /* promoted Gold represemtations */
\r
3410 pieceBitmap[0][WhiteCannon] = DoLoadBitmap(hInst, "wp", squareSize, "s");
\r
3411 pieceBitmap[1][WhiteCannon] = DoLoadBitmap(hInst, "wp", squareSize, "o");
\r
3412 pieceBitmap[2][WhiteCannon] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
3413 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "wn", squareSize, "s");
\r
3414 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "wn", squareSize, "o");
\r
3415 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
3416 pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "ws", squareSize, "s");
\r
3417 pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "ws", squareSize, "o");
\r
3418 pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
3419 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "wl", squareSize, "s");
\r
3420 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "wl", squareSize, "o");
\r
3421 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
3423 pieceBitmap[0][WhiteCannon] = DoLoadBitmap(hInst, "o", squareSize, "s");
\r
3424 pieceBitmap[1][WhiteCannon] = DoLoadBitmap(hInst, "o", squareSize, "o");
\r
3425 pieceBitmap[2][WhiteCannon] = DoLoadBitmap(hInst, "o", squareSize, "w");
\r
3426 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "h", squareSize, "s");
\r
3427 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "h", squareSize, "o");
\r
3428 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "h", squareSize, "w");
\r
3429 pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "s");
\r
3430 pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "o");
\r
3431 pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "w");
\r
3432 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "g", squareSize, "s");
\r
3433 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "g", squareSize, "o");
\r
3434 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "g", squareSize, "w");
\r
3437 } else { /* other size, no special bitmaps available. Use smaller symbols */
\r
3438 if((int)boardSize < 2) minorSize = sizeInfo[0].squareSize;
\r
3439 else minorSize = sizeInfo[(int)boardSize - 2].squareSize;
\r
3440 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "n", minorSize, "s");
\r
3441 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "n", minorSize, "o");
\r
3442 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "n", minorSize, "w");
\r
3443 pieceBitmap[0][WhiteCardinal] = DoLoadBitmap(hInst, "b", minorSize, "s");
\r
3444 pieceBitmap[1][WhiteCardinal] = DoLoadBitmap(hInst, "b", minorSize, "o");
\r
3445 pieceBitmap[2][WhiteCardinal] = DoLoadBitmap(hInst, "b", minorSize, "w");
\r
3446 pieceBitmap[0][WhiteDragon] = DoLoadBitmap(hInst, "r", minorSize, "s");
\r
3447 pieceBitmap[1][WhiteDragon] = DoLoadBitmap(hInst, "r", minorSize, "o");
\r
3448 pieceBitmap[2][WhiteDragon] = DoLoadBitmap(hInst, "r", minorSize, "w");
\r
3449 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "q", minorSize, "s");
\r
3450 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "q", minorSize, "o");
\r
3451 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "q", minorSize, "w");
\r
3455 if(gameInfo.variant == VariantShogi && squareSize == 58)
\r
3456 /* special Shogi support in this size */
\r
3457 { for (i=0; i<=2; i++) { /* replace all bitmaps */
\r
3458 for (piece = WhitePawn;
\r
3459 (int) piece < (int) BlackPawn;
\r
3460 piece = (ChessSquare) ((int) piece + 1)) {
\r
3461 if (pieceBitmap[i][piece] != NULL)
\r
3462 DeleteObject(pieceBitmap[i][piece]);
\r
3465 pieceBitmap[0][WhitePawn] = DoLoadBitmap(hInst, "sp", squareSize, "o");
\r
3466 pieceBitmap[0][WhiteKnight] = DoLoadBitmap(hInst, "sn", squareSize, "o");
\r
3467 pieceBitmap[0][WhiteBishop] = DoLoadBitmap(hInst, "sb", squareSize, "o");
\r
3468 pieceBitmap[0][WhiteRook] = DoLoadBitmap(hInst, "sr", squareSize, "o");
\r
3469 pieceBitmap[0][WhiteQueen] = DoLoadBitmap(hInst, "sl", squareSize, "o");
\r
3470 pieceBitmap[0][WhiteKing] = DoLoadBitmap(hInst, "sk", squareSize, "o");
\r
3471 pieceBitmap[0][WhiteFerz] = DoLoadBitmap(hInst, "sf", squareSize, "o");
\r
3472 pieceBitmap[0][WhiteWazir] = DoLoadBitmap(hInst, "sw", squareSize, "o");
\r
3473 pieceBitmap[0][WhiteCannon] = DoLoadBitmap(hInst, "su", squareSize, "o");
\r
3474 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "sh", squareSize, "o");
\r
3475 pieceBitmap[0][WhiteCardinal] = DoLoadBitmap(hInst, "sa", squareSize, "o");
\r
3476 pieceBitmap[0][WhiteDragon] = DoLoadBitmap(hInst, "sc", squareSize, "o");
\r
3477 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "sg", squareSize, "o");
\r
3478 pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "ss", squareSize, "o");
\r
3479 pieceBitmap[1][WhitePawn] = DoLoadBitmap(hInst, "sp", squareSize, "o");
\r
3480 pieceBitmap[1][WhiteKnight] = DoLoadBitmap(hInst, "sn", squareSize, "o");
\r
3481 pieceBitmap[1][WhiteBishop] = DoLoadBitmap(hInst, "sb", squareSize, "o");
\r
3482 pieceBitmap[1][WhiteRook] = DoLoadBitmap(hInst, "sr", squareSize, "o");
\r
3483 pieceBitmap[1][WhiteQueen] = DoLoadBitmap(hInst, "sl", squareSize, "o");
\r
3484 pieceBitmap[1][WhiteKing] = DoLoadBitmap(hInst, "sk", squareSize, "o");
\r
3485 pieceBitmap[1][WhiteFerz] = DoLoadBitmap(hInst, "sf", squareSize, "o");
\r
3486 pieceBitmap[1][WhiteWazir] = DoLoadBitmap(hInst, "sw", squareSize, "o");
\r
3487 pieceBitmap[1][WhiteCannon] = DoLoadBitmap(hInst, "su", squareSize, "o");
\r
3488 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "sh", squareSize, "o");
\r
3489 pieceBitmap[1][WhiteCardinal] = DoLoadBitmap(hInst, "sa", squareSize, "o");
\r
3490 pieceBitmap[1][WhiteDragon] = DoLoadBitmap(hInst, "sc", squareSize, "o");
\r
3491 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "sg", squareSize, "o");
\r
3492 pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "ss", squareSize, "o");
\r
3493 pieceBitmap[2][WhitePawn] = DoLoadBitmap(hInst, "sp", squareSize, "w");
\r
3494 pieceBitmap[2][WhiteKnight] = DoLoadBitmap(hInst, "sn", squareSize, "w");
\r
3495 pieceBitmap[2][WhiteBishop] = DoLoadBitmap(hInst, "sr", squareSize, "w");
\r
3496 pieceBitmap[2][WhiteRook] = DoLoadBitmap(hInst, "sr", squareSize, "w");
\r
3497 pieceBitmap[2][WhiteQueen] = DoLoadBitmap(hInst, "sl", squareSize, "w");
\r
3498 pieceBitmap[2][WhiteKing] = DoLoadBitmap(hInst, "sk", squareSize, "w");
\r
3499 pieceBitmap[2][WhiteFerz] = DoLoadBitmap(hInst, "sw", squareSize, "w");
\r
3500 pieceBitmap[2][WhiteWazir] = DoLoadBitmap(hInst, "sw", squareSize, "w");
\r
3501 pieceBitmap[2][WhiteCannon] = DoLoadBitmap(hInst, "sp", squareSize, "w");
\r
3502 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "sn", squareSize, "w");
\r
3503 pieceBitmap[2][WhiteCardinal] = DoLoadBitmap(hInst, "sr", squareSize, "w");
\r
3504 pieceBitmap[2][WhiteDragon] = DoLoadBitmap(hInst, "sr", squareSize, "w");
\r
3505 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "sl", squareSize, "w");
\r
3506 pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "sw", squareSize, "w");
\r
3512 PieceBitmap(ChessSquare p, int kind)
\r
3514 if ((int) p >= (int) BlackPawn)
\r
3515 p = (ChessSquare) ((int) p - (int) BlackPawn + (int) WhitePawn);
\r
3517 return pieceBitmap[kind][(int) p];
\r
3520 /***************************************************************/
\r
3522 #define MIN(a,b) (((a) < (b)) ? (a) : (b))
\r
3523 #define MAX(a,b) (((a) > (b)) ? (a) : (b))
\r
3525 #define MIN3(a,b,c) (((a) < (b) && (a) < (c)) ? (a) : (((b) < (a) && (b) < (c)) ? (b) : (c)))
\r
3526 #define MAX3(a,b,c) (((a) > (b) && (a) > (c)) ? (a) : (((b) > (a) && (b) > (c)) ? (b) : (c)))
\r
3530 SquareToPos(int row, int column, int * x, int * y)
\r
3533 *x = boardRect.left + lineGap + ((BOARD_WIDTH-1)-column) * (squareSize + lineGap);
\r
3534 *y = boardRect.top + lineGap + row * (squareSize + lineGap);
\r
3536 *x = boardRect.left + lineGap + column * (squareSize + lineGap);
\r
3537 *y = boardRect.top + lineGap + ((BOARD_HEIGHT-1)-row) * (squareSize + lineGap);
\r
3542 DrawCoordsOnDC(HDC hdc)
\r
3544 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
3545 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
3546 char str[2] = { NULLCHAR, NULLCHAR };
\r
3547 int oldMode, oldAlign, x, y, start, i;
\r
3551 if (!appData.showCoords)
\r
3554 start = flipView ? 1-(ONE!='1') : 23+(ONE!='1')-BOARD_HEIGHT;
\r
3556 oldBrush = SelectObject(hdc, GetStockObject(BLACK_BRUSH));
\r
3557 oldMode = SetBkMode(hdc, (appData.monoMode ? OPAQUE : TRANSPARENT));
\r
3558 oldAlign = GetTextAlign(hdc);
\r
3559 oldFont = SelectObject(hdc, font[boardSize][COORD_FONT]->hf);
\r
3561 y = boardRect.top + lineGap;
\r
3562 x = boardRect.left + lineGap + gameInfo.holdingsWidth*(squareSize + lineGap);
\r
3564 SetTextAlign(hdc, TA_LEFT|TA_TOP);
\r
3565 for (i = 0; i < BOARD_HEIGHT; i++) {
\r
3566 str[0] = files[start + i];
\r
3567 ExtTextOut(hdc, x + 2, y + 1, 0, NULL, str, 1, NULL);
\r
3568 y += squareSize + lineGap;
\r
3571 start = flipView ? 12-(BOARD_RGHT-BOARD_LEFT) : 12;
\r
3573 SetTextAlign(hdc, TA_RIGHT|TA_BOTTOM);
\r
3574 for (i = 0; i < BOARD_RGHT - BOARD_LEFT; i++) {
\r
3575 str[0] = ranks[start + i];
\r
3576 ExtTextOut(hdc, x + squareSize - 2, y - 1, 0, NULL, str, 1, NULL);
\r
3577 x += squareSize + lineGap;
\r
3580 SelectObject(hdc, oldBrush);
\r
3581 SetBkMode(hdc, oldMode);
\r
3582 SetTextAlign(hdc, oldAlign);
\r
3583 SelectObject(hdc, oldFont);
\r
3587 DrawGridOnDC(HDC hdc)
\r
3591 if (lineGap != 0) {
\r
3592 oldPen = SelectObject(hdc, gridPen);
\r
3593 PolyPolyline(hdc, gridEndpoints, gridVertexCounts, BOARD_WIDTH+BOARD_HEIGHT + 2);
\r
3594 SelectObject(hdc, oldPen);
\r
3598 #define HIGHLIGHT_PEN 0
\r
3599 #define PREMOVE_PEN 1
\r
3602 DrawHighlightOnDC(HDC hdc, BOOLEAN on, int x, int y, int pen)
\r
3605 HPEN oldPen, hPen;
\r
3606 if (lineGap == 0) return;
\r
3608 x1 = boardRect.left +
\r
3609 lineGap/2 + ((BOARD_WIDTH-1)-x) * (squareSize + lineGap);
\r
3610 y1 = boardRect.top +
\r
3611 lineGap/2 + y * (squareSize + lineGap);
\r
3613 x1 = boardRect.left +
\r
3614 lineGap/2 + x * (squareSize + lineGap);
\r
3615 y1 = boardRect.top +
\r
3616 lineGap/2 + ((BOARD_HEIGHT-1)-y) * (squareSize + lineGap);
\r
3618 hPen = pen ? premovePen : highlightPen;
\r
3619 oldPen = SelectObject(hdc, on ? hPen : gridPen);
\r
3620 MoveToEx(hdc, x1, y1, NULL);
\r
3621 LineTo(hdc, x1 + squareSize + lineGap, y1);
\r
3622 LineTo(hdc, x1 + squareSize + lineGap, y1 + squareSize + lineGap);
\r
3623 LineTo(hdc, x1, y1 + squareSize + lineGap);
\r
3624 LineTo(hdc, x1, y1);
\r
3625 SelectObject(hdc, oldPen);
\r
3629 DrawHighlightsOnDC(HDC hdc)
\r
3632 for (i=0; i<2; i++) {
\r
3633 if (highlightInfo.sq[i].x >= 0 && highlightInfo.sq[i].y >= 0)
\r
3634 DrawHighlightOnDC(hdc, TRUE,
\r
3635 highlightInfo.sq[i].x, highlightInfo.sq[i].y,
\r
3638 for (i=0; i<2; i++) {
\r
3639 if (premoveHighlightInfo.sq[i].x >= 0 &&
\r
3640 premoveHighlightInfo.sq[i].y >= 0) {
\r
3641 DrawHighlightOnDC(hdc, TRUE,
\r
3642 premoveHighlightInfo.sq[i].x,
\r
3643 premoveHighlightInfo.sq[i].y,
\r
3649 /* Note: sqcolor is used only in monoMode */
\r
3650 /* Note that this code is largely duplicated in woptions.c,
\r
3651 function DrawSampleSquare, so that needs to be updated too */
\r
3653 DrawPieceOnDC(HDC hdc, ChessSquare piece, int color, int sqcolor, int x, int y, HDC tmphdc)
\r
3655 HBITMAP oldBitmap;
\r
3659 if (appData.blindfold) return;
\r
3661 /* [AS] Use font-based pieces if needed */
\r
3662 if( fontBitmapSquareSize >= 0 && squareSize > 32 ) {
\r
3663 /* Create piece bitmaps, or do nothing if piece set is up to date */
\r
3664 CreatePiecesFromFont();
\r
3666 if( fontBitmapSquareSize == squareSize ) {
\r
3667 int index = TranslatePieceToFontPiece(piece);
\r
3669 SelectObject( tmphdc, hPieceMask[ index ] );
\r
3673 squareSize, squareSize,
\r
3678 SelectObject( tmphdc, hPieceFace[ index ] );
\r
3682 squareSize, squareSize,
\r
3691 if (appData.monoMode) {
\r
3692 SelectObject(tmphdc, PieceBitmap(piece,
\r
3693 color == sqcolor ? OUTLINE_PIECE : SOLID_PIECE));
\r
3694 BitBlt(hdc, x, y, squareSize, squareSize, tmphdc, 0, 0,
\r
3695 sqcolor ? SRCCOPY : NOTSRCCOPY);
\r
3697 tmpSize = squareSize;
\r
3699 ((piece >= (int)WhiteNightrider && piece <= WhiteGrasshopper) ||
\r
3700 (piece >= (int)BlackNightrider && piece <= BlackGrasshopper)) ) {
\r
3701 /* [HGM] no bitmap available for promoted pieces in Crazyhouse */
\r
3702 /* Bitmaps of smaller size are substituted, but we have to align them */
\r
3703 x += (squareSize - minorSize)>>1;
\r
3704 y += squareSize - minorSize - 2;
\r
3705 tmpSize = minorSize;
\r
3707 if (color || appData.allWhite ) {
\r
3708 oldBitmap = SelectObject(tmphdc, PieceBitmap(piece, WHITE_PIECE));
\r
3710 oldBrush = SelectObject(hdc, whitePieceBrush);
\r
3711 else oldBrush = SelectObject(hdc, blackPieceBrush);
\r
3712 if(appData.upsideDown && color==flipView)
\r
3713 StretchBlt(hdc, x+tmpSize, y+tmpSize, -tmpSize, -tmpSize, tmphdc, 0, 0, tmpSize, tmpSize, 0x00B8074A);
\r
3715 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, 0x00B8074A);
\r
3717 /* Use black piece color for outline of white pieces */
\r
3718 /* Not sure this looks really good (though xboard does it).
\r
3719 Maybe better to have another selectable color, default black */
\r
3720 SelectObject(hdc, blackPieceBrush); /* could have own brush */
\r
3721 SelectObject(tmphdc, PieceBitmap(piece, OUTLINE_PIECE));
\r
3722 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, 0x00B8074A);
\r
3724 /* Use black for outline of white pieces */
\r
3725 SelectObject(tmphdc, PieceBitmap(piece, OUTLINE_PIECE));
\r
3726 if(appData.upsideDown && color==flipView)
\r
3727 StretchBlt(hdc, x+tmpSize, y+tmpSize, -tmpSize, -tmpSize, tmphdc, 0, 0, tmpSize, tmpSize, SRCAND);
\r
3729 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, SRCAND);
\r
3733 /* Use white piece color for details of black pieces */
\r
3734 /* Requires filled-in solid bitmaps (BLACK_PIECE class); the
\r
3735 WHITE_PIECE ones aren't always the right shape. */
\r
3736 /* Not sure this looks really good (though xboard does it).
\r
3737 Maybe better to have another selectable color, default medium gray? */
\r
3738 oldBitmap = SelectObject(tmphdc, PieceBitmap(piece, BLACK_PIECE));
\r
3739 oldBrush = SelectObject(hdc, whitePieceBrush); /* could have own brush */
\r
3740 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, 0x00B8074A);
\r
3741 SelectObject(tmphdc, PieceBitmap(piece, SOLID_PIECE));
\r
3742 SelectObject(hdc, blackPieceBrush);
\r
3743 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, 0x00B8074A);
\r
3745 /* Use square color for details of black pieces */
\r
3746 oldBitmap = SelectObject(tmphdc, PieceBitmap(piece, SOLID_PIECE));
\r
3747 oldBrush = SelectObject(hdc, blackPieceBrush);
\r
3748 if(appData.upsideDown && !flipView)
\r
3749 StretchBlt(hdc, x+tmpSize, y+tmpSize, -tmpSize, -tmpSize, tmphdc, 0, 0, tmpSize, tmpSize, 0x00B8074A);
\r
3751 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, 0x00B8074A);
\r
3754 SelectObject(hdc, oldBrush);
\r
3755 SelectObject(tmphdc, oldBitmap);
\r
3759 /* [AS] Compute a drawing mode for a square, based on specified settings (see DrawTile) */
\r
3760 int GetBackTextureMode( int algo )
\r
3762 int result = BACK_TEXTURE_MODE_DISABLED;
\r
3766 case BACK_TEXTURE_MODE_PLAIN:
\r
3767 result = 1; /* Always use identity map */
\r
3769 case BACK_TEXTURE_MODE_FULL_RANDOM:
\r
3770 result = 1 + (myrandom() % 3); /* Pick a transformation at random */
\r
3778 [AS] Compute and save texture drawing info, otherwise we may not be able
\r
3779 to handle redraws cleanly (as random numbers would always be different).
\r
3781 VOID RebuildTextureSquareInfo()
\r
3791 ZeroMemory( &backTextureSquareInfo, sizeof(backTextureSquareInfo) );
\r
3793 if( liteBackTexture != NULL ) {
\r
3794 if( GetObject( liteBackTexture, sizeof(bi), &bi ) > 0 ) {
\r
3795 lite_w = bi.bmWidth;
\r
3796 lite_h = bi.bmHeight;
\r
3800 if( darkBackTexture != NULL ) {
\r
3801 if( GetObject( darkBackTexture, sizeof(bi), &bi ) > 0 ) {
\r
3802 dark_w = bi.bmWidth;
\r
3803 dark_h = bi.bmHeight;
\r
3807 for( row=0; row<BOARD_HEIGHT; row++ ) {
\r
3808 for( col=0; col<BOARD_WIDTH; col++ ) {
\r
3809 if( (col + row) & 1 ) {
\r
3811 if( lite_w >= squareSize && lite_h >= squareSize ) {
\r
3812 backTextureSquareInfo[row][col].x = col * (lite_w - squareSize) / (BOARD_WIDTH-1); /* [HGM] divide by size-1 in stead of size! */
\r
3813 backTextureSquareInfo[row][col].y = (BOARD_HEIGHT-1-row) * (lite_h - squareSize) / (BOARD_HEIGHT-1);
\r
3814 backTextureSquareInfo[row][col].mode = GetBackTextureMode(liteBackTextureMode);
\r
3819 if( dark_w >= squareSize && dark_h >= squareSize ) {
\r
3820 backTextureSquareInfo[row][col].x = col * (dark_w - squareSize) / (BOARD_WIDTH-1);
\r
3821 backTextureSquareInfo[row][col].y = (BOARD_HEIGHT-1-row) * (dark_h - squareSize) / (BOARD_HEIGHT-1);
\r
3822 backTextureSquareInfo[row][col].mode = GetBackTextureMode(darkBackTextureMode);
\r
3829 /* [AS] Arrow highlighting support */
\r
3831 static int A_WIDTH = 5; /* Width of arrow body */
\r
3833 #define A_HEIGHT_FACTOR 6 /* Length of arrow "point", relative to body width */
\r
3834 #define A_WIDTH_FACTOR 3 /* Width of arrow "point", relative to body width */
\r
3836 static double Sqr( double x )
\r
3841 static int Round( double x )
\r
3843 return (int) (x + 0.5);
\r
3846 /* Draw an arrow between two points using current settings */
\r
3847 VOID DrawArrowBetweenPoints( HDC hdc, int s_x, int s_y, int d_x, int d_y )
\r
3850 double dx, dy, j, k, x, y;
\r
3852 if( d_x == s_x ) {
\r
3853 int h = (d_y > s_y) ? +A_WIDTH*A_HEIGHT_FACTOR : -A_WIDTH*A_HEIGHT_FACTOR;
\r
3855 arrow[0].x = s_x + A_WIDTH;
\r
3858 arrow[1].x = s_x + A_WIDTH;
\r
3859 arrow[1].y = d_y - h;
\r
3861 arrow[2].x = s_x + A_WIDTH*A_WIDTH_FACTOR;
\r
3862 arrow[2].y = d_y - h;
\r
3867 arrow[4].x = s_x - A_WIDTH*A_WIDTH_FACTOR;
\r
3868 arrow[4].y = d_y - h;
\r
3870 arrow[5].x = s_x - A_WIDTH;
\r
3871 arrow[5].y = d_y - h;
\r
3873 arrow[6].x = s_x - A_WIDTH;
\r
3876 else if( d_y == s_y ) {
\r
3877 int w = (d_x > s_x) ? +A_WIDTH*A_HEIGHT_FACTOR : -A_WIDTH*A_HEIGHT_FACTOR;
\r
3880 arrow[0].y = s_y + A_WIDTH;
\r
3882 arrow[1].x = d_x - w;
\r
3883 arrow[1].y = s_y + A_WIDTH;
\r
3885 arrow[2].x = d_x - w;
\r
3886 arrow[2].y = s_y + A_WIDTH*A_WIDTH_FACTOR;
\r
3891 arrow[4].x = d_x - w;
\r
3892 arrow[4].y = s_y - A_WIDTH*A_WIDTH_FACTOR;
\r
3894 arrow[5].x = d_x - w;
\r
3895 arrow[5].y = s_y - A_WIDTH;
\r
3898 arrow[6].y = s_y - A_WIDTH;
\r
3901 /* [AS] Needed a lot of paper for this! :-) */
\r
3902 dy = (double) (d_y - s_y) / (double) (d_x - s_x);
\r
3903 dx = (double) (s_x - d_x) / (double) (s_y - d_y);
\r
3905 j = sqrt( Sqr(A_WIDTH) / (1.0 + Sqr(dx)) );
\r
3907 k = sqrt( Sqr(A_WIDTH*A_HEIGHT_FACTOR) / (1.0 + Sqr(dy)) );
\r
3912 arrow[0].x = Round(x - j);
\r
3913 arrow[0].y = Round(y + j*dx);
\r
3915 arrow[1].x = Round(x + j);
\r
3916 arrow[1].y = Round(y - j*dx);
\r
3919 x = (double) d_x - k;
\r
3920 y = (double) d_y - k*dy;
\r
3923 x = (double) d_x + k;
\r
3924 y = (double) d_y + k*dy;
\r
3927 arrow[2].x = Round(x + j);
\r
3928 arrow[2].y = Round(y - j*dx);
\r
3930 arrow[3].x = Round(x + j*A_WIDTH_FACTOR);
\r
3931 arrow[3].y = Round(y - j*A_WIDTH_FACTOR*dx);
\r
3936 arrow[5].x = Round(x - j*A_WIDTH_FACTOR);
\r
3937 arrow[5].y = Round(y + j*A_WIDTH_FACTOR*dx);
\r
3939 arrow[6].x = Round(x - j);
\r
3940 arrow[6].y = Round(y + j*dx);
\r
3943 Polygon( hdc, arrow, 7 );
\r
3946 /* [AS] Draw an arrow between two squares */
\r
3947 VOID DrawArrowBetweenSquares( HDC hdc, int s_col, int s_row, int d_col, int d_row )
\r
3949 int s_x, s_y, d_x, d_y;
\r
3956 if( s_col == d_col && s_row == d_row ) {
\r
3960 /* Get source and destination points */
\r
3961 SquareToPos( s_row, s_col, &s_x, &s_y);
\r
3962 SquareToPos( d_row, d_col, &d_x, &d_y);
\r
3965 d_y += squareSize / 4;
\r
3967 else if( d_y < s_y ) {
\r
3968 d_y += 3 * squareSize / 4;
\r
3971 d_y += squareSize / 2;
\r
3975 d_x += squareSize / 4;
\r
3977 else if( d_x < s_x ) {
\r
3978 d_x += 3 * squareSize / 4;
\r
3981 d_x += squareSize / 2;
\r
3984 s_x += squareSize / 2;
\r
3985 s_y += squareSize / 2;
\r
3987 /* Adjust width */
\r
3988 A_WIDTH = squareSize / 14;
\r
3991 stLB.lbStyle = BS_SOLID;
\r
3992 stLB.lbColor = appData.highlightArrowColor;
\r
3995 hpen = CreatePen( PS_SOLID, 2, RGB(0x00,0x00,0x00) );
\r
3996 holdpen = SelectObject( hdc, hpen );
\r
3997 hbrush = CreateBrushIndirect( &stLB );
\r
3998 holdbrush = SelectObject( hdc, hbrush );
\r
4000 DrawArrowBetweenPoints( hdc, s_x, s_y, d_x, d_y );
\r
4002 SelectObject( hdc, holdpen );
\r
4003 SelectObject( hdc, holdbrush );
\r
4004 DeleteObject( hpen );
\r
4005 DeleteObject( hbrush );
\r
4008 BOOL HasHighlightInfo()
\r
4010 BOOL result = FALSE;
\r
4012 if( highlightInfo.sq[0].x >= 0 && highlightInfo.sq[0].y >= 0 &&
\r
4013 highlightInfo.sq[1].x >= 0 && highlightInfo.sq[1].y >= 0 )
\r
4021 BOOL IsDrawArrowEnabled()
\r
4023 BOOL result = FALSE;
\r
4025 if( appData.highlightMoveWithArrow && squareSize >= 32 ) {
\r
4032 VOID DrawArrowHighlight( HDC hdc )
\r
4034 if( IsDrawArrowEnabled() && HasHighlightInfo() ) {
\r
4035 DrawArrowBetweenSquares( hdc,
\r
4036 highlightInfo.sq[0].x, highlightInfo.sq[0].y,
\r
4037 highlightInfo.sq[1].x, highlightInfo.sq[1].y );
\r
4041 HRGN GetArrowHighlightClipRegion( HDC hdc )
\r
4043 HRGN result = NULL;
\r
4045 if( HasHighlightInfo() ) {
\r
4046 int x1, y1, x2, y2;
\r
4047 int sx, sy, dx, dy;
\r
4049 SquareToPos(highlightInfo.sq[0].y, highlightInfo.sq[0].x, &x1, &y1 );
\r
4050 SquareToPos(highlightInfo.sq[1].y, highlightInfo.sq[1].x, &x2, &y2 );
\r
4052 sx = MIN( x1, x2 );
\r
4053 sy = MIN( y1, y2 );
\r
4054 dx = MAX( x1, x2 ) + squareSize;
\r
4055 dy = MAX( y1, y2 ) + squareSize;
\r
4057 result = CreateRectRgn( sx, sy, dx, dy );
\r
4064 Warning: this function modifies the behavior of several other functions.
\r
4066 Basically, Winboard is optimized to avoid drawing the whole board if not strictly
\r
4067 needed. Unfortunately, the decision whether or not to perform a full or partial
\r
4068 repaint is scattered all over the place, which is not good for features such as
\r
4069 "arrow highlighting" that require a full repaint of the board.
\r
4071 So, I've tried to patch the code where I thought it made sense (e.g. after or during
\r
4072 user interaction, when speed is not so important) but especially to avoid errors
\r
4073 in the displayed graphics.
\r
4075 In such patched places, I always try refer to this function so there is a single
\r
4076 place to maintain knowledge.
\r
4078 To restore the original behavior, just return FALSE unconditionally.
\r
4080 BOOL IsFullRepaintPreferrable()
\r
4082 BOOL result = FALSE;
\r
4084 if( (appData.highlightLastMove || appData.highlightDragging) && IsDrawArrowEnabled() ) {
\r
4085 /* Arrow may appear on the board */
\r
4093 This function is called by DrawPosition to know whether a full repaint must
\r
4096 Only DrawPosition may directly call this function, which makes use of
\r
4097 some state information. Other function should call DrawPosition specifying
\r
4098 the repaint flag, and can use IsFullRepaintPreferrable if needed.
\r
4100 BOOL DrawPositionNeedsFullRepaint()
\r
4102 BOOL result = FALSE;
\r
4105 Probably a slightly better policy would be to trigger a full repaint
\r
4106 when animInfo.piece changes state (i.e. empty -> non-empty and viceversa),
\r
4107 but animation is fast enough that it's difficult to notice.
\r
4109 if( animInfo.piece == EmptySquare ) {
\r
4110 if( (appData.highlightLastMove || appData.highlightDragging) && IsDrawArrowEnabled() && HasHighlightInfo() ) {
\r
4119 DrawBoardOnDC(HDC hdc, Board board, HDC tmphdc)
\r
4121 int row, column, x, y, square_color, piece_color;
\r
4122 ChessSquare piece;
\r
4124 HDC texture_hdc = NULL;
\r
4126 /* [AS] Initialize background textures if needed */
\r
4127 if( liteBackTexture != NULL || darkBackTexture != NULL ) {
\r
4128 static int backTextureBoardSize; /* [HGM] boardsize: also new texture if board format changed */
\r
4129 if( backTextureSquareSize != squareSize
\r
4130 || backTextureBoardSize != BOARD_WIDTH+BOARD_SIZE*BOARD_HEIGHT) {
\r
4131 backTextureBoardSize = BOARD_WIDTH+BOARD_SIZE*BOARD_HEIGHT;
\r
4132 backTextureSquareSize = squareSize;
\r
4133 RebuildTextureSquareInfo();
\r
4136 texture_hdc = CreateCompatibleDC( hdc );
\r
4139 for (row = 0; row < BOARD_HEIGHT; row++) {
\r
4140 for (column = 0; column < BOARD_WIDTH; column++) {
\r
4142 SquareToPos(row, column, &x, &y);
\r
4144 piece = board[row][column];
\r
4146 square_color = ((column + row) % 2) == 1;
\r
4147 if( gameInfo.variant == VariantXiangqi ) {
\r
4148 square_color = !InPalace(row, column);
\r
4149 if(BOARD_HEIGHT&1) { if(row==BOARD_HEIGHT/2) square_color ^= 1; }
\r
4150 else if(row < BOARD_HEIGHT/2) square_color ^= 1;
\r
4152 piece_color = (int) piece < (int) BlackPawn;
\r
4155 /* [HGM] holdings file: light square or black */
\r
4156 if(column == BOARD_LEFT-2) {
\r
4157 if( row > BOARD_HEIGHT - gameInfo.holdingsSize - 1 )
\r
4160 DisplayHoldingsCount(hdc, x, y, 0, 0); /* black out */
\r
4164 if(column == BOARD_RGHT + 1 ) {
\r
4165 if( row < gameInfo.holdingsSize )
\r
4168 DisplayHoldingsCount(hdc, x, y, 0, 0);
\r
4172 if(column == BOARD_LEFT-1 ) /* left align */
\r
4173 DisplayHoldingsCount(hdc, x, y, flipView, (int) board[row][column]);
\r
4174 else if( column == BOARD_RGHT) /* right align */
\r
4175 DisplayHoldingsCount(hdc, x, y, !flipView, (int) board[row][column]);
\r
4177 if (appData.monoMode) {
\r
4178 if (piece == EmptySquare) {
\r
4179 BitBlt(hdc, x, y, squareSize, squareSize, 0, 0, 0,
\r
4180 square_color ? WHITENESS : BLACKNESS);
\r
4182 DrawPieceOnDC(hdc, piece, piece_color, square_color, x, y, tmphdc);
\r
4185 else if( backTextureSquareInfo[row][column].mode > 0 ) {
\r
4186 /* [AS] Draw the square using a texture bitmap */
\r
4187 HBITMAP hbm = SelectObject( texture_hdc, square_color ? liteBackTexture : darkBackTexture );
\r
4188 int r = row, c = column; // [HGM] do not flip board in flipView
\r
4189 if(flipView) { r = BOARD_HEIGHT-1 - r; c = BOARD_WIDTH-1 - c; }
\r
4192 squareSize, squareSize,
\r
4195 backTextureSquareInfo[r][c].mode,
\r
4196 backTextureSquareInfo[r][c].x,
\r
4197 backTextureSquareInfo[r][c].y );
\r
4199 SelectObject( texture_hdc, hbm );
\r
4201 if (piece != EmptySquare) {
\r
4202 DrawPieceOnDC(hdc, piece, piece_color, -1, x, y, tmphdc);
\r
4206 HBRUSH brush = square_color ? lightSquareBrush : darkSquareBrush;
\r
4208 oldBrush = SelectObject(hdc, brush );
\r
4209 BitBlt(hdc, x, y, squareSize, squareSize, 0, 0, 0, PATCOPY);
\r
4210 SelectObject(hdc, oldBrush);
\r
4211 if (piece != EmptySquare)
\r
4212 DrawPieceOnDC(hdc, piece, piece_color, -1, x, y, tmphdc);
\r
4217 if( texture_hdc != NULL ) {
\r
4218 DeleteDC( texture_hdc );
\r
4222 int saveDiagFlag = 0; FILE *diagFile; // [HGM] diag
\r
4223 void fputDW(FILE *f, int x)
\r
4225 fputc(x & 255, f);
\r
4226 fputc(x>>8 & 255, f);
\r
4227 fputc(x>>16 & 255, f);
\r
4228 fputc(x>>24 & 255, f);
\r
4231 #define MAX_CLIPS 200 /* more than enough */
\r
4234 DrawLogoOnDC(HDC hdc, RECT logoRect, ChessProgramState *cps)
\r
4236 // HBITMAP bufferBitmap;
\r
4241 int w = 100, h = 50;
\r
4243 if(cps->programLogo == NULL) return;
\r
4244 // GetClientRect(hwndMain, &Rect);
\r
4245 // bufferBitmap = CreateCompatibleBitmap(hdc, Rect.right-Rect.left+1,
\r
4246 // Rect.bottom-Rect.top+1);
\r
4247 tmphdc = CreateCompatibleDC(hdc);
\r
4248 hbm = SelectObject(tmphdc, (HBITMAP) cps->programLogo);
\r
4249 if( GetObject( cps->programLogo, sizeof(bi), &bi ) > 0 ) {
\r
4253 StretchBlt(hdc, logoRect.left, logoRect.top, logoRect.right - logoRect.left,
\r
4254 logoRect.bottom - logoRect.top, tmphdc, 0, 0, w, h, SRCCOPY);
\r
4255 SelectObject(tmphdc, hbm);
\r
4260 HDCDrawPosition(HDC hdc, BOOLEAN repaint, Board board)
\r
4262 static Board lastReq, lastDrawn;
\r
4263 static HighlightInfo lastDrawnHighlight, lastDrawnPremove;
\r
4264 static int lastDrawnFlipView = 0;
\r
4265 static int lastReqValid = 0, lastDrawnValid = 0;
\r
4266 int releaseDC, x, y, x2, y2, row, column, num_clips = 0, i;
\r
4269 HBITMAP bufferBitmap;
\r
4270 HBITMAP oldBitmap;
\r
4272 HRGN clips[MAX_CLIPS];
\r
4273 ChessSquare dragged_piece = EmptySquare;
\r
4275 /* I'm undecided on this - this function figures out whether a full
\r
4276 * repaint is necessary on its own, so there's no real reason to have the
\r
4277 * caller tell it that. I think this can safely be set to FALSE - but
\r
4278 * if we trust the callers not to request full repaints unnessesarily, then
\r
4279 * we could skip some clipping work. In other words, only request a full
\r
4280 * redraw when the majority of pieces have changed positions (ie. flip,
\r
4281 * gamestart and similar) --Hawk
\r
4283 Boolean fullrepaint = repaint;
\r
4285 if( DrawPositionNeedsFullRepaint() ) {
\r
4286 fullrepaint = TRUE;
\r
4290 if( fullrepaint ) {
\r
4291 static int repaint_count = 0;
\r
4295 sprintf( buf, "FULL repaint: %d\n", repaint_count );
\r
4296 OutputDebugString( buf );
\r
4300 if (board == NULL) {
\r
4301 if (!lastReqValid) {
\r
4306 CopyBoard(lastReq, board);
\r
4310 if (doingSizing) {
\r
4314 if (IsIconic(hwndMain)) {
\r
4318 if (hdc == NULL) {
\r
4319 hdc = GetDC(hwndMain);
\r
4320 if (!appData.monoMode) {
\r
4321 SelectPalette(hdc, hPal, FALSE);
\r
4322 RealizePalette(hdc);
\r
4326 releaseDC = FALSE;
\r
4330 fprintf(debugFP, "*******************************\n"
\r
4332 "dragInfo.from (%d,%d)\n"
\r
4333 "dragInfo.start (%d,%d)\n"
\r
4334 "dragInfo.pos (%d,%d)\n"
\r
4335 "dragInfo.lastpos (%d,%d)\n",
\r
4336 repaint ? "TRUE" : "FALSE",
\r
4337 dragInfo.from.x, dragInfo.from.y,
\r
4338 dragInfo.start.x, dragInfo.start.y,
\r
4339 dragInfo.pos.x, dragInfo.pos.y,
\r
4340 dragInfo.lastpos.x, dragInfo.lastpos.y);
\r
4341 fprintf(debugFP, "prev: ");
\r
4342 for (row = 0; row < BOARD_HEIGHT; row++) {
\r
4343 for (column = 0; column < BOARD_WIDTH; column++) {
\r
4344 fprintf(debugFP, "%d ", lastDrawn[row][column]);
\r
4347 fprintf(debugFP, "\n");
\r
4348 fprintf(debugFP, "board: ");
\r
4349 for (row = 0; row < BOARD_HEIGHT; row++) {
\r
4350 for (column = 0; column < BOARD_WIDTH; column++) {
\r
4351 fprintf(debugFP, "%d ", board[row][column]);
\r
4354 fprintf(debugFP, "\n");
\r
4358 /* Create some work-DCs */
\r
4359 hdcmem = CreateCompatibleDC(hdc);
\r
4360 tmphdc = CreateCompatibleDC(hdc);
\r
4362 /* If dragging is in progress, we temporarely remove the piece */
\r
4363 /* [HGM] or temporarily decrease count if stacked */
\r
4364 /* !! Moved to before board compare !! */
\r
4365 if (dragInfo.from.x >= 0 && dragInfo.pos.x >= 0) {
\r
4366 dragged_piece = board[dragInfo.from.y][dragInfo.from.x];
\r
4367 if(dragInfo.from.x == BOARD_LEFT-2 ) {
\r
4368 if(--board[dragInfo.from.y][dragInfo.from.x+1] == 0 )
\r
4369 board[dragInfo.from.y][dragInfo.from.x] = EmptySquare;
\r
4371 if(dragInfo.from.x == BOARD_RGHT+1) {
\r
4372 if(--board[dragInfo.from.y][dragInfo.from.x-1] == 0 )
\r
4373 board[dragInfo.from.y][dragInfo.from.x] = EmptySquare;
\r
4375 board[dragInfo.from.y][dragInfo.from.x] = EmptySquare;
\r
4378 /* Figure out which squares need updating by comparing the
\r
4379 * newest board with the last drawn board and checking if
\r
4380 * flipping has changed.
\r
4382 if (!fullrepaint && lastDrawnValid && lastDrawnFlipView == flipView) {
\r
4383 for (row = 0; row < BOARD_HEIGHT; row++) { /* [HGM] true size, not 8 */
\r
4384 for (column = 0; column < BOARD_WIDTH; column++) {
\r
4385 if (lastDrawn[row][column] != board[row][column]) {
\r
4386 SquareToPos(row, column, &x, &y);
\r
4387 clips[num_clips++] =
\r
4388 CreateRectRgn(x, y, x + squareSize, y + squareSize);
\r
4392 for (i=0; i<2; i++) {
\r
4393 if (lastDrawnHighlight.sq[i].x != highlightInfo.sq[i].x ||
\r
4394 lastDrawnHighlight.sq[i].y != highlightInfo.sq[i].y) {
\r
4395 if (lastDrawnHighlight.sq[i].x >= 0 &&
\r
4396 lastDrawnHighlight.sq[i].y >= 0) {
\r
4397 SquareToPos(lastDrawnHighlight.sq[i].y,
\r
4398 lastDrawnHighlight.sq[i].x, &x, &y);
\r
4399 clips[num_clips++] =
\r
4400 CreateRectRgn(x - lineGap, y - lineGap,
\r
4401 x + squareSize + lineGap, y + squareSize + lineGap);
\r
4403 if (highlightInfo.sq[i].x >= 0 && highlightInfo.sq[i].y >= 0) {
\r
4404 SquareToPos(highlightInfo.sq[i].y, highlightInfo.sq[i].x, &x, &y);
\r
4405 clips[num_clips++] =
\r
4406 CreateRectRgn(x - lineGap, y - lineGap,
\r
4407 x + squareSize + lineGap, y + squareSize + lineGap);
\r
4411 for (i=0; i<2; i++) {
\r
4412 if (lastDrawnPremove.sq[i].x != premoveHighlightInfo.sq[i].x ||
\r
4413 lastDrawnPremove.sq[i].y != premoveHighlightInfo.sq[i].y) {
\r
4414 if (lastDrawnPremove.sq[i].x >= 0 &&
\r
4415 lastDrawnPremove.sq[i].y >= 0) {
\r
4416 SquareToPos(lastDrawnPremove.sq[i].y,
\r
4417 lastDrawnPremove.sq[i].x, &x, &y);
\r
4418 clips[num_clips++] =
\r
4419 CreateRectRgn(x - lineGap, y - lineGap,
\r
4420 x + squareSize + lineGap, y + squareSize + lineGap);
\r
4422 if (premoveHighlightInfo.sq[i].x >= 0 &&
\r
4423 premoveHighlightInfo.sq[i].y >= 0) {
\r
4424 SquareToPos(premoveHighlightInfo.sq[i].y,
\r
4425 premoveHighlightInfo.sq[i].x, &x, &y);
\r
4426 clips[num_clips++] =
\r
4427 CreateRectRgn(x - lineGap, y - lineGap,
\r
4428 x + squareSize + lineGap, y + squareSize + lineGap);
\r
4433 fullrepaint = TRUE;
\r
4436 /* Create a buffer bitmap - this is the actual bitmap
\r
4437 * being written to. When all the work is done, we can
\r
4438 * copy it to the real DC (the screen). This avoids
\r
4439 * the problems with flickering.
\r
4441 GetClientRect(hwndMain, &Rect);
\r
4442 bufferBitmap = CreateCompatibleBitmap(hdc, Rect.right-Rect.left+1,
\r
4443 Rect.bottom-Rect.top+1);
\r
4444 oldBitmap = SelectObject(hdcmem, bufferBitmap);
\r
4445 if (!appData.monoMode) {
\r
4446 SelectPalette(hdcmem, hPal, FALSE);
\r
4449 /* Create clips for dragging */
\r
4450 if (!fullrepaint) {
\r
4451 if (dragInfo.from.x >= 0) {
\r
4452 SquareToPos(dragInfo.from.y, dragInfo.from.x, &x, &y);
\r
4453 clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);
\r
4455 if (dragInfo.start.x >= 0) {
\r
4456 SquareToPos(dragInfo.start.y, dragInfo.start.x, &x, &y);
\r
4457 clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);
\r
4459 if (dragInfo.pos.x >= 0) {
\r
4460 x = dragInfo.pos.x - squareSize / 2;
\r
4461 y = dragInfo.pos.y - squareSize / 2;
\r
4462 clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);
\r
4464 if (dragInfo.lastpos.x >= 0) {
\r
4465 x = dragInfo.lastpos.x - squareSize / 2;
\r
4466 y = dragInfo.lastpos.y - squareSize / 2;
\r
4467 clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);
\r
4471 /* Are we animating a move?
\r
4473 * - remove the piece from the board (temporarely)
\r
4474 * - calculate the clipping region
\r
4476 if (!fullrepaint) {
\r
4477 if (animInfo.piece != EmptySquare) {
\r
4478 board[animInfo.from.y][animInfo.from.x] = EmptySquare;
\r
4479 x = boardRect.left + animInfo.lastpos.x;
\r
4480 y = boardRect.top + animInfo.lastpos.y;
\r
4481 x2 = boardRect.left + animInfo.pos.x;
\r
4482 y2 = boardRect.top + animInfo.pos.y;
\r
4483 clips[num_clips++] = CreateRectRgn(MIN(x,x2), MIN(y,y2), MAX(x,x2)+squareSize, MAX(y,y2)+squareSize);
\r
4484 /* [HGM] old location of "slight kludge" below */
\r
4488 /* No clips? Make sure we have fullrepaint set to TRUE */
\r
4489 if (num_clips == 0)
\r
4490 fullrepaint = TRUE;
\r
4492 /* Set clipping on the memory DC */
\r
4493 if (!fullrepaint) {
\r
4494 SelectClipRgn(hdcmem, clips[0]);
\r
4495 for (x = 1; x < num_clips; x++) {
\r
4496 if (ExtSelectClipRgn(hdcmem, clips[x], RGN_OR) == ERROR)
\r
4497 abort(); // this should never ever happen!
\r
4501 /* Do all the drawing to the memory DC */
\r
4502 if(explodeInfo.radius) { // [HGM] atomic
\r
4504 int x, y, r=(explodeInfo.radius * squareSize)/100;
\r
4505 SquareToPos(explodeInfo.y, explodeInfo.x, &x, &y);
\r
4506 x += squareSize/2;
\r
4507 y += squareSize/2;
\r
4508 if(!fullrepaint) {
\r
4509 clips[num_clips] = CreateRectRgn(x-r, y-r, x+r, y+r);
\r
4510 ExtSelectClipRgn(hdcmem, clips[num_clips++], RGN_OR);
\r
4512 DrawGridOnDC(hdcmem);
\r
4513 DrawHighlightsOnDC(hdcmem);
\r
4514 DrawBoardOnDC(hdcmem, board, tmphdc);
\r
4515 oldBrush = SelectObject(hdcmem, explodeBrush);
\r
4516 Ellipse(hdcmem, x-r, y-r, x+r, y+r);
\r
4517 SelectObject(hdcmem, oldBrush);
\r
4519 DrawGridOnDC(hdcmem);
\r
4520 DrawHighlightsOnDC(hdcmem);
\r
4521 DrawBoardOnDC(hdcmem, board, tmphdc);
\r
4524 DrawLogoOnDC(hdc, leftLogoRect, flipClock ? &second : &first);
\r
4525 DrawLogoOnDC(hdc, rightLogoRect, flipClock ? &first : &second);
\r
4528 if( appData.highlightMoveWithArrow ) {
\r
4529 DrawArrowHighlight(hdcmem);
\r
4532 DrawCoordsOnDC(hdcmem);
\r
4534 CopyBoard(lastDrawn, board); /* [HGM] Moved to here from end of routine, */
\r
4535 /* to make sure lastDrawn contains what is actually drawn */
\r
4537 /* Put the dragged piece back into place and draw it (out of place!) */
\r
4538 if (dragged_piece != EmptySquare) {
\r
4539 /* [HGM] or restack */
\r
4540 if(dragInfo.from.x == BOARD_LEFT-2 )
\r
4541 board[dragInfo.from.y][dragInfo.from.x+1]++;
\r
4543 if(dragInfo.from.x == BOARD_RGHT+1 )
\r
4544 board[dragInfo.from.y][dragInfo.from.x-1]++;
\r
4545 board[dragInfo.from.y][dragInfo.from.x] = dragged_piece;
\r
4546 x = dragInfo.pos.x - squareSize / 2;
\r
4547 y = dragInfo.pos.y - squareSize / 2;
\r
4548 DrawPieceOnDC(hdcmem, dragged_piece,
\r
4549 ((int) dragged_piece < (int) BlackPawn),
\r
4550 (dragInfo.from.y + dragInfo.from.x) % 2, x, y, tmphdc);
\r
4553 /* Put the animated piece back into place and draw it */
\r
4554 if (animInfo.piece != EmptySquare) {
\r
4555 board[animInfo.from.y][animInfo.from.x] = animInfo.piece;
\r
4556 x = boardRect.left + animInfo.pos.x;
\r
4557 y = boardRect.top + animInfo.pos.y;
\r
4558 DrawPieceOnDC(hdcmem, animInfo.piece,
\r
4559 ((int) animInfo.piece < (int) BlackPawn),
\r
4560 (animInfo.from.y + animInfo.from.x) % 2, x, y, tmphdc);
\r
4561 /* Slight kludge. The real problem is that after AnimateMove is
\r
4562 done, the position on the screen does not match lastDrawn.
\r
4563 This currently causes trouble only on e.p. captures in
\r
4564 atomic, where the piece moves to an empty square and then
\r
4565 explodes. The old and new positions both had an empty square
\r
4566 at the destination, but animation has drawn a piece there and
\r
4567 we have to remember to erase it. [HGM] moved until after setting lastDrawn */
\r
4568 lastDrawn[animInfo.to.y][animInfo.to.x] = animInfo.piece;
\r
4571 /* Release the bufferBitmap by selecting in the old bitmap
\r
4572 * and delete the memory DC
\r
4574 SelectObject(hdcmem, oldBitmap);
\r
4577 /* Set clipping on the target DC */
\r
4578 if (!fullrepaint) {
\r
4579 SelectClipRgn(hdc, clips[0]);
\r
4580 for (x = 1; x < num_clips; x++) {
\r
4581 if (ExtSelectClipRgn(hdc, clips[x], RGN_OR) == ERROR)
\r
4582 abort(); // this should never ever happen!
\r
4586 /* Copy the new bitmap onto the screen in one go.
\r
4587 * This way we avoid any flickering
\r
4589 oldBitmap = SelectObject(tmphdc, bufferBitmap);
\r
4590 BitBlt(hdc, boardRect.left, boardRect.top,
\r
4591 boardRect.right - boardRect.left,
\r
4592 boardRect.bottom - boardRect.top,
\r
4593 tmphdc, boardRect.left, boardRect.top, SRCCOPY);
\r
4594 if(saveDiagFlag) {
\r
4595 BITMAP b; int i, j=0, m, w, wb, fac=0; char pData[1000000];
\r
4596 BITMAPINFOHEADER bih; int color[16], nrColors=0;
\r
4598 GetObject(bufferBitmap, sizeof(b), &b);
\r
4599 if(b.bmWidthBytes*b.bmHeight <= 990000) {
\r
4600 bih.biSize = sizeof(BITMAPINFOHEADER);
\r
4601 bih.biWidth = b.bmWidth;
\r
4602 bih.biHeight = b.bmHeight;
\r
4604 bih.biBitCount = b.bmBitsPixel;
\r
4605 bih.biCompression = 0;
\r
4606 bih.biSizeImage = b.bmWidthBytes*b.bmHeight;
\r
4607 bih.biXPelsPerMeter = 0;
\r
4608 bih.biYPelsPerMeter = 0;
\r
4609 bih.biClrUsed = 0;
\r
4610 bih.biClrImportant = 0;
\r
4611 // fprintf(diagFile, "t=%d\nw=%d\nh=%d\nB=%d\nP=%d\nX=%d\n",
\r
4612 // b.bmType, b.bmWidth, b.bmHeight, b.bmWidthBytes, b.bmPlanes, b.bmBitsPixel);
\r
4613 GetDIBits(tmphdc,bufferBitmap,0,b.bmHeight,pData,(BITMAPINFO*)&bih,DIB_RGB_COLORS);
\r
4614 // fprintf(diagFile, "%8x\n", (int) pData);
\r
4617 wb = b.bmWidthBytes;
\r
4619 for(i=0; i<wb*(b.bmHeight - boardRect.top + OUTER_MARGIN)>>2; i++) {
\r
4620 int k = ((int*) pData)[i];
\r
4621 for(j=0; j<nrColors; j++) if(color[j] == k) break;
\r
4622 if(j >= 16) break;
\r
4624 if(j >= nrColors) nrColors = j+1;
\r
4626 if(j<16) { // 16 colors is enough. Compress to 4 bits per pixel
\r
4628 for(i=0; i<b.bmHeight - boardRect.top + OUTER_MARGIN; i++) {
\r
4629 for(w=0; w<(wb>>2); w+=2) {
\r
4630 int k = ((int*) pData)[(wb*i>>2) + w];
\r
4631 for(j=0; j<nrColors; j++) if(color[j] == k) break;
\r
4632 k = ((int*) pData)[(wb*i>>2) + w + 1];
\r
4633 for(m=0; m<nrColors; m++) if(color[m] == k) break;
\r
4634 pData[p++] = m | j<<4;
\r
4636 while(p&3) pData[p++] = 0;
\r
4639 wb = ((wb+31)>>5)<<2;
\r
4641 // write BITMAPFILEHEADER
\r
4642 fprintf(diagFile, "BM");
\r
4643 fputDW(diagFile, wb*(b.bmHeight - boardRect.top + OUTER_MARGIN)+0x36 + (fac?64:0));
\r
4644 fputDW(diagFile, 0);
\r
4645 fputDW(diagFile, 0x36 + (fac?64:0));
\r
4646 // write BITMAPINFOHEADER
\r
4647 fputDW(diagFile, 40);
\r
4648 fputDW(diagFile, b.bmWidth);
\r
4649 fputDW(diagFile, b.bmHeight - boardRect.top + OUTER_MARGIN);
\r
4650 if(fac) fputDW(diagFile, 0x040001); // planes and bits/pixel
\r
4651 else fputDW(diagFile, 0x200001); // planes and bits/pixel
\r
4652 fputDW(diagFile, 0);
\r
4653 fputDW(diagFile, 0);
\r
4654 fputDW(diagFile, 0);
\r
4655 fputDW(diagFile, 0);
\r
4656 fputDW(diagFile, 0);
\r
4657 fputDW(diagFile, 0);
\r
4658 // write color table
\r
4660 for(i=0; i<16; i++) fputDW(diagFile, color[i]);
\r
4661 // write bitmap data
\r
4662 for(i=0; i<wb*(b.bmHeight - boardRect.top + OUTER_MARGIN); i++)
\r
4663 fputc(pData[i], diagFile);
\r
4668 SelectObject(tmphdc, oldBitmap);
\r
4670 /* Massive cleanup */
\r
4671 for (x = 0; x < num_clips; x++)
\r
4672 DeleteObject(clips[x]);
\r
4675 DeleteObject(bufferBitmap);
\r
4678 ReleaseDC(hwndMain, hdc);
\r
4680 if (lastDrawnFlipView != flipView) {
\r
4682 CheckMenuItem(GetMenu(hwndMain),IDM_FlipView, MF_BYCOMMAND|MF_CHECKED);
\r
4684 CheckMenuItem(GetMenu(hwndMain),IDM_FlipView, MF_BYCOMMAND|MF_UNCHECKED);
\r
4687 /* CopyBoard(lastDrawn, board);*/
\r
4688 lastDrawnHighlight = highlightInfo;
\r
4689 lastDrawnPremove = premoveHighlightInfo;
\r
4690 lastDrawnFlipView = flipView;
\r
4691 lastDrawnValid = 1;
\r
4694 /* [HGM] diag: Save the current board display to the given open file and close the file */
\r
4699 saveDiagFlag = 1; diagFile = f;
\r
4700 HDCDrawPosition(NULL, TRUE, NULL);
\r
4704 // if(f != NULL) fprintf(f, "Sorry, but this feature is still in preparation\n");
\r
4711 /*---------------------------------------------------------------------------*\
\r
4712 | CLIENT PAINT PROCEDURE
\r
4713 | This is the main event-handler for the WM_PAINT message.
\r
4715 \*---------------------------------------------------------------------------*/
\r
4717 PaintProc(HWND hwnd)
\r
4723 if((hdc = BeginPaint(hwnd, &ps))) {
\r
4724 if (IsIconic(hwnd)) {
\r
4725 DrawIcon(hdc, 2, 2, iconCurrent);
\r
4727 if (!appData.monoMode) {
\r
4728 SelectPalette(hdc, hPal, FALSE);
\r
4729 RealizePalette(hdc);
\r
4731 HDCDrawPosition(hdc, 1, NULL);
\r
4733 SelectObject(hdc, font[boardSize][MESSAGE_FONT]->hf);
\r
4734 ExtTextOut(hdc, messageRect.left, messageRect.top,
\r
4735 ETO_CLIPPED|ETO_OPAQUE,
\r
4736 &messageRect, messageText, strlen(messageText), NULL);
\r
4737 SelectObject(hdc, oldFont);
\r
4738 DisplayBothClocks();
\r
4740 EndPaint(hwnd,&ps);
\r
4748 * If the user selects on a border boundary, return -1; if off the board,
\r
4749 * return -2. Otherwise map the event coordinate to the square.
\r
4750 * The offset boardRect.left or boardRect.top must already have been
\r
4751 * subtracted from x.
\r
4754 EventToSquare(int x)
\r
4761 if ((x % (squareSize + lineGap)) >= squareSize)
\r
4763 x /= (squareSize + lineGap);
\r
4764 if (x >= BOARD_SIZE)
\r
4775 DropEnable dropEnables[] = {
\r
4776 { 'P', DP_Pawn, "Pawn" },
\r
4777 { 'N', DP_Knight, "Knight" },
\r
4778 { 'B', DP_Bishop, "Bishop" },
\r
4779 { 'R', DP_Rook, "Rook" },
\r
4780 { 'Q', DP_Queen, "Queen" },
\r
4784 SetupDropMenu(HMENU hmenu)
\r
4786 int i, count, enable;
\r
4788 extern char white_holding[], black_holding[];
\r
4789 char item[MSG_SIZ];
\r
4791 for (i=0; i<sizeof(dropEnables)/sizeof(DropEnable); i++) {
\r
4792 p = strchr(gameMode == IcsPlayingWhite ? white_holding : black_holding,
\r
4793 dropEnables[i].piece);
\r
4795 while (p && *p++ == dropEnables[i].piece) count++;
\r
4796 sprintf(item, "%s %d", dropEnables[i].name, count);
\r
4797 enable = count > 0 || !appData.testLegality
\r
4798 /*!!temp:*/ || (gameInfo.variant == VariantCrazyhouse
\r
4799 && !appData.icsActive);
\r
4800 ModifyMenu(hmenu, dropEnables[i].command,
\r
4801 MF_BYCOMMAND | (enable ? MF_ENABLED : MF_GRAYED) | MF_STRING,
\r
4802 dropEnables[i].command, item);
\r
4806 static int fromX = -1, fromY = -1, toX, toY;
\r
4808 /* Event handler for mouse messages */
\r
4810 MouseEvent(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
4814 static int recursive = 0;
\r
4816 // BOOLEAN needsRedraw = FALSE;
\r
4817 BOOLEAN saveAnimate;
\r
4818 BOOLEAN forceFullRepaint = IsFullRepaintPreferrable(); /* [AS] */
\r
4819 static BOOLEAN sameAgain = FALSE, promotionChoice = FALSE;
\r
4820 ChessMove moveType;
\r
4823 if (message == WM_MBUTTONUP) {
\r
4824 /* Hideous kludge to fool TrackPopupMenu into paying attention
\r
4825 to the middle button: we simulate pressing the left button too!
\r
4827 PostMessage(hwnd, WM_LBUTTONDOWN, wParam, lParam);
\r
4828 PostMessage(hwnd, WM_LBUTTONUP, wParam, lParam);
\r
4834 pt.x = LOWORD(lParam);
\r
4835 pt.y = HIWORD(lParam);
\r
4836 x = EventToSquare(pt.x - boardRect.left);
\r
4837 y = EventToSquare(pt.y - boardRect.top);
\r
4838 if (!flipView && y >= 0) {
\r
4839 y = BOARD_HEIGHT - 1 - y;
\r
4841 if (flipView && x >= 0) {
\r
4842 x = BOARD_WIDTH - 1 - x;
\r
4845 switch (message) {
\r
4846 case WM_LBUTTONDOWN:
\r
4847 if(promotionChoice) { // we are waiting for a click to indicate promotion piece
\r
4848 promotionChoice = FALSE; // only one chance: if click not OK it is interpreted as cancel
\r
4849 if(appData.debugMode) fprintf(debugFP, "promotion click, x=%d, y=%d\n", x, y);
\r
4850 if(gameInfo.holdingsWidth &&
\r
4851 (WhiteOnMove(currentMove)
\r
4852 ? x == BOARD_WIDTH-1 && y < gameInfo.holdingsSize && y > 0
\r
4853 : x == 0 && y >= BOARD_HEIGHT - gameInfo.holdingsSize && y < BOARD_HEIGHT-1) ) {
\r
4854 // click in right holdings, for determining promotion piece
\r
4855 ChessSquare p = boards[currentMove][y][x];
\r
4856 if(appData.debugMode) fprintf(debugFP, "square contains %d\n", (int)p);
\r
4857 if(p != EmptySquare) {
\r
4858 FinishMove(WhitePromotionQueen, fromX, fromY, toX, toY, ToLower(PieceToChar(p)));
\r
4859 fromX = fromY = -1;
\r
4863 DrawPosition(FALSE, boards[currentMove]);
\r
4867 sameAgain = FALSE;
\r
4869 /* Downclick vertically off board; check if on clock */
\r
4870 if (PtInRect((LPRECT) &whiteRect, pt)) {
\r
4871 if (gameMode == EditPosition) {
\r
4872 SetWhiteToPlayEvent();
\r
4873 } else if (gameMode == IcsPlayingBlack ||
\r
4874 gameMode == MachinePlaysWhite) {
\r
4876 } else if (gameMode == EditGame) {
\r
4877 AdjustClock((logoHeight > 0 ? flipView: flipClock), -1);
\r
4879 } else if (PtInRect((LPRECT) &blackRect, pt)) {
\r
4880 if (gameMode == EditPosition) {
\r
4881 SetBlackToPlayEvent();
\r
4882 } else if (gameMode == IcsPlayingWhite ||
\r
4883 gameMode == MachinePlaysBlack) {
\r
4885 } else if (gameMode == EditGame) {
\r
4886 AdjustClock(!(logoHeight > 0 ? flipView: flipClock), -1);
\r
4889 if (!appData.highlightLastMove) {
\r
4890 ClearHighlights();
\r
4891 DrawPosition((int) (forceFullRepaint || FALSE), NULL);
\r
4893 fromX = fromY = -1;
\r
4894 dragInfo.start.x = dragInfo.start.y = -1;
\r
4895 dragInfo.from = dragInfo.start;
\r
4897 } else if (x < 0 || y < 0
\r
4898 /* [HGM] block clicks between board and holdings */
\r
4899 || x == BOARD_LEFT-1 || x == BOARD_RGHT
\r
4900 || (x == BOARD_LEFT-2 && y < BOARD_HEIGHT-gameInfo.holdingsSize)
\r
4901 || (x == BOARD_RGHT+1 && y >= gameInfo.holdingsSize)
\r
4902 /* EditPosition, empty square, or different color piece;
\r
4903 click-click move is possible */
\r
4906 } else if (fromX == x && fromY == y) {
\r
4907 /* Downclick on same square again */
\r
4908 ClearHighlights();
\r
4909 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
4910 sameAgain = TRUE;
\r
4911 } else if (fromX != -1 &&
\r
4912 x != BOARD_LEFT-2 && x != BOARD_RGHT+1
\r
4914 /* Downclick on different square. */
\r
4915 /* [HGM] if on holdings file, should count as new first click ! */
\r
4916 { /* [HGM] <sameColor> now always do UserMoveTest(), and check colors there */
\r
4919 /* [HGM] <popupFix> UserMoveEvent requires two calls now,
\r
4920 to make sure move is legal before showing promotion popup */
\r
4921 moveType = UserMoveTest(fromX, fromY, toX, toY, NULLCHAR);
\r
4922 if(moveType == AmbiguousMove) { /* [HGM] Edit-Position move executed */
\r
4923 fromX = fromY = -1;
\r
4924 ClearHighlights();
\r
4925 DrawPosition(FALSE, boards[currentMove]);
\r
4928 if(moveType != ImpossibleMove) {
\r
4929 /* [HGM] We use PromotionToKnight in Shogi to indicate frorced promotion */
\r
4930 if (moveType == WhitePromotionKnight || moveType == BlackPromotionKnight ||
\r
4931 ((moveType == WhitePromotionQueen || moveType == BlackPromotionQueen) &&
\r
4932 appData.alwaysPromoteToQueen)) {
\r
4933 FinishMove(moveType, fromX, fromY, toX, toY, 'q');
\r
4934 if (!appData.highlightLastMove) {
\r
4935 ClearHighlights();
\r
4936 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
4939 if (moveType == WhitePromotionQueen || moveType == BlackPromotionQueen ) {
\r
4940 SetHighlights(fromX, fromY, toX, toY);
\r
4941 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
4942 /* [HGM] <popupFix> Popup calls FinishMove now.
\r
4943 If promotion to Q is legal, all are legal! */
\r
4944 if(gameInfo.variant == VariantSuper || gameInfo.variant == VariantGreat)
\r
4945 { ChessSquare p = boards[currentMove][fromY][fromX], q = boards[currentMove][toY][toX];
\r
4946 // kludge to temporarily execute move on display, wthout promotng yet
\r
4947 promotionChoice = TRUE;
\r
4948 boards[currentMove][fromY][fromX] = EmptySquare; // move Pawn to 8th rank
\r
4949 boards[currentMove][toY][toX] = p;
\r
4950 DrawPosition(FALSE, boards[currentMove]);
\r
4951 boards[currentMove][fromY][fromX] = p; // take back, but display stays
\r
4952 boards[currentMove][toY][toX] = q;
\r
4954 PromotionPopup(hwnd);
\r
4955 } else { /* not a promotion */
\r
4956 if (appData.animate || appData.highlightLastMove) {
\r
4957 SetHighlights(fromX, fromY, toX, toY);
\r
4959 ClearHighlights();
\r
4961 FinishMove(moveType, fromX, fromY, toX, toY, NULLCHAR);
\r
4962 fromX = fromY = -1;
\r
4963 if (appData.animate && !appData.highlightLastMove) {
\r
4964 ClearHighlights();
\r
4965 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
4971 /* [HGM] it seemed that braces were missing here */
\r
4972 SetPremoveHighlights(fromX, fromY, toX, toY);
\r
4973 fromX = fromY = -1;
\r
4977 ClearHighlights();
\r
4978 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
4980 /* First downclick, or restart on a square with same color piece */
\r
4981 if (!frozen && OKToStartUserMove(x, y)) {
\r
4984 dragInfo.lastpos = pt;
\r
4985 dragInfo.from.x = fromX;
\r
4986 dragInfo.from.y = fromY;
\r
4987 dragInfo.start = dragInfo.from;
\r
4988 SetCapture(hwndMain);
\r
4990 fromX = fromY = -1;
\r
4991 dragInfo.start.x = dragInfo.start.y = -1;
\r
4992 dragInfo.from = dragInfo.start;
\r
4993 DrawPosition(forceFullRepaint || FALSE, NULL); /* [AS] */
\r
4997 case WM_LBUTTONUP:
\r
4999 if (fromX == -1) break;
\r
5000 if (x == fromX && y == fromY) {
\r
5001 dragInfo.from.x = dragInfo.from.y = -1;
\r
5002 /* Upclick on same square */
\r
5004 /* Clicked same square twice: abort click-click move */
\r
5005 fromX = fromY = -1;
\r
5007 ClearPremoveHighlights();
\r
5009 /* First square clicked: start click-click move */
\r
5010 SetHighlights(fromX, fromY, -1, -1);
\r
5012 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
5013 } else if (dragInfo.from.x < 0 || dragInfo.from.y < 0) {
\r
5014 /* Errant click; ignore */
\r
5017 /* Finish drag move. */
\r
5018 if (appData.debugMode) {
\r
5019 fprintf(debugFP, "release\n");
\r
5021 dragInfo.from.x = dragInfo.from.y = -1;
\r
5024 saveAnimate = appData.animate; /* sorry, Hawk :) */
\r
5025 appData.animate = appData.animate && !appData.animateDragging;
\r
5026 moveType = UserMoveTest(fromX, fromY, toX, toY, NULLCHAR);
\r
5027 if(moveType == AmbiguousMove) { /* [HGM] Edit-Position move executed */
\r
5028 fromX = fromY = -1;
\r
5029 ClearHighlights();
\r
5030 DrawPosition(FALSE, boards[currentMove]);
\r
5033 if(moveType != ImpossibleMove) {
\r
5034 /* [HGM] use move type to determine if move is promotion.
\r
5035 Knight is Shogi kludge for mandatory promotion, Queen means choice */
\r
5036 if (moveType == WhitePromotionKnight || moveType == BlackPromotionKnight ||
\r
5037 ((moveType == WhitePromotionQueen || moveType == BlackPromotionQueen) &&
\r
5038 appData.alwaysPromoteToQueen))
\r
5039 FinishMove(moveType, fromX, fromY, toX, toY, 'q');
\r
5041 if (moveType == WhitePromotionQueen || moveType == BlackPromotionQueen ) {
\r
5042 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
5043 if(gameInfo.variant == VariantSuper || gameInfo.variant == VariantGreat)
\r
5044 { ChessSquare p = boards[currentMove][fromY][fromX], q = boards[currentMove][toY][toX];
\r
5045 // kludge to temporarily execute move on display, wthout promotng yet
\r
5046 promotionChoice = TRUE;
\r
5047 boards[currentMove][fromY][fromX] = EmptySquare; // move Pawn to 8th rank
\r
5048 boards[currentMove][toY][toX] = p;
\r
5049 DrawPosition(FALSE, boards[currentMove]);
\r
5050 boards[currentMove][fromY][fromX] = p; // take back, but display stays
\r
5051 boards[currentMove][toY][toX] = q;
\r
5054 PromotionPopup(hwnd); /* [HGM] Popup now calls FinishMove */
\r
5056 if(saveAnimate /* ^$!%@#$!$ */ && gameInfo.variant == VariantAtomic
\r
5057 && boards[currentMove][toY][toX] != EmptySquare) AnimateAtomicCapture(toX, toY, 20);
\r
5058 FinishMove(moveType, fromX, fromY, toX, toY, NULLCHAR);
\r
5061 if (gotPremove) SetPremoveHighlights(fromX, fromY, toX, toY);
\r
5062 appData.animate = saveAnimate;
\r
5063 fromX = fromY = -1;
\r
5064 if (appData.highlightDragging && !appData.highlightLastMove) {
\r
5065 ClearHighlights();
\r
5067 if (appData.animate || appData.animateDragging ||
\r
5068 appData.highlightDragging || gotPremove) {
\r
5069 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
5072 dragInfo.start.x = dragInfo.start.y = -1;
\r
5073 dragInfo.pos = dragInfo.lastpos = dragInfo.start;
\r
5076 case WM_MOUSEMOVE:
\r
5077 if ((appData.animateDragging || appData.highlightDragging)
\r
5078 && (wParam & MK_LBUTTON)
\r
5079 && dragInfo.from.x >= 0)
\r
5081 BOOL full_repaint = FALSE;
\r
5083 sameAgain = FALSE; /* [HGM] if we drag something around, do keep square selected */
\r
5084 if (appData.animateDragging) {
\r
5085 dragInfo.pos = pt;
\r
5087 if (appData.highlightDragging) {
\r
5088 SetHighlights(fromX, fromY, x, y);
\r
5089 if( IsDrawArrowEnabled() && (x < 0 || x >= BOARD_WIDTH || y < 0 || y >= BOARD_HEIGHT) ) {
\r
5090 full_repaint = TRUE;
\r
5094 DrawPosition( full_repaint, NULL);
\r
5096 dragInfo.lastpos = dragInfo.pos;
\r
5100 case WM_MOUSEWHEEL: // [DM]
\r
5101 { static int lastDir = 0; // [HGM] build in some hysteresis to avoid spurious events
\r
5102 /* Mouse Wheel is being rolled forward
\r
5103 * Play moves forward
\r
5105 if((short)HIWORD(wParam) > 0 && currentMove < forwardMostMove)
\r
5106 { if(lastDir == 1) ForwardEvent(); else lastDir = 1; } // [HGM] suppress first event in direction
\r
5107 /* Mouse Wheel is being rolled backward
\r
5108 * Play moves backward
\r
5110 if((short)HIWORD(wParam) < 0 && currentMove > backwardMostMove)
\r
5111 { if(lastDir == -1) BackwardEvent(); else lastDir = -1; }
\r
5115 case WM_MBUTTONDOWN:
\r
5116 case WM_RBUTTONDOWN:
\r
5119 fromX = fromY = -1;
\r
5120 dragInfo.pos.x = dragInfo.pos.y = -1;
\r
5121 dragInfo.start.x = dragInfo.start.y = -1;
\r
5122 dragInfo.from = dragInfo.start;
\r
5123 dragInfo.lastpos = dragInfo.pos;
\r
5124 if (appData.highlightDragging) {
\r
5125 ClearHighlights();
\r
5128 /* [HGM] right mouse button in clock area edit-game mode ups clock */
\r
5129 if (PtInRect((LPRECT) &whiteRect, pt)) {
\r
5130 if (gameMode == EditGame) AdjustClock((logoHeight > 0 ? flipView: flipClock), 1);
\r
5131 } else if (PtInRect((LPRECT) &blackRect, pt)) {
\r
5132 if (gameMode == EditGame) AdjustClock(!(logoHeight > 0 ? flipView: flipClock), 1);
\r
5135 DrawPosition(TRUE, NULL);
\r
5137 switch (gameMode) {
\r
5138 case EditPosition:
\r
5139 case IcsExamining:
\r
5140 if (x < 0 || y < 0) break;
\r
5143 if (message == WM_MBUTTONDOWN) {
\r
5144 buttonCount = 3; /* even if system didn't think so */
\r
5145 if (wParam & MK_SHIFT)
\r
5146 MenuPopup(hwnd, pt, LoadMenu(hInst, "BlackPieceMenu"), -1);
\r
5148 MenuPopup(hwnd, pt, LoadMenu(hInst, "WhitePieceMenu"), -1);
\r
5149 } else { /* message == WM_RBUTTONDOWN */
\r
5151 if (buttonCount == 3) {
\r
5152 if (wParam & MK_SHIFT)
\r
5153 MenuPopup(hwnd, pt, LoadMenu(hInst, "WhitePieceMenu"), -1);
\r
5155 MenuPopup(hwnd, pt, LoadMenu(hInst, "BlackPieceMenu"), -1);
\r
5157 MenuPopup(hwnd, pt, LoadMenu(hInst, "PieceMenu"), -1);
\r
5160 /* Just have one menu, on the right button. Windows users don't
\r
5161 think to try the middle one, and sometimes other software steals
\r
5162 it, or it doesn't really exist. */
\r
5163 if(gameInfo.variant != VariantShogi)
\r
5164 MenuPopup(hwnd, pt, LoadMenu(hInst, "PieceMenu"), -1);
\r
5166 MenuPopup(hwnd, pt, LoadMenu(hInst, "ShogiPieceMenu"), -1);
\r
5170 case IcsPlayingWhite:
\r
5171 case IcsPlayingBlack:
\r
5173 case MachinePlaysWhite:
\r
5174 case MachinePlaysBlack:
\r
5175 if (appData.testLegality &&
\r
5176 gameInfo.variant != VariantBughouse &&
\r
5177 gameInfo.variant != VariantCrazyhouse) break;
\r
5178 if (x < 0 || y < 0) break;
\r
5181 hmenu = LoadMenu(hInst, "DropPieceMenu");
\r
5182 SetupDropMenu(hmenu);
\r
5183 MenuPopup(hwnd, pt, hmenu, -1);
\r
5194 /* Preprocess messages for buttons in main window */
\r
5196 ButtonProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
5198 int id = GetWindowLong(hwnd, GWL_ID);
\r
5201 for (i=0; i<N_BUTTONS; i++) {
\r
5202 if (buttonDesc[i].id == id) break;
\r
5204 if (i == N_BUTTONS) return 0;
\r
5205 switch (message) {
\r
5210 dir = (wParam == VK_LEFT) ? -1 : 1;
\r
5211 SetFocus(buttonDesc[(i + dir + N_BUTTONS) % N_BUTTONS].hwnd);
\r
5218 SendMessage(hwndMain, WM_COMMAND, MAKEWPARAM(buttonDesc[i].id, 0), 0);
\r
5221 if (appData.icsActive) {
\r
5222 if (GetKeyState(VK_SHIFT) < 0) {
\r
5224 HWND h = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
5225 if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
5229 HWND h = GetDlgItem(hwndConsole, OPT_ConsoleText);
\r
5230 if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
5237 if (appData.icsActive) {
\r
5238 HWND h = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
5239 if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
5241 SendMessage(h, WM_CHAR, wParam, lParam);
\r
5243 } else if (isalpha((char)wParam) || isdigit((char)wParam)){
\r
5244 PopUpMoveDialog((char)wParam);
\r
5250 return CallWindowProc(buttonDesc[i].wndproc, hwnd, message, wParam, lParam);
\r
5253 /* Process messages for Promotion dialog box */
\r
5255 Promotion(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
5259 switch (message) {
\r
5260 case WM_INITDIALOG: /* message: initialize dialog box */
\r
5261 /* Center the dialog over the application window */
\r
5262 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
5263 ShowWindow(GetDlgItem(hDlg, PB_King),
\r
5264 (!appData.testLegality || gameInfo.variant == VariantSuicide ||
\r
5265 gameInfo.variant == VariantGiveaway || gameInfo.variant == VariantSuper ) ?
\r
5266 SW_SHOW : SW_HIDE);
\r
5267 /* [HGM] Only allow C & A promotions if these pieces are defined */
\r
5268 ShowWindow(GetDlgItem(hDlg, PB_Archbishop),
\r
5269 ((PieceToChar(WhiteAngel) >= 'A' &&
\r
5270 PieceToChar(WhiteAngel) != '~') ||
\r
5271 (PieceToChar(BlackAngel) >= 'A' &&
\r
5272 PieceToChar(BlackAngel) != '~') ) ?
\r
5273 SW_SHOW : SW_HIDE);
\r
5274 ShowWindow(GetDlgItem(hDlg, PB_Chancellor),
\r
5275 ((PieceToChar(WhiteMarshall) >= 'A' &&
\r
5276 PieceToChar(WhiteMarshall) != '~') ||
\r
5277 (PieceToChar(BlackMarshall) >= 'A' &&
\r
5278 PieceToChar(BlackMarshall) != '~') ) ?
\r
5279 SW_SHOW : SW_HIDE);
\r
5280 /* [HGM] Hide B & R button in Shogi, use Q as promote, N as defer */
\r
5281 ShowWindow(GetDlgItem(hDlg, PB_Rook),
\r
5282 gameInfo.variant != VariantShogi ?
\r
5283 SW_SHOW : SW_HIDE);
\r
5284 ShowWindow(GetDlgItem(hDlg, PB_Bishop),
\r
5285 gameInfo.variant != VariantShogi ?
\r
5286 SW_SHOW : SW_HIDE);
\r
5287 ShowWindow(GetDlgItem(hDlg, IDC_Yes),
\r
5288 gameInfo.variant == VariantShogi ?
\r
5289 SW_SHOW : SW_HIDE);
\r
5290 ShowWindow(GetDlgItem(hDlg, IDC_No),
\r
5291 gameInfo.variant == VariantShogi ?
\r
5292 SW_SHOW : SW_HIDE);
\r
5293 ShowWindow(GetDlgItem(hDlg, IDC_Centaur),
\r
5294 gameInfo.variant == VariantSuper ?
\r
5295 SW_SHOW : SW_HIDE);
\r
5298 case WM_COMMAND: /* message: received a command */
\r
5299 switch (LOWORD(wParam)) {
\r
5301 EndDialog(hDlg, TRUE); /* Exit the dialog */
\r
5302 ClearHighlights();
\r
5303 DrawPosition(FALSE, NULL);
\r
5306 promoChar = gameInfo.variant == VariantSuper ? PieceToChar(BlackSilver) : PieceToChar(BlackKing);
\r
5309 promoChar = gameInfo.variant == VariantShogi ? '+' : PieceToChar(BlackQueen);
\r
5312 promoChar = PieceToChar(BlackRook);
\r
5315 promoChar = PieceToChar(BlackBishop);
\r
5317 case PB_Chancellor:
\r
5318 promoChar = PieceToChar(BlackMarshall);
\r
5320 case PB_Archbishop:
\r
5321 promoChar = PieceToChar(BlackAngel);
\r
5324 promoChar = gameInfo.variant == VariantShogi ? '=' : PieceToChar(BlackKnight);
\r
5329 EndDialog(hDlg, TRUE); /* Exit the dialog */
\r
5330 /* [HGM] <popupFix> Call FinishMove rather than UserMoveEvent, as we
\r
5331 only show the popup when we are already sure the move is valid or
\r
5332 legal. We pass a faulty move type, but the kludge is that FinishMove
\r
5333 will figure out it is a promotion from the promoChar. */
\r
5334 FinishMove(NormalMove, fromX, fromY, toX, toY, promoChar);
\r
5335 if (!appData.highlightLastMove) {
\r
5336 ClearHighlights();
\r
5337 DrawPosition(FALSE, NULL);
\r
5344 /* Pop up promotion dialog */
\r
5346 PromotionPopup(HWND hwnd)
\r
5350 lpProc = MakeProcInstance((FARPROC)Promotion, hInst);
\r
5351 DialogBox(hInst, MAKEINTRESOURCE(DLG_PromotionKing),
\r
5352 hwnd, (DLGPROC)lpProc);
\r
5353 FreeProcInstance(lpProc);
\r
5356 /* Toggle ShowThinking */
\r
5358 ToggleShowThinking()
\r
5360 appData.showThinking = !appData.showThinking;
\r
5361 ShowThinkingEvent();
\r
5365 LoadGameDialog(HWND hwnd, char* title)
\r
5369 char fileTitle[MSG_SIZ];
\r
5370 f = OpenFileDialog(hwnd, "rb", "",
\r
5371 appData.oldSaveStyle ? "gam" : "pgn",
\r
5373 title, &number, fileTitle, NULL);
\r
5375 cmailMsgLoaded = FALSE;
\r
5376 if (number == 0) {
\r
5377 int error = GameListBuild(f);
\r
5379 DisplayError("Cannot build game list", error);
\r
5380 } else if (!ListEmpty(&gameList) &&
\r
5381 ((ListGame *) gameList.tailPred)->number > 1) {
\r
5382 GameListPopUp(f, fileTitle);
\r
5385 GameListDestroy();
\r
5388 LoadGame(f, number, fileTitle, FALSE);
\r
5393 ChangedConsoleFont()
\r
5396 CHARRANGE tmpsel, sel;
\r
5397 MyFont *f = font[boardSize][CONSOLE_FONT];
\r
5398 HWND hText = GetDlgItem(hwndConsole, OPT_ConsoleText);
\r
5399 HWND hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
5402 cfmt.cbSize = sizeof(CHARFORMAT);
\r
5403 cfmt.dwMask = CFM_FACE|CFM_SIZE|CFM_CHARSET;
\r
5404 strcpy(cfmt.szFaceName, font[boardSize][CONSOLE_FONT]->mfp.faceName);
\r
5405 /* yHeight is expressed in twips. A twip is 1/20 of a font's point
\r
5406 * size. This was undocumented in the version of MSVC++ that I had
\r
5407 * when I wrote the code, but is apparently documented now.
\r
5409 cfmt.yHeight = (int)(f->mfp.pointSize * 20.0 + 0.5);
\r
5410 cfmt.bCharSet = f->lf.lfCharSet;
\r
5411 cfmt.bPitchAndFamily = f->lf.lfPitchAndFamily;
\r
5412 SendMessage(hText, EM_SETCHARFORMAT, SCF_ALL, (LPARAM) &cfmt);
\r
5413 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM) &cfmt);
\r
5414 /* Why are the following seemingly needed too? */
\r
5415 SendMessage(hText, EM_SETCHARFORMAT, SCF_DEFAULT, (LPARAM) &cfmt);
\r
5416 SendMessage(hInput, EM_SETCHARFORMAT, SCF_DEFAULT, (LPARAM) &cfmt);
\r
5417 SendMessage(hText, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
5419 tmpsel.cpMax = -1; /*999999?*/
\r
5420 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&tmpsel);
\r
5421 SendMessage(hText, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM) &cfmt);
\r
5422 /* Trying putting this here too. It still seems to tickle a RichEdit
\r
5423 * bug: sometimes RichEdit indents the first line of a paragraph too.
\r
5425 paraf.cbSize = sizeof(paraf);
\r
5426 paraf.dwMask = PFM_OFFSET | PFM_STARTINDENT;
\r
5427 paraf.dxStartIndent = 0;
\r
5428 paraf.dxOffset = WRAP_INDENT;
\r
5429 SendMessage(hText, EM_SETPARAFORMAT, 0, (LPARAM) ¶f);
\r
5430 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
5433 /*---------------------------------------------------------------------------*\
\r
5435 * Window Proc for main window
\r
5437 \*---------------------------------------------------------------------------*/
\r
5439 /* Process messages for main window, etc. */
\r
5441 WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
5444 int wmId, wmEvent;
\r
5448 char fileTitle[MSG_SIZ];
\r
5449 char buf[MSG_SIZ];
\r
5450 static SnapData sd;
\r
5452 switch (message) {
\r
5454 case WM_PAINT: /* message: repaint portion of window */
\r
5458 case WM_ERASEBKGND:
\r
5459 if (IsIconic(hwnd)) {
\r
5460 /* Cheat; change the message */
\r
5461 return (DefWindowProc(hwnd, WM_ICONERASEBKGND, wParam, lParam));
\r
5463 return (DefWindowProc(hwnd, message, wParam, lParam));
\r
5467 case WM_LBUTTONDOWN:
\r
5468 case WM_MBUTTONDOWN:
\r
5469 case WM_RBUTTONDOWN:
\r
5470 case WM_LBUTTONUP:
\r
5471 case WM_MBUTTONUP:
\r
5472 case WM_RBUTTONUP:
\r
5473 case WM_MOUSEMOVE:
\r
5474 case WM_MOUSEWHEEL:
\r
5475 MouseEvent(hwnd, message, wParam, lParam);
\r
5480 if (appData.icsActive) {
\r
5481 if (wParam == '\t') {
\r
5482 if (GetKeyState(VK_SHIFT) < 0) {
\r
5484 HWND h = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
5485 if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
5489 HWND h = GetDlgItem(hwndConsole, OPT_ConsoleText);
\r
5490 if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
5494 HWND h = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
5495 if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
5497 SendMessage(h, message, wParam, lParam);
\r
5499 } else if (isalpha((char)wParam) || isdigit((char)wParam)) {
\r
5500 PopUpMoveDialog((char)wParam);
\r
5504 case WM_PALETTECHANGED:
\r
5505 if (hwnd != (HWND)wParam && !appData.monoMode) {
\r
5507 HDC hdc = GetDC(hwndMain);
\r
5508 SelectPalette(hdc, hPal, TRUE);
\r
5509 nnew = RealizePalette(hdc);
\r
5511 paletteChanged = TRUE;
\r
5513 UpdateColors(hdc);
\r
5515 InvalidateRect(hwnd, &boardRect, FALSE);/*faster!*/
\r
5518 ReleaseDC(hwnd, hdc);
\r
5522 case WM_QUERYNEWPALETTE:
\r
5523 if (!appData.monoMode /*&& paletteChanged*/) {
\r
5525 HDC hdc = GetDC(hwndMain);
\r
5526 paletteChanged = FALSE;
\r
5527 SelectPalette(hdc, hPal, FALSE);
\r
5528 nnew = RealizePalette(hdc);
\r
5530 InvalidateRect(hwnd, &boardRect, FALSE);
\r
5532 ReleaseDC(hwnd, hdc);
\r
5537 case WM_COMMAND: /* message: command from application menu */
\r
5538 wmId = LOWORD(wParam);
\r
5539 wmEvent = HIWORD(wParam);
\r
5544 AnalysisPopDown();
\r
5547 case IDM_NewGameFRC:
\r
5548 if( NewGameFRC() == 0 ) {
\r
5550 AnalysisPopDown();
\r
5554 case IDM_NewVariant:
\r
5555 NewVariantPopup(hwnd);
\r
5558 case IDM_LoadGame:
\r
5559 LoadGameDialog(hwnd, "Load Game from File");
\r
5562 case IDM_LoadNextGame:
\r
5566 case IDM_LoadPrevGame:
\r
5570 case IDM_ReloadGame:
\r
5574 case IDM_LoadPosition:
\r
5575 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile) {
\r
5576 Reset(FALSE, TRUE);
\r
5579 f = OpenFileDialog(hwnd, "rb", "",
\r
5580 appData.oldSaveStyle ? "pos" : "fen",
\r
5582 "Load Position from File", &number, fileTitle, NULL);
\r
5584 LoadPosition(f, number, fileTitle);
\r
5588 case IDM_LoadNextPosition:
\r
5589 ReloadPosition(1);
\r
5592 case IDM_LoadPrevPosition:
\r
5593 ReloadPosition(-1);
\r
5596 case IDM_ReloadPosition:
\r
5597 ReloadPosition(0);
\r
5600 case IDM_SaveGame:
\r
5601 defName = DefaultFileName(appData.oldSaveStyle ? "gam" : "pgn");
\r
5602 f = OpenFileDialog(hwnd, "a", defName,
\r
5603 appData.oldSaveStyle ? "gam" : "pgn",
\r
5605 "Save Game to File", NULL, fileTitle, NULL);
\r
5607 SaveGame(f, 0, "");
\r
5611 case IDM_SavePosition:
\r
5612 defName = DefaultFileName(appData.oldSaveStyle ? "pos" : "fen");
\r
5613 f = OpenFileDialog(hwnd, "a", defName,
\r
5614 appData.oldSaveStyle ? "pos" : "fen",
\r
5616 "Save Position to File", NULL, fileTitle, NULL);
\r
5618 SavePosition(f, 0, "");
\r
5622 case IDM_SaveDiagram:
\r
5623 defName = "diagram";
\r
5624 f = OpenFileDialog(hwnd, "wb", defName,
\r
5627 "Save Diagram to File", NULL, fileTitle, NULL);
\r
5633 case IDM_CopyGame:
\r
5634 CopyGameToClipboard();
\r
5637 case IDM_PasteGame:
\r
5638 PasteGameFromClipboard();
\r
5641 case IDM_CopyGameListToClipboard:
\r
5642 CopyGameListToClipboard();
\r
5645 /* [AS] Autodetect FEN or PGN data */
\r
5646 case IDM_PasteAny:
\r
5647 PasteGameOrFENFromClipboard();
\r
5650 /* [AS] Move history */
\r
5651 case IDM_ShowMoveHistory:
\r
5652 if( MoveHistoryIsUp() ) {
\r
5653 MoveHistoryPopDown();
\r
5656 MoveHistoryPopUp();
\r
5660 /* [AS] Eval graph */
\r
5661 case IDM_ShowEvalGraph:
\r
5662 if( EvalGraphIsUp() ) {
\r
5663 EvalGraphPopDown();
\r
5670 /* [AS] Engine output */
\r
5671 case IDM_ShowEngineOutput:
\r
5672 if( EngineOutputIsUp() ) {
\r
5673 EngineOutputPopDown();
\r
5676 EngineOutputPopUp();
\r
5680 /* [AS] User adjudication */
\r
5681 case IDM_UserAdjudication_White:
\r
5682 UserAdjudicationEvent( +1 );
\r
5685 case IDM_UserAdjudication_Black:
\r
5686 UserAdjudicationEvent( -1 );
\r
5689 case IDM_UserAdjudication_Draw:
\r
5690 UserAdjudicationEvent( 0 );
\r
5693 /* [AS] Game list options dialog */
\r
5694 case IDM_GameListOptions:
\r
5695 GameListOptions();
\r
5698 case IDM_CopyPosition:
\r
5699 CopyFENToClipboard();
\r
5702 case IDM_PastePosition:
\r
5703 PasteFENFromClipboard();
\r
5706 case IDM_MailMove:
\r
5710 case IDM_ReloadCMailMsg:
\r
5711 Reset(TRUE, TRUE);
\r
5712 ReloadCmailMsgEvent(FALSE);
\r
5715 case IDM_Minimize:
\r
5716 ShowWindow(hwnd, SW_MINIMIZE);
\r
5723 case IDM_MachineWhite:
\r
5724 MachineWhiteEvent();
\r
5726 * refresh the tags dialog only if it's visible
\r
5728 if (gameMode == MachinePlaysWhite && IsWindowVisible(editTagsDialog)) {
\r
5730 tags = PGNTags(&gameInfo);
\r
5731 TagsPopUp(tags, CmailMsg());
\r
5736 case IDM_MachineBlack:
\r
5737 MachineBlackEvent();
\r
5739 * refresh the tags dialog only if it's visible
\r
5741 if (gameMode == MachinePlaysBlack && IsWindowVisible(editTagsDialog)) {
\r
5743 tags = PGNTags(&gameInfo);
\r
5744 TagsPopUp(tags, CmailMsg());
\r
5749 case IDM_TwoMachines:
\r
5750 TwoMachinesEvent();
\r
5752 * refresh the tags dialog only if it's visible
\r
5754 if (gameMode == TwoMachinesPlay && IsWindowVisible(editTagsDialog)) {
\r
5756 tags = PGNTags(&gameInfo);
\r
5757 TagsPopUp(tags, CmailMsg());
\r
5762 case IDM_AnalysisMode:
\r
5763 if (!first.analysisSupport) {
\r
5764 sprintf(buf, "%s does not support analysis", first.tidy);
\r
5765 DisplayError(buf, 0);
\r
5767 /* [DM] icsEngineAnlyze [HGM] Why is this front-end??? */
\r
5768 if (appData.icsActive) {
\r
5769 if (gameMode != IcsObserving) {
\r
5770 sprintf(buf, "You are not observing a game");
\r
5771 DisplayError(buf, 0);
\r
5772 /* secure check */
\r
5773 if (appData.icsEngineAnalyze) {
\r
5774 if (appData.debugMode)
\r
5775 fprintf(debugFP, "Found unexpected active ICS engine analyze \n");
\r
5776 ExitAnalyzeMode();
\r
5782 /* if enable, user want disable icsEngineAnalyze */
\r
5783 if (appData.icsEngineAnalyze) {
\r
5784 ExitAnalyzeMode();
\r
5788 appData.icsEngineAnalyze = TRUE;
\r
5789 if (appData.debugMode) fprintf(debugFP, "ICS engine analyze starting...\n");
\r
5792 if (!appData.showThinking) ToggleShowThinking();
\r
5793 AnalyzeModeEvent();
\r
5797 case IDM_AnalyzeFile:
\r
5798 if (!first.analysisSupport) {
\r
5799 char buf[MSG_SIZ];
\r
5800 sprintf(buf, "%s does not support analysis", first.tidy);
\r
5801 DisplayError(buf, 0);
\r
5803 if (!appData.showThinking) ToggleShowThinking();
\r
5804 AnalyzeFileEvent();
\r
5805 LoadGameDialog(hwnd, "Analyze Game from File");
\r
5806 AnalysisPeriodicEvent(1);
\r
5810 case IDM_IcsClient:
\r
5814 case IDM_EditGame:
\r
5818 case IDM_EditPosition:
\r
5819 EditPositionEvent();
\r
5822 case IDM_Training:
\r
5826 case IDM_ShowGameList:
\r
5827 ShowGameListProc();
\r
5830 case IDM_EditTags:
\r
5834 case IDM_EditComment:
\r
5835 if (commentDialogUp && editComment) {
\r
5838 EditCommentEvent();
\r
5858 case IDM_CallFlag:
\r
5878 case IDM_StopObserving:
\r
5879 StopObservingEvent();
\r
5882 case IDM_StopExamining:
\r
5883 StopExaminingEvent();
\r
5886 case IDM_TypeInMove:
\r
5887 PopUpMoveDialog('\000');
\r
5890 case IDM_TypeInName:
\r
5891 PopUpNameDialog('\000');
\r
5894 case IDM_Backward:
\r
5896 SetFocus(hwndMain);
\r
5901 SetFocus(hwndMain);
\r
5906 SetFocus(hwndMain);
\r
5911 SetFocus(hwndMain);
\r
5918 case IDM_TruncateGame:
\r
5919 TruncateGameEvent();
\r
5926 case IDM_RetractMove:
\r
5927 RetractMoveEvent();
\r
5930 case IDM_FlipView:
\r
5931 flipView = !flipView;
\r
5932 DrawPosition(FALSE, NULL);
\r
5935 case IDM_FlipClock:
\r
5936 flipClock = !flipClock;
\r
5937 DisplayBothClocks();
\r
5940 case IDM_GeneralOptions:
\r
5941 GeneralOptionsPopup(hwnd);
\r
5942 DrawPosition(TRUE, NULL);
\r
5945 case IDM_BoardOptions:
\r
5946 BoardOptionsPopup(hwnd);
\r
5949 case IDM_EnginePlayOptions:
\r
5950 EnginePlayOptionsPopup(hwnd);
\r
5953 case IDM_OptionsUCI:
\r
5954 UciOptionsPopup(hwnd);
\r
5957 case IDM_IcsOptions:
\r
5958 IcsOptionsPopup(hwnd);
\r
5962 FontsOptionsPopup(hwnd);
\r
5966 SoundOptionsPopup(hwnd);
\r
5969 case IDM_CommPort:
\r
5970 CommPortOptionsPopup(hwnd);
\r
5973 case IDM_LoadOptions:
\r
5974 LoadOptionsPopup(hwnd);
\r
5977 case IDM_SaveOptions:
\r
5978 SaveOptionsPopup(hwnd);
\r
5981 case IDM_TimeControl:
\r
5982 TimeControlOptionsPopup(hwnd);
\r
5985 case IDM_SaveSettings:
\r
5986 SaveSettings(settingsFileName);
\r
5989 case IDM_SaveSettingsOnExit:
\r
5990 saveSettingsOnExit = !saveSettingsOnExit;
\r
5991 (void) CheckMenuItem(GetMenu(hwndMain), IDM_SaveSettingsOnExit,
\r
5992 MF_BYCOMMAND|(saveSettingsOnExit ?
\r
5993 MF_CHECKED : MF_UNCHECKED));
\r
6004 case IDM_AboutGame:
\r
6009 appData.debugMode = !appData.debugMode;
\r
6010 if (appData.debugMode) {
\r
6011 char dir[MSG_SIZ];
\r
6012 GetCurrentDirectory(MSG_SIZ, dir);
\r
6013 SetCurrentDirectory(installDir);
\r
6014 debugFP = fopen(appData.nameOfDebugFile, "w");
\r
6015 SetCurrentDirectory(dir);
\r
6016 setbuf(debugFP, NULL);
\r
6023 case IDM_HELPCONTENTS:
\r
6024 if (!WinHelp (hwnd, "winboard.hlp", HELP_KEY,(DWORD)(LPSTR)"CONTENTS")) {
\r
6025 MessageBox (GetFocus(),
\r
6026 "Unable to activate help",
\r
6027 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
6031 case IDM_HELPSEARCH:
\r
6032 if (!WinHelp(hwnd, "winboard.hlp", HELP_PARTIALKEY, (DWORD)(LPSTR)"")) {
\r
6033 MessageBox (GetFocus(),
\r
6034 "Unable to activate help",
\r
6035 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
6039 case IDM_HELPHELP:
\r
6040 if(!WinHelp(hwnd, (LPSTR)NULL, HELP_HELPONHELP, 0)) {
\r
6041 MessageBox (GetFocus(),
\r
6042 "Unable to activate help",
\r
6043 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
6048 lpProc = MakeProcInstance((FARPROC)About, hInst);
\r
6050 (gameInfo.event && strcmp(gameInfo.event, "Easter Egg Hunt") == 0) ?
\r
6051 "AboutBox2" : "AboutBox", hwnd, (DLGPROC)lpProc);
\r
6052 FreeProcInstance(lpProc);
\r
6055 case IDM_DirectCommand1:
\r
6056 AskQuestionEvent("Direct Command",
\r
6057 "Send to chess program:", "", "1");
\r
6059 case IDM_DirectCommand2:
\r
6060 AskQuestionEvent("Direct Command",
\r
6061 "Send to second chess program:", "", "2");
\r
6064 case EP_WhitePawn:
\r
6065 EditPositionMenuEvent(WhitePawn, fromX, fromY);
\r
6066 fromX = fromY = -1;
\r
6069 case EP_WhiteKnight:
\r
6070 EditPositionMenuEvent(WhiteKnight, fromX, fromY);
\r
6071 fromX = fromY = -1;
\r
6074 case EP_WhiteBishop:
\r
6075 EditPositionMenuEvent(WhiteBishop, fromX, fromY);
\r
6076 fromX = fromY = -1;
\r
6079 case EP_WhiteRook:
\r
6080 EditPositionMenuEvent(WhiteRook, fromX, fromY);
\r
6081 fromX = fromY = -1;
\r
6084 case EP_WhiteQueen:
\r
6085 EditPositionMenuEvent(WhiteQueen, fromX, fromY);
\r
6086 fromX = fromY = -1;
\r
6089 case EP_WhiteFerz:
\r
6090 EditPositionMenuEvent(WhiteFerz, fromX, fromY);
\r
6091 fromX = fromY = -1;
\r
6094 case EP_WhiteWazir:
\r
6095 EditPositionMenuEvent(WhiteWazir, fromX, fromY);
\r
6096 fromX = fromY = -1;
\r
6099 case EP_WhiteAlfil:
\r
6100 EditPositionMenuEvent(WhiteAlfil, fromX, fromY);
\r
6101 fromX = fromY = -1;
\r
6104 case EP_WhiteCannon:
\r
6105 EditPositionMenuEvent(WhiteCannon, fromX, fromY);
\r
6106 fromX = fromY = -1;
\r
6109 case EP_WhiteCardinal:
\r
6110 EditPositionMenuEvent(WhiteAngel, fromX, fromY);
\r
6111 fromX = fromY = -1;
\r
6114 case EP_WhiteMarshall:
\r
6115 EditPositionMenuEvent(WhiteMarshall, fromX, fromY);
\r
6116 fromX = fromY = -1;
\r
6119 case EP_WhiteKing:
\r
6120 EditPositionMenuEvent(WhiteKing, fromX, fromY);
\r
6121 fromX = fromY = -1;
\r
6124 case EP_BlackPawn:
\r
6125 EditPositionMenuEvent(BlackPawn, fromX, fromY);
\r
6126 fromX = fromY = -1;
\r
6129 case EP_BlackKnight:
\r
6130 EditPositionMenuEvent(BlackKnight, fromX, fromY);
\r
6131 fromX = fromY = -1;
\r
6134 case EP_BlackBishop:
\r
6135 EditPositionMenuEvent(BlackBishop, fromX, fromY);
\r
6136 fromX = fromY = -1;
\r
6139 case EP_BlackRook:
\r
6140 EditPositionMenuEvent(BlackRook, fromX, fromY);
\r
6141 fromX = fromY = -1;
\r
6144 case EP_BlackQueen:
\r
6145 EditPositionMenuEvent(BlackQueen, fromX, fromY);
\r
6146 fromX = fromY = -1;
\r
6149 case EP_BlackFerz:
\r
6150 EditPositionMenuEvent(BlackFerz, fromX, fromY);
\r
6151 fromX = fromY = -1;
\r
6154 case EP_BlackWazir:
\r
6155 EditPositionMenuEvent(BlackWazir, fromX, fromY);
\r
6156 fromX = fromY = -1;
\r
6159 case EP_BlackAlfil:
\r
6160 EditPositionMenuEvent(BlackAlfil, fromX, fromY);
\r
6161 fromX = fromY = -1;
\r
6164 case EP_BlackCannon:
\r
6165 EditPositionMenuEvent(BlackCannon, fromX, fromY);
\r
6166 fromX = fromY = -1;
\r
6169 case EP_BlackCardinal:
\r
6170 EditPositionMenuEvent(BlackAngel, fromX, fromY);
\r
6171 fromX = fromY = -1;
\r
6174 case EP_BlackMarshall:
\r
6175 EditPositionMenuEvent(BlackMarshall, fromX, fromY);
\r
6176 fromX = fromY = -1;
\r
6179 case EP_BlackKing:
\r
6180 EditPositionMenuEvent(BlackKing, fromX, fromY);
\r
6181 fromX = fromY = -1;
\r
6184 case EP_EmptySquare:
\r
6185 EditPositionMenuEvent(EmptySquare, fromX, fromY);
\r
6186 fromX = fromY = -1;
\r
6189 case EP_ClearBoard:
\r
6190 EditPositionMenuEvent(ClearBoard, fromX, fromY);
\r
6191 fromX = fromY = -1;
\r
6195 EditPositionMenuEvent(WhitePlay, fromX, fromY);
\r
6196 fromX = fromY = -1;
\r
6200 EditPositionMenuEvent(BlackPlay, fromX, fromY);
\r
6201 fromX = fromY = -1;
\r
6205 EditPositionMenuEvent(PromotePiece, fromX, fromY);
\r
6206 fromX = fromY = -1;
\r
6210 EditPositionMenuEvent(DemotePiece, fromX, fromY);
\r
6211 fromX = fromY = -1;
\r
6215 DropMenuEvent(WhitePawn, fromX, fromY);
\r
6216 fromX = fromY = -1;
\r
6220 DropMenuEvent(WhiteKnight, fromX, fromY);
\r
6221 fromX = fromY = -1;
\r
6225 DropMenuEvent(WhiteBishop, fromX, fromY);
\r
6226 fromX = fromY = -1;
\r
6230 DropMenuEvent(WhiteRook, fromX, fromY);
\r
6231 fromX = fromY = -1;
\r
6235 DropMenuEvent(WhiteQueen, fromX, fromY);
\r
6236 fromX = fromY = -1;
\r
6240 return (DefWindowProc(hwnd, message, wParam, lParam));
\r
6246 case CLOCK_TIMER_ID:
\r
6247 KillTimer(hwnd, clockTimerEvent); /* Simulate one-shot timer as in X */
\r
6248 clockTimerEvent = 0;
\r
6249 DecrementClocks(); /* call into back end */
\r
6251 case LOAD_GAME_TIMER_ID:
\r
6252 KillTimer(hwnd, loadGameTimerEvent); /* Simulate one-shot timer as in X*/
\r
6253 loadGameTimerEvent = 0;
\r
6254 AutoPlayGameLoop(); /* call into back end */
\r
6256 case ANALYSIS_TIMER_ID:
\r
6257 if ((gameMode == AnalyzeMode || gameMode == AnalyzeFile
\r
6258 || appData.icsEngineAnalyze) && appData.periodicUpdates) {
\r
6259 AnalysisPeriodicEvent(0);
\r
6261 KillTimer(hwnd, analysisTimerEvent);
\r
6262 analysisTimerEvent = 0;
\r
6265 case DELAYED_TIMER_ID:
\r
6266 KillTimer(hwnd, delayedTimerEvent);
\r
6267 delayedTimerEvent = 0;
\r
6268 delayedTimerCallback();
\r
6273 case WM_USER_Input:
\r
6274 InputEvent(hwnd, message, wParam, lParam);
\r
6277 /* [AS] Also move "attached" child windows */
\r
6278 case WM_WINDOWPOSCHANGING:
\r
6279 if( hwnd == hwndMain && appData.useStickyWindows ) {
\r
6280 LPWINDOWPOS lpwp = (LPWINDOWPOS) lParam;
\r
6282 if( ((lpwp->flags & SWP_NOMOVE) == 0) && ((lpwp->flags & SWP_NOSIZE) != 0) ) {
\r
6283 /* Window is moving */
\r
6286 GetWindowRect( hwnd, &rcMain );
\r
6288 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, moveHistoryDialog, &wpMoveHistory );
\r
6289 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, evalGraphDialog, &wpEvalGraph );
\r
6290 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, engineOutputDialog, &wpEngineOutput );
\r
6295 /* [AS] Snapping */
\r
6296 case WM_ENTERSIZEMOVE:
\r
6297 if(appData.debugMode) { fprintf(debugFP, "size-move\n"); }
\r
6298 if (hwnd == hwndMain) {
\r
6299 doingSizing = TRUE;
\r
6302 return OnEnterSizeMove( &sd, hwnd, wParam, lParam );
\r
6306 if(appData.debugMode) { fprintf(debugFP, "sizing\n"); }
\r
6307 if (hwnd == hwndMain) {
\r
6308 lastSizing = wParam;
\r
6313 if(appData.debugMode) { fprintf(debugFP, "moving\n"); }
\r
6314 return OnMoving( &sd, hwnd, wParam, lParam );
\r
6316 case WM_EXITSIZEMOVE:
\r
6317 if(appData.debugMode) { fprintf(debugFP, "exit size-move, size = %d\n", squareSize); }
\r
6318 if (hwnd == hwndMain) {
\r
6320 doingSizing = FALSE;
\r
6321 InvalidateRect(hwnd, &boardRect, FALSE);
\r
6322 GetClientRect(hwnd, &client);
\r
6323 ResizeBoard(client.right, client.bottom, lastSizing);
\r
6325 if(appData.debugMode) { fprintf(debugFP, "square size = %d\n", squareSize); }
\r
6327 return OnExitSizeMove( &sd, hwnd, wParam, lParam );
\r
6330 case WM_DESTROY: /* message: window being destroyed */
\r
6331 PostQuitMessage(0);
\r
6335 if (hwnd == hwndMain) {
\r
6340 default: /* Passes it on if unprocessed */
\r
6341 return (DefWindowProc(hwnd, message, wParam, lParam));
\r
6346 /*---------------------------------------------------------------------------*\
\r
6348 * Misc utility routines
\r
6350 \*---------------------------------------------------------------------------*/
\r
6353 * Decent random number generator, at least not as bad as Windows
\r
6354 * standard rand, which returns a value in the range 0 to 0x7fff.
\r
6356 unsigned int randstate;
\r
6361 randstate = randstate * 1664525 + 1013904223;
\r
6362 return (int) randstate & 0x7fffffff;
\r
6366 mysrandom(unsigned int seed)
\r
6373 * returns TRUE if user selects a different color, FALSE otherwise
\r
6377 ChangeColor(HWND hwnd, COLORREF *which)
\r
6379 static BOOL firstTime = TRUE;
\r
6380 static DWORD customColors[16];
\r
6382 COLORREF newcolor;
\r
6387 /* Make initial colors in use available as custom colors */
\r
6388 /* Should we put the compiled-in defaults here instead? */
\r
6390 customColors[i++] = lightSquareColor & 0xffffff;
\r
6391 customColors[i++] = darkSquareColor & 0xffffff;
\r
6392 customColors[i++] = whitePieceColor & 0xffffff;
\r
6393 customColors[i++] = blackPieceColor & 0xffffff;
\r
6394 customColors[i++] = highlightSquareColor & 0xffffff;
\r
6395 customColors[i++] = premoveHighlightColor & 0xffffff;
\r
6397 for (ccl = (ColorClass) 0; ccl < NColorClasses && i < 16; ccl++) {
\r
6398 customColors[i++] = textAttribs[ccl].color;
\r
6400 while (i < 16) customColors[i++] = RGB(255, 255, 255);
\r
6401 firstTime = FALSE;
\r
6404 cc.lStructSize = sizeof(cc);
\r
6405 cc.hwndOwner = hwnd;
\r
6406 cc.hInstance = NULL;
\r
6407 cc.rgbResult = (DWORD) (*which & 0xffffff);
\r
6408 cc.lpCustColors = (LPDWORD) customColors;
\r
6409 cc.Flags = CC_RGBINIT|CC_FULLOPEN;
\r
6411 if (!ChooseColor(&cc)) return FALSE;
\r
6413 newcolor = (COLORREF) (0x2000000 | cc.rgbResult);
\r
6414 if (newcolor == *which) return FALSE;
\r
6415 *which = newcolor;
\r
6419 InitDrawingColors();
\r
6420 InvalidateRect(hwnd, &boardRect, FALSE);
\r
6425 MyLoadSound(MySound *ms)
\r
6431 if (ms->data) free(ms->data);
\r
6434 switch (ms->name[0]) {
\r
6440 /* System sound from Control Panel. Don't preload here. */
\r
6444 if (ms->name[1] == NULLCHAR) {
\r
6445 /* "!" alone = silence */
\r
6448 /* Builtin wave resource. Error if not found. */
\r
6449 HANDLE h = FindResource(hInst, ms->name + 1, "WAVE");
\r
6450 if (h == NULL) break;
\r
6451 ms->data = (void *)LoadResource(hInst, h);
\r
6452 if (h == NULL) break;
\r
6457 /* .wav file. Error if not found. */
\r
6458 f = fopen(ms->name, "rb");
\r
6459 if (f == NULL) break;
\r
6460 if (fstat(fileno(f), &st) < 0) break;
\r
6461 ms->data = malloc(st.st_size);
\r
6462 if (fread(ms->data, st.st_size, 1, f) < 1) break;
\r
6468 char buf[MSG_SIZ];
\r
6469 sprintf(buf, "Error loading sound %s", ms->name);
\r
6470 DisplayError(buf, GetLastError());
\r
6476 MyPlaySound(MySound *ms)
\r
6478 BOOLEAN ok = FALSE;
\r
6479 switch (ms->name[0]) {
\r
6485 /* System sound from Control Panel (deprecated feature).
\r
6486 "$" alone or an unset sound name gets default beep (still in use). */
\r
6487 if (ms->name[1]) {
\r
6488 ok = PlaySound(ms->name + 1, NULL, SND_ALIAS|SND_ASYNC);
\r
6490 if (!ok) ok = MessageBeep(MB_OK);
\r
6493 /* Builtin wave resource, or "!" alone for silence */
\r
6494 if (ms->name[1]) {
\r
6495 if (ms->data == NULL) return FALSE;
\r
6496 ok = PlaySound(ms->data, NULL, SND_MEMORY|SND_ASYNC);
\r
6502 /* .wav file. Error if not found. */
\r
6503 if (ms->data == NULL) return FALSE;
\r
6504 ok = PlaySound(ms->data, NULL, SND_MEMORY|SND_ASYNC);
\r
6507 /* Don't print an error: this can happen innocently if the sound driver
\r
6508 is busy; for instance, if another instance of WinBoard is playing
\r
6509 a sound at about the same time. */
\r
6512 char buf[MSG_SIZ];
\r
6513 sprintf(buf, "Error playing sound %s", ms->name);
\r
6514 DisplayError(buf, GetLastError());
\r
6522 OldOpenFileHook(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
6525 OPENFILENAME *ofn;
\r
6526 static UINT *number; /* gross that this is static */
\r
6528 switch (message) {
\r
6529 case WM_INITDIALOG: /* message: initialize dialog box */
\r
6530 /* Center the dialog over the application window */
\r
6531 ofn = (OPENFILENAME *) lParam;
\r
6532 if (ofn->Flags & OFN_ENABLETEMPLATE) {
\r
6533 number = (UINT *) ofn->lCustData;
\r
6534 SendMessage(GetDlgItem(hDlg, edt2), WM_SETTEXT, 0, (LPARAM) "");
\r
6538 CenterWindow (hDlg, GetWindow (hDlg, GW_OWNER));
\r
6539 return FALSE; /* Allow for further processing */
\r
6542 if ((LOWORD(wParam) == IDOK) && (number != NULL)) {
\r
6543 *number = GetDlgItemInt(hDlg, OPT_IndexNumberOld, &ok, FALSE);
\r
6545 return FALSE; /* Allow for further processing */
\r
6551 OpenFileHook(HWND hdlg, UINT uiMsg, WPARAM wParam, LPARAM lParam)
\r
6553 static UINT *number;
\r
6554 OPENFILENAME *ofname;
\r
6557 case WM_INITDIALOG:
\r
6558 ofname = (OPENFILENAME *)lParam;
\r
6559 number = (UINT *)(ofname->lCustData);
\r
6562 ofnot = (OFNOTIFY *)lParam;
\r
6563 if (ofnot->hdr.code == CDN_FILEOK) {
\r
6564 *number = GetDlgItemInt(hdlg, OPT_IndexNumber, NULL, FALSE);
\r
6573 OpenFileDialog(HWND hwnd, char *write, char *defName, char *defExt, // [HGM] diag: type of 'write' now string
\r
6574 char *nameFilt, char *dlgTitle, UINT *number,
\r
6575 char fileTitle[MSG_SIZ], char fileName[MSG_SIZ])
\r
6577 OPENFILENAME openFileName;
\r
6578 char buf1[MSG_SIZ];
\r
6581 if (fileName == NULL) fileName = buf1;
\r
6582 if (defName == NULL) {
\r
6583 strcpy(fileName, "*.");
\r
6584 strcat(fileName, defExt);
\r
6586 strcpy(fileName, defName);
\r
6588 if (fileTitle) strcpy(fileTitle, "");
\r
6589 if (number) *number = 0;
\r
6591 openFileName.lStructSize = sizeof(OPENFILENAME);
\r
6592 openFileName.hwndOwner = hwnd;
\r
6593 openFileName.hInstance = (HANDLE) hInst;
\r
6594 openFileName.lpstrFilter = nameFilt;
\r
6595 openFileName.lpstrCustomFilter = (LPSTR) NULL;
\r
6596 openFileName.nMaxCustFilter = 0L;
\r
6597 openFileName.nFilterIndex = 1L;
\r
6598 openFileName.lpstrFile = fileName;
\r
6599 openFileName.nMaxFile = MSG_SIZ;
\r
6600 openFileName.lpstrFileTitle = fileTitle;
\r
6601 openFileName.nMaxFileTitle = fileTitle ? MSG_SIZ : 0;
\r
6602 openFileName.lpstrInitialDir = NULL;
\r
6603 openFileName.lpstrTitle = dlgTitle;
\r
6604 openFileName.Flags = OFN_PATHMUSTEXIST | OFN_HIDEREADONLY
\r
6605 | (write[0] != 'r' ? 0 : OFN_FILEMUSTEXIST)
\r
6606 | (number ? OFN_ENABLETEMPLATE | OFN_ENABLEHOOK: 0)
\r
6607 | (oldDialog ? 0 : OFN_EXPLORER);
\r
6608 openFileName.nFileOffset = 0;
\r
6609 openFileName.nFileExtension = 0;
\r
6610 openFileName.lpstrDefExt = defExt;
\r
6611 openFileName.lCustData = (LONG) number;
\r
6612 openFileName.lpfnHook = oldDialog ?
\r
6613 (LPOFNHOOKPROC) OldOpenFileHook : (LPOFNHOOKPROC) OpenFileHook;
\r
6614 openFileName.lpTemplateName = (LPSTR)(oldDialog ? 1536 : DLG_IndexNumber);
\r
6616 if (write[0] != 'r' ? GetSaveFileName(&openFileName) :
\r
6617 GetOpenFileName(&openFileName)) {
\r
6618 /* open the file */
\r
6619 f = fopen(openFileName.lpstrFile, write);
\r
6621 MessageBox(hwnd, "File open failed", NULL,
\r
6622 MB_OK|MB_ICONEXCLAMATION);
\r
6626 int err = CommDlgExtendedError();
\r
6627 if (err != 0) DisplayError("Internal error in file dialog box", err);
\r
6636 MenuPopup(HWND hwnd, POINT pt, HMENU hmenu, UINT def)
\r
6638 HMENU hmenuTrackPopup; /* floating pop-up menu */
\r
6641 * Get the first pop-up menu in the menu template. This is the
\r
6642 * menu that TrackPopupMenu displays.
\r
6644 hmenuTrackPopup = GetSubMenu(hmenu, 0);
\r
6646 SetMenuDefaultItem(hmenuTrackPopup, def, FALSE);
\r
6649 * TrackPopup uses screen coordinates, so convert the
\r
6650 * coordinates of the mouse click to screen coordinates.
\r
6652 ClientToScreen(hwnd, (LPPOINT) &pt);
\r
6654 /* Draw and track the floating pop-up menu. */
\r
6655 TrackPopupMenu(hmenuTrackPopup, TPM_CENTERALIGN | TPM_RIGHTBUTTON,
\r
6656 pt.x, pt.y, 0, hwnd, NULL);
\r
6658 /* Destroy the menu.*/
\r
6659 DestroyMenu(hmenu);
\r
6664 int sizeX, sizeY, newSizeX, newSizeY;
\r
6666 } ResizeEditPlusButtonsClosure;
\r
6669 ResizeEditPlusButtonsCallback(HWND hChild, LPARAM lparam)
\r
6671 ResizeEditPlusButtonsClosure *cl = (ResizeEditPlusButtonsClosure *)lparam;
\r
6675 if (hChild == cl->hText) return TRUE;
\r
6676 GetWindowRect(hChild, &rect); /* gives screen coords */
\r
6677 pt.x = rect.left + (cl->newSizeX - cl->sizeX)/2;
\r
6678 pt.y = rect.top + cl->newSizeY - cl->sizeY;
\r
6679 ScreenToClient(cl->hDlg, &pt);
\r
6680 cl->hdwp = DeferWindowPos(cl->hdwp, hChild, NULL,
\r
6681 pt.x, pt.y, rect.right - rect.left, rect.bottom - rect.top, SWP_NOZORDER);
\r
6685 /* Resize a dialog that has a (rich) edit field filling most of
\r
6686 the top, with a row of buttons below */
\r
6688 ResizeEditPlusButtons(HWND hDlg, HWND hText, int sizeX, int sizeY, int newSizeX, int newSizeY)
\r
6691 int newTextHeight, newTextWidth;
\r
6692 ResizeEditPlusButtonsClosure cl;
\r
6694 /*if (IsIconic(hDlg)) return;*/
\r
6695 if (newSizeX == sizeX && newSizeY == sizeY) return;
\r
6697 cl.hdwp = BeginDeferWindowPos(8);
\r
6699 GetWindowRect(hText, &rectText); /* gives screen coords */
\r
6700 newTextWidth = rectText.right - rectText.left + newSizeX - sizeX;
\r
6701 newTextHeight = rectText.bottom - rectText.top + newSizeY - sizeY;
\r
6702 if (newTextHeight < 0) {
\r
6703 newSizeY += -newTextHeight;
\r
6704 newTextHeight = 0;
\r
6706 cl.hdwp = DeferWindowPos(cl.hdwp, hText, NULL, 0, 0,
\r
6707 newTextWidth, newTextHeight, SWP_NOZORDER|SWP_NOMOVE);
\r
6713 cl.newSizeX = newSizeX;
\r
6714 cl.newSizeY = newSizeY;
\r
6715 EnumChildWindows(hDlg, ResizeEditPlusButtonsCallback, (LPARAM)&cl);
\r
6717 EndDeferWindowPos(cl.hdwp);
\r
6720 BOOL CenterWindowEx(HWND hwndChild, HWND hwndParent, int mode)
\r
6722 RECT rChild, rParent;
\r
6723 int wChild, hChild, wParent, hParent;
\r
6724 int wScreen, hScreen, xNew, yNew;
\r
6727 /* Get the Height and Width of the child window */
\r
6728 GetWindowRect (hwndChild, &rChild);
\r
6729 wChild = rChild.right - rChild.left;
\r
6730 hChild = rChild.bottom - rChild.top;
\r
6732 /* Get the Height and Width of the parent window */
\r
6733 GetWindowRect (hwndParent, &rParent);
\r
6734 wParent = rParent.right - rParent.left;
\r
6735 hParent = rParent.bottom - rParent.top;
\r
6737 /* Get the display limits */
\r
6738 hdc = GetDC (hwndChild);
\r
6739 wScreen = GetDeviceCaps (hdc, HORZRES);
\r
6740 hScreen = GetDeviceCaps (hdc, VERTRES);
\r
6741 ReleaseDC(hwndChild, hdc);
\r
6743 /* Calculate new X position, then adjust for screen */
\r
6744 xNew = rParent.left + ((wParent - wChild) /2);
\r
6747 } else if ((xNew+wChild) > wScreen) {
\r
6748 xNew = wScreen - wChild;
\r
6751 /* Calculate new Y position, then adjust for screen */
\r
6753 yNew = rParent.top + ((hParent - hChild) /2);
\r
6756 yNew = rParent.top + GetSystemMetrics( SM_CYCAPTION ) * 2 / 3;
\r
6761 } else if ((yNew+hChild) > hScreen) {
\r
6762 yNew = hScreen - hChild;
\r
6765 /* Set it, and return */
\r
6766 return SetWindowPos (hwndChild, NULL,
\r
6767 xNew, yNew, 0, 0, SWP_NOSIZE | SWP_NOZORDER);
\r
6770 /* Center one window over another */
\r
6771 BOOL CenterWindow (HWND hwndChild, HWND hwndParent)
\r
6773 return CenterWindowEx( hwndChild, hwndParent, 0 );
\r
6776 /*---------------------------------------------------------------------------*\
\r
6778 * Startup Dialog functions
\r
6780 \*---------------------------------------------------------------------------*/
\r
6782 InitComboStrings(HANDLE hwndCombo, char **cd)
\r
6784 SendMessage(hwndCombo, CB_RESETCONTENT, 0, 0);
\r
6786 while (*cd != NULL) {
\r
6787 SendMessage(hwndCombo, CB_ADDSTRING, 0, (LPARAM) *cd);
\r
6793 InitComboStringsFromOption(HANDLE hwndCombo, char *str)
\r
6795 char buf1[ARG_MAX];
\r
6798 if (str[0] == '@') {
\r
6799 FILE* f = fopen(str + 1, "r");
\r
6801 DisplayFatalError(str + 1, errno, 2);
\r
6804 len = fread(buf1, 1, sizeof(buf1)-1, f);
\r
6806 buf1[len] = NULLCHAR;
\r
6810 SendMessage(hwndCombo, CB_RESETCONTENT, 0, 0);
\r
6813 char buf[MSG_SIZ];
\r
6814 char *end = strchr(str, '\n');
\r
6815 if (end == NULL) return;
\r
6816 memcpy(buf, str, end - str);
\r
6817 buf[end - str] = NULLCHAR;
\r
6818 SendMessage(hwndCombo, CB_ADDSTRING, 0, (LPARAM) buf);
\r
6824 SetStartupDialogEnables(HWND hDlg)
\r
6826 EnableWindow(GetDlgItem(hDlg, OPT_ChessEngineName),
\r
6827 IsDlgButtonChecked(hDlg, OPT_ChessEngine) ||
\r
6828 (appData.zippyPlay && IsDlgButtonChecked(hDlg, OPT_ChessServer)));
\r
6829 EnableWindow(GetDlgItem(hDlg, OPT_SecondChessEngineName),
\r
6830 IsDlgButtonChecked(hDlg, OPT_ChessEngine));
\r
6831 EnableWindow(GetDlgItem(hDlg, OPT_ChessServerName),
\r
6832 IsDlgButtonChecked(hDlg, OPT_ChessServer));
\r
6833 EnableWindow(GetDlgItem(hDlg, OPT_AdditionalOptions),
\r
6834 IsDlgButtonChecked(hDlg, OPT_AnyAdditional));
\r
6835 EnableWindow(GetDlgItem(hDlg, IDOK),
\r
6836 IsDlgButtonChecked(hDlg, OPT_ChessEngine) ||
\r
6837 IsDlgButtonChecked(hDlg, OPT_ChessServer) ||
\r
6838 IsDlgButtonChecked(hDlg, OPT_View));
\r
6842 QuoteForFilename(char *filename)
\r
6844 int dquote, space;
\r
6845 dquote = strchr(filename, '"') != NULL;
\r
6846 space = strchr(filename, ' ') != NULL;
\r
6847 if (dquote || space) {
\r
6859 InitEngineBox(HWND hDlg, HWND hwndCombo, char* nthcp, char* nthd, char* nthdir, char *nthnames)
\r
6861 char buf[MSG_SIZ];
\r
6864 InitComboStringsFromOption(hwndCombo, nthnames);
\r
6865 q = QuoteForFilename(nthcp);
\r
6866 sprintf(buf, "%s%s%s", q, nthcp, q);
\r
6867 if (*nthdir != NULLCHAR) {
\r
6868 q = QuoteForFilename(nthdir);
\r
6869 sprintf(buf + strlen(buf), " /%s=%s%s%s", nthd, q, nthdir, q);
\r
6871 if (*nthcp == NULLCHAR) {
\r
6872 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) 0, (LPARAM) 0);
\r
6873 } else if (SendMessage(hwndCombo, CB_SELECTSTRING, (WPARAM) -1, (LPARAM) buf) == CB_ERR) {
\r
6874 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) -1, (LPARAM) 0);
\r
6875 SendMessage(hwndCombo, WM_SETTEXT, (WPARAM) 0, (LPARAM) buf);
\r
6880 StartupDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
6882 char buf[MSG_SIZ];
\r
6886 switch (message) {
\r
6887 case WM_INITDIALOG:
\r
6888 /* Center the dialog */
\r
6889 CenterWindow (hDlg, GetDesktopWindow());
\r
6890 /* Initialize the dialog items */
\r
6891 InitEngineBox(hDlg, GetDlgItem(hDlg, OPT_ChessEngineName),
\r
6892 appData.firstChessProgram, "fd", appData.firstDirectory,
\r
6893 firstChessProgramNames);
\r
6894 InitEngineBox(hDlg, GetDlgItem(hDlg, OPT_SecondChessEngineName),
\r
6895 appData.secondChessProgram, "sd", appData.secondDirectory,
\r
6896 secondChessProgramNames);
\r
6897 hwndCombo = GetDlgItem(hDlg, OPT_ChessServerName);
\r
6898 InitComboStringsFromOption(hwndCombo, icsNames);
\r
6899 sprintf(buf, "%s /icsport=%s", appData.icsHost, appData.icsPort);
\r
6900 if (*appData.icsHelper != NULLCHAR) {
\r
6901 char *q = QuoteForFilename(appData.icsHelper);
\r
6902 sprintf(buf + strlen(buf), " /icshelper=%s%s%s", q, appData.icsHelper, q);
\r
6904 if (*appData.icsHost == NULLCHAR) {
\r
6905 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) 0, (LPARAM) 0);
\r
6906 /*SendMessage(hwndCombo, CB_SHOWDROPDOWN, (WPARAM) TRUE, (LPARAM) 0); !!too soon */
\r
6907 } else if (SendMessage(hwndCombo, CB_SELECTSTRING, (WPARAM) -1, (LPARAM) buf) == CB_ERR) {
\r
6908 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) -1, (LPARAM) 0);
\r
6909 SendMessage(hwndCombo, WM_SETTEXT, (WPARAM) 0, (LPARAM) buf);
\r
6912 if (appData.icsActive) {
\r
6913 CheckDlgButton(hDlg, OPT_ChessServer, BST_CHECKED);
\r
6915 else if (appData.noChessProgram) {
\r
6916 CheckDlgButton(hDlg, OPT_View, BST_CHECKED);
\r
6919 CheckDlgButton(hDlg, OPT_ChessEngine, BST_CHECKED);
\r
6922 SetStartupDialogEnables(hDlg);
\r
6926 switch (LOWORD(wParam)) {
\r
6928 if (IsDlgButtonChecked(hDlg, OPT_ChessEngine)) {
\r
6929 strcpy(buf, "/fcp=");
\r
6930 GetDlgItemText(hDlg, OPT_ChessEngineName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
6932 ParseArgs(StringGet, &p);
\r
6933 strcpy(buf, "/scp=");
\r
6934 GetDlgItemText(hDlg, OPT_SecondChessEngineName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
6936 ParseArgs(StringGet, &p);
\r
6937 appData.noChessProgram = FALSE;
\r
6938 appData.icsActive = FALSE;
\r
6939 } else if (IsDlgButtonChecked(hDlg, OPT_ChessServer)) {
\r
6940 strcpy(buf, "/ics /icshost=");
\r
6941 GetDlgItemText(hDlg, OPT_ChessServerName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
6943 ParseArgs(StringGet, &p);
\r
6944 if (appData.zippyPlay) {
\r
6945 strcpy(buf, "/fcp=");
\r
6946 GetDlgItemText(hDlg, OPT_ChessEngineName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
6948 ParseArgs(StringGet, &p);
\r
6950 } else if (IsDlgButtonChecked(hDlg, OPT_View)) {
\r
6951 appData.noChessProgram = TRUE;
\r
6952 appData.icsActive = FALSE;
\r
6954 MessageBox(hDlg, "Choose an option, or cancel to exit",
\r
6955 "Option Error", MB_OK|MB_ICONEXCLAMATION);
\r
6958 if (IsDlgButtonChecked(hDlg, OPT_AnyAdditional)) {
\r
6959 GetDlgItemText(hDlg, OPT_AdditionalOptions, buf, sizeof(buf));
\r
6961 ParseArgs(StringGet, &p);
\r
6963 EndDialog(hDlg, TRUE);
\r
6970 case IDM_HELPCONTENTS:
\r
6971 if (!WinHelp (hDlg, "winboard.hlp", HELP_KEY,(DWORD)(LPSTR)"CONTENTS")) {
\r
6972 MessageBox (GetFocus(),
\r
6973 "Unable to activate help",
\r
6974 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
6979 SetStartupDialogEnables(hDlg);
\r
6987 /*---------------------------------------------------------------------------*\
\r
6989 * About box dialog functions
\r
6991 \*---------------------------------------------------------------------------*/
\r
6993 /* Process messages for "About" dialog box */
\r
6995 About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
6997 switch (message) {
\r
6998 case WM_INITDIALOG: /* message: initialize dialog box */
\r
6999 /* Center the dialog over the application window */
\r
7000 CenterWindow (hDlg, GetWindow (hDlg, GW_OWNER));
\r
7001 SetDlgItemText(hDlg, ABOUTBOX_Version, programVersion);
\r
7004 case WM_COMMAND: /* message: received a command */
\r
7005 if (LOWORD(wParam) == IDOK /* "OK" box selected? */
\r
7006 || LOWORD(wParam) == IDCANCEL) { /* System menu close command? */
\r
7007 EndDialog(hDlg, TRUE); /* Exit the dialog */
\r
7015 /*---------------------------------------------------------------------------*\
\r
7017 * Comment Dialog functions
\r
7019 \*---------------------------------------------------------------------------*/
\r
7022 CommentDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7024 static HANDLE hwndText = NULL;
\r
7025 int len, newSizeX, newSizeY, flags;
\r
7026 static int sizeX, sizeY;
\r
7031 switch (message) {
\r
7032 case WM_INITDIALOG: /* message: initialize dialog box */
\r
7033 /* Initialize the dialog items */
\r
7034 hwndText = GetDlgItem(hDlg, OPT_CommentText);
\r
7035 SetDlgItemText(hDlg, OPT_CommentText, commentText);
\r
7036 EnableWindow(GetDlgItem(hDlg, OPT_CancelComment), editComment);
\r
7037 EnableWindow(GetDlgItem(hDlg, OPT_ClearComment), editComment);
\r
7038 EnableWindow(GetDlgItem(hDlg, OPT_EditComment), !editComment);
\r
7039 SendMessage(hwndText, EM_SETREADONLY, !editComment, 0);
\r
7040 SetWindowText(hDlg, commentTitle);
\r
7041 if (editComment) {
\r
7042 SetFocus(hwndText);
\r
7044 SetFocus(GetDlgItem(hDlg, IDOK));
\r
7046 SendMessage(GetDlgItem(hDlg, OPT_CommentText),
\r
7047 WM_SETFONT, (WPARAM)font[boardSize][COMMENT_FONT]->hf,
\r
7048 MAKELPARAM(FALSE, 0));
\r
7049 /* Size and position the dialog */
\r
7050 if (!commentDialog) {
\r
7051 commentDialog = hDlg;
\r
7052 flags = SWP_NOZORDER;
\r
7053 GetClientRect(hDlg, &rect);
\r
7054 sizeX = rect.right;
\r
7055 sizeY = rect.bottom;
\r
7056 if (commentX != CW_USEDEFAULT && commentY != CW_USEDEFAULT &&
\r
7057 commentW != CW_USEDEFAULT && commentH != CW_USEDEFAULT) {
\r
7058 WINDOWPLACEMENT wp;
\r
7059 EnsureOnScreen(&commentX, &commentY);
\r
7060 wp.length = sizeof(WINDOWPLACEMENT);
\r
7062 wp.showCmd = SW_SHOW;
\r
7063 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
7064 wp.rcNormalPosition.left = commentX;
\r
7065 wp.rcNormalPosition.right = commentX + commentW;
\r
7066 wp.rcNormalPosition.top = commentY;
\r
7067 wp.rcNormalPosition.bottom = commentY + commentH;
\r
7068 SetWindowPlacement(hDlg, &wp);
\r
7070 GetClientRect(hDlg, &rect);
\r
7071 newSizeX = rect.right;
\r
7072 newSizeY = rect.bottom;
\r
7073 ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY,
\r
7074 newSizeX, newSizeY);
\r
7081 case WM_COMMAND: /* message: received a command */
\r
7082 switch (LOWORD(wParam)) {
\r
7084 if (editComment) {
\r
7086 /* Read changed options from the dialog box */
\r
7087 hwndText = GetDlgItem(hDlg, OPT_CommentText);
\r
7088 len = GetWindowTextLength(hwndText);
\r
7089 str = (char *) malloc(len + 1);
\r
7090 GetWindowText(hwndText, str, len + 1);
\r
7099 ReplaceComment(commentIndex, str);
\r
7106 case OPT_CancelComment:
\r
7110 case OPT_ClearComment:
\r
7111 SetDlgItemText(hDlg, OPT_CommentText, "");
\r
7114 case OPT_EditComment:
\r
7115 EditCommentEvent();
\r
7124 newSizeX = LOWORD(lParam);
\r
7125 newSizeY = HIWORD(lParam);
\r
7126 ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY, newSizeX, newSizeY);
\r
7131 case WM_GETMINMAXINFO:
\r
7132 /* Prevent resizing window too small */
\r
7133 mmi = (MINMAXINFO *) lParam;
\r
7134 mmi->ptMinTrackSize.x = 100;
\r
7135 mmi->ptMinTrackSize.y = 100;
\r
7142 EitherCommentPopUp(int index, char *title, char *str, BOOLEAN edit)
\r
7147 CheckMenuItem(GetMenu(hwndMain), IDM_EditComment, edit ? MF_CHECKED : MF_UNCHECKED);
\r
7149 if (str == NULL) str = "";
\r
7150 p = (char *) malloc(2 * strlen(str) + 2);
\r
7153 if (*str == '\n') *q++ = '\r';
\r
7157 if (commentText != NULL) free(commentText);
\r
7159 commentIndex = index;
\r
7160 commentTitle = title;
\r
7162 editComment = edit;
\r
7164 if (commentDialog) {
\r
7165 SendMessage(commentDialog, WM_INITDIALOG, 0, 0);
\r
7166 if (!commentDialogUp) ShowWindow(commentDialog, SW_SHOW);
\r
7168 lpProc = MakeProcInstance((FARPROC)CommentDialog, hInst);
\r
7169 CreateDialog(hInst, MAKEINTRESOURCE(DLG_EditComment),
\r
7170 hwndMain, (DLGPROC)lpProc);
\r
7171 FreeProcInstance(lpProc);
\r
7173 commentDialogUp = TRUE;
\r
7177 /*---------------------------------------------------------------------------*\
\r
7179 * Type-in move dialog functions
\r
7181 \*---------------------------------------------------------------------------*/
\r
7184 TypeInMoveDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7186 char move[MSG_SIZ];
\r
7188 ChessMove moveType;
\r
7189 int fromX, fromY, toX, toY;
\r
7192 switch (message) {
\r
7193 case WM_INITDIALOG:
\r
7194 move[0] = (char) lParam;
\r
7195 move[1] = NULLCHAR;
\r
7196 CenterWindowEx(hDlg, GetWindow(hDlg, GW_OWNER), 1 );
\r
7197 hInput = GetDlgItem(hDlg, OPT_Move);
\r
7198 SetWindowText(hInput, move);
\r
7200 SendMessage(hInput, EM_SETSEL, (WPARAM)9999, (LPARAM)9999);
\r
7204 switch (LOWORD(wParam)) {
\r
7206 if (gameMode != EditGame && currentMove != forwardMostMove &&
\r
7207 gameMode != Training) {
\r
7208 DisplayMoveError("Displayed move is not current");
\r
7210 GetDlgItemText(hDlg, OPT_Move, move, sizeof(move));
\r
7211 if (ParseOneMove(move, gameMode == EditPosition ? blackPlaysFirst : currentMove,
\r
7212 &moveType, &fromX, &fromY, &toX, &toY, &promoChar)) {
\r
7213 if (gameMode != Training)
\r
7214 forwardMostMove = currentMove;
\r
7215 UserMoveEvent(fromX, fromY, toX, toY, promoChar);
\r
7217 DisplayMoveError("Could not parse move");
\r
7220 EndDialog(hDlg, TRUE);
\r
7223 EndDialog(hDlg, FALSE);
\r
7234 PopUpMoveDialog(char firstchar)
\r
7238 if ((gameMode == BeginningOfGame && !appData.icsActive) ||
\r
7239 gameMode == MachinePlaysWhite || gameMode == MachinePlaysBlack ||
\r
7240 gameMode == AnalyzeMode || gameMode == EditGame ||
\r
7241 gameMode == EditPosition || gameMode == IcsExamining ||
\r
7242 gameMode == IcsPlayingWhite || gameMode == IcsPlayingBlack ||
\r
7243 gameMode == Training) {
\r
7244 lpProc = MakeProcInstance((FARPROC)TypeInMoveDialog, hInst);
\r
7245 DialogBoxParam(hInst, MAKEINTRESOURCE(DLG_TypeInMove),
\r
7246 hwndMain, (DLGPROC)lpProc, (LPARAM)firstchar);
\r
7247 FreeProcInstance(lpProc);
\r
7251 /*---------------------------------------------------------------------------*\
\r
7253 * Type-in name dialog functions
\r
7255 \*---------------------------------------------------------------------------*/
\r
7258 TypeInNameDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7260 char move[MSG_SIZ];
\r
7263 switch (message) {
\r
7264 case WM_INITDIALOG:
\r
7265 move[0] = (char) lParam;
\r
7266 move[1] = NULLCHAR;
\r
7267 CenterWindowEx(hDlg, GetWindow(hDlg, GW_OWNER), 1 );
\r
7268 hInput = GetDlgItem(hDlg, OPT_Name);
\r
7269 SetWindowText(hInput, move);
\r
7271 SendMessage(hInput, EM_SETSEL, (WPARAM)9999, (LPARAM)9999);
\r
7275 switch (LOWORD(wParam)) {
\r
7277 GetDlgItemText(hDlg, OPT_Name, move, sizeof(move));
\r
7278 appData.userName = strdup(move);
\r
7280 EndDialog(hDlg, TRUE);
\r
7283 EndDialog(hDlg, FALSE);
\r
7294 PopUpNameDialog(char firstchar)
\r
7298 lpProc = MakeProcInstance((FARPROC)TypeInNameDialog, hInst);
\r
7299 DialogBoxParam(hInst, MAKEINTRESOURCE(DLG_TypeInName),
\r
7300 hwndMain, (DLGPROC)lpProc, (LPARAM)firstchar);
\r
7301 FreeProcInstance(lpProc);
\r
7304 /*---------------------------------------------------------------------------*\
\r
7308 \*---------------------------------------------------------------------------*/
\r
7310 /* Nonmodal error box */
\r
7311 LRESULT CALLBACK ErrorDialog(HWND hDlg, UINT message,
\r
7312 WPARAM wParam, LPARAM lParam);
\r
7315 ErrorPopUp(char *title, char *content)
\r
7319 BOOLEAN modal = hwndMain == NULL;
\r
7337 strncpy(errorTitle, title, sizeof(errorTitle));
\r
7338 errorTitle[sizeof(errorTitle) - 1] = '\0';
\r
7341 MessageBox(NULL, errorMessage, errorTitle, MB_OK|MB_ICONEXCLAMATION);
\r
7343 lpProc = MakeProcInstance((FARPROC)ErrorDialog, hInst);
\r
7344 CreateDialog(hInst, MAKEINTRESOURCE(DLG_Error),
\r
7345 hwndMain, (DLGPROC)lpProc);
\r
7346 FreeProcInstance(lpProc);
\r
7353 if (!appData.popupMoveErrors && moveErrorMessageUp) DisplayMessage("", "");
\r
7354 if (errorDialog == NULL) return;
\r
7355 DestroyWindow(errorDialog);
\r
7356 errorDialog = NULL;
\r
7360 ErrorDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7365 switch (message) {
\r
7366 case WM_INITDIALOG:
\r
7367 GetWindowRect(hDlg, &rChild);
\r
7370 SetWindowPos(hDlg, NULL, rChild.left,
\r
7371 rChild.top + boardRect.top - (rChild.bottom - rChild.top),
\r
7372 0, 0, SWP_NOZORDER|SWP_NOSIZE);
\r
7376 [AS] It seems that the above code wants to move the dialog up in the "caption
\r
7377 area" of the main window, but it uses the dialog height as an hard-coded constant,
\r
7378 and it doesn't work when you resize the dialog.
\r
7379 For now, just give it a default position.
\r
7381 SetWindowPos(hDlg, NULL, boardRect.left+8, boardRect.top+8, 0, 0, SWP_NOZORDER|SWP_NOSIZE);
\r
7383 errorDialog = hDlg;
\r
7384 SetWindowText(hDlg, errorTitle);
\r
7385 hwndText = GetDlgItem(hDlg, OPT_ErrorText);
\r
7386 SetDlgItemText(hDlg, OPT_ErrorText, errorMessage);
\r
7390 switch (LOWORD(wParam)) {
\r
7393 if (errorDialog == hDlg) errorDialog = NULL;
\r
7394 DestroyWindow(hDlg);
\r
7406 HWND gothicDialog = NULL;
\r
7409 GothicDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7413 int height = GetSystemMetrics(SM_CYCAPTION)+GetSystemMetrics(SM_CYFRAME);
\r
7415 switch (message) {
\r
7416 case WM_INITDIALOG:
\r
7417 GetWindowRect(hDlg, &rChild);
\r
7419 SetWindowPos(hDlg, NULL, boardX, boardY-height, winWidth, height,
\r
7423 [AS] It seems that the above code wants to move the dialog up in the "caption
\r
7424 area" of the main window, but it uses the dialog height as an hard-coded constant,
\r
7425 and it doesn't work when you resize the dialog.
\r
7426 For now, just give it a default position.
\r
7428 gothicDialog = hDlg;
\r
7429 SetWindowText(hDlg, errorTitle);
\r
7430 hwndText = GetDlgItem(hDlg, OPT_ErrorText);
\r
7431 SetDlgItemText(hDlg, OPT_ErrorText, errorMessage);
\r
7435 switch (LOWORD(wParam)) {
\r
7438 if (errorDialog == hDlg) errorDialog = NULL;
\r
7439 DestroyWindow(hDlg);
\r
7451 GothicPopUp(char *title, VariantClass variant)
\r
7454 static char *lastTitle;
\r
7456 strncpy(errorTitle, title, sizeof(errorTitle));
\r
7457 errorTitle[sizeof(errorTitle) - 1] = '\0';
\r
7459 if(lastTitle != title && gothicDialog != NULL) {
\r
7460 DestroyWindow(gothicDialog);
\r
7461 gothicDialog = NULL;
\r
7463 if(variant != VariantNormal && gothicDialog == NULL) {
\r
7464 title = lastTitle;
\r
7465 lpProc = MakeProcInstance((FARPROC)GothicDialog, hInst);
\r
7466 CreateDialog(hInst, MAKEINTRESOURCE(DLG_Error),
\r
7467 hwndMain, (DLGPROC)lpProc);
\r
7468 FreeProcInstance(lpProc);
\r
7473 /*---------------------------------------------------------------------------*\
\r
7475 * Ics Interaction console functions
\r
7477 \*---------------------------------------------------------------------------*/
\r
7479 #define HISTORY_SIZE 64
\r
7480 static char *history[HISTORY_SIZE];
\r
7481 int histIn = 0, histP = 0;
\r
7484 SaveInHistory(char *cmd)
\r
7486 if (history[histIn] != NULL) {
\r
7487 free(history[histIn]);
\r
7488 history[histIn] = NULL;
\r
7490 if (*cmd == NULLCHAR) return;
\r
7491 history[histIn] = StrSave(cmd);
\r
7492 histIn = (histIn + 1) % HISTORY_SIZE;
\r
7493 if (history[histIn] != NULL) {
\r
7494 free(history[histIn]);
\r
7495 history[histIn] = NULL;
\r
7501 PrevInHistory(char *cmd)
\r
7504 if (histP == histIn) {
\r
7505 if (history[histIn] != NULL) free(history[histIn]);
\r
7506 history[histIn] = StrSave(cmd);
\r
7508 newhp = (histP - 1 + HISTORY_SIZE) % HISTORY_SIZE;
\r
7509 if (newhp == histIn || history[newhp] == NULL) return NULL;
\r
7511 return history[histP];
\r
7517 if (histP == histIn) return NULL;
\r
7518 histP = (histP + 1) % HISTORY_SIZE;
\r
7519 return history[histP];
\r
7526 BOOLEAN immediate;
\r
7527 } IcsTextMenuEntry;
\r
7528 #define ICS_TEXT_MENU_SIZE (IDM_CommandXLast - IDM_CommandX + 1)
\r
7529 IcsTextMenuEntry icsTextMenuEntry[ICS_TEXT_MENU_SIZE];
\r
7532 ParseIcsTextMenu(char *icsTextMenuString)
\r
7535 IcsTextMenuEntry *e = icsTextMenuEntry;
\r
7536 char *p = icsTextMenuString;
\r
7537 while (e->item != NULL && e < icsTextMenuEntry + ICS_TEXT_MENU_SIZE) {
\r
7540 if (e->command != NULL) {
\r
7542 e->command = NULL;
\r
7546 e = icsTextMenuEntry;
\r
7547 while (*p && e < icsTextMenuEntry + ICS_TEXT_MENU_SIZE) {
\r
7548 if (*p == ';' || *p == '\n') {
\r
7549 e->item = strdup("-");
\r
7550 e->command = NULL;
\r
7552 } else if (*p == '-') {
\r
7553 e->item = strdup("-");
\r
7554 e->command = NULL;
\r
7558 char *q, *r, *s, *t;
\r
7560 q = strchr(p, ',');
\r
7561 if (q == NULL) break;
\r
7563 r = strchr(q + 1, ',');
\r
7564 if (r == NULL) break;
\r
7566 s = strchr(r + 1, ',');
\r
7567 if (s == NULL) break;
\r
7570 t = strchr(s + 1, c);
\r
7573 t = strchr(s + 1, c);
\r
7575 if (t != NULL) *t = NULLCHAR;
\r
7576 e->item = strdup(p);
\r
7577 e->command = strdup(q + 1);
\r
7578 e->getname = *(r + 1) != '0';
\r
7579 e->immediate = *(s + 1) != '0';
\r
7583 if (t == NULL) break;
\r
7592 LoadIcsTextMenu(IcsTextMenuEntry *e)
\r
7596 hmenu = LoadMenu(hInst, "TextMenu");
\r
7597 h = GetSubMenu(hmenu, 0);
\r
7599 if (strcmp(e->item, "-") == 0) {
\r
7600 AppendMenu(h, MF_SEPARATOR, 0, 0);
\r
7602 if (e->item[0] == '|') {
\r
7603 AppendMenu(h, MF_STRING|MF_MENUBARBREAK,
\r
7604 IDM_CommandX + i, &e->item[1]);
\r
7606 AppendMenu(h, MF_STRING, IDM_CommandX + i, e->item);
\r
7615 WNDPROC consoleTextWindowProc;
\r
7618 CommandX(HWND hwnd, char *command, BOOLEAN getname, BOOLEAN immediate)
\r
7620 char buf[MSG_SIZ], name[MSG_SIZ];
\r
7621 HWND hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
7625 SetWindowText(hInput, command);
\r
7627 SendMessage(hInput, WM_CHAR, '\r', 0);
\r
7629 sel.cpMin = 999999;
\r
7630 sel.cpMax = 999999;
\r
7631 SendMessage(hInput, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7636 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
7637 if (sel.cpMin == sel.cpMax) {
\r
7638 /* Expand to surrounding word */
\r
7641 tr.chrg.cpMax = sel.cpMin;
\r
7642 tr.chrg.cpMin = --sel.cpMin;
\r
7643 if (sel.cpMin < 0) break;
\r
7644 tr.lpstrText = name;
\r
7645 SendMessage(hwnd, EM_GETTEXTRANGE, 0, (LPARAM) &tr);
\r
7646 } while (isalpha(name[0]) || isdigit(name[0]) || name[0] == '-');
\r
7650 tr.chrg.cpMin = sel.cpMax;
\r
7651 tr.chrg.cpMax = ++sel.cpMax;
\r
7652 tr.lpstrText = name;
\r
7653 if (SendMessage(hwnd, EM_GETTEXTRANGE, 0, (LPARAM) &tr) < 1) break;
\r
7654 } while (isalpha(name[0]) || isdigit(name[0]) || name[0] == '-');
\r
7657 if (sel.cpMax == sel.cpMin || sel.cpMax - sel.cpMin > MSG_SIZ/2) {
\r
7658 MessageBeep(MB_ICONEXCLAMATION);
\r
7662 tr.lpstrText = name;
\r
7663 SendMessage(hwnd, EM_GETTEXTRANGE, 0, (LPARAM) &tr);
\r
7665 if (sel.cpMax - sel.cpMin > MSG_SIZ/2) {
\r
7666 MessageBeep(MB_ICONEXCLAMATION);
\r
7669 SendMessage(hwnd, EM_GETSELTEXT, 0, (LPARAM) name);
\r
7672 sprintf(buf, "%s %s", command, name);
\r
7673 SetWindowText(hInput, buf);
\r
7674 SendMessage(hInput, WM_CHAR, '\r', 0);
\r
7676 sprintf(buf, "%s %s ", command, name); /* trailing space */
\r
7677 SetWindowText(hInput, buf);
\r
7678 sel.cpMin = 999999;
\r
7679 sel.cpMax = 999999;
\r
7680 SendMessage(hInput, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7686 ConsoleTextSubclass(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
7691 switch (message) {
\r
7693 if (!(GetKeyState(VK_CONTROL) & ~1)) break;
\r
7696 SendMessage(hwnd, EM_LINESCROLL, 0, -999999);
\r
7699 sel.cpMin = 999999;
\r
7700 sel.cpMax = 999999;
\r
7701 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7702 SendMessage(hwnd, EM_SCROLLCARET, 0, 0);
\r
7707 if (wParam == '\t') {
\r
7708 if (GetKeyState(VK_SHIFT) < 0) {
\r
7710 if (IsIconic(hwndMain)) ShowWindow(hwndMain, SW_RESTORE);
\r
7711 if (buttonDesc[0].hwnd) {
\r
7712 SetFocus(buttonDesc[0].hwnd);
\r
7714 SetFocus(hwndMain);
\r
7718 SetFocus(GetDlgItem(hwndConsole, OPT_ConsoleInput));
\r
7721 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
7723 SendMessage(hInput, message, wParam, lParam);
\r
7727 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
7729 return SendMessage(hInput, message, wParam, lParam);
\r
7730 case WM_MBUTTONDOWN:
\r
7731 return SendMessage(hwnd, WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
7732 case WM_RBUTTONDOWN:
\r
7733 if (!(GetKeyState(VK_SHIFT) & ~1)) {
\r
7734 /* Move selection here if it was empty */
\r
7736 pt.x = LOWORD(lParam);
\r
7737 pt.y = HIWORD(lParam);
\r
7738 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
7739 if (sel.cpMin == sel.cpMax) {
\r
7740 sel.cpMin = SendMessage(hwnd, EM_CHARFROMPOS, 0, (LPARAM)&pt); /*doc is wrong*/
\r
7741 sel.cpMax = sel.cpMin;
\r
7742 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7744 SendMessage(hwnd, EM_HIDESELECTION, FALSE, FALSE);
\r
7747 case WM_RBUTTONUP:
\r
7748 if (GetKeyState(VK_SHIFT) & ~1) {
\r
7749 SendDlgItemMessage(hwndConsole, OPT_ConsoleText,
\r
7750 WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
7753 HMENU hmenu = LoadIcsTextMenu(icsTextMenuEntry);
\r
7754 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
7755 if (sel.cpMin == sel.cpMax) {
\r
7756 EnableMenuItem(hmenu, IDM_Copy, MF_BYCOMMAND|MF_GRAYED);
\r
7757 EnableMenuItem(hmenu, IDM_QuickPaste, MF_BYCOMMAND|MF_GRAYED);
\r
7759 if (!IsClipboardFormatAvailable(CF_TEXT)) {
\r
7760 EnableMenuItem(hmenu, IDM_Paste, MF_BYCOMMAND|MF_GRAYED);
\r
7762 pt.x = LOWORD(lParam);
\r
7763 pt.y = HIWORD(lParam);
\r
7764 MenuPopup(hwnd, pt, hmenu, -1);
\r
7768 switch (LOWORD(wParam)) {
\r
7769 case IDM_QuickPaste:
\r
7771 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
7772 if (sel.cpMin == sel.cpMax) {
\r
7773 MessageBeep(MB_ICONEXCLAMATION);
\r
7776 SendMessage(hwnd, WM_COPY, 0, 0);
\r
7777 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
7778 SendMessage(hInput, WM_PASTE, 0, 0);
\r
7783 SendMessage(hwnd, WM_CUT, 0, 0);
\r
7786 SendMessage(hwnd, WM_PASTE, 0, 0);
\r
7789 SendMessage(hwnd, WM_COPY, 0, 0);
\r
7793 int i = LOWORD(wParam) - IDM_CommandX;
\r
7794 if (i >= 0 && i < ICS_TEXT_MENU_SIZE &&
\r
7795 icsTextMenuEntry[i].command != NULL) {
\r
7796 CommandX(hwnd, icsTextMenuEntry[i].command,
\r
7797 icsTextMenuEntry[i].getname,
\r
7798 icsTextMenuEntry[i].immediate);
\r
7806 return (*consoleTextWindowProc)(hwnd, message, wParam, lParam);
\r
7809 WNDPROC consoleInputWindowProc;
\r
7812 ConsoleInputSubclass(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
7814 char buf[MSG_SIZ];
\r
7816 static BOOL sendNextChar = FALSE;
\r
7817 static BOOL quoteNextChar = FALSE;
\r
7818 InputSource *is = consoleInputSource;
\r
7822 switch (message) {
\r
7824 if (!appData.localLineEditing || sendNextChar) {
\r
7825 is->buf[0] = (CHAR) wParam;
\r
7827 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
7828 sendNextChar = FALSE;
\r
7831 if (quoteNextChar) {
\r
7832 buf[0] = (char) wParam;
\r
7833 buf[1] = NULLCHAR;
\r
7834 SendMessage(hwnd, EM_REPLACESEL, TRUE, (LPARAM) buf);
\r
7835 quoteNextChar = FALSE;
\r
7839 case '\r': /* Enter key */
\r
7840 is->count = GetWindowText(hwnd, is->buf, INPUT_SOURCE_BUF_SIZE-1);
\r
7841 if (consoleEcho) SaveInHistory(is->buf);
\r
7842 is->buf[is->count++] = '\n';
\r
7843 is->buf[is->count] = NULLCHAR;
\r
7844 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
7845 if (consoleEcho) {
\r
7846 ConsoleOutput(is->buf, is->count, TRUE);
\r
7847 } else if (appData.localLineEditing) {
\r
7848 ConsoleOutput("\n", 1, TRUE);
\r
7851 case '\033': /* Escape key */
\r
7852 SetWindowText(hwnd, "");
\r
7853 cf.cbSize = sizeof(CHARFORMAT);
\r
7854 cf.dwMask = CFM_COLOR|CFM_BOLD|CFM_ITALIC|CFM_UNDERLINE|CFM_STRIKEOUT;
\r
7855 if (consoleEcho) {
\r
7856 cf.crTextColor = textAttribs[ColorNormal].color;
\r
7858 cf.crTextColor = COLOR_ECHOOFF;
\r
7860 cf.dwEffects = textAttribs[ColorNormal].effects;
\r
7861 SendMessage(hwnd, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&cf);
\r
7863 case '\t': /* Tab key */
\r
7864 if (GetKeyState(VK_SHIFT) < 0) {
\r
7866 SetFocus(GetDlgItem(hwndConsole, OPT_ConsoleText));
\r
7869 if (IsIconic(hwndMain)) ShowWindow(hwndMain, SW_RESTORE);
\r
7870 if (buttonDesc[0].hwnd) {
\r
7871 SetFocus(buttonDesc[0].hwnd);
\r
7873 SetFocus(hwndMain);
\r
7877 case '\023': /* Ctrl+S */
\r
7878 sendNextChar = TRUE;
\r
7880 case '\021': /* Ctrl+Q */
\r
7881 quoteNextChar = TRUE;
\r
7890 GetWindowText(hwnd, buf, MSG_SIZ);
\r
7891 p = PrevInHistory(buf);
\r
7893 SetWindowText(hwnd, p);
\r
7894 sel.cpMin = 999999;
\r
7895 sel.cpMax = 999999;
\r
7896 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7901 p = NextInHistory();
\r
7903 SetWindowText(hwnd, p);
\r
7904 sel.cpMin = 999999;
\r
7905 sel.cpMax = 999999;
\r
7906 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7912 if (!(GetKeyState(VK_CONTROL) & ~1)) break;
\r
7916 SendDlgItemMessage(hwndConsole, OPT_ConsoleText, message, wParam, lParam);
\r
7920 case WM_MBUTTONDOWN:
\r
7921 SendDlgItemMessage(hwndConsole, OPT_ConsoleText,
\r
7922 WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
7924 case WM_RBUTTONUP:
\r
7925 if (GetKeyState(VK_SHIFT) & ~1) {
\r
7926 SendDlgItemMessage(hwndConsole, OPT_ConsoleText,
\r
7927 WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
7931 hmenu = LoadMenu(hInst, "InputMenu");
\r
7932 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
7933 if (sel.cpMin == sel.cpMax) {
\r
7934 EnableMenuItem(hmenu, IDM_Copy, MF_BYCOMMAND|MF_GRAYED);
\r
7935 EnableMenuItem(hmenu, IDM_Cut, MF_BYCOMMAND|MF_GRAYED);
\r
7937 if (!IsClipboardFormatAvailable(CF_TEXT)) {
\r
7938 EnableMenuItem(hmenu, IDM_Paste, MF_BYCOMMAND|MF_GRAYED);
\r
7940 pt.x = LOWORD(lParam);
\r
7941 pt.y = HIWORD(lParam);
\r
7942 MenuPopup(hwnd, pt, hmenu, -1);
\r
7946 switch (LOWORD(wParam)) {
\r
7948 SendMessage(hwnd, EM_UNDO, 0, 0);
\r
7950 case IDM_SelectAll:
\r
7952 sel.cpMax = -1; /*999999?*/
\r
7953 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7956 SendMessage(hwnd, WM_CUT, 0, 0);
\r
7959 SendMessage(hwnd, WM_PASTE, 0, 0);
\r
7962 SendMessage(hwnd, WM_COPY, 0, 0);
\r
7967 return (*consoleInputWindowProc)(hwnd, message, wParam, lParam);
\r
7970 #define CO_MAX 100000
\r
7971 #define CO_TRIM 1000
\r
7974 ConsoleWndProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7976 static SnapData sd;
\r
7977 static HWND hText, hInput /*, hFocus*/;
\r
7978 // InputSource *is = consoleInputSource;
\r
7980 static int sizeX, sizeY;
\r
7981 int newSizeX, newSizeY;
\r
7984 switch (message) {
\r
7985 case WM_INITDIALOG: /* message: initialize dialog box */
\r
7986 hwndConsole = hDlg;
\r
7987 hText = GetDlgItem(hDlg, OPT_ConsoleText);
\r
7988 hInput = GetDlgItem(hDlg, OPT_ConsoleInput);
\r
7990 consoleTextWindowProc = (WNDPROC)
\r
7991 SetWindowLong(hText, GWL_WNDPROC, (LONG) ConsoleTextSubclass);
\r
7992 SendMessage(hText, EM_SETBKGNDCOLOR, FALSE, consoleBackgroundColor);
\r
7993 consoleInputWindowProc = (WNDPROC)
\r
7994 SetWindowLong(hInput, GWL_WNDPROC, (LONG) ConsoleInputSubclass);
\r
7995 SendMessage(hInput, EM_SETBKGNDCOLOR, FALSE, consoleBackgroundColor);
\r
7996 Colorize(ColorNormal, TRUE);
\r
7997 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM) &consoleCF);
\r
7998 ChangedConsoleFont();
\r
7999 GetClientRect(hDlg, &rect);
\r
8000 sizeX = rect.right;
\r
8001 sizeY = rect.bottom;
\r
8002 if (consoleX != CW_USEDEFAULT && consoleY != CW_USEDEFAULT &&
\r
8003 consoleW != CW_USEDEFAULT && consoleH != CW_USEDEFAULT) {
\r
8004 WINDOWPLACEMENT wp;
\r
8005 EnsureOnScreen(&consoleX, &consoleY);
\r
8006 wp.length = sizeof(WINDOWPLACEMENT);
\r
8008 wp.showCmd = SW_SHOW;
\r
8009 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
8010 wp.rcNormalPosition.left = consoleX;
\r
8011 wp.rcNormalPosition.right = consoleX + consoleW;
\r
8012 wp.rcNormalPosition.top = consoleY;
\r
8013 wp.rcNormalPosition.bottom = consoleY + consoleH;
\r
8014 SetWindowPlacement(hDlg, &wp);
\r
8017 // [HGM] Chessknight's change 2004-07-13
\r
8018 else { /* Determine Defaults */
\r
8019 WINDOWPLACEMENT wp;
\r
8020 consoleX = winWidth + 1;
\r
8021 consoleY = boardY;
\r
8022 consoleW = screenWidth - winWidth;
\r
8023 consoleH = winHeight;
\r
8024 EnsureOnScreen(&consoleX, &consoleY);
\r
8025 wp.length = sizeof(WINDOWPLACEMENT);
\r
8027 wp.showCmd = SW_SHOW;
\r
8028 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
8029 wp.rcNormalPosition.left = consoleX;
\r
8030 wp.rcNormalPosition.right = consoleX + consoleW;
\r
8031 wp.rcNormalPosition.top = consoleY;
\r
8032 wp.rcNormalPosition.bottom = consoleY + consoleH;
\r
8033 SetWindowPlacement(hDlg, &wp);
\r
8048 if (IsIconic(hDlg)) break;
\r
8049 newSizeX = LOWORD(lParam);
\r
8050 newSizeY = HIWORD(lParam);
\r
8051 if (sizeX != newSizeX || sizeY != newSizeY) {
\r
8052 RECT rectText, rectInput;
\r
8054 int newTextHeight, newTextWidth;
\r
8055 GetWindowRect(hText, &rectText);
\r
8056 newTextWidth = rectText.right - rectText.left + newSizeX - sizeX;
\r
8057 newTextHeight = rectText.bottom - rectText.top + newSizeY - sizeY;
\r
8058 if (newTextHeight < 0) {
\r
8059 newSizeY += -newTextHeight;
\r
8060 newTextHeight = 0;
\r
8062 SetWindowPos(hText, NULL, 0, 0,
\r
8063 newTextWidth, newTextHeight, SWP_NOZORDER|SWP_NOMOVE);
\r
8064 GetWindowRect(hInput, &rectInput); /* gives screen coords */
\r
8065 pt.x = rectInput.left;
\r
8066 pt.y = rectInput.top + newSizeY - sizeY;
\r
8067 ScreenToClient(hDlg, &pt);
\r
8068 SetWindowPos(hInput, NULL,
\r
8069 pt.x, pt.y, /* needs client coords */
\r
8070 rectInput.right - rectInput.left + newSizeX - sizeX,
\r
8071 rectInput.bottom - rectInput.top, SWP_NOZORDER);
\r
8077 case WM_GETMINMAXINFO:
\r
8078 /* Prevent resizing window too small */
\r
8079 mmi = (MINMAXINFO *) lParam;
\r
8080 mmi->ptMinTrackSize.x = 100;
\r
8081 mmi->ptMinTrackSize.y = 100;
\r
8084 /* [AS] Snapping */
\r
8085 case WM_ENTERSIZEMOVE:
\r
8086 return OnEnterSizeMove( &sd, hDlg, wParam, lParam );
\r
8089 return OnSizing( &sd, hDlg, wParam, lParam );
\r
8092 return OnMoving( &sd, hDlg, wParam, lParam );
\r
8094 case WM_EXITSIZEMOVE:
\r
8095 return OnExitSizeMove( &sd, hDlg, wParam, lParam );
\r
8098 return DefWindowProc(hDlg, message, wParam, lParam);
\r
8106 if (hwndConsole) return;
\r
8107 hCons = CreateDialog(hInst, szConsoleName, 0, NULL);
\r
8108 SendMessage(hCons, WM_INITDIALOG, 0, 0);
\r
8113 ConsoleOutput(char* data, int length, int forceVisible)
\r
8118 char buf[CO_MAX+1];
\r
8121 static int delayLF = 0;
\r
8122 CHARRANGE savesel, sel;
\r
8124 if (hwndConsole == NULL || length > CO_MAX-100 || length == 0) return;
\r
8132 while (length--) {
\r
8140 } else if (*p == '\007') {
\r
8141 MyPlaySound(&sounds[(int)SoundBell]);
\r
8148 hText = GetDlgItem(hwndConsole, OPT_ConsoleText);
\r
8149 SendMessage(hText, EM_HIDESELECTION, TRUE, FALSE);
\r
8150 /* Save current selection */
\r
8151 SendMessage(hText, EM_EXGETSEL, 0, (LPARAM)&savesel);
\r
8152 exlen = GetWindowTextLength(hText);
\r
8153 /* Find out whether current end of text is visible */
\r
8154 SendMessage(hText, EM_GETRECT, 0, (LPARAM) &rect);
\r
8155 SendMessage(hText, EM_POSFROMCHAR, (WPARAM) &pEnd, exlen);
\r
8156 /* Trim existing text if it's too long */
\r
8157 if (exlen + (q - buf) > CO_MAX) {
\r
8158 trim = (CO_TRIM > (q - buf)) ? CO_TRIM : (q - buf);
\r
8161 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
8162 SendMessage(hText, EM_REPLACESEL, 0, (LPARAM)"");
\r
8164 savesel.cpMin -= trim;
\r
8165 savesel.cpMax -= trim;
\r
8166 if (exlen < 0) exlen = 0;
\r
8167 if (savesel.cpMin < 0) savesel.cpMin = 0;
\r
8168 if (savesel.cpMax < savesel.cpMin) savesel.cpMax = savesel.cpMin;
\r
8170 /* Append the new text */
\r
8171 sel.cpMin = exlen;
\r
8172 sel.cpMax = exlen;
\r
8173 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
8174 SendMessage(hText, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&consoleCF);
\r
8175 SendMessage(hText, EM_REPLACESEL, 0, (LPARAM) buf);
\r
8176 if (forceVisible || exlen == 0 ||
\r
8177 (rect.left <= pEnd.x && pEnd.x < rect.right &&
\r
8178 rect.top <= pEnd.y && pEnd.y < rect.bottom)) {
\r
8179 /* Scroll to make new end of text visible if old end of text
\r
8180 was visible or new text is an echo of user typein */
\r
8181 sel.cpMin = 9999999;
\r
8182 sel.cpMax = 9999999;
\r
8183 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
8184 SendMessage(hText, EM_HIDESELECTION, FALSE, FALSE);
\r
8185 SendMessage(hText, EM_SCROLLCARET, 0, 0);
\r
8186 SendMessage(hText, EM_HIDESELECTION, TRUE, FALSE);
\r
8188 if (savesel.cpMax == exlen || forceVisible) {
\r
8189 /* Move insert point to new end of text if it was at the old
\r
8190 end of text or if the new text is an echo of user typein */
\r
8191 sel.cpMin = 9999999;
\r
8192 sel.cpMax = 9999999;
\r
8193 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
8195 /* Restore previous selection */
\r
8196 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&savesel);
\r
8198 SendMessage(hText, EM_HIDESELECTION, FALSE, FALSE);
\r
8205 DisplayHoldingsCount(HDC hdc, int x, int y, int rightAlign, int copyNumber)
\r
8209 COLORREF oldFg, oldBg;
\r
8213 if(copyNumber > 1) sprintf(buf, "%d", copyNumber); else buf[0] = 0;
\r
8215 oldFg = SetTextColor(hdc, RGB(255, 255, 255)); /* white */
\r
8216 oldBg = SetBkColor(hdc, RGB(0, 0, 0)); /* black */
\r
8217 oldFont = SelectObject(hdc, font[boardSize][CLOCK_FONT]->hf);
\r
8220 rect.right = x + squareSize;
\r
8222 rect.bottom = y + squareSize;
\r
8225 ExtTextOut(hdc, x + MESSAGE_LINE_LEFTMARGIN
\r
8226 + (rightAlign ? (squareSize*2)/3 : 0),
\r
8227 y, ETO_CLIPPED|ETO_OPAQUE,
\r
8228 &rect, str, strlen(str), NULL);
\r
8230 (void) SetTextColor(hdc, oldFg);
\r
8231 (void) SetBkColor(hdc, oldBg);
\r
8232 (void) SelectObject(hdc, oldFont);
\r
8236 DisplayAClock(HDC hdc, int timeRemaining, int highlight,
\r
8237 RECT *rect, char *color, char *flagFell)
\r
8241 COLORREF oldFg, oldBg;
\r
8244 if (appData.clockMode) {
\r
8246 sprintf(buf, "%c %s %s", color[0], TimeString(timeRemaining), flagFell);
\r
8248 sprintf(buf, "%s: %s %s", color, TimeString(timeRemaining), flagFell);
\r
8255 oldFg = SetTextColor(hdc, RGB(255, 255, 255)); /* white */
\r
8256 oldBg = SetBkColor(hdc, RGB(0, 0, 0)); /* black */
\r
8258 oldFg = SetTextColor(hdc, RGB(0, 0, 0)); /* black */
\r
8259 oldBg = SetBkColor(hdc, RGB(255, 255, 255)); /* white */
\r
8261 oldFont = SelectObject(hdc, font[boardSize][CLOCK_FONT]->hf);
\r
8263 ExtTextOut(hdc, rect->left + MESSAGE_LINE_LEFTMARGIN,
\r
8264 rect->top, ETO_CLIPPED|ETO_OPAQUE,
\r
8265 rect, str, strlen(str), NULL);
\r
8267 (void) SetTextColor(hdc, oldFg);
\r
8268 (void) SetBkColor(hdc, oldBg);
\r
8269 (void) SelectObject(hdc, oldFont);
\r
8274 DoReadFile(HANDLE hFile, char *buf, int count, DWORD *outCount,
\r
8280 if( count <= 0 ) {
\r
8281 if (appData.debugMode) {
\r
8282 fprintf( debugFP, "DoReadFile: trying to read past end of buffer, overflow = %d\n", count );
\r
8285 return ERROR_INVALID_USER_BUFFER;
\r
8288 ResetEvent(ovl->hEvent);
\r
8289 ovl->Offset = ovl->OffsetHigh = 0;
\r
8290 ok = ReadFile(hFile, buf, count, outCount, ovl);
\r
8294 err = GetLastError();
\r
8295 if (err == ERROR_IO_PENDING) {
\r
8296 ok = GetOverlappedResult(hFile, ovl, outCount, TRUE);
\r
8300 err = GetLastError();
\r
8307 DoWriteFile(HANDLE hFile, char *buf, int count, DWORD *outCount,
\r
8312 ResetEvent(ovl->hEvent);
\r
8313 ovl->Offset = ovl->OffsetHigh = 0;
\r
8314 ok = WriteFile(hFile, buf, count, outCount, ovl);
\r
8318 err = GetLastError();
\r
8319 if (err == ERROR_IO_PENDING) {
\r
8320 ok = GetOverlappedResult(hFile, ovl, outCount, TRUE);
\r
8324 err = GetLastError();
\r
8330 /* [AS] If input is line by line and a line exceed the buffer size, force an error */
\r
8331 void CheckForInputBufferFull( InputSource * is )
\r
8333 if( is->lineByLine && (is->next - is->buf) >= INPUT_SOURCE_BUF_SIZE ) {
\r
8334 /* Look for end of line */
\r
8335 char * p = is->buf;
\r
8337 while( p < is->next && *p != '\n' ) {
\r
8341 if( p >= is->next ) {
\r
8342 if (appData.debugMode) {
\r
8343 fprintf( debugFP, "Input line exceeded buffer size (source id=%lu)\n", is->id );
\r
8346 is->error = ERROR_BROKEN_PIPE; /* [AS] Just any non-successful code! */
\r
8347 is->count = (DWORD) -1;
\r
8348 is->next = is->buf;
\r
8354 InputThread(LPVOID arg)
\r
8359 is = (InputSource *) arg;
\r
8360 ovl.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
\r
8361 ovl.Internal = ovl.InternalHigh = ovl.Offset = ovl.OffsetHigh = 0;
\r
8362 while (is->hThread != NULL) {
\r
8363 is->error = DoReadFile(is->hFile, is->next,
\r
8364 INPUT_SOURCE_BUF_SIZE - (is->next - is->buf),
\r
8365 &is->count, &ovl);
\r
8366 if (is->error == NO_ERROR) {
\r
8367 is->next += is->count;
\r
8369 if (is->error == ERROR_BROKEN_PIPE) {
\r
8370 /* Correct for MS brain damage. EOF reading a pipe is not an error. */
\r
8373 is->count = (DWORD) -1;
\r
8374 /* [AS] The (is->count <= 0) check below is not useful for unsigned values! */
\r
8379 CheckForInputBufferFull( is );
\r
8381 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
8383 if( is->count == ((DWORD) -1) ) break; /* [AS] */
\r
8385 if (is->count <= 0) break; /* Quit on EOF or error */
\r
8388 CloseHandle(ovl.hEvent);
\r
8389 CloseHandle(is->hFile);
\r
8391 if (appData.debugMode) {
\r
8392 fprintf( debugFP, "Input thread terminated (id=%lu, error=%d, count=%ld)\n", is->id, is->error, is->count );
\r
8399 /* Windows 95 beta 2 won't let you do overlapped i/o on a console or pipe */
\r
8401 NonOvlInputThread(LPVOID arg)
\r
8408 is = (InputSource *) arg;
\r
8409 while (is->hThread != NULL) {
\r
8410 is->error = ReadFile(is->hFile, is->next,
\r
8411 INPUT_SOURCE_BUF_SIZE - (is->next - is->buf),
\r
8412 &is->count, NULL) ? NO_ERROR : GetLastError();
\r
8413 if (is->error == NO_ERROR) {
\r
8414 /* Change CRLF to LF */
\r
8415 if (is->next > is->buf) {
\r
8417 i = is->count + 1;
\r
8425 if (prev == '\r' && *p == '\n') {
\r
8437 if (is->error == ERROR_BROKEN_PIPE) {
\r
8438 /* Correct for MS brain damage. EOF reading a pipe is not an error. */
\r
8441 is->count = (DWORD) -1;
\r
8445 CheckForInputBufferFull( is );
\r
8447 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
8449 if( is->count == ((DWORD) -1) ) break; /* [AS] */
\r
8451 if (is->count < 0) break; /* Quit on error */
\r
8453 CloseHandle(is->hFile);
\r
8458 SocketInputThread(LPVOID arg)
\r
8462 is = (InputSource *) arg;
\r
8463 while (is->hThread != NULL) {
\r
8464 is->count = recv(is->sock, is->buf, INPUT_SOURCE_BUF_SIZE, 0);
\r
8465 if ((int)is->count == SOCKET_ERROR) {
\r
8466 is->count = (DWORD) -1;
\r
8467 is->error = WSAGetLastError();
\r
8469 is->error = NO_ERROR;
\r
8470 is->next += is->count;
\r
8471 if (is->count == 0 && is->second == is) {
\r
8472 /* End of file on stderr; quit with no message */
\r
8476 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
8478 if( is->count == ((DWORD) -1) ) break; /* [AS] */
\r
8480 if (is->count <= 0) break; /* Quit on EOF or error */
\r
8486 InputEvent(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
8490 is = (InputSource *) lParam;
\r
8491 if (is->lineByLine) {
\r
8492 /* Feed in lines one by one */
\r
8493 char *p = is->buf;
\r
8495 while (q < is->next) {
\r
8496 if (*q++ == '\n') {
\r
8497 (is->func)(is, is->closure, p, q - p, NO_ERROR);
\r
8502 /* Move any partial line to the start of the buffer */
\r
8504 while (p < is->next) {
\r
8509 if (is->error != NO_ERROR || is->count == 0) {
\r
8510 /* Notify backend of the error. Note: If there was a partial
\r
8511 line at the end, it is not flushed through. */
\r
8512 (is->func)(is, is->closure, is->buf, is->count, is->error);
\r
8515 /* Feed in the whole chunk of input at once */
\r
8516 (is->func)(is, is->closure, is->buf, is->count, is->error);
\r
8517 is->next = is->buf;
\r
8521 /*---------------------------------------------------------------------------*\
\r
8523 * Menu enables. Used when setting various modes.
\r
8525 \*---------------------------------------------------------------------------*/
\r
8533 SetMenuEnables(HMENU hmenu, Enables *enab)
\r
8535 while (enab->item > 0) {
\r
8536 (void) EnableMenuItem(hmenu, enab->item, enab->flags);
\r
8541 Enables gnuEnables[] = {
\r
8542 { IDM_MailMove, MF_BYCOMMAND|MF_GRAYED },
\r
8543 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_GRAYED },
\r
8544 { IDM_IcsClient, MF_BYCOMMAND|MF_GRAYED },
\r
8545 { IDM_Accept, MF_BYCOMMAND|MF_GRAYED },
\r
8546 { IDM_Decline, MF_BYCOMMAND|MF_GRAYED },
\r
8547 { IDM_Rematch, MF_BYCOMMAND|MF_GRAYED },
\r
8548 { IDM_Adjourn, MF_BYCOMMAND|MF_GRAYED },
\r
8549 { IDM_StopExamining, MF_BYCOMMAND|MF_GRAYED },
\r
8550 { IDM_StopObserving, MF_BYCOMMAND|MF_GRAYED },
\r
8551 { IDM_Revert, MF_BYCOMMAND|MF_GRAYED },
\r
8555 Enables icsEnables[] = {
\r
8556 { IDM_MailMove, MF_BYCOMMAND|MF_GRAYED },
\r
8557 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_GRAYED },
\r
8558 { IDM_MachineWhite, MF_BYCOMMAND|MF_GRAYED },
\r
8559 { IDM_MachineBlack, MF_BYCOMMAND|MF_GRAYED },
\r
8560 { IDM_TwoMachines, MF_BYCOMMAND|MF_GRAYED },
\r
8561 { IDM_AnalysisMode, MF_BYCOMMAND|MF_ENABLED },
\r
8562 { IDM_AnalyzeFile, MF_BYCOMMAND|MF_GRAYED },
\r
8563 { IDM_TimeControl, MF_BYCOMMAND|MF_GRAYED },
\r
8564 { IDM_MoveNow, MF_BYCOMMAND|MF_GRAYED },
\r
8565 { IDM_Hint, MF_BYCOMMAND|MF_GRAYED },
\r
8566 { IDM_Book, MF_BYCOMMAND|MF_GRAYED },
\r
8567 { IDM_IcsOptions, MF_BYCOMMAND|MF_ENABLED },
\r
8572 Enables zippyEnables[] = {
\r
8573 { IDM_MoveNow, MF_BYCOMMAND|MF_ENABLED },
\r
8574 { IDM_Hint, MF_BYCOMMAND|MF_ENABLED },
\r
8575 { IDM_Book, MF_BYCOMMAND|MF_ENABLED },
\r
8580 Enables ncpEnables[] = {
\r
8581 { IDM_MailMove, MF_BYCOMMAND|MF_GRAYED },
\r
8582 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_GRAYED },
\r
8583 { IDM_MachineWhite, MF_BYCOMMAND|MF_GRAYED },
\r
8584 { IDM_MachineBlack, MF_BYCOMMAND|MF_GRAYED },
\r
8585 { IDM_TwoMachines, MF_BYCOMMAND|MF_GRAYED },
\r
8586 { IDM_AnalysisMode, MF_BYCOMMAND|MF_GRAYED },
\r
8587 { IDM_AnalyzeFile, MF_BYCOMMAND|MF_GRAYED },
\r
8588 { IDM_IcsClient, MF_BYCOMMAND|MF_GRAYED },
\r
8589 { ACTION_POS, MF_BYPOSITION|MF_GRAYED },
\r
8590 { IDM_Revert, MF_BYCOMMAND|MF_GRAYED },
\r
8591 { IDM_MoveNow, MF_BYCOMMAND|MF_GRAYED },
\r
8592 { IDM_RetractMove, MF_BYCOMMAND|MF_GRAYED },
\r
8593 { IDM_TimeControl, MF_BYCOMMAND|MF_GRAYED },
\r
8594 { IDM_Hint, MF_BYCOMMAND|MF_GRAYED },
\r
8595 { IDM_Book, MF_BYCOMMAND|MF_GRAYED },
\r
8599 Enables trainingOnEnables[] = {
\r
8600 { IDM_EditComment, MF_BYCOMMAND|MF_GRAYED },
\r
8601 { IDM_Pause, MF_BYCOMMAND|MF_GRAYED },
\r
8602 { IDM_Forward, MF_BYCOMMAND|MF_GRAYED },
\r
8603 { IDM_Backward, MF_BYCOMMAND|MF_GRAYED },
\r
8604 { IDM_ToEnd, MF_BYCOMMAND|MF_GRAYED },
\r
8605 { IDM_ToStart, MF_BYCOMMAND|MF_GRAYED },
\r
8606 { IDM_MoveNow, MF_BYCOMMAND|MF_GRAYED },
\r
8607 { IDM_TruncateGame, MF_BYCOMMAND|MF_GRAYED },
\r
8611 Enables trainingOffEnables[] = {
\r
8612 { IDM_EditComment, MF_BYCOMMAND|MF_ENABLED },
\r
8613 { IDM_Pause, MF_BYCOMMAND|MF_ENABLED },
\r
8614 { IDM_Forward, MF_BYCOMMAND|MF_ENABLED },
\r
8615 { IDM_Backward, MF_BYCOMMAND|MF_ENABLED },
\r
8616 { IDM_ToEnd, MF_BYCOMMAND|MF_ENABLED },
\r
8617 { IDM_ToStart, MF_BYCOMMAND|MF_ENABLED },
\r
8618 { IDM_MoveNow, MF_BYCOMMAND|MF_ENABLED },
\r
8619 { IDM_TruncateGame, MF_BYCOMMAND|MF_ENABLED },
\r
8623 /* These modify either ncpEnables or gnuEnables */
\r
8624 Enables cmailEnables[] = {
\r
8625 { IDM_MailMove, MF_BYCOMMAND|MF_ENABLED },
\r
8626 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_ENABLED },
\r
8627 { ACTION_POS, MF_BYPOSITION|MF_ENABLED },
\r
8628 { IDM_CallFlag, MF_BYCOMMAND|MF_GRAYED },
\r
8629 { IDM_Draw, MF_BYCOMMAND|MF_ENABLED },
\r
8630 { IDM_Adjourn, MF_BYCOMMAND|MF_GRAYED },
\r
8631 { IDM_Abort, MF_BYCOMMAND|MF_GRAYED },
\r
8635 Enables machineThinkingEnables[] = {
\r
8636 { IDM_LoadGame, MF_BYCOMMAND|MF_GRAYED },
\r
8637 { IDM_LoadNextGame, MF_BYCOMMAND|MF_GRAYED },
\r
8638 { IDM_LoadPrevGame, MF_BYCOMMAND|MF_GRAYED },
\r
8639 { IDM_ReloadGame, MF_BYCOMMAND|MF_GRAYED },
\r
8640 { IDM_PasteGame, MF_BYCOMMAND|MF_GRAYED },
\r
8641 { IDM_LoadPosition, MF_BYCOMMAND|MF_GRAYED },
\r
8642 { IDM_LoadNextPosition, MF_BYCOMMAND|MF_GRAYED },
\r
8643 { IDM_LoadPrevPosition, MF_BYCOMMAND|MF_GRAYED },
\r
8644 { IDM_ReloadPosition, MF_BYCOMMAND|MF_GRAYED },
\r
8645 { IDM_PastePosition, MF_BYCOMMAND|MF_GRAYED },
\r
8646 { IDM_MachineWhite, MF_BYCOMMAND|MF_GRAYED },
\r
8647 { IDM_MachineBlack, MF_BYCOMMAND|MF_GRAYED },
\r
8648 { IDM_TwoMachines, MF_BYCOMMAND|MF_GRAYED },
\r
8649 { IDM_TypeInMove, MF_BYCOMMAND|MF_GRAYED },
\r
8650 { IDM_RetractMove, MF_BYCOMMAND|MF_GRAYED },
\r
8654 Enables userThinkingEnables[] = {
\r
8655 { IDM_LoadGame, MF_BYCOMMAND|MF_ENABLED },
\r
8656 { IDM_LoadNextGame, MF_BYCOMMAND|MF_ENABLED },
\r
8657 { IDM_LoadPrevGame, MF_BYCOMMAND|MF_ENABLED },
\r
8658 { IDM_ReloadGame, MF_BYCOMMAND|MF_ENABLED },
\r
8659 { IDM_PasteGame, MF_BYCOMMAND|MF_ENABLED },
\r
8660 { IDM_LoadPosition, MF_BYCOMMAND|MF_ENABLED },
\r
8661 { IDM_LoadNextPosition, MF_BYCOMMAND|MF_ENABLED },
\r
8662 { IDM_LoadPrevPosition, MF_BYCOMMAND|MF_ENABLED },
\r
8663 { IDM_ReloadPosition, MF_BYCOMMAND|MF_ENABLED },
\r
8664 { IDM_PastePosition, MF_BYCOMMAND|MF_ENABLED },
\r
8665 { IDM_MachineWhite, MF_BYCOMMAND|MF_ENABLED },
\r
8666 { IDM_MachineBlack, MF_BYCOMMAND|MF_ENABLED },
\r
8667 { IDM_TwoMachines, MF_BYCOMMAND|MF_ENABLED },
\r
8668 { IDM_TypeInMove, MF_BYCOMMAND|MF_ENABLED },
\r
8669 { IDM_RetractMove, MF_BYCOMMAND|MF_ENABLED },
\r
8673 /*---------------------------------------------------------------------------*\
\r
8675 * Front-end interface functions exported by XBoard.
\r
8676 * Functions appear in same order as prototypes in frontend.h.
\r
8678 \*---------------------------------------------------------------------------*/
\r
8682 static UINT prevChecked = 0;
\r
8683 static int prevPausing = 0;
\r
8686 if (pausing != prevPausing) {
\r
8687 prevPausing = pausing;
\r
8688 (void) CheckMenuItem(GetMenu(hwndMain), IDM_Pause,
\r
8689 MF_BYCOMMAND|(pausing ? MF_CHECKED : MF_UNCHECKED));
\r
8690 if (hwndPause) SetWindowText(hwndPause, pausing ? "C" : "P");
\r
8693 switch (gameMode) {
\r
8694 case BeginningOfGame:
\r
8695 if (appData.icsActive)
\r
8696 nowChecked = IDM_IcsClient;
\r
8697 else if (appData.noChessProgram)
\r
8698 nowChecked = IDM_EditGame;
\r
8700 nowChecked = IDM_MachineBlack;
\r
8702 case MachinePlaysBlack:
\r
8703 nowChecked = IDM_MachineBlack;
\r
8705 case MachinePlaysWhite:
\r
8706 nowChecked = IDM_MachineWhite;
\r
8708 case TwoMachinesPlay:
\r
8709 nowChecked = IDM_TwoMachines;
\r
8712 nowChecked = IDM_AnalysisMode;
\r
8715 nowChecked = IDM_AnalyzeFile;
\r
8718 nowChecked = IDM_EditGame;
\r
8720 case PlayFromGameFile:
\r
8721 nowChecked = IDM_LoadGame;
\r
8723 case EditPosition:
\r
8724 nowChecked = IDM_EditPosition;
\r
8727 nowChecked = IDM_Training;
\r
8729 case IcsPlayingWhite:
\r
8730 case IcsPlayingBlack:
\r
8731 case IcsObserving:
\r
8733 nowChecked = IDM_IcsClient;
\r
8740 if (prevChecked != 0)
\r
8741 (void) CheckMenuItem(GetMenu(hwndMain),
\r
8742 prevChecked, MF_BYCOMMAND|MF_UNCHECKED);
\r
8743 if (nowChecked != 0)
\r
8744 (void) CheckMenuItem(GetMenu(hwndMain),
\r
8745 nowChecked, MF_BYCOMMAND|MF_CHECKED);
\r
8747 if (nowChecked == IDM_LoadGame || nowChecked == IDM_Training) {
\r
8748 (void) EnableMenuItem(GetMenu(hwndMain), IDM_Training,
\r
8749 MF_BYCOMMAND|MF_ENABLED);
\r
8751 (void) EnableMenuItem(GetMenu(hwndMain),
\r
8752 IDM_Training, MF_BYCOMMAND|MF_GRAYED);
\r
8755 prevChecked = nowChecked;
\r
8757 /* [DM] icsEngineAnalyze - Do a sceure check too */
\r
8758 if (appData.icsActive) {
\r
8759 if (appData.icsEngineAnalyze) {
\r
8760 (void) CheckMenuItem(GetMenu(hwndMain), IDM_AnalysisMode,
\r
8761 MF_BYCOMMAND|MF_CHECKED);
\r
8763 (void) CheckMenuItem(GetMenu(hwndMain), IDM_AnalysisMode,
\r
8764 MF_BYCOMMAND|MF_UNCHECKED);
\r
8772 HMENU hmenu = GetMenu(hwndMain);
\r
8773 SetMenuEnables(hmenu, icsEnables);
\r
8774 EnableMenuItem(GetSubMenu(hmenu, OPTIONS_POS), ICS_POS,
\r
8775 MF_BYPOSITION|MF_ENABLED);
\r
8777 if (appData.zippyPlay) {
\r
8778 SetMenuEnables(hmenu, zippyEnables);
\r
8779 if (!appData.noChessProgram) /* [DM] icsEngineAnalyze */
\r
8780 (void) EnableMenuItem(GetMenu(hwndMain), IDM_AnalysisMode,
\r
8781 MF_BYCOMMAND|MF_ENABLED);
\r
8789 SetMenuEnables(GetMenu(hwndMain), gnuEnables);
\r
8795 HMENU hmenu = GetMenu(hwndMain);
\r
8796 SetMenuEnables(hmenu, ncpEnables);
\r
8797 EnableMenuItem(GetSubMenu(hmenu, OPTIONS_POS), SOUNDS_POS,
\r
8798 MF_BYPOSITION|MF_GRAYED);
\r
8799 DrawMenuBar(hwndMain);
\r
8805 SetMenuEnables(GetMenu(hwndMain), cmailEnables);
\r
8809 SetTrainingModeOn()
\r
8812 SetMenuEnables(GetMenu(hwndMain), trainingOnEnables);
\r
8813 for (i = 0; i < N_BUTTONS; i++) {
\r
8814 if (buttonDesc[i].hwnd != NULL)
\r
8815 EnableWindow(buttonDesc[i].hwnd, FALSE);
\r
8820 VOID SetTrainingModeOff()
\r
8823 SetMenuEnables(GetMenu(hwndMain), trainingOffEnables);
\r
8824 for (i = 0; i < N_BUTTONS; i++) {
\r
8825 if (buttonDesc[i].hwnd != NULL)
\r
8826 EnableWindow(buttonDesc[i].hwnd, TRUE);
\r
8832 SetUserThinkingEnables()
\r
8834 SetMenuEnables(GetMenu(hwndMain), userThinkingEnables);
\r
8838 SetMachineThinkingEnables()
\r
8840 HMENU hMenu = GetMenu(hwndMain);
\r
8841 int flags = MF_BYCOMMAND|MF_ENABLED;
\r
8843 SetMenuEnables(hMenu, machineThinkingEnables);
\r
8845 if (gameMode == MachinePlaysBlack) {
\r
8846 (void)EnableMenuItem(hMenu, IDM_MachineBlack, flags);
\r
8847 } else if (gameMode == MachinePlaysWhite) {
\r
8848 (void)EnableMenuItem(hMenu, IDM_MachineWhite, flags);
\r
8849 } else if (gameMode == TwoMachinesPlay) {
\r
8850 (void)EnableMenuItem(hMenu, IDM_TwoMachines, flags);
\r
8856 DisplayTitle(char *str)
\r
8858 char title[MSG_SIZ], *host;
\r
8859 if (str[0] != NULLCHAR) {
\r
8860 strcpy(title, str);
\r
8861 } else if (appData.icsActive) {
\r
8862 if (appData.icsCommPort[0] != NULLCHAR)
\r
8865 host = appData.icsHost;
\r
8866 sprintf(title, "%s: %s", szTitle, host);
\r
8867 } else if (appData.noChessProgram) {
\r
8868 strcpy(title, szTitle);
\r
8870 strcpy(title, szTitle);
\r
8871 strcat(title, ": ");
\r
8872 strcat(title, first.tidy);
\r
8874 SetWindowText(hwndMain, title);
\r
8879 DisplayMessage(char *str1, char *str2)
\r
8883 int remain = MESSAGE_TEXT_MAX - 1;
\r
8886 moveErrorMessageUp = FALSE; /* turned on later by caller if needed */
\r
8887 messageText[0] = NULLCHAR;
\r
8889 len = strlen(str1);
\r
8890 if (len > remain) len = remain;
\r
8891 strncpy(messageText, str1, len);
\r
8892 messageText[len] = NULLCHAR;
\r
8895 if (*str2 && remain >= 2) {
\r
8897 strcat(messageText, " ");
\r
8900 len = strlen(str2);
\r
8901 if (len > remain) len = remain;
\r
8902 strncat(messageText, str2, len);
\r
8904 messageText[MESSAGE_TEXT_MAX - 1] = NULLCHAR;
\r
8906 if (hwndMain == NULL || IsIconic(hwndMain)) return;
\r
8907 hdc = GetDC(hwndMain);
\r
8908 oldFont = SelectObject(hdc, font[boardSize][MESSAGE_FONT]->hf);
\r
8909 ExtTextOut(hdc, messageRect.left, messageRect.top, ETO_CLIPPED|ETO_OPAQUE,
\r
8910 &messageRect, messageText, strlen(messageText), NULL);
\r
8911 (void) SelectObject(hdc, oldFont);
\r
8912 (void) ReleaseDC(hwndMain, hdc);
\r
8916 DisplayError(char *str, int error)
\r
8918 char buf[MSG_SIZ*2], buf2[MSG_SIZ];
\r
8924 len = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
\r
8925 NULL, error, LANG_NEUTRAL,
\r
8926 (LPSTR) buf2, MSG_SIZ, NULL);
\r
8928 sprintf(buf, "%s:\n%s", str, buf2);
\r
8930 ErrorMap *em = errmap;
\r
8931 while (em->err != 0 && em->err != error) em++;
\r
8932 if (em->err != 0) {
\r
8933 sprintf(buf, "%s:\n%s", str, em->msg);
\r
8935 sprintf(buf, "%s:\nError code %d", str, error);
\r
8940 ErrorPopUp("Error", buf);
\r
8945 DisplayMoveError(char *str)
\r
8947 fromX = fromY = -1;
\r
8948 ClearHighlights();
\r
8949 DrawPosition(FALSE, NULL);
\r
8950 if (appData.popupMoveErrors) {
\r
8951 ErrorPopUp("Error", str);
\r
8953 DisplayMessage(str, "");
\r
8954 moveErrorMessageUp = TRUE;
\r
8959 DisplayFatalError(char *str, int error, int exitStatus)
\r
8961 char buf[2*MSG_SIZ], buf2[MSG_SIZ];
\r
8963 char *label = exitStatus ? "Fatal Error" : "Exiting";
\r
8966 len = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
\r
8967 NULL, error, LANG_NEUTRAL,
\r
8968 (LPSTR) buf2, MSG_SIZ, NULL);
\r
8970 sprintf(buf, "%s:\n%s", str, buf2);
\r
8972 ErrorMap *em = errmap;
\r
8973 while (em->err != 0 && em->err != error) em++;
\r
8974 if (em->err != 0) {
\r
8975 sprintf(buf, "%s:\n%s", str, em->msg);
\r
8977 sprintf(buf, "%s:\nError code %d", str, error);
\r
8982 if (appData.debugMode) {
\r
8983 fprintf(debugFP, "%s: %s\n", label, str);
\r
8985 if (appData.popupExitMessage) {
\r
8986 (void) MessageBox(hwndMain, str, label, MB_OK|
\r
8987 (exitStatus ? MB_ICONSTOP : MB_ICONINFORMATION));
\r
8989 ExitEvent(exitStatus);
\r
8994 DisplayInformation(char *str)
\r
8996 (void) MessageBox(hwndMain, str, "Information", MB_OK|MB_ICONINFORMATION);
\r
9001 DisplayNote(char *str)
\r
9003 ErrorPopUp("Note", str);
\r
9008 char *title, *question, *replyPrefix;
\r
9013 QuestionDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
9015 static QuestionParams *qp;
\r
9016 char reply[MSG_SIZ];
\r
9019 switch (message) {
\r
9020 case WM_INITDIALOG:
\r
9021 qp = (QuestionParams *) lParam;
\r
9022 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
9023 SetWindowText(hDlg, qp->title);
\r
9024 SetDlgItemText(hDlg, OPT_QuestionText, qp->question);
\r
9025 SetFocus(GetDlgItem(hDlg, OPT_QuestionInput));
\r
9029 switch (LOWORD(wParam)) {
\r
9031 strcpy(reply, qp->replyPrefix);
\r
9032 if (*reply) strcat(reply, " ");
\r
9033 len = strlen(reply);
\r
9034 GetDlgItemText(hDlg, OPT_QuestionInput, reply + len, sizeof(reply) - len);
\r
9035 strcat(reply, "\n");
\r
9036 OutputToProcess(qp->pr, reply, strlen(reply), &err);
\r
9037 EndDialog(hDlg, TRUE);
\r
9038 if (err) DisplayFatalError("Error writing to chess program", err, 1);
\r
9041 EndDialog(hDlg, FALSE);
\r
9052 AskQuestion(char* title, char *question, char *replyPrefix, ProcRef pr)
\r
9054 QuestionParams qp;
\r
9058 qp.question = question;
\r
9059 qp.replyPrefix = replyPrefix;
\r
9061 lpProc = MakeProcInstance((FARPROC)QuestionDialog, hInst);
\r
9062 DialogBoxParam(hInst, MAKEINTRESOURCE(DLG_Question),
\r
9063 hwndMain, (DLGPROC)lpProc, (LPARAM)&qp);
\r
9064 FreeProcInstance(lpProc);
\r
9067 /* [AS] Pick FRC position */
\r
9068 LRESULT CALLBACK NewGameFRC_Proc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
9070 static int * lpIndexFRC;
\r
9076 case WM_INITDIALOG:
\r
9077 lpIndexFRC = (int *) lParam;
\r
9079 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
9081 SendDlgItemMessage( hDlg, IDC_NFG_Edit, EM_SETLIMITTEXT, sizeof(buf)-1, 0 );
\r
9082 SetDlgItemInt( hDlg, IDC_NFG_Edit, *lpIndexFRC, TRUE );
\r
9083 SendDlgItemMessage( hDlg, IDC_NFG_Edit, EM_SETSEL, 0, -1 );
\r
9084 SetFocus(GetDlgItem(hDlg, IDC_NFG_Edit));
\r
9089 switch( LOWORD(wParam) ) {
\r
9091 *lpIndexFRC = GetDlgItemInt(hDlg, IDC_NFG_Edit, &index_is_ok, TRUE );
\r
9092 EndDialog( hDlg, 0 );
\r
9093 shuffleOpenings = TRUE; /* [HGM] shuffle: switch shuffling on for as long as we stay in current variant */
\r
9096 EndDialog( hDlg, 1 );
\r
9098 case IDC_NFG_Edit:
\r
9099 if( HIWORD(wParam) == EN_CHANGE ) {
\r
9100 GetDlgItemInt(hDlg, IDC_NFG_Edit, &index_is_ok, TRUE );
\r
9102 EnableWindow( GetDlgItem(hDlg, IDOK), index_is_ok );
\r
9105 case IDC_NFG_Random:
\r
9106 sprintf( buf, "%d", myrandom() ); /* [HGM] shuffle: no longer limit to 960 */
\r
9107 SetDlgItemText(hDlg, IDC_NFG_Edit, buf );
\r
9120 int index = appData.defaultFrcPosition;
\r
9121 FARPROC lpProc = MakeProcInstance( (FARPROC) NewGameFRC_Proc, hInst );
\r
9123 result = DialogBoxParam( hInst, MAKEINTRESOURCE(DLG_NewGameFRC), hwndMain, (DLGPROC)lpProc, (LPARAM)&index );
\r
9125 if( result == 0 ) {
\r
9126 appData.defaultFrcPosition = index;
\r
9132 /* [AS] Game list options */
\r
9138 static GLT_Item GLT_ItemInfo[] = {
\r
9139 { GLT_EVENT, "Event" },
\r
9140 { GLT_SITE, "Site" },
\r
9141 { GLT_DATE, "Date" },
\r
9142 { GLT_ROUND, "Round" },
\r
9143 { GLT_PLAYERS, "Players" },
\r
9144 { GLT_RESULT, "Result" },
\r
9145 { GLT_WHITE_ELO, "White Rating" },
\r
9146 { GLT_BLACK_ELO, "Black Rating" },
\r
9147 { GLT_TIME_CONTROL,"Time Control" },
\r
9148 { GLT_VARIANT, "Variant" },
\r
9149 { GLT_OUT_OF_BOOK,PGN_OUT_OF_BOOK },
\r
9153 const char * GLT_FindItem( char id )
\r
9155 const char * result = 0;
\r
9157 GLT_Item * list = GLT_ItemInfo;
\r
9159 while( list->id != 0 ) {
\r
9160 if( list->id == id ) {
\r
9161 result = list->name;
\r
9171 void GLT_AddToList( HWND hDlg, int iDlgItem, char id, int index )
\r
9173 const char * name = GLT_FindItem( id );
\r
9176 if( index >= 0 ) {
\r
9177 SendDlgItemMessage( hDlg, iDlgItem, LB_INSERTSTRING, index, (LPARAM) name );
\r
9180 SendDlgItemMessage( hDlg, iDlgItem, LB_ADDSTRING, 0, (LPARAM) name );
\r
9185 void GLT_TagsToList( HWND hDlg, char * tags )
\r
9189 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_RESETCONTENT, 0, 0 );
\r
9192 GLT_AddToList( hDlg, IDC_GameListTags, *pc, -1 );
\r
9196 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_ADDSTRING, 0, (LPARAM) "\t --- Hidden tags ---" );
\r
9198 pc = GLT_ALL_TAGS;
\r
9201 if( strchr( tags, *pc ) == 0 ) {
\r
9202 GLT_AddToList( hDlg, IDC_GameListTags, *pc, -1 );
\r
9207 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_SETCURSEL, 0, 0 );
\r
9210 char GLT_ListItemToTag( HWND hDlg, int index )
\r
9212 char result = '\0';
\r
9215 GLT_Item * list = GLT_ItemInfo;
\r
9217 if( SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETTEXT, index, (LPARAM) name ) != LB_ERR ) {
\r
9218 while( list->id != 0 ) {
\r
9219 if( strcmp( list->name, name ) == 0 ) {
\r
9220 result = list->id;
\r
9231 void GLT_MoveSelection( HWND hDlg, int delta )
\r
9233 int idx1 = (int) SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETCURSEL, 0, 0 );
\r
9234 int idx2 = idx1 + delta;
\r
9235 int count = (int) SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETCOUNT, 0, 0 );
\r
9237 if( idx1 >=0 && idx1 < count && idx2 >= 0 && idx2 < count ) {
\r
9240 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETTEXT, idx1, (LPARAM) buf );
\r
9241 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_DELETESTRING, idx1, 0 );
\r
9242 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_INSERTSTRING, idx2, (LPARAM) buf );
\r
9243 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_SETCURSEL, idx2, 0 );
\r
9247 LRESULT CALLBACK GameListOptions_Proc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
9249 static char glt[64];
\r
9250 static char * lpUserGLT;
\r
9254 case WM_INITDIALOG:
\r
9255 lpUserGLT = (char *) lParam;
\r
9257 strcpy( glt, lpUserGLT );
\r
9259 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
9261 /* Initialize list */
\r
9262 GLT_TagsToList( hDlg, glt );
\r
9264 SetFocus( GetDlgItem(hDlg, IDC_GameListTags) );
\r
9269 switch( LOWORD(wParam) ) {
\r
9272 char * pc = lpUserGLT;
\r
9274 // int cnt = (int) SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETCOUNT, 0, 0 );
\r
9278 id = GLT_ListItemToTag( hDlg, idx );
\r
9282 } while( id != '\0' );
\r
9284 EndDialog( hDlg, 0 );
\r
9287 EndDialog( hDlg, 1 );
\r
9290 case IDC_GLT_Default:
\r
9291 strcpy( glt, GLT_DEFAULT_TAGS );
\r
9292 GLT_TagsToList( hDlg, glt );
\r
9295 case IDC_GLT_Restore:
\r
9296 strcpy( glt, lpUserGLT );
\r
9297 GLT_TagsToList( hDlg, glt );
\r
9301 GLT_MoveSelection( hDlg, -1 );
\r
9304 case IDC_GLT_Down:
\r
9305 GLT_MoveSelection( hDlg, +1 );
\r
9315 int GameListOptions()
\r
9319 FARPROC lpProc = MakeProcInstance( (FARPROC) GameListOptions_Proc, hInst );
\r
9321 strcpy( glt, appData.gameListTags );
\r
9323 result = DialogBoxParam( hInst, MAKEINTRESOURCE(DLG_GameListOptions), hwndMain, (DLGPROC)lpProc, (LPARAM)glt );
\r
9325 if( result == 0 ) {
\r
9326 /* [AS] Memory leak here! */
\r
9327 appData.gameListTags = strdup( glt );
\r
9335 DisplayIcsInteractionTitle(char *str)
\r
9337 char consoleTitle[MSG_SIZ];
\r
9339 sprintf(consoleTitle, "%s: %s", szConsoleTitle, str);
\r
9340 SetWindowText(hwndConsole, consoleTitle);
\r
9344 DrawPosition(int fullRedraw, Board board)
\r
9346 HDCDrawPosition(NULL, (BOOLEAN) fullRedraw, board);
\r
9353 fromX = fromY = -1;
\r
9354 if (dragInfo.pos.x != -1 || dragInfo.pos.y != -1) {
\r
9355 dragInfo.pos.x = dragInfo.pos.y = -1;
\r
9356 dragInfo.pos.x = dragInfo.pos.y = -1;
\r
9357 dragInfo.lastpos = dragInfo.pos;
\r
9358 dragInfo.start.x = dragInfo.start.y = -1;
\r
9359 dragInfo.from = dragInfo.start;
\r
9361 DrawPosition(TRUE, NULL);
\r
9367 CommentPopUp(char *title, char *str)
\r
9369 HWND hwnd = GetActiveWindow();
\r
9370 EitherCommentPopUp(0, title, str, FALSE);
\r
9371 SetActiveWindow(hwnd);
\r
9375 CommentPopDown(void)
\r
9377 CheckMenuItem(GetMenu(hwndMain), IDM_EditComment, MF_UNCHECKED);
\r
9378 if (commentDialog) {
\r
9379 ShowWindow(commentDialog, SW_HIDE);
\r
9381 commentDialogUp = FALSE;
\r
9385 EditCommentPopUp(int index, char *title, char *str)
\r
9387 EitherCommentPopUp(index, title, str, TRUE);
\r
9394 MyPlaySound(&sounds[(int)SoundMove]);
\r
9397 VOID PlayIcsWinSound()
\r
9399 MyPlaySound(&sounds[(int)SoundIcsWin]);
\r
9402 VOID PlayIcsLossSound()
\r
9404 MyPlaySound(&sounds[(int)SoundIcsLoss]);
\r
9407 VOID PlayIcsDrawSound()
\r
9409 MyPlaySound(&sounds[(int)SoundIcsDraw]);
\r
9412 VOID PlayIcsUnfinishedSound()
\r
9414 MyPlaySound(&sounds[(int)SoundIcsUnfinished]);
\r
9420 MyPlaySound(&sounds[(int)SoundAlarm]);
\r
9428 consoleEcho = TRUE;
\r
9429 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
9430 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&consoleCF);
\r
9431 SendMessage(hInput, EM_SETBKGNDCOLOR, FALSE, consoleBackgroundColor);
\r
9440 consoleEcho = FALSE;
\r
9441 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
9442 /* This works OK: set text and background both to the same color */
\r
9444 cf.crTextColor = COLOR_ECHOOFF;
\r
9445 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&cf);
\r
9446 SendMessage(hInput, EM_SETBKGNDCOLOR, FALSE, cf.crTextColor);
\r
9449 /* No Raw()...? */
\r
9451 void Colorize(ColorClass cc, int continuation)
\r
9453 currentColorClass = cc;
\r
9454 consoleCF.dwMask = CFM_COLOR|CFM_BOLD|CFM_ITALIC|CFM_UNDERLINE|CFM_STRIKEOUT;
\r
9455 consoleCF.crTextColor = textAttribs[cc].color;
\r
9456 consoleCF.dwEffects = textAttribs[cc].effects;
\r
9457 if (!continuation) MyPlaySound(&textAttribs[cc].sound);
\r
9463 static char buf[MSG_SIZ];
\r
9464 DWORD bufsiz = MSG_SIZ;
\r
9466 if(appData.userName != NULL && appData.userName[0] != 0) {
\r
9467 return appData.userName; /* [HGM] username: prefer name selected by user over his system login */
\r
9469 if (!GetUserName(buf, &bufsiz)) {
\r
9470 /*DisplayError("Error getting user name", GetLastError());*/
\r
9471 strcpy(buf, "User");
\r
9479 static char buf[MSG_SIZ];
\r
9480 DWORD bufsiz = MSG_SIZ;
\r
9482 if (!GetComputerName(buf, &bufsiz)) {
\r
9483 /*DisplayError("Error getting host name", GetLastError());*/
\r
9484 strcpy(buf, "Unknown");
\r
9491 ClockTimerRunning()
\r
9493 return clockTimerEvent != 0;
\r
9499 if (clockTimerEvent == 0) return FALSE;
\r
9500 KillTimer(hwndMain, clockTimerEvent);
\r
9501 clockTimerEvent = 0;
\r
9506 StartClockTimer(long millisec)
\r
9508 clockTimerEvent = SetTimer(hwndMain, (UINT) CLOCK_TIMER_ID,
\r
9509 (UINT) millisec, NULL);
\r
9513 DisplayWhiteClock(long timeRemaining, int highlight)
\r
9516 char *flag = whiteFlag && gameMode == TwoMachinesPlay ? "(!)" : "";
\r
9518 if(appData.noGUI) return;
\r
9519 hdc = GetDC(hwndMain);
\r
9520 if (!IsIconic(hwndMain)) {
\r
9521 DisplayAClock(hdc, timeRemaining, highlight,
\r
9522 (logoHeight > 0 ? flipView: flipClock) ? &blackRect : &whiteRect, "White", flag);
\r
9524 if (highlight && iconCurrent == iconBlack) {
\r
9525 iconCurrent = iconWhite;
\r
9526 PostMessage(hwndMain, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
9527 if (IsIconic(hwndMain)) {
\r
9528 DrawIcon(hdc, 2, 2, iconCurrent);
\r
9531 (void) ReleaseDC(hwndMain, hdc);
\r
9533 PostMessage(hwndConsole, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
9537 DisplayBlackClock(long timeRemaining, int highlight)
\r
9540 char *flag = blackFlag && gameMode == TwoMachinesPlay ? "(!)" : "";
\r
9542 if(appData.noGUI) return;
\r
9543 hdc = GetDC(hwndMain);
\r
9544 if (!IsIconic(hwndMain)) {
\r
9545 DisplayAClock(hdc, timeRemaining, highlight,
\r
9546 (logoHeight > 0 ? flipView: flipClock) ? &whiteRect : &blackRect, "Black", flag);
\r
9548 if (highlight && iconCurrent == iconWhite) {
\r
9549 iconCurrent = iconBlack;
\r
9550 PostMessage(hwndMain, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
9551 if (IsIconic(hwndMain)) {
\r
9552 DrawIcon(hdc, 2, 2, iconCurrent);
\r
9555 (void) ReleaseDC(hwndMain, hdc);
\r
9557 PostMessage(hwndConsole, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
9562 LoadGameTimerRunning()
\r
9564 return loadGameTimerEvent != 0;
\r
9568 StopLoadGameTimer()
\r
9570 if (loadGameTimerEvent == 0) return FALSE;
\r
9571 KillTimer(hwndMain, loadGameTimerEvent);
\r
9572 loadGameTimerEvent = 0;
\r
9577 StartLoadGameTimer(long millisec)
\r
9579 loadGameTimerEvent = SetTimer(hwndMain, (UINT) LOAD_GAME_TIMER_ID,
\r
9580 (UINT) millisec, NULL);
\r
9588 char fileTitle[MSG_SIZ];
\r
9590 defName = DefaultFileName(appData.oldSaveStyle ? "gam" : "pgn");
\r
9591 f = OpenFileDialog(hwndMain, "a", defName,
\r
9592 appData.oldSaveStyle ? "gam" : "pgn",
\r
9594 "Save Game to File", NULL, fileTitle, NULL);
\r
9596 SaveGame(f, 0, "");
\r
9603 ScheduleDelayedEvent(DelayedEventCallback cb, long millisec)
\r
9605 if (delayedTimerEvent != 0) {
\r
9606 if (appData.debugMode) {
\r
9607 fprintf(debugFP, "ScheduleDelayedEvent: event already scheduled\n");
\r
9609 KillTimer(hwndMain, delayedTimerEvent);
\r
9610 delayedTimerEvent = 0;
\r
9611 delayedTimerCallback();
\r
9613 delayedTimerCallback = cb;
\r
9614 delayedTimerEvent = SetTimer(hwndMain, (UINT) DELAYED_TIMER_ID,
\r
9615 (UINT) millisec, NULL);
\r
9618 DelayedEventCallback
\r
9621 if (delayedTimerEvent) {
\r
9622 return delayedTimerCallback;
\r
9629 CancelDelayedEvent()
\r
9631 if (delayedTimerEvent) {
\r
9632 KillTimer(hwndMain, delayedTimerEvent);
\r
9633 delayedTimerEvent = 0;
\r
9637 DWORD GetWin32Priority(int nice)
\r
9638 { // [HGM] nice: translate Unix nice() value to indows priority class. (Code stolen from Polyglot 1.4w11)
\r
9640 REALTIME_PRIORITY_CLASS 0x00000100
\r
9641 HIGH_PRIORITY_CLASS 0x00000080
\r
9642 ABOVE_NORMAL_PRIORITY_CLASS 0x00008000
\r
9643 NORMAL_PRIORITY_CLASS 0x00000020
\r
9644 BELOW_NORMAL_PRIORITY_CLASS 0x00004000
\r
9645 IDLE_PRIORITY_CLASS 0x00000040
\r
9647 if (nice < -15) return 0x00000080;
\r
9648 if (nice < 0) return 0x00008000;
\r
9649 if (nice == 0) return 0x00000020;
\r
9650 if (nice < 15) return 0x00004000;
\r
9651 return 0x00000040;
\r
9654 /* Start a child process running the given program.
\r
9655 The process's standard output can be read from "from", and its
\r
9656 standard input can be written to "to".
\r
9657 Exit with fatal error if anything goes wrong.
\r
9658 Returns an opaque pointer that can be used to destroy the process
\r
9662 StartChildProcess(char *cmdLine, char *dir, ProcRef *pr)
\r
9664 #define BUFSIZE 4096
\r
9666 HANDLE hChildStdinRd, hChildStdinWr,
\r
9667 hChildStdoutRd, hChildStdoutWr;
\r
9668 HANDLE hChildStdinWrDup, hChildStdoutRdDup;
\r
9669 SECURITY_ATTRIBUTES saAttr;
\r
9671 PROCESS_INFORMATION piProcInfo;
\r
9672 STARTUPINFO siStartInfo;
\r
9674 char buf[MSG_SIZ];
\r
9677 if (appData.debugMode) {
\r
9678 fprintf(debugFP, "StartChildProcess (dir=\"%s\") %s\n", dir, cmdLine);
\r
9683 /* Set the bInheritHandle flag so pipe handles are inherited. */
\r
9684 saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
\r
9685 saAttr.bInheritHandle = TRUE;
\r
9686 saAttr.lpSecurityDescriptor = NULL;
\r
9689 * The steps for redirecting child's STDOUT:
\r
9690 * 1. Create anonymous pipe to be STDOUT for child.
\r
9691 * 2. Create a noninheritable duplicate of read handle,
\r
9692 * and close the inheritable read handle.
\r
9695 /* Create a pipe for the child's STDOUT. */
\r
9696 if (! CreatePipe(&hChildStdoutRd, &hChildStdoutWr, &saAttr, 0)) {
\r
9697 return GetLastError();
\r
9700 /* Duplicate the read handle to the pipe, so it is not inherited. */
\r
9701 fSuccess = DuplicateHandle(GetCurrentProcess(), hChildStdoutRd,
\r
9702 GetCurrentProcess(), &hChildStdoutRdDup, 0,
\r
9703 FALSE, /* not inherited */
\r
9704 DUPLICATE_SAME_ACCESS);
\r
9706 return GetLastError();
\r
9708 CloseHandle(hChildStdoutRd);
\r
9711 * The steps for redirecting child's STDIN:
\r
9712 * 1. Create anonymous pipe to be STDIN for child.
\r
9713 * 2. Create a noninheritable duplicate of write handle,
\r
9714 * and close the inheritable write handle.
\r
9717 /* Create a pipe for the child's STDIN. */
\r
9718 if (! CreatePipe(&hChildStdinRd, &hChildStdinWr, &saAttr, 0)) {
\r
9719 return GetLastError();
\r
9722 /* Duplicate the write handle to the pipe, so it is not inherited. */
\r
9723 fSuccess = DuplicateHandle(GetCurrentProcess(), hChildStdinWr,
\r
9724 GetCurrentProcess(), &hChildStdinWrDup, 0,
\r
9725 FALSE, /* not inherited */
\r
9726 DUPLICATE_SAME_ACCESS);
\r
9728 return GetLastError();
\r
9730 CloseHandle(hChildStdinWr);
\r
9732 /* Arrange to (1) look in dir for the child .exe file, and
\r
9733 * (2) have dir be the child's working directory. Interpret
\r
9734 * dir relative to the directory WinBoard loaded from. */
\r
9735 GetCurrentDirectory(MSG_SIZ, buf);
\r
9736 SetCurrentDirectory(installDir);
\r
9737 SetCurrentDirectory(dir);
\r
9739 /* Now create the child process. */
\r
9741 siStartInfo.cb = sizeof(STARTUPINFO);
\r
9742 siStartInfo.lpReserved = NULL;
\r
9743 siStartInfo.lpDesktop = NULL;
\r
9744 siStartInfo.lpTitle = NULL;
\r
9745 siStartInfo.dwFlags = STARTF_USESTDHANDLES;
\r
9746 siStartInfo.cbReserved2 = 0;
\r
9747 siStartInfo.lpReserved2 = NULL;
\r
9748 siStartInfo.hStdInput = hChildStdinRd;
\r
9749 siStartInfo.hStdOutput = hChildStdoutWr;
\r
9750 siStartInfo.hStdError = hChildStdoutWr;
\r
9752 fSuccess = CreateProcess(NULL,
\r
9753 cmdLine, /* command line */
\r
9754 NULL, /* process security attributes */
\r
9755 NULL, /* primary thread security attrs */
\r
9756 TRUE, /* handles are inherited */
\r
9757 DETACHED_PROCESS|CREATE_NEW_PROCESS_GROUP,
\r
9758 NULL, /* use parent's environment */
\r
9760 &siStartInfo, /* STARTUPINFO pointer */
\r
9761 &piProcInfo); /* receives PROCESS_INFORMATION */
\r
9763 err = GetLastError();
\r
9764 SetCurrentDirectory(buf); /* return to prev directory */
\r
9769 if (appData.niceEngines){ // [HGM] nice: adjust engine proc priority
\r
9770 if(appData.debugMode) fprintf(debugFP, "nice engine proc to %d\n", appData.niceEngines);
\r
9771 SetPriorityClass(piProcInfo.hProcess, GetWin32Priority(appData.niceEngines));
\r
9774 /* Close the handles we don't need in the parent */
\r
9775 CloseHandle(piProcInfo.hThread);
\r
9776 CloseHandle(hChildStdinRd);
\r
9777 CloseHandle(hChildStdoutWr);
\r
9779 /* Prepare return value */
\r
9780 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
9781 cp->kind = CPReal;
\r
9782 cp->hProcess = piProcInfo.hProcess;
\r
9783 cp->pid = piProcInfo.dwProcessId;
\r
9784 cp->hFrom = hChildStdoutRdDup;
\r
9785 cp->hTo = hChildStdinWrDup;
\r
9787 *pr = (void *) cp;
\r
9789 /* Klaus Friedel says that this Sleep solves a problem under Windows
\r
9790 2000 where engines sometimes don't see the initial command(s)
\r
9791 from WinBoard and hang. I don't understand how that can happen,
\r
9792 but the Sleep is harmless, so I've put it in. Others have also
\r
9793 reported what may be the same problem, so hopefully this will fix
\r
9794 it for them too. */
\r
9802 DestroyChildProcess(ProcRef pr, int/*boolean*/ signal)
\r
9804 ChildProc *cp; int result;
\r
9806 cp = (ChildProc *) pr;
\r
9807 if (cp == NULL) return;
\r
9809 switch (cp->kind) {
\r
9811 /* TerminateProcess is considered harmful, so... */
\r
9812 CloseHandle(cp->hTo); /* Closing this will give the child an EOF and hopefully kill it */
\r
9813 if (cp->hFrom) CloseHandle(cp->hFrom); /* if NULL, InputThread will close it */
\r
9814 /* The following doesn't work because the chess program
\r
9815 doesn't "have the same console" as WinBoard. Maybe
\r
9816 we could arrange for this even though neither WinBoard
\r
9817 nor the chess program uses a console for stdio? */
\r
9818 /*!!if (signal) GenerateConsoleCtrlEvent(CTRL_BREAK_EVENT, cp->pid);*/
\r
9820 /* [AS] Special termination modes for misbehaving programs... */
\r
9821 if( signal == 9 ) {
\r
9822 result = TerminateProcess( cp->hProcess, 0 );
\r
9824 if ( appData.debugMode) {
\r
9825 fprintf( debugFP, "Terminating process %lu, result=%d\n", cp->pid, result );
\r
9828 else if( signal == 10 ) {
\r
9829 DWORD dw = WaitForSingleObject( cp->hProcess, 3*1000 ); // Wait 3 seconds at most
\r
9831 if( dw != WAIT_OBJECT_0 ) {
\r
9832 result = TerminateProcess( cp->hProcess, 0 );
\r
9834 if ( appData.debugMode) {
\r
9835 fprintf( debugFP, "Process %lu still alive after timeout, killing... result=%d\n", cp->pid, result );
\r
9841 CloseHandle(cp->hProcess);
\r
9845 if (cp->hFrom) CloseHandle(cp->hFrom);
\r
9849 closesocket(cp->sock);
\r
9854 if (signal) send(cp->sock2, "\017", 1, 0); /* 017 = 15 = SIGTERM */
\r
9855 closesocket(cp->sock);
\r
9856 closesocket(cp->sock2);
\r
9864 InterruptChildProcess(ProcRef pr)
\r
9868 cp = (ChildProc *) pr;
\r
9869 if (cp == NULL) return;
\r
9870 switch (cp->kind) {
\r
9872 /* The following doesn't work because the chess program
\r
9873 doesn't "have the same console" as WinBoard. Maybe
\r
9874 we could arrange for this even though neither WinBoard
\r
9875 nor the chess program uses a console for stdio */
\r
9876 /*!!GenerateConsoleCtrlEvent(CTRL_C_EVENT, cp->pid);*/
\r
9881 /* Can't interrupt */
\r
9885 send(cp->sock2, "\002", 1, 0); /* 2 = SIGINT */
\r
9892 OpenTelnet(char *host, char *port, ProcRef *pr)
\r
9894 char cmdLine[MSG_SIZ];
\r
9896 if (port[0] == NULLCHAR) {
\r
9897 sprintf(cmdLine, "%s %s", appData.telnetProgram, host);
\r
9899 sprintf(cmdLine, "%s %s %s", appData.telnetProgram, host, port);
\r
9901 return StartChildProcess(cmdLine, "", pr);
\r
9905 /* Code to open TCP sockets */
\r
9908 OpenTCP(char *host, char *port, ProcRef *pr)
\r
9913 struct sockaddr_in sa, mysa;
\r
9914 struct hostent FAR *hp;
\r
9915 unsigned short uport;
\r
9916 WORD wVersionRequested;
\r
9919 /* Initialize socket DLL */
\r
9920 wVersionRequested = MAKEWORD(1, 1);
\r
9921 err = WSAStartup(wVersionRequested, &wsaData);
\r
9922 if (err != 0) return err;
\r
9925 if ((s = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
\r
9926 err = WSAGetLastError();
\r
9931 /* Bind local address using (mostly) don't-care values.
\r
9933 memset((char *) &mysa, 0, sizeof(struct sockaddr_in));
\r
9934 mysa.sin_family = AF_INET;
\r
9935 mysa.sin_addr.s_addr = INADDR_ANY;
\r
9936 uport = (unsigned short) 0;
\r
9937 mysa.sin_port = htons(uport);
\r
9938 if (bind(s, (struct sockaddr *) &mysa, sizeof(struct sockaddr_in))
\r
9939 == SOCKET_ERROR) {
\r
9940 err = WSAGetLastError();
\r
9945 /* Resolve remote host name */
\r
9946 memset((char *) &sa, 0, sizeof(struct sockaddr_in));
\r
9947 if (!(hp = gethostbyname(host))) {
\r
9948 unsigned int b0, b1, b2, b3;
\r
9950 err = WSAGetLastError();
\r
9952 if (sscanf(host, "%u.%u.%u.%u", &b0, &b1, &b2, &b3) == 4) {
\r
9953 hp = (struct hostent *) calloc(1, sizeof(struct hostent));
\r
9954 hp->h_addrtype = AF_INET;
\r
9956 hp->h_addr_list = (char **) calloc(2, sizeof(char *));
\r
9957 hp->h_addr_list[0] = (char *) malloc(4);
\r
9958 hp->h_addr_list[0][0] = (char) b0;
\r
9959 hp->h_addr_list[0][1] = (char) b1;
\r
9960 hp->h_addr_list[0][2] = (char) b2;
\r
9961 hp->h_addr_list[0][3] = (char) b3;
\r
9967 sa.sin_family = hp->h_addrtype;
\r
9968 uport = (unsigned short) atoi(port);
\r
9969 sa.sin_port = htons(uport);
\r
9970 memcpy((char *) &sa.sin_addr, hp->h_addr, hp->h_length);
\r
9972 /* Make connection */
\r
9973 if (connect(s, (struct sockaddr *) &sa,
\r
9974 sizeof(struct sockaddr_in)) == SOCKET_ERROR) {
\r
9975 err = WSAGetLastError();
\r
9980 /* Prepare return value */
\r
9981 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
9982 cp->kind = CPSock;
\r
9984 *pr = (ProcRef *) cp;
\r
9990 OpenCommPort(char *name, ProcRef *pr)
\r
9995 char fullname[MSG_SIZ];
\r
9997 if (*name != '\\')
\r
9998 sprintf(fullname, "\\\\.\\%s", name);
\r
10000 strcpy(fullname, name);
\r
10002 h = CreateFile(name, GENERIC_READ | GENERIC_WRITE,
\r
10003 0, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
\r
10004 if (h == (HANDLE) -1) {
\r
10005 return GetLastError();
\r
10009 if (!SetCommState(h, (LPDCB) &dcb)) return GetLastError();
\r
10011 /* Accumulate characters until a 100ms pause, then parse */
\r
10012 ct.ReadIntervalTimeout = 100;
\r
10013 ct.ReadTotalTimeoutMultiplier = 0;
\r
10014 ct.ReadTotalTimeoutConstant = 0;
\r
10015 ct.WriteTotalTimeoutMultiplier = 0;
\r
10016 ct.WriteTotalTimeoutConstant = 0;
\r
10017 if (!SetCommTimeouts(h, (LPCOMMTIMEOUTS) &ct)) return GetLastError();
\r
10019 /* Prepare return value */
\r
10020 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
10021 cp->kind = CPComm;
\r
10024 *pr = (ProcRef *) cp;
\r
10030 OpenLoopback(ProcRef *pr)
\r
10032 DisplayFatalError("Not implemented", 0, 1);
\r
10038 OpenRcmd(char* host, char* user, char* cmd, ProcRef* pr)
\r
10042 SOCKET s, s2, s3;
\r
10043 struct sockaddr_in sa, mysa;
\r
10044 struct hostent FAR *hp;
\r
10045 unsigned short uport;
\r
10046 WORD wVersionRequested;
\r
10049 char stderrPortStr[MSG_SIZ];
\r
10051 /* Initialize socket DLL */
\r
10052 wVersionRequested = MAKEWORD(1, 1);
\r
10053 err = WSAStartup(wVersionRequested, &wsaData);
\r
10054 if (err != 0) return err;
\r
10056 /* Resolve remote host name */
\r
10057 memset((char *) &sa, 0, sizeof(struct sockaddr_in));
\r
10058 if (!(hp = gethostbyname(host))) {
\r
10059 unsigned int b0, b1, b2, b3;
\r
10061 err = WSAGetLastError();
\r
10063 if (sscanf(host, "%u.%u.%u.%u", &b0, &b1, &b2, &b3) == 4) {
\r
10064 hp = (struct hostent *) calloc(1, sizeof(struct hostent));
\r
10065 hp->h_addrtype = AF_INET;
\r
10066 hp->h_length = 4;
\r
10067 hp->h_addr_list = (char **) calloc(2, sizeof(char *));
\r
10068 hp->h_addr_list[0] = (char *) malloc(4);
\r
10069 hp->h_addr_list[0][0] = (char) b0;
\r
10070 hp->h_addr_list[0][1] = (char) b1;
\r
10071 hp->h_addr_list[0][2] = (char) b2;
\r
10072 hp->h_addr_list[0][3] = (char) b3;
\r
10078 sa.sin_family = hp->h_addrtype;
\r
10079 uport = (unsigned short) 514;
\r
10080 sa.sin_port = htons(uport);
\r
10081 memcpy((char *) &sa.sin_addr, hp->h_addr, hp->h_length);
\r
10083 /* Bind local socket to unused "privileged" port address
\r
10085 s = INVALID_SOCKET;
\r
10086 memset((char *) &mysa, 0, sizeof(struct sockaddr_in));
\r
10087 mysa.sin_family = AF_INET;
\r
10088 mysa.sin_addr.s_addr = INADDR_ANY;
\r
10089 for (fromPort = 1023;; fromPort--) {
\r
10090 if (fromPort < 0) {
\r
10092 return WSAEADDRINUSE;
\r
10094 if (s == INVALID_SOCKET) {
\r
10095 if ((s = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
\r
10096 err = WSAGetLastError();
\r
10101 uport = (unsigned short) fromPort;
\r
10102 mysa.sin_port = htons(uport);
\r
10103 if (bind(s, (struct sockaddr *) &mysa, sizeof(struct sockaddr_in))
\r
10104 == SOCKET_ERROR) {
\r
10105 err = WSAGetLastError();
\r
10106 if (err == WSAEADDRINUSE) continue;
\r
10110 if (connect(s, (struct sockaddr *) &sa,
\r
10111 sizeof(struct sockaddr_in)) == SOCKET_ERROR) {
\r
10112 err = WSAGetLastError();
\r
10113 if (err == WSAEADDRINUSE) {
\r
10124 /* Bind stderr local socket to unused "privileged" port address
\r
10126 s2 = INVALID_SOCKET;
\r
10127 memset((char *) &mysa, 0, sizeof(struct sockaddr_in));
\r
10128 mysa.sin_family = AF_INET;
\r
10129 mysa.sin_addr.s_addr = INADDR_ANY;
\r
10130 for (fromPort = 1023;; fromPort--) {
\r
10131 if (fromPort == prevStderrPort) continue; // don't reuse port
\r
10132 if (fromPort < 0) {
\r
10133 (void) closesocket(s);
\r
10135 return WSAEADDRINUSE;
\r
10137 if (s2 == INVALID_SOCKET) {
\r
10138 if ((s2 = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
\r
10139 err = WSAGetLastError();
\r
10145 uport = (unsigned short) fromPort;
\r
10146 mysa.sin_port = htons(uport);
\r
10147 if (bind(s2, (struct sockaddr *) &mysa, sizeof(struct sockaddr_in))
\r
10148 == SOCKET_ERROR) {
\r
10149 err = WSAGetLastError();
\r
10150 if (err == WSAEADDRINUSE) continue;
\r
10151 (void) closesocket(s);
\r
10155 if (listen(s2, 1) == SOCKET_ERROR) {
\r
10156 err = WSAGetLastError();
\r
10157 if (err == WSAEADDRINUSE) {
\r
10159 s2 = INVALID_SOCKET;
\r
10162 (void) closesocket(s);
\r
10163 (void) closesocket(s2);
\r
10169 prevStderrPort = fromPort; // remember port used
\r
10170 sprintf(stderrPortStr, "%d", fromPort);
\r
10172 if (send(s, stderrPortStr, strlen(stderrPortStr) + 1, 0) == SOCKET_ERROR) {
\r
10173 err = WSAGetLastError();
\r
10174 (void) closesocket(s);
\r
10175 (void) closesocket(s2);
\r
10180 if (send(s, UserName(), strlen(UserName()) + 1, 0) == SOCKET_ERROR) {
\r
10181 err = WSAGetLastError();
\r
10182 (void) closesocket(s);
\r
10183 (void) closesocket(s2);
\r
10187 if (*user == NULLCHAR) user = UserName();
\r
10188 if (send(s, user, strlen(user) + 1, 0) == SOCKET_ERROR) {
\r
10189 err = WSAGetLastError();
\r
10190 (void) closesocket(s);
\r
10191 (void) closesocket(s2);
\r
10195 if (send(s, cmd, strlen(cmd) + 1, 0) == SOCKET_ERROR) {
\r
10196 err = WSAGetLastError();
\r
10197 (void) closesocket(s);
\r
10198 (void) closesocket(s2);
\r
10203 if ((s3 = accept(s2, NULL, NULL)) == INVALID_SOCKET) {
\r
10204 err = WSAGetLastError();
\r
10205 (void) closesocket(s);
\r
10206 (void) closesocket(s2);
\r
10210 (void) closesocket(s2); /* Stop listening */
\r
10212 /* Prepare return value */
\r
10213 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
10214 cp->kind = CPRcmd;
\r
10217 *pr = (ProcRef *) cp;
\r
10224 AddInputSource(ProcRef pr, int lineByLine,
\r
10225 InputCallback func, VOIDSTAR closure)
\r
10227 InputSource *is, *is2 = NULL;
\r
10228 ChildProc *cp = (ChildProc *) pr;
\r
10230 is = (InputSource *) calloc(1, sizeof(InputSource));
\r
10231 is->lineByLine = lineByLine;
\r
10233 is->closure = closure;
\r
10234 is->second = NULL;
\r
10235 is->next = is->buf;
\r
10236 if (pr == NoProc) {
\r
10237 is->kind = CPReal;
\r
10238 consoleInputSource = is;
\r
10240 is->kind = cp->kind;
\r
10242 [AS] Try to avoid a race condition if the thread is given control too early:
\r
10243 we create all threads suspended so that the is->hThread variable can be
\r
10244 safely assigned, then let the threads start with ResumeThread.
\r
10246 switch (cp->kind) {
\r
10248 is->hFile = cp->hFrom;
\r
10249 cp->hFrom = NULL; /* now owned by InputThread */
\r
10251 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) NonOvlInputThread,
\r
10252 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
10256 is->hFile = cp->hFrom;
\r
10257 cp->hFrom = NULL; /* now owned by InputThread */
\r
10259 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) InputThread,
\r
10260 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
10264 is->sock = cp->sock;
\r
10266 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SocketInputThread,
\r
10267 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
10271 is2 = (InputSource *) calloc(1, sizeof(InputSource));
\r
10273 is->sock = cp->sock;
\r
10274 is->second = is2;
\r
10275 is2->sock = cp->sock2;
\r
10276 is2->second = is2;
\r
10278 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SocketInputThread,
\r
10279 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
10281 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SocketInputThread,
\r
10282 (LPVOID) is2, CREATE_SUSPENDED, &is2->id);
\r
10286 if( is->hThread != NULL ) {
\r
10287 ResumeThread( is->hThread );
\r
10290 if( is2 != NULL && is2->hThread != NULL ) {
\r
10291 ResumeThread( is2->hThread );
\r
10295 return (InputSourceRef) is;
\r
10299 RemoveInputSource(InputSourceRef isr)
\r
10303 is = (InputSource *) isr;
\r
10304 is->hThread = NULL; /* tell thread to stop */
\r
10305 CloseHandle(is->hThread);
\r
10306 if (is->second != NULL) {
\r
10307 is->second->hThread = NULL;
\r
10308 CloseHandle(is->second->hThread);
\r
10314 OutputToProcess(ProcRef pr, char *message, int count, int *outError)
\r
10317 int outCount = SOCKET_ERROR;
\r
10318 ChildProc *cp = (ChildProc *) pr;
\r
10319 static OVERLAPPED ovl;
\r
10321 if (pr == NoProc) {
\r
10322 ConsoleOutput(message, count, FALSE);
\r
10326 if (ovl.hEvent == NULL) {
\r
10327 ovl.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
\r
10329 ovl.Internal = ovl.InternalHigh = ovl.Offset = ovl.OffsetHigh = 0;
\r
10331 switch (cp->kind) {
\r
10334 outCount = send(cp->sock, message, count, 0);
\r
10335 if (outCount == SOCKET_ERROR) {
\r
10336 *outError = WSAGetLastError();
\r
10338 *outError = NO_ERROR;
\r
10343 if (WriteFile(((ChildProc *)pr)->hTo, message, count,
\r
10344 &dOutCount, NULL)) {
\r
10345 *outError = NO_ERROR;
\r
10346 outCount = (int) dOutCount;
\r
10348 *outError = GetLastError();
\r
10353 *outError = DoWriteFile(((ChildProc *)pr)->hTo, message, count,
\r
10354 &dOutCount, &ovl);
\r
10355 if (*outError == NO_ERROR) {
\r
10356 outCount = (int) dOutCount;
\r
10364 OutputToProcessDelayed(ProcRef pr, char *message, int count, int *outError,
\r
10367 /* Ignore delay, not implemented for WinBoard */
\r
10368 return OutputToProcess(pr, message, count, outError);
\r
10373 CmailSigHandlerCallBack(InputSourceRef isr, VOIDSTAR closure,
\r
10374 char *buf, int count, int error)
\r
10376 DisplayFatalError("Not implemented", 0, 1);
\r
10379 /* see wgamelist.c for Game List functions */
\r
10380 /* see wedittags.c for Edit Tags functions */
\r
10387 char buf[MSG_SIZ];
\r
10390 if (SearchPath(installDir, appData.icsLogon, NULL, MSG_SIZ, buf, &dummy)) {
\r
10391 f = fopen(buf, "r");
\r
10393 ProcessICSInitScript(f);
\r
10401 StartAnalysisClock()
\r
10403 if (analysisTimerEvent) return;
\r
10404 analysisTimerEvent = SetTimer(hwndMain, (UINT) ANALYSIS_TIMER_ID,
\r
10405 (UINT) 2000, NULL);
\r
10409 AnalysisDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
10411 static HANDLE hwndText;
\r
10413 static int sizeX, sizeY;
\r
10414 int newSizeX, newSizeY, flags;
\r
10417 switch (message) {
\r
10418 case WM_INITDIALOG: /* message: initialize dialog box */
\r
10419 /* Initialize the dialog items */
\r
10420 hwndText = GetDlgItem(hDlg, OPT_AnalysisText);
\r
10421 SetWindowText(hDlg, analysisTitle);
\r
10422 SetDlgItemText(hDlg, OPT_AnalysisText, analysisText);
\r
10423 /* Size and position the dialog */
\r
10424 if (!analysisDialog) {
\r
10425 analysisDialog = hDlg;
\r
10426 flags = SWP_NOZORDER;
\r
10427 GetClientRect(hDlg, &rect);
\r
10428 sizeX = rect.right;
\r
10429 sizeY = rect.bottom;
\r
10430 if (analysisX != CW_USEDEFAULT && analysisY != CW_USEDEFAULT &&
\r
10431 analysisW != CW_USEDEFAULT && analysisH != CW_USEDEFAULT) {
\r
10432 WINDOWPLACEMENT wp;
\r
10433 EnsureOnScreen(&analysisX, &analysisY);
\r
10434 wp.length = sizeof(WINDOWPLACEMENT);
\r
10436 wp.showCmd = SW_SHOW;
\r
10437 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
10438 wp.rcNormalPosition.left = analysisX;
\r
10439 wp.rcNormalPosition.right = analysisX + analysisW;
\r
10440 wp.rcNormalPosition.top = analysisY;
\r
10441 wp.rcNormalPosition.bottom = analysisY + analysisH;
\r
10442 SetWindowPlacement(hDlg, &wp);
\r
10444 GetClientRect(hDlg, &rect);
\r
10445 newSizeX = rect.right;
\r
10446 newSizeY = rect.bottom;
\r
10447 ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY,
\r
10448 newSizeX, newSizeY);
\r
10449 sizeX = newSizeX;
\r
10450 sizeY = newSizeY;
\r
10455 case WM_COMMAND: /* message: received a command */
\r
10456 switch (LOWORD(wParam)) {
\r
10458 if (appData.icsActive && appData.icsEngineAnalyze) { /* [DM] icsEngineAnalyze */
\r
10459 ExitAnalyzeMode();
\r
10471 newSizeX = LOWORD(lParam);
\r
10472 newSizeY = HIWORD(lParam);
\r
10473 ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY, newSizeX, newSizeY);
\r
10474 sizeX = newSizeX;
\r
10475 sizeY = newSizeY;
\r
10478 case WM_GETMINMAXINFO:
\r
10479 /* Prevent resizing window too small */
\r
10480 mmi = (MINMAXINFO *) lParam;
\r
10481 mmi->ptMinTrackSize.x = 100;
\r
10482 mmi->ptMinTrackSize.y = 100;
\r
10489 AnalysisPopUp(char* title, char* str)
\r
10495 EngineOutputPopUp();
\r
10498 if (str == NULL) str = "";
\r
10499 p = (char *) malloc(2 * strlen(str) + 2);
\r
10502 if (*str == '\n') *q++ = '\r';
\r
10506 if (analysisText != NULL) free(analysisText);
\r
10507 analysisText = p;
\r
10509 if (analysisDialog) {
\r
10510 SetWindowText(analysisDialog, title);
\r
10511 SetDlgItemText(analysisDialog, OPT_AnalysisText, analysisText);
\r
10512 ShowWindow(analysisDialog, SW_SHOW);
\r
10514 analysisTitle = title;
\r
10515 lpProc = MakeProcInstance((FARPROC)AnalysisDialog, hInst);
\r
10516 CreateDialog(hInst, MAKEINTRESOURCE(DLG_Analysis),
\r
10517 hwndMain, (DLGPROC)lpProc);
\r
10518 FreeProcInstance(lpProc);
\r
10520 analysisDialogUp = TRUE;
\r
10524 AnalysisPopDown()
\r
10526 if (analysisDialog) {
\r
10527 ShowWindow(analysisDialog, SW_HIDE);
\r
10529 analysisDialogUp = FALSE;
\r
10534 SetHighlights(int fromX, int fromY, int toX, int toY)
\r
10536 highlightInfo.sq[0].x = fromX;
\r
10537 highlightInfo.sq[0].y = fromY;
\r
10538 highlightInfo.sq[1].x = toX;
\r
10539 highlightInfo.sq[1].y = toY;
\r
10543 ClearHighlights()
\r
10545 highlightInfo.sq[0].x = highlightInfo.sq[0].y =
\r
10546 highlightInfo.sq[1].x = highlightInfo.sq[1].y = -1;
\r
10550 SetPremoveHighlights(int fromX, int fromY, int toX, int toY)
\r
10552 premoveHighlightInfo.sq[0].x = fromX;
\r
10553 premoveHighlightInfo.sq[0].y = fromY;
\r
10554 premoveHighlightInfo.sq[1].x = toX;
\r
10555 premoveHighlightInfo.sq[1].y = toY;
\r
10559 ClearPremoveHighlights()
\r
10561 premoveHighlightInfo.sq[0].x = premoveHighlightInfo.sq[0].y =
\r
10562 premoveHighlightInfo.sq[1].x = premoveHighlightInfo.sq[1].y = -1;
\r
10566 ShutDownFrontEnd()
\r
10568 if (saveSettingsOnExit) SaveSettings(settingsFileName);
\r
10569 DeleteClipboardTempFiles();
\r
10575 if (IsIconic(hwndMain))
\r
10576 ShowWindow(hwndMain, SW_RESTORE);
\r
10578 SetActiveWindow(hwndMain);
\r
10582 * Prototypes for animation support routines
\r
10584 static void ScreenSquare(int column, int row, POINT * pt);
\r
10585 static void Tween( POINT * start, POINT * mid, POINT * finish, int factor,
\r
10586 POINT frames[], int * nFrames);
\r
10590 AnimateAtomicCapture(int toX, int toY, int nFrames)
\r
10591 { // [HGM] atomic: animate blast wave
\r
10593 if(appData.debugMode) fprintf(debugFP, "exploding (%d,%d)\n", toX, toY);
\r
10594 explodeInfo.x = toX;
\r
10595 explodeInfo.y = toY;
\r
10596 for(i=0; i<nFrames; i++) {
\r
10597 explodeInfo.radius = (i*180)/(nFrames-1);
\r
10598 DrawPosition(FALSE, NULL);
\r
10599 Sleep(appData.animSpeed);
\r
10601 explodeInfo.radius = 0;
\r
10602 DrawPosition(TRUE, NULL);
\r
10605 #define kFactor 4
\r
10608 AnimateMove(board, fromX, fromY, toX, toY)
\r
10615 ChessSquare piece;
\r
10616 POINT start, finish, mid;
\r
10617 POINT frames[kFactor * 2 + 1];
\r
10620 if (!appData.animate) return;
\r
10621 if (doingSizing) return;
\r
10622 if (fromY < 0 || fromX < 0) return;
\r
10623 piece = board[fromY][fromX];
\r
10624 if (piece >= EmptySquare) return;
\r
10626 ScreenSquare(fromX, fromY, &start);
\r
10627 ScreenSquare(toX, toY, &finish);
\r
10629 /* All pieces except knights move in straight line */
\r
10630 if (piece != WhiteKnight && piece != BlackKnight) {
\r
10631 mid.x = start.x + (finish.x - start.x) / 2;
\r
10632 mid.y = start.y + (finish.y - start.y) / 2;
\r
10634 /* Knight: make diagonal movement then straight */
\r
10635 if (abs(toY - fromY) < abs(toX - fromX)) {
\r
10636 mid.x = start.x + (finish.x - start.x) / 2;
\r
10637 mid.y = finish.y;
\r
10639 mid.x = finish.x;
\r
10640 mid.y = start.y + (finish.y - start.y) / 2;
\r
10644 /* Don't use as many frames for very short moves */
\r
10645 if (abs(toY - fromY) + abs(toX - fromX) <= 2)
\r
10646 Tween(&start, &mid, &finish, kFactor - 1, frames, &nFrames);
\r
10648 Tween(&start, &mid, &finish, kFactor, frames, &nFrames);
\r
10650 animInfo.from.x = fromX;
\r
10651 animInfo.from.y = fromY;
\r
10652 animInfo.to.x = toX;
\r
10653 animInfo.to.y = toY;
\r
10654 animInfo.lastpos = start;
\r
10655 animInfo.piece = piece;
\r
10656 for (n = 0; n < nFrames; n++) {
\r
10657 animInfo.pos = frames[n];
\r
10658 DrawPosition(FALSE, NULL);
\r
10659 animInfo.lastpos = animInfo.pos;
\r
10660 Sleep(appData.animSpeed);
\r
10662 animInfo.pos = finish;
\r
10663 DrawPosition(FALSE, NULL);
\r
10664 animInfo.piece = EmptySquare;
\r
10665 if(gameInfo.variant == VariantAtomic && board[toY][toX] != EmptySquare)
\r
10666 AnimateAtomicCapture(toX, toY, 2*nFrames);
\r
10669 /* Convert board position to corner of screen rect and color */
\r
10672 ScreenSquare(column, row, pt)
\r
10673 int column; int row; POINT * pt;
\r
10676 pt->x = lineGap + ((BOARD_WIDTH-1)-column) * (squareSize + lineGap);
\r
10677 pt->y = lineGap + row * (squareSize + lineGap);
\r
10679 pt->x = lineGap + column * (squareSize + lineGap);
\r
10680 pt->y = lineGap + ((BOARD_HEIGHT-1)-row) * (squareSize + lineGap);
\r
10684 /* Generate a series of frame coords from start->mid->finish.
\r
10685 The movement rate doubles until the half way point is
\r
10686 reached, then halves back down to the final destination,
\r
10687 which gives a nice slow in/out effect. The algorithmn
\r
10688 may seem to generate too many intermediates for short
\r
10689 moves, but remember that the purpose is to attract the
\r
10690 viewers attention to the piece about to be moved and
\r
10691 then to where it ends up. Too few frames would be less
\r
10695 Tween(start, mid, finish, factor, frames, nFrames)
\r
10696 POINT * start; POINT * mid;
\r
10697 POINT * finish; int factor;
\r
10698 POINT frames[]; int * nFrames;
\r
10700 int n, fraction = 1, count = 0;
\r
10702 /* Slow in, stepping 1/16th, then 1/8th, ... */
\r
10703 for (n = 0; n < factor; n++)
\r
10705 for (n = 0; n < factor; n++) {
\r
10706 frames[count].x = start->x + (mid->x - start->x) / fraction;
\r
10707 frames[count].y = start->y + (mid->y - start->y) / fraction;
\r
10709 fraction = fraction / 2;
\r
10713 frames[count] = *mid;
\r
10716 /* Slow out, stepping 1/2, then 1/4, ... */
\r
10718 for (n = 0; n < factor; n++) {
\r
10719 frames[count].x = finish->x - (finish->x - mid->x) / fraction;
\r
10720 frames[count].y = finish->y - (finish->y - mid->y) / fraction;
\r
10722 fraction = fraction * 2;
\r
10724 *nFrames = count;
\r
10728 HistorySet( char movelist[][2*MOVE_LEN], int first, int last, int current )
\r
10733 sprintf( buf, "HistorySet: first=%d, last=%d, current=%d (%s)\n",
\r
10734 first, last, current, current >= 0 ? movelist[current] : "n/a" );
\r
10736 OutputDebugString( buf );
\r
10739 MoveHistorySet( movelist, first, last, current, pvInfoList );
\r
10741 EvalGraphSet( first, last, current, pvInfoList );
\r
10744 void SetProgramStats( FrontEndProgramStats * stats )
\r
10749 sprintf( buf, "SetStats for %d: depth=%d, nodes=%lu, score=%5.2f, time=%5.2f, pv=%s\n",
\r
10750 stats->which, stats->depth, stats->nodes, stats->score / 100.0, stats->time / 100.0, stats->pv == 0 ? "n/a" : stats->pv );
\r
10752 OutputDebugString( buf );
\r
10755 EngineOutputUpdate( stats );
\r