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 /* Slight kludge. The real problem is that after AnimateMove is
\r
4485 done, the position on the screen does not match lastDrawn.
\r
4486 This currently causes trouble only on e.p. captures in
\r
4487 atomic, where the piece moves to an empty square and then
\r
4488 explodes. The old and new positions both had an empty square
\r
4489 at the destination, but animation has drawn a piece there and
\r
4490 we have to remember to erase it. [HGM] moved until after setting lastDrawn */
\r
4491 lastDrawn[animInfo.to.y][animInfo.to.x] = animInfo.piece;
\r
4495 /* No clips? Make sure we have fullrepaint set to TRUE */
\r
4496 if (num_clips == 0)
\r
4497 fullrepaint = TRUE;
\r
4499 /* Set clipping on the memory DC */
\r
4500 if (!fullrepaint) {
\r
4501 SelectClipRgn(hdcmem, clips[0]);
\r
4502 for (x = 1; x < num_clips; x++) {
\r
4503 if (ExtSelectClipRgn(hdcmem, clips[x], RGN_OR) == ERROR)
\r
4504 abort(); // this should never ever happen!
\r
4508 /* Do all the drawing to the memory DC */
\r
4509 if(explodeInfo.radius) { // [HGM] atomic
\r
4511 int x, y, r=(explodeInfo.radius * squareSize)/100;
\r
4512 SquareToPos(explodeInfo.y, explodeInfo.x, &x, &y);
\r
4513 x += squareSize/2;
\r
4514 y += squareSize/2;
\r
4515 if(!fullrepaint) {
\r
4516 clips[num_clips] = CreateRectRgn(x-r, y-r, x+r, y+r);
\r
4517 ExtSelectClipRgn(hdcmem, clips[num_clips++], RGN_OR);
\r
4519 DrawGridOnDC(hdcmem);
\r
4520 DrawHighlightsOnDC(hdcmem);
\r
4521 DrawBoardOnDC(hdcmem, board, tmphdc);
\r
4522 oldBrush = SelectObject(hdcmem, explodeBrush);
\r
4523 Ellipse(hdcmem, x-r, y-r, x+r, y+r);
\r
4524 SelectObject(hdcmem, oldBrush);
\r
4526 DrawGridOnDC(hdcmem);
\r
4527 DrawHighlightsOnDC(hdcmem);
\r
4528 DrawBoardOnDC(hdcmem, board, tmphdc);
\r
4531 DrawLogoOnDC(hdc, leftLogoRect, flipClock ? &second : &first);
\r
4532 DrawLogoOnDC(hdc, rightLogoRect, flipClock ? &first : &second);
\r
4535 if( appData.highlightMoveWithArrow ) {
\r
4536 DrawArrowHighlight(hdcmem);
\r
4539 DrawCoordsOnDC(hdcmem);
\r
4541 CopyBoard(lastDrawn, board); /* [HGM] Moved to here from end of routine, */
\r
4542 /* to make sure lastDrawn contains what is actually drawn */
\r
4544 /* Put the dragged piece back into place and draw it (out of place!) */
\r
4545 if (dragged_piece != EmptySquare) {
\r
4546 /* [HGM] or restack */
\r
4547 if(dragInfo.from.x == BOARD_LEFT-2 )
\r
4548 board[dragInfo.from.y][dragInfo.from.x+1]++;
\r
4550 if(dragInfo.from.x == BOARD_RGHT+1 )
\r
4551 board[dragInfo.from.y][dragInfo.from.x-1]++;
\r
4552 board[dragInfo.from.y][dragInfo.from.x] = dragged_piece;
\r
4553 x = dragInfo.pos.x - squareSize / 2;
\r
4554 y = dragInfo.pos.y - squareSize / 2;
\r
4555 DrawPieceOnDC(hdcmem, dragged_piece,
\r
4556 ((int) dragged_piece < (int) BlackPawn),
\r
4557 (dragInfo.from.y + dragInfo.from.x) % 2, x, y, tmphdc);
\r
4560 /* Put the animated piece back into place and draw it */
\r
4561 if (animInfo.piece != EmptySquare) {
\r
4562 board[animInfo.from.y][animInfo.from.x] = animInfo.piece;
\r
4563 x = boardRect.left + animInfo.pos.x;
\r
4564 y = boardRect.top + animInfo.pos.y;
\r
4565 DrawPieceOnDC(hdcmem, animInfo.piece,
\r
4566 ((int) animInfo.piece < (int) BlackPawn),
\r
4567 (animInfo.from.y + animInfo.from.x) % 2, x, y, tmphdc);
\r
4570 /* Release the bufferBitmap by selecting in the old bitmap
\r
4571 * and delete the memory DC
\r
4573 SelectObject(hdcmem, oldBitmap);
\r
4576 /* Set clipping on the target DC */
\r
4577 if (!fullrepaint) {
\r
4578 SelectClipRgn(hdc, clips[0]);
\r
4579 for (x = 1; x < num_clips; x++) {
\r
4580 if (ExtSelectClipRgn(hdc, clips[x], RGN_OR) == ERROR)
\r
4581 abort(); // this should never ever happen!
\r
4585 /* Copy the new bitmap onto the screen in one go.
\r
4586 * This way we avoid any flickering
\r
4588 oldBitmap = SelectObject(tmphdc, bufferBitmap);
\r
4589 BitBlt(hdc, boardRect.left, boardRect.top,
\r
4590 boardRect.right - boardRect.left,
\r
4591 boardRect.bottom - boardRect.top,
\r
4592 tmphdc, boardRect.left, boardRect.top, SRCCOPY);
\r
4593 if(saveDiagFlag) {
\r
4594 BITMAP b; int i, j=0, m, w, wb, fac=0; char pData[1000000];
\r
4595 BITMAPINFOHEADER bih; int color[16], nrColors=0;
\r
4597 GetObject(bufferBitmap, sizeof(b), &b);
\r
4598 if(b.bmWidthBytes*b.bmHeight <= 990000) {
\r
4599 bih.biSize = sizeof(BITMAPINFOHEADER);
\r
4600 bih.biWidth = b.bmWidth;
\r
4601 bih.biHeight = b.bmHeight;
\r
4603 bih.biBitCount = b.bmBitsPixel;
\r
4604 bih.biCompression = 0;
\r
4605 bih.biSizeImage = b.bmWidthBytes*b.bmHeight;
\r
4606 bih.biXPelsPerMeter = 0;
\r
4607 bih.biYPelsPerMeter = 0;
\r
4608 bih.biClrUsed = 0;
\r
4609 bih.biClrImportant = 0;
\r
4610 // fprintf(diagFile, "t=%d\nw=%d\nh=%d\nB=%d\nP=%d\nX=%d\n",
\r
4611 // b.bmType, b.bmWidth, b.bmHeight, b.bmWidthBytes, b.bmPlanes, b.bmBitsPixel);
\r
4612 GetDIBits(tmphdc,bufferBitmap,0,b.bmHeight,pData,(BITMAPINFO*)&bih,DIB_RGB_COLORS);
\r
4613 // fprintf(diagFile, "%8x\n", (int) pData);
\r
4616 wb = b.bmWidthBytes;
\r
4618 for(i=0; i<wb*(b.bmHeight - boardRect.top + OUTER_MARGIN)>>2; i++) {
\r
4619 int k = ((int*) pData)[i];
\r
4620 for(j=0; j<nrColors; j++) if(color[j] == k) break;
\r
4621 if(j >= 16) break;
\r
4623 if(j >= nrColors) nrColors = j+1;
\r
4625 if(j<16) { // 16 colors is enough. Compress to 4 bits per pixel
\r
4627 for(i=0; i<b.bmHeight - boardRect.top + OUTER_MARGIN; i++) {
\r
4628 for(w=0; w<(wb>>2); w+=2) {
\r
4629 int k = ((int*) pData)[(wb*i>>2) + w];
\r
4630 for(j=0; j<nrColors; j++) if(color[j] == k) break;
\r
4631 k = ((int*) pData)[(wb*i>>2) + w + 1];
\r
4632 for(m=0; m<nrColors; m++) if(color[m] == k) break;
\r
4633 pData[p++] = m | j<<4;
\r
4635 while(p&3) pData[p++] = 0;
\r
4638 wb = ((wb+31)>>5)<<2;
\r
4640 // write BITMAPFILEHEADER
\r
4641 fprintf(diagFile, "BM");
\r
4642 fputDW(diagFile, wb*(b.bmHeight - boardRect.top + OUTER_MARGIN)+0x36 + (fac?64:0));
\r
4643 fputDW(diagFile, 0);
\r
4644 fputDW(diagFile, 0x36 + (fac?64:0));
\r
4645 // write BITMAPINFOHEADER
\r
4646 fputDW(diagFile, 40);
\r
4647 fputDW(diagFile, b.bmWidth);
\r
4648 fputDW(diagFile, b.bmHeight - boardRect.top + OUTER_MARGIN);
\r
4649 if(fac) fputDW(diagFile, 0x040001); // planes and bits/pixel
\r
4650 else fputDW(diagFile, 0x200001); // planes and bits/pixel
\r
4651 fputDW(diagFile, 0);
\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 // write color table
\r
4659 for(i=0; i<16; i++) fputDW(diagFile, color[i]);
\r
4660 // write bitmap data
\r
4661 for(i=0; i<wb*(b.bmHeight - boardRect.top + OUTER_MARGIN); i++)
\r
4662 fputc(pData[i], diagFile);
\r
4667 SelectObject(tmphdc, oldBitmap);
\r
4669 /* Massive cleanup */
\r
4670 for (x = 0; x < num_clips; x++)
\r
4671 DeleteObject(clips[x]);
\r
4674 DeleteObject(bufferBitmap);
\r
4677 ReleaseDC(hwndMain, hdc);
\r
4679 if (lastDrawnFlipView != flipView) {
\r
4681 CheckMenuItem(GetMenu(hwndMain),IDM_FlipView, MF_BYCOMMAND|MF_CHECKED);
\r
4683 CheckMenuItem(GetMenu(hwndMain),IDM_FlipView, MF_BYCOMMAND|MF_UNCHECKED);
\r
4686 /* CopyBoard(lastDrawn, board);*/
\r
4687 lastDrawnHighlight = highlightInfo;
\r
4688 lastDrawnPremove = premoveHighlightInfo;
\r
4689 lastDrawnFlipView = flipView;
\r
4690 lastDrawnValid = 1;
\r
4693 /* [HGM] diag: Save the current board display to the given open file and close the file */
\r
4698 saveDiagFlag = 1; diagFile = f;
\r
4699 HDCDrawPosition(NULL, TRUE, NULL);
\r
4703 // if(f != NULL) fprintf(f, "Sorry, but this feature is still in preparation\n");
\r
4710 /*---------------------------------------------------------------------------*\
\r
4711 | CLIENT PAINT PROCEDURE
\r
4712 | This is the main event-handler for the WM_PAINT message.
\r
4714 \*---------------------------------------------------------------------------*/
\r
4716 PaintProc(HWND hwnd)
\r
4722 if((hdc = BeginPaint(hwnd, &ps))) {
\r
4723 if (IsIconic(hwnd)) {
\r
4724 DrawIcon(hdc, 2, 2, iconCurrent);
\r
4726 if (!appData.monoMode) {
\r
4727 SelectPalette(hdc, hPal, FALSE);
\r
4728 RealizePalette(hdc);
\r
4730 HDCDrawPosition(hdc, 1, NULL);
\r
4732 SelectObject(hdc, font[boardSize][MESSAGE_FONT]->hf);
\r
4733 ExtTextOut(hdc, messageRect.left, messageRect.top,
\r
4734 ETO_CLIPPED|ETO_OPAQUE,
\r
4735 &messageRect, messageText, strlen(messageText), NULL);
\r
4736 SelectObject(hdc, oldFont);
\r
4737 DisplayBothClocks();
\r
4739 EndPaint(hwnd,&ps);
\r
4747 * If the user selects on a border boundary, return -1; if off the board,
\r
4748 * return -2. Otherwise map the event coordinate to the square.
\r
4749 * The offset boardRect.left or boardRect.top must already have been
\r
4750 * subtracted from x.
\r
4753 EventToSquare(int x)
\r
4760 if ((x % (squareSize + lineGap)) >= squareSize)
\r
4762 x /= (squareSize + lineGap);
\r
4763 if (x >= BOARD_SIZE)
\r
4774 DropEnable dropEnables[] = {
\r
4775 { 'P', DP_Pawn, "Pawn" },
\r
4776 { 'N', DP_Knight, "Knight" },
\r
4777 { 'B', DP_Bishop, "Bishop" },
\r
4778 { 'R', DP_Rook, "Rook" },
\r
4779 { 'Q', DP_Queen, "Queen" },
\r
4783 SetupDropMenu(HMENU hmenu)
\r
4785 int i, count, enable;
\r
4787 extern char white_holding[], black_holding[];
\r
4788 char item[MSG_SIZ];
\r
4790 for (i=0; i<sizeof(dropEnables)/sizeof(DropEnable); i++) {
\r
4791 p = strchr(gameMode == IcsPlayingWhite ? white_holding : black_holding,
\r
4792 dropEnables[i].piece);
\r
4794 while (p && *p++ == dropEnables[i].piece) count++;
\r
4795 sprintf(item, "%s %d", dropEnables[i].name, count);
\r
4796 enable = count > 0 || !appData.testLegality
\r
4797 /*!!temp:*/ || (gameInfo.variant == VariantCrazyhouse
\r
4798 && !appData.icsActive);
\r
4799 ModifyMenu(hmenu, dropEnables[i].command,
\r
4800 MF_BYCOMMAND | (enable ? MF_ENABLED : MF_GRAYED) | MF_STRING,
\r
4801 dropEnables[i].command, item);
\r
4805 static int fromX = -1, fromY = -1, toX, toY;
\r
4807 /* Event handler for mouse messages */
\r
4809 MouseEvent(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
4813 static int recursive = 0;
\r
4815 // BOOLEAN needsRedraw = FALSE;
\r
4816 BOOLEAN saveAnimate;
\r
4817 BOOLEAN forceFullRepaint = IsFullRepaintPreferrable(); /* [AS] */
\r
4818 static BOOLEAN sameAgain = FALSE, promotionChoice = FALSE;
\r
4819 ChessMove moveType;
\r
4822 if (message == WM_MBUTTONUP) {
\r
4823 /* Hideous kludge to fool TrackPopupMenu into paying attention
\r
4824 to the middle button: we simulate pressing the left button too!
\r
4826 PostMessage(hwnd, WM_LBUTTONDOWN, wParam, lParam);
\r
4827 PostMessage(hwnd, WM_LBUTTONUP, wParam, lParam);
\r
4833 pt.x = LOWORD(lParam);
\r
4834 pt.y = HIWORD(lParam);
\r
4835 x = EventToSquare(pt.x - boardRect.left);
\r
4836 y = EventToSquare(pt.y - boardRect.top);
\r
4837 if (!flipView && y >= 0) {
\r
4838 y = BOARD_HEIGHT - 1 - y;
\r
4840 if (flipView && x >= 0) {
\r
4841 x = BOARD_WIDTH - 1 - x;
\r
4844 switch (message) {
\r
4845 case WM_LBUTTONDOWN:
\r
4846 if(promotionChoice) { // we are waiting for a click to indicate promotion piece
\r
4847 promotionChoice = FALSE; // only one chance: if click not OK it is interpreted as cancel
\r
4848 if(appData.debugMode) fprintf(debugFP, "promotion click, x=%d, y=%d\n", x, y);
\r
4849 if(gameInfo.holdingsWidth &&
\r
4850 (WhiteOnMove(currentMove)
\r
4851 ? x == BOARD_WIDTH-1 && y < gameInfo.holdingsSize && y > 0
\r
4852 : x == 0 && y >= BOARD_HEIGHT - gameInfo.holdingsSize && y < BOARD_HEIGHT-1) ) {
\r
4853 // click in right holdings, for determining promotion piece
\r
4854 ChessSquare p = boards[currentMove][y][x];
\r
4855 if(appData.debugMode) fprintf(debugFP, "square contains %d\n", (int)p);
\r
4856 if(p != EmptySquare) {
\r
4857 FinishMove(WhitePromotionQueen, fromX, fromY, toX, toY, ToLower(PieceToChar(p)));
\r
4858 fromX = fromY = -1;
\r
4862 DrawPosition(FALSE, boards[currentMove]);
\r
4866 sameAgain = FALSE;
\r
4868 /* Downclick vertically off board; check if on clock */
\r
4869 if (PtInRect((LPRECT) &whiteRect, pt)) {
\r
4870 if (gameMode == EditPosition) {
\r
4871 SetWhiteToPlayEvent();
\r
4872 } else if (gameMode == IcsPlayingBlack ||
\r
4873 gameMode == MachinePlaysWhite) {
\r
4875 } else if (gameMode == EditGame) {
\r
4876 AdjustClock((logoHeight > 0 ? flipView: flipClock), -1);
\r
4878 } else if (PtInRect((LPRECT) &blackRect, pt)) {
\r
4879 if (gameMode == EditPosition) {
\r
4880 SetBlackToPlayEvent();
\r
4881 } else if (gameMode == IcsPlayingWhite ||
\r
4882 gameMode == MachinePlaysBlack) {
\r
4884 } else if (gameMode == EditGame) {
\r
4885 AdjustClock(!(logoHeight > 0 ? flipView: flipClock), -1);
\r
4888 if (!appData.highlightLastMove) {
\r
4889 ClearHighlights();
\r
4890 DrawPosition((int) (forceFullRepaint || FALSE), NULL);
\r
4892 fromX = fromY = -1;
\r
4893 dragInfo.start.x = dragInfo.start.y = -1;
\r
4894 dragInfo.from = dragInfo.start;
\r
4896 } else if (x < 0 || y < 0
\r
4897 /* [HGM] block clicks between board and holdings */
\r
4898 || x == BOARD_LEFT-1 || x == BOARD_RGHT
\r
4899 || (x == BOARD_LEFT-2 && y < BOARD_HEIGHT-gameInfo.holdingsSize)
\r
4900 || (x == BOARD_RGHT+1 && y >= gameInfo.holdingsSize)
\r
4901 /* EditPosition, empty square, or different color piece;
\r
4902 click-click move is possible */
\r
4905 } else if (fromX == x && fromY == y) {
\r
4906 /* Downclick on same square again */
\r
4907 ClearHighlights();
\r
4908 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
4909 sameAgain = TRUE;
\r
4910 } else if (fromX != -1 &&
\r
4911 x != BOARD_LEFT-2 && x != BOARD_RGHT+1
\r
4913 /* Downclick on different square. */
\r
4914 /* [HGM] if on holdings file, should count as new first click ! */
\r
4915 { /* [HGM] <sameColor> now always do UserMoveTest(), and check colors there */
\r
4918 /* [HGM] <popupFix> UserMoveEvent requires two calls now,
\r
4919 to make sure move is legal before showing promotion popup */
\r
4920 moveType = UserMoveTest(fromX, fromY, toX, toY, NULLCHAR);
\r
4921 if(moveType == AmbiguousMove) { /* [HGM] Edit-Position move executed */
\r
4922 fromX = fromY = -1;
\r
4923 ClearHighlights();
\r
4924 DrawPosition(FALSE, boards[currentMove]);
\r
4927 if(moveType != ImpossibleMove) {
\r
4928 /* [HGM] We use PromotionToKnight in Shogi to indicate frorced promotion */
\r
4929 if (moveType == WhitePromotionKnight || moveType == BlackPromotionKnight ||
\r
4930 ((moveType == WhitePromotionQueen || moveType == BlackPromotionQueen) &&
\r
4931 appData.alwaysPromoteToQueen)) {
\r
4932 FinishMove(moveType, fromX, fromY, toX, toY, 'q');
\r
4933 if (!appData.highlightLastMove) {
\r
4934 ClearHighlights();
\r
4935 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
4938 if (moveType == WhitePromotionQueen || moveType == BlackPromotionQueen ) {
\r
4939 SetHighlights(fromX, fromY, toX, toY);
\r
4940 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
4941 /* [HGM] <popupFix> Popup calls FinishMove now.
\r
4942 If promotion to Q is legal, all are legal! */
\r
4943 if(gameInfo.variant == VariantSuper || gameInfo.variant == VariantGreat)
\r
4944 { ChessSquare p = boards[currentMove][fromY][fromX], q = boards[currentMove][toY][toX];
\r
4945 // kludge to temporarily execute move on display, wthout promotng yet
\r
4946 promotionChoice = TRUE;
\r
4947 boards[currentMove][fromY][fromX] = EmptySquare; // move Pawn to 8th rank
\r
4948 boards[currentMove][toY][toX] = p;
\r
4949 DrawPosition(FALSE, boards[currentMove]);
\r
4950 boards[currentMove][fromY][fromX] = p; // take back, but display stays
\r
4951 boards[currentMove][toY][toX] = q;
\r
4953 PromotionPopup(hwnd);
\r
4954 } else { /* not a promotion */
\r
4955 if (appData.animate || appData.highlightLastMove) {
\r
4956 SetHighlights(fromX, fromY, toX, toY);
\r
4958 ClearHighlights();
\r
4960 FinishMove(moveType, fromX, fromY, toX, toY, NULLCHAR);
\r
4961 fromX = fromY = -1;
\r
4962 if (appData.animate && !appData.highlightLastMove) {
\r
4963 ClearHighlights();
\r
4964 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
4970 /* [HGM] it seemed that braces were missing here */
\r
4971 SetPremoveHighlights(fromX, fromY, toX, toY);
\r
4972 fromX = fromY = -1;
\r
4976 ClearHighlights();
\r
4977 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
4979 /* First downclick, or restart on a square with same color piece */
\r
4980 if (!frozen && OKToStartUserMove(x, y)) {
\r
4983 dragInfo.lastpos = pt;
\r
4984 dragInfo.from.x = fromX;
\r
4985 dragInfo.from.y = fromY;
\r
4986 dragInfo.start = dragInfo.from;
\r
4987 SetCapture(hwndMain);
\r
4989 fromX = fromY = -1;
\r
4990 dragInfo.start.x = dragInfo.start.y = -1;
\r
4991 dragInfo.from = dragInfo.start;
\r
4992 DrawPosition(forceFullRepaint || FALSE, NULL); /* [AS] */
\r
4996 case WM_LBUTTONUP:
\r
4998 if (fromX == -1) break;
\r
4999 if (x == fromX && y == fromY) {
\r
5000 dragInfo.from.x = dragInfo.from.y = -1;
\r
5001 /* Upclick on same square */
\r
5003 /* Clicked same square twice: abort click-click move */
\r
5004 fromX = fromY = -1;
\r
5006 ClearPremoveHighlights();
\r
5008 /* First square clicked: start click-click move */
\r
5009 SetHighlights(fromX, fromY, -1, -1);
\r
5011 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
5012 } else if (dragInfo.from.x < 0 || dragInfo.from.y < 0) {
\r
5013 /* Errant click; ignore */
\r
5016 /* Finish drag move. */
\r
5017 if (appData.debugMode) {
\r
5018 fprintf(debugFP, "release\n");
\r
5020 dragInfo.from.x = dragInfo.from.y = -1;
\r
5023 saveAnimate = appData.animate; /* sorry, Hawk :) */
\r
5024 appData.animate = appData.animate && !appData.animateDragging;
\r
5025 moveType = UserMoveTest(fromX, fromY, toX, toY, NULLCHAR);
\r
5026 if(moveType == AmbiguousMove) { /* [HGM] Edit-Position move executed */
\r
5027 fromX = fromY = -1;
\r
5028 ClearHighlights();
\r
5029 DrawPosition(FALSE, boards[currentMove]);
\r
5032 if(moveType != ImpossibleMove) {
\r
5033 /* [HGM] use move type to determine if move is promotion.
\r
5034 Knight is Shogi kludge for mandatory promotion, Queen means choice */
\r
5035 if (moveType == WhitePromotionKnight || moveType == BlackPromotionKnight ||
\r
5036 ((moveType == WhitePromotionQueen || moveType == BlackPromotionQueen) &&
\r
5037 appData.alwaysPromoteToQueen))
\r
5038 FinishMove(moveType, fromX, fromY, toX, toY, 'q');
\r
5040 if (moveType == WhitePromotionQueen || moveType == BlackPromotionQueen ) {
\r
5041 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
5042 if(gameInfo.variant == VariantSuper || gameInfo.variant == VariantGreat)
\r
5043 { ChessSquare p = boards[currentMove][fromY][fromX], q = boards[currentMove][toY][toX];
\r
5044 // kludge to temporarily execute move on display, wthout promotng yet
\r
5045 promotionChoice = TRUE;
\r
5046 boards[currentMove][fromY][fromX] = EmptySquare; // move Pawn to 8th rank
\r
5047 boards[currentMove][toY][toX] = p;
\r
5048 DrawPosition(FALSE, boards[currentMove]);
\r
5049 boards[currentMove][fromY][fromX] = p; // take back, but display stays
\r
5050 boards[currentMove][toY][toX] = q;
\r
5053 PromotionPopup(hwnd); /* [HGM] Popup now calls FinishMove */
\r
5055 if(saveAnimate /* ^$!%@#$!$ */ && gameInfo.variant == VariantAtomic
\r
5056 && boards[currentMove][toY][toX] != EmptySquare) AnimateAtomicCapture(toX, toY, 20);
\r
5057 FinishMove(moveType, fromX, fromY, toX, toY, NULLCHAR);
\r
5060 if (gotPremove) SetPremoveHighlights(fromX, fromY, toX, toY);
\r
5061 appData.animate = saveAnimate;
\r
5062 fromX = fromY = -1;
\r
5063 if (appData.highlightDragging && !appData.highlightLastMove) {
\r
5064 ClearHighlights();
\r
5066 if (appData.animate || appData.animateDragging ||
\r
5067 appData.highlightDragging || gotPremove) {
\r
5068 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
5071 dragInfo.start.x = dragInfo.start.y = -1;
\r
5072 dragInfo.pos = dragInfo.lastpos = dragInfo.start;
\r
5075 case WM_MOUSEMOVE:
\r
5076 if ((appData.animateDragging || appData.highlightDragging)
\r
5077 && (wParam & MK_LBUTTON)
\r
5078 && dragInfo.from.x >= 0)
\r
5080 BOOL full_repaint = FALSE;
\r
5082 sameAgain = FALSE; /* [HGM] if we drag something around, do keep square selected */
\r
5083 if (appData.animateDragging) {
\r
5084 dragInfo.pos = pt;
\r
5086 if (appData.highlightDragging) {
\r
5087 SetHighlights(fromX, fromY, x, y);
\r
5088 if( IsDrawArrowEnabled() && (x < 0 || x >= BOARD_WIDTH || y < 0 || y >= BOARD_HEIGHT) ) {
\r
5089 full_repaint = TRUE;
\r
5093 DrawPosition( full_repaint, NULL);
\r
5095 dragInfo.lastpos = dragInfo.pos;
\r
5099 case WM_MOUSEWHEEL: // [DM]
\r
5100 { static int lastDir = 0; // [HGM] build in some hysteresis to avoid spurious events
\r
5101 /* Mouse Wheel is being rolled forward
\r
5102 * Play moves forward
\r
5104 if((short)HIWORD(wParam) > 0 && currentMove < forwardMostMove)
\r
5105 { if(lastDir == 1) ForwardEvent(); else lastDir = 1; } // [HGM] suppress first event in direction
\r
5106 /* Mouse Wheel is being rolled backward
\r
5107 * Play moves backward
\r
5109 if((short)HIWORD(wParam) < 0 && currentMove > backwardMostMove)
\r
5110 { if(lastDir == -1) BackwardEvent(); else lastDir = -1; }
\r
5114 case WM_MBUTTONDOWN:
\r
5115 case WM_RBUTTONDOWN:
\r
5118 fromX = fromY = -1;
\r
5119 dragInfo.pos.x = dragInfo.pos.y = -1;
\r
5120 dragInfo.start.x = dragInfo.start.y = -1;
\r
5121 dragInfo.from = dragInfo.start;
\r
5122 dragInfo.lastpos = dragInfo.pos;
\r
5123 if (appData.highlightDragging) {
\r
5124 ClearHighlights();
\r
5127 /* [HGM] right mouse button in clock area edit-game mode ups clock */
\r
5128 if (PtInRect((LPRECT) &whiteRect, pt)) {
\r
5129 if (gameMode == EditGame) AdjustClock((logoHeight > 0 ? flipView: flipClock), 1);
\r
5130 } else if (PtInRect((LPRECT) &blackRect, pt)) {
\r
5131 if (gameMode == EditGame) AdjustClock(!(logoHeight > 0 ? flipView: flipClock), 1);
\r
5134 DrawPosition(TRUE, NULL);
\r
5136 switch (gameMode) {
\r
5137 case EditPosition:
\r
5138 case IcsExamining:
\r
5139 if (x < 0 || y < 0) break;
\r
5142 if (message == WM_MBUTTONDOWN) {
\r
5143 buttonCount = 3; /* even if system didn't think so */
\r
5144 if (wParam & MK_SHIFT)
\r
5145 MenuPopup(hwnd, pt, LoadMenu(hInst, "BlackPieceMenu"), -1);
\r
5147 MenuPopup(hwnd, pt, LoadMenu(hInst, "WhitePieceMenu"), -1);
\r
5148 } else { /* message == WM_RBUTTONDOWN */
\r
5150 if (buttonCount == 3) {
\r
5151 if (wParam & MK_SHIFT)
\r
5152 MenuPopup(hwnd, pt, LoadMenu(hInst, "WhitePieceMenu"), -1);
\r
5154 MenuPopup(hwnd, pt, LoadMenu(hInst, "BlackPieceMenu"), -1);
\r
5156 MenuPopup(hwnd, pt, LoadMenu(hInst, "PieceMenu"), -1);
\r
5159 /* Just have one menu, on the right button. Windows users don't
\r
5160 think to try the middle one, and sometimes other software steals
\r
5161 it, or it doesn't really exist. */
\r
5162 if(gameInfo.variant != VariantShogi)
\r
5163 MenuPopup(hwnd, pt, LoadMenu(hInst, "PieceMenu"), -1);
\r
5165 MenuPopup(hwnd, pt, LoadMenu(hInst, "ShogiPieceMenu"), -1);
\r
5169 case IcsPlayingWhite:
\r
5170 case IcsPlayingBlack:
\r
5172 case MachinePlaysWhite:
\r
5173 case MachinePlaysBlack:
\r
5174 if (appData.testLegality &&
\r
5175 gameInfo.variant != VariantBughouse &&
\r
5176 gameInfo.variant != VariantCrazyhouse) break;
\r
5177 if (x < 0 || y < 0) break;
\r
5180 hmenu = LoadMenu(hInst, "DropPieceMenu");
\r
5181 SetupDropMenu(hmenu);
\r
5182 MenuPopup(hwnd, pt, hmenu, -1);
\r
5193 /* Preprocess messages for buttons in main window */
\r
5195 ButtonProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
5197 int id = GetWindowLong(hwnd, GWL_ID);
\r
5200 for (i=0; i<N_BUTTONS; i++) {
\r
5201 if (buttonDesc[i].id == id) break;
\r
5203 if (i == N_BUTTONS) return 0;
\r
5204 switch (message) {
\r
5209 dir = (wParam == VK_LEFT) ? -1 : 1;
\r
5210 SetFocus(buttonDesc[(i + dir + N_BUTTONS) % N_BUTTONS].hwnd);
\r
5217 SendMessage(hwndMain, WM_COMMAND, MAKEWPARAM(buttonDesc[i].id, 0), 0);
\r
5220 if (appData.icsActive) {
\r
5221 if (GetKeyState(VK_SHIFT) < 0) {
\r
5223 HWND h = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
5224 if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
5228 HWND h = GetDlgItem(hwndConsole, OPT_ConsoleText);
\r
5229 if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
5236 if (appData.icsActive) {
\r
5237 HWND h = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
5238 if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
5240 SendMessage(h, WM_CHAR, wParam, lParam);
\r
5242 } else if (isalpha((char)wParam) || isdigit((char)wParam)){
\r
5243 PopUpMoveDialog((char)wParam);
\r
5249 return CallWindowProc(buttonDesc[i].wndproc, hwnd, message, wParam, lParam);
\r
5252 /* Process messages for Promotion dialog box */
\r
5254 Promotion(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
5258 switch (message) {
\r
5259 case WM_INITDIALOG: /* message: initialize dialog box */
\r
5260 /* Center the dialog over the application window */
\r
5261 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
5262 ShowWindow(GetDlgItem(hDlg, PB_King),
\r
5263 (!appData.testLegality || gameInfo.variant == VariantSuicide ||
\r
5264 gameInfo.variant == VariantGiveaway || gameInfo.variant == VariantSuper ) ?
\r
5265 SW_SHOW : SW_HIDE);
\r
5266 /* [HGM] Only allow C & A promotions if these pieces are defined */
\r
5267 ShowWindow(GetDlgItem(hDlg, PB_Archbishop),
\r
5268 ((PieceToChar(WhiteAngel) >= 'A' &&
\r
5269 PieceToChar(WhiteAngel) != '~') ||
\r
5270 (PieceToChar(BlackAngel) >= 'A' &&
\r
5271 PieceToChar(BlackAngel) != '~') ) ?
\r
5272 SW_SHOW : SW_HIDE);
\r
5273 ShowWindow(GetDlgItem(hDlg, PB_Chancellor),
\r
5274 ((PieceToChar(WhiteMarshall) >= 'A' &&
\r
5275 PieceToChar(WhiteMarshall) != '~') ||
\r
5276 (PieceToChar(BlackMarshall) >= 'A' &&
\r
5277 PieceToChar(BlackMarshall) != '~') ) ?
\r
5278 SW_SHOW : SW_HIDE);
\r
5279 /* [HGM] Hide B & R button in Shogi, use Q as promote, N as defer */
\r
5280 ShowWindow(GetDlgItem(hDlg, PB_Rook),
\r
5281 gameInfo.variant != VariantShogi ?
\r
5282 SW_SHOW : SW_HIDE);
\r
5283 ShowWindow(GetDlgItem(hDlg, PB_Bishop),
\r
5284 gameInfo.variant != VariantShogi ?
\r
5285 SW_SHOW : SW_HIDE);
\r
5286 ShowWindow(GetDlgItem(hDlg, IDC_Yes),
\r
5287 gameInfo.variant == VariantShogi ?
\r
5288 SW_SHOW : SW_HIDE);
\r
5289 ShowWindow(GetDlgItem(hDlg, IDC_No),
\r
5290 gameInfo.variant == VariantShogi ?
\r
5291 SW_SHOW : SW_HIDE);
\r
5292 ShowWindow(GetDlgItem(hDlg, IDC_Centaur),
\r
5293 gameInfo.variant == VariantSuper ?
\r
5294 SW_SHOW : SW_HIDE);
\r
5297 case WM_COMMAND: /* message: received a command */
\r
5298 switch (LOWORD(wParam)) {
\r
5300 EndDialog(hDlg, TRUE); /* Exit the dialog */
\r
5301 ClearHighlights();
\r
5302 DrawPosition(FALSE, NULL);
\r
5305 promoChar = gameInfo.variant == VariantSuper ? PieceToChar(BlackSilver) : PieceToChar(BlackKing);
\r
5308 promoChar = gameInfo.variant == VariantShogi ? '+' : PieceToChar(BlackQueen);
\r
5311 promoChar = PieceToChar(BlackRook);
\r
5314 promoChar = PieceToChar(BlackBishop);
\r
5316 case PB_Chancellor:
\r
5317 promoChar = PieceToChar(BlackMarshall);
\r
5319 case PB_Archbishop:
\r
5320 promoChar = PieceToChar(BlackAngel);
\r
5323 promoChar = gameInfo.variant == VariantShogi ? '=' : PieceToChar(BlackKnight);
\r
5328 EndDialog(hDlg, TRUE); /* Exit the dialog */
\r
5329 /* [HGM] <popupFix> Call FinishMove rather than UserMoveEvent, as we
\r
5330 only show the popup when we are already sure the move is valid or
\r
5331 legal. We pass a faulty move type, but the kludge is that FinishMove
\r
5332 will figure out it is a promotion from the promoChar. */
\r
5333 FinishMove(NormalMove, fromX, fromY, toX, toY, promoChar);
\r
5334 if (!appData.highlightLastMove) {
\r
5335 ClearHighlights();
\r
5336 DrawPosition(FALSE, NULL);
\r
5343 /* Pop up promotion dialog */
\r
5345 PromotionPopup(HWND hwnd)
\r
5349 lpProc = MakeProcInstance((FARPROC)Promotion, hInst);
\r
5350 DialogBox(hInst, MAKEINTRESOURCE(DLG_PromotionKing),
\r
5351 hwnd, (DLGPROC)lpProc);
\r
5352 FreeProcInstance(lpProc);
\r
5355 /* Toggle ShowThinking */
\r
5357 ToggleShowThinking()
\r
5359 appData.showThinking = !appData.showThinking;
\r
5360 ShowThinkingEvent();
\r
5364 LoadGameDialog(HWND hwnd, char* title)
\r
5368 char fileTitle[MSG_SIZ];
\r
5369 f = OpenFileDialog(hwnd, "rb", "",
\r
5370 appData.oldSaveStyle ? "gam" : "pgn",
\r
5372 title, &number, fileTitle, NULL);
\r
5374 cmailMsgLoaded = FALSE;
\r
5375 if (number == 0) {
\r
5376 int error = GameListBuild(f);
\r
5378 DisplayError("Cannot build game list", error);
\r
5379 } else if (!ListEmpty(&gameList) &&
\r
5380 ((ListGame *) gameList.tailPred)->number > 1) {
\r
5381 GameListPopUp(f, fileTitle);
\r
5384 GameListDestroy();
\r
5387 LoadGame(f, number, fileTitle, FALSE);
\r
5392 ChangedConsoleFont()
\r
5395 CHARRANGE tmpsel, sel;
\r
5396 MyFont *f = font[boardSize][CONSOLE_FONT];
\r
5397 HWND hText = GetDlgItem(hwndConsole, OPT_ConsoleText);
\r
5398 HWND hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
5401 cfmt.cbSize = sizeof(CHARFORMAT);
\r
5402 cfmt.dwMask = CFM_FACE|CFM_SIZE|CFM_CHARSET;
\r
5403 strcpy(cfmt.szFaceName, font[boardSize][CONSOLE_FONT]->mfp.faceName);
\r
5404 /* yHeight is expressed in twips. A twip is 1/20 of a font's point
\r
5405 * size. This was undocumented in the version of MSVC++ that I had
\r
5406 * when I wrote the code, but is apparently documented now.
\r
5408 cfmt.yHeight = (int)(f->mfp.pointSize * 20.0 + 0.5);
\r
5409 cfmt.bCharSet = f->lf.lfCharSet;
\r
5410 cfmt.bPitchAndFamily = f->lf.lfPitchAndFamily;
\r
5411 SendMessage(hText, EM_SETCHARFORMAT, SCF_ALL, (LPARAM) &cfmt);
\r
5412 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM) &cfmt);
\r
5413 /* Why are the following seemingly needed too? */
\r
5414 SendMessage(hText, EM_SETCHARFORMAT, SCF_DEFAULT, (LPARAM) &cfmt);
\r
5415 SendMessage(hInput, EM_SETCHARFORMAT, SCF_DEFAULT, (LPARAM) &cfmt);
\r
5416 SendMessage(hText, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
5418 tmpsel.cpMax = -1; /*999999?*/
\r
5419 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&tmpsel);
\r
5420 SendMessage(hText, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM) &cfmt);
\r
5421 /* Trying putting this here too. It still seems to tickle a RichEdit
\r
5422 * bug: sometimes RichEdit indents the first line of a paragraph too.
\r
5424 paraf.cbSize = sizeof(paraf);
\r
5425 paraf.dwMask = PFM_OFFSET | PFM_STARTINDENT;
\r
5426 paraf.dxStartIndent = 0;
\r
5427 paraf.dxOffset = WRAP_INDENT;
\r
5428 SendMessage(hText, EM_SETPARAFORMAT, 0, (LPARAM) ¶f);
\r
5429 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
5432 /*---------------------------------------------------------------------------*\
\r
5434 * Window Proc for main window
\r
5436 \*---------------------------------------------------------------------------*/
\r
5438 /* Process messages for main window, etc. */
\r
5440 WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
5443 int wmId, wmEvent;
\r
5447 char fileTitle[MSG_SIZ];
\r
5448 char buf[MSG_SIZ];
\r
5449 static SnapData sd;
\r
5451 switch (message) {
\r
5453 case WM_PAINT: /* message: repaint portion of window */
\r
5457 case WM_ERASEBKGND:
\r
5458 if (IsIconic(hwnd)) {
\r
5459 /* Cheat; change the message */
\r
5460 return (DefWindowProc(hwnd, WM_ICONERASEBKGND, wParam, lParam));
\r
5462 return (DefWindowProc(hwnd, message, wParam, lParam));
\r
5466 case WM_LBUTTONDOWN:
\r
5467 case WM_MBUTTONDOWN:
\r
5468 case WM_RBUTTONDOWN:
\r
5469 case WM_LBUTTONUP:
\r
5470 case WM_MBUTTONUP:
\r
5471 case WM_RBUTTONUP:
\r
5472 case WM_MOUSEMOVE:
\r
5473 case WM_MOUSEWHEEL:
\r
5474 MouseEvent(hwnd, message, wParam, lParam);
\r
5479 if (appData.icsActive) {
\r
5480 if (wParam == '\t') {
\r
5481 if (GetKeyState(VK_SHIFT) < 0) {
\r
5483 HWND h = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
5484 if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
5488 HWND h = GetDlgItem(hwndConsole, OPT_ConsoleText);
\r
5489 if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
5493 HWND h = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
5494 if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
5496 SendMessage(h, message, wParam, lParam);
\r
5498 } else if (isalpha((char)wParam) || isdigit((char)wParam)) {
\r
5499 PopUpMoveDialog((char)wParam);
\r
5503 case WM_PALETTECHANGED:
\r
5504 if (hwnd != (HWND)wParam && !appData.monoMode) {
\r
5506 HDC hdc = GetDC(hwndMain);
\r
5507 SelectPalette(hdc, hPal, TRUE);
\r
5508 nnew = RealizePalette(hdc);
\r
5510 paletteChanged = TRUE;
\r
5512 UpdateColors(hdc);
\r
5514 InvalidateRect(hwnd, &boardRect, FALSE);/*faster!*/
\r
5517 ReleaseDC(hwnd, hdc);
\r
5521 case WM_QUERYNEWPALETTE:
\r
5522 if (!appData.monoMode /*&& paletteChanged*/) {
\r
5524 HDC hdc = GetDC(hwndMain);
\r
5525 paletteChanged = FALSE;
\r
5526 SelectPalette(hdc, hPal, FALSE);
\r
5527 nnew = RealizePalette(hdc);
\r
5529 InvalidateRect(hwnd, &boardRect, FALSE);
\r
5531 ReleaseDC(hwnd, hdc);
\r
5536 case WM_COMMAND: /* message: command from application menu */
\r
5537 wmId = LOWORD(wParam);
\r
5538 wmEvent = HIWORD(wParam);
\r
5543 AnalysisPopDown();
\r
5546 case IDM_NewGameFRC:
\r
5547 if( NewGameFRC() == 0 ) {
\r
5549 AnalysisPopDown();
\r
5553 case IDM_NewVariant:
\r
5554 NewVariantPopup(hwnd);
\r
5557 case IDM_LoadGame:
\r
5558 LoadGameDialog(hwnd, "Load Game from File");
\r
5561 case IDM_LoadNextGame:
\r
5565 case IDM_LoadPrevGame:
\r
5569 case IDM_ReloadGame:
\r
5573 case IDM_LoadPosition:
\r
5574 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile) {
\r
5575 Reset(FALSE, TRUE);
\r
5578 f = OpenFileDialog(hwnd, "rb", "",
\r
5579 appData.oldSaveStyle ? "pos" : "fen",
\r
5581 "Load Position from File", &number, fileTitle, NULL);
\r
5583 LoadPosition(f, number, fileTitle);
\r
5587 case IDM_LoadNextPosition:
\r
5588 ReloadPosition(1);
\r
5591 case IDM_LoadPrevPosition:
\r
5592 ReloadPosition(-1);
\r
5595 case IDM_ReloadPosition:
\r
5596 ReloadPosition(0);
\r
5599 case IDM_SaveGame:
\r
5600 defName = DefaultFileName(appData.oldSaveStyle ? "gam" : "pgn");
\r
5601 f = OpenFileDialog(hwnd, "a", defName,
\r
5602 appData.oldSaveStyle ? "gam" : "pgn",
\r
5604 "Save Game to File", NULL, fileTitle, NULL);
\r
5606 SaveGame(f, 0, "");
\r
5610 case IDM_SavePosition:
\r
5611 defName = DefaultFileName(appData.oldSaveStyle ? "pos" : "fen");
\r
5612 f = OpenFileDialog(hwnd, "a", defName,
\r
5613 appData.oldSaveStyle ? "pos" : "fen",
\r
5615 "Save Position to File", NULL, fileTitle, NULL);
\r
5617 SavePosition(f, 0, "");
\r
5621 case IDM_SaveDiagram:
\r
5622 defName = "diagram";
\r
5623 f = OpenFileDialog(hwnd, "wb", defName,
\r
5626 "Save Diagram to File", NULL, fileTitle, NULL);
\r
5632 case IDM_CopyGame:
\r
5633 CopyGameToClipboard();
\r
5636 case IDM_PasteGame:
\r
5637 PasteGameFromClipboard();
\r
5640 case IDM_CopyGameListToClipboard:
\r
5641 CopyGameListToClipboard();
\r
5644 /* [AS] Autodetect FEN or PGN data */
\r
5645 case IDM_PasteAny:
\r
5646 PasteGameOrFENFromClipboard();
\r
5649 /* [AS] Move history */
\r
5650 case IDM_ShowMoveHistory:
\r
5651 if( MoveHistoryIsUp() ) {
\r
5652 MoveHistoryPopDown();
\r
5655 MoveHistoryPopUp();
\r
5659 /* [AS] Eval graph */
\r
5660 case IDM_ShowEvalGraph:
\r
5661 if( EvalGraphIsUp() ) {
\r
5662 EvalGraphPopDown();
\r
5669 /* [AS] Engine output */
\r
5670 case IDM_ShowEngineOutput:
\r
5671 if( EngineOutputIsUp() ) {
\r
5672 EngineOutputPopDown();
\r
5675 EngineOutputPopUp();
\r
5679 /* [AS] User adjudication */
\r
5680 case IDM_UserAdjudication_White:
\r
5681 UserAdjudicationEvent( +1 );
\r
5684 case IDM_UserAdjudication_Black:
\r
5685 UserAdjudicationEvent( -1 );
\r
5688 case IDM_UserAdjudication_Draw:
\r
5689 UserAdjudicationEvent( 0 );
\r
5692 /* [AS] Game list options dialog */
\r
5693 case IDM_GameListOptions:
\r
5694 GameListOptions();
\r
5697 case IDM_CopyPosition:
\r
5698 CopyFENToClipboard();
\r
5701 case IDM_PastePosition:
\r
5702 PasteFENFromClipboard();
\r
5705 case IDM_MailMove:
\r
5709 case IDM_ReloadCMailMsg:
\r
5710 Reset(TRUE, TRUE);
\r
5711 ReloadCmailMsgEvent(FALSE);
\r
5714 case IDM_Minimize:
\r
5715 ShowWindow(hwnd, SW_MINIMIZE);
\r
5722 case IDM_MachineWhite:
\r
5723 MachineWhiteEvent();
\r
5725 * refresh the tags dialog only if it's visible
\r
5727 if (gameMode == MachinePlaysWhite && IsWindowVisible(editTagsDialog)) {
\r
5729 tags = PGNTags(&gameInfo);
\r
5730 TagsPopUp(tags, CmailMsg());
\r
5735 case IDM_MachineBlack:
\r
5736 MachineBlackEvent();
\r
5738 * refresh the tags dialog only if it's visible
\r
5740 if (gameMode == MachinePlaysBlack && IsWindowVisible(editTagsDialog)) {
\r
5742 tags = PGNTags(&gameInfo);
\r
5743 TagsPopUp(tags, CmailMsg());
\r
5748 case IDM_TwoMachines:
\r
5749 TwoMachinesEvent();
\r
5751 * refresh the tags dialog only if it's visible
\r
5753 if (gameMode == TwoMachinesPlay && IsWindowVisible(editTagsDialog)) {
\r
5755 tags = PGNTags(&gameInfo);
\r
5756 TagsPopUp(tags, CmailMsg());
\r
5761 case IDM_AnalysisMode:
\r
5762 if (!first.analysisSupport) {
\r
5763 sprintf(buf, "%s does not support analysis", first.tidy);
\r
5764 DisplayError(buf, 0);
\r
5766 /* [DM] icsEngineAnlyze [HGM] Why is this front-end??? */
\r
5767 if (appData.icsActive) {
\r
5768 if (gameMode != IcsObserving) {
\r
5769 sprintf(buf, "You are not observing a game");
\r
5770 DisplayError(buf, 0);
\r
5771 /* secure check */
\r
5772 if (appData.icsEngineAnalyze) {
\r
5773 if (appData.debugMode)
\r
5774 fprintf(debugFP, "Found unexpected active ICS engine analyze \n");
\r
5775 ExitAnalyzeMode();
\r
5781 /* if enable, user want disable icsEngineAnalyze */
\r
5782 if (appData.icsEngineAnalyze) {
\r
5783 ExitAnalyzeMode();
\r
5787 appData.icsEngineAnalyze = TRUE;
\r
5788 if (appData.debugMode) fprintf(debugFP, "ICS engine analyze starting...\n");
\r
5791 if (!appData.showThinking) ToggleShowThinking();
\r
5792 AnalyzeModeEvent();
\r
5796 case IDM_AnalyzeFile:
\r
5797 if (!first.analysisSupport) {
\r
5798 char buf[MSG_SIZ];
\r
5799 sprintf(buf, "%s does not support analysis", first.tidy);
\r
5800 DisplayError(buf, 0);
\r
5802 if (!appData.showThinking) ToggleShowThinking();
\r
5803 AnalyzeFileEvent();
\r
5804 LoadGameDialog(hwnd, "Analyze Game from File");
\r
5805 AnalysisPeriodicEvent(1);
\r
5809 case IDM_IcsClient:
\r
5813 case IDM_EditGame:
\r
5817 case IDM_EditPosition:
\r
5818 EditPositionEvent();
\r
5821 case IDM_Training:
\r
5825 case IDM_ShowGameList:
\r
5826 ShowGameListProc();
\r
5829 case IDM_EditTags:
\r
5833 case IDM_EditComment:
\r
5834 if (commentDialogUp && editComment) {
\r
5837 EditCommentEvent();
\r
5857 case IDM_CallFlag:
\r
5877 case IDM_StopObserving:
\r
5878 StopObservingEvent();
\r
5881 case IDM_StopExamining:
\r
5882 StopExaminingEvent();
\r
5885 case IDM_TypeInMove:
\r
5886 PopUpMoveDialog('\000');
\r
5889 case IDM_TypeInName:
\r
5890 PopUpNameDialog('\000');
\r
5893 case IDM_Backward:
\r
5895 SetFocus(hwndMain);
\r
5900 SetFocus(hwndMain);
\r
5905 SetFocus(hwndMain);
\r
5910 SetFocus(hwndMain);
\r
5917 case IDM_TruncateGame:
\r
5918 TruncateGameEvent();
\r
5925 case IDM_RetractMove:
\r
5926 RetractMoveEvent();
\r
5929 case IDM_FlipView:
\r
5930 flipView = !flipView;
\r
5931 DrawPosition(FALSE, NULL);
\r
5934 case IDM_FlipClock:
\r
5935 flipClock = !flipClock;
\r
5936 DisplayBothClocks();
\r
5939 case IDM_GeneralOptions:
\r
5940 GeneralOptionsPopup(hwnd);
\r
5941 DrawPosition(TRUE, NULL);
\r
5944 case IDM_BoardOptions:
\r
5945 BoardOptionsPopup(hwnd);
\r
5948 case IDM_EnginePlayOptions:
\r
5949 EnginePlayOptionsPopup(hwnd);
\r
5952 case IDM_OptionsUCI:
\r
5953 UciOptionsPopup(hwnd);
\r
5956 case IDM_IcsOptions:
\r
5957 IcsOptionsPopup(hwnd);
\r
5961 FontsOptionsPopup(hwnd);
\r
5965 SoundOptionsPopup(hwnd);
\r
5968 case IDM_CommPort:
\r
5969 CommPortOptionsPopup(hwnd);
\r
5972 case IDM_LoadOptions:
\r
5973 LoadOptionsPopup(hwnd);
\r
5976 case IDM_SaveOptions:
\r
5977 SaveOptionsPopup(hwnd);
\r
5980 case IDM_TimeControl:
\r
5981 TimeControlOptionsPopup(hwnd);
\r
5984 case IDM_SaveSettings:
\r
5985 SaveSettings(settingsFileName);
\r
5988 case IDM_SaveSettingsOnExit:
\r
5989 saveSettingsOnExit = !saveSettingsOnExit;
\r
5990 (void) CheckMenuItem(GetMenu(hwndMain), IDM_SaveSettingsOnExit,
\r
5991 MF_BYCOMMAND|(saveSettingsOnExit ?
\r
5992 MF_CHECKED : MF_UNCHECKED));
\r
6003 case IDM_AboutGame:
\r
6008 appData.debugMode = !appData.debugMode;
\r
6009 if (appData.debugMode) {
\r
6010 char dir[MSG_SIZ];
\r
6011 GetCurrentDirectory(MSG_SIZ, dir);
\r
6012 SetCurrentDirectory(installDir);
\r
6013 debugFP = fopen(appData.nameOfDebugFile, "w");
\r
6014 SetCurrentDirectory(dir);
\r
6015 setbuf(debugFP, NULL);
\r
6022 case IDM_HELPCONTENTS:
\r
6023 if (!WinHelp (hwnd, "winboard.hlp", HELP_KEY,(DWORD)(LPSTR)"CONTENTS")) {
\r
6024 MessageBox (GetFocus(),
\r
6025 "Unable to activate help",
\r
6026 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
6030 case IDM_HELPSEARCH:
\r
6031 if (!WinHelp(hwnd, "winboard.hlp", HELP_PARTIALKEY, (DWORD)(LPSTR)"")) {
\r
6032 MessageBox (GetFocus(),
\r
6033 "Unable to activate help",
\r
6034 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
6038 case IDM_HELPHELP:
\r
6039 if(!WinHelp(hwnd, (LPSTR)NULL, HELP_HELPONHELP, 0)) {
\r
6040 MessageBox (GetFocus(),
\r
6041 "Unable to activate help",
\r
6042 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
6047 lpProc = MakeProcInstance((FARPROC)About, hInst);
\r
6049 (gameInfo.event && strcmp(gameInfo.event, "Easter Egg Hunt") == 0) ?
\r
6050 "AboutBox2" : "AboutBox", hwnd, (DLGPROC)lpProc);
\r
6051 FreeProcInstance(lpProc);
\r
6054 case IDM_DirectCommand1:
\r
6055 AskQuestionEvent("Direct Command",
\r
6056 "Send to chess program:", "", "1");
\r
6058 case IDM_DirectCommand2:
\r
6059 AskQuestionEvent("Direct Command",
\r
6060 "Send to second chess program:", "", "2");
\r
6063 case EP_WhitePawn:
\r
6064 EditPositionMenuEvent(WhitePawn, fromX, fromY);
\r
6065 fromX = fromY = -1;
\r
6068 case EP_WhiteKnight:
\r
6069 EditPositionMenuEvent(WhiteKnight, fromX, fromY);
\r
6070 fromX = fromY = -1;
\r
6073 case EP_WhiteBishop:
\r
6074 EditPositionMenuEvent(WhiteBishop, fromX, fromY);
\r
6075 fromX = fromY = -1;
\r
6078 case EP_WhiteRook:
\r
6079 EditPositionMenuEvent(WhiteRook, fromX, fromY);
\r
6080 fromX = fromY = -1;
\r
6083 case EP_WhiteQueen:
\r
6084 EditPositionMenuEvent(WhiteQueen, fromX, fromY);
\r
6085 fromX = fromY = -1;
\r
6088 case EP_WhiteFerz:
\r
6089 EditPositionMenuEvent(WhiteFerz, fromX, fromY);
\r
6090 fromX = fromY = -1;
\r
6093 case EP_WhiteWazir:
\r
6094 EditPositionMenuEvent(WhiteWazir, fromX, fromY);
\r
6095 fromX = fromY = -1;
\r
6098 case EP_WhiteAlfil:
\r
6099 EditPositionMenuEvent(WhiteAlfil, fromX, fromY);
\r
6100 fromX = fromY = -1;
\r
6103 case EP_WhiteCannon:
\r
6104 EditPositionMenuEvent(WhiteCannon, fromX, fromY);
\r
6105 fromX = fromY = -1;
\r
6108 case EP_WhiteCardinal:
\r
6109 EditPositionMenuEvent(WhiteAngel, fromX, fromY);
\r
6110 fromX = fromY = -1;
\r
6113 case EP_WhiteMarshall:
\r
6114 EditPositionMenuEvent(WhiteMarshall, fromX, fromY);
\r
6115 fromX = fromY = -1;
\r
6118 case EP_WhiteKing:
\r
6119 EditPositionMenuEvent(WhiteKing, fromX, fromY);
\r
6120 fromX = fromY = -1;
\r
6123 case EP_BlackPawn:
\r
6124 EditPositionMenuEvent(BlackPawn, fromX, fromY);
\r
6125 fromX = fromY = -1;
\r
6128 case EP_BlackKnight:
\r
6129 EditPositionMenuEvent(BlackKnight, fromX, fromY);
\r
6130 fromX = fromY = -1;
\r
6133 case EP_BlackBishop:
\r
6134 EditPositionMenuEvent(BlackBishop, fromX, fromY);
\r
6135 fromX = fromY = -1;
\r
6138 case EP_BlackRook:
\r
6139 EditPositionMenuEvent(BlackRook, fromX, fromY);
\r
6140 fromX = fromY = -1;
\r
6143 case EP_BlackQueen:
\r
6144 EditPositionMenuEvent(BlackQueen, fromX, fromY);
\r
6145 fromX = fromY = -1;
\r
6148 case EP_BlackFerz:
\r
6149 EditPositionMenuEvent(BlackFerz, fromX, fromY);
\r
6150 fromX = fromY = -1;
\r
6153 case EP_BlackWazir:
\r
6154 EditPositionMenuEvent(BlackWazir, fromX, fromY);
\r
6155 fromX = fromY = -1;
\r
6158 case EP_BlackAlfil:
\r
6159 EditPositionMenuEvent(BlackAlfil, fromX, fromY);
\r
6160 fromX = fromY = -1;
\r
6163 case EP_BlackCannon:
\r
6164 EditPositionMenuEvent(BlackCannon, fromX, fromY);
\r
6165 fromX = fromY = -1;
\r
6168 case EP_BlackCardinal:
\r
6169 EditPositionMenuEvent(BlackAngel, fromX, fromY);
\r
6170 fromX = fromY = -1;
\r
6173 case EP_BlackMarshall:
\r
6174 EditPositionMenuEvent(BlackMarshall, fromX, fromY);
\r
6175 fromX = fromY = -1;
\r
6178 case EP_BlackKing:
\r
6179 EditPositionMenuEvent(BlackKing, fromX, fromY);
\r
6180 fromX = fromY = -1;
\r
6183 case EP_EmptySquare:
\r
6184 EditPositionMenuEvent(EmptySquare, fromX, fromY);
\r
6185 fromX = fromY = -1;
\r
6188 case EP_ClearBoard:
\r
6189 EditPositionMenuEvent(ClearBoard, fromX, fromY);
\r
6190 fromX = fromY = -1;
\r
6194 EditPositionMenuEvent(WhitePlay, fromX, fromY);
\r
6195 fromX = fromY = -1;
\r
6199 EditPositionMenuEvent(BlackPlay, fromX, fromY);
\r
6200 fromX = fromY = -1;
\r
6204 EditPositionMenuEvent(PromotePiece, fromX, fromY);
\r
6205 fromX = fromY = -1;
\r
6209 EditPositionMenuEvent(DemotePiece, fromX, fromY);
\r
6210 fromX = fromY = -1;
\r
6214 DropMenuEvent(WhitePawn, fromX, fromY);
\r
6215 fromX = fromY = -1;
\r
6219 DropMenuEvent(WhiteKnight, fromX, fromY);
\r
6220 fromX = fromY = -1;
\r
6224 DropMenuEvent(WhiteBishop, fromX, fromY);
\r
6225 fromX = fromY = -1;
\r
6229 DropMenuEvent(WhiteRook, fromX, fromY);
\r
6230 fromX = fromY = -1;
\r
6234 DropMenuEvent(WhiteQueen, fromX, fromY);
\r
6235 fromX = fromY = -1;
\r
6239 return (DefWindowProc(hwnd, message, wParam, lParam));
\r
6245 case CLOCK_TIMER_ID:
\r
6246 KillTimer(hwnd, clockTimerEvent); /* Simulate one-shot timer as in X */
\r
6247 clockTimerEvent = 0;
\r
6248 DecrementClocks(); /* call into back end */
\r
6250 case LOAD_GAME_TIMER_ID:
\r
6251 KillTimer(hwnd, loadGameTimerEvent); /* Simulate one-shot timer as in X*/
\r
6252 loadGameTimerEvent = 0;
\r
6253 AutoPlayGameLoop(); /* call into back end */
\r
6255 case ANALYSIS_TIMER_ID:
\r
6256 if ((gameMode == AnalyzeMode || gameMode == AnalyzeFile
\r
6257 || appData.icsEngineAnalyze) && appData.periodicUpdates) {
\r
6258 AnalysisPeriodicEvent(0);
\r
6260 KillTimer(hwnd, analysisTimerEvent);
\r
6261 analysisTimerEvent = 0;
\r
6264 case DELAYED_TIMER_ID:
\r
6265 KillTimer(hwnd, delayedTimerEvent);
\r
6266 delayedTimerEvent = 0;
\r
6267 delayedTimerCallback();
\r
6272 case WM_USER_Input:
\r
6273 InputEvent(hwnd, message, wParam, lParam);
\r
6276 /* [AS] Also move "attached" child windows */
\r
6277 case WM_WINDOWPOSCHANGING:
\r
6278 if( hwnd == hwndMain && appData.useStickyWindows ) {
\r
6279 LPWINDOWPOS lpwp = (LPWINDOWPOS) lParam;
\r
6281 if( ((lpwp->flags & SWP_NOMOVE) == 0) && ((lpwp->flags & SWP_NOSIZE) != 0) ) {
\r
6282 /* Window is moving */
\r
6285 GetWindowRect( hwnd, &rcMain );
\r
6287 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, moveHistoryDialog, &wpMoveHistory );
\r
6288 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, evalGraphDialog, &wpEvalGraph );
\r
6289 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, engineOutputDialog, &wpEngineOutput );
\r
6294 /* [AS] Snapping */
\r
6295 case WM_ENTERSIZEMOVE:
\r
6296 if(appData.debugMode) { fprintf(debugFP, "size-move\n"); }
\r
6297 if (hwnd == hwndMain) {
\r
6298 doingSizing = TRUE;
\r
6301 return OnEnterSizeMove( &sd, hwnd, wParam, lParam );
\r
6305 if(appData.debugMode) { fprintf(debugFP, "sizing\n"); }
\r
6306 if (hwnd == hwndMain) {
\r
6307 lastSizing = wParam;
\r
6312 if(appData.debugMode) { fprintf(debugFP, "moving\n"); }
\r
6313 return OnMoving( &sd, hwnd, wParam, lParam );
\r
6315 case WM_EXITSIZEMOVE:
\r
6316 if(appData.debugMode) { fprintf(debugFP, "exit size-move, size = %d\n", squareSize); }
\r
6317 if (hwnd == hwndMain) {
\r
6319 doingSizing = FALSE;
\r
6320 InvalidateRect(hwnd, &boardRect, FALSE);
\r
6321 GetClientRect(hwnd, &client);
\r
6322 ResizeBoard(client.right, client.bottom, lastSizing);
\r
6324 if(appData.debugMode) { fprintf(debugFP, "square size = %d\n", squareSize); }
\r
6326 return OnExitSizeMove( &sd, hwnd, wParam, lParam );
\r
6329 case WM_DESTROY: /* message: window being destroyed */
\r
6330 PostQuitMessage(0);
\r
6334 if (hwnd == hwndMain) {
\r
6339 default: /* Passes it on if unprocessed */
\r
6340 return (DefWindowProc(hwnd, message, wParam, lParam));
\r
6345 /*---------------------------------------------------------------------------*\
\r
6347 * Misc utility routines
\r
6349 \*---------------------------------------------------------------------------*/
\r
6352 * Decent random number generator, at least not as bad as Windows
\r
6353 * standard rand, which returns a value in the range 0 to 0x7fff.
\r
6355 unsigned int randstate;
\r
6360 randstate = randstate * 1664525 + 1013904223;
\r
6361 return (int) randstate & 0x7fffffff;
\r
6365 mysrandom(unsigned int seed)
\r
6372 * returns TRUE if user selects a different color, FALSE otherwise
\r
6376 ChangeColor(HWND hwnd, COLORREF *which)
\r
6378 static BOOL firstTime = TRUE;
\r
6379 static DWORD customColors[16];
\r
6381 COLORREF newcolor;
\r
6386 /* Make initial colors in use available as custom colors */
\r
6387 /* Should we put the compiled-in defaults here instead? */
\r
6389 customColors[i++] = lightSquareColor & 0xffffff;
\r
6390 customColors[i++] = darkSquareColor & 0xffffff;
\r
6391 customColors[i++] = whitePieceColor & 0xffffff;
\r
6392 customColors[i++] = blackPieceColor & 0xffffff;
\r
6393 customColors[i++] = highlightSquareColor & 0xffffff;
\r
6394 customColors[i++] = premoveHighlightColor & 0xffffff;
\r
6396 for (ccl = (ColorClass) 0; ccl < NColorClasses && i < 16; ccl++) {
\r
6397 customColors[i++] = textAttribs[ccl].color;
\r
6399 while (i < 16) customColors[i++] = RGB(255, 255, 255);
\r
6400 firstTime = FALSE;
\r
6403 cc.lStructSize = sizeof(cc);
\r
6404 cc.hwndOwner = hwnd;
\r
6405 cc.hInstance = NULL;
\r
6406 cc.rgbResult = (DWORD) (*which & 0xffffff);
\r
6407 cc.lpCustColors = (LPDWORD) customColors;
\r
6408 cc.Flags = CC_RGBINIT|CC_FULLOPEN;
\r
6410 if (!ChooseColor(&cc)) return FALSE;
\r
6412 newcolor = (COLORREF) (0x2000000 | cc.rgbResult);
\r
6413 if (newcolor == *which) return FALSE;
\r
6414 *which = newcolor;
\r
6418 InitDrawingColors();
\r
6419 InvalidateRect(hwnd, &boardRect, FALSE);
\r
6424 MyLoadSound(MySound *ms)
\r
6430 if (ms->data) free(ms->data);
\r
6433 switch (ms->name[0]) {
\r
6439 /* System sound from Control Panel. Don't preload here. */
\r
6443 if (ms->name[1] == NULLCHAR) {
\r
6444 /* "!" alone = silence */
\r
6447 /* Builtin wave resource. Error if not found. */
\r
6448 HANDLE h = FindResource(hInst, ms->name + 1, "WAVE");
\r
6449 if (h == NULL) break;
\r
6450 ms->data = (void *)LoadResource(hInst, h);
\r
6451 if (h == NULL) break;
\r
6456 /* .wav file. Error if not found. */
\r
6457 f = fopen(ms->name, "rb");
\r
6458 if (f == NULL) break;
\r
6459 if (fstat(fileno(f), &st) < 0) break;
\r
6460 ms->data = malloc(st.st_size);
\r
6461 if (fread(ms->data, st.st_size, 1, f) < 1) break;
\r
6467 char buf[MSG_SIZ];
\r
6468 sprintf(buf, "Error loading sound %s", ms->name);
\r
6469 DisplayError(buf, GetLastError());
\r
6475 MyPlaySound(MySound *ms)
\r
6477 BOOLEAN ok = FALSE;
\r
6478 switch (ms->name[0]) {
\r
6484 /* System sound from Control Panel (deprecated feature).
\r
6485 "$" alone or an unset sound name gets default beep (still in use). */
\r
6486 if (ms->name[1]) {
\r
6487 ok = PlaySound(ms->name + 1, NULL, SND_ALIAS|SND_ASYNC);
\r
6489 if (!ok) ok = MessageBeep(MB_OK);
\r
6492 /* Builtin wave resource, or "!" alone for silence */
\r
6493 if (ms->name[1]) {
\r
6494 if (ms->data == NULL) return FALSE;
\r
6495 ok = PlaySound(ms->data, NULL, SND_MEMORY|SND_ASYNC);
\r
6501 /* .wav file. Error if not found. */
\r
6502 if (ms->data == NULL) return FALSE;
\r
6503 ok = PlaySound(ms->data, NULL, SND_MEMORY|SND_ASYNC);
\r
6506 /* Don't print an error: this can happen innocently if the sound driver
\r
6507 is busy; for instance, if another instance of WinBoard is playing
\r
6508 a sound at about the same time. */
\r
6511 char buf[MSG_SIZ];
\r
6512 sprintf(buf, "Error playing sound %s", ms->name);
\r
6513 DisplayError(buf, GetLastError());
\r
6521 OldOpenFileHook(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
6524 OPENFILENAME *ofn;
\r
6525 static UINT *number; /* gross that this is static */
\r
6527 switch (message) {
\r
6528 case WM_INITDIALOG: /* message: initialize dialog box */
\r
6529 /* Center the dialog over the application window */
\r
6530 ofn = (OPENFILENAME *) lParam;
\r
6531 if (ofn->Flags & OFN_ENABLETEMPLATE) {
\r
6532 number = (UINT *) ofn->lCustData;
\r
6533 SendMessage(GetDlgItem(hDlg, edt2), WM_SETTEXT, 0, (LPARAM) "");
\r
6537 CenterWindow (hDlg, GetWindow (hDlg, GW_OWNER));
\r
6538 return FALSE; /* Allow for further processing */
\r
6541 if ((LOWORD(wParam) == IDOK) && (number != NULL)) {
\r
6542 *number = GetDlgItemInt(hDlg, OPT_IndexNumberOld, &ok, FALSE);
\r
6544 return FALSE; /* Allow for further processing */
\r
6550 OpenFileHook(HWND hdlg, UINT uiMsg, WPARAM wParam, LPARAM lParam)
\r
6552 static UINT *number;
\r
6553 OPENFILENAME *ofname;
\r
6556 case WM_INITDIALOG:
\r
6557 ofname = (OPENFILENAME *)lParam;
\r
6558 number = (UINT *)(ofname->lCustData);
\r
6561 ofnot = (OFNOTIFY *)lParam;
\r
6562 if (ofnot->hdr.code == CDN_FILEOK) {
\r
6563 *number = GetDlgItemInt(hdlg, OPT_IndexNumber, NULL, FALSE);
\r
6572 OpenFileDialog(HWND hwnd, char *write, char *defName, char *defExt, // [HGM] diag: type of 'write' now string
\r
6573 char *nameFilt, char *dlgTitle, UINT *number,
\r
6574 char fileTitle[MSG_SIZ], char fileName[MSG_SIZ])
\r
6576 OPENFILENAME openFileName;
\r
6577 char buf1[MSG_SIZ];
\r
6580 if (fileName == NULL) fileName = buf1;
\r
6581 if (defName == NULL) {
\r
6582 strcpy(fileName, "*.");
\r
6583 strcat(fileName, defExt);
\r
6585 strcpy(fileName, defName);
\r
6587 if (fileTitle) strcpy(fileTitle, "");
\r
6588 if (number) *number = 0;
\r
6590 openFileName.lStructSize = sizeof(OPENFILENAME);
\r
6591 openFileName.hwndOwner = hwnd;
\r
6592 openFileName.hInstance = (HANDLE) hInst;
\r
6593 openFileName.lpstrFilter = nameFilt;
\r
6594 openFileName.lpstrCustomFilter = (LPSTR) NULL;
\r
6595 openFileName.nMaxCustFilter = 0L;
\r
6596 openFileName.nFilterIndex = 1L;
\r
6597 openFileName.lpstrFile = fileName;
\r
6598 openFileName.nMaxFile = MSG_SIZ;
\r
6599 openFileName.lpstrFileTitle = fileTitle;
\r
6600 openFileName.nMaxFileTitle = fileTitle ? MSG_SIZ : 0;
\r
6601 openFileName.lpstrInitialDir = NULL;
\r
6602 openFileName.lpstrTitle = dlgTitle;
\r
6603 openFileName.Flags = OFN_PATHMUSTEXIST | OFN_HIDEREADONLY
\r
6604 | (write[0] != 'r' ? 0 : OFN_FILEMUSTEXIST)
\r
6605 | (number ? OFN_ENABLETEMPLATE | OFN_ENABLEHOOK: 0)
\r
6606 | (oldDialog ? 0 : OFN_EXPLORER);
\r
6607 openFileName.nFileOffset = 0;
\r
6608 openFileName.nFileExtension = 0;
\r
6609 openFileName.lpstrDefExt = defExt;
\r
6610 openFileName.lCustData = (LONG) number;
\r
6611 openFileName.lpfnHook = oldDialog ?
\r
6612 (LPOFNHOOKPROC) OldOpenFileHook : (LPOFNHOOKPROC) OpenFileHook;
\r
6613 openFileName.lpTemplateName = (LPSTR)(oldDialog ? 1536 : DLG_IndexNumber);
\r
6615 if (write[0] != 'r' ? GetSaveFileName(&openFileName) :
\r
6616 GetOpenFileName(&openFileName)) {
\r
6617 /* open the file */
\r
6618 f = fopen(openFileName.lpstrFile, write);
\r
6620 MessageBox(hwnd, "File open failed", NULL,
\r
6621 MB_OK|MB_ICONEXCLAMATION);
\r
6625 int err = CommDlgExtendedError();
\r
6626 if (err != 0) DisplayError("Internal error in file dialog box", err);
\r
6635 MenuPopup(HWND hwnd, POINT pt, HMENU hmenu, UINT def)
\r
6637 HMENU hmenuTrackPopup; /* floating pop-up menu */
\r
6640 * Get the first pop-up menu in the menu template. This is the
\r
6641 * menu that TrackPopupMenu displays.
\r
6643 hmenuTrackPopup = GetSubMenu(hmenu, 0);
\r
6645 SetMenuDefaultItem(hmenuTrackPopup, def, FALSE);
\r
6648 * TrackPopup uses screen coordinates, so convert the
\r
6649 * coordinates of the mouse click to screen coordinates.
\r
6651 ClientToScreen(hwnd, (LPPOINT) &pt);
\r
6653 /* Draw and track the floating pop-up menu. */
\r
6654 TrackPopupMenu(hmenuTrackPopup, TPM_CENTERALIGN | TPM_RIGHTBUTTON,
\r
6655 pt.x, pt.y, 0, hwnd, NULL);
\r
6657 /* Destroy the menu.*/
\r
6658 DestroyMenu(hmenu);
\r
6663 int sizeX, sizeY, newSizeX, newSizeY;
\r
6665 } ResizeEditPlusButtonsClosure;
\r
6668 ResizeEditPlusButtonsCallback(HWND hChild, LPARAM lparam)
\r
6670 ResizeEditPlusButtonsClosure *cl = (ResizeEditPlusButtonsClosure *)lparam;
\r
6674 if (hChild == cl->hText) return TRUE;
\r
6675 GetWindowRect(hChild, &rect); /* gives screen coords */
\r
6676 pt.x = rect.left + (cl->newSizeX - cl->sizeX)/2;
\r
6677 pt.y = rect.top + cl->newSizeY - cl->sizeY;
\r
6678 ScreenToClient(cl->hDlg, &pt);
\r
6679 cl->hdwp = DeferWindowPos(cl->hdwp, hChild, NULL,
\r
6680 pt.x, pt.y, rect.right - rect.left, rect.bottom - rect.top, SWP_NOZORDER);
\r
6684 /* Resize a dialog that has a (rich) edit field filling most of
\r
6685 the top, with a row of buttons below */
\r
6687 ResizeEditPlusButtons(HWND hDlg, HWND hText, int sizeX, int sizeY, int newSizeX, int newSizeY)
\r
6690 int newTextHeight, newTextWidth;
\r
6691 ResizeEditPlusButtonsClosure cl;
\r
6693 /*if (IsIconic(hDlg)) return;*/
\r
6694 if (newSizeX == sizeX && newSizeY == sizeY) return;
\r
6696 cl.hdwp = BeginDeferWindowPos(8);
\r
6698 GetWindowRect(hText, &rectText); /* gives screen coords */
\r
6699 newTextWidth = rectText.right - rectText.left + newSizeX - sizeX;
\r
6700 newTextHeight = rectText.bottom - rectText.top + newSizeY - sizeY;
\r
6701 if (newTextHeight < 0) {
\r
6702 newSizeY += -newTextHeight;
\r
6703 newTextHeight = 0;
\r
6705 cl.hdwp = DeferWindowPos(cl.hdwp, hText, NULL, 0, 0,
\r
6706 newTextWidth, newTextHeight, SWP_NOZORDER|SWP_NOMOVE);
\r
6712 cl.newSizeX = newSizeX;
\r
6713 cl.newSizeY = newSizeY;
\r
6714 EnumChildWindows(hDlg, ResizeEditPlusButtonsCallback, (LPARAM)&cl);
\r
6716 EndDeferWindowPos(cl.hdwp);
\r
6719 BOOL CenterWindowEx(HWND hwndChild, HWND hwndParent, int mode)
\r
6721 RECT rChild, rParent;
\r
6722 int wChild, hChild, wParent, hParent;
\r
6723 int wScreen, hScreen, xNew, yNew;
\r
6726 /* Get the Height and Width of the child window */
\r
6727 GetWindowRect (hwndChild, &rChild);
\r
6728 wChild = rChild.right - rChild.left;
\r
6729 hChild = rChild.bottom - rChild.top;
\r
6731 /* Get the Height and Width of the parent window */
\r
6732 GetWindowRect (hwndParent, &rParent);
\r
6733 wParent = rParent.right - rParent.left;
\r
6734 hParent = rParent.bottom - rParent.top;
\r
6736 /* Get the display limits */
\r
6737 hdc = GetDC (hwndChild);
\r
6738 wScreen = GetDeviceCaps (hdc, HORZRES);
\r
6739 hScreen = GetDeviceCaps (hdc, VERTRES);
\r
6740 ReleaseDC(hwndChild, hdc);
\r
6742 /* Calculate new X position, then adjust for screen */
\r
6743 xNew = rParent.left + ((wParent - wChild) /2);
\r
6746 } else if ((xNew+wChild) > wScreen) {
\r
6747 xNew = wScreen - wChild;
\r
6750 /* Calculate new Y position, then adjust for screen */
\r
6752 yNew = rParent.top + ((hParent - hChild) /2);
\r
6755 yNew = rParent.top + GetSystemMetrics( SM_CYCAPTION ) * 2 / 3;
\r
6760 } else if ((yNew+hChild) > hScreen) {
\r
6761 yNew = hScreen - hChild;
\r
6764 /* Set it, and return */
\r
6765 return SetWindowPos (hwndChild, NULL,
\r
6766 xNew, yNew, 0, 0, SWP_NOSIZE | SWP_NOZORDER);
\r
6769 /* Center one window over another */
\r
6770 BOOL CenterWindow (HWND hwndChild, HWND hwndParent)
\r
6772 return CenterWindowEx( hwndChild, hwndParent, 0 );
\r
6775 /*---------------------------------------------------------------------------*\
\r
6777 * Startup Dialog functions
\r
6779 \*---------------------------------------------------------------------------*/
\r
6781 InitComboStrings(HANDLE hwndCombo, char **cd)
\r
6783 SendMessage(hwndCombo, CB_RESETCONTENT, 0, 0);
\r
6785 while (*cd != NULL) {
\r
6786 SendMessage(hwndCombo, CB_ADDSTRING, 0, (LPARAM) *cd);
\r
6792 InitComboStringsFromOption(HANDLE hwndCombo, char *str)
\r
6794 char buf1[ARG_MAX];
\r
6797 if (str[0] == '@') {
\r
6798 FILE* f = fopen(str + 1, "r");
\r
6800 DisplayFatalError(str + 1, errno, 2);
\r
6803 len = fread(buf1, 1, sizeof(buf1)-1, f);
\r
6805 buf1[len] = NULLCHAR;
\r
6809 SendMessage(hwndCombo, CB_RESETCONTENT, 0, 0);
\r
6812 char buf[MSG_SIZ];
\r
6813 char *end = strchr(str, '\n');
\r
6814 if (end == NULL) return;
\r
6815 memcpy(buf, str, end - str);
\r
6816 buf[end - str] = NULLCHAR;
\r
6817 SendMessage(hwndCombo, CB_ADDSTRING, 0, (LPARAM) buf);
\r
6823 SetStartupDialogEnables(HWND hDlg)
\r
6825 EnableWindow(GetDlgItem(hDlg, OPT_ChessEngineName),
\r
6826 IsDlgButtonChecked(hDlg, OPT_ChessEngine) ||
\r
6827 (appData.zippyPlay && IsDlgButtonChecked(hDlg, OPT_ChessServer)));
\r
6828 EnableWindow(GetDlgItem(hDlg, OPT_SecondChessEngineName),
\r
6829 IsDlgButtonChecked(hDlg, OPT_ChessEngine));
\r
6830 EnableWindow(GetDlgItem(hDlg, OPT_ChessServerName),
\r
6831 IsDlgButtonChecked(hDlg, OPT_ChessServer));
\r
6832 EnableWindow(GetDlgItem(hDlg, OPT_AdditionalOptions),
\r
6833 IsDlgButtonChecked(hDlg, OPT_AnyAdditional));
\r
6834 EnableWindow(GetDlgItem(hDlg, IDOK),
\r
6835 IsDlgButtonChecked(hDlg, OPT_ChessEngine) ||
\r
6836 IsDlgButtonChecked(hDlg, OPT_ChessServer) ||
\r
6837 IsDlgButtonChecked(hDlg, OPT_View));
\r
6841 QuoteForFilename(char *filename)
\r
6843 int dquote, space;
\r
6844 dquote = strchr(filename, '"') != NULL;
\r
6845 space = strchr(filename, ' ') != NULL;
\r
6846 if (dquote || space) {
\r
6858 InitEngineBox(HWND hDlg, HWND hwndCombo, char* nthcp, char* nthd, char* nthdir, char *nthnames)
\r
6860 char buf[MSG_SIZ];
\r
6863 InitComboStringsFromOption(hwndCombo, nthnames);
\r
6864 q = QuoteForFilename(nthcp);
\r
6865 sprintf(buf, "%s%s%s", q, nthcp, q);
\r
6866 if (*nthdir != NULLCHAR) {
\r
6867 q = QuoteForFilename(nthdir);
\r
6868 sprintf(buf + strlen(buf), " /%s=%s%s%s", nthd, q, nthdir, q);
\r
6870 if (*nthcp == NULLCHAR) {
\r
6871 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) 0, (LPARAM) 0);
\r
6872 } else if (SendMessage(hwndCombo, CB_SELECTSTRING, (WPARAM) -1, (LPARAM) buf) == CB_ERR) {
\r
6873 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) -1, (LPARAM) 0);
\r
6874 SendMessage(hwndCombo, WM_SETTEXT, (WPARAM) 0, (LPARAM) buf);
\r
6879 StartupDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
6881 char buf[MSG_SIZ];
\r
6885 switch (message) {
\r
6886 case WM_INITDIALOG:
\r
6887 /* Center the dialog */
\r
6888 CenterWindow (hDlg, GetDesktopWindow());
\r
6889 /* Initialize the dialog items */
\r
6890 InitEngineBox(hDlg, GetDlgItem(hDlg, OPT_ChessEngineName),
\r
6891 appData.firstChessProgram, "fd", appData.firstDirectory,
\r
6892 firstChessProgramNames);
\r
6893 InitEngineBox(hDlg, GetDlgItem(hDlg, OPT_SecondChessEngineName),
\r
6894 appData.secondChessProgram, "sd", appData.secondDirectory,
\r
6895 secondChessProgramNames);
\r
6896 hwndCombo = GetDlgItem(hDlg, OPT_ChessServerName);
\r
6897 InitComboStringsFromOption(hwndCombo, icsNames);
\r
6898 sprintf(buf, "%s /icsport=%s", appData.icsHost, appData.icsPort);
\r
6899 if (*appData.icsHelper != NULLCHAR) {
\r
6900 char *q = QuoteForFilename(appData.icsHelper);
\r
6901 sprintf(buf + strlen(buf), " /icshelper=%s%s%s", q, appData.icsHelper, q);
\r
6903 if (*appData.icsHost == NULLCHAR) {
\r
6904 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) 0, (LPARAM) 0);
\r
6905 /*SendMessage(hwndCombo, CB_SHOWDROPDOWN, (WPARAM) TRUE, (LPARAM) 0); !!too soon */
\r
6906 } else if (SendMessage(hwndCombo, CB_SELECTSTRING, (WPARAM) -1, (LPARAM) buf) == CB_ERR) {
\r
6907 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) -1, (LPARAM) 0);
\r
6908 SendMessage(hwndCombo, WM_SETTEXT, (WPARAM) 0, (LPARAM) buf);
\r
6911 if (appData.icsActive) {
\r
6912 CheckDlgButton(hDlg, OPT_ChessServer, BST_CHECKED);
\r
6914 else if (appData.noChessProgram) {
\r
6915 CheckDlgButton(hDlg, OPT_View, BST_CHECKED);
\r
6918 CheckDlgButton(hDlg, OPT_ChessEngine, BST_CHECKED);
\r
6921 SetStartupDialogEnables(hDlg);
\r
6925 switch (LOWORD(wParam)) {
\r
6927 if (IsDlgButtonChecked(hDlg, OPT_ChessEngine)) {
\r
6928 strcpy(buf, "/fcp=");
\r
6929 GetDlgItemText(hDlg, OPT_ChessEngineName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
6931 ParseArgs(StringGet, &p);
\r
6932 strcpy(buf, "/scp=");
\r
6933 GetDlgItemText(hDlg, OPT_SecondChessEngineName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
6935 ParseArgs(StringGet, &p);
\r
6936 appData.noChessProgram = FALSE;
\r
6937 appData.icsActive = FALSE;
\r
6938 } else if (IsDlgButtonChecked(hDlg, OPT_ChessServer)) {
\r
6939 strcpy(buf, "/ics /icshost=");
\r
6940 GetDlgItemText(hDlg, OPT_ChessServerName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
6942 ParseArgs(StringGet, &p);
\r
6943 if (appData.zippyPlay) {
\r
6944 strcpy(buf, "/fcp=");
\r
6945 GetDlgItemText(hDlg, OPT_ChessEngineName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
6947 ParseArgs(StringGet, &p);
\r
6949 } else if (IsDlgButtonChecked(hDlg, OPT_View)) {
\r
6950 appData.noChessProgram = TRUE;
\r
6951 appData.icsActive = FALSE;
\r
6953 MessageBox(hDlg, "Choose an option, or cancel to exit",
\r
6954 "Option Error", MB_OK|MB_ICONEXCLAMATION);
\r
6957 if (IsDlgButtonChecked(hDlg, OPT_AnyAdditional)) {
\r
6958 GetDlgItemText(hDlg, OPT_AdditionalOptions, buf, sizeof(buf));
\r
6960 ParseArgs(StringGet, &p);
\r
6962 EndDialog(hDlg, TRUE);
\r
6969 case IDM_HELPCONTENTS:
\r
6970 if (!WinHelp (hDlg, "winboard.hlp", HELP_KEY,(DWORD)(LPSTR)"CONTENTS")) {
\r
6971 MessageBox (GetFocus(),
\r
6972 "Unable to activate help",
\r
6973 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
6978 SetStartupDialogEnables(hDlg);
\r
6986 /*---------------------------------------------------------------------------*\
\r
6988 * About box dialog functions
\r
6990 \*---------------------------------------------------------------------------*/
\r
6992 /* Process messages for "About" dialog box */
\r
6994 About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
6996 switch (message) {
\r
6997 case WM_INITDIALOG: /* message: initialize dialog box */
\r
6998 /* Center the dialog over the application window */
\r
6999 CenterWindow (hDlg, GetWindow (hDlg, GW_OWNER));
\r
7000 SetDlgItemText(hDlg, ABOUTBOX_Version, programVersion);
\r
7003 case WM_COMMAND: /* message: received a command */
\r
7004 if (LOWORD(wParam) == IDOK /* "OK" box selected? */
\r
7005 || LOWORD(wParam) == IDCANCEL) { /* System menu close command? */
\r
7006 EndDialog(hDlg, TRUE); /* Exit the dialog */
\r
7014 /*---------------------------------------------------------------------------*\
\r
7016 * Comment Dialog functions
\r
7018 \*---------------------------------------------------------------------------*/
\r
7021 CommentDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7023 static HANDLE hwndText = NULL;
\r
7024 int len, newSizeX, newSizeY, flags;
\r
7025 static int sizeX, sizeY;
\r
7030 switch (message) {
\r
7031 case WM_INITDIALOG: /* message: initialize dialog box */
\r
7032 /* Initialize the dialog items */
\r
7033 hwndText = GetDlgItem(hDlg, OPT_CommentText);
\r
7034 SetDlgItemText(hDlg, OPT_CommentText, commentText);
\r
7035 EnableWindow(GetDlgItem(hDlg, OPT_CancelComment), editComment);
\r
7036 EnableWindow(GetDlgItem(hDlg, OPT_ClearComment), editComment);
\r
7037 EnableWindow(GetDlgItem(hDlg, OPT_EditComment), !editComment);
\r
7038 SendMessage(hwndText, EM_SETREADONLY, !editComment, 0);
\r
7039 SetWindowText(hDlg, commentTitle);
\r
7040 if (editComment) {
\r
7041 SetFocus(hwndText);
\r
7043 SetFocus(GetDlgItem(hDlg, IDOK));
\r
7045 SendMessage(GetDlgItem(hDlg, OPT_CommentText),
\r
7046 WM_SETFONT, (WPARAM)font[boardSize][COMMENT_FONT]->hf,
\r
7047 MAKELPARAM(FALSE, 0));
\r
7048 /* Size and position the dialog */
\r
7049 if (!commentDialog) {
\r
7050 commentDialog = hDlg;
\r
7051 flags = SWP_NOZORDER;
\r
7052 GetClientRect(hDlg, &rect);
\r
7053 sizeX = rect.right;
\r
7054 sizeY = rect.bottom;
\r
7055 if (commentX != CW_USEDEFAULT && commentY != CW_USEDEFAULT &&
\r
7056 commentW != CW_USEDEFAULT && commentH != CW_USEDEFAULT) {
\r
7057 WINDOWPLACEMENT wp;
\r
7058 EnsureOnScreen(&commentX, &commentY);
\r
7059 wp.length = sizeof(WINDOWPLACEMENT);
\r
7061 wp.showCmd = SW_SHOW;
\r
7062 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
7063 wp.rcNormalPosition.left = commentX;
\r
7064 wp.rcNormalPosition.right = commentX + commentW;
\r
7065 wp.rcNormalPosition.top = commentY;
\r
7066 wp.rcNormalPosition.bottom = commentY + commentH;
\r
7067 SetWindowPlacement(hDlg, &wp);
\r
7069 GetClientRect(hDlg, &rect);
\r
7070 newSizeX = rect.right;
\r
7071 newSizeY = rect.bottom;
\r
7072 ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY,
\r
7073 newSizeX, newSizeY);
\r
7080 case WM_COMMAND: /* message: received a command */
\r
7081 switch (LOWORD(wParam)) {
\r
7083 if (editComment) {
\r
7085 /* Read changed options from the dialog box */
\r
7086 hwndText = GetDlgItem(hDlg, OPT_CommentText);
\r
7087 len = GetWindowTextLength(hwndText);
\r
7088 str = (char *) malloc(len + 1);
\r
7089 GetWindowText(hwndText, str, len + 1);
\r
7098 ReplaceComment(commentIndex, str);
\r
7105 case OPT_CancelComment:
\r
7109 case OPT_ClearComment:
\r
7110 SetDlgItemText(hDlg, OPT_CommentText, "");
\r
7113 case OPT_EditComment:
\r
7114 EditCommentEvent();
\r
7123 newSizeX = LOWORD(lParam);
\r
7124 newSizeY = HIWORD(lParam);
\r
7125 ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY, newSizeX, newSizeY);
\r
7130 case WM_GETMINMAXINFO:
\r
7131 /* Prevent resizing window too small */
\r
7132 mmi = (MINMAXINFO *) lParam;
\r
7133 mmi->ptMinTrackSize.x = 100;
\r
7134 mmi->ptMinTrackSize.y = 100;
\r
7141 EitherCommentPopUp(int index, char *title, char *str, BOOLEAN edit)
\r
7146 CheckMenuItem(GetMenu(hwndMain), IDM_EditComment, edit ? MF_CHECKED : MF_UNCHECKED);
\r
7148 if (str == NULL) str = "";
\r
7149 p = (char *) malloc(2 * strlen(str) + 2);
\r
7152 if (*str == '\n') *q++ = '\r';
\r
7156 if (commentText != NULL) free(commentText);
\r
7158 commentIndex = index;
\r
7159 commentTitle = title;
\r
7161 editComment = edit;
\r
7163 if (commentDialog) {
\r
7164 SendMessage(commentDialog, WM_INITDIALOG, 0, 0);
\r
7165 if (!commentDialogUp) ShowWindow(commentDialog, SW_SHOW);
\r
7167 lpProc = MakeProcInstance((FARPROC)CommentDialog, hInst);
\r
7168 CreateDialog(hInst, MAKEINTRESOURCE(DLG_EditComment),
\r
7169 hwndMain, (DLGPROC)lpProc);
\r
7170 FreeProcInstance(lpProc);
\r
7172 commentDialogUp = TRUE;
\r
7176 /*---------------------------------------------------------------------------*\
\r
7178 * Type-in move dialog functions
\r
7180 \*---------------------------------------------------------------------------*/
\r
7183 TypeInMoveDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7185 char move[MSG_SIZ];
\r
7187 ChessMove moveType;
\r
7188 int fromX, fromY, toX, toY;
\r
7191 switch (message) {
\r
7192 case WM_INITDIALOG:
\r
7193 move[0] = (char) lParam;
\r
7194 move[1] = NULLCHAR;
\r
7195 CenterWindowEx(hDlg, GetWindow(hDlg, GW_OWNER), 1 );
\r
7196 hInput = GetDlgItem(hDlg, OPT_Move);
\r
7197 SetWindowText(hInput, move);
\r
7199 SendMessage(hInput, EM_SETSEL, (WPARAM)9999, (LPARAM)9999);
\r
7203 switch (LOWORD(wParam)) {
\r
7205 if (gameMode != EditGame && currentMove != forwardMostMove &&
\r
7206 gameMode != Training) {
\r
7207 DisplayMoveError("Displayed move is not current");
\r
7209 GetDlgItemText(hDlg, OPT_Move, move, sizeof(move));
\r
7210 if (ParseOneMove(move, gameMode == EditPosition ? blackPlaysFirst : currentMove,
\r
7211 &moveType, &fromX, &fromY, &toX, &toY, &promoChar)) {
\r
7212 if (gameMode != Training)
\r
7213 forwardMostMove = currentMove;
\r
7214 UserMoveEvent(fromX, fromY, toX, toY, promoChar);
\r
7216 DisplayMoveError("Could not parse move");
\r
7219 EndDialog(hDlg, TRUE);
\r
7222 EndDialog(hDlg, FALSE);
\r
7233 PopUpMoveDialog(char firstchar)
\r
7237 if ((gameMode == BeginningOfGame && !appData.icsActive) ||
\r
7238 gameMode == MachinePlaysWhite || gameMode == MachinePlaysBlack ||
\r
7239 gameMode == AnalyzeMode || gameMode == EditGame ||
\r
7240 gameMode == EditPosition || gameMode == IcsExamining ||
\r
7241 gameMode == IcsPlayingWhite || gameMode == IcsPlayingBlack ||
\r
7242 gameMode == Training) {
\r
7243 lpProc = MakeProcInstance((FARPROC)TypeInMoveDialog, hInst);
\r
7244 DialogBoxParam(hInst, MAKEINTRESOURCE(DLG_TypeInMove),
\r
7245 hwndMain, (DLGPROC)lpProc, (LPARAM)firstchar);
\r
7246 FreeProcInstance(lpProc);
\r
7250 /*---------------------------------------------------------------------------*\
\r
7252 * Type-in name dialog functions
\r
7254 \*---------------------------------------------------------------------------*/
\r
7257 TypeInNameDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7259 char move[MSG_SIZ];
\r
7262 switch (message) {
\r
7263 case WM_INITDIALOG:
\r
7264 move[0] = (char) lParam;
\r
7265 move[1] = NULLCHAR;
\r
7266 CenterWindowEx(hDlg, GetWindow(hDlg, GW_OWNER), 1 );
\r
7267 hInput = GetDlgItem(hDlg, OPT_Name);
\r
7268 SetWindowText(hInput, move);
\r
7270 SendMessage(hInput, EM_SETSEL, (WPARAM)9999, (LPARAM)9999);
\r
7274 switch (LOWORD(wParam)) {
\r
7276 GetDlgItemText(hDlg, OPT_Name, move, sizeof(move));
\r
7277 appData.userName = strdup(move);
\r
7279 EndDialog(hDlg, TRUE);
\r
7282 EndDialog(hDlg, FALSE);
\r
7293 PopUpNameDialog(char firstchar)
\r
7297 lpProc = MakeProcInstance((FARPROC)TypeInNameDialog, hInst);
\r
7298 DialogBoxParam(hInst, MAKEINTRESOURCE(DLG_TypeInName),
\r
7299 hwndMain, (DLGPROC)lpProc, (LPARAM)firstchar);
\r
7300 FreeProcInstance(lpProc);
\r
7303 /*---------------------------------------------------------------------------*\
\r
7307 \*---------------------------------------------------------------------------*/
\r
7309 /* Nonmodal error box */
\r
7310 LRESULT CALLBACK ErrorDialog(HWND hDlg, UINT message,
\r
7311 WPARAM wParam, LPARAM lParam);
\r
7314 ErrorPopUp(char *title, char *content)
\r
7318 BOOLEAN modal = hwndMain == NULL;
\r
7336 strncpy(errorTitle, title, sizeof(errorTitle));
\r
7337 errorTitle[sizeof(errorTitle) - 1] = '\0';
\r
7340 MessageBox(NULL, errorMessage, errorTitle, MB_OK|MB_ICONEXCLAMATION);
\r
7342 lpProc = MakeProcInstance((FARPROC)ErrorDialog, hInst);
\r
7343 CreateDialog(hInst, MAKEINTRESOURCE(DLG_Error),
\r
7344 hwndMain, (DLGPROC)lpProc);
\r
7345 FreeProcInstance(lpProc);
\r
7352 if (!appData.popupMoveErrors && moveErrorMessageUp) DisplayMessage("", "");
\r
7353 if (errorDialog == NULL) return;
\r
7354 DestroyWindow(errorDialog);
\r
7355 errorDialog = NULL;
\r
7359 ErrorDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7364 switch (message) {
\r
7365 case WM_INITDIALOG:
\r
7366 GetWindowRect(hDlg, &rChild);
\r
7369 SetWindowPos(hDlg, NULL, rChild.left,
\r
7370 rChild.top + boardRect.top - (rChild.bottom - rChild.top),
\r
7371 0, 0, SWP_NOZORDER|SWP_NOSIZE);
\r
7375 [AS] It seems that the above code wants to move the dialog up in the "caption
\r
7376 area" of the main window, but it uses the dialog height as an hard-coded constant,
\r
7377 and it doesn't work when you resize the dialog.
\r
7378 For now, just give it a default position.
\r
7380 SetWindowPos(hDlg, NULL, boardRect.left+8, boardRect.top+8, 0, 0, SWP_NOZORDER|SWP_NOSIZE);
\r
7382 errorDialog = hDlg;
\r
7383 SetWindowText(hDlg, errorTitle);
\r
7384 hwndText = GetDlgItem(hDlg, OPT_ErrorText);
\r
7385 SetDlgItemText(hDlg, OPT_ErrorText, errorMessage);
\r
7389 switch (LOWORD(wParam)) {
\r
7392 if (errorDialog == hDlg) errorDialog = NULL;
\r
7393 DestroyWindow(hDlg);
\r
7405 HWND gothicDialog = NULL;
\r
7408 GothicDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7412 int height = GetSystemMetrics(SM_CYCAPTION)+GetSystemMetrics(SM_CYFRAME);
\r
7414 switch (message) {
\r
7415 case WM_INITDIALOG:
\r
7416 GetWindowRect(hDlg, &rChild);
\r
7418 SetWindowPos(hDlg, NULL, boardX, boardY-height, winWidth, height,
\r
7422 [AS] It seems that the above code wants to move the dialog up in the "caption
\r
7423 area" of the main window, but it uses the dialog height as an hard-coded constant,
\r
7424 and it doesn't work when you resize the dialog.
\r
7425 For now, just give it a default position.
\r
7427 gothicDialog = hDlg;
\r
7428 SetWindowText(hDlg, errorTitle);
\r
7429 hwndText = GetDlgItem(hDlg, OPT_ErrorText);
\r
7430 SetDlgItemText(hDlg, OPT_ErrorText, errorMessage);
\r
7434 switch (LOWORD(wParam)) {
\r
7437 if (errorDialog == hDlg) errorDialog = NULL;
\r
7438 DestroyWindow(hDlg);
\r
7450 GothicPopUp(char *title, VariantClass variant)
\r
7453 static char *lastTitle;
\r
7455 strncpy(errorTitle, title, sizeof(errorTitle));
\r
7456 errorTitle[sizeof(errorTitle) - 1] = '\0';
\r
7458 if(lastTitle != title && gothicDialog != NULL) {
\r
7459 DestroyWindow(gothicDialog);
\r
7460 gothicDialog = NULL;
\r
7462 if(variant != VariantNormal && gothicDialog == NULL) {
\r
7463 title = lastTitle;
\r
7464 lpProc = MakeProcInstance((FARPROC)GothicDialog, hInst);
\r
7465 CreateDialog(hInst, MAKEINTRESOURCE(DLG_Error),
\r
7466 hwndMain, (DLGPROC)lpProc);
\r
7467 FreeProcInstance(lpProc);
\r
7472 /*---------------------------------------------------------------------------*\
\r
7474 * Ics Interaction console functions
\r
7476 \*---------------------------------------------------------------------------*/
\r
7478 #define HISTORY_SIZE 64
\r
7479 static char *history[HISTORY_SIZE];
\r
7480 int histIn = 0, histP = 0;
\r
7483 SaveInHistory(char *cmd)
\r
7485 if (history[histIn] != NULL) {
\r
7486 free(history[histIn]);
\r
7487 history[histIn] = NULL;
\r
7489 if (*cmd == NULLCHAR) return;
\r
7490 history[histIn] = StrSave(cmd);
\r
7491 histIn = (histIn + 1) % HISTORY_SIZE;
\r
7492 if (history[histIn] != NULL) {
\r
7493 free(history[histIn]);
\r
7494 history[histIn] = NULL;
\r
7500 PrevInHistory(char *cmd)
\r
7503 if (histP == histIn) {
\r
7504 if (history[histIn] != NULL) free(history[histIn]);
\r
7505 history[histIn] = StrSave(cmd);
\r
7507 newhp = (histP - 1 + HISTORY_SIZE) % HISTORY_SIZE;
\r
7508 if (newhp == histIn || history[newhp] == NULL) return NULL;
\r
7510 return history[histP];
\r
7516 if (histP == histIn) return NULL;
\r
7517 histP = (histP + 1) % HISTORY_SIZE;
\r
7518 return history[histP];
\r
7525 BOOLEAN immediate;
\r
7526 } IcsTextMenuEntry;
\r
7527 #define ICS_TEXT_MENU_SIZE (IDM_CommandXLast - IDM_CommandX + 1)
\r
7528 IcsTextMenuEntry icsTextMenuEntry[ICS_TEXT_MENU_SIZE];
\r
7531 ParseIcsTextMenu(char *icsTextMenuString)
\r
7534 IcsTextMenuEntry *e = icsTextMenuEntry;
\r
7535 char *p = icsTextMenuString;
\r
7536 while (e->item != NULL && e < icsTextMenuEntry + ICS_TEXT_MENU_SIZE) {
\r
7539 if (e->command != NULL) {
\r
7541 e->command = NULL;
\r
7545 e = icsTextMenuEntry;
\r
7546 while (*p && e < icsTextMenuEntry + ICS_TEXT_MENU_SIZE) {
\r
7547 if (*p == ';' || *p == '\n') {
\r
7548 e->item = strdup("-");
\r
7549 e->command = NULL;
\r
7551 } else if (*p == '-') {
\r
7552 e->item = strdup("-");
\r
7553 e->command = NULL;
\r
7557 char *q, *r, *s, *t;
\r
7559 q = strchr(p, ',');
\r
7560 if (q == NULL) break;
\r
7562 r = strchr(q + 1, ',');
\r
7563 if (r == NULL) break;
\r
7565 s = strchr(r + 1, ',');
\r
7566 if (s == NULL) break;
\r
7569 t = strchr(s + 1, c);
\r
7572 t = strchr(s + 1, c);
\r
7574 if (t != NULL) *t = NULLCHAR;
\r
7575 e->item = strdup(p);
\r
7576 e->command = strdup(q + 1);
\r
7577 e->getname = *(r + 1) != '0';
\r
7578 e->immediate = *(s + 1) != '0';
\r
7582 if (t == NULL) break;
\r
7591 LoadIcsTextMenu(IcsTextMenuEntry *e)
\r
7595 hmenu = LoadMenu(hInst, "TextMenu");
\r
7596 h = GetSubMenu(hmenu, 0);
\r
7598 if (strcmp(e->item, "-") == 0) {
\r
7599 AppendMenu(h, MF_SEPARATOR, 0, 0);
\r
7601 if (e->item[0] == '|') {
\r
7602 AppendMenu(h, MF_STRING|MF_MENUBARBREAK,
\r
7603 IDM_CommandX + i, &e->item[1]);
\r
7605 AppendMenu(h, MF_STRING, IDM_CommandX + i, e->item);
\r
7614 WNDPROC consoleTextWindowProc;
\r
7617 CommandX(HWND hwnd, char *command, BOOLEAN getname, BOOLEAN immediate)
\r
7619 char buf[MSG_SIZ], name[MSG_SIZ];
\r
7620 HWND hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
7624 SetWindowText(hInput, command);
\r
7626 SendMessage(hInput, WM_CHAR, '\r', 0);
\r
7628 sel.cpMin = 999999;
\r
7629 sel.cpMax = 999999;
\r
7630 SendMessage(hInput, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7635 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
7636 if (sel.cpMin == sel.cpMax) {
\r
7637 /* Expand to surrounding word */
\r
7640 tr.chrg.cpMax = sel.cpMin;
\r
7641 tr.chrg.cpMin = --sel.cpMin;
\r
7642 if (sel.cpMin < 0) break;
\r
7643 tr.lpstrText = name;
\r
7644 SendMessage(hwnd, EM_GETTEXTRANGE, 0, (LPARAM) &tr);
\r
7645 } while (isalpha(name[0]) || isdigit(name[0]) || name[0] == '-');
\r
7649 tr.chrg.cpMin = sel.cpMax;
\r
7650 tr.chrg.cpMax = ++sel.cpMax;
\r
7651 tr.lpstrText = name;
\r
7652 if (SendMessage(hwnd, EM_GETTEXTRANGE, 0, (LPARAM) &tr) < 1) break;
\r
7653 } while (isalpha(name[0]) || isdigit(name[0]) || name[0] == '-');
\r
7656 if (sel.cpMax == sel.cpMin || sel.cpMax - sel.cpMin > MSG_SIZ/2) {
\r
7657 MessageBeep(MB_ICONEXCLAMATION);
\r
7661 tr.lpstrText = name;
\r
7662 SendMessage(hwnd, EM_GETTEXTRANGE, 0, (LPARAM) &tr);
\r
7664 if (sel.cpMax - sel.cpMin > MSG_SIZ/2) {
\r
7665 MessageBeep(MB_ICONEXCLAMATION);
\r
7668 SendMessage(hwnd, EM_GETSELTEXT, 0, (LPARAM) name);
\r
7671 sprintf(buf, "%s %s", command, name);
\r
7672 SetWindowText(hInput, buf);
\r
7673 SendMessage(hInput, WM_CHAR, '\r', 0);
\r
7675 sprintf(buf, "%s %s ", command, name); /* trailing space */
\r
7676 SetWindowText(hInput, buf);
\r
7677 sel.cpMin = 999999;
\r
7678 sel.cpMax = 999999;
\r
7679 SendMessage(hInput, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7685 ConsoleTextSubclass(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
7690 switch (message) {
\r
7692 if (!(GetKeyState(VK_CONTROL) & ~1)) break;
\r
7695 SendMessage(hwnd, EM_LINESCROLL, 0, -999999);
\r
7698 sel.cpMin = 999999;
\r
7699 sel.cpMax = 999999;
\r
7700 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7701 SendMessage(hwnd, EM_SCROLLCARET, 0, 0);
\r
7706 if (wParam == '\t') {
\r
7707 if (GetKeyState(VK_SHIFT) < 0) {
\r
7709 if (IsIconic(hwndMain)) ShowWindow(hwndMain, SW_RESTORE);
\r
7710 if (buttonDesc[0].hwnd) {
\r
7711 SetFocus(buttonDesc[0].hwnd);
\r
7713 SetFocus(hwndMain);
\r
7717 SetFocus(GetDlgItem(hwndConsole, OPT_ConsoleInput));
\r
7720 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
7722 SendMessage(hInput, message, wParam, lParam);
\r
7726 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
7728 return SendMessage(hInput, message, wParam, lParam);
\r
7729 case WM_MBUTTONDOWN:
\r
7730 return SendMessage(hwnd, WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
7731 case WM_RBUTTONDOWN:
\r
7732 if (!(GetKeyState(VK_SHIFT) & ~1)) {
\r
7733 /* Move selection here if it was empty */
\r
7735 pt.x = LOWORD(lParam);
\r
7736 pt.y = HIWORD(lParam);
\r
7737 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
7738 if (sel.cpMin == sel.cpMax) {
\r
7739 sel.cpMin = SendMessage(hwnd, EM_CHARFROMPOS, 0, (LPARAM)&pt); /*doc is wrong*/
\r
7740 sel.cpMax = sel.cpMin;
\r
7741 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7743 SendMessage(hwnd, EM_HIDESELECTION, FALSE, FALSE);
\r
7746 case WM_RBUTTONUP:
\r
7747 if (GetKeyState(VK_SHIFT) & ~1) {
\r
7748 SendDlgItemMessage(hwndConsole, OPT_ConsoleText,
\r
7749 WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
7752 HMENU hmenu = LoadIcsTextMenu(icsTextMenuEntry);
\r
7753 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
7754 if (sel.cpMin == sel.cpMax) {
\r
7755 EnableMenuItem(hmenu, IDM_Copy, MF_BYCOMMAND|MF_GRAYED);
\r
7756 EnableMenuItem(hmenu, IDM_QuickPaste, MF_BYCOMMAND|MF_GRAYED);
\r
7758 if (!IsClipboardFormatAvailable(CF_TEXT)) {
\r
7759 EnableMenuItem(hmenu, IDM_Paste, MF_BYCOMMAND|MF_GRAYED);
\r
7761 pt.x = LOWORD(lParam);
\r
7762 pt.y = HIWORD(lParam);
\r
7763 MenuPopup(hwnd, pt, hmenu, -1);
\r
7767 switch (LOWORD(wParam)) {
\r
7768 case IDM_QuickPaste:
\r
7770 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
7771 if (sel.cpMin == sel.cpMax) {
\r
7772 MessageBeep(MB_ICONEXCLAMATION);
\r
7775 SendMessage(hwnd, WM_COPY, 0, 0);
\r
7776 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
7777 SendMessage(hInput, WM_PASTE, 0, 0);
\r
7782 SendMessage(hwnd, WM_CUT, 0, 0);
\r
7785 SendMessage(hwnd, WM_PASTE, 0, 0);
\r
7788 SendMessage(hwnd, WM_COPY, 0, 0);
\r
7792 int i = LOWORD(wParam) - IDM_CommandX;
\r
7793 if (i >= 0 && i < ICS_TEXT_MENU_SIZE &&
\r
7794 icsTextMenuEntry[i].command != NULL) {
\r
7795 CommandX(hwnd, icsTextMenuEntry[i].command,
\r
7796 icsTextMenuEntry[i].getname,
\r
7797 icsTextMenuEntry[i].immediate);
\r
7805 return (*consoleTextWindowProc)(hwnd, message, wParam, lParam);
\r
7808 WNDPROC consoleInputWindowProc;
\r
7811 ConsoleInputSubclass(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
7813 char buf[MSG_SIZ];
\r
7815 static BOOL sendNextChar = FALSE;
\r
7816 static BOOL quoteNextChar = FALSE;
\r
7817 InputSource *is = consoleInputSource;
\r
7821 switch (message) {
\r
7823 if (!appData.localLineEditing || sendNextChar) {
\r
7824 is->buf[0] = (CHAR) wParam;
\r
7826 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
7827 sendNextChar = FALSE;
\r
7830 if (quoteNextChar) {
\r
7831 buf[0] = (char) wParam;
\r
7832 buf[1] = NULLCHAR;
\r
7833 SendMessage(hwnd, EM_REPLACESEL, TRUE, (LPARAM) buf);
\r
7834 quoteNextChar = FALSE;
\r
7838 case '\r': /* Enter key */
\r
7839 is->count = GetWindowText(hwnd, is->buf, INPUT_SOURCE_BUF_SIZE-1);
\r
7840 if (consoleEcho) SaveInHistory(is->buf);
\r
7841 is->buf[is->count++] = '\n';
\r
7842 is->buf[is->count] = NULLCHAR;
\r
7843 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
7844 if (consoleEcho) {
\r
7845 ConsoleOutput(is->buf, is->count, TRUE);
\r
7846 } else if (appData.localLineEditing) {
\r
7847 ConsoleOutput("\n", 1, TRUE);
\r
7850 case '\033': /* Escape key */
\r
7851 SetWindowText(hwnd, "");
\r
7852 cf.cbSize = sizeof(CHARFORMAT);
\r
7853 cf.dwMask = CFM_COLOR|CFM_BOLD|CFM_ITALIC|CFM_UNDERLINE|CFM_STRIKEOUT;
\r
7854 if (consoleEcho) {
\r
7855 cf.crTextColor = textAttribs[ColorNormal].color;
\r
7857 cf.crTextColor = COLOR_ECHOOFF;
\r
7859 cf.dwEffects = textAttribs[ColorNormal].effects;
\r
7860 SendMessage(hwnd, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&cf);
\r
7862 case '\t': /* Tab key */
\r
7863 if (GetKeyState(VK_SHIFT) < 0) {
\r
7865 SetFocus(GetDlgItem(hwndConsole, OPT_ConsoleText));
\r
7868 if (IsIconic(hwndMain)) ShowWindow(hwndMain, SW_RESTORE);
\r
7869 if (buttonDesc[0].hwnd) {
\r
7870 SetFocus(buttonDesc[0].hwnd);
\r
7872 SetFocus(hwndMain);
\r
7876 case '\023': /* Ctrl+S */
\r
7877 sendNextChar = TRUE;
\r
7879 case '\021': /* Ctrl+Q */
\r
7880 quoteNextChar = TRUE;
\r
7889 GetWindowText(hwnd, buf, MSG_SIZ);
\r
7890 p = PrevInHistory(buf);
\r
7892 SetWindowText(hwnd, p);
\r
7893 sel.cpMin = 999999;
\r
7894 sel.cpMax = 999999;
\r
7895 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7900 p = NextInHistory();
\r
7902 SetWindowText(hwnd, p);
\r
7903 sel.cpMin = 999999;
\r
7904 sel.cpMax = 999999;
\r
7905 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7911 if (!(GetKeyState(VK_CONTROL) & ~1)) break;
\r
7915 SendDlgItemMessage(hwndConsole, OPT_ConsoleText, message, wParam, lParam);
\r
7919 case WM_MBUTTONDOWN:
\r
7920 SendDlgItemMessage(hwndConsole, OPT_ConsoleText,
\r
7921 WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
7923 case WM_RBUTTONUP:
\r
7924 if (GetKeyState(VK_SHIFT) & ~1) {
\r
7925 SendDlgItemMessage(hwndConsole, OPT_ConsoleText,
\r
7926 WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
7930 hmenu = LoadMenu(hInst, "InputMenu");
\r
7931 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
7932 if (sel.cpMin == sel.cpMax) {
\r
7933 EnableMenuItem(hmenu, IDM_Copy, MF_BYCOMMAND|MF_GRAYED);
\r
7934 EnableMenuItem(hmenu, IDM_Cut, MF_BYCOMMAND|MF_GRAYED);
\r
7936 if (!IsClipboardFormatAvailable(CF_TEXT)) {
\r
7937 EnableMenuItem(hmenu, IDM_Paste, MF_BYCOMMAND|MF_GRAYED);
\r
7939 pt.x = LOWORD(lParam);
\r
7940 pt.y = HIWORD(lParam);
\r
7941 MenuPopup(hwnd, pt, hmenu, -1);
\r
7945 switch (LOWORD(wParam)) {
\r
7947 SendMessage(hwnd, EM_UNDO, 0, 0);
\r
7949 case IDM_SelectAll:
\r
7951 sel.cpMax = -1; /*999999?*/
\r
7952 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7955 SendMessage(hwnd, WM_CUT, 0, 0);
\r
7958 SendMessage(hwnd, WM_PASTE, 0, 0);
\r
7961 SendMessage(hwnd, WM_COPY, 0, 0);
\r
7966 return (*consoleInputWindowProc)(hwnd, message, wParam, lParam);
\r
7969 #define CO_MAX 100000
\r
7970 #define CO_TRIM 1000
\r
7973 ConsoleWndProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7975 static SnapData sd;
\r
7976 static HWND hText, hInput /*, hFocus*/;
\r
7977 // InputSource *is = consoleInputSource;
\r
7979 static int sizeX, sizeY;
\r
7980 int newSizeX, newSizeY;
\r
7983 switch (message) {
\r
7984 case WM_INITDIALOG: /* message: initialize dialog box */
\r
7985 hwndConsole = hDlg;
\r
7986 hText = GetDlgItem(hDlg, OPT_ConsoleText);
\r
7987 hInput = GetDlgItem(hDlg, OPT_ConsoleInput);
\r
7989 consoleTextWindowProc = (WNDPROC)
\r
7990 SetWindowLong(hText, GWL_WNDPROC, (LONG) ConsoleTextSubclass);
\r
7991 SendMessage(hText, EM_SETBKGNDCOLOR, FALSE, consoleBackgroundColor);
\r
7992 consoleInputWindowProc = (WNDPROC)
\r
7993 SetWindowLong(hInput, GWL_WNDPROC, (LONG) ConsoleInputSubclass);
\r
7994 SendMessage(hInput, EM_SETBKGNDCOLOR, FALSE, consoleBackgroundColor);
\r
7995 Colorize(ColorNormal, TRUE);
\r
7996 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM) &consoleCF);
\r
7997 ChangedConsoleFont();
\r
7998 GetClientRect(hDlg, &rect);
\r
7999 sizeX = rect.right;
\r
8000 sizeY = rect.bottom;
\r
8001 if (consoleX != CW_USEDEFAULT && consoleY != CW_USEDEFAULT &&
\r
8002 consoleW != CW_USEDEFAULT && consoleH != CW_USEDEFAULT) {
\r
8003 WINDOWPLACEMENT wp;
\r
8004 EnsureOnScreen(&consoleX, &consoleY);
\r
8005 wp.length = sizeof(WINDOWPLACEMENT);
\r
8007 wp.showCmd = SW_SHOW;
\r
8008 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
8009 wp.rcNormalPosition.left = consoleX;
\r
8010 wp.rcNormalPosition.right = consoleX + consoleW;
\r
8011 wp.rcNormalPosition.top = consoleY;
\r
8012 wp.rcNormalPosition.bottom = consoleY + consoleH;
\r
8013 SetWindowPlacement(hDlg, &wp);
\r
8016 // [HGM] Chessknight's change 2004-07-13
\r
8017 else { /* Determine Defaults */
\r
8018 WINDOWPLACEMENT wp;
\r
8019 consoleX = winWidth + 1;
\r
8020 consoleY = boardY;
\r
8021 consoleW = screenWidth - winWidth;
\r
8022 consoleH = winHeight;
\r
8023 EnsureOnScreen(&consoleX, &consoleY);
\r
8024 wp.length = sizeof(WINDOWPLACEMENT);
\r
8026 wp.showCmd = SW_SHOW;
\r
8027 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
8028 wp.rcNormalPosition.left = consoleX;
\r
8029 wp.rcNormalPosition.right = consoleX + consoleW;
\r
8030 wp.rcNormalPosition.top = consoleY;
\r
8031 wp.rcNormalPosition.bottom = consoleY + consoleH;
\r
8032 SetWindowPlacement(hDlg, &wp);
\r
8047 if (IsIconic(hDlg)) break;
\r
8048 newSizeX = LOWORD(lParam);
\r
8049 newSizeY = HIWORD(lParam);
\r
8050 if (sizeX != newSizeX || sizeY != newSizeY) {
\r
8051 RECT rectText, rectInput;
\r
8053 int newTextHeight, newTextWidth;
\r
8054 GetWindowRect(hText, &rectText);
\r
8055 newTextWidth = rectText.right - rectText.left + newSizeX - sizeX;
\r
8056 newTextHeight = rectText.bottom - rectText.top + newSizeY - sizeY;
\r
8057 if (newTextHeight < 0) {
\r
8058 newSizeY += -newTextHeight;
\r
8059 newTextHeight = 0;
\r
8061 SetWindowPos(hText, NULL, 0, 0,
\r
8062 newTextWidth, newTextHeight, SWP_NOZORDER|SWP_NOMOVE);
\r
8063 GetWindowRect(hInput, &rectInput); /* gives screen coords */
\r
8064 pt.x = rectInput.left;
\r
8065 pt.y = rectInput.top + newSizeY - sizeY;
\r
8066 ScreenToClient(hDlg, &pt);
\r
8067 SetWindowPos(hInput, NULL,
\r
8068 pt.x, pt.y, /* needs client coords */
\r
8069 rectInput.right - rectInput.left + newSizeX - sizeX,
\r
8070 rectInput.bottom - rectInput.top, SWP_NOZORDER);
\r
8076 case WM_GETMINMAXINFO:
\r
8077 /* Prevent resizing window too small */
\r
8078 mmi = (MINMAXINFO *) lParam;
\r
8079 mmi->ptMinTrackSize.x = 100;
\r
8080 mmi->ptMinTrackSize.y = 100;
\r
8083 /* [AS] Snapping */
\r
8084 case WM_ENTERSIZEMOVE:
\r
8085 return OnEnterSizeMove( &sd, hDlg, wParam, lParam );
\r
8088 return OnSizing( &sd, hDlg, wParam, lParam );
\r
8091 return OnMoving( &sd, hDlg, wParam, lParam );
\r
8093 case WM_EXITSIZEMOVE:
\r
8094 return OnExitSizeMove( &sd, hDlg, wParam, lParam );
\r
8097 return DefWindowProc(hDlg, message, wParam, lParam);
\r
8105 if (hwndConsole) return;
\r
8106 hCons = CreateDialog(hInst, szConsoleName, 0, NULL);
\r
8107 SendMessage(hCons, WM_INITDIALOG, 0, 0);
\r
8112 ConsoleOutput(char* data, int length, int forceVisible)
\r
8117 char buf[CO_MAX+1];
\r
8120 static int delayLF = 0;
\r
8121 CHARRANGE savesel, sel;
\r
8123 if (hwndConsole == NULL || length > CO_MAX-100 || length == 0) return;
\r
8131 while (length--) {
\r
8139 } else if (*p == '\007') {
\r
8140 MyPlaySound(&sounds[(int)SoundBell]);
\r
8147 hText = GetDlgItem(hwndConsole, OPT_ConsoleText);
\r
8148 SendMessage(hText, EM_HIDESELECTION, TRUE, FALSE);
\r
8149 /* Save current selection */
\r
8150 SendMessage(hText, EM_EXGETSEL, 0, (LPARAM)&savesel);
\r
8151 exlen = GetWindowTextLength(hText);
\r
8152 /* Find out whether current end of text is visible */
\r
8153 SendMessage(hText, EM_GETRECT, 0, (LPARAM) &rect);
\r
8154 SendMessage(hText, EM_POSFROMCHAR, (WPARAM) &pEnd, exlen);
\r
8155 /* Trim existing text if it's too long */
\r
8156 if (exlen + (q - buf) > CO_MAX) {
\r
8157 trim = (CO_TRIM > (q - buf)) ? CO_TRIM : (q - buf);
\r
8160 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
8161 SendMessage(hText, EM_REPLACESEL, 0, (LPARAM)"");
\r
8163 savesel.cpMin -= trim;
\r
8164 savesel.cpMax -= trim;
\r
8165 if (exlen < 0) exlen = 0;
\r
8166 if (savesel.cpMin < 0) savesel.cpMin = 0;
\r
8167 if (savesel.cpMax < savesel.cpMin) savesel.cpMax = savesel.cpMin;
\r
8169 /* Append the new text */
\r
8170 sel.cpMin = exlen;
\r
8171 sel.cpMax = exlen;
\r
8172 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
8173 SendMessage(hText, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&consoleCF);
\r
8174 SendMessage(hText, EM_REPLACESEL, 0, (LPARAM) buf);
\r
8175 if (forceVisible || exlen == 0 ||
\r
8176 (rect.left <= pEnd.x && pEnd.x < rect.right &&
\r
8177 rect.top <= pEnd.y && pEnd.y < rect.bottom)) {
\r
8178 /* Scroll to make new end of text visible if old end of text
\r
8179 was visible or new text is an echo of user typein */
\r
8180 sel.cpMin = 9999999;
\r
8181 sel.cpMax = 9999999;
\r
8182 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
8183 SendMessage(hText, EM_HIDESELECTION, FALSE, FALSE);
\r
8184 SendMessage(hText, EM_SCROLLCARET, 0, 0);
\r
8185 SendMessage(hText, EM_HIDESELECTION, TRUE, FALSE);
\r
8187 if (savesel.cpMax == exlen || forceVisible) {
\r
8188 /* Move insert point to new end of text if it was at the old
\r
8189 end of text or if the new text is an echo of user typein */
\r
8190 sel.cpMin = 9999999;
\r
8191 sel.cpMax = 9999999;
\r
8192 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
8194 /* Restore previous selection */
\r
8195 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&savesel);
\r
8197 SendMessage(hText, EM_HIDESELECTION, FALSE, FALSE);
\r
8204 DisplayHoldingsCount(HDC hdc, int x, int y, int rightAlign, int copyNumber)
\r
8208 COLORREF oldFg, oldBg;
\r
8212 if(copyNumber > 1) sprintf(buf, "%d", copyNumber); else buf[0] = 0;
\r
8214 oldFg = SetTextColor(hdc, RGB(255, 255, 255)); /* white */
\r
8215 oldBg = SetBkColor(hdc, RGB(0, 0, 0)); /* black */
\r
8216 oldFont = SelectObject(hdc, font[boardSize][CLOCK_FONT]->hf);
\r
8219 rect.right = x + squareSize;
\r
8221 rect.bottom = y + squareSize;
\r
8224 ExtTextOut(hdc, x + MESSAGE_LINE_LEFTMARGIN
\r
8225 + (rightAlign ? (squareSize*2)/3 : 0),
\r
8226 y, ETO_CLIPPED|ETO_OPAQUE,
\r
8227 &rect, str, strlen(str), NULL);
\r
8229 (void) SetTextColor(hdc, oldFg);
\r
8230 (void) SetBkColor(hdc, oldBg);
\r
8231 (void) SelectObject(hdc, oldFont);
\r
8235 DisplayAClock(HDC hdc, int timeRemaining, int highlight,
\r
8236 RECT *rect, char *color, char *flagFell)
\r
8240 COLORREF oldFg, oldBg;
\r
8243 if (appData.clockMode) {
\r
8245 sprintf(buf, "%c %s %s", color[0], TimeString(timeRemaining), flagFell);
\r
8247 sprintf(buf, "%s: %s %s", color, TimeString(timeRemaining), flagFell);
\r
8254 oldFg = SetTextColor(hdc, RGB(255, 255, 255)); /* white */
\r
8255 oldBg = SetBkColor(hdc, RGB(0, 0, 0)); /* black */
\r
8257 oldFg = SetTextColor(hdc, RGB(0, 0, 0)); /* black */
\r
8258 oldBg = SetBkColor(hdc, RGB(255, 255, 255)); /* white */
\r
8260 oldFont = SelectObject(hdc, font[boardSize][CLOCK_FONT]->hf);
\r
8262 ExtTextOut(hdc, rect->left + MESSAGE_LINE_LEFTMARGIN,
\r
8263 rect->top, ETO_CLIPPED|ETO_OPAQUE,
\r
8264 rect, str, strlen(str), NULL);
\r
8266 (void) SetTextColor(hdc, oldFg);
\r
8267 (void) SetBkColor(hdc, oldBg);
\r
8268 (void) SelectObject(hdc, oldFont);
\r
8273 DoReadFile(HANDLE hFile, char *buf, int count, DWORD *outCount,
\r
8279 if( count <= 0 ) {
\r
8280 if (appData.debugMode) {
\r
8281 fprintf( debugFP, "DoReadFile: trying to read past end of buffer, overflow = %d\n", count );
\r
8284 return ERROR_INVALID_USER_BUFFER;
\r
8287 ResetEvent(ovl->hEvent);
\r
8288 ovl->Offset = ovl->OffsetHigh = 0;
\r
8289 ok = ReadFile(hFile, buf, count, outCount, ovl);
\r
8293 err = GetLastError();
\r
8294 if (err == ERROR_IO_PENDING) {
\r
8295 ok = GetOverlappedResult(hFile, ovl, outCount, TRUE);
\r
8299 err = GetLastError();
\r
8306 DoWriteFile(HANDLE hFile, char *buf, int count, DWORD *outCount,
\r
8311 ResetEvent(ovl->hEvent);
\r
8312 ovl->Offset = ovl->OffsetHigh = 0;
\r
8313 ok = WriteFile(hFile, buf, count, outCount, ovl);
\r
8317 err = GetLastError();
\r
8318 if (err == ERROR_IO_PENDING) {
\r
8319 ok = GetOverlappedResult(hFile, ovl, outCount, TRUE);
\r
8323 err = GetLastError();
\r
8329 /* [AS] If input is line by line and a line exceed the buffer size, force an error */
\r
8330 void CheckForInputBufferFull( InputSource * is )
\r
8332 if( is->lineByLine && (is->next - is->buf) >= INPUT_SOURCE_BUF_SIZE ) {
\r
8333 /* Look for end of line */
\r
8334 char * p = is->buf;
\r
8336 while( p < is->next && *p != '\n' ) {
\r
8340 if( p >= is->next ) {
\r
8341 if (appData.debugMode) {
\r
8342 fprintf( debugFP, "Input line exceeded buffer size (source id=%lu)\n", is->id );
\r
8345 is->error = ERROR_BROKEN_PIPE; /* [AS] Just any non-successful code! */
\r
8346 is->count = (DWORD) -1;
\r
8347 is->next = is->buf;
\r
8353 InputThread(LPVOID arg)
\r
8358 is = (InputSource *) arg;
\r
8359 ovl.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
\r
8360 ovl.Internal = ovl.InternalHigh = ovl.Offset = ovl.OffsetHigh = 0;
\r
8361 while (is->hThread != NULL) {
\r
8362 is->error = DoReadFile(is->hFile, is->next,
\r
8363 INPUT_SOURCE_BUF_SIZE - (is->next - is->buf),
\r
8364 &is->count, &ovl);
\r
8365 if (is->error == NO_ERROR) {
\r
8366 is->next += is->count;
\r
8368 if (is->error == ERROR_BROKEN_PIPE) {
\r
8369 /* Correct for MS brain damage. EOF reading a pipe is not an error. */
\r
8372 is->count = (DWORD) -1;
\r
8373 /* [AS] The (is->count <= 0) check below is not useful for unsigned values! */
\r
8378 CheckForInputBufferFull( is );
\r
8380 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
8382 if( is->count == ((DWORD) -1) ) break; /* [AS] */
\r
8384 if (is->count <= 0) break; /* Quit on EOF or error */
\r
8387 CloseHandle(ovl.hEvent);
\r
8388 CloseHandle(is->hFile);
\r
8390 if (appData.debugMode) {
\r
8391 fprintf( debugFP, "Input thread terminated (id=%lu, error=%d, count=%ld)\n", is->id, is->error, is->count );
\r
8398 /* Windows 95 beta 2 won't let you do overlapped i/o on a console or pipe */
\r
8400 NonOvlInputThread(LPVOID arg)
\r
8407 is = (InputSource *) arg;
\r
8408 while (is->hThread != NULL) {
\r
8409 is->error = ReadFile(is->hFile, is->next,
\r
8410 INPUT_SOURCE_BUF_SIZE - (is->next - is->buf),
\r
8411 &is->count, NULL) ? NO_ERROR : GetLastError();
\r
8412 if (is->error == NO_ERROR) {
\r
8413 /* Change CRLF to LF */
\r
8414 if (is->next > is->buf) {
\r
8416 i = is->count + 1;
\r
8424 if (prev == '\r' && *p == '\n') {
\r
8436 if (is->error == ERROR_BROKEN_PIPE) {
\r
8437 /* Correct for MS brain damage. EOF reading a pipe is not an error. */
\r
8440 is->count = (DWORD) -1;
\r
8444 CheckForInputBufferFull( is );
\r
8446 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
8448 if( is->count == ((DWORD) -1) ) break; /* [AS] */
\r
8450 if (is->count < 0) break; /* Quit on error */
\r
8452 CloseHandle(is->hFile);
\r
8457 SocketInputThread(LPVOID arg)
\r
8461 is = (InputSource *) arg;
\r
8462 while (is->hThread != NULL) {
\r
8463 is->count = recv(is->sock, is->buf, INPUT_SOURCE_BUF_SIZE, 0);
\r
8464 if ((int)is->count == SOCKET_ERROR) {
\r
8465 is->count = (DWORD) -1;
\r
8466 is->error = WSAGetLastError();
\r
8468 is->error = NO_ERROR;
\r
8469 is->next += is->count;
\r
8470 if (is->count == 0 && is->second == is) {
\r
8471 /* End of file on stderr; quit with no message */
\r
8475 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
8477 if( is->count == ((DWORD) -1) ) break; /* [AS] */
\r
8479 if (is->count <= 0) break; /* Quit on EOF or error */
\r
8485 InputEvent(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
8489 is = (InputSource *) lParam;
\r
8490 if (is->lineByLine) {
\r
8491 /* Feed in lines one by one */
\r
8492 char *p = is->buf;
\r
8494 while (q < is->next) {
\r
8495 if (*q++ == '\n') {
\r
8496 (is->func)(is, is->closure, p, q - p, NO_ERROR);
\r
8501 /* Move any partial line to the start of the buffer */
\r
8503 while (p < is->next) {
\r
8508 if (is->error != NO_ERROR || is->count == 0) {
\r
8509 /* Notify backend of the error. Note: If there was a partial
\r
8510 line at the end, it is not flushed through. */
\r
8511 (is->func)(is, is->closure, is->buf, is->count, is->error);
\r
8514 /* Feed in the whole chunk of input at once */
\r
8515 (is->func)(is, is->closure, is->buf, is->count, is->error);
\r
8516 is->next = is->buf;
\r
8520 /*---------------------------------------------------------------------------*\
\r
8522 * Menu enables. Used when setting various modes.
\r
8524 \*---------------------------------------------------------------------------*/
\r
8532 SetMenuEnables(HMENU hmenu, Enables *enab)
\r
8534 while (enab->item > 0) {
\r
8535 (void) EnableMenuItem(hmenu, enab->item, enab->flags);
\r
8540 Enables gnuEnables[] = {
\r
8541 { IDM_MailMove, MF_BYCOMMAND|MF_GRAYED },
\r
8542 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_GRAYED },
\r
8543 { IDM_IcsClient, MF_BYCOMMAND|MF_GRAYED },
\r
8544 { IDM_Accept, MF_BYCOMMAND|MF_GRAYED },
\r
8545 { IDM_Decline, MF_BYCOMMAND|MF_GRAYED },
\r
8546 { IDM_Rematch, MF_BYCOMMAND|MF_GRAYED },
\r
8547 { IDM_Adjourn, MF_BYCOMMAND|MF_GRAYED },
\r
8548 { IDM_StopExamining, MF_BYCOMMAND|MF_GRAYED },
\r
8549 { IDM_StopObserving, MF_BYCOMMAND|MF_GRAYED },
\r
8550 { IDM_Revert, MF_BYCOMMAND|MF_GRAYED },
\r
8554 Enables icsEnables[] = {
\r
8555 { IDM_MailMove, MF_BYCOMMAND|MF_GRAYED },
\r
8556 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_GRAYED },
\r
8557 { IDM_MachineWhite, MF_BYCOMMAND|MF_GRAYED },
\r
8558 { IDM_MachineBlack, MF_BYCOMMAND|MF_GRAYED },
\r
8559 { IDM_TwoMachines, MF_BYCOMMAND|MF_GRAYED },
\r
8560 { IDM_AnalysisMode, MF_BYCOMMAND|MF_ENABLED },
\r
8561 { IDM_AnalyzeFile, MF_BYCOMMAND|MF_GRAYED },
\r
8562 { IDM_TimeControl, MF_BYCOMMAND|MF_GRAYED },
\r
8563 { IDM_MoveNow, MF_BYCOMMAND|MF_GRAYED },
\r
8564 { IDM_Hint, MF_BYCOMMAND|MF_GRAYED },
\r
8565 { IDM_Book, MF_BYCOMMAND|MF_GRAYED },
\r
8566 { IDM_IcsOptions, MF_BYCOMMAND|MF_ENABLED },
\r
8571 Enables zippyEnables[] = {
\r
8572 { IDM_MoveNow, MF_BYCOMMAND|MF_ENABLED },
\r
8573 { IDM_Hint, MF_BYCOMMAND|MF_ENABLED },
\r
8574 { IDM_Book, MF_BYCOMMAND|MF_ENABLED },
\r
8579 Enables ncpEnables[] = {
\r
8580 { IDM_MailMove, MF_BYCOMMAND|MF_GRAYED },
\r
8581 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_GRAYED },
\r
8582 { IDM_MachineWhite, MF_BYCOMMAND|MF_GRAYED },
\r
8583 { IDM_MachineBlack, MF_BYCOMMAND|MF_GRAYED },
\r
8584 { IDM_TwoMachines, MF_BYCOMMAND|MF_GRAYED },
\r
8585 { IDM_AnalysisMode, MF_BYCOMMAND|MF_GRAYED },
\r
8586 { IDM_AnalyzeFile, MF_BYCOMMAND|MF_GRAYED },
\r
8587 { IDM_IcsClient, MF_BYCOMMAND|MF_GRAYED },
\r
8588 { ACTION_POS, MF_BYPOSITION|MF_GRAYED },
\r
8589 { IDM_Revert, MF_BYCOMMAND|MF_GRAYED },
\r
8590 { IDM_MoveNow, MF_BYCOMMAND|MF_GRAYED },
\r
8591 { IDM_RetractMove, MF_BYCOMMAND|MF_GRAYED },
\r
8592 { IDM_TimeControl, MF_BYCOMMAND|MF_GRAYED },
\r
8593 { IDM_Hint, MF_BYCOMMAND|MF_GRAYED },
\r
8594 { IDM_Book, MF_BYCOMMAND|MF_GRAYED },
\r
8598 Enables trainingOnEnables[] = {
\r
8599 { IDM_EditComment, MF_BYCOMMAND|MF_GRAYED },
\r
8600 { IDM_Pause, MF_BYCOMMAND|MF_GRAYED },
\r
8601 { IDM_Forward, MF_BYCOMMAND|MF_GRAYED },
\r
8602 { IDM_Backward, MF_BYCOMMAND|MF_GRAYED },
\r
8603 { IDM_ToEnd, MF_BYCOMMAND|MF_GRAYED },
\r
8604 { IDM_ToStart, MF_BYCOMMAND|MF_GRAYED },
\r
8605 { IDM_MoveNow, MF_BYCOMMAND|MF_GRAYED },
\r
8606 { IDM_TruncateGame, MF_BYCOMMAND|MF_GRAYED },
\r
8610 Enables trainingOffEnables[] = {
\r
8611 { IDM_EditComment, MF_BYCOMMAND|MF_ENABLED },
\r
8612 { IDM_Pause, MF_BYCOMMAND|MF_ENABLED },
\r
8613 { IDM_Forward, MF_BYCOMMAND|MF_ENABLED },
\r
8614 { IDM_Backward, MF_BYCOMMAND|MF_ENABLED },
\r
8615 { IDM_ToEnd, MF_BYCOMMAND|MF_ENABLED },
\r
8616 { IDM_ToStart, MF_BYCOMMAND|MF_ENABLED },
\r
8617 { IDM_MoveNow, MF_BYCOMMAND|MF_ENABLED },
\r
8618 { IDM_TruncateGame, MF_BYCOMMAND|MF_ENABLED },
\r
8622 /* These modify either ncpEnables or gnuEnables */
\r
8623 Enables cmailEnables[] = {
\r
8624 { IDM_MailMove, MF_BYCOMMAND|MF_ENABLED },
\r
8625 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_ENABLED },
\r
8626 { ACTION_POS, MF_BYPOSITION|MF_ENABLED },
\r
8627 { IDM_CallFlag, MF_BYCOMMAND|MF_GRAYED },
\r
8628 { IDM_Draw, MF_BYCOMMAND|MF_ENABLED },
\r
8629 { IDM_Adjourn, MF_BYCOMMAND|MF_GRAYED },
\r
8630 { IDM_Abort, MF_BYCOMMAND|MF_GRAYED },
\r
8634 Enables machineThinkingEnables[] = {
\r
8635 { IDM_LoadGame, MF_BYCOMMAND|MF_GRAYED },
\r
8636 { IDM_LoadNextGame, MF_BYCOMMAND|MF_GRAYED },
\r
8637 { IDM_LoadPrevGame, MF_BYCOMMAND|MF_GRAYED },
\r
8638 { IDM_ReloadGame, MF_BYCOMMAND|MF_GRAYED },
\r
8639 { IDM_PasteGame, MF_BYCOMMAND|MF_GRAYED },
\r
8640 { IDM_LoadPosition, MF_BYCOMMAND|MF_GRAYED },
\r
8641 { IDM_LoadNextPosition, MF_BYCOMMAND|MF_GRAYED },
\r
8642 { IDM_LoadPrevPosition, MF_BYCOMMAND|MF_GRAYED },
\r
8643 { IDM_ReloadPosition, MF_BYCOMMAND|MF_GRAYED },
\r
8644 { IDM_PastePosition, MF_BYCOMMAND|MF_GRAYED },
\r
8645 { IDM_MachineWhite, MF_BYCOMMAND|MF_GRAYED },
\r
8646 { IDM_MachineBlack, MF_BYCOMMAND|MF_GRAYED },
\r
8647 { IDM_TwoMachines, MF_BYCOMMAND|MF_GRAYED },
\r
8648 { IDM_TypeInMove, MF_BYCOMMAND|MF_GRAYED },
\r
8649 { IDM_RetractMove, MF_BYCOMMAND|MF_GRAYED },
\r
8653 Enables userThinkingEnables[] = {
\r
8654 { IDM_LoadGame, MF_BYCOMMAND|MF_ENABLED },
\r
8655 { IDM_LoadNextGame, MF_BYCOMMAND|MF_ENABLED },
\r
8656 { IDM_LoadPrevGame, MF_BYCOMMAND|MF_ENABLED },
\r
8657 { IDM_ReloadGame, MF_BYCOMMAND|MF_ENABLED },
\r
8658 { IDM_PasteGame, MF_BYCOMMAND|MF_ENABLED },
\r
8659 { IDM_LoadPosition, MF_BYCOMMAND|MF_ENABLED },
\r
8660 { IDM_LoadNextPosition, MF_BYCOMMAND|MF_ENABLED },
\r
8661 { IDM_LoadPrevPosition, MF_BYCOMMAND|MF_ENABLED },
\r
8662 { IDM_ReloadPosition, MF_BYCOMMAND|MF_ENABLED },
\r
8663 { IDM_PastePosition, MF_BYCOMMAND|MF_ENABLED },
\r
8664 { IDM_MachineWhite, MF_BYCOMMAND|MF_ENABLED },
\r
8665 { IDM_MachineBlack, MF_BYCOMMAND|MF_ENABLED },
\r
8666 { IDM_TwoMachines, MF_BYCOMMAND|MF_ENABLED },
\r
8667 { IDM_TypeInMove, MF_BYCOMMAND|MF_ENABLED },
\r
8668 { IDM_RetractMove, MF_BYCOMMAND|MF_ENABLED },
\r
8672 /*---------------------------------------------------------------------------*\
\r
8674 * Front-end interface functions exported by XBoard.
\r
8675 * Functions appear in same order as prototypes in frontend.h.
\r
8677 \*---------------------------------------------------------------------------*/
\r
8681 static UINT prevChecked = 0;
\r
8682 static int prevPausing = 0;
\r
8685 if (pausing != prevPausing) {
\r
8686 prevPausing = pausing;
\r
8687 (void) CheckMenuItem(GetMenu(hwndMain), IDM_Pause,
\r
8688 MF_BYCOMMAND|(pausing ? MF_CHECKED : MF_UNCHECKED));
\r
8689 if (hwndPause) SetWindowText(hwndPause, pausing ? "C" : "P");
\r
8692 switch (gameMode) {
\r
8693 case BeginningOfGame:
\r
8694 if (appData.icsActive)
\r
8695 nowChecked = IDM_IcsClient;
\r
8696 else if (appData.noChessProgram)
\r
8697 nowChecked = IDM_EditGame;
\r
8699 nowChecked = IDM_MachineBlack;
\r
8701 case MachinePlaysBlack:
\r
8702 nowChecked = IDM_MachineBlack;
\r
8704 case MachinePlaysWhite:
\r
8705 nowChecked = IDM_MachineWhite;
\r
8707 case TwoMachinesPlay:
\r
8708 nowChecked = IDM_TwoMachines;
\r
8711 nowChecked = IDM_AnalysisMode;
\r
8714 nowChecked = IDM_AnalyzeFile;
\r
8717 nowChecked = IDM_EditGame;
\r
8719 case PlayFromGameFile:
\r
8720 nowChecked = IDM_LoadGame;
\r
8722 case EditPosition:
\r
8723 nowChecked = IDM_EditPosition;
\r
8726 nowChecked = IDM_Training;
\r
8728 case IcsPlayingWhite:
\r
8729 case IcsPlayingBlack:
\r
8730 case IcsObserving:
\r
8732 nowChecked = IDM_IcsClient;
\r
8739 if (prevChecked != 0)
\r
8740 (void) CheckMenuItem(GetMenu(hwndMain),
\r
8741 prevChecked, MF_BYCOMMAND|MF_UNCHECKED);
\r
8742 if (nowChecked != 0)
\r
8743 (void) CheckMenuItem(GetMenu(hwndMain),
\r
8744 nowChecked, MF_BYCOMMAND|MF_CHECKED);
\r
8746 if (nowChecked == IDM_LoadGame || nowChecked == IDM_Training) {
\r
8747 (void) EnableMenuItem(GetMenu(hwndMain), IDM_Training,
\r
8748 MF_BYCOMMAND|MF_ENABLED);
\r
8750 (void) EnableMenuItem(GetMenu(hwndMain),
\r
8751 IDM_Training, MF_BYCOMMAND|MF_GRAYED);
\r
8754 prevChecked = nowChecked;
\r
8756 /* [DM] icsEngineAnalyze - Do a sceure check too */
\r
8757 if (appData.icsActive) {
\r
8758 if (appData.icsEngineAnalyze) {
\r
8759 (void) CheckMenuItem(GetMenu(hwndMain), IDM_AnalysisMode,
\r
8760 MF_BYCOMMAND|MF_CHECKED);
\r
8762 (void) CheckMenuItem(GetMenu(hwndMain), IDM_AnalysisMode,
\r
8763 MF_BYCOMMAND|MF_UNCHECKED);
\r
8771 HMENU hmenu = GetMenu(hwndMain);
\r
8772 SetMenuEnables(hmenu, icsEnables);
\r
8773 EnableMenuItem(GetSubMenu(hmenu, OPTIONS_POS), ICS_POS,
\r
8774 MF_BYPOSITION|MF_ENABLED);
\r
8776 if (appData.zippyPlay) {
\r
8777 SetMenuEnables(hmenu, zippyEnables);
\r
8778 if (!appData.noChessProgram) /* [DM] icsEngineAnalyze */
\r
8779 (void) EnableMenuItem(GetMenu(hwndMain), IDM_AnalysisMode,
\r
8780 MF_BYCOMMAND|MF_ENABLED);
\r
8788 SetMenuEnables(GetMenu(hwndMain), gnuEnables);
\r
8794 HMENU hmenu = GetMenu(hwndMain);
\r
8795 SetMenuEnables(hmenu, ncpEnables);
\r
8796 EnableMenuItem(GetSubMenu(hmenu, OPTIONS_POS), SOUNDS_POS,
\r
8797 MF_BYPOSITION|MF_GRAYED);
\r
8798 DrawMenuBar(hwndMain);
\r
8804 SetMenuEnables(GetMenu(hwndMain), cmailEnables);
\r
8808 SetTrainingModeOn()
\r
8811 SetMenuEnables(GetMenu(hwndMain), trainingOnEnables);
\r
8812 for (i = 0; i < N_BUTTONS; i++) {
\r
8813 if (buttonDesc[i].hwnd != NULL)
\r
8814 EnableWindow(buttonDesc[i].hwnd, FALSE);
\r
8819 VOID SetTrainingModeOff()
\r
8822 SetMenuEnables(GetMenu(hwndMain), trainingOffEnables);
\r
8823 for (i = 0; i < N_BUTTONS; i++) {
\r
8824 if (buttonDesc[i].hwnd != NULL)
\r
8825 EnableWindow(buttonDesc[i].hwnd, TRUE);
\r
8831 SetUserThinkingEnables()
\r
8833 SetMenuEnables(GetMenu(hwndMain), userThinkingEnables);
\r
8837 SetMachineThinkingEnables()
\r
8839 HMENU hMenu = GetMenu(hwndMain);
\r
8840 int flags = MF_BYCOMMAND|MF_ENABLED;
\r
8842 SetMenuEnables(hMenu, machineThinkingEnables);
\r
8844 if (gameMode == MachinePlaysBlack) {
\r
8845 (void)EnableMenuItem(hMenu, IDM_MachineBlack, flags);
\r
8846 } else if (gameMode == MachinePlaysWhite) {
\r
8847 (void)EnableMenuItem(hMenu, IDM_MachineWhite, flags);
\r
8848 } else if (gameMode == TwoMachinesPlay) {
\r
8849 (void)EnableMenuItem(hMenu, IDM_TwoMachines, flags);
\r
8855 DisplayTitle(char *str)
\r
8857 char title[MSG_SIZ], *host;
\r
8858 if (str[0] != NULLCHAR) {
\r
8859 strcpy(title, str);
\r
8860 } else if (appData.icsActive) {
\r
8861 if (appData.icsCommPort[0] != NULLCHAR)
\r
8864 host = appData.icsHost;
\r
8865 sprintf(title, "%s: %s", szTitle, host);
\r
8866 } else if (appData.noChessProgram) {
\r
8867 strcpy(title, szTitle);
\r
8869 strcpy(title, szTitle);
\r
8870 strcat(title, ": ");
\r
8871 strcat(title, first.tidy);
\r
8873 SetWindowText(hwndMain, title);
\r
8878 DisplayMessage(char *str1, char *str2)
\r
8882 int remain = MESSAGE_TEXT_MAX - 1;
\r
8885 moveErrorMessageUp = FALSE; /* turned on later by caller if needed */
\r
8886 messageText[0] = NULLCHAR;
\r
8888 len = strlen(str1);
\r
8889 if (len > remain) len = remain;
\r
8890 strncpy(messageText, str1, len);
\r
8891 messageText[len] = NULLCHAR;
\r
8894 if (*str2 && remain >= 2) {
\r
8896 strcat(messageText, " ");
\r
8899 len = strlen(str2);
\r
8900 if (len > remain) len = remain;
\r
8901 strncat(messageText, str2, len);
\r
8903 messageText[MESSAGE_TEXT_MAX - 1] = NULLCHAR;
\r
8905 if (hwndMain == NULL || IsIconic(hwndMain)) return;
\r
8906 hdc = GetDC(hwndMain);
\r
8907 oldFont = SelectObject(hdc, font[boardSize][MESSAGE_FONT]->hf);
\r
8908 ExtTextOut(hdc, messageRect.left, messageRect.top, ETO_CLIPPED|ETO_OPAQUE,
\r
8909 &messageRect, messageText, strlen(messageText), NULL);
\r
8910 (void) SelectObject(hdc, oldFont);
\r
8911 (void) ReleaseDC(hwndMain, hdc);
\r
8915 DisplayError(char *str, int error)
\r
8917 char buf[MSG_SIZ*2], buf2[MSG_SIZ];
\r
8923 len = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
\r
8924 NULL, error, LANG_NEUTRAL,
\r
8925 (LPSTR) buf2, MSG_SIZ, NULL);
\r
8927 sprintf(buf, "%s:\n%s", str, buf2);
\r
8929 ErrorMap *em = errmap;
\r
8930 while (em->err != 0 && em->err != error) em++;
\r
8931 if (em->err != 0) {
\r
8932 sprintf(buf, "%s:\n%s", str, em->msg);
\r
8934 sprintf(buf, "%s:\nError code %d", str, error);
\r
8939 ErrorPopUp("Error", buf);
\r
8944 DisplayMoveError(char *str)
\r
8946 fromX = fromY = -1;
\r
8947 ClearHighlights();
\r
8948 DrawPosition(FALSE, NULL);
\r
8949 if (appData.popupMoveErrors) {
\r
8950 ErrorPopUp("Error", str);
\r
8952 DisplayMessage(str, "");
\r
8953 moveErrorMessageUp = TRUE;
\r
8958 DisplayFatalError(char *str, int error, int exitStatus)
\r
8960 char buf[2*MSG_SIZ], buf2[MSG_SIZ];
\r
8962 char *label = exitStatus ? "Fatal Error" : "Exiting";
\r
8965 len = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
\r
8966 NULL, error, LANG_NEUTRAL,
\r
8967 (LPSTR) buf2, MSG_SIZ, NULL);
\r
8969 sprintf(buf, "%s:\n%s", str, buf2);
\r
8971 ErrorMap *em = errmap;
\r
8972 while (em->err != 0 && em->err != error) em++;
\r
8973 if (em->err != 0) {
\r
8974 sprintf(buf, "%s:\n%s", str, em->msg);
\r
8976 sprintf(buf, "%s:\nError code %d", str, error);
\r
8981 if (appData.debugMode) {
\r
8982 fprintf(debugFP, "%s: %s\n", label, str);
\r
8984 if (appData.popupExitMessage) {
\r
8985 (void) MessageBox(hwndMain, str, label, MB_OK|
\r
8986 (exitStatus ? MB_ICONSTOP : MB_ICONINFORMATION));
\r
8988 ExitEvent(exitStatus);
\r
8993 DisplayInformation(char *str)
\r
8995 (void) MessageBox(hwndMain, str, "Information", MB_OK|MB_ICONINFORMATION);
\r
9000 DisplayNote(char *str)
\r
9002 ErrorPopUp("Note", str);
\r
9007 char *title, *question, *replyPrefix;
\r
9012 QuestionDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
9014 static QuestionParams *qp;
\r
9015 char reply[MSG_SIZ];
\r
9018 switch (message) {
\r
9019 case WM_INITDIALOG:
\r
9020 qp = (QuestionParams *) lParam;
\r
9021 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
9022 SetWindowText(hDlg, qp->title);
\r
9023 SetDlgItemText(hDlg, OPT_QuestionText, qp->question);
\r
9024 SetFocus(GetDlgItem(hDlg, OPT_QuestionInput));
\r
9028 switch (LOWORD(wParam)) {
\r
9030 strcpy(reply, qp->replyPrefix);
\r
9031 if (*reply) strcat(reply, " ");
\r
9032 len = strlen(reply);
\r
9033 GetDlgItemText(hDlg, OPT_QuestionInput, reply + len, sizeof(reply) - len);
\r
9034 strcat(reply, "\n");
\r
9035 OutputToProcess(qp->pr, reply, strlen(reply), &err);
\r
9036 EndDialog(hDlg, TRUE);
\r
9037 if (err) DisplayFatalError("Error writing to chess program", err, 1);
\r
9040 EndDialog(hDlg, FALSE);
\r
9051 AskQuestion(char* title, char *question, char *replyPrefix, ProcRef pr)
\r
9053 QuestionParams qp;
\r
9057 qp.question = question;
\r
9058 qp.replyPrefix = replyPrefix;
\r
9060 lpProc = MakeProcInstance((FARPROC)QuestionDialog, hInst);
\r
9061 DialogBoxParam(hInst, MAKEINTRESOURCE(DLG_Question),
\r
9062 hwndMain, (DLGPROC)lpProc, (LPARAM)&qp);
\r
9063 FreeProcInstance(lpProc);
\r
9066 /* [AS] Pick FRC position */
\r
9067 LRESULT CALLBACK NewGameFRC_Proc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
9069 static int * lpIndexFRC;
\r
9075 case WM_INITDIALOG:
\r
9076 lpIndexFRC = (int *) lParam;
\r
9078 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
9080 SendDlgItemMessage( hDlg, IDC_NFG_Edit, EM_SETLIMITTEXT, sizeof(buf)-1, 0 );
\r
9081 SetDlgItemInt( hDlg, IDC_NFG_Edit, *lpIndexFRC, TRUE );
\r
9082 SendDlgItemMessage( hDlg, IDC_NFG_Edit, EM_SETSEL, 0, -1 );
\r
9083 SetFocus(GetDlgItem(hDlg, IDC_NFG_Edit));
\r
9088 switch( LOWORD(wParam) ) {
\r
9090 *lpIndexFRC = GetDlgItemInt(hDlg, IDC_NFG_Edit, &index_is_ok, TRUE );
\r
9091 EndDialog( hDlg, 0 );
\r
9092 shuffleOpenings = TRUE; /* [HGM] shuffle: switch shuffling on for as long as we stay in current variant */
\r
9095 EndDialog( hDlg, 1 );
\r
9097 case IDC_NFG_Edit:
\r
9098 if( HIWORD(wParam) == EN_CHANGE ) {
\r
9099 GetDlgItemInt(hDlg, IDC_NFG_Edit, &index_is_ok, TRUE );
\r
9101 EnableWindow( GetDlgItem(hDlg, IDOK), index_is_ok );
\r
9104 case IDC_NFG_Random:
\r
9105 sprintf( buf, "%d", myrandom() ); /* [HGM] shuffle: no longer limit to 960 */
\r
9106 SetDlgItemText(hDlg, IDC_NFG_Edit, buf );
\r
9119 int index = appData.defaultFrcPosition;
\r
9120 FARPROC lpProc = MakeProcInstance( (FARPROC) NewGameFRC_Proc, hInst );
\r
9122 result = DialogBoxParam( hInst, MAKEINTRESOURCE(DLG_NewGameFRC), hwndMain, (DLGPROC)lpProc, (LPARAM)&index );
\r
9124 if( result == 0 ) {
\r
9125 appData.defaultFrcPosition = index;
\r
9131 /* [AS] Game list options */
\r
9137 static GLT_Item GLT_ItemInfo[] = {
\r
9138 { GLT_EVENT, "Event" },
\r
9139 { GLT_SITE, "Site" },
\r
9140 { GLT_DATE, "Date" },
\r
9141 { GLT_ROUND, "Round" },
\r
9142 { GLT_PLAYERS, "Players" },
\r
9143 { GLT_RESULT, "Result" },
\r
9144 { GLT_WHITE_ELO, "White Rating" },
\r
9145 { GLT_BLACK_ELO, "Black Rating" },
\r
9146 { GLT_TIME_CONTROL,"Time Control" },
\r
9147 { GLT_VARIANT, "Variant" },
\r
9148 { GLT_OUT_OF_BOOK,PGN_OUT_OF_BOOK },
\r
9152 const char * GLT_FindItem( char id )
\r
9154 const char * result = 0;
\r
9156 GLT_Item * list = GLT_ItemInfo;
\r
9158 while( list->id != 0 ) {
\r
9159 if( list->id == id ) {
\r
9160 result = list->name;
\r
9170 void GLT_AddToList( HWND hDlg, int iDlgItem, char id, int index )
\r
9172 const char * name = GLT_FindItem( id );
\r
9175 if( index >= 0 ) {
\r
9176 SendDlgItemMessage( hDlg, iDlgItem, LB_INSERTSTRING, index, (LPARAM) name );
\r
9179 SendDlgItemMessage( hDlg, iDlgItem, LB_ADDSTRING, 0, (LPARAM) name );
\r
9184 void GLT_TagsToList( HWND hDlg, char * tags )
\r
9188 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_RESETCONTENT, 0, 0 );
\r
9191 GLT_AddToList( hDlg, IDC_GameListTags, *pc, -1 );
\r
9195 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_ADDSTRING, 0, (LPARAM) "\t --- Hidden tags ---" );
\r
9197 pc = GLT_ALL_TAGS;
\r
9200 if( strchr( tags, *pc ) == 0 ) {
\r
9201 GLT_AddToList( hDlg, IDC_GameListTags, *pc, -1 );
\r
9206 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_SETCURSEL, 0, 0 );
\r
9209 char GLT_ListItemToTag( HWND hDlg, int index )
\r
9211 char result = '\0';
\r
9214 GLT_Item * list = GLT_ItemInfo;
\r
9216 if( SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETTEXT, index, (LPARAM) name ) != LB_ERR ) {
\r
9217 while( list->id != 0 ) {
\r
9218 if( strcmp( list->name, name ) == 0 ) {
\r
9219 result = list->id;
\r
9230 void GLT_MoveSelection( HWND hDlg, int delta )
\r
9232 int idx1 = (int) SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETCURSEL, 0, 0 );
\r
9233 int idx2 = idx1 + delta;
\r
9234 int count = (int) SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETCOUNT, 0, 0 );
\r
9236 if( idx1 >=0 && idx1 < count && idx2 >= 0 && idx2 < count ) {
\r
9239 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETTEXT, idx1, (LPARAM) buf );
\r
9240 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_DELETESTRING, idx1, 0 );
\r
9241 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_INSERTSTRING, idx2, (LPARAM) buf );
\r
9242 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_SETCURSEL, idx2, 0 );
\r
9246 LRESULT CALLBACK GameListOptions_Proc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
9248 static char glt[64];
\r
9249 static char * lpUserGLT;
\r
9253 case WM_INITDIALOG:
\r
9254 lpUserGLT = (char *) lParam;
\r
9256 strcpy( glt, lpUserGLT );
\r
9258 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
9260 /* Initialize list */
\r
9261 GLT_TagsToList( hDlg, glt );
\r
9263 SetFocus( GetDlgItem(hDlg, IDC_GameListTags) );
\r
9268 switch( LOWORD(wParam) ) {
\r
9271 char * pc = lpUserGLT;
\r
9273 // int cnt = (int) SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETCOUNT, 0, 0 );
\r
9277 id = GLT_ListItemToTag( hDlg, idx );
\r
9281 } while( id != '\0' );
\r
9283 EndDialog( hDlg, 0 );
\r
9286 EndDialog( hDlg, 1 );
\r
9289 case IDC_GLT_Default:
\r
9290 strcpy( glt, GLT_DEFAULT_TAGS );
\r
9291 GLT_TagsToList( hDlg, glt );
\r
9294 case IDC_GLT_Restore:
\r
9295 strcpy( glt, lpUserGLT );
\r
9296 GLT_TagsToList( hDlg, glt );
\r
9300 GLT_MoveSelection( hDlg, -1 );
\r
9303 case IDC_GLT_Down:
\r
9304 GLT_MoveSelection( hDlg, +1 );
\r
9314 int GameListOptions()
\r
9318 FARPROC lpProc = MakeProcInstance( (FARPROC) GameListOptions_Proc, hInst );
\r
9320 strcpy( glt, appData.gameListTags );
\r
9322 result = DialogBoxParam( hInst, MAKEINTRESOURCE(DLG_GameListOptions), hwndMain, (DLGPROC)lpProc, (LPARAM)glt );
\r
9324 if( result == 0 ) {
\r
9325 /* [AS] Memory leak here! */
\r
9326 appData.gameListTags = strdup( glt );
\r
9334 DisplayIcsInteractionTitle(char *str)
\r
9336 char consoleTitle[MSG_SIZ];
\r
9338 sprintf(consoleTitle, "%s: %s", szConsoleTitle, str);
\r
9339 SetWindowText(hwndConsole, consoleTitle);
\r
9343 DrawPosition(int fullRedraw, Board board)
\r
9345 HDCDrawPosition(NULL, (BOOLEAN) fullRedraw, board);
\r
9352 fromX = fromY = -1;
\r
9353 if (dragInfo.pos.x != -1 || dragInfo.pos.y != -1) {
\r
9354 dragInfo.pos.x = dragInfo.pos.y = -1;
\r
9355 dragInfo.pos.x = dragInfo.pos.y = -1;
\r
9356 dragInfo.lastpos = dragInfo.pos;
\r
9357 dragInfo.start.x = dragInfo.start.y = -1;
\r
9358 dragInfo.from = dragInfo.start;
\r
9360 DrawPosition(TRUE, NULL);
\r
9366 CommentPopUp(char *title, char *str)
\r
9368 HWND hwnd = GetActiveWindow();
\r
9369 EitherCommentPopUp(0, title, str, FALSE);
\r
9370 SetActiveWindow(hwnd);
\r
9374 CommentPopDown(void)
\r
9376 CheckMenuItem(GetMenu(hwndMain), IDM_EditComment, MF_UNCHECKED);
\r
9377 if (commentDialog) {
\r
9378 ShowWindow(commentDialog, SW_HIDE);
\r
9380 commentDialogUp = FALSE;
\r
9384 EditCommentPopUp(int index, char *title, char *str)
\r
9386 EitherCommentPopUp(index, title, str, TRUE);
\r
9393 MyPlaySound(&sounds[(int)SoundMove]);
\r
9396 VOID PlayIcsWinSound()
\r
9398 MyPlaySound(&sounds[(int)SoundIcsWin]);
\r
9401 VOID PlayIcsLossSound()
\r
9403 MyPlaySound(&sounds[(int)SoundIcsLoss]);
\r
9406 VOID PlayIcsDrawSound()
\r
9408 MyPlaySound(&sounds[(int)SoundIcsDraw]);
\r
9411 VOID PlayIcsUnfinishedSound()
\r
9413 MyPlaySound(&sounds[(int)SoundIcsUnfinished]);
\r
9419 MyPlaySound(&sounds[(int)SoundAlarm]);
\r
9427 consoleEcho = TRUE;
\r
9428 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
9429 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&consoleCF);
\r
9430 SendMessage(hInput, EM_SETBKGNDCOLOR, FALSE, consoleBackgroundColor);
\r
9439 consoleEcho = FALSE;
\r
9440 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
9441 /* This works OK: set text and background both to the same color */
\r
9443 cf.crTextColor = COLOR_ECHOOFF;
\r
9444 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&cf);
\r
9445 SendMessage(hInput, EM_SETBKGNDCOLOR, FALSE, cf.crTextColor);
\r
9448 /* No Raw()...? */
\r
9450 void Colorize(ColorClass cc, int continuation)
\r
9452 currentColorClass = cc;
\r
9453 consoleCF.dwMask = CFM_COLOR|CFM_BOLD|CFM_ITALIC|CFM_UNDERLINE|CFM_STRIKEOUT;
\r
9454 consoleCF.crTextColor = textAttribs[cc].color;
\r
9455 consoleCF.dwEffects = textAttribs[cc].effects;
\r
9456 if (!continuation) MyPlaySound(&textAttribs[cc].sound);
\r
9462 static char buf[MSG_SIZ];
\r
9463 DWORD bufsiz = MSG_SIZ;
\r
9465 if(appData.userName != NULL && appData.userName[0] != 0) {
\r
9466 return appData.userName; /* [HGM] username: prefer name selected by user over his system login */
\r
9468 if (!GetUserName(buf, &bufsiz)) {
\r
9469 /*DisplayError("Error getting user name", GetLastError());*/
\r
9470 strcpy(buf, "User");
\r
9478 static char buf[MSG_SIZ];
\r
9479 DWORD bufsiz = MSG_SIZ;
\r
9481 if (!GetComputerName(buf, &bufsiz)) {
\r
9482 /*DisplayError("Error getting host name", GetLastError());*/
\r
9483 strcpy(buf, "Unknown");
\r
9490 ClockTimerRunning()
\r
9492 return clockTimerEvent != 0;
\r
9498 if (clockTimerEvent == 0) return FALSE;
\r
9499 KillTimer(hwndMain, clockTimerEvent);
\r
9500 clockTimerEvent = 0;
\r
9505 StartClockTimer(long millisec)
\r
9507 clockTimerEvent = SetTimer(hwndMain, (UINT) CLOCK_TIMER_ID,
\r
9508 (UINT) millisec, NULL);
\r
9512 DisplayWhiteClock(long timeRemaining, int highlight)
\r
9515 char *flag = whiteFlag && gameMode == TwoMachinesPlay ? "(!)" : "";
\r
9517 if(appData.noGUI) return;
\r
9518 hdc = GetDC(hwndMain);
\r
9519 if (!IsIconic(hwndMain)) {
\r
9520 DisplayAClock(hdc, timeRemaining, highlight,
\r
9521 (logoHeight > 0 ? flipView: flipClock) ? &blackRect : &whiteRect, "White", flag);
\r
9523 if (highlight && iconCurrent == iconBlack) {
\r
9524 iconCurrent = iconWhite;
\r
9525 PostMessage(hwndMain, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
9526 if (IsIconic(hwndMain)) {
\r
9527 DrawIcon(hdc, 2, 2, iconCurrent);
\r
9530 (void) ReleaseDC(hwndMain, hdc);
\r
9532 PostMessage(hwndConsole, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
9536 DisplayBlackClock(long timeRemaining, int highlight)
\r
9539 char *flag = blackFlag && gameMode == TwoMachinesPlay ? "(!)" : "";
\r
9541 if(appData.noGUI) return;
\r
9542 hdc = GetDC(hwndMain);
\r
9543 if (!IsIconic(hwndMain)) {
\r
9544 DisplayAClock(hdc, timeRemaining, highlight,
\r
9545 (logoHeight > 0 ? flipView: flipClock) ? &whiteRect : &blackRect, "Black", flag);
\r
9547 if (highlight && iconCurrent == iconWhite) {
\r
9548 iconCurrent = iconBlack;
\r
9549 PostMessage(hwndMain, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
9550 if (IsIconic(hwndMain)) {
\r
9551 DrawIcon(hdc, 2, 2, iconCurrent);
\r
9554 (void) ReleaseDC(hwndMain, hdc);
\r
9556 PostMessage(hwndConsole, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
9561 LoadGameTimerRunning()
\r
9563 return loadGameTimerEvent != 0;
\r
9567 StopLoadGameTimer()
\r
9569 if (loadGameTimerEvent == 0) return FALSE;
\r
9570 KillTimer(hwndMain, loadGameTimerEvent);
\r
9571 loadGameTimerEvent = 0;
\r
9576 StartLoadGameTimer(long millisec)
\r
9578 loadGameTimerEvent = SetTimer(hwndMain, (UINT) LOAD_GAME_TIMER_ID,
\r
9579 (UINT) millisec, NULL);
\r
9587 char fileTitle[MSG_SIZ];
\r
9589 defName = DefaultFileName(appData.oldSaveStyle ? "gam" : "pgn");
\r
9590 f = OpenFileDialog(hwndMain, "a", defName,
\r
9591 appData.oldSaveStyle ? "gam" : "pgn",
\r
9593 "Save Game to File", NULL, fileTitle, NULL);
\r
9595 SaveGame(f, 0, "");
\r
9602 ScheduleDelayedEvent(DelayedEventCallback cb, long millisec)
\r
9604 if (delayedTimerEvent != 0) {
\r
9605 if (appData.debugMode) {
\r
9606 fprintf(debugFP, "ScheduleDelayedEvent: event already scheduled\n");
\r
9608 KillTimer(hwndMain, delayedTimerEvent);
\r
9609 delayedTimerEvent = 0;
\r
9610 delayedTimerCallback();
\r
9612 delayedTimerCallback = cb;
\r
9613 delayedTimerEvent = SetTimer(hwndMain, (UINT) DELAYED_TIMER_ID,
\r
9614 (UINT) millisec, NULL);
\r
9617 DelayedEventCallback
\r
9620 if (delayedTimerEvent) {
\r
9621 return delayedTimerCallback;
\r
9628 CancelDelayedEvent()
\r
9630 if (delayedTimerEvent) {
\r
9631 KillTimer(hwndMain, delayedTimerEvent);
\r
9632 delayedTimerEvent = 0;
\r
9636 DWORD GetWin32Priority(int nice)
\r
9637 { // [HGM] nice: translate Unix nice() value to indows priority class. (Code stolen from Polyglot 1.4w11)
\r
9639 REALTIME_PRIORITY_CLASS 0x00000100
\r
9640 HIGH_PRIORITY_CLASS 0x00000080
\r
9641 ABOVE_NORMAL_PRIORITY_CLASS 0x00008000
\r
9642 NORMAL_PRIORITY_CLASS 0x00000020
\r
9643 BELOW_NORMAL_PRIORITY_CLASS 0x00004000
\r
9644 IDLE_PRIORITY_CLASS 0x00000040
\r
9646 if (nice < -15) return 0x00000080;
\r
9647 if (nice < 0) return 0x00008000;
\r
9648 if (nice == 0) return 0x00000020;
\r
9649 if (nice < 15) return 0x00004000;
\r
9650 return 0x00000040;
\r
9653 /* Start a child process running the given program.
\r
9654 The process's standard output can be read from "from", and its
\r
9655 standard input can be written to "to".
\r
9656 Exit with fatal error if anything goes wrong.
\r
9657 Returns an opaque pointer that can be used to destroy the process
\r
9661 StartChildProcess(char *cmdLine, char *dir, ProcRef *pr)
\r
9663 #define BUFSIZE 4096
\r
9665 HANDLE hChildStdinRd, hChildStdinWr,
\r
9666 hChildStdoutRd, hChildStdoutWr;
\r
9667 HANDLE hChildStdinWrDup, hChildStdoutRdDup;
\r
9668 SECURITY_ATTRIBUTES saAttr;
\r
9670 PROCESS_INFORMATION piProcInfo;
\r
9671 STARTUPINFO siStartInfo;
\r
9673 char buf[MSG_SIZ];
\r
9676 if (appData.debugMode) {
\r
9677 fprintf(debugFP, "StartChildProcess (dir=\"%s\") %s\n", dir, cmdLine);
\r
9682 /* Set the bInheritHandle flag so pipe handles are inherited. */
\r
9683 saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
\r
9684 saAttr.bInheritHandle = TRUE;
\r
9685 saAttr.lpSecurityDescriptor = NULL;
\r
9688 * The steps for redirecting child's STDOUT:
\r
9689 * 1. Create anonymous pipe to be STDOUT for child.
\r
9690 * 2. Create a noninheritable duplicate of read handle,
\r
9691 * and close the inheritable read handle.
\r
9694 /* Create a pipe for the child's STDOUT. */
\r
9695 if (! CreatePipe(&hChildStdoutRd, &hChildStdoutWr, &saAttr, 0)) {
\r
9696 return GetLastError();
\r
9699 /* Duplicate the read handle to the pipe, so it is not inherited. */
\r
9700 fSuccess = DuplicateHandle(GetCurrentProcess(), hChildStdoutRd,
\r
9701 GetCurrentProcess(), &hChildStdoutRdDup, 0,
\r
9702 FALSE, /* not inherited */
\r
9703 DUPLICATE_SAME_ACCESS);
\r
9705 return GetLastError();
\r
9707 CloseHandle(hChildStdoutRd);
\r
9710 * The steps for redirecting child's STDIN:
\r
9711 * 1. Create anonymous pipe to be STDIN for child.
\r
9712 * 2. Create a noninheritable duplicate of write handle,
\r
9713 * and close the inheritable write handle.
\r
9716 /* Create a pipe for the child's STDIN. */
\r
9717 if (! CreatePipe(&hChildStdinRd, &hChildStdinWr, &saAttr, 0)) {
\r
9718 return GetLastError();
\r
9721 /* Duplicate the write handle to the pipe, so it is not inherited. */
\r
9722 fSuccess = DuplicateHandle(GetCurrentProcess(), hChildStdinWr,
\r
9723 GetCurrentProcess(), &hChildStdinWrDup, 0,
\r
9724 FALSE, /* not inherited */
\r
9725 DUPLICATE_SAME_ACCESS);
\r
9727 return GetLastError();
\r
9729 CloseHandle(hChildStdinWr);
\r
9731 /* Arrange to (1) look in dir for the child .exe file, and
\r
9732 * (2) have dir be the child's working directory. Interpret
\r
9733 * dir relative to the directory WinBoard loaded from. */
\r
9734 GetCurrentDirectory(MSG_SIZ, buf);
\r
9735 SetCurrentDirectory(installDir);
\r
9736 SetCurrentDirectory(dir);
\r
9738 /* Now create the child process. */
\r
9740 siStartInfo.cb = sizeof(STARTUPINFO);
\r
9741 siStartInfo.lpReserved = NULL;
\r
9742 siStartInfo.lpDesktop = NULL;
\r
9743 siStartInfo.lpTitle = NULL;
\r
9744 siStartInfo.dwFlags = STARTF_USESTDHANDLES;
\r
9745 siStartInfo.cbReserved2 = 0;
\r
9746 siStartInfo.lpReserved2 = NULL;
\r
9747 siStartInfo.hStdInput = hChildStdinRd;
\r
9748 siStartInfo.hStdOutput = hChildStdoutWr;
\r
9749 siStartInfo.hStdError = hChildStdoutWr;
\r
9751 fSuccess = CreateProcess(NULL,
\r
9752 cmdLine, /* command line */
\r
9753 NULL, /* process security attributes */
\r
9754 NULL, /* primary thread security attrs */
\r
9755 TRUE, /* handles are inherited */
\r
9756 DETACHED_PROCESS|CREATE_NEW_PROCESS_GROUP,
\r
9757 NULL, /* use parent's environment */
\r
9759 &siStartInfo, /* STARTUPINFO pointer */
\r
9760 &piProcInfo); /* receives PROCESS_INFORMATION */
\r
9762 err = GetLastError();
\r
9763 SetCurrentDirectory(buf); /* return to prev directory */
\r
9768 if (appData.niceEngines){ // [HGM] nice: adjust engine proc priority
\r
9769 if(appData.debugMode) fprintf(debugFP, "nice engine proc to %d\n", appData.niceEngines);
\r
9770 SetPriorityClass(piProcInfo.hProcess, GetWin32Priority(appData.niceEngines));
\r
9773 /* Close the handles we don't need in the parent */
\r
9774 CloseHandle(piProcInfo.hThread);
\r
9775 CloseHandle(hChildStdinRd);
\r
9776 CloseHandle(hChildStdoutWr);
\r
9778 /* Prepare return value */
\r
9779 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
9780 cp->kind = CPReal;
\r
9781 cp->hProcess = piProcInfo.hProcess;
\r
9782 cp->pid = piProcInfo.dwProcessId;
\r
9783 cp->hFrom = hChildStdoutRdDup;
\r
9784 cp->hTo = hChildStdinWrDup;
\r
9786 *pr = (void *) cp;
\r
9788 /* Klaus Friedel says that this Sleep solves a problem under Windows
\r
9789 2000 where engines sometimes don't see the initial command(s)
\r
9790 from WinBoard and hang. I don't understand how that can happen,
\r
9791 but the Sleep is harmless, so I've put it in. Others have also
\r
9792 reported what may be the same problem, so hopefully this will fix
\r
9793 it for them too. */
\r
9801 DestroyChildProcess(ProcRef pr, int/*boolean*/ signal)
\r
9803 ChildProc *cp; int result;
\r
9805 cp = (ChildProc *) pr;
\r
9806 if (cp == NULL) return;
\r
9808 switch (cp->kind) {
\r
9810 /* TerminateProcess is considered harmful, so... */
\r
9811 CloseHandle(cp->hTo); /* Closing this will give the child an EOF and hopefully kill it */
\r
9812 if (cp->hFrom) CloseHandle(cp->hFrom); /* if NULL, InputThread will close it */
\r
9813 /* The following doesn't work because the chess program
\r
9814 doesn't "have the same console" as WinBoard. Maybe
\r
9815 we could arrange for this even though neither WinBoard
\r
9816 nor the chess program uses a console for stdio? */
\r
9817 /*!!if (signal) GenerateConsoleCtrlEvent(CTRL_BREAK_EVENT, cp->pid);*/
\r
9819 /* [AS] Special termination modes for misbehaving programs... */
\r
9820 if( signal == 9 ) {
\r
9821 result = TerminateProcess( cp->hProcess, 0 );
\r
9823 if ( appData.debugMode) {
\r
9824 fprintf( debugFP, "Terminating process %lu, result=%d\n", cp->pid, result );
\r
9827 else if( signal == 10 ) {
\r
9828 DWORD dw = WaitForSingleObject( cp->hProcess, 3*1000 ); // Wait 3 seconds at most
\r
9830 if( dw != WAIT_OBJECT_0 ) {
\r
9831 result = TerminateProcess( cp->hProcess, 0 );
\r
9833 if ( appData.debugMode) {
\r
9834 fprintf( debugFP, "Process %lu still alive after timeout, killing... result=%d\n", cp->pid, result );
\r
9840 CloseHandle(cp->hProcess);
\r
9844 if (cp->hFrom) CloseHandle(cp->hFrom);
\r
9848 closesocket(cp->sock);
\r
9853 if (signal) send(cp->sock2, "\017", 1, 0); /* 017 = 15 = SIGTERM */
\r
9854 closesocket(cp->sock);
\r
9855 closesocket(cp->sock2);
\r
9863 InterruptChildProcess(ProcRef pr)
\r
9867 cp = (ChildProc *) pr;
\r
9868 if (cp == NULL) return;
\r
9869 switch (cp->kind) {
\r
9871 /* The following doesn't work because the chess program
\r
9872 doesn't "have the same console" as WinBoard. Maybe
\r
9873 we could arrange for this even though neither WinBoard
\r
9874 nor the chess program uses a console for stdio */
\r
9875 /*!!GenerateConsoleCtrlEvent(CTRL_C_EVENT, cp->pid);*/
\r
9880 /* Can't interrupt */
\r
9884 send(cp->sock2, "\002", 1, 0); /* 2 = SIGINT */
\r
9891 OpenTelnet(char *host, char *port, ProcRef *pr)
\r
9893 char cmdLine[MSG_SIZ];
\r
9895 if (port[0] == NULLCHAR) {
\r
9896 sprintf(cmdLine, "%s %s", appData.telnetProgram, host);
\r
9898 sprintf(cmdLine, "%s %s %s", appData.telnetProgram, host, port);
\r
9900 return StartChildProcess(cmdLine, "", pr);
\r
9904 /* Code to open TCP sockets */
\r
9907 OpenTCP(char *host, char *port, ProcRef *pr)
\r
9912 struct sockaddr_in sa, mysa;
\r
9913 struct hostent FAR *hp;
\r
9914 unsigned short uport;
\r
9915 WORD wVersionRequested;
\r
9918 /* Initialize socket DLL */
\r
9919 wVersionRequested = MAKEWORD(1, 1);
\r
9920 err = WSAStartup(wVersionRequested, &wsaData);
\r
9921 if (err != 0) return err;
\r
9924 if ((s = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
\r
9925 err = WSAGetLastError();
\r
9930 /* Bind local address using (mostly) don't-care values.
\r
9932 memset((char *) &mysa, 0, sizeof(struct sockaddr_in));
\r
9933 mysa.sin_family = AF_INET;
\r
9934 mysa.sin_addr.s_addr = INADDR_ANY;
\r
9935 uport = (unsigned short) 0;
\r
9936 mysa.sin_port = htons(uport);
\r
9937 if (bind(s, (struct sockaddr *) &mysa, sizeof(struct sockaddr_in))
\r
9938 == SOCKET_ERROR) {
\r
9939 err = WSAGetLastError();
\r
9944 /* Resolve remote host name */
\r
9945 memset((char *) &sa, 0, sizeof(struct sockaddr_in));
\r
9946 if (!(hp = gethostbyname(host))) {
\r
9947 unsigned int b0, b1, b2, b3;
\r
9949 err = WSAGetLastError();
\r
9951 if (sscanf(host, "%u.%u.%u.%u", &b0, &b1, &b2, &b3) == 4) {
\r
9952 hp = (struct hostent *) calloc(1, sizeof(struct hostent));
\r
9953 hp->h_addrtype = AF_INET;
\r
9955 hp->h_addr_list = (char **) calloc(2, sizeof(char *));
\r
9956 hp->h_addr_list[0] = (char *) malloc(4);
\r
9957 hp->h_addr_list[0][0] = (char) b0;
\r
9958 hp->h_addr_list[0][1] = (char) b1;
\r
9959 hp->h_addr_list[0][2] = (char) b2;
\r
9960 hp->h_addr_list[0][3] = (char) b3;
\r
9966 sa.sin_family = hp->h_addrtype;
\r
9967 uport = (unsigned short) atoi(port);
\r
9968 sa.sin_port = htons(uport);
\r
9969 memcpy((char *) &sa.sin_addr, hp->h_addr, hp->h_length);
\r
9971 /* Make connection */
\r
9972 if (connect(s, (struct sockaddr *) &sa,
\r
9973 sizeof(struct sockaddr_in)) == SOCKET_ERROR) {
\r
9974 err = WSAGetLastError();
\r
9979 /* Prepare return value */
\r
9980 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
9981 cp->kind = CPSock;
\r
9983 *pr = (ProcRef *) cp;
\r
9989 OpenCommPort(char *name, ProcRef *pr)
\r
9994 char fullname[MSG_SIZ];
\r
9996 if (*name != '\\')
\r
9997 sprintf(fullname, "\\\\.\\%s", name);
\r
9999 strcpy(fullname, name);
\r
10001 h = CreateFile(name, GENERIC_READ | GENERIC_WRITE,
\r
10002 0, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
\r
10003 if (h == (HANDLE) -1) {
\r
10004 return GetLastError();
\r
10008 if (!SetCommState(h, (LPDCB) &dcb)) return GetLastError();
\r
10010 /* Accumulate characters until a 100ms pause, then parse */
\r
10011 ct.ReadIntervalTimeout = 100;
\r
10012 ct.ReadTotalTimeoutMultiplier = 0;
\r
10013 ct.ReadTotalTimeoutConstant = 0;
\r
10014 ct.WriteTotalTimeoutMultiplier = 0;
\r
10015 ct.WriteTotalTimeoutConstant = 0;
\r
10016 if (!SetCommTimeouts(h, (LPCOMMTIMEOUTS) &ct)) return GetLastError();
\r
10018 /* Prepare return value */
\r
10019 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
10020 cp->kind = CPComm;
\r
10023 *pr = (ProcRef *) cp;
\r
10029 OpenLoopback(ProcRef *pr)
\r
10031 DisplayFatalError("Not implemented", 0, 1);
\r
10037 OpenRcmd(char* host, char* user, char* cmd, ProcRef* pr)
\r
10041 SOCKET s, s2, s3;
\r
10042 struct sockaddr_in sa, mysa;
\r
10043 struct hostent FAR *hp;
\r
10044 unsigned short uport;
\r
10045 WORD wVersionRequested;
\r
10048 char stderrPortStr[MSG_SIZ];
\r
10050 /* Initialize socket DLL */
\r
10051 wVersionRequested = MAKEWORD(1, 1);
\r
10052 err = WSAStartup(wVersionRequested, &wsaData);
\r
10053 if (err != 0) return err;
\r
10055 /* Resolve remote host name */
\r
10056 memset((char *) &sa, 0, sizeof(struct sockaddr_in));
\r
10057 if (!(hp = gethostbyname(host))) {
\r
10058 unsigned int b0, b1, b2, b3;
\r
10060 err = WSAGetLastError();
\r
10062 if (sscanf(host, "%u.%u.%u.%u", &b0, &b1, &b2, &b3) == 4) {
\r
10063 hp = (struct hostent *) calloc(1, sizeof(struct hostent));
\r
10064 hp->h_addrtype = AF_INET;
\r
10065 hp->h_length = 4;
\r
10066 hp->h_addr_list = (char **) calloc(2, sizeof(char *));
\r
10067 hp->h_addr_list[0] = (char *) malloc(4);
\r
10068 hp->h_addr_list[0][0] = (char) b0;
\r
10069 hp->h_addr_list[0][1] = (char) b1;
\r
10070 hp->h_addr_list[0][2] = (char) b2;
\r
10071 hp->h_addr_list[0][3] = (char) b3;
\r
10077 sa.sin_family = hp->h_addrtype;
\r
10078 uport = (unsigned short) 514;
\r
10079 sa.sin_port = htons(uport);
\r
10080 memcpy((char *) &sa.sin_addr, hp->h_addr, hp->h_length);
\r
10082 /* Bind local socket to unused "privileged" port address
\r
10084 s = INVALID_SOCKET;
\r
10085 memset((char *) &mysa, 0, sizeof(struct sockaddr_in));
\r
10086 mysa.sin_family = AF_INET;
\r
10087 mysa.sin_addr.s_addr = INADDR_ANY;
\r
10088 for (fromPort = 1023;; fromPort--) {
\r
10089 if (fromPort < 0) {
\r
10091 return WSAEADDRINUSE;
\r
10093 if (s == INVALID_SOCKET) {
\r
10094 if ((s = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
\r
10095 err = WSAGetLastError();
\r
10100 uport = (unsigned short) fromPort;
\r
10101 mysa.sin_port = htons(uport);
\r
10102 if (bind(s, (struct sockaddr *) &mysa, sizeof(struct sockaddr_in))
\r
10103 == SOCKET_ERROR) {
\r
10104 err = WSAGetLastError();
\r
10105 if (err == WSAEADDRINUSE) continue;
\r
10109 if (connect(s, (struct sockaddr *) &sa,
\r
10110 sizeof(struct sockaddr_in)) == SOCKET_ERROR) {
\r
10111 err = WSAGetLastError();
\r
10112 if (err == WSAEADDRINUSE) {
\r
10123 /* Bind stderr local socket to unused "privileged" port address
\r
10125 s2 = INVALID_SOCKET;
\r
10126 memset((char *) &mysa, 0, sizeof(struct sockaddr_in));
\r
10127 mysa.sin_family = AF_INET;
\r
10128 mysa.sin_addr.s_addr = INADDR_ANY;
\r
10129 for (fromPort = 1023;; fromPort--) {
\r
10130 if (fromPort == prevStderrPort) continue; // don't reuse port
\r
10131 if (fromPort < 0) {
\r
10132 (void) closesocket(s);
\r
10134 return WSAEADDRINUSE;
\r
10136 if (s2 == INVALID_SOCKET) {
\r
10137 if ((s2 = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
\r
10138 err = WSAGetLastError();
\r
10144 uport = (unsigned short) fromPort;
\r
10145 mysa.sin_port = htons(uport);
\r
10146 if (bind(s2, (struct sockaddr *) &mysa, sizeof(struct sockaddr_in))
\r
10147 == SOCKET_ERROR) {
\r
10148 err = WSAGetLastError();
\r
10149 if (err == WSAEADDRINUSE) continue;
\r
10150 (void) closesocket(s);
\r
10154 if (listen(s2, 1) == SOCKET_ERROR) {
\r
10155 err = WSAGetLastError();
\r
10156 if (err == WSAEADDRINUSE) {
\r
10158 s2 = INVALID_SOCKET;
\r
10161 (void) closesocket(s);
\r
10162 (void) closesocket(s2);
\r
10168 prevStderrPort = fromPort; // remember port used
\r
10169 sprintf(stderrPortStr, "%d", fromPort);
\r
10171 if (send(s, stderrPortStr, strlen(stderrPortStr) + 1, 0) == SOCKET_ERROR) {
\r
10172 err = WSAGetLastError();
\r
10173 (void) closesocket(s);
\r
10174 (void) closesocket(s2);
\r
10179 if (send(s, UserName(), strlen(UserName()) + 1, 0) == SOCKET_ERROR) {
\r
10180 err = WSAGetLastError();
\r
10181 (void) closesocket(s);
\r
10182 (void) closesocket(s2);
\r
10186 if (*user == NULLCHAR) user = UserName();
\r
10187 if (send(s, user, strlen(user) + 1, 0) == SOCKET_ERROR) {
\r
10188 err = WSAGetLastError();
\r
10189 (void) closesocket(s);
\r
10190 (void) closesocket(s2);
\r
10194 if (send(s, cmd, strlen(cmd) + 1, 0) == SOCKET_ERROR) {
\r
10195 err = WSAGetLastError();
\r
10196 (void) closesocket(s);
\r
10197 (void) closesocket(s2);
\r
10202 if ((s3 = accept(s2, NULL, NULL)) == INVALID_SOCKET) {
\r
10203 err = WSAGetLastError();
\r
10204 (void) closesocket(s);
\r
10205 (void) closesocket(s2);
\r
10209 (void) closesocket(s2); /* Stop listening */
\r
10211 /* Prepare return value */
\r
10212 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
10213 cp->kind = CPRcmd;
\r
10216 *pr = (ProcRef *) cp;
\r
10223 AddInputSource(ProcRef pr, int lineByLine,
\r
10224 InputCallback func, VOIDSTAR closure)
\r
10226 InputSource *is, *is2 = NULL;
\r
10227 ChildProc *cp = (ChildProc *) pr;
\r
10229 is = (InputSource *) calloc(1, sizeof(InputSource));
\r
10230 is->lineByLine = lineByLine;
\r
10232 is->closure = closure;
\r
10233 is->second = NULL;
\r
10234 is->next = is->buf;
\r
10235 if (pr == NoProc) {
\r
10236 is->kind = CPReal;
\r
10237 consoleInputSource = is;
\r
10239 is->kind = cp->kind;
\r
10241 [AS] Try to avoid a race condition if the thread is given control too early:
\r
10242 we create all threads suspended so that the is->hThread variable can be
\r
10243 safely assigned, then let the threads start with ResumeThread.
\r
10245 switch (cp->kind) {
\r
10247 is->hFile = cp->hFrom;
\r
10248 cp->hFrom = NULL; /* now owned by InputThread */
\r
10250 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) NonOvlInputThread,
\r
10251 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
10255 is->hFile = cp->hFrom;
\r
10256 cp->hFrom = NULL; /* now owned by InputThread */
\r
10258 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) InputThread,
\r
10259 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
10263 is->sock = cp->sock;
\r
10265 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SocketInputThread,
\r
10266 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
10270 is2 = (InputSource *) calloc(1, sizeof(InputSource));
\r
10272 is->sock = cp->sock;
\r
10273 is->second = is2;
\r
10274 is2->sock = cp->sock2;
\r
10275 is2->second = is2;
\r
10277 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SocketInputThread,
\r
10278 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
10280 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SocketInputThread,
\r
10281 (LPVOID) is2, CREATE_SUSPENDED, &is2->id);
\r
10285 if( is->hThread != NULL ) {
\r
10286 ResumeThread( is->hThread );
\r
10289 if( is2 != NULL && is2->hThread != NULL ) {
\r
10290 ResumeThread( is2->hThread );
\r
10294 return (InputSourceRef) is;
\r
10298 RemoveInputSource(InputSourceRef isr)
\r
10302 is = (InputSource *) isr;
\r
10303 is->hThread = NULL; /* tell thread to stop */
\r
10304 CloseHandle(is->hThread);
\r
10305 if (is->second != NULL) {
\r
10306 is->second->hThread = NULL;
\r
10307 CloseHandle(is->second->hThread);
\r
10313 OutputToProcess(ProcRef pr, char *message, int count, int *outError)
\r
10316 int outCount = SOCKET_ERROR;
\r
10317 ChildProc *cp = (ChildProc *) pr;
\r
10318 static OVERLAPPED ovl;
\r
10320 if (pr == NoProc) {
\r
10321 ConsoleOutput(message, count, FALSE);
\r
10325 if (ovl.hEvent == NULL) {
\r
10326 ovl.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
\r
10328 ovl.Internal = ovl.InternalHigh = ovl.Offset = ovl.OffsetHigh = 0;
\r
10330 switch (cp->kind) {
\r
10333 outCount = send(cp->sock, message, count, 0);
\r
10334 if (outCount == SOCKET_ERROR) {
\r
10335 *outError = WSAGetLastError();
\r
10337 *outError = NO_ERROR;
\r
10342 if (WriteFile(((ChildProc *)pr)->hTo, message, count,
\r
10343 &dOutCount, NULL)) {
\r
10344 *outError = NO_ERROR;
\r
10345 outCount = (int) dOutCount;
\r
10347 *outError = GetLastError();
\r
10352 *outError = DoWriteFile(((ChildProc *)pr)->hTo, message, count,
\r
10353 &dOutCount, &ovl);
\r
10354 if (*outError == NO_ERROR) {
\r
10355 outCount = (int) dOutCount;
\r
10363 OutputToProcessDelayed(ProcRef pr, char *message, int count, int *outError,
\r
10366 /* Ignore delay, not implemented for WinBoard */
\r
10367 return OutputToProcess(pr, message, count, outError);
\r
10372 CmailSigHandlerCallBack(InputSourceRef isr, VOIDSTAR closure,
\r
10373 char *buf, int count, int error)
\r
10375 DisplayFatalError("Not implemented", 0, 1);
\r
10378 /* see wgamelist.c for Game List functions */
\r
10379 /* see wedittags.c for Edit Tags functions */
\r
10386 char buf[MSG_SIZ];
\r
10389 if (SearchPath(installDir, appData.icsLogon, NULL, MSG_SIZ, buf, &dummy)) {
\r
10390 f = fopen(buf, "r");
\r
10392 ProcessICSInitScript(f);
\r
10400 StartAnalysisClock()
\r
10402 if (analysisTimerEvent) return;
\r
10403 analysisTimerEvent = SetTimer(hwndMain, (UINT) ANALYSIS_TIMER_ID,
\r
10404 (UINT) 2000, NULL);
\r
10408 AnalysisDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
10410 static HANDLE hwndText;
\r
10412 static int sizeX, sizeY;
\r
10413 int newSizeX, newSizeY, flags;
\r
10416 switch (message) {
\r
10417 case WM_INITDIALOG: /* message: initialize dialog box */
\r
10418 /* Initialize the dialog items */
\r
10419 hwndText = GetDlgItem(hDlg, OPT_AnalysisText);
\r
10420 SetWindowText(hDlg, analysisTitle);
\r
10421 SetDlgItemText(hDlg, OPT_AnalysisText, analysisText);
\r
10422 /* Size and position the dialog */
\r
10423 if (!analysisDialog) {
\r
10424 analysisDialog = hDlg;
\r
10425 flags = SWP_NOZORDER;
\r
10426 GetClientRect(hDlg, &rect);
\r
10427 sizeX = rect.right;
\r
10428 sizeY = rect.bottom;
\r
10429 if (analysisX != CW_USEDEFAULT && analysisY != CW_USEDEFAULT &&
\r
10430 analysisW != CW_USEDEFAULT && analysisH != CW_USEDEFAULT) {
\r
10431 WINDOWPLACEMENT wp;
\r
10432 EnsureOnScreen(&analysisX, &analysisY);
\r
10433 wp.length = sizeof(WINDOWPLACEMENT);
\r
10435 wp.showCmd = SW_SHOW;
\r
10436 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
10437 wp.rcNormalPosition.left = analysisX;
\r
10438 wp.rcNormalPosition.right = analysisX + analysisW;
\r
10439 wp.rcNormalPosition.top = analysisY;
\r
10440 wp.rcNormalPosition.bottom = analysisY + analysisH;
\r
10441 SetWindowPlacement(hDlg, &wp);
\r
10443 GetClientRect(hDlg, &rect);
\r
10444 newSizeX = rect.right;
\r
10445 newSizeY = rect.bottom;
\r
10446 ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY,
\r
10447 newSizeX, newSizeY);
\r
10448 sizeX = newSizeX;
\r
10449 sizeY = newSizeY;
\r
10454 case WM_COMMAND: /* message: received a command */
\r
10455 switch (LOWORD(wParam)) {
\r
10457 if (appData.icsActive && appData.icsEngineAnalyze) { /* [DM] icsEngineAnalyze */
\r
10458 ExitAnalyzeMode();
\r
10470 newSizeX = LOWORD(lParam);
\r
10471 newSizeY = HIWORD(lParam);
\r
10472 ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY, newSizeX, newSizeY);
\r
10473 sizeX = newSizeX;
\r
10474 sizeY = newSizeY;
\r
10477 case WM_GETMINMAXINFO:
\r
10478 /* Prevent resizing window too small */
\r
10479 mmi = (MINMAXINFO *) lParam;
\r
10480 mmi->ptMinTrackSize.x = 100;
\r
10481 mmi->ptMinTrackSize.y = 100;
\r
10488 AnalysisPopUp(char* title, char* str)
\r
10494 EngineOutputPopUp();
\r
10497 if (str == NULL) str = "";
\r
10498 p = (char *) malloc(2 * strlen(str) + 2);
\r
10501 if (*str == '\n') *q++ = '\r';
\r
10505 if (analysisText != NULL) free(analysisText);
\r
10506 analysisText = p;
\r
10508 if (analysisDialog) {
\r
10509 SetWindowText(analysisDialog, title);
\r
10510 SetDlgItemText(analysisDialog, OPT_AnalysisText, analysisText);
\r
10511 ShowWindow(analysisDialog, SW_SHOW);
\r
10513 analysisTitle = title;
\r
10514 lpProc = MakeProcInstance((FARPROC)AnalysisDialog, hInst);
\r
10515 CreateDialog(hInst, MAKEINTRESOURCE(DLG_Analysis),
\r
10516 hwndMain, (DLGPROC)lpProc);
\r
10517 FreeProcInstance(lpProc);
\r
10519 analysisDialogUp = TRUE;
\r
10523 AnalysisPopDown()
\r
10525 if (analysisDialog) {
\r
10526 ShowWindow(analysisDialog, SW_HIDE);
\r
10528 analysisDialogUp = FALSE;
\r
10533 SetHighlights(int fromX, int fromY, int toX, int toY)
\r
10535 highlightInfo.sq[0].x = fromX;
\r
10536 highlightInfo.sq[0].y = fromY;
\r
10537 highlightInfo.sq[1].x = toX;
\r
10538 highlightInfo.sq[1].y = toY;
\r
10542 ClearHighlights()
\r
10544 highlightInfo.sq[0].x = highlightInfo.sq[0].y =
\r
10545 highlightInfo.sq[1].x = highlightInfo.sq[1].y = -1;
\r
10549 SetPremoveHighlights(int fromX, int fromY, int toX, int toY)
\r
10551 premoveHighlightInfo.sq[0].x = fromX;
\r
10552 premoveHighlightInfo.sq[0].y = fromY;
\r
10553 premoveHighlightInfo.sq[1].x = toX;
\r
10554 premoveHighlightInfo.sq[1].y = toY;
\r
10558 ClearPremoveHighlights()
\r
10560 premoveHighlightInfo.sq[0].x = premoveHighlightInfo.sq[0].y =
\r
10561 premoveHighlightInfo.sq[1].x = premoveHighlightInfo.sq[1].y = -1;
\r
10565 ShutDownFrontEnd()
\r
10567 if (saveSettingsOnExit) SaveSettings(settingsFileName);
\r
10568 DeleteClipboardTempFiles();
\r
10574 if (IsIconic(hwndMain))
\r
10575 ShowWindow(hwndMain, SW_RESTORE);
\r
10577 SetActiveWindow(hwndMain);
\r
10581 * Prototypes for animation support routines
\r
10583 static void ScreenSquare(int column, int row, POINT * pt);
\r
10584 static void Tween( POINT * start, POINT * mid, POINT * finish, int factor,
\r
10585 POINT frames[], int * nFrames);
\r
10589 AnimateAtomicCapture(int toX, int toY, int nFrames)
\r
10590 { // [HGM] atomic: animate blast wave
\r
10592 if(appData.debugMode) fprintf(debugFP, "exploding (%d,%d)\n", toX, toY);
\r
10593 explodeInfo.x = toX;
\r
10594 explodeInfo.y = toY;
\r
10595 for(i=0; i<nFrames; i++) {
\r
10596 explodeInfo.radius = (i*180)/(nFrames-1);
\r
10597 DrawPosition(FALSE, NULL);
\r
10598 Sleep(appData.animSpeed);
\r
10600 explodeInfo.radius = 0;
\r
10601 DrawPosition(TRUE, NULL);
\r
10604 #define kFactor 4
\r
10607 AnimateMove(board, fromX, fromY, toX, toY)
\r
10614 ChessSquare piece;
\r
10615 POINT start, finish, mid;
\r
10616 POINT frames[kFactor * 2 + 1];
\r
10619 if (!appData.animate) return;
\r
10620 if (doingSizing) return;
\r
10621 if (fromY < 0 || fromX < 0) return;
\r
10622 piece = board[fromY][fromX];
\r
10623 if (piece >= EmptySquare) return;
\r
10625 ScreenSquare(fromX, fromY, &start);
\r
10626 ScreenSquare(toX, toY, &finish);
\r
10628 /* All pieces except knights move in straight line */
\r
10629 if (piece != WhiteKnight && piece != BlackKnight) {
\r
10630 mid.x = start.x + (finish.x - start.x) / 2;
\r
10631 mid.y = start.y + (finish.y - start.y) / 2;
\r
10633 /* Knight: make diagonal movement then straight */
\r
10634 if (abs(toY - fromY) < abs(toX - fromX)) {
\r
10635 mid.x = start.x + (finish.x - start.x) / 2;
\r
10636 mid.y = finish.y;
\r
10638 mid.x = finish.x;
\r
10639 mid.y = start.y + (finish.y - start.y) / 2;
\r
10643 /* Don't use as many frames for very short moves */
\r
10644 if (abs(toY - fromY) + abs(toX - fromX) <= 2)
\r
10645 Tween(&start, &mid, &finish, kFactor - 1, frames, &nFrames);
\r
10647 Tween(&start, &mid, &finish, kFactor, frames, &nFrames);
\r
10649 animInfo.from.x = fromX;
\r
10650 animInfo.from.y = fromY;
\r
10651 animInfo.to.x = toX;
\r
10652 animInfo.to.y = toY;
\r
10653 animInfo.lastpos = start;
\r
10654 animInfo.piece = piece;
\r
10655 for (n = 0; n < nFrames; n++) {
\r
10656 animInfo.pos = frames[n];
\r
10657 DrawPosition(FALSE, NULL);
\r
10658 animInfo.lastpos = animInfo.pos;
\r
10659 Sleep(appData.animSpeed);
\r
10661 animInfo.pos = finish;
\r
10662 DrawPosition(FALSE, NULL);
\r
10663 animInfo.piece = EmptySquare;
\r
10664 if(gameInfo.variant == VariantAtomic && board[toY][toX] != EmptySquare)
\r
10665 AnimateAtomicCapture(toX, toY, 2*nFrames);
\r
10668 /* Convert board position to corner of screen rect and color */
\r
10671 ScreenSquare(column, row, pt)
\r
10672 int column; int row; POINT * pt;
\r
10675 pt->x = lineGap + ((BOARD_WIDTH-1)-column) * (squareSize + lineGap);
\r
10676 pt->y = lineGap + row * (squareSize + lineGap);
\r
10678 pt->x = lineGap + column * (squareSize + lineGap);
\r
10679 pt->y = lineGap + ((BOARD_HEIGHT-1)-row) * (squareSize + lineGap);
\r
10683 /* Generate a series of frame coords from start->mid->finish.
\r
10684 The movement rate doubles until the half way point is
\r
10685 reached, then halves back down to the final destination,
\r
10686 which gives a nice slow in/out effect. The algorithmn
\r
10687 may seem to generate too many intermediates for short
\r
10688 moves, but remember that the purpose is to attract the
\r
10689 viewers attention to the piece about to be moved and
\r
10690 then to where it ends up. Too few frames would be less
\r
10694 Tween(start, mid, finish, factor, frames, nFrames)
\r
10695 POINT * start; POINT * mid;
\r
10696 POINT * finish; int factor;
\r
10697 POINT frames[]; int * nFrames;
\r
10699 int n, fraction = 1, count = 0;
\r
10701 /* Slow in, stepping 1/16th, then 1/8th, ... */
\r
10702 for (n = 0; n < factor; n++)
\r
10704 for (n = 0; n < factor; n++) {
\r
10705 frames[count].x = start->x + (mid->x - start->x) / fraction;
\r
10706 frames[count].y = start->y + (mid->y - start->y) / fraction;
\r
10708 fraction = fraction / 2;
\r
10712 frames[count] = *mid;
\r
10715 /* Slow out, stepping 1/2, then 1/4, ... */
\r
10717 for (n = 0; n < factor; n++) {
\r
10718 frames[count].x = finish->x - (finish->x - mid->x) / fraction;
\r
10719 frames[count].y = finish->y - (finish->y - mid->y) / fraction;
\r
10721 fraction = fraction * 2;
\r
10723 *nFrames = count;
\r
10727 HistorySet( char movelist[][2*MOVE_LEN], int first, int last, int current )
\r
10732 sprintf( buf, "HistorySet: first=%d, last=%d, current=%d (%s)\n",
\r
10733 first, last, current, current >= 0 ? movelist[current] : "n/a" );
\r
10735 OutputDebugString( buf );
\r
10738 MoveHistorySet( movelist, first, last, current, pvInfoList );
\r
10740 EvalGraphSet( first, last, current, pvInfoList );
\r
10743 void SetProgramStats( FrontEndProgramStats * stats )
\r
10748 sprintf( buf, "SetStats for %d: depth=%d, nodes=%lu, score=%5.2f, time=%5.2f, pv=%s\n",
\r
10749 stats->which, stats->depth, stats->nodes, stats->score / 100.0, stats->time / 100.0, stats->pv == 0 ? "n/a" : stats->pv );
\r
10751 OutputDebugString( buf );
\r
10754 EngineOutputUpdate( stats );
\r