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
6279 if( hwnd == hwndMain && appData.useStickyWindows ) {
\r
6280 LPWINDOWPOS lpwp = (LPWINDOWPOS) lParam;
\r
6282 if( ((lpwp->flags & SWP_NOMOVE) == 0) && ((lpwp->flags & SWP_NOSIZE) != 0) ) {
\r
6283 /* Window is moving */
\r
6286 // GetWindowRect( hwnd, &rcMain ); //[HGM] sticky: in XP this returned new position, not old
\r
6287 rcMain.left = boardX; // replace by these 4 lines to reconstruct old rect
\r
6288 rcMain.right = boardX + winWidth;
\r
6289 rcMain.top = boardY;
\r
6290 rcMain.bottom = boardY + winHeight;
\r
6292 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, moveHistoryDialog, &wpMoveHistory );
\r
6293 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, evalGraphDialog, &wpEvalGraph );
\r
6294 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, engineOutputDialog, &wpEngineOutput );
\r
6301 /* [AS] Snapping */
\r
6302 case WM_ENTERSIZEMOVE:
\r
6303 if(appData.debugMode) { fprintf(debugFP, "size-move\n"); }
\r
6304 if (hwnd == hwndMain) {
\r
6305 doingSizing = TRUE;
\r
6308 return OnEnterSizeMove( &sd, hwnd, wParam, lParam );
\r
6312 if(appData.debugMode) { fprintf(debugFP, "sizing\n"); }
\r
6313 if (hwnd == hwndMain) {
\r
6314 lastSizing = wParam;
\r
6319 if(appData.debugMode) { fprintf(debugFP, "moving\n"); }
\r
6320 return OnMoving( &sd, hwnd, wParam, lParam );
\r
6322 case WM_EXITSIZEMOVE:
\r
6323 if(appData.debugMode) { fprintf(debugFP, "exit size-move, size = %d\n", squareSize); }
\r
6324 if (hwnd == hwndMain) {
\r
6326 doingSizing = FALSE;
\r
6327 InvalidateRect(hwnd, &boardRect, FALSE);
\r
6328 GetClientRect(hwnd, &client);
\r
6329 ResizeBoard(client.right, client.bottom, lastSizing);
\r
6331 if(appData.debugMode) { fprintf(debugFP, "square size = %d\n", squareSize); }
\r
6333 return OnExitSizeMove( &sd, hwnd, wParam, lParam );
\r
6336 case WM_DESTROY: /* message: window being destroyed */
\r
6337 PostQuitMessage(0);
\r
6341 if (hwnd == hwndMain) {
\r
6346 default: /* Passes it on if unprocessed */
\r
6347 return (DefWindowProc(hwnd, message, wParam, lParam));
\r
6352 /*---------------------------------------------------------------------------*\
\r
6354 * Misc utility routines
\r
6356 \*---------------------------------------------------------------------------*/
\r
6359 * Decent random number generator, at least not as bad as Windows
\r
6360 * standard rand, which returns a value in the range 0 to 0x7fff.
\r
6362 unsigned int randstate;
\r
6367 randstate = randstate * 1664525 + 1013904223;
\r
6368 return (int) randstate & 0x7fffffff;
\r
6372 mysrandom(unsigned int seed)
\r
6379 * returns TRUE if user selects a different color, FALSE otherwise
\r
6383 ChangeColor(HWND hwnd, COLORREF *which)
\r
6385 static BOOL firstTime = TRUE;
\r
6386 static DWORD customColors[16];
\r
6388 COLORREF newcolor;
\r
6393 /* Make initial colors in use available as custom colors */
\r
6394 /* Should we put the compiled-in defaults here instead? */
\r
6396 customColors[i++] = lightSquareColor & 0xffffff;
\r
6397 customColors[i++] = darkSquareColor & 0xffffff;
\r
6398 customColors[i++] = whitePieceColor & 0xffffff;
\r
6399 customColors[i++] = blackPieceColor & 0xffffff;
\r
6400 customColors[i++] = highlightSquareColor & 0xffffff;
\r
6401 customColors[i++] = premoveHighlightColor & 0xffffff;
\r
6403 for (ccl = (ColorClass) 0; ccl < NColorClasses && i < 16; ccl++) {
\r
6404 customColors[i++] = textAttribs[ccl].color;
\r
6406 while (i < 16) customColors[i++] = RGB(255, 255, 255);
\r
6407 firstTime = FALSE;
\r
6410 cc.lStructSize = sizeof(cc);
\r
6411 cc.hwndOwner = hwnd;
\r
6412 cc.hInstance = NULL;
\r
6413 cc.rgbResult = (DWORD) (*which & 0xffffff);
\r
6414 cc.lpCustColors = (LPDWORD) customColors;
\r
6415 cc.Flags = CC_RGBINIT|CC_FULLOPEN;
\r
6417 if (!ChooseColor(&cc)) return FALSE;
\r
6419 newcolor = (COLORREF) (0x2000000 | cc.rgbResult);
\r
6420 if (newcolor == *which) return FALSE;
\r
6421 *which = newcolor;
\r
6425 InitDrawingColors();
\r
6426 InvalidateRect(hwnd, &boardRect, FALSE);
\r
6431 MyLoadSound(MySound *ms)
\r
6437 if (ms->data) free(ms->data);
\r
6440 switch (ms->name[0]) {
\r
6446 /* System sound from Control Panel. Don't preload here. */
\r
6450 if (ms->name[1] == NULLCHAR) {
\r
6451 /* "!" alone = silence */
\r
6454 /* Builtin wave resource. Error if not found. */
\r
6455 HANDLE h = FindResource(hInst, ms->name + 1, "WAVE");
\r
6456 if (h == NULL) break;
\r
6457 ms->data = (void *)LoadResource(hInst, h);
\r
6458 if (h == NULL) break;
\r
6463 /* .wav file. Error if not found. */
\r
6464 f = fopen(ms->name, "rb");
\r
6465 if (f == NULL) break;
\r
6466 if (fstat(fileno(f), &st) < 0) break;
\r
6467 ms->data = malloc(st.st_size);
\r
6468 if (fread(ms->data, st.st_size, 1, f) < 1) break;
\r
6474 char buf[MSG_SIZ];
\r
6475 sprintf(buf, "Error loading sound %s", ms->name);
\r
6476 DisplayError(buf, GetLastError());
\r
6482 MyPlaySound(MySound *ms)
\r
6484 BOOLEAN ok = FALSE;
\r
6485 switch (ms->name[0]) {
\r
6491 /* System sound from Control Panel (deprecated feature).
\r
6492 "$" alone or an unset sound name gets default beep (still in use). */
\r
6493 if (ms->name[1]) {
\r
6494 ok = PlaySound(ms->name + 1, NULL, SND_ALIAS|SND_ASYNC);
\r
6496 if (!ok) ok = MessageBeep(MB_OK);
\r
6499 /* Builtin wave resource, or "!" alone for silence */
\r
6500 if (ms->name[1]) {
\r
6501 if (ms->data == NULL) return FALSE;
\r
6502 ok = PlaySound(ms->data, NULL, SND_MEMORY|SND_ASYNC);
\r
6508 /* .wav file. Error if not found. */
\r
6509 if (ms->data == NULL) return FALSE;
\r
6510 ok = PlaySound(ms->data, NULL, SND_MEMORY|SND_ASYNC);
\r
6513 /* Don't print an error: this can happen innocently if the sound driver
\r
6514 is busy; for instance, if another instance of WinBoard is playing
\r
6515 a sound at about the same time. */
\r
6518 char buf[MSG_SIZ];
\r
6519 sprintf(buf, "Error playing sound %s", ms->name);
\r
6520 DisplayError(buf, GetLastError());
\r
6528 OldOpenFileHook(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
6531 OPENFILENAME *ofn;
\r
6532 static UINT *number; /* gross that this is static */
\r
6534 switch (message) {
\r
6535 case WM_INITDIALOG: /* message: initialize dialog box */
\r
6536 /* Center the dialog over the application window */
\r
6537 ofn = (OPENFILENAME *) lParam;
\r
6538 if (ofn->Flags & OFN_ENABLETEMPLATE) {
\r
6539 number = (UINT *) ofn->lCustData;
\r
6540 SendMessage(GetDlgItem(hDlg, edt2), WM_SETTEXT, 0, (LPARAM) "");
\r
6544 CenterWindow (hDlg, GetWindow (hDlg, GW_OWNER));
\r
6545 return FALSE; /* Allow for further processing */
\r
6548 if ((LOWORD(wParam) == IDOK) && (number != NULL)) {
\r
6549 *number = GetDlgItemInt(hDlg, OPT_IndexNumberOld, &ok, FALSE);
\r
6551 return FALSE; /* Allow for further processing */
\r
6557 OpenFileHook(HWND hdlg, UINT uiMsg, WPARAM wParam, LPARAM lParam)
\r
6559 static UINT *number;
\r
6560 OPENFILENAME *ofname;
\r
6563 case WM_INITDIALOG:
\r
6564 ofname = (OPENFILENAME *)lParam;
\r
6565 number = (UINT *)(ofname->lCustData);
\r
6568 ofnot = (OFNOTIFY *)lParam;
\r
6569 if (ofnot->hdr.code == CDN_FILEOK) {
\r
6570 *number = GetDlgItemInt(hdlg, OPT_IndexNumber, NULL, FALSE);
\r
6579 OpenFileDialog(HWND hwnd, char *write, char *defName, char *defExt, // [HGM] diag: type of 'write' now string
\r
6580 char *nameFilt, char *dlgTitle, UINT *number,
\r
6581 char fileTitle[MSG_SIZ], char fileName[MSG_SIZ])
\r
6583 OPENFILENAME openFileName;
\r
6584 char buf1[MSG_SIZ];
\r
6587 if (fileName == NULL) fileName = buf1;
\r
6588 if (defName == NULL) {
\r
6589 strcpy(fileName, "*.");
\r
6590 strcat(fileName, defExt);
\r
6592 strcpy(fileName, defName);
\r
6594 if (fileTitle) strcpy(fileTitle, "");
\r
6595 if (number) *number = 0;
\r
6597 openFileName.lStructSize = sizeof(OPENFILENAME);
\r
6598 openFileName.hwndOwner = hwnd;
\r
6599 openFileName.hInstance = (HANDLE) hInst;
\r
6600 openFileName.lpstrFilter = nameFilt;
\r
6601 openFileName.lpstrCustomFilter = (LPSTR) NULL;
\r
6602 openFileName.nMaxCustFilter = 0L;
\r
6603 openFileName.nFilterIndex = 1L;
\r
6604 openFileName.lpstrFile = fileName;
\r
6605 openFileName.nMaxFile = MSG_SIZ;
\r
6606 openFileName.lpstrFileTitle = fileTitle;
\r
6607 openFileName.nMaxFileTitle = fileTitle ? MSG_SIZ : 0;
\r
6608 openFileName.lpstrInitialDir = NULL;
\r
6609 openFileName.lpstrTitle = dlgTitle;
\r
6610 openFileName.Flags = OFN_PATHMUSTEXIST | OFN_HIDEREADONLY
\r
6611 | (write[0] != 'r' ? 0 : OFN_FILEMUSTEXIST)
\r
6612 | (number ? OFN_ENABLETEMPLATE | OFN_ENABLEHOOK: 0)
\r
6613 | (oldDialog ? 0 : OFN_EXPLORER);
\r
6614 openFileName.nFileOffset = 0;
\r
6615 openFileName.nFileExtension = 0;
\r
6616 openFileName.lpstrDefExt = defExt;
\r
6617 openFileName.lCustData = (LONG) number;
\r
6618 openFileName.lpfnHook = oldDialog ?
\r
6619 (LPOFNHOOKPROC) OldOpenFileHook : (LPOFNHOOKPROC) OpenFileHook;
\r
6620 openFileName.lpTemplateName = (LPSTR)(oldDialog ? 1536 : DLG_IndexNumber);
\r
6622 if (write[0] != 'r' ? GetSaveFileName(&openFileName) :
\r
6623 GetOpenFileName(&openFileName)) {
\r
6624 /* open the file */
\r
6625 f = fopen(openFileName.lpstrFile, write);
\r
6627 MessageBox(hwnd, "File open failed", NULL,
\r
6628 MB_OK|MB_ICONEXCLAMATION);
\r
6632 int err = CommDlgExtendedError();
\r
6633 if (err != 0) DisplayError("Internal error in file dialog box", err);
\r
6642 MenuPopup(HWND hwnd, POINT pt, HMENU hmenu, UINT def)
\r
6644 HMENU hmenuTrackPopup; /* floating pop-up menu */
\r
6647 * Get the first pop-up menu in the menu template. This is the
\r
6648 * menu that TrackPopupMenu displays.
\r
6650 hmenuTrackPopup = GetSubMenu(hmenu, 0);
\r
6652 SetMenuDefaultItem(hmenuTrackPopup, def, FALSE);
\r
6655 * TrackPopup uses screen coordinates, so convert the
\r
6656 * coordinates of the mouse click to screen coordinates.
\r
6658 ClientToScreen(hwnd, (LPPOINT) &pt);
\r
6660 /* Draw and track the floating pop-up menu. */
\r
6661 TrackPopupMenu(hmenuTrackPopup, TPM_CENTERALIGN | TPM_RIGHTBUTTON,
\r
6662 pt.x, pt.y, 0, hwnd, NULL);
\r
6664 /* Destroy the menu.*/
\r
6665 DestroyMenu(hmenu);
\r
6670 int sizeX, sizeY, newSizeX, newSizeY;
\r
6672 } ResizeEditPlusButtonsClosure;
\r
6675 ResizeEditPlusButtonsCallback(HWND hChild, LPARAM lparam)
\r
6677 ResizeEditPlusButtonsClosure *cl = (ResizeEditPlusButtonsClosure *)lparam;
\r
6681 if (hChild == cl->hText) return TRUE;
\r
6682 GetWindowRect(hChild, &rect); /* gives screen coords */
\r
6683 pt.x = rect.left + (cl->newSizeX - cl->sizeX)/2;
\r
6684 pt.y = rect.top + cl->newSizeY - cl->sizeY;
\r
6685 ScreenToClient(cl->hDlg, &pt);
\r
6686 cl->hdwp = DeferWindowPos(cl->hdwp, hChild, NULL,
\r
6687 pt.x, pt.y, rect.right - rect.left, rect.bottom - rect.top, SWP_NOZORDER);
\r
6691 /* Resize a dialog that has a (rich) edit field filling most of
\r
6692 the top, with a row of buttons below */
\r
6694 ResizeEditPlusButtons(HWND hDlg, HWND hText, int sizeX, int sizeY, int newSizeX, int newSizeY)
\r
6697 int newTextHeight, newTextWidth;
\r
6698 ResizeEditPlusButtonsClosure cl;
\r
6700 /*if (IsIconic(hDlg)) return;*/
\r
6701 if (newSizeX == sizeX && newSizeY == sizeY) return;
\r
6703 cl.hdwp = BeginDeferWindowPos(8);
\r
6705 GetWindowRect(hText, &rectText); /* gives screen coords */
\r
6706 newTextWidth = rectText.right - rectText.left + newSizeX - sizeX;
\r
6707 newTextHeight = rectText.bottom - rectText.top + newSizeY - sizeY;
\r
6708 if (newTextHeight < 0) {
\r
6709 newSizeY += -newTextHeight;
\r
6710 newTextHeight = 0;
\r
6712 cl.hdwp = DeferWindowPos(cl.hdwp, hText, NULL, 0, 0,
\r
6713 newTextWidth, newTextHeight, SWP_NOZORDER|SWP_NOMOVE);
\r
6719 cl.newSizeX = newSizeX;
\r
6720 cl.newSizeY = newSizeY;
\r
6721 EnumChildWindows(hDlg, ResizeEditPlusButtonsCallback, (LPARAM)&cl);
\r
6723 EndDeferWindowPos(cl.hdwp);
\r
6726 BOOL CenterWindowEx(HWND hwndChild, HWND hwndParent, int mode)
\r
6728 RECT rChild, rParent;
\r
6729 int wChild, hChild, wParent, hParent;
\r
6730 int wScreen, hScreen, xNew, yNew;
\r
6733 /* Get the Height and Width of the child window */
\r
6734 GetWindowRect (hwndChild, &rChild);
\r
6735 wChild = rChild.right - rChild.left;
\r
6736 hChild = rChild.bottom - rChild.top;
\r
6738 /* Get the Height and Width of the parent window */
\r
6739 GetWindowRect (hwndParent, &rParent);
\r
6740 wParent = rParent.right - rParent.left;
\r
6741 hParent = rParent.bottom - rParent.top;
\r
6743 /* Get the display limits */
\r
6744 hdc = GetDC (hwndChild);
\r
6745 wScreen = GetDeviceCaps (hdc, HORZRES);
\r
6746 hScreen = GetDeviceCaps (hdc, VERTRES);
\r
6747 ReleaseDC(hwndChild, hdc);
\r
6749 /* Calculate new X position, then adjust for screen */
\r
6750 xNew = rParent.left + ((wParent - wChild) /2);
\r
6753 } else if ((xNew+wChild) > wScreen) {
\r
6754 xNew = wScreen - wChild;
\r
6757 /* Calculate new Y position, then adjust for screen */
\r
6759 yNew = rParent.top + ((hParent - hChild) /2);
\r
6762 yNew = rParent.top + GetSystemMetrics( SM_CYCAPTION ) * 2 / 3;
\r
6767 } else if ((yNew+hChild) > hScreen) {
\r
6768 yNew = hScreen - hChild;
\r
6771 /* Set it, and return */
\r
6772 return SetWindowPos (hwndChild, NULL,
\r
6773 xNew, yNew, 0, 0, SWP_NOSIZE | SWP_NOZORDER);
\r
6776 /* Center one window over another */
\r
6777 BOOL CenterWindow (HWND hwndChild, HWND hwndParent)
\r
6779 return CenterWindowEx( hwndChild, hwndParent, 0 );
\r
6782 /*---------------------------------------------------------------------------*\
\r
6784 * Startup Dialog functions
\r
6786 \*---------------------------------------------------------------------------*/
\r
6788 InitComboStrings(HANDLE hwndCombo, char **cd)
\r
6790 SendMessage(hwndCombo, CB_RESETCONTENT, 0, 0);
\r
6792 while (*cd != NULL) {
\r
6793 SendMessage(hwndCombo, CB_ADDSTRING, 0, (LPARAM) *cd);
\r
6799 InitComboStringsFromOption(HANDLE hwndCombo, char *str)
\r
6801 char buf1[ARG_MAX];
\r
6804 if (str[0] == '@') {
\r
6805 FILE* f = fopen(str + 1, "r");
\r
6807 DisplayFatalError(str + 1, errno, 2);
\r
6810 len = fread(buf1, 1, sizeof(buf1)-1, f);
\r
6812 buf1[len] = NULLCHAR;
\r
6816 SendMessage(hwndCombo, CB_RESETCONTENT, 0, 0);
\r
6819 char buf[MSG_SIZ];
\r
6820 char *end = strchr(str, '\n');
\r
6821 if (end == NULL) return;
\r
6822 memcpy(buf, str, end - str);
\r
6823 buf[end - str] = NULLCHAR;
\r
6824 SendMessage(hwndCombo, CB_ADDSTRING, 0, (LPARAM) buf);
\r
6830 SetStartupDialogEnables(HWND hDlg)
\r
6832 EnableWindow(GetDlgItem(hDlg, OPT_ChessEngineName),
\r
6833 IsDlgButtonChecked(hDlg, OPT_ChessEngine) ||
\r
6834 (appData.zippyPlay && IsDlgButtonChecked(hDlg, OPT_ChessServer)));
\r
6835 EnableWindow(GetDlgItem(hDlg, OPT_SecondChessEngineName),
\r
6836 IsDlgButtonChecked(hDlg, OPT_ChessEngine));
\r
6837 EnableWindow(GetDlgItem(hDlg, OPT_ChessServerName),
\r
6838 IsDlgButtonChecked(hDlg, OPT_ChessServer));
\r
6839 EnableWindow(GetDlgItem(hDlg, OPT_AdditionalOptions),
\r
6840 IsDlgButtonChecked(hDlg, OPT_AnyAdditional));
\r
6841 EnableWindow(GetDlgItem(hDlg, IDOK),
\r
6842 IsDlgButtonChecked(hDlg, OPT_ChessEngine) ||
\r
6843 IsDlgButtonChecked(hDlg, OPT_ChessServer) ||
\r
6844 IsDlgButtonChecked(hDlg, OPT_View));
\r
6848 QuoteForFilename(char *filename)
\r
6850 int dquote, space;
\r
6851 dquote = strchr(filename, '"') != NULL;
\r
6852 space = strchr(filename, ' ') != NULL;
\r
6853 if (dquote || space) {
\r
6865 InitEngineBox(HWND hDlg, HWND hwndCombo, char* nthcp, char* nthd, char* nthdir, char *nthnames)
\r
6867 char buf[MSG_SIZ];
\r
6870 InitComboStringsFromOption(hwndCombo, nthnames);
\r
6871 q = QuoteForFilename(nthcp);
\r
6872 sprintf(buf, "%s%s%s", q, nthcp, q);
\r
6873 if (*nthdir != NULLCHAR) {
\r
6874 q = QuoteForFilename(nthdir);
\r
6875 sprintf(buf + strlen(buf), " /%s=%s%s%s", nthd, q, nthdir, q);
\r
6877 if (*nthcp == NULLCHAR) {
\r
6878 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) 0, (LPARAM) 0);
\r
6879 } else if (SendMessage(hwndCombo, CB_SELECTSTRING, (WPARAM) -1, (LPARAM) buf) == CB_ERR) {
\r
6880 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) -1, (LPARAM) 0);
\r
6881 SendMessage(hwndCombo, WM_SETTEXT, (WPARAM) 0, (LPARAM) buf);
\r
6886 StartupDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
6888 char buf[MSG_SIZ];
\r
6892 switch (message) {
\r
6893 case WM_INITDIALOG:
\r
6894 /* Center the dialog */
\r
6895 CenterWindow (hDlg, GetDesktopWindow());
\r
6896 /* Initialize the dialog items */
\r
6897 InitEngineBox(hDlg, GetDlgItem(hDlg, OPT_ChessEngineName),
\r
6898 appData.firstChessProgram, "fd", appData.firstDirectory,
\r
6899 firstChessProgramNames);
\r
6900 InitEngineBox(hDlg, GetDlgItem(hDlg, OPT_SecondChessEngineName),
\r
6901 appData.secondChessProgram, "sd", appData.secondDirectory,
\r
6902 secondChessProgramNames);
\r
6903 hwndCombo = GetDlgItem(hDlg, OPT_ChessServerName);
\r
6904 InitComboStringsFromOption(hwndCombo, icsNames);
\r
6905 sprintf(buf, "%s /icsport=%s", appData.icsHost, appData.icsPort);
\r
6906 if (*appData.icsHelper != NULLCHAR) {
\r
6907 char *q = QuoteForFilename(appData.icsHelper);
\r
6908 sprintf(buf + strlen(buf), " /icshelper=%s%s%s", q, appData.icsHelper, q);
\r
6910 if (*appData.icsHost == NULLCHAR) {
\r
6911 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) 0, (LPARAM) 0);
\r
6912 /*SendMessage(hwndCombo, CB_SHOWDROPDOWN, (WPARAM) TRUE, (LPARAM) 0); !!too soon */
\r
6913 } else if (SendMessage(hwndCombo, CB_SELECTSTRING, (WPARAM) -1, (LPARAM) buf) == CB_ERR) {
\r
6914 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) -1, (LPARAM) 0);
\r
6915 SendMessage(hwndCombo, WM_SETTEXT, (WPARAM) 0, (LPARAM) buf);
\r
6918 if (appData.icsActive) {
\r
6919 CheckDlgButton(hDlg, OPT_ChessServer, BST_CHECKED);
\r
6921 else if (appData.noChessProgram) {
\r
6922 CheckDlgButton(hDlg, OPT_View, BST_CHECKED);
\r
6925 CheckDlgButton(hDlg, OPT_ChessEngine, BST_CHECKED);
\r
6928 SetStartupDialogEnables(hDlg);
\r
6932 switch (LOWORD(wParam)) {
\r
6934 if (IsDlgButtonChecked(hDlg, OPT_ChessEngine)) {
\r
6935 strcpy(buf, "/fcp=");
\r
6936 GetDlgItemText(hDlg, OPT_ChessEngineName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
6938 ParseArgs(StringGet, &p);
\r
6939 strcpy(buf, "/scp=");
\r
6940 GetDlgItemText(hDlg, OPT_SecondChessEngineName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
6942 ParseArgs(StringGet, &p);
\r
6943 appData.noChessProgram = FALSE;
\r
6944 appData.icsActive = FALSE;
\r
6945 } else if (IsDlgButtonChecked(hDlg, OPT_ChessServer)) {
\r
6946 strcpy(buf, "/ics /icshost=");
\r
6947 GetDlgItemText(hDlg, OPT_ChessServerName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
6949 ParseArgs(StringGet, &p);
\r
6950 if (appData.zippyPlay) {
\r
6951 strcpy(buf, "/fcp=");
\r
6952 GetDlgItemText(hDlg, OPT_ChessEngineName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
6954 ParseArgs(StringGet, &p);
\r
6956 } else if (IsDlgButtonChecked(hDlg, OPT_View)) {
\r
6957 appData.noChessProgram = TRUE;
\r
6958 appData.icsActive = FALSE;
\r
6960 MessageBox(hDlg, "Choose an option, or cancel to exit",
\r
6961 "Option Error", MB_OK|MB_ICONEXCLAMATION);
\r
6964 if (IsDlgButtonChecked(hDlg, OPT_AnyAdditional)) {
\r
6965 GetDlgItemText(hDlg, OPT_AdditionalOptions, buf, sizeof(buf));
\r
6967 ParseArgs(StringGet, &p);
\r
6969 EndDialog(hDlg, TRUE);
\r
6976 case IDM_HELPCONTENTS:
\r
6977 if (!WinHelp (hDlg, "winboard.hlp", HELP_KEY,(DWORD)(LPSTR)"CONTENTS")) {
\r
6978 MessageBox (GetFocus(),
\r
6979 "Unable to activate help",
\r
6980 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
6985 SetStartupDialogEnables(hDlg);
\r
6993 /*---------------------------------------------------------------------------*\
\r
6995 * About box dialog functions
\r
6997 \*---------------------------------------------------------------------------*/
\r
6999 /* Process messages for "About" dialog box */
\r
7001 About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7003 switch (message) {
\r
7004 case WM_INITDIALOG: /* message: initialize dialog box */
\r
7005 /* Center the dialog over the application window */
\r
7006 CenterWindow (hDlg, GetWindow (hDlg, GW_OWNER));
\r
7007 SetDlgItemText(hDlg, ABOUTBOX_Version, programVersion);
\r
7010 case WM_COMMAND: /* message: received a command */
\r
7011 if (LOWORD(wParam) == IDOK /* "OK" box selected? */
\r
7012 || LOWORD(wParam) == IDCANCEL) { /* System menu close command? */
\r
7013 EndDialog(hDlg, TRUE); /* Exit the dialog */
\r
7021 /*---------------------------------------------------------------------------*\
\r
7023 * Comment Dialog functions
\r
7025 \*---------------------------------------------------------------------------*/
\r
7028 CommentDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7030 static HANDLE hwndText = NULL;
\r
7031 int len, newSizeX, newSizeY, flags;
\r
7032 static int sizeX, sizeY;
\r
7037 switch (message) {
\r
7038 case WM_INITDIALOG: /* message: initialize dialog box */
\r
7039 /* Initialize the dialog items */
\r
7040 hwndText = GetDlgItem(hDlg, OPT_CommentText);
\r
7041 SetDlgItemText(hDlg, OPT_CommentText, commentText);
\r
7042 EnableWindow(GetDlgItem(hDlg, OPT_CancelComment), editComment);
\r
7043 EnableWindow(GetDlgItem(hDlg, OPT_ClearComment), editComment);
\r
7044 EnableWindow(GetDlgItem(hDlg, OPT_EditComment), !editComment);
\r
7045 SendMessage(hwndText, EM_SETREADONLY, !editComment, 0);
\r
7046 SetWindowText(hDlg, commentTitle);
\r
7047 if (editComment) {
\r
7048 SetFocus(hwndText);
\r
7050 SetFocus(GetDlgItem(hDlg, IDOK));
\r
7052 SendMessage(GetDlgItem(hDlg, OPT_CommentText),
\r
7053 WM_SETFONT, (WPARAM)font[boardSize][COMMENT_FONT]->hf,
\r
7054 MAKELPARAM(FALSE, 0));
\r
7055 /* Size and position the dialog */
\r
7056 if (!commentDialog) {
\r
7057 commentDialog = hDlg;
\r
7058 flags = SWP_NOZORDER;
\r
7059 GetClientRect(hDlg, &rect);
\r
7060 sizeX = rect.right;
\r
7061 sizeY = rect.bottom;
\r
7062 if (commentX != CW_USEDEFAULT && commentY != CW_USEDEFAULT &&
\r
7063 commentW != CW_USEDEFAULT && commentH != CW_USEDEFAULT) {
\r
7064 WINDOWPLACEMENT wp;
\r
7065 EnsureOnScreen(&commentX, &commentY);
\r
7066 wp.length = sizeof(WINDOWPLACEMENT);
\r
7068 wp.showCmd = SW_SHOW;
\r
7069 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
7070 wp.rcNormalPosition.left = commentX;
\r
7071 wp.rcNormalPosition.right = commentX + commentW;
\r
7072 wp.rcNormalPosition.top = commentY;
\r
7073 wp.rcNormalPosition.bottom = commentY + commentH;
\r
7074 SetWindowPlacement(hDlg, &wp);
\r
7076 GetClientRect(hDlg, &rect);
\r
7077 newSizeX = rect.right;
\r
7078 newSizeY = rect.bottom;
\r
7079 ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY,
\r
7080 newSizeX, newSizeY);
\r
7087 case WM_COMMAND: /* message: received a command */
\r
7088 switch (LOWORD(wParam)) {
\r
7090 if (editComment) {
\r
7092 /* Read changed options from the dialog box */
\r
7093 hwndText = GetDlgItem(hDlg, OPT_CommentText);
\r
7094 len = GetWindowTextLength(hwndText);
\r
7095 str = (char *) malloc(len + 1);
\r
7096 GetWindowText(hwndText, str, len + 1);
\r
7105 ReplaceComment(commentIndex, str);
\r
7112 case OPT_CancelComment:
\r
7116 case OPT_ClearComment:
\r
7117 SetDlgItemText(hDlg, OPT_CommentText, "");
\r
7120 case OPT_EditComment:
\r
7121 EditCommentEvent();
\r
7130 newSizeX = LOWORD(lParam);
\r
7131 newSizeY = HIWORD(lParam);
\r
7132 ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY, newSizeX, newSizeY);
\r
7137 case WM_GETMINMAXINFO:
\r
7138 /* Prevent resizing window too small */
\r
7139 mmi = (MINMAXINFO *) lParam;
\r
7140 mmi->ptMinTrackSize.x = 100;
\r
7141 mmi->ptMinTrackSize.y = 100;
\r
7148 EitherCommentPopUp(int index, char *title, char *str, BOOLEAN edit)
\r
7153 CheckMenuItem(GetMenu(hwndMain), IDM_EditComment, edit ? MF_CHECKED : MF_UNCHECKED);
\r
7155 if (str == NULL) str = "";
\r
7156 p = (char *) malloc(2 * strlen(str) + 2);
\r
7159 if (*str == '\n') *q++ = '\r';
\r
7163 if (commentText != NULL) free(commentText);
\r
7165 commentIndex = index;
\r
7166 commentTitle = title;
\r
7168 editComment = edit;
\r
7170 if (commentDialog) {
\r
7171 SendMessage(commentDialog, WM_INITDIALOG, 0, 0);
\r
7172 if (!commentDialogUp) ShowWindow(commentDialog, SW_SHOW);
\r
7174 lpProc = MakeProcInstance((FARPROC)CommentDialog, hInst);
\r
7175 CreateDialog(hInst, MAKEINTRESOURCE(DLG_EditComment),
\r
7176 hwndMain, (DLGPROC)lpProc);
\r
7177 FreeProcInstance(lpProc);
\r
7179 commentDialogUp = TRUE;
\r
7183 /*---------------------------------------------------------------------------*\
\r
7185 * Type-in move dialog functions
\r
7187 \*---------------------------------------------------------------------------*/
\r
7190 TypeInMoveDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7192 char move[MSG_SIZ];
\r
7194 ChessMove moveType;
\r
7195 int fromX, fromY, toX, toY;
\r
7198 switch (message) {
\r
7199 case WM_INITDIALOG:
\r
7200 move[0] = (char) lParam;
\r
7201 move[1] = NULLCHAR;
\r
7202 CenterWindowEx(hDlg, GetWindow(hDlg, GW_OWNER), 1 );
\r
7203 hInput = GetDlgItem(hDlg, OPT_Move);
\r
7204 SetWindowText(hInput, move);
\r
7206 SendMessage(hInput, EM_SETSEL, (WPARAM)9999, (LPARAM)9999);
\r
7210 switch (LOWORD(wParam)) {
\r
7212 if (gameMode != EditGame && currentMove != forwardMostMove &&
\r
7213 gameMode != Training) {
\r
7214 DisplayMoveError("Displayed move is not current");
\r
7216 GetDlgItemText(hDlg, OPT_Move, move, sizeof(move));
\r
7217 if (ParseOneMove(move, gameMode == EditPosition ? blackPlaysFirst : currentMove,
\r
7218 &moveType, &fromX, &fromY, &toX, &toY, &promoChar)) {
\r
7219 if (gameMode != Training)
\r
7220 forwardMostMove = currentMove;
\r
7221 UserMoveEvent(fromX, fromY, toX, toY, promoChar);
\r
7223 DisplayMoveError("Could not parse move");
\r
7226 EndDialog(hDlg, TRUE);
\r
7229 EndDialog(hDlg, FALSE);
\r
7240 PopUpMoveDialog(char firstchar)
\r
7244 if ((gameMode == BeginningOfGame && !appData.icsActive) ||
\r
7245 gameMode == MachinePlaysWhite || gameMode == MachinePlaysBlack ||
\r
7246 gameMode == AnalyzeMode || gameMode == EditGame ||
\r
7247 gameMode == EditPosition || gameMode == IcsExamining ||
\r
7248 gameMode == IcsPlayingWhite || gameMode == IcsPlayingBlack ||
\r
7249 gameMode == Training) {
\r
7250 lpProc = MakeProcInstance((FARPROC)TypeInMoveDialog, hInst);
\r
7251 DialogBoxParam(hInst, MAKEINTRESOURCE(DLG_TypeInMove),
\r
7252 hwndMain, (DLGPROC)lpProc, (LPARAM)firstchar);
\r
7253 FreeProcInstance(lpProc);
\r
7257 /*---------------------------------------------------------------------------*\
\r
7259 * Type-in name dialog functions
\r
7261 \*---------------------------------------------------------------------------*/
\r
7264 TypeInNameDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7266 char move[MSG_SIZ];
\r
7269 switch (message) {
\r
7270 case WM_INITDIALOG:
\r
7271 move[0] = (char) lParam;
\r
7272 move[1] = NULLCHAR;
\r
7273 CenterWindowEx(hDlg, GetWindow(hDlg, GW_OWNER), 1 );
\r
7274 hInput = GetDlgItem(hDlg, OPT_Name);
\r
7275 SetWindowText(hInput, move);
\r
7277 SendMessage(hInput, EM_SETSEL, (WPARAM)9999, (LPARAM)9999);
\r
7281 switch (LOWORD(wParam)) {
\r
7283 GetDlgItemText(hDlg, OPT_Name, move, sizeof(move));
\r
7284 appData.userName = strdup(move);
\r
7286 EndDialog(hDlg, TRUE);
\r
7289 EndDialog(hDlg, FALSE);
\r
7300 PopUpNameDialog(char firstchar)
\r
7304 lpProc = MakeProcInstance((FARPROC)TypeInNameDialog, hInst);
\r
7305 DialogBoxParam(hInst, MAKEINTRESOURCE(DLG_TypeInName),
\r
7306 hwndMain, (DLGPROC)lpProc, (LPARAM)firstchar);
\r
7307 FreeProcInstance(lpProc);
\r
7310 /*---------------------------------------------------------------------------*\
\r
7314 \*---------------------------------------------------------------------------*/
\r
7316 /* Nonmodal error box */
\r
7317 LRESULT CALLBACK ErrorDialog(HWND hDlg, UINT message,
\r
7318 WPARAM wParam, LPARAM lParam);
\r
7321 ErrorPopUp(char *title, char *content)
\r
7325 BOOLEAN modal = hwndMain == NULL;
\r
7343 strncpy(errorTitle, title, sizeof(errorTitle));
\r
7344 errorTitle[sizeof(errorTitle) - 1] = '\0';
\r
7347 MessageBox(NULL, errorMessage, errorTitle, MB_OK|MB_ICONEXCLAMATION);
\r
7349 lpProc = MakeProcInstance((FARPROC)ErrorDialog, hInst);
\r
7350 CreateDialog(hInst, MAKEINTRESOURCE(DLG_Error),
\r
7351 hwndMain, (DLGPROC)lpProc);
\r
7352 FreeProcInstance(lpProc);
\r
7359 if (!appData.popupMoveErrors && moveErrorMessageUp) DisplayMessage("", "");
\r
7360 if (errorDialog == NULL) return;
\r
7361 DestroyWindow(errorDialog);
\r
7362 errorDialog = NULL;
\r
7366 ErrorDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7371 switch (message) {
\r
7372 case WM_INITDIALOG:
\r
7373 GetWindowRect(hDlg, &rChild);
\r
7376 SetWindowPos(hDlg, NULL, rChild.left,
\r
7377 rChild.top + boardRect.top - (rChild.bottom - rChild.top),
\r
7378 0, 0, SWP_NOZORDER|SWP_NOSIZE);
\r
7382 [AS] It seems that the above code wants to move the dialog up in the "caption
\r
7383 area" of the main window, but it uses the dialog height as an hard-coded constant,
\r
7384 and it doesn't work when you resize the dialog.
\r
7385 For now, just give it a default position.
\r
7387 SetWindowPos(hDlg, NULL, boardRect.left+8, boardRect.top+8, 0, 0, SWP_NOZORDER|SWP_NOSIZE);
\r
7389 errorDialog = hDlg;
\r
7390 SetWindowText(hDlg, errorTitle);
\r
7391 hwndText = GetDlgItem(hDlg, OPT_ErrorText);
\r
7392 SetDlgItemText(hDlg, OPT_ErrorText, errorMessage);
\r
7396 switch (LOWORD(wParam)) {
\r
7399 if (errorDialog == hDlg) errorDialog = NULL;
\r
7400 DestroyWindow(hDlg);
\r
7412 HWND gothicDialog = NULL;
\r
7415 GothicDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7419 int height = GetSystemMetrics(SM_CYCAPTION)+GetSystemMetrics(SM_CYFRAME);
\r
7421 switch (message) {
\r
7422 case WM_INITDIALOG:
\r
7423 GetWindowRect(hDlg, &rChild);
\r
7425 SetWindowPos(hDlg, NULL, boardX, boardY-height, winWidth, height,
\r
7429 [AS] It seems that the above code wants to move the dialog up in the "caption
\r
7430 area" of the main window, but it uses the dialog height as an hard-coded constant,
\r
7431 and it doesn't work when you resize the dialog.
\r
7432 For now, just give it a default position.
\r
7434 gothicDialog = hDlg;
\r
7435 SetWindowText(hDlg, errorTitle);
\r
7436 hwndText = GetDlgItem(hDlg, OPT_ErrorText);
\r
7437 SetDlgItemText(hDlg, OPT_ErrorText, errorMessage);
\r
7441 switch (LOWORD(wParam)) {
\r
7444 if (errorDialog == hDlg) errorDialog = NULL;
\r
7445 DestroyWindow(hDlg);
\r
7457 GothicPopUp(char *title, VariantClass variant)
\r
7460 static char *lastTitle;
\r
7462 strncpy(errorTitle, title, sizeof(errorTitle));
\r
7463 errorTitle[sizeof(errorTitle) - 1] = '\0';
\r
7465 if(lastTitle != title && gothicDialog != NULL) {
\r
7466 DestroyWindow(gothicDialog);
\r
7467 gothicDialog = NULL;
\r
7469 if(variant != VariantNormal && gothicDialog == NULL) {
\r
7470 title = lastTitle;
\r
7471 lpProc = MakeProcInstance((FARPROC)GothicDialog, hInst);
\r
7472 CreateDialog(hInst, MAKEINTRESOURCE(DLG_Error),
\r
7473 hwndMain, (DLGPROC)lpProc);
\r
7474 FreeProcInstance(lpProc);
\r
7479 /*---------------------------------------------------------------------------*\
\r
7481 * Ics Interaction console functions
\r
7483 \*---------------------------------------------------------------------------*/
\r
7485 #define HISTORY_SIZE 64
\r
7486 static char *history[HISTORY_SIZE];
\r
7487 int histIn = 0, histP = 0;
\r
7490 SaveInHistory(char *cmd)
\r
7492 if (history[histIn] != NULL) {
\r
7493 free(history[histIn]);
\r
7494 history[histIn] = NULL;
\r
7496 if (*cmd == NULLCHAR) return;
\r
7497 history[histIn] = StrSave(cmd);
\r
7498 histIn = (histIn + 1) % HISTORY_SIZE;
\r
7499 if (history[histIn] != NULL) {
\r
7500 free(history[histIn]);
\r
7501 history[histIn] = NULL;
\r
7507 PrevInHistory(char *cmd)
\r
7510 if (histP == histIn) {
\r
7511 if (history[histIn] != NULL) free(history[histIn]);
\r
7512 history[histIn] = StrSave(cmd);
\r
7514 newhp = (histP - 1 + HISTORY_SIZE) % HISTORY_SIZE;
\r
7515 if (newhp == histIn || history[newhp] == NULL) return NULL;
\r
7517 return history[histP];
\r
7523 if (histP == histIn) return NULL;
\r
7524 histP = (histP + 1) % HISTORY_SIZE;
\r
7525 return history[histP];
\r
7532 BOOLEAN immediate;
\r
7533 } IcsTextMenuEntry;
\r
7534 #define ICS_TEXT_MENU_SIZE (IDM_CommandXLast - IDM_CommandX + 1)
\r
7535 IcsTextMenuEntry icsTextMenuEntry[ICS_TEXT_MENU_SIZE];
\r
7538 ParseIcsTextMenu(char *icsTextMenuString)
\r
7541 IcsTextMenuEntry *e = icsTextMenuEntry;
\r
7542 char *p = icsTextMenuString;
\r
7543 while (e->item != NULL && e < icsTextMenuEntry + ICS_TEXT_MENU_SIZE) {
\r
7546 if (e->command != NULL) {
\r
7548 e->command = NULL;
\r
7552 e = icsTextMenuEntry;
\r
7553 while (*p && e < icsTextMenuEntry + ICS_TEXT_MENU_SIZE) {
\r
7554 if (*p == ';' || *p == '\n') {
\r
7555 e->item = strdup("-");
\r
7556 e->command = NULL;
\r
7558 } else if (*p == '-') {
\r
7559 e->item = strdup("-");
\r
7560 e->command = NULL;
\r
7564 char *q, *r, *s, *t;
\r
7566 q = strchr(p, ',');
\r
7567 if (q == NULL) break;
\r
7569 r = strchr(q + 1, ',');
\r
7570 if (r == NULL) break;
\r
7572 s = strchr(r + 1, ',');
\r
7573 if (s == NULL) break;
\r
7576 t = strchr(s + 1, c);
\r
7579 t = strchr(s + 1, c);
\r
7581 if (t != NULL) *t = NULLCHAR;
\r
7582 e->item = strdup(p);
\r
7583 e->command = strdup(q + 1);
\r
7584 e->getname = *(r + 1) != '0';
\r
7585 e->immediate = *(s + 1) != '0';
\r
7589 if (t == NULL) break;
\r
7598 LoadIcsTextMenu(IcsTextMenuEntry *e)
\r
7602 hmenu = LoadMenu(hInst, "TextMenu");
\r
7603 h = GetSubMenu(hmenu, 0);
\r
7605 if (strcmp(e->item, "-") == 0) {
\r
7606 AppendMenu(h, MF_SEPARATOR, 0, 0);
\r
7608 if (e->item[0] == '|') {
\r
7609 AppendMenu(h, MF_STRING|MF_MENUBARBREAK,
\r
7610 IDM_CommandX + i, &e->item[1]);
\r
7612 AppendMenu(h, MF_STRING, IDM_CommandX + i, e->item);
\r
7621 WNDPROC consoleTextWindowProc;
\r
7624 CommandX(HWND hwnd, char *command, BOOLEAN getname, BOOLEAN immediate)
\r
7626 char buf[MSG_SIZ], name[MSG_SIZ];
\r
7627 HWND hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
7631 SetWindowText(hInput, command);
\r
7633 SendMessage(hInput, WM_CHAR, '\r', 0);
\r
7635 sel.cpMin = 999999;
\r
7636 sel.cpMax = 999999;
\r
7637 SendMessage(hInput, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7642 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
7643 if (sel.cpMin == sel.cpMax) {
\r
7644 /* Expand to surrounding word */
\r
7647 tr.chrg.cpMax = sel.cpMin;
\r
7648 tr.chrg.cpMin = --sel.cpMin;
\r
7649 if (sel.cpMin < 0) break;
\r
7650 tr.lpstrText = name;
\r
7651 SendMessage(hwnd, EM_GETTEXTRANGE, 0, (LPARAM) &tr);
\r
7652 } while (isalpha(name[0]) || isdigit(name[0]) || name[0] == '-');
\r
7656 tr.chrg.cpMin = sel.cpMax;
\r
7657 tr.chrg.cpMax = ++sel.cpMax;
\r
7658 tr.lpstrText = name;
\r
7659 if (SendMessage(hwnd, EM_GETTEXTRANGE, 0, (LPARAM) &tr) < 1) break;
\r
7660 } while (isalpha(name[0]) || isdigit(name[0]) || name[0] == '-');
\r
7663 if (sel.cpMax == sel.cpMin || sel.cpMax - sel.cpMin > MSG_SIZ/2) {
\r
7664 MessageBeep(MB_ICONEXCLAMATION);
\r
7668 tr.lpstrText = name;
\r
7669 SendMessage(hwnd, EM_GETTEXTRANGE, 0, (LPARAM) &tr);
\r
7671 if (sel.cpMax - sel.cpMin > MSG_SIZ/2) {
\r
7672 MessageBeep(MB_ICONEXCLAMATION);
\r
7675 SendMessage(hwnd, EM_GETSELTEXT, 0, (LPARAM) name);
\r
7678 sprintf(buf, "%s %s", command, name);
\r
7679 SetWindowText(hInput, buf);
\r
7680 SendMessage(hInput, WM_CHAR, '\r', 0);
\r
7682 sprintf(buf, "%s %s ", command, name); /* trailing space */
\r
7683 SetWindowText(hInput, buf);
\r
7684 sel.cpMin = 999999;
\r
7685 sel.cpMax = 999999;
\r
7686 SendMessage(hInput, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7692 ConsoleTextSubclass(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
7697 switch (message) {
\r
7699 if (!(GetKeyState(VK_CONTROL) & ~1)) break;
\r
7702 SendMessage(hwnd, EM_LINESCROLL, 0, -999999);
\r
7705 sel.cpMin = 999999;
\r
7706 sel.cpMax = 999999;
\r
7707 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7708 SendMessage(hwnd, EM_SCROLLCARET, 0, 0);
\r
7713 if (wParam == '\t') {
\r
7714 if (GetKeyState(VK_SHIFT) < 0) {
\r
7716 if (IsIconic(hwndMain)) ShowWindow(hwndMain, SW_RESTORE);
\r
7717 if (buttonDesc[0].hwnd) {
\r
7718 SetFocus(buttonDesc[0].hwnd);
\r
7720 SetFocus(hwndMain);
\r
7724 SetFocus(GetDlgItem(hwndConsole, OPT_ConsoleInput));
\r
7727 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
7729 SendMessage(hInput, message, wParam, lParam);
\r
7733 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
7735 return SendMessage(hInput, message, wParam, lParam);
\r
7736 case WM_MBUTTONDOWN:
\r
7737 return SendMessage(hwnd, WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
7738 case WM_RBUTTONDOWN:
\r
7739 if (!(GetKeyState(VK_SHIFT) & ~1)) {
\r
7740 /* Move selection here if it was empty */
\r
7742 pt.x = LOWORD(lParam);
\r
7743 pt.y = HIWORD(lParam);
\r
7744 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
7745 if (sel.cpMin == sel.cpMax) {
\r
7746 sel.cpMin = SendMessage(hwnd, EM_CHARFROMPOS, 0, (LPARAM)&pt); /*doc is wrong*/
\r
7747 sel.cpMax = sel.cpMin;
\r
7748 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7750 SendMessage(hwnd, EM_HIDESELECTION, FALSE, FALSE);
\r
7753 case WM_RBUTTONUP:
\r
7754 if (GetKeyState(VK_SHIFT) & ~1) {
\r
7755 SendDlgItemMessage(hwndConsole, OPT_ConsoleText,
\r
7756 WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
7759 HMENU hmenu = LoadIcsTextMenu(icsTextMenuEntry);
\r
7760 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
7761 if (sel.cpMin == sel.cpMax) {
\r
7762 EnableMenuItem(hmenu, IDM_Copy, MF_BYCOMMAND|MF_GRAYED);
\r
7763 EnableMenuItem(hmenu, IDM_QuickPaste, MF_BYCOMMAND|MF_GRAYED);
\r
7765 if (!IsClipboardFormatAvailable(CF_TEXT)) {
\r
7766 EnableMenuItem(hmenu, IDM_Paste, MF_BYCOMMAND|MF_GRAYED);
\r
7768 pt.x = LOWORD(lParam);
\r
7769 pt.y = HIWORD(lParam);
\r
7770 MenuPopup(hwnd, pt, hmenu, -1);
\r
7774 switch (LOWORD(wParam)) {
\r
7775 case IDM_QuickPaste:
\r
7777 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
7778 if (sel.cpMin == sel.cpMax) {
\r
7779 MessageBeep(MB_ICONEXCLAMATION);
\r
7782 SendMessage(hwnd, WM_COPY, 0, 0);
\r
7783 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
7784 SendMessage(hInput, WM_PASTE, 0, 0);
\r
7789 SendMessage(hwnd, WM_CUT, 0, 0);
\r
7792 SendMessage(hwnd, WM_PASTE, 0, 0);
\r
7795 SendMessage(hwnd, WM_COPY, 0, 0);
\r
7799 int i = LOWORD(wParam) - IDM_CommandX;
\r
7800 if (i >= 0 && i < ICS_TEXT_MENU_SIZE &&
\r
7801 icsTextMenuEntry[i].command != NULL) {
\r
7802 CommandX(hwnd, icsTextMenuEntry[i].command,
\r
7803 icsTextMenuEntry[i].getname,
\r
7804 icsTextMenuEntry[i].immediate);
\r
7812 return (*consoleTextWindowProc)(hwnd, message, wParam, lParam);
\r
7815 WNDPROC consoleInputWindowProc;
\r
7818 ConsoleInputSubclass(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
7820 char buf[MSG_SIZ];
\r
7822 static BOOL sendNextChar = FALSE;
\r
7823 static BOOL quoteNextChar = FALSE;
\r
7824 InputSource *is = consoleInputSource;
\r
7828 switch (message) {
\r
7830 if (!appData.localLineEditing || sendNextChar) {
\r
7831 is->buf[0] = (CHAR) wParam;
\r
7833 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
7834 sendNextChar = FALSE;
\r
7837 if (quoteNextChar) {
\r
7838 buf[0] = (char) wParam;
\r
7839 buf[1] = NULLCHAR;
\r
7840 SendMessage(hwnd, EM_REPLACESEL, TRUE, (LPARAM) buf);
\r
7841 quoteNextChar = FALSE;
\r
7845 case '\r': /* Enter key */
\r
7846 is->count = GetWindowText(hwnd, is->buf, INPUT_SOURCE_BUF_SIZE-1);
\r
7847 if (consoleEcho) SaveInHistory(is->buf);
\r
7848 is->buf[is->count++] = '\n';
\r
7849 is->buf[is->count] = NULLCHAR;
\r
7850 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
7851 if (consoleEcho) {
\r
7852 ConsoleOutput(is->buf, is->count, TRUE);
\r
7853 } else if (appData.localLineEditing) {
\r
7854 ConsoleOutput("\n", 1, TRUE);
\r
7857 case '\033': /* Escape key */
\r
7858 SetWindowText(hwnd, "");
\r
7859 cf.cbSize = sizeof(CHARFORMAT);
\r
7860 cf.dwMask = CFM_COLOR|CFM_BOLD|CFM_ITALIC|CFM_UNDERLINE|CFM_STRIKEOUT;
\r
7861 if (consoleEcho) {
\r
7862 cf.crTextColor = textAttribs[ColorNormal].color;
\r
7864 cf.crTextColor = COLOR_ECHOOFF;
\r
7866 cf.dwEffects = textAttribs[ColorNormal].effects;
\r
7867 SendMessage(hwnd, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&cf);
\r
7869 case '\t': /* Tab key */
\r
7870 if (GetKeyState(VK_SHIFT) < 0) {
\r
7872 SetFocus(GetDlgItem(hwndConsole, OPT_ConsoleText));
\r
7875 if (IsIconic(hwndMain)) ShowWindow(hwndMain, SW_RESTORE);
\r
7876 if (buttonDesc[0].hwnd) {
\r
7877 SetFocus(buttonDesc[0].hwnd);
\r
7879 SetFocus(hwndMain);
\r
7883 case '\023': /* Ctrl+S */
\r
7884 sendNextChar = TRUE;
\r
7886 case '\021': /* Ctrl+Q */
\r
7887 quoteNextChar = TRUE;
\r
7896 GetWindowText(hwnd, buf, MSG_SIZ);
\r
7897 p = PrevInHistory(buf);
\r
7899 SetWindowText(hwnd, p);
\r
7900 sel.cpMin = 999999;
\r
7901 sel.cpMax = 999999;
\r
7902 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7907 p = NextInHistory();
\r
7909 SetWindowText(hwnd, p);
\r
7910 sel.cpMin = 999999;
\r
7911 sel.cpMax = 999999;
\r
7912 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7918 if (!(GetKeyState(VK_CONTROL) & ~1)) break;
\r
7922 SendDlgItemMessage(hwndConsole, OPT_ConsoleText, message, wParam, lParam);
\r
7926 case WM_MBUTTONDOWN:
\r
7927 SendDlgItemMessage(hwndConsole, OPT_ConsoleText,
\r
7928 WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
7930 case WM_RBUTTONUP:
\r
7931 if (GetKeyState(VK_SHIFT) & ~1) {
\r
7932 SendDlgItemMessage(hwndConsole, OPT_ConsoleText,
\r
7933 WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
7937 hmenu = LoadMenu(hInst, "InputMenu");
\r
7938 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
7939 if (sel.cpMin == sel.cpMax) {
\r
7940 EnableMenuItem(hmenu, IDM_Copy, MF_BYCOMMAND|MF_GRAYED);
\r
7941 EnableMenuItem(hmenu, IDM_Cut, MF_BYCOMMAND|MF_GRAYED);
\r
7943 if (!IsClipboardFormatAvailable(CF_TEXT)) {
\r
7944 EnableMenuItem(hmenu, IDM_Paste, MF_BYCOMMAND|MF_GRAYED);
\r
7946 pt.x = LOWORD(lParam);
\r
7947 pt.y = HIWORD(lParam);
\r
7948 MenuPopup(hwnd, pt, hmenu, -1);
\r
7952 switch (LOWORD(wParam)) {
\r
7954 SendMessage(hwnd, EM_UNDO, 0, 0);
\r
7956 case IDM_SelectAll:
\r
7958 sel.cpMax = -1; /*999999?*/
\r
7959 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7962 SendMessage(hwnd, WM_CUT, 0, 0);
\r
7965 SendMessage(hwnd, WM_PASTE, 0, 0);
\r
7968 SendMessage(hwnd, WM_COPY, 0, 0);
\r
7973 return (*consoleInputWindowProc)(hwnd, message, wParam, lParam);
\r
7976 #define CO_MAX 100000
\r
7977 #define CO_TRIM 1000
\r
7980 ConsoleWndProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7982 static SnapData sd;
\r
7983 static HWND hText, hInput /*, hFocus*/;
\r
7984 // InputSource *is = consoleInputSource;
\r
7986 static int sizeX, sizeY;
\r
7987 int newSizeX, newSizeY;
\r
7990 switch (message) {
\r
7991 case WM_INITDIALOG: /* message: initialize dialog box */
\r
7992 hwndConsole = hDlg;
\r
7993 hText = GetDlgItem(hDlg, OPT_ConsoleText);
\r
7994 hInput = GetDlgItem(hDlg, OPT_ConsoleInput);
\r
7996 consoleTextWindowProc = (WNDPROC)
\r
7997 SetWindowLong(hText, GWL_WNDPROC, (LONG) ConsoleTextSubclass);
\r
7998 SendMessage(hText, EM_SETBKGNDCOLOR, FALSE, consoleBackgroundColor);
\r
7999 consoleInputWindowProc = (WNDPROC)
\r
8000 SetWindowLong(hInput, GWL_WNDPROC, (LONG) ConsoleInputSubclass);
\r
8001 SendMessage(hInput, EM_SETBKGNDCOLOR, FALSE, consoleBackgroundColor);
\r
8002 Colorize(ColorNormal, TRUE);
\r
8003 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM) &consoleCF);
\r
8004 ChangedConsoleFont();
\r
8005 GetClientRect(hDlg, &rect);
\r
8006 sizeX = rect.right;
\r
8007 sizeY = rect.bottom;
\r
8008 if (consoleX != CW_USEDEFAULT && consoleY != CW_USEDEFAULT &&
\r
8009 consoleW != CW_USEDEFAULT && consoleH != CW_USEDEFAULT) {
\r
8010 WINDOWPLACEMENT wp;
\r
8011 EnsureOnScreen(&consoleX, &consoleY);
\r
8012 wp.length = sizeof(WINDOWPLACEMENT);
\r
8014 wp.showCmd = SW_SHOW;
\r
8015 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
8016 wp.rcNormalPosition.left = consoleX;
\r
8017 wp.rcNormalPosition.right = consoleX + consoleW;
\r
8018 wp.rcNormalPosition.top = consoleY;
\r
8019 wp.rcNormalPosition.bottom = consoleY + consoleH;
\r
8020 SetWindowPlacement(hDlg, &wp);
\r
8023 // [HGM] Chessknight's change 2004-07-13
\r
8024 else { /* Determine Defaults */
\r
8025 WINDOWPLACEMENT wp;
\r
8026 consoleX = winWidth + 1;
\r
8027 consoleY = boardY;
\r
8028 consoleW = screenWidth - winWidth;
\r
8029 consoleH = winHeight;
\r
8030 EnsureOnScreen(&consoleX, &consoleY);
\r
8031 wp.length = sizeof(WINDOWPLACEMENT);
\r
8033 wp.showCmd = SW_SHOW;
\r
8034 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
8035 wp.rcNormalPosition.left = consoleX;
\r
8036 wp.rcNormalPosition.right = consoleX + consoleW;
\r
8037 wp.rcNormalPosition.top = consoleY;
\r
8038 wp.rcNormalPosition.bottom = consoleY + consoleH;
\r
8039 SetWindowPlacement(hDlg, &wp);
\r
8054 if (IsIconic(hDlg)) break;
\r
8055 newSizeX = LOWORD(lParam);
\r
8056 newSizeY = HIWORD(lParam);
\r
8057 if (sizeX != newSizeX || sizeY != newSizeY) {
\r
8058 RECT rectText, rectInput;
\r
8060 int newTextHeight, newTextWidth;
\r
8061 GetWindowRect(hText, &rectText);
\r
8062 newTextWidth = rectText.right - rectText.left + newSizeX - sizeX;
\r
8063 newTextHeight = rectText.bottom - rectText.top + newSizeY - sizeY;
\r
8064 if (newTextHeight < 0) {
\r
8065 newSizeY += -newTextHeight;
\r
8066 newTextHeight = 0;
\r
8068 SetWindowPos(hText, NULL, 0, 0,
\r
8069 newTextWidth, newTextHeight, SWP_NOZORDER|SWP_NOMOVE);
\r
8070 GetWindowRect(hInput, &rectInput); /* gives screen coords */
\r
8071 pt.x = rectInput.left;
\r
8072 pt.y = rectInput.top + newSizeY - sizeY;
\r
8073 ScreenToClient(hDlg, &pt);
\r
8074 SetWindowPos(hInput, NULL,
\r
8075 pt.x, pt.y, /* needs client coords */
\r
8076 rectInput.right - rectInput.left + newSizeX - sizeX,
\r
8077 rectInput.bottom - rectInput.top, SWP_NOZORDER);
\r
8083 case WM_GETMINMAXINFO:
\r
8084 /* Prevent resizing window too small */
\r
8085 mmi = (MINMAXINFO *) lParam;
\r
8086 mmi->ptMinTrackSize.x = 100;
\r
8087 mmi->ptMinTrackSize.y = 100;
\r
8090 /* [AS] Snapping */
\r
8091 case WM_ENTERSIZEMOVE:
\r
8092 return OnEnterSizeMove( &sd, hDlg, wParam, lParam );
\r
8095 return OnSizing( &sd, hDlg, wParam, lParam );
\r
8098 return OnMoving( &sd, hDlg, wParam, lParam );
\r
8100 case WM_EXITSIZEMOVE:
\r
8101 return OnExitSizeMove( &sd, hDlg, wParam, lParam );
\r
8104 return DefWindowProc(hDlg, message, wParam, lParam);
\r
8112 if (hwndConsole) return;
\r
8113 hCons = CreateDialog(hInst, szConsoleName, 0, NULL);
\r
8114 SendMessage(hCons, WM_INITDIALOG, 0, 0);
\r
8119 ConsoleOutput(char* data, int length, int forceVisible)
\r
8124 char buf[CO_MAX+1];
\r
8127 static int delayLF = 0;
\r
8128 CHARRANGE savesel, sel;
\r
8130 if (hwndConsole == NULL || length > CO_MAX-100 || length == 0) return;
\r
8138 while (length--) {
\r
8146 } else if (*p == '\007') {
\r
8147 MyPlaySound(&sounds[(int)SoundBell]);
\r
8154 hText = GetDlgItem(hwndConsole, OPT_ConsoleText);
\r
8155 SendMessage(hText, EM_HIDESELECTION, TRUE, FALSE);
\r
8156 /* Save current selection */
\r
8157 SendMessage(hText, EM_EXGETSEL, 0, (LPARAM)&savesel);
\r
8158 exlen = GetWindowTextLength(hText);
\r
8159 /* Find out whether current end of text is visible */
\r
8160 SendMessage(hText, EM_GETRECT, 0, (LPARAM) &rect);
\r
8161 SendMessage(hText, EM_POSFROMCHAR, (WPARAM) &pEnd, exlen);
\r
8162 /* Trim existing text if it's too long */
\r
8163 if (exlen + (q - buf) > CO_MAX) {
\r
8164 trim = (CO_TRIM > (q - buf)) ? CO_TRIM : (q - buf);
\r
8167 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
8168 SendMessage(hText, EM_REPLACESEL, 0, (LPARAM)"");
\r
8170 savesel.cpMin -= trim;
\r
8171 savesel.cpMax -= trim;
\r
8172 if (exlen < 0) exlen = 0;
\r
8173 if (savesel.cpMin < 0) savesel.cpMin = 0;
\r
8174 if (savesel.cpMax < savesel.cpMin) savesel.cpMax = savesel.cpMin;
\r
8176 /* Append the new text */
\r
8177 sel.cpMin = exlen;
\r
8178 sel.cpMax = exlen;
\r
8179 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
8180 SendMessage(hText, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&consoleCF);
\r
8181 SendMessage(hText, EM_REPLACESEL, 0, (LPARAM) buf);
\r
8182 if (forceVisible || exlen == 0 ||
\r
8183 (rect.left <= pEnd.x && pEnd.x < rect.right &&
\r
8184 rect.top <= pEnd.y && pEnd.y < rect.bottom)) {
\r
8185 /* Scroll to make new end of text visible if old end of text
\r
8186 was visible or new text is an echo of user typein */
\r
8187 sel.cpMin = 9999999;
\r
8188 sel.cpMax = 9999999;
\r
8189 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
8190 SendMessage(hText, EM_HIDESELECTION, FALSE, FALSE);
\r
8191 SendMessage(hText, EM_SCROLLCARET, 0, 0);
\r
8192 SendMessage(hText, EM_HIDESELECTION, TRUE, FALSE);
\r
8194 if (savesel.cpMax == exlen || forceVisible) {
\r
8195 /* Move insert point to new end of text if it was at the old
\r
8196 end of text or if the new text is an echo of user typein */
\r
8197 sel.cpMin = 9999999;
\r
8198 sel.cpMax = 9999999;
\r
8199 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
8201 /* Restore previous selection */
\r
8202 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&savesel);
\r
8204 SendMessage(hText, EM_HIDESELECTION, FALSE, FALSE);
\r
8211 DisplayHoldingsCount(HDC hdc, int x, int y, int rightAlign, int copyNumber)
\r
8215 COLORREF oldFg, oldBg;
\r
8219 if(copyNumber > 1) sprintf(buf, "%d", copyNumber); else buf[0] = 0;
\r
8221 oldFg = SetTextColor(hdc, RGB(255, 255, 255)); /* white */
\r
8222 oldBg = SetBkColor(hdc, RGB(0, 0, 0)); /* black */
\r
8223 oldFont = SelectObject(hdc, font[boardSize][CLOCK_FONT]->hf);
\r
8226 rect.right = x + squareSize;
\r
8228 rect.bottom = y + squareSize;
\r
8231 ExtTextOut(hdc, x + MESSAGE_LINE_LEFTMARGIN
\r
8232 + (rightAlign ? (squareSize*2)/3 : 0),
\r
8233 y, ETO_CLIPPED|ETO_OPAQUE,
\r
8234 &rect, str, strlen(str), NULL);
\r
8236 (void) SetTextColor(hdc, oldFg);
\r
8237 (void) SetBkColor(hdc, oldBg);
\r
8238 (void) SelectObject(hdc, oldFont);
\r
8242 DisplayAClock(HDC hdc, int timeRemaining, int highlight,
\r
8243 RECT *rect, char *color, char *flagFell)
\r
8247 COLORREF oldFg, oldBg;
\r
8250 if (appData.clockMode) {
\r
8252 sprintf(buf, "%c %s %s", color[0], TimeString(timeRemaining), flagFell);
\r
8254 sprintf(buf, "%s: %s %s", color, TimeString(timeRemaining), flagFell);
\r
8261 oldFg = SetTextColor(hdc, RGB(255, 255, 255)); /* white */
\r
8262 oldBg = SetBkColor(hdc, RGB(0, 0, 0)); /* black */
\r
8264 oldFg = SetTextColor(hdc, RGB(0, 0, 0)); /* black */
\r
8265 oldBg = SetBkColor(hdc, RGB(255, 255, 255)); /* white */
\r
8267 oldFont = SelectObject(hdc, font[boardSize][CLOCK_FONT]->hf);
\r
8269 ExtTextOut(hdc, rect->left + MESSAGE_LINE_LEFTMARGIN,
\r
8270 rect->top, ETO_CLIPPED|ETO_OPAQUE,
\r
8271 rect, str, strlen(str), NULL);
\r
8273 (void) SetTextColor(hdc, oldFg);
\r
8274 (void) SetBkColor(hdc, oldBg);
\r
8275 (void) SelectObject(hdc, oldFont);
\r
8280 DoReadFile(HANDLE hFile, char *buf, int count, DWORD *outCount,
\r
8286 if( count <= 0 ) {
\r
8287 if (appData.debugMode) {
\r
8288 fprintf( debugFP, "DoReadFile: trying to read past end of buffer, overflow = %d\n", count );
\r
8291 return ERROR_INVALID_USER_BUFFER;
\r
8294 ResetEvent(ovl->hEvent);
\r
8295 ovl->Offset = ovl->OffsetHigh = 0;
\r
8296 ok = ReadFile(hFile, buf, count, outCount, ovl);
\r
8300 err = GetLastError();
\r
8301 if (err == ERROR_IO_PENDING) {
\r
8302 ok = GetOverlappedResult(hFile, ovl, outCount, TRUE);
\r
8306 err = GetLastError();
\r
8313 DoWriteFile(HANDLE hFile, char *buf, int count, DWORD *outCount,
\r
8318 ResetEvent(ovl->hEvent);
\r
8319 ovl->Offset = ovl->OffsetHigh = 0;
\r
8320 ok = WriteFile(hFile, buf, count, outCount, ovl);
\r
8324 err = GetLastError();
\r
8325 if (err == ERROR_IO_PENDING) {
\r
8326 ok = GetOverlappedResult(hFile, ovl, outCount, TRUE);
\r
8330 err = GetLastError();
\r
8336 /* [AS] If input is line by line and a line exceed the buffer size, force an error */
\r
8337 void CheckForInputBufferFull( InputSource * is )
\r
8339 if( is->lineByLine && (is->next - is->buf) >= INPUT_SOURCE_BUF_SIZE ) {
\r
8340 /* Look for end of line */
\r
8341 char * p = is->buf;
\r
8343 while( p < is->next && *p != '\n' ) {
\r
8347 if( p >= is->next ) {
\r
8348 if (appData.debugMode) {
\r
8349 fprintf( debugFP, "Input line exceeded buffer size (source id=%lu)\n", is->id );
\r
8352 is->error = ERROR_BROKEN_PIPE; /* [AS] Just any non-successful code! */
\r
8353 is->count = (DWORD) -1;
\r
8354 is->next = is->buf;
\r
8360 InputThread(LPVOID arg)
\r
8365 is = (InputSource *) arg;
\r
8366 ovl.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
\r
8367 ovl.Internal = ovl.InternalHigh = ovl.Offset = ovl.OffsetHigh = 0;
\r
8368 while (is->hThread != NULL) {
\r
8369 is->error = DoReadFile(is->hFile, is->next,
\r
8370 INPUT_SOURCE_BUF_SIZE - (is->next - is->buf),
\r
8371 &is->count, &ovl);
\r
8372 if (is->error == NO_ERROR) {
\r
8373 is->next += is->count;
\r
8375 if (is->error == ERROR_BROKEN_PIPE) {
\r
8376 /* Correct for MS brain damage. EOF reading a pipe is not an error. */
\r
8379 is->count = (DWORD) -1;
\r
8380 /* [AS] The (is->count <= 0) check below is not useful for unsigned values! */
\r
8385 CheckForInputBufferFull( is );
\r
8387 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
8389 if( is->count == ((DWORD) -1) ) break; /* [AS] */
\r
8391 if (is->count <= 0) break; /* Quit on EOF or error */
\r
8394 CloseHandle(ovl.hEvent);
\r
8395 CloseHandle(is->hFile);
\r
8397 if (appData.debugMode) {
\r
8398 fprintf( debugFP, "Input thread terminated (id=%lu, error=%d, count=%ld)\n", is->id, is->error, is->count );
\r
8405 /* Windows 95 beta 2 won't let you do overlapped i/o on a console or pipe */
\r
8407 NonOvlInputThread(LPVOID arg)
\r
8414 is = (InputSource *) arg;
\r
8415 while (is->hThread != NULL) {
\r
8416 is->error = ReadFile(is->hFile, is->next,
\r
8417 INPUT_SOURCE_BUF_SIZE - (is->next - is->buf),
\r
8418 &is->count, NULL) ? NO_ERROR : GetLastError();
\r
8419 if (is->error == NO_ERROR) {
\r
8420 /* Change CRLF to LF */
\r
8421 if (is->next > is->buf) {
\r
8423 i = is->count + 1;
\r
8431 if (prev == '\r' && *p == '\n') {
\r
8443 if (is->error == ERROR_BROKEN_PIPE) {
\r
8444 /* Correct for MS brain damage. EOF reading a pipe is not an error. */
\r
8447 is->count = (DWORD) -1;
\r
8451 CheckForInputBufferFull( is );
\r
8453 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
8455 if( is->count == ((DWORD) -1) ) break; /* [AS] */
\r
8457 if (is->count < 0) break; /* Quit on error */
\r
8459 CloseHandle(is->hFile);
\r
8464 SocketInputThread(LPVOID arg)
\r
8468 is = (InputSource *) arg;
\r
8469 while (is->hThread != NULL) {
\r
8470 is->count = recv(is->sock, is->buf, INPUT_SOURCE_BUF_SIZE, 0);
\r
8471 if ((int)is->count == SOCKET_ERROR) {
\r
8472 is->count = (DWORD) -1;
\r
8473 is->error = WSAGetLastError();
\r
8475 is->error = NO_ERROR;
\r
8476 is->next += is->count;
\r
8477 if (is->count == 0 && is->second == is) {
\r
8478 /* End of file on stderr; quit with no message */
\r
8482 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
8484 if( is->count == ((DWORD) -1) ) break; /* [AS] */
\r
8486 if (is->count <= 0) break; /* Quit on EOF or error */
\r
8492 InputEvent(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
8496 is = (InputSource *) lParam;
\r
8497 if (is->lineByLine) {
\r
8498 /* Feed in lines one by one */
\r
8499 char *p = is->buf;
\r
8501 while (q < is->next) {
\r
8502 if (*q++ == '\n') {
\r
8503 (is->func)(is, is->closure, p, q - p, NO_ERROR);
\r
8508 /* Move any partial line to the start of the buffer */
\r
8510 while (p < is->next) {
\r
8515 if (is->error != NO_ERROR || is->count == 0) {
\r
8516 /* Notify backend of the error. Note: If there was a partial
\r
8517 line at the end, it is not flushed through. */
\r
8518 (is->func)(is, is->closure, is->buf, is->count, is->error);
\r
8521 /* Feed in the whole chunk of input at once */
\r
8522 (is->func)(is, is->closure, is->buf, is->count, is->error);
\r
8523 is->next = is->buf;
\r
8527 /*---------------------------------------------------------------------------*\
\r
8529 * Menu enables. Used when setting various modes.
\r
8531 \*---------------------------------------------------------------------------*/
\r
8539 SetMenuEnables(HMENU hmenu, Enables *enab)
\r
8541 while (enab->item > 0) {
\r
8542 (void) EnableMenuItem(hmenu, enab->item, enab->flags);
\r
8547 Enables gnuEnables[] = {
\r
8548 { IDM_MailMove, MF_BYCOMMAND|MF_GRAYED },
\r
8549 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_GRAYED },
\r
8550 { IDM_IcsClient, MF_BYCOMMAND|MF_GRAYED },
\r
8551 { IDM_Accept, MF_BYCOMMAND|MF_GRAYED },
\r
8552 { IDM_Decline, MF_BYCOMMAND|MF_GRAYED },
\r
8553 { IDM_Rematch, MF_BYCOMMAND|MF_GRAYED },
\r
8554 { IDM_Adjourn, MF_BYCOMMAND|MF_GRAYED },
\r
8555 { IDM_StopExamining, MF_BYCOMMAND|MF_GRAYED },
\r
8556 { IDM_StopObserving, MF_BYCOMMAND|MF_GRAYED },
\r
8557 { IDM_Revert, MF_BYCOMMAND|MF_GRAYED },
\r
8561 Enables icsEnables[] = {
\r
8562 { IDM_MailMove, MF_BYCOMMAND|MF_GRAYED },
\r
8563 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_GRAYED },
\r
8564 { IDM_MachineWhite, MF_BYCOMMAND|MF_GRAYED },
\r
8565 { IDM_MachineBlack, MF_BYCOMMAND|MF_GRAYED },
\r
8566 { IDM_TwoMachines, MF_BYCOMMAND|MF_GRAYED },
\r
8567 { IDM_AnalysisMode, MF_BYCOMMAND|MF_ENABLED },
\r
8568 { IDM_AnalyzeFile, MF_BYCOMMAND|MF_GRAYED },
\r
8569 { IDM_TimeControl, MF_BYCOMMAND|MF_GRAYED },
\r
8570 { IDM_MoveNow, MF_BYCOMMAND|MF_GRAYED },
\r
8571 { IDM_Hint, MF_BYCOMMAND|MF_GRAYED },
\r
8572 { IDM_Book, MF_BYCOMMAND|MF_GRAYED },
\r
8573 { IDM_IcsOptions, MF_BYCOMMAND|MF_ENABLED },
\r
8578 Enables zippyEnables[] = {
\r
8579 { IDM_MoveNow, MF_BYCOMMAND|MF_ENABLED },
\r
8580 { IDM_Hint, MF_BYCOMMAND|MF_ENABLED },
\r
8581 { IDM_Book, MF_BYCOMMAND|MF_ENABLED },
\r
8586 Enables ncpEnables[] = {
\r
8587 { IDM_MailMove, MF_BYCOMMAND|MF_GRAYED },
\r
8588 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_GRAYED },
\r
8589 { IDM_MachineWhite, MF_BYCOMMAND|MF_GRAYED },
\r
8590 { IDM_MachineBlack, MF_BYCOMMAND|MF_GRAYED },
\r
8591 { IDM_TwoMachines, MF_BYCOMMAND|MF_GRAYED },
\r
8592 { IDM_AnalysisMode, MF_BYCOMMAND|MF_GRAYED },
\r
8593 { IDM_AnalyzeFile, MF_BYCOMMAND|MF_GRAYED },
\r
8594 { IDM_IcsClient, MF_BYCOMMAND|MF_GRAYED },
\r
8595 { ACTION_POS, MF_BYPOSITION|MF_GRAYED },
\r
8596 { IDM_Revert, MF_BYCOMMAND|MF_GRAYED },
\r
8597 { IDM_MoveNow, MF_BYCOMMAND|MF_GRAYED },
\r
8598 { IDM_RetractMove, MF_BYCOMMAND|MF_GRAYED },
\r
8599 { IDM_TimeControl, MF_BYCOMMAND|MF_GRAYED },
\r
8600 { IDM_Hint, MF_BYCOMMAND|MF_GRAYED },
\r
8601 { IDM_Book, MF_BYCOMMAND|MF_GRAYED },
\r
8605 Enables trainingOnEnables[] = {
\r
8606 { IDM_EditComment, MF_BYCOMMAND|MF_GRAYED },
\r
8607 { IDM_Pause, MF_BYCOMMAND|MF_GRAYED },
\r
8608 { IDM_Forward, MF_BYCOMMAND|MF_GRAYED },
\r
8609 { IDM_Backward, MF_BYCOMMAND|MF_GRAYED },
\r
8610 { IDM_ToEnd, MF_BYCOMMAND|MF_GRAYED },
\r
8611 { IDM_ToStart, MF_BYCOMMAND|MF_GRAYED },
\r
8612 { IDM_MoveNow, MF_BYCOMMAND|MF_GRAYED },
\r
8613 { IDM_TruncateGame, MF_BYCOMMAND|MF_GRAYED },
\r
8617 Enables trainingOffEnables[] = {
\r
8618 { IDM_EditComment, MF_BYCOMMAND|MF_ENABLED },
\r
8619 { IDM_Pause, MF_BYCOMMAND|MF_ENABLED },
\r
8620 { IDM_Forward, MF_BYCOMMAND|MF_ENABLED },
\r
8621 { IDM_Backward, MF_BYCOMMAND|MF_ENABLED },
\r
8622 { IDM_ToEnd, MF_BYCOMMAND|MF_ENABLED },
\r
8623 { IDM_ToStart, MF_BYCOMMAND|MF_ENABLED },
\r
8624 { IDM_MoveNow, MF_BYCOMMAND|MF_ENABLED },
\r
8625 { IDM_TruncateGame, MF_BYCOMMAND|MF_ENABLED },
\r
8629 /* These modify either ncpEnables or gnuEnables */
\r
8630 Enables cmailEnables[] = {
\r
8631 { IDM_MailMove, MF_BYCOMMAND|MF_ENABLED },
\r
8632 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_ENABLED },
\r
8633 { ACTION_POS, MF_BYPOSITION|MF_ENABLED },
\r
8634 { IDM_CallFlag, MF_BYCOMMAND|MF_GRAYED },
\r
8635 { IDM_Draw, MF_BYCOMMAND|MF_ENABLED },
\r
8636 { IDM_Adjourn, MF_BYCOMMAND|MF_GRAYED },
\r
8637 { IDM_Abort, MF_BYCOMMAND|MF_GRAYED },
\r
8641 Enables machineThinkingEnables[] = {
\r
8642 { IDM_LoadGame, MF_BYCOMMAND|MF_GRAYED },
\r
8643 { IDM_LoadNextGame, MF_BYCOMMAND|MF_GRAYED },
\r
8644 { IDM_LoadPrevGame, MF_BYCOMMAND|MF_GRAYED },
\r
8645 { IDM_ReloadGame, MF_BYCOMMAND|MF_GRAYED },
\r
8646 { IDM_PasteGame, MF_BYCOMMAND|MF_GRAYED },
\r
8647 { IDM_LoadPosition, MF_BYCOMMAND|MF_GRAYED },
\r
8648 { IDM_LoadNextPosition, MF_BYCOMMAND|MF_GRAYED },
\r
8649 { IDM_LoadPrevPosition, MF_BYCOMMAND|MF_GRAYED },
\r
8650 { IDM_ReloadPosition, MF_BYCOMMAND|MF_GRAYED },
\r
8651 { IDM_PastePosition, MF_BYCOMMAND|MF_GRAYED },
\r
8652 { IDM_MachineWhite, MF_BYCOMMAND|MF_GRAYED },
\r
8653 { IDM_MachineBlack, MF_BYCOMMAND|MF_GRAYED },
\r
8654 { IDM_TwoMachines, MF_BYCOMMAND|MF_GRAYED },
\r
8655 { IDM_TypeInMove, MF_BYCOMMAND|MF_GRAYED },
\r
8656 { IDM_RetractMove, MF_BYCOMMAND|MF_GRAYED },
\r
8660 Enables userThinkingEnables[] = {
\r
8661 { IDM_LoadGame, MF_BYCOMMAND|MF_ENABLED },
\r
8662 { IDM_LoadNextGame, MF_BYCOMMAND|MF_ENABLED },
\r
8663 { IDM_LoadPrevGame, MF_BYCOMMAND|MF_ENABLED },
\r
8664 { IDM_ReloadGame, MF_BYCOMMAND|MF_ENABLED },
\r
8665 { IDM_PasteGame, MF_BYCOMMAND|MF_ENABLED },
\r
8666 { IDM_LoadPosition, MF_BYCOMMAND|MF_ENABLED },
\r
8667 { IDM_LoadNextPosition, MF_BYCOMMAND|MF_ENABLED },
\r
8668 { IDM_LoadPrevPosition, MF_BYCOMMAND|MF_ENABLED },
\r
8669 { IDM_ReloadPosition, MF_BYCOMMAND|MF_ENABLED },
\r
8670 { IDM_PastePosition, MF_BYCOMMAND|MF_ENABLED },
\r
8671 { IDM_MachineWhite, MF_BYCOMMAND|MF_ENABLED },
\r
8672 { IDM_MachineBlack, MF_BYCOMMAND|MF_ENABLED },
\r
8673 { IDM_TwoMachines, MF_BYCOMMAND|MF_ENABLED },
\r
8674 { IDM_TypeInMove, MF_BYCOMMAND|MF_ENABLED },
\r
8675 { IDM_RetractMove, MF_BYCOMMAND|MF_ENABLED },
\r
8679 /*---------------------------------------------------------------------------*\
\r
8681 * Front-end interface functions exported by XBoard.
\r
8682 * Functions appear in same order as prototypes in frontend.h.
\r
8684 \*---------------------------------------------------------------------------*/
\r
8688 static UINT prevChecked = 0;
\r
8689 static int prevPausing = 0;
\r
8692 if (pausing != prevPausing) {
\r
8693 prevPausing = pausing;
\r
8694 (void) CheckMenuItem(GetMenu(hwndMain), IDM_Pause,
\r
8695 MF_BYCOMMAND|(pausing ? MF_CHECKED : MF_UNCHECKED));
\r
8696 if (hwndPause) SetWindowText(hwndPause, pausing ? "C" : "P");
\r
8699 switch (gameMode) {
\r
8700 case BeginningOfGame:
\r
8701 if (appData.icsActive)
\r
8702 nowChecked = IDM_IcsClient;
\r
8703 else if (appData.noChessProgram)
\r
8704 nowChecked = IDM_EditGame;
\r
8706 nowChecked = IDM_MachineBlack;
\r
8708 case MachinePlaysBlack:
\r
8709 nowChecked = IDM_MachineBlack;
\r
8711 case MachinePlaysWhite:
\r
8712 nowChecked = IDM_MachineWhite;
\r
8714 case TwoMachinesPlay:
\r
8715 nowChecked = IDM_TwoMachines;
\r
8718 nowChecked = IDM_AnalysisMode;
\r
8721 nowChecked = IDM_AnalyzeFile;
\r
8724 nowChecked = IDM_EditGame;
\r
8726 case PlayFromGameFile:
\r
8727 nowChecked = IDM_LoadGame;
\r
8729 case EditPosition:
\r
8730 nowChecked = IDM_EditPosition;
\r
8733 nowChecked = IDM_Training;
\r
8735 case IcsPlayingWhite:
\r
8736 case IcsPlayingBlack:
\r
8737 case IcsObserving:
\r
8739 nowChecked = IDM_IcsClient;
\r
8746 if (prevChecked != 0)
\r
8747 (void) CheckMenuItem(GetMenu(hwndMain),
\r
8748 prevChecked, MF_BYCOMMAND|MF_UNCHECKED);
\r
8749 if (nowChecked != 0)
\r
8750 (void) CheckMenuItem(GetMenu(hwndMain),
\r
8751 nowChecked, MF_BYCOMMAND|MF_CHECKED);
\r
8753 if (nowChecked == IDM_LoadGame || nowChecked == IDM_Training) {
\r
8754 (void) EnableMenuItem(GetMenu(hwndMain), IDM_Training,
\r
8755 MF_BYCOMMAND|MF_ENABLED);
\r
8757 (void) EnableMenuItem(GetMenu(hwndMain),
\r
8758 IDM_Training, MF_BYCOMMAND|MF_GRAYED);
\r
8761 prevChecked = nowChecked;
\r
8763 /* [DM] icsEngineAnalyze - Do a sceure check too */
\r
8764 if (appData.icsActive) {
\r
8765 if (appData.icsEngineAnalyze) {
\r
8766 (void) CheckMenuItem(GetMenu(hwndMain), IDM_AnalysisMode,
\r
8767 MF_BYCOMMAND|MF_CHECKED);
\r
8769 (void) CheckMenuItem(GetMenu(hwndMain), IDM_AnalysisMode,
\r
8770 MF_BYCOMMAND|MF_UNCHECKED);
\r
8778 HMENU hmenu = GetMenu(hwndMain);
\r
8779 SetMenuEnables(hmenu, icsEnables);
\r
8780 EnableMenuItem(GetSubMenu(hmenu, OPTIONS_POS), ICS_POS,
\r
8781 MF_BYPOSITION|MF_ENABLED);
\r
8783 if (appData.zippyPlay) {
\r
8784 SetMenuEnables(hmenu, zippyEnables);
\r
8785 if (!appData.noChessProgram) /* [DM] icsEngineAnalyze */
\r
8786 (void) EnableMenuItem(GetMenu(hwndMain), IDM_AnalysisMode,
\r
8787 MF_BYCOMMAND|MF_ENABLED);
\r
8795 SetMenuEnables(GetMenu(hwndMain), gnuEnables);
\r
8801 HMENU hmenu = GetMenu(hwndMain);
\r
8802 SetMenuEnables(hmenu, ncpEnables);
\r
8803 EnableMenuItem(GetSubMenu(hmenu, OPTIONS_POS), SOUNDS_POS,
\r
8804 MF_BYPOSITION|MF_GRAYED);
\r
8805 DrawMenuBar(hwndMain);
\r
8811 SetMenuEnables(GetMenu(hwndMain), cmailEnables);
\r
8815 SetTrainingModeOn()
\r
8818 SetMenuEnables(GetMenu(hwndMain), trainingOnEnables);
\r
8819 for (i = 0; i < N_BUTTONS; i++) {
\r
8820 if (buttonDesc[i].hwnd != NULL)
\r
8821 EnableWindow(buttonDesc[i].hwnd, FALSE);
\r
8826 VOID SetTrainingModeOff()
\r
8829 SetMenuEnables(GetMenu(hwndMain), trainingOffEnables);
\r
8830 for (i = 0; i < N_BUTTONS; i++) {
\r
8831 if (buttonDesc[i].hwnd != NULL)
\r
8832 EnableWindow(buttonDesc[i].hwnd, TRUE);
\r
8838 SetUserThinkingEnables()
\r
8840 SetMenuEnables(GetMenu(hwndMain), userThinkingEnables);
\r
8844 SetMachineThinkingEnables()
\r
8846 HMENU hMenu = GetMenu(hwndMain);
\r
8847 int flags = MF_BYCOMMAND|MF_ENABLED;
\r
8849 SetMenuEnables(hMenu, machineThinkingEnables);
\r
8851 if (gameMode == MachinePlaysBlack) {
\r
8852 (void)EnableMenuItem(hMenu, IDM_MachineBlack, flags);
\r
8853 } else if (gameMode == MachinePlaysWhite) {
\r
8854 (void)EnableMenuItem(hMenu, IDM_MachineWhite, flags);
\r
8855 } else if (gameMode == TwoMachinesPlay) {
\r
8856 (void)EnableMenuItem(hMenu, IDM_TwoMachines, flags);
\r
8862 DisplayTitle(char *str)
\r
8864 char title[MSG_SIZ], *host;
\r
8865 if (str[0] != NULLCHAR) {
\r
8866 strcpy(title, str);
\r
8867 } else if (appData.icsActive) {
\r
8868 if (appData.icsCommPort[0] != NULLCHAR)
\r
8871 host = appData.icsHost;
\r
8872 sprintf(title, "%s: %s", szTitle, host);
\r
8873 } else if (appData.noChessProgram) {
\r
8874 strcpy(title, szTitle);
\r
8876 strcpy(title, szTitle);
\r
8877 strcat(title, ": ");
\r
8878 strcat(title, first.tidy);
\r
8880 SetWindowText(hwndMain, title);
\r
8885 DisplayMessage(char *str1, char *str2)
\r
8889 int remain = MESSAGE_TEXT_MAX - 1;
\r
8892 moveErrorMessageUp = FALSE; /* turned on later by caller if needed */
\r
8893 messageText[0] = NULLCHAR;
\r
8895 len = strlen(str1);
\r
8896 if (len > remain) len = remain;
\r
8897 strncpy(messageText, str1, len);
\r
8898 messageText[len] = NULLCHAR;
\r
8901 if (*str2 && remain >= 2) {
\r
8903 strcat(messageText, " ");
\r
8906 len = strlen(str2);
\r
8907 if (len > remain) len = remain;
\r
8908 strncat(messageText, str2, len);
\r
8910 messageText[MESSAGE_TEXT_MAX - 1] = NULLCHAR;
\r
8912 if (hwndMain == NULL || IsIconic(hwndMain)) return;
\r
8913 hdc = GetDC(hwndMain);
\r
8914 oldFont = SelectObject(hdc, font[boardSize][MESSAGE_FONT]->hf);
\r
8915 ExtTextOut(hdc, messageRect.left, messageRect.top, ETO_CLIPPED|ETO_OPAQUE,
\r
8916 &messageRect, messageText, strlen(messageText), NULL);
\r
8917 (void) SelectObject(hdc, oldFont);
\r
8918 (void) ReleaseDC(hwndMain, hdc);
\r
8922 DisplayError(char *str, int error)
\r
8924 char buf[MSG_SIZ*2], buf2[MSG_SIZ];
\r
8930 len = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
\r
8931 NULL, error, LANG_NEUTRAL,
\r
8932 (LPSTR) buf2, MSG_SIZ, NULL);
\r
8934 sprintf(buf, "%s:\n%s", str, buf2);
\r
8936 ErrorMap *em = errmap;
\r
8937 while (em->err != 0 && em->err != error) em++;
\r
8938 if (em->err != 0) {
\r
8939 sprintf(buf, "%s:\n%s", str, em->msg);
\r
8941 sprintf(buf, "%s:\nError code %d", str, error);
\r
8946 ErrorPopUp("Error", buf);
\r
8951 DisplayMoveError(char *str)
\r
8953 fromX = fromY = -1;
\r
8954 ClearHighlights();
\r
8955 DrawPosition(FALSE, NULL);
\r
8956 if (appData.popupMoveErrors) {
\r
8957 ErrorPopUp("Error", str);
\r
8959 DisplayMessage(str, "");
\r
8960 moveErrorMessageUp = TRUE;
\r
8965 DisplayFatalError(char *str, int error, int exitStatus)
\r
8967 char buf[2*MSG_SIZ], buf2[MSG_SIZ];
\r
8969 char *label = exitStatus ? "Fatal Error" : "Exiting";
\r
8972 len = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
\r
8973 NULL, error, LANG_NEUTRAL,
\r
8974 (LPSTR) buf2, MSG_SIZ, NULL);
\r
8976 sprintf(buf, "%s:\n%s", str, buf2);
\r
8978 ErrorMap *em = errmap;
\r
8979 while (em->err != 0 && em->err != error) em++;
\r
8980 if (em->err != 0) {
\r
8981 sprintf(buf, "%s:\n%s", str, em->msg);
\r
8983 sprintf(buf, "%s:\nError code %d", str, error);
\r
8988 if (appData.debugMode) {
\r
8989 fprintf(debugFP, "%s: %s\n", label, str);
\r
8991 if (appData.popupExitMessage) {
\r
8992 (void) MessageBox(hwndMain, str, label, MB_OK|
\r
8993 (exitStatus ? MB_ICONSTOP : MB_ICONINFORMATION));
\r
8995 ExitEvent(exitStatus);
\r
9000 DisplayInformation(char *str)
\r
9002 (void) MessageBox(hwndMain, str, "Information", MB_OK|MB_ICONINFORMATION);
\r
9007 DisplayNote(char *str)
\r
9009 ErrorPopUp("Note", str);
\r
9014 char *title, *question, *replyPrefix;
\r
9019 QuestionDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
9021 static QuestionParams *qp;
\r
9022 char reply[MSG_SIZ];
\r
9025 switch (message) {
\r
9026 case WM_INITDIALOG:
\r
9027 qp = (QuestionParams *) lParam;
\r
9028 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
9029 SetWindowText(hDlg, qp->title);
\r
9030 SetDlgItemText(hDlg, OPT_QuestionText, qp->question);
\r
9031 SetFocus(GetDlgItem(hDlg, OPT_QuestionInput));
\r
9035 switch (LOWORD(wParam)) {
\r
9037 strcpy(reply, qp->replyPrefix);
\r
9038 if (*reply) strcat(reply, " ");
\r
9039 len = strlen(reply);
\r
9040 GetDlgItemText(hDlg, OPT_QuestionInput, reply + len, sizeof(reply) - len);
\r
9041 strcat(reply, "\n");
\r
9042 OutputToProcess(qp->pr, reply, strlen(reply), &err);
\r
9043 EndDialog(hDlg, TRUE);
\r
9044 if (err) DisplayFatalError("Error writing to chess program", err, 1);
\r
9047 EndDialog(hDlg, FALSE);
\r
9058 AskQuestion(char* title, char *question, char *replyPrefix, ProcRef pr)
\r
9060 QuestionParams qp;
\r
9064 qp.question = question;
\r
9065 qp.replyPrefix = replyPrefix;
\r
9067 lpProc = MakeProcInstance((FARPROC)QuestionDialog, hInst);
\r
9068 DialogBoxParam(hInst, MAKEINTRESOURCE(DLG_Question),
\r
9069 hwndMain, (DLGPROC)lpProc, (LPARAM)&qp);
\r
9070 FreeProcInstance(lpProc);
\r
9073 /* [AS] Pick FRC position */
\r
9074 LRESULT CALLBACK NewGameFRC_Proc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
9076 static int * lpIndexFRC;
\r
9082 case WM_INITDIALOG:
\r
9083 lpIndexFRC = (int *) lParam;
\r
9085 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
9087 SendDlgItemMessage( hDlg, IDC_NFG_Edit, EM_SETLIMITTEXT, sizeof(buf)-1, 0 );
\r
9088 SetDlgItemInt( hDlg, IDC_NFG_Edit, *lpIndexFRC, TRUE );
\r
9089 SendDlgItemMessage( hDlg, IDC_NFG_Edit, EM_SETSEL, 0, -1 );
\r
9090 SetFocus(GetDlgItem(hDlg, IDC_NFG_Edit));
\r
9095 switch( LOWORD(wParam) ) {
\r
9097 *lpIndexFRC = GetDlgItemInt(hDlg, IDC_NFG_Edit, &index_is_ok, TRUE );
\r
9098 EndDialog( hDlg, 0 );
\r
9099 shuffleOpenings = TRUE; /* [HGM] shuffle: switch shuffling on for as long as we stay in current variant */
\r
9102 EndDialog( hDlg, 1 );
\r
9104 case IDC_NFG_Edit:
\r
9105 if( HIWORD(wParam) == EN_CHANGE ) {
\r
9106 GetDlgItemInt(hDlg, IDC_NFG_Edit, &index_is_ok, TRUE );
\r
9108 EnableWindow( GetDlgItem(hDlg, IDOK), index_is_ok );
\r
9111 case IDC_NFG_Random:
\r
9112 sprintf( buf, "%d", myrandom() ); /* [HGM] shuffle: no longer limit to 960 */
\r
9113 SetDlgItemText(hDlg, IDC_NFG_Edit, buf );
\r
9126 int index = appData.defaultFrcPosition;
\r
9127 FARPROC lpProc = MakeProcInstance( (FARPROC) NewGameFRC_Proc, hInst );
\r
9129 result = DialogBoxParam( hInst, MAKEINTRESOURCE(DLG_NewGameFRC), hwndMain, (DLGPROC)lpProc, (LPARAM)&index );
\r
9131 if( result == 0 ) {
\r
9132 appData.defaultFrcPosition = index;
\r
9138 /* [AS] Game list options */
\r
9144 static GLT_Item GLT_ItemInfo[] = {
\r
9145 { GLT_EVENT, "Event" },
\r
9146 { GLT_SITE, "Site" },
\r
9147 { GLT_DATE, "Date" },
\r
9148 { GLT_ROUND, "Round" },
\r
9149 { GLT_PLAYERS, "Players" },
\r
9150 { GLT_RESULT, "Result" },
\r
9151 { GLT_WHITE_ELO, "White Rating" },
\r
9152 { GLT_BLACK_ELO, "Black Rating" },
\r
9153 { GLT_TIME_CONTROL,"Time Control" },
\r
9154 { GLT_VARIANT, "Variant" },
\r
9155 { GLT_OUT_OF_BOOK,PGN_OUT_OF_BOOK },
\r
9159 const char * GLT_FindItem( char id )
\r
9161 const char * result = 0;
\r
9163 GLT_Item * list = GLT_ItemInfo;
\r
9165 while( list->id != 0 ) {
\r
9166 if( list->id == id ) {
\r
9167 result = list->name;
\r
9177 void GLT_AddToList( HWND hDlg, int iDlgItem, char id, int index )
\r
9179 const char * name = GLT_FindItem( id );
\r
9182 if( index >= 0 ) {
\r
9183 SendDlgItemMessage( hDlg, iDlgItem, LB_INSERTSTRING, index, (LPARAM) name );
\r
9186 SendDlgItemMessage( hDlg, iDlgItem, LB_ADDSTRING, 0, (LPARAM) name );
\r
9191 void GLT_TagsToList( HWND hDlg, char * tags )
\r
9195 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_RESETCONTENT, 0, 0 );
\r
9198 GLT_AddToList( hDlg, IDC_GameListTags, *pc, -1 );
\r
9202 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_ADDSTRING, 0, (LPARAM) "\t --- Hidden tags ---" );
\r
9204 pc = GLT_ALL_TAGS;
\r
9207 if( strchr( tags, *pc ) == 0 ) {
\r
9208 GLT_AddToList( hDlg, IDC_GameListTags, *pc, -1 );
\r
9213 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_SETCURSEL, 0, 0 );
\r
9216 char GLT_ListItemToTag( HWND hDlg, int index )
\r
9218 char result = '\0';
\r
9221 GLT_Item * list = GLT_ItemInfo;
\r
9223 if( SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETTEXT, index, (LPARAM) name ) != LB_ERR ) {
\r
9224 while( list->id != 0 ) {
\r
9225 if( strcmp( list->name, name ) == 0 ) {
\r
9226 result = list->id;
\r
9237 void GLT_MoveSelection( HWND hDlg, int delta )
\r
9239 int idx1 = (int) SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETCURSEL, 0, 0 );
\r
9240 int idx2 = idx1 + delta;
\r
9241 int count = (int) SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETCOUNT, 0, 0 );
\r
9243 if( idx1 >=0 && idx1 < count && idx2 >= 0 && idx2 < count ) {
\r
9246 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETTEXT, idx1, (LPARAM) buf );
\r
9247 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_DELETESTRING, idx1, 0 );
\r
9248 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_INSERTSTRING, idx2, (LPARAM) buf );
\r
9249 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_SETCURSEL, idx2, 0 );
\r
9253 LRESULT CALLBACK GameListOptions_Proc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
9255 static char glt[64];
\r
9256 static char * lpUserGLT;
\r
9260 case WM_INITDIALOG:
\r
9261 lpUserGLT = (char *) lParam;
\r
9263 strcpy( glt, lpUserGLT );
\r
9265 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
9267 /* Initialize list */
\r
9268 GLT_TagsToList( hDlg, glt );
\r
9270 SetFocus( GetDlgItem(hDlg, IDC_GameListTags) );
\r
9275 switch( LOWORD(wParam) ) {
\r
9278 char * pc = lpUserGLT;
\r
9280 // int cnt = (int) SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETCOUNT, 0, 0 );
\r
9284 id = GLT_ListItemToTag( hDlg, idx );
\r
9288 } while( id != '\0' );
\r
9290 EndDialog( hDlg, 0 );
\r
9293 EndDialog( hDlg, 1 );
\r
9296 case IDC_GLT_Default:
\r
9297 strcpy( glt, GLT_DEFAULT_TAGS );
\r
9298 GLT_TagsToList( hDlg, glt );
\r
9301 case IDC_GLT_Restore:
\r
9302 strcpy( glt, lpUserGLT );
\r
9303 GLT_TagsToList( hDlg, glt );
\r
9307 GLT_MoveSelection( hDlg, -1 );
\r
9310 case IDC_GLT_Down:
\r
9311 GLT_MoveSelection( hDlg, +1 );
\r
9321 int GameListOptions()
\r
9325 FARPROC lpProc = MakeProcInstance( (FARPROC) GameListOptions_Proc, hInst );
\r
9327 strcpy( glt, appData.gameListTags );
\r
9329 result = DialogBoxParam( hInst, MAKEINTRESOURCE(DLG_GameListOptions), hwndMain, (DLGPROC)lpProc, (LPARAM)glt );
\r
9331 if( result == 0 ) {
\r
9332 /* [AS] Memory leak here! */
\r
9333 appData.gameListTags = strdup( glt );
\r
9341 DisplayIcsInteractionTitle(char *str)
\r
9343 char consoleTitle[MSG_SIZ];
\r
9345 sprintf(consoleTitle, "%s: %s", szConsoleTitle, str);
\r
9346 SetWindowText(hwndConsole, consoleTitle);
\r
9350 DrawPosition(int fullRedraw, Board board)
\r
9352 HDCDrawPosition(NULL, (BOOLEAN) fullRedraw, board);
\r
9359 fromX = fromY = -1;
\r
9360 if (dragInfo.pos.x != -1 || dragInfo.pos.y != -1) {
\r
9361 dragInfo.pos.x = dragInfo.pos.y = -1;
\r
9362 dragInfo.pos.x = dragInfo.pos.y = -1;
\r
9363 dragInfo.lastpos = dragInfo.pos;
\r
9364 dragInfo.start.x = dragInfo.start.y = -1;
\r
9365 dragInfo.from = dragInfo.start;
\r
9367 DrawPosition(TRUE, NULL);
\r
9373 CommentPopUp(char *title, char *str)
\r
9375 HWND hwnd = GetActiveWindow();
\r
9376 EitherCommentPopUp(0, title, str, FALSE);
\r
9377 SetActiveWindow(hwnd);
\r
9381 CommentPopDown(void)
\r
9383 CheckMenuItem(GetMenu(hwndMain), IDM_EditComment, MF_UNCHECKED);
\r
9384 if (commentDialog) {
\r
9385 ShowWindow(commentDialog, SW_HIDE);
\r
9387 commentDialogUp = FALSE;
\r
9391 EditCommentPopUp(int index, char *title, char *str)
\r
9393 EitherCommentPopUp(index, title, str, TRUE);
\r
9400 MyPlaySound(&sounds[(int)SoundMove]);
\r
9403 VOID PlayIcsWinSound()
\r
9405 MyPlaySound(&sounds[(int)SoundIcsWin]);
\r
9408 VOID PlayIcsLossSound()
\r
9410 MyPlaySound(&sounds[(int)SoundIcsLoss]);
\r
9413 VOID PlayIcsDrawSound()
\r
9415 MyPlaySound(&sounds[(int)SoundIcsDraw]);
\r
9418 VOID PlayIcsUnfinishedSound()
\r
9420 MyPlaySound(&sounds[(int)SoundIcsUnfinished]);
\r
9426 MyPlaySound(&sounds[(int)SoundAlarm]);
\r
9434 consoleEcho = TRUE;
\r
9435 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
9436 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&consoleCF);
\r
9437 SendMessage(hInput, EM_SETBKGNDCOLOR, FALSE, consoleBackgroundColor);
\r
9446 consoleEcho = FALSE;
\r
9447 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
9448 /* This works OK: set text and background both to the same color */
\r
9450 cf.crTextColor = COLOR_ECHOOFF;
\r
9451 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&cf);
\r
9452 SendMessage(hInput, EM_SETBKGNDCOLOR, FALSE, cf.crTextColor);
\r
9455 /* No Raw()...? */
\r
9457 void Colorize(ColorClass cc, int continuation)
\r
9459 currentColorClass = cc;
\r
9460 consoleCF.dwMask = CFM_COLOR|CFM_BOLD|CFM_ITALIC|CFM_UNDERLINE|CFM_STRIKEOUT;
\r
9461 consoleCF.crTextColor = textAttribs[cc].color;
\r
9462 consoleCF.dwEffects = textAttribs[cc].effects;
\r
9463 if (!continuation) MyPlaySound(&textAttribs[cc].sound);
\r
9469 static char buf[MSG_SIZ];
\r
9470 DWORD bufsiz = MSG_SIZ;
\r
9472 if(appData.userName != NULL && appData.userName[0] != 0) {
\r
9473 return appData.userName; /* [HGM] username: prefer name selected by user over his system login */
\r
9475 if (!GetUserName(buf, &bufsiz)) {
\r
9476 /*DisplayError("Error getting user name", GetLastError());*/
\r
9477 strcpy(buf, "User");
\r
9485 static char buf[MSG_SIZ];
\r
9486 DWORD bufsiz = MSG_SIZ;
\r
9488 if (!GetComputerName(buf, &bufsiz)) {
\r
9489 /*DisplayError("Error getting host name", GetLastError());*/
\r
9490 strcpy(buf, "Unknown");
\r
9497 ClockTimerRunning()
\r
9499 return clockTimerEvent != 0;
\r
9505 if (clockTimerEvent == 0) return FALSE;
\r
9506 KillTimer(hwndMain, clockTimerEvent);
\r
9507 clockTimerEvent = 0;
\r
9512 StartClockTimer(long millisec)
\r
9514 clockTimerEvent = SetTimer(hwndMain, (UINT) CLOCK_TIMER_ID,
\r
9515 (UINT) millisec, NULL);
\r
9519 DisplayWhiteClock(long timeRemaining, int highlight)
\r
9522 char *flag = whiteFlag && gameMode == TwoMachinesPlay ? "(!)" : "";
\r
9524 if(appData.noGUI) return;
\r
9525 hdc = GetDC(hwndMain);
\r
9526 if (!IsIconic(hwndMain)) {
\r
9527 DisplayAClock(hdc, timeRemaining, highlight,
\r
9528 (logoHeight > 0 ? flipView: flipClock) ? &blackRect : &whiteRect, "White", flag);
\r
9530 if (highlight && iconCurrent == iconBlack) {
\r
9531 iconCurrent = iconWhite;
\r
9532 PostMessage(hwndMain, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
9533 if (IsIconic(hwndMain)) {
\r
9534 DrawIcon(hdc, 2, 2, iconCurrent);
\r
9537 (void) ReleaseDC(hwndMain, hdc);
\r
9539 PostMessage(hwndConsole, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
9543 DisplayBlackClock(long timeRemaining, int highlight)
\r
9546 char *flag = blackFlag && gameMode == TwoMachinesPlay ? "(!)" : "";
\r
9548 if(appData.noGUI) return;
\r
9549 hdc = GetDC(hwndMain);
\r
9550 if (!IsIconic(hwndMain)) {
\r
9551 DisplayAClock(hdc, timeRemaining, highlight,
\r
9552 (logoHeight > 0 ? flipView: flipClock) ? &whiteRect : &blackRect, "Black", flag);
\r
9554 if (highlight && iconCurrent == iconWhite) {
\r
9555 iconCurrent = iconBlack;
\r
9556 PostMessage(hwndMain, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
9557 if (IsIconic(hwndMain)) {
\r
9558 DrawIcon(hdc, 2, 2, iconCurrent);
\r
9561 (void) ReleaseDC(hwndMain, hdc);
\r
9563 PostMessage(hwndConsole, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
9568 LoadGameTimerRunning()
\r
9570 return loadGameTimerEvent != 0;
\r
9574 StopLoadGameTimer()
\r
9576 if (loadGameTimerEvent == 0) return FALSE;
\r
9577 KillTimer(hwndMain, loadGameTimerEvent);
\r
9578 loadGameTimerEvent = 0;
\r
9583 StartLoadGameTimer(long millisec)
\r
9585 loadGameTimerEvent = SetTimer(hwndMain, (UINT) LOAD_GAME_TIMER_ID,
\r
9586 (UINT) millisec, NULL);
\r
9594 char fileTitle[MSG_SIZ];
\r
9596 defName = DefaultFileName(appData.oldSaveStyle ? "gam" : "pgn");
\r
9597 f = OpenFileDialog(hwndMain, "a", defName,
\r
9598 appData.oldSaveStyle ? "gam" : "pgn",
\r
9600 "Save Game to File", NULL, fileTitle, NULL);
\r
9602 SaveGame(f, 0, "");
\r
9609 ScheduleDelayedEvent(DelayedEventCallback cb, long millisec)
\r
9611 if (delayedTimerEvent != 0) {
\r
9612 if (appData.debugMode) {
\r
9613 fprintf(debugFP, "ScheduleDelayedEvent: event already scheduled\n");
\r
9615 KillTimer(hwndMain, delayedTimerEvent);
\r
9616 delayedTimerEvent = 0;
\r
9617 delayedTimerCallback();
\r
9619 delayedTimerCallback = cb;
\r
9620 delayedTimerEvent = SetTimer(hwndMain, (UINT) DELAYED_TIMER_ID,
\r
9621 (UINT) millisec, NULL);
\r
9624 DelayedEventCallback
\r
9627 if (delayedTimerEvent) {
\r
9628 return delayedTimerCallback;
\r
9635 CancelDelayedEvent()
\r
9637 if (delayedTimerEvent) {
\r
9638 KillTimer(hwndMain, delayedTimerEvent);
\r
9639 delayedTimerEvent = 0;
\r
9643 DWORD GetWin32Priority(int nice)
\r
9644 { // [HGM] nice: translate Unix nice() value to indows priority class. (Code stolen from Polyglot 1.4w11)
\r
9646 REALTIME_PRIORITY_CLASS 0x00000100
\r
9647 HIGH_PRIORITY_CLASS 0x00000080
\r
9648 ABOVE_NORMAL_PRIORITY_CLASS 0x00008000
\r
9649 NORMAL_PRIORITY_CLASS 0x00000020
\r
9650 BELOW_NORMAL_PRIORITY_CLASS 0x00004000
\r
9651 IDLE_PRIORITY_CLASS 0x00000040
\r
9653 if (nice < -15) return 0x00000080;
\r
9654 if (nice < 0) return 0x00008000;
\r
9655 if (nice == 0) return 0x00000020;
\r
9656 if (nice < 15) return 0x00004000;
\r
9657 return 0x00000040;
\r
9660 /* Start a child process running the given program.
\r
9661 The process's standard output can be read from "from", and its
\r
9662 standard input can be written to "to".
\r
9663 Exit with fatal error if anything goes wrong.
\r
9664 Returns an opaque pointer that can be used to destroy the process
\r
9668 StartChildProcess(char *cmdLine, char *dir, ProcRef *pr)
\r
9670 #define BUFSIZE 4096
\r
9672 HANDLE hChildStdinRd, hChildStdinWr,
\r
9673 hChildStdoutRd, hChildStdoutWr;
\r
9674 HANDLE hChildStdinWrDup, hChildStdoutRdDup;
\r
9675 SECURITY_ATTRIBUTES saAttr;
\r
9677 PROCESS_INFORMATION piProcInfo;
\r
9678 STARTUPINFO siStartInfo;
\r
9680 char buf[MSG_SIZ];
\r
9683 if (appData.debugMode) {
\r
9684 fprintf(debugFP, "StartChildProcess (dir=\"%s\") %s\n", dir, cmdLine);
\r
9689 /* Set the bInheritHandle flag so pipe handles are inherited. */
\r
9690 saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
\r
9691 saAttr.bInheritHandle = TRUE;
\r
9692 saAttr.lpSecurityDescriptor = NULL;
\r
9695 * The steps for redirecting child's STDOUT:
\r
9696 * 1. Create anonymous pipe to be STDOUT for child.
\r
9697 * 2. Create a noninheritable duplicate of read handle,
\r
9698 * and close the inheritable read handle.
\r
9701 /* Create a pipe for the child's STDOUT. */
\r
9702 if (! CreatePipe(&hChildStdoutRd, &hChildStdoutWr, &saAttr, 0)) {
\r
9703 return GetLastError();
\r
9706 /* Duplicate the read handle to the pipe, so it is not inherited. */
\r
9707 fSuccess = DuplicateHandle(GetCurrentProcess(), hChildStdoutRd,
\r
9708 GetCurrentProcess(), &hChildStdoutRdDup, 0,
\r
9709 FALSE, /* not inherited */
\r
9710 DUPLICATE_SAME_ACCESS);
\r
9712 return GetLastError();
\r
9714 CloseHandle(hChildStdoutRd);
\r
9717 * The steps for redirecting child's STDIN:
\r
9718 * 1. Create anonymous pipe to be STDIN for child.
\r
9719 * 2. Create a noninheritable duplicate of write handle,
\r
9720 * and close the inheritable write handle.
\r
9723 /* Create a pipe for the child's STDIN. */
\r
9724 if (! CreatePipe(&hChildStdinRd, &hChildStdinWr, &saAttr, 0)) {
\r
9725 return GetLastError();
\r
9728 /* Duplicate the write handle to the pipe, so it is not inherited. */
\r
9729 fSuccess = DuplicateHandle(GetCurrentProcess(), hChildStdinWr,
\r
9730 GetCurrentProcess(), &hChildStdinWrDup, 0,
\r
9731 FALSE, /* not inherited */
\r
9732 DUPLICATE_SAME_ACCESS);
\r
9734 return GetLastError();
\r
9736 CloseHandle(hChildStdinWr);
\r
9738 /* Arrange to (1) look in dir for the child .exe file, and
\r
9739 * (2) have dir be the child's working directory. Interpret
\r
9740 * dir relative to the directory WinBoard loaded from. */
\r
9741 GetCurrentDirectory(MSG_SIZ, buf);
\r
9742 SetCurrentDirectory(installDir);
\r
9743 SetCurrentDirectory(dir);
\r
9745 /* Now create the child process. */
\r
9747 siStartInfo.cb = sizeof(STARTUPINFO);
\r
9748 siStartInfo.lpReserved = NULL;
\r
9749 siStartInfo.lpDesktop = NULL;
\r
9750 siStartInfo.lpTitle = NULL;
\r
9751 siStartInfo.dwFlags = STARTF_USESTDHANDLES;
\r
9752 siStartInfo.cbReserved2 = 0;
\r
9753 siStartInfo.lpReserved2 = NULL;
\r
9754 siStartInfo.hStdInput = hChildStdinRd;
\r
9755 siStartInfo.hStdOutput = hChildStdoutWr;
\r
9756 siStartInfo.hStdError = hChildStdoutWr;
\r
9758 fSuccess = CreateProcess(NULL,
\r
9759 cmdLine, /* command line */
\r
9760 NULL, /* process security attributes */
\r
9761 NULL, /* primary thread security attrs */
\r
9762 TRUE, /* handles are inherited */
\r
9763 DETACHED_PROCESS|CREATE_NEW_PROCESS_GROUP,
\r
9764 NULL, /* use parent's environment */
\r
9766 &siStartInfo, /* STARTUPINFO pointer */
\r
9767 &piProcInfo); /* receives PROCESS_INFORMATION */
\r
9769 err = GetLastError();
\r
9770 SetCurrentDirectory(buf); /* return to prev directory */
\r
9775 if (appData.niceEngines){ // [HGM] nice: adjust engine proc priority
\r
9776 if(appData.debugMode) fprintf(debugFP, "nice engine proc to %d\n", appData.niceEngines);
\r
9777 SetPriorityClass(piProcInfo.hProcess, GetWin32Priority(appData.niceEngines));
\r
9780 /* Close the handles we don't need in the parent */
\r
9781 CloseHandle(piProcInfo.hThread);
\r
9782 CloseHandle(hChildStdinRd);
\r
9783 CloseHandle(hChildStdoutWr);
\r
9785 /* Prepare return value */
\r
9786 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
9787 cp->kind = CPReal;
\r
9788 cp->hProcess = piProcInfo.hProcess;
\r
9789 cp->pid = piProcInfo.dwProcessId;
\r
9790 cp->hFrom = hChildStdoutRdDup;
\r
9791 cp->hTo = hChildStdinWrDup;
\r
9793 *pr = (void *) cp;
\r
9795 /* Klaus Friedel says that this Sleep solves a problem under Windows
\r
9796 2000 where engines sometimes don't see the initial command(s)
\r
9797 from WinBoard and hang. I don't understand how that can happen,
\r
9798 but the Sleep is harmless, so I've put it in. Others have also
\r
9799 reported what may be the same problem, so hopefully this will fix
\r
9800 it for them too. */
\r
9808 DestroyChildProcess(ProcRef pr, int/*boolean*/ signal)
\r
9810 ChildProc *cp; int result;
\r
9812 cp = (ChildProc *) pr;
\r
9813 if (cp == NULL) return;
\r
9815 switch (cp->kind) {
\r
9817 /* TerminateProcess is considered harmful, so... */
\r
9818 CloseHandle(cp->hTo); /* Closing this will give the child an EOF and hopefully kill it */
\r
9819 if (cp->hFrom) CloseHandle(cp->hFrom); /* if NULL, InputThread will close it */
\r
9820 /* The following doesn't work because the chess program
\r
9821 doesn't "have the same console" as WinBoard. Maybe
\r
9822 we could arrange for this even though neither WinBoard
\r
9823 nor the chess program uses a console for stdio? */
\r
9824 /*!!if (signal) GenerateConsoleCtrlEvent(CTRL_BREAK_EVENT, cp->pid);*/
\r
9826 /* [AS] Special termination modes for misbehaving programs... */
\r
9827 if( signal == 9 ) {
\r
9828 result = TerminateProcess( cp->hProcess, 0 );
\r
9830 if ( appData.debugMode) {
\r
9831 fprintf( debugFP, "Terminating process %lu, result=%d\n", cp->pid, result );
\r
9834 else if( signal == 10 ) {
\r
9835 DWORD dw = WaitForSingleObject( cp->hProcess, 3*1000 ); // Wait 3 seconds at most
\r
9837 if( dw != WAIT_OBJECT_0 ) {
\r
9838 result = TerminateProcess( cp->hProcess, 0 );
\r
9840 if ( appData.debugMode) {
\r
9841 fprintf( debugFP, "Process %lu still alive after timeout, killing... result=%d\n", cp->pid, result );
\r
9847 CloseHandle(cp->hProcess);
\r
9851 if (cp->hFrom) CloseHandle(cp->hFrom);
\r
9855 closesocket(cp->sock);
\r
9860 if (signal) send(cp->sock2, "\017", 1, 0); /* 017 = 15 = SIGTERM */
\r
9861 closesocket(cp->sock);
\r
9862 closesocket(cp->sock2);
\r
9870 InterruptChildProcess(ProcRef pr)
\r
9874 cp = (ChildProc *) pr;
\r
9875 if (cp == NULL) return;
\r
9876 switch (cp->kind) {
\r
9878 /* The following doesn't work because the chess program
\r
9879 doesn't "have the same console" as WinBoard. Maybe
\r
9880 we could arrange for this even though neither WinBoard
\r
9881 nor the chess program uses a console for stdio */
\r
9882 /*!!GenerateConsoleCtrlEvent(CTRL_C_EVENT, cp->pid);*/
\r
9887 /* Can't interrupt */
\r
9891 send(cp->sock2, "\002", 1, 0); /* 2 = SIGINT */
\r
9898 OpenTelnet(char *host, char *port, ProcRef *pr)
\r
9900 char cmdLine[MSG_SIZ];
\r
9902 if (port[0] == NULLCHAR) {
\r
9903 sprintf(cmdLine, "%s %s", appData.telnetProgram, host);
\r
9905 sprintf(cmdLine, "%s %s %s", appData.telnetProgram, host, port);
\r
9907 return StartChildProcess(cmdLine, "", pr);
\r
9911 /* Code to open TCP sockets */
\r
9914 OpenTCP(char *host, char *port, ProcRef *pr)
\r
9919 struct sockaddr_in sa, mysa;
\r
9920 struct hostent FAR *hp;
\r
9921 unsigned short uport;
\r
9922 WORD wVersionRequested;
\r
9925 /* Initialize socket DLL */
\r
9926 wVersionRequested = MAKEWORD(1, 1);
\r
9927 err = WSAStartup(wVersionRequested, &wsaData);
\r
9928 if (err != 0) return err;
\r
9931 if ((s = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
\r
9932 err = WSAGetLastError();
\r
9937 /* Bind local address using (mostly) don't-care values.
\r
9939 memset((char *) &mysa, 0, sizeof(struct sockaddr_in));
\r
9940 mysa.sin_family = AF_INET;
\r
9941 mysa.sin_addr.s_addr = INADDR_ANY;
\r
9942 uport = (unsigned short) 0;
\r
9943 mysa.sin_port = htons(uport);
\r
9944 if (bind(s, (struct sockaddr *) &mysa, sizeof(struct sockaddr_in))
\r
9945 == SOCKET_ERROR) {
\r
9946 err = WSAGetLastError();
\r
9951 /* Resolve remote host name */
\r
9952 memset((char *) &sa, 0, sizeof(struct sockaddr_in));
\r
9953 if (!(hp = gethostbyname(host))) {
\r
9954 unsigned int b0, b1, b2, b3;
\r
9956 err = WSAGetLastError();
\r
9958 if (sscanf(host, "%u.%u.%u.%u", &b0, &b1, &b2, &b3) == 4) {
\r
9959 hp = (struct hostent *) calloc(1, sizeof(struct hostent));
\r
9960 hp->h_addrtype = AF_INET;
\r
9962 hp->h_addr_list = (char **) calloc(2, sizeof(char *));
\r
9963 hp->h_addr_list[0] = (char *) malloc(4);
\r
9964 hp->h_addr_list[0][0] = (char) b0;
\r
9965 hp->h_addr_list[0][1] = (char) b1;
\r
9966 hp->h_addr_list[0][2] = (char) b2;
\r
9967 hp->h_addr_list[0][3] = (char) b3;
\r
9973 sa.sin_family = hp->h_addrtype;
\r
9974 uport = (unsigned short) atoi(port);
\r
9975 sa.sin_port = htons(uport);
\r
9976 memcpy((char *) &sa.sin_addr, hp->h_addr, hp->h_length);
\r
9978 /* Make connection */
\r
9979 if (connect(s, (struct sockaddr *) &sa,
\r
9980 sizeof(struct sockaddr_in)) == SOCKET_ERROR) {
\r
9981 err = WSAGetLastError();
\r
9986 /* Prepare return value */
\r
9987 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
9988 cp->kind = CPSock;
\r
9990 *pr = (ProcRef *) cp;
\r
9996 OpenCommPort(char *name, ProcRef *pr)
\r
10001 char fullname[MSG_SIZ];
\r
10003 if (*name != '\\')
\r
10004 sprintf(fullname, "\\\\.\\%s", name);
\r
10006 strcpy(fullname, name);
\r
10008 h = CreateFile(name, GENERIC_READ | GENERIC_WRITE,
\r
10009 0, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
\r
10010 if (h == (HANDLE) -1) {
\r
10011 return GetLastError();
\r
10015 if (!SetCommState(h, (LPDCB) &dcb)) return GetLastError();
\r
10017 /* Accumulate characters until a 100ms pause, then parse */
\r
10018 ct.ReadIntervalTimeout = 100;
\r
10019 ct.ReadTotalTimeoutMultiplier = 0;
\r
10020 ct.ReadTotalTimeoutConstant = 0;
\r
10021 ct.WriteTotalTimeoutMultiplier = 0;
\r
10022 ct.WriteTotalTimeoutConstant = 0;
\r
10023 if (!SetCommTimeouts(h, (LPCOMMTIMEOUTS) &ct)) return GetLastError();
\r
10025 /* Prepare return value */
\r
10026 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
10027 cp->kind = CPComm;
\r
10030 *pr = (ProcRef *) cp;
\r
10036 OpenLoopback(ProcRef *pr)
\r
10038 DisplayFatalError("Not implemented", 0, 1);
\r
10044 OpenRcmd(char* host, char* user, char* cmd, ProcRef* pr)
\r
10048 SOCKET s, s2, s3;
\r
10049 struct sockaddr_in sa, mysa;
\r
10050 struct hostent FAR *hp;
\r
10051 unsigned short uport;
\r
10052 WORD wVersionRequested;
\r
10055 char stderrPortStr[MSG_SIZ];
\r
10057 /* Initialize socket DLL */
\r
10058 wVersionRequested = MAKEWORD(1, 1);
\r
10059 err = WSAStartup(wVersionRequested, &wsaData);
\r
10060 if (err != 0) return err;
\r
10062 /* Resolve remote host name */
\r
10063 memset((char *) &sa, 0, sizeof(struct sockaddr_in));
\r
10064 if (!(hp = gethostbyname(host))) {
\r
10065 unsigned int b0, b1, b2, b3;
\r
10067 err = WSAGetLastError();
\r
10069 if (sscanf(host, "%u.%u.%u.%u", &b0, &b1, &b2, &b3) == 4) {
\r
10070 hp = (struct hostent *) calloc(1, sizeof(struct hostent));
\r
10071 hp->h_addrtype = AF_INET;
\r
10072 hp->h_length = 4;
\r
10073 hp->h_addr_list = (char **) calloc(2, sizeof(char *));
\r
10074 hp->h_addr_list[0] = (char *) malloc(4);
\r
10075 hp->h_addr_list[0][0] = (char) b0;
\r
10076 hp->h_addr_list[0][1] = (char) b1;
\r
10077 hp->h_addr_list[0][2] = (char) b2;
\r
10078 hp->h_addr_list[0][3] = (char) b3;
\r
10084 sa.sin_family = hp->h_addrtype;
\r
10085 uport = (unsigned short) 514;
\r
10086 sa.sin_port = htons(uport);
\r
10087 memcpy((char *) &sa.sin_addr, hp->h_addr, hp->h_length);
\r
10089 /* Bind local socket to unused "privileged" port address
\r
10091 s = INVALID_SOCKET;
\r
10092 memset((char *) &mysa, 0, sizeof(struct sockaddr_in));
\r
10093 mysa.sin_family = AF_INET;
\r
10094 mysa.sin_addr.s_addr = INADDR_ANY;
\r
10095 for (fromPort = 1023;; fromPort--) {
\r
10096 if (fromPort < 0) {
\r
10098 return WSAEADDRINUSE;
\r
10100 if (s == INVALID_SOCKET) {
\r
10101 if ((s = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
\r
10102 err = WSAGetLastError();
\r
10107 uport = (unsigned short) fromPort;
\r
10108 mysa.sin_port = htons(uport);
\r
10109 if (bind(s, (struct sockaddr *) &mysa, sizeof(struct sockaddr_in))
\r
10110 == SOCKET_ERROR) {
\r
10111 err = WSAGetLastError();
\r
10112 if (err == WSAEADDRINUSE) continue;
\r
10116 if (connect(s, (struct sockaddr *) &sa,
\r
10117 sizeof(struct sockaddr_in)) == SOCKET_ERROR) {
\r
10118 err = WSAGetLastError();
\r
10119 if (err == WSAEADDRINUSE) {
\r
10130 /* Bind stderr local socket to unused "privileged" port address
\r
10132 s2 = INVALID_SOCKET;
\r
10133 memset((char *) &mysa, 0, sizeof(struct sockaddr_in));
\r
10134 mysa.sin_family = AF_INET;
\r
10135 mysa.sin_addr.s_addr = INADDR_ANY;
\r
10136 for (fromPort = 1023;; fromPort--) {
\r
10137 if (fromPort == prevStderrPort) continue; // don't reuse port
\r
10138 if (fromPort < 0) {
\r
10139 (void) closesocket(s);
\r
10141 return WSAEADDRINUSE;
\r
10143 if (s2 == INVALID_SOCKET) {
\r
10144 if ((s2 = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
\r
10145 err = WSAGetLastError();
\r
10151 uport = (unsigned short) fromPort;
\r
10152 mysa.sin_port = htons(uport);
\r
10153 if (bind(s2, (struct sockaddr *) &mysa, sizeof(struct sockaddr_in))
\r
10154 == SOCKET_ERROR) {
\r
10155 err = WSAGetLastError();
\r
10156 if (err == WSAEADDRINUSE) continue;
\r
10157 (void) closesocket(s);
\r
10161 if (listen(s2, 1) == SOCKET_ERROR) {
\r
10162 err = WSAGetLastError();
\r
10163 if (err == WSAEADDRINUSE) {
\r
10165 s2 = INVALID_SOCKET;
\r
10168 (void) closesocket(s);
\r
10169 (void) closesocket(s2);
\r
10175 prevStderrPort = fromPort; // remember port used
\r
10176 sprintf(stderrPortStr, "%d", fromPort);
\r
10178 if (send(s, stderrPortStr, strlen(stderrPortStr) + 1, 0) == SOCKET_ERROR) {
\r
10179 err = WSAGetLastError();
\r
10180 (void) closesocket(s);
\r
10181 (void) closesocket(s2);
\r
10186 if (send(s, UserName(), strlen(UserName()) + 1, 0) == SOCKET_ERROR) {
\r
10187 err = WSAGetLastError();
\r
10188 (void) closesocket(s);
\r
10189 (void) closesocket(s2);
\r
10193 if (*user == NULLCHAR) user = UserName();
\r
10194 if (send(s, user, strlen(user) + 1, 0) == SOCKET_ERROR) {
\r
10195 err = WSAGetLastError();
\r
10196 (void) closesocket(s);
\r
10197 (void) closesocket(s2);
\r
10201 if (send(s, cmd, strlen(cmd) + 1, 0) == SOCKET_ERROR) {
\r
10202 err = WSAGetLastError();
\r
10203 (void) closesocket(s);
\r
10204 (void) closesocket(s2);
\r
10209 if ((s3 = accept(s2, NULL, NULL)) == INVALID_SOCKET) {
\r
10210 err = WSAGetLastError();
\r
10211 (void) closesocket(s);
\r
10212 (void) closesocket(s2);
\r
10216 (void) closesocket(s2); /* Stop listening */
\r
10218 /* Prepare return value */
\r
10219 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
10220 cp->kind = CPRcmd;
\r
10223 *pr = (ProcRef *) cp;
\r
10230 AddInputSource(ProcRef pr, int lineByLine,
\r
10231 InputCallback func, VOIDSTAR closure)
\r
10233 InputSource *is, *is2 = NULL;
\r
10234 ChildProc *cp = (ChildProc *) pr;
\r
10236 is = (InputSource *) calloc(1, sizeof(InputSource));
\r
10237 is->lineByLine = lineByLine;
\r
10239 is->closure = closure;
\r
10240 is->second = NULL;
\r
10241 is->next = is->buf;
\r
10242 if (pr == NoProc) {
\r
10243 is->kind = CPReal;
\r
10244 consoleInputSource = is;
\r
10246 is->kind = cp->kind;
\r
10248 [AS] Try to avoid a race condition if the thread is given control too early:
\r
10249 we create all threads suspended so that the is->hThread variable can be
\r
10250 safely assigned, then let the threads start with ResumeThread.
\r
10252 switch (cp->kind) {
\r
10254 is->hFile = cp->hFrom;
\r
10255 cp->hFrom = NULL; /* now owned by InputThread */
\r
10257 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) NonOvlInputThread,
\r
10258 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
10262 is->hFile = cp->hFrom;
\r
10263 cp->hFrom = NULL; /* now owned by InputThread */
\r
10265 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) InputThread,
\r
10266 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
10270 is->sock = cp->sock;
\r
10272 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SocketInputThread,
\r
10273 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
10277 is2 = (InputSource *) calloc(1, sizeof(InputSource));
\r
10279 is->sock = cp->sock;
\r
10280 is->second = is2;
\r
10281 is2->sock = cp->sock2;
\r
10282 is2->second = is2;
\r
10284 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SocketInputThread,
\r
10285 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
10287 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SocketInputThread,
\r
10288 (LPVOID) is2, CREATE_SUSPENDED, &is2->id);
\r
10292 if( is->hThread != NULL ) {
\r
10293 ResumeThread( is->hThread );
\r
10296 if( is2 != NULL && is2->hThread != NULL ) {
\r
10297 ResumeThread( is2->hThread );
\r
10301 return (InputSourceRef) is;
\r
10305 RemoveInputSource(InputSourceRef isr)
\r
10309 is = (InputSource *) isr;
\r
10310 is->hThread = NULL; /* tell thread to stop */
\r
10311 CloseHandle(is->hThread);
\r
10312 if (is->second != NULL) {
\r
10313 is->second->hThread = NULL;
\r
10314 CloseHandle(is->second->hThread);
\r
10320 OutputToProcess(ProcRef pr, char *message, int count, int *outError)
\r
10323 int outCount = SOCKET_ERROR;
\r
10324 ChildProc *cp = (ChildProc *) pr;
\r
10325 static OVERLAPPED ovl;
\r
10327 if (pr == NoProc) {
\r
10328 ConsoleOutput(message, count, FALSE);
\r
10332 if (ovl.hEvent == NULL) {
\r
10333 ovl.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
\r
10335 ovl.Internal = ovl.InternalHigh = ovl.Offset = ovl.OffsetHigh = 0;
\r
10337 switch (cp->kind) {
\r
10340 outCount = send(cp->sock, message, count, 0);
\r
10341 if (outCount == SOCKET_ERROR) {
\r
10342 *outError = WSAGetLastError();
\r
10344 *outError = NO_ERROR;
\r
10349 if (WriteFile(((ChildProc *)pr)->hTo, message, count,
\r
10350 &dOutCount, NULL)) {
\r
10351 *outError = NO_ERROR;
\r
10352 outCount = (int) dOutCount;
\r
10354 *outError = GetLastError();
\r
10359 *outError = DoWriteFile(((ChildProc *)pr)->hTo, message, count,
\r
10360 &dOutCount, &ovl);
\r
10361 if (*outError == NO_ERROR) {
\r
10362 outCount = (int) dOutCount;
\r
10370 OutputToProcessDelayed(ProcRef pr, char *message, int count, int *outError,
\r
10373 /* Ignore delay, not implemented for WinBoard */
\r
10374 return OutputToProcess(pr, message, count, outError);
\r
10379 CmailSigHandlerCallBack(InputSourceRef isr, VOIDSTAR closure,
\r
10380 char *buf, int count, int error)
\r
10382 DisplayFatalError("Not implemented", 0, 1);
\r
10385 /* see wgamelist.c for Game List functions */
\r
10386 /* see wedittags.c for Edit Tags functions */
\r
10393 char buf[MSG_SIZ];
\r
10396 if (SearchPath(installDir, appData.icsLogon, NULL, MSG_SIZ, buf, &dummy)) {
\r
10397 f = fopen(buf, "r");
\r
10399 ProcessICSInitScript(f);
\r
10407 StartAnalysisClock()
\r
10409 if (analysisTimerEvent) return;
\r
10410 analysisTimerEvent = SetTimer(hwndMain, (UINT) ANALYSIS_TIMER_ID,
\r
10411 (UINT) 2000, NULL);
\r
10415 AnalysisDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
10417 static HANDLE hwndText;
\r
10419 static int sizeX, sizeY;
\r
10420 int newSizeX, newSizeY, flags;
\r
10423 switch (message) {
\r
10424 case WM_INITDIALOG: /* message: initialize dialog box */
\r
10425 /* Initialize the dialog items */
\r
10426 hwndText = GetDlgItem(hDlg, OPT_AnalysisText);
\r
10427 SetWindowText(hDlg, analysisTitle);
\r
10428 SetDlgItemText(hDlg, OPT_AnalysisText, analysisText);
\r
10429 /* Size and position the dialog */
\r
10430 if (!analysisDialog) {
\r
10431 analysisDialog = hDlg;
\r
10432 flags = SWP_NOZORDER;
\r
10433 GetClientRect(hDlg, &rect);
\r
10434 sizeX = rect.right;
\r
10435 sizeY = rect.bottom;
\r
10436 if (analysisX != CW_USEDEFAULT && analysisY != CW_USEDEFAULT &&
\r
10437 analysisW != CW_USEDEFAULT && analysisH != CW_USEDEFAULT) {
\r
10438 WINDOWPLACEMENT wp;
\r
10439 EnsureOnScreen(&analysisX, &analysisY);
\r
10440 wp.length = sizeof(WINDOWPLACEMENT);
\r
10442 wp.showCmd = SW_SHOW;
\r
10443 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
10444 wp.rcNormalPosition.left = analysisX;
\r
10445 wp.rcNormalPosition.right = analysisX + analysisW;
\r
10446 wp.rcNormalPosition.top = analysisY;
\r
10447 wp.rcNormalPosition.bottom = analysisY + analysisH;
\r
10448 SetWindowPlacement(hDlg, &wp);
\r
10450 GetClientRect(hDlg, &rect);
\r
10451 newSizeX = rect.right;
\r
10452 newSizeY = rect.bottom;
\r
10453 ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY,
\r
10454 newSizeX, newSizeY);
\r
10455 sizeX = newSizeX;
\r
10456 sizeY = newSizeY;
\r
10461 case WM_COMMAND: /* message: received a command */
\r
10462 switch (LOWORD(wParam)) {
\r
10464 if (appData.icsActive && appData.icsEngineAnalyze) { /* [DM] icsEngineAnalyze */
\r
10465 ExitAnalyzeMode();
\r
10477 newSizeX = LOWORD(lParam);
\r
10478 newSizeY = HIWORD(lParam);
\r
10479 ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY, newSizeX, newSizeY);
\r
10480 sizeX = newSizeX;
\r
10481 sizeY = newSizeY;
\r
10484 case WM_GETMINMAXINFO:
\r
10485 /* Prevent resizing window too small */
\r
10486 mmi = (MINMAXINFO *) lParam;
\r
10487 mmi->ptMinTrackSize.x = 100;
\r
10488 mmi->ptMinTrackSize.y = 100;
\r
10495 AnalysisPopUp(char* title, char* str)
\r
10501 EngineOutputPopUp();
\r
10504 if (str == NULL) str = "";
\r
10505 p = (char *) malloc(2 * strlen(str) + 2);
\r
10508 if (*str == '\n') *q++ = '\r';
\r
10512 if (analysisText != NULL) free(analysisText);
\r
10513 analysisText = p;
\r
10515 if (analysisDialog) {
\r
10516 SetWindowText(analysisDialog, title);
\r
10517 SetDlgItemText(analysisDialog, OPT_AnalysisText, analysisText);
\r
10518 ShowWindow(analysisDialog, SW_SHOW);
\r
10520 analysisTitle = title;
\r
10521 lpProc = MakeProcInstance((FARPROC)AnalysisDialog, hInst);
\r
10522 CreateDialog(hInst, MAKEINTRESOURCE(DLG_Analysis),
\r
10523 hwndMain, (DLGPROC)lpProc);
\r
10524 FreeProcInstance(lpProc);
\r
10526 analysisDialogUp = TRUE;
\r
10530 AnalysisPopDown()
\r
10532 if (analysisDialog) {
\r
10533 ShowWindow(analysisDialog, SW_HIDE);
\r
10535 analysisDialogUp = FALSE;
\r
10540 SetHighlights(int fromX, int fromY, int toX, int toY)
\r
10542 highlightInfo.sq[0].x = fromX;
\r
10543 highlightInfo.sq[0].y = fromY;
\r
10544 highlightInfo.sq[1].x = toX;
\r
10545 highlightInfo.sq[1].y = toY;
\r
10549 ClearHighlights()
\r
10551 highlightInfo.sq[0].x = highlightInfo.sq[0].y =
\r
10552 highlightInfo.sq[1].x = highlightInfo.sq[1].y = -1;
\r
10556 SetPremoveHighlights(int fromX, int fromY, int toX, int toY)
\r
10558 premoveHighlightInfo.sq[0].x = fromX;
\r
10559 premoveHighlightInfo.sq[0].y = fromY;
\r
10560 premoveHighlightInfo.sq[1].x = toX;
\r
10561 premoveHighlightInfo.sq[1].y = toY;
\r
10565 ClearPremoveHighlights()
\r
10567 premoveHighlightInfo.sq[0].x = premoveHighlightInfo.sq[0].y =
\r
10568 premoveHighlightInfo.sq[1].x = premoveHighlightInfo.sq[1].y = -1;
\r
10572 ShutDownFrontEnd()
\r
10574 if (saveSettingsOnExit) SaveSettings(settingsFileName);
\r
10575 DeleteClipboardTempFiles();
\r
10581 if (IsIconic(hwndMain))
\r
10582 ShowWindow(hwndMain, SW_RESTORE);
\r
10584 SetActiveWindow(hwndMain);
\r
10588 * Prototypes for animation support routines
\r
10590 static void ScreenSquare(int column, int row, POINT * pt);
\r
10591 static void Tween( POINT * start, POINT * mid, POINT * finish, int factor,
\r
10592 POINT frames[], int * nFrames);
\r
10596 AnimateAtomicCapture(int toX, int toY, int nFrames)
\r
10597 { // [HGM] atomic: animate blast wave
\r
10599 if(appData.debugMode) fprintf(debugFP, "exploding (%d,%d)\n", toX, toY);
\r
10600 explodeInfo.x = toX;
\r
10601 explodeInfo.y = toY;
\r
10602 for(i=0; i<nFrames; i++) {
\r
10603 explodeInfo.radius = (i*180)/(nFrames-1);
\r
10604 DrawPosition(FALSE, NULL);
\r
10605 Sleep(appData.animSpeed);
\r
10607 explodeInfo.radius = 0;
\r
10608 DrawPosition(TRUE, NULL);
\r
10611 #define kFactor 4
\r
10614 AnimateMove(board, fromX, fromY, toX, toY)
\r
10621 ChessSquare piece;
\r
10622 POINT start, finish, mid;
\r
10623 POINT frames[kFactor * 2 + 1];
\r
10626 if (!appData.animate) return;
\r
10627 if (doingSizing) return;
\r
10628 if (fromY < 0 || fromX < 0) return;
\r
10629 piece = board[fromY][fromX];
\r
10630 if (piece >= EmptySquare) return;
\r
10632 ScreenSquare(fromX, fromY, &start);
\r
10633 ScreenSquare(toX, toY, &finish);
\r
10635 /* All pieces except knights move in straight line */
\r
10636 if (piece != WhiteKnight && piece != BlackKnight) {
\r
10637 mid.x = start.x + (finish.x - start.x) / 2;
\r
10638 mid.y = start.y + (finish.y - start.y) / 2;
\r
10640 /* Knight: make diagonal movement then straight */
\r
10641 if (abs(toY - fromY) < abs(toX - fromX)) {
\r
10642 mid.x = start.x + (finish.x - start.x) / 2;
\r
10643 mid.y = finish.y;
\r
10645 mid.x = finish.x;
\r
10646 mid.y = start.y + (finish.y - start.y) / 2;
\r
10650 /* Don't use as many frames for very short moves */
\r
10651 if (abs(toY - fromY) + abs(toX - fromX) <= 2)
\r
10652 Tween(&start, &mid, &finish, kFactor - 1, frames, &nFrames);
\r
10654 Tween(&start, &mid, &finish, kFactor, frames, &nFrames);
\r
10656 animInfo.from.x = fromX;
\r
10657 animInfo.from.y = fromY;
\r
10658 animInfo.to.x = toX;
\r
10659 animInfo.to.y = toY;
\r
10660 animInfo.lastpos = start;
\r
10661 animInfo.piece = piece;
\r
10662 for (n = 0; n < nFrames; n++) {
\r
10663 animInfo.pos = frames[n];
\r
10664 DrawPosition(FALSE, NULL);
\r
10665 animInfo.lastpos = animInfo.pos;
\r
10666 Sleep(appData.animSpeed);
\r
10668 animInfo.pos = finish;
\r
10669 DrawPosition(FALSE, NULL);
\r
10670 animInfo.piece = EmptySquare;
\r
10671 if(gameInfo.variant == VariantAtomic && board[toY][toX] != EmptySquare)
\r
10672 AnimateAtomicCapture(toX, toY, 2*nFrames);
\r
10675 /* Convert board position to corner of screen rect and color */
\r
10678 ScreenSquare(column, row, pt)
\r
10679 int column; int row; POINT * pt;
\r
10682 pt->x = lineGap + ((BOARD_WIDTH-1)-column) * (squareSize + lineGap);
\r
10683 pt->y = lineGap + row * (squareSize + lineGap);
\r
10685 pt->x = lineGap + column * (squareSize + lineGap);
\r
10686 pt->y = lineGap + ((BOARD_HEIGHT-1)-row) * (squareSize + lineGap);
\r
10690 /* Generate a series of frame coords from start->mid->finish.
\r
10691 The movement rate doubles until the half way point is
\r
10692 reached, then halves back down to the final destination,
\r
10693 which gives a nice slow in/out effect. The algorithmn
\r
10694 may seem to generate too many intermediates for short
\r
10695 moves, but remember that the purpose is to attract the
\r
10696 viewers attention to the piece about to be moved and
\r
10697 then to where it ends up. Too few frames would be less
\r
10701 Tween(start, mid, finish, factor, frames, nFrames)
\r
10702 POINT * start; POINT * mid;
\r
10703 POINT * finish; int factor;
\r
10704 POINT frames[]; int * nFrames;
\r
10706 int n, fraction = 1, count = 0;
\r
10708 /* Slow in, stepping 1/16th, then 1/8th, ... */
\r
10709 for (n = 0; n < factor; n++)
\r
10711 for (n = 0; n < factor; n++) {
\r
10712 frames[count].x = start->x + (mid->x - start->x) / fraction;
\r
10713 frames[count].y = start->y + (mid->y - start->y) / fraction;
\r
10715 fraction = fraction / 2;
\r
10719 frames[count] = *mid;
\r
10722 /* Slow out, stepping 1/2, then 1/4, ... */
\r
10724 for (n = 0; n < factor; n++) {
\r
10725 frames[count].x = finish->x - (finish->x - mid->x) / fraction;
\r
10726 frames[count].y = finish->y - (finish->y - mid->y) / fraction;
\r
10728 fraction = fraction * 2;
\r
10730 *nFrames = count;
\r
10734 HistorySet( char movelist[][2*MOVE_LEN], int first, int last, int current )
\r
10739 sprintf( buf, "HistorySet: first=%d, last=%d, current=%d (%s)\n",
\r
10740 first, last, current, current >= 0 ? movelist[current] : "n/a" );
\r
10742 OutputDebugString( buf );
\r
10745 MoveHistorySet( movelist, first, last, current, pvInfoList );
\r
10747 EvalGraphSet( first, last, current, pvInfoList );
\r
10750 void SetProgramStats( FrontEndProgramStats * stats )
\r
10755 sprintf( buf, "SetStats for %d: depth=%d, nodes=%lu, score=%5.2f, time=%5.2f, pv=%s\n",
\r
10756 stats->which, stats->depth, stats->nodes, stats->score / 100.0, stats->time / 100.0, stats->pv == 0 ? "n/a" : stats->pv );
\r
10758 OutputDebugString( buf );
\r
10761 EngineOutputUpdate( stats );
\r