2 * WinBoard.c -- Windows NT front end to XBoard
\r
4 * Copyright 1991 by Digital Equipment Corporation, Maynard,
\r
7 * Enhancements Copyright 1992-2001, 2002, 2003, 2004, 2005, 2006,
\r
8 * 2007, 2008, 2009 Free Software Foundation, Inc.
\r
10 * Enhancements Copyright 2005 Alessandro Scotti
\r
12 * XBoard borrows its colors and the bitmaps.xchess bitmap set from XChess,
\r
13 * which was written and is copyrighted by Wayne Christopher.
\r
15 * The following terms apply to Digital Equipment Corporation's copyright
\r
16 * interest in XBoard:
\r
17 * ------------------------------------------------------------------------
\r
18 * All Rights Reserved
\r
20 * Permission to use, copy, modify, and distribute this software and its
\r
21 * documentation for any purpose and without fee is hereby granted,
\r
22 * provided that the above copyright notice appear in all copies and that
\r
23 * both that copyright notice and this permission notice appear in
\r
24 * supporting documentation, and that the name of Digital not be
\r
25 * used in advertising or publicity pertaining to distribution of the
\r
26 * software without specific, written prior permission.
\r
28 * DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
\r
29 * ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
\r
30 * DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
\r
31 * ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
\r
32 * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
\r
33 * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
\r
35 * ------------------------------------------------------------------------
\r
37 * The following terms apply to the enhanced version of XBoard
\r
38 * distributed by the Free Software Foundation:
\r
39 * ------------------------------------------------------------------------
\r
41 * GNU XBoard is free software: you can redistribute it and/or modify
\r
42 * it under the terms of the GNU General Public License as published by
\r
43 * the Free Software Foundation, either version 3 of the License, or (at
\r
44 * your option) any later version.
\r
46 * GNU XBoard is distributed in the hope that it will be useful, but
\r
47 * WITHOUT ANY WARRANTY; without even the implied warranty of
\r
48 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
\r
49 * General Public License for more details.
\r
51 * You should have received a copy of the GNU General Public License
\r
52 * along with this program. If not, see http://www.gnu.org/licenses/. *
\r
54 *------------------------------------------------------------------------
\r
55 ** See the file ChangeLog for a revision history. */
\r
59 #include <windows.h>
\r
60 #include <winuser.h>
\r
61 #include <winsock.h>
\r
62 #include <commctrl.h>
\r
68 #include <sys/stat.h>
\r
71 #include <commdlg.h>
\r
73 #include <richedit.h>
\r
74 #include <mmsystem.h>
\r
83 #include "frontend.h"
\r
84 #include "backend.h"
\r
85 #include "winboard.h"
\r
87 #include "wclipbrd.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
101 extern HANDLE chatHandle[];
\r
102 extern int ics_type;
\r
104 void DisplayHoldingsCount(HDC hdc, int x, int y, int align, int copyNumber);
\r
105 VOID NewVariantPopup(HWND hwnd);
\r
106 int FinishMove P((ChessMove moveType, int fromX, int fromY, int toX, int toY,
\r
107 /*char*/int promoChar));
\r
108 void AnimateAtomicCapture(int fromX, int fromY, int toX, int toY, int nFrames);
\r
109 void DisplayMove P((int moveNumber));
\r
110 Boolean ParseFEN P((Board board, int *blackPlaysFirst, char *fen));
\r
111 void ChatPopUp P(());
\r
113 ChessSquare piece;
\r
114 POINT pos; /* window coordinates of current pos */
\r
115 POINT lastpos; /* window coordinates of last pos - used for clipping */
\r
116 POINT from; /* board coordinates of the piece's orig pos */
\r
117 POINT to; /* board coordinates of the piece's new pos */
\r
120 static AnimInfo animInfo = { EmptySquare, {-1,-1}, {-1,-1}, {-1,-1} };
\r
123 POINT start; /* window coordinates of start pos */
\r
124 POINT pos; /* window coordinates of current pos */
\r
125 POINT lastpos; /* window coordinates of last pos - used for clipping */
\r
126 POINT from; /* board coordinates of the piece's orig pos */
\r
129 static DragInfo dragInfo = { {-1,-1}, {-1,-1}, {-1,-1}, {-1,-1} };
\r
132 POINT sq[2]; /* board coordinates of from, to squares */
\r
135 static HighlightInfo highlightInfo = { {{-1, -1}, {-1, -1}} };
\r
136 static HighlightInfo premoveHighlightInfo = { {{-1, -1}, {-1, -1}} };
\r
138 typedef struct { // [HGM] atomic
\r
139 int fromX, fromY, toX, toY, radius;
\r
142 static ExplodeInfo explodeInfo;
\r
144 /* Window class names */
\r
145 char szAppName[] = "WinBoard";
\r
146 char szConsoleName[] = "WBConsole";
\r
148 /* Title bar text */
\r
149 char szTitle[] = "WinBoard";
\r
150 char szConsoleTitle[] = "I C S Interaction";
\r
153 char *settingsFileName;
\r
154 Boolean saveSettingsOnExit;
\r
155 char installDir[MSG_SIZ];
\r
156 int errorExitStatus;
\r
158 BoardSize boardSize;
\r
159 Boolean chessProgram;
\r
160 //static int boardX, boardY;
\r
161 int minX, minY; // [HGM] placement: volatile limits on upper-left corner
\r
162 static int squareSize, lineGap, minorSize;
\r
163 static int winW, winH;
\r
164 static RECT messageRect, whiteRect, blackRect, leftLogoRect, rightLogoRect; // [HGM] logo
\r
165 static int logoHeight = 0;
\r
166 static char messageText[MESSAGE_TEXT_MAX];
\r
167 static int clockTimerEvent = 0;
\r
168 static int loadGameTimerEvent = 0;
\r
169 static int analysisTimerEvent = 0;
\r
170 static DelayedEventCallback delayedTimerCallback;
\r
171 static int delayedTimerEvent = 0;
\r
172 static int buttonCount = 2;
\r
173 char *icsTextMenuString;
\r
175 char *firstChessProgramNames;
\r
176 char *secondChessProgramNames;
\r
178 #define PALETTESIZE 256
\r
180 HINSTANCE hInst; /* current instance */
\r
181 Boolean alwaysOnTop = FALSE;
\r
183 COLORREF lightSquareColor, darkSquareColor, whitePieceColor,
\r
184 blackPieceColor, highlightSquareColor, premoveHighlightColor;
\r
186 ColorClass currentColorClass;
\r
188 HWND hCommPort = NULL; /* currently open comm port */
\r
189 static HWND hwndPause; /* pause button */
\r
190 static HBITMAP pieceBitmap[3][(int) BlackPawn]; /* [HGM] nr of bitmaps referred to bP in stead of wK */
\r
191 static HBRUSH lightSquareBrush, darkSquareBrush,
\r
192 blackSquareBrush, /* [HGM] for band between board and holdings */
\r
193 explodeBrush, /* [HGM] atomic */
\r
194 whitePieceBrush, blackPieceBrush, iconBkgndBrush /*, outlineBrush*/;
\r
195 static POINT gridEndpoints[(BOARD_RANKS + BOARD_FILES + 2) * 2];
\r
196 static DWORD gridVertexCounts[BOARD_RANKS + BOARD_FILES + 2];
\r
197 static HPEN gridPen = NULL;
\r
198 static HPEN highlightPen = NULL;
\r
199 static HPEN premovePen = NULL;
\r
200 static NPLOGPALETTE pLogPal;
\r
201 static BOOL paletteChanged = FALSE;
\r
202 static HICON iconWhite, iconBlack, iconCurrent;
\r
203 static int doingSizing = FALSE;
\r
204 static int lastSizing = 0;
\r
205 static int prevStderrPort;
\r
206 static HBITMAP userLogo;
\r
208 static HBITMAP liteBackTexture = NULL;
\r
209 static HBITMAP darkBackTexture = NULL;
\r
210 static int liteBackTextureMode = BACK_TEXTURE_MODE_PLAIN;
\r
211 static int darkBackTextureMode = BACK_TEXTURE_MODE_PLAIN;
\r
212 static int backTextureSquareSize = 0;
\r
213 static struct { int x; int y; int mode; } backTextureSquareInfo[BOARD_RANKS][BOARD_FILES];
\r
215 #if __GNUC__ && !defined(_winmajor)
\r
216 #define oldDialog 0 /* cygwin doesn't define _winmajor; mingw does */
\r
218 #if defined(_winmajor)
\r
219 #define oldDialog (_winmajor < 4)
\r
221 #define oldDialog 0
\r
231 int cliWidth, cliHeight;
\r
234 SizeInfo sizeInfo[] =
\r
236 { "tiny", 21, 0, 1, 1, 0, 0 },
\r
237 { "teeny", 25, 1, 1, 1, 0, 0 },
\r
238 { "dinky", 29, 1, 1, 1, 0, 0 },
\r
239 { "petite", 33, 1, 1, 1, 0, 0 },
\r
240 { "slim", 37, 2, 1, 0, 0, 0 },
\r
241 { "small", 40, 2, 1, 0, 0, 0 },
\r
242 { "mediocre", 45, 2, 1, 0, 0, 0 },
\r
243 { "middling", 49, 2, 0, 0, 0, 0 },
\r
244 { "average", 54, 2, 0, 0, 0, 0 },
\r
245 { "moderate", 58, 3, 0, 0, 0, 0 },
\r
246 { "medium", 64, 3, 0, 0, 0, 0 },
\r
247 { "bulky", 72, 3, 0, 0, 0, 0 },
\r
248 { "large", 80, 3, 0, 0, 0, 0 },
\r
249 { "big", 87, 3, 0, 0, 0, 0 },
\r
250 { "huge", 95, 3, 0, 0, 0, 0 },
\r
251 { "giant", 108, 3, 0, 0, 0, 0 },
\r
252 { "colossal", 116, 4, 0, 0, 0, 0 },
\r
253 { "titanic", 129, 4, 0, 0, 0, 0 },
\r
254 { NULL, 0, 0, 0, 0, 0, 0 }
\r
257 #define MF(x) {x, {{0,}, 0. }, {0, }, 0}
\r
258 MyFont fontRec[NUM_SIZES][NUM_FONTS] =
\r
260 { 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
261 { 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
262 { 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
263 { 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
264 { 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
265 { 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
266 { 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
267 { 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
268 { 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
269 { 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
270 { 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
271 { 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
272 { 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
273 { 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
274 { 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
275 { 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
276 { 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
277 { 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
280 MyFont *font[NUM_SIZES][NUM_FONTS];
\r
289 #define BUTTON_WIDTH (tinyLayout ? 16 : 32)
\r
290 #define N_BUTTONS 5
\r
292 MyButtonDesc buttonDesc[N_BUTTONS] =
\r
294 {"<<", IDM_ToStart, NULL, NULL},
\r
295 {"<", IDM_Backward, NULL, NULL},
\r
296 {"P", IDM_Pause, NULL, NULL},
\r
297 {">", IDM_Forward, NULL, NULL},
\r
298 {">>", IDM_ToEnd, NULL, NULL},
\r
301 int tinyLayout = 0, smallLayout = 0;
\r
302 #define MENU_BAR_ITEMS 7
\r
303 char *menuBarText[2][MENU_BAR_ITEMS+1] = {
\r
304 { "&File", "&Mode", "&Action", "&Step", "&Options", "&Help", NULL },
\r
305 { "&F", "&M", "&A", "&S", "&O", "&H", NULL },
\r
309 MySound sounds[(int)NSoundClasses];
\r
310 MyTextAttribs textAttribs[(int)NColorClasses];
\r
312 MyColorizeAttribs colorizeAttribs[] = {
\r
313 { (COLORREF)0, 0, "Shout Text" },
\r
314 { (COLORREF)0, 0, "SShout/CShout" },
\r
315 { (COLORREF)0, 0, "Channel 1 Text" },
\r
316 { (COLORREF)0, 0, "Channel Text" },
\r
317 { (COLORREF)0, 0, "Kibitz Text" },
\r
318 { (COLORREF)0, 0, "Tell Text" },
\r
319 { (COLORREF)0, 0, "Challenge Text" },
\r
320 { (COLORREF)0, 0, "Request Text" },
\r
321 { (COLORREF)0, 0, "Seek Text" },
\r
322 { (COLORREF)0, 0, "Normal Text" },
\r
323 { (COLORREF)0, 0, "None" }
\r
328 static char *commentTitle;
\r
329 static char *commentText;
\r
330 static int commentIndex;
\r
331 static Boolean editComment = FALSE;
\r
334 char errorTitle[MSG_SIZ];
\r
335 char errorMessage[2*MSG_SIZ];
\r
336 HWND errorDialog = NULL;
\r
337 BOOLEAN moveErrorMessageUp = FALSE;
\r
338 BOOLEAN consoleEcho = TRUE;
\r
339 CHARFORMAT consoleCF;
\r
340 COLORREF consoleBackgroundColor;
\r
342 char *programVersion;
\r
348 typedef int CPKind;
\r
357 SOCKET sock2; /* stderr socket for OpenRcmd */
\r
360 #define INPUT_SOURCE_BUF_SIZE 4096
\r
362 typedef struct _InputSource {
\r
369 char buf[INPUT_SOURCE_BUF_SIZE];
\r
373 InputCallback func;
\r
374 struct _InputSource *second; /* for stderr thread on CPRcmd */
\r
378 InputSource *consoleInputSource;
\r
383 VOID ConsoleOutput(char* data, int length, int forceVisible);
\r
384 VOID ConsoleCreate();
\r
386 ConsoleWndProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);
\r
387 VOID ColorizeTextPopup(HWND hwnd, ColorClass cc);
\r
388 VOID PrintCommSettings(FILE *f, char *name, DCB *dcb);
\r
389 VOID ParseCommSettings(char *arg, DCB *dcb);
\r
391 StartupDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);
\r
392 VOID APIENTRY MenuPopup(HWND hwnd, POINT pt, HMENU hmenu, UINT def);
\r
393 void ParseIcsTextMenu(char *icsTextMenuString);
\r
394 VOID PopUpMoveDialog(char firstchar);
\r
395 VOID PopUpNameDialog(char firstchar);
\r
396 VOID UpdateSampleText(HWND hDlg, int id, MyColorizeAttribs *mca);
\r
400 int GameListOptions();
\r
402 int dummy; // [HGM] for obsolete args
\r
404 HWND hwndMain = NULL; /* root window*/
\r
405 HWND hwndConsole = NULL;
\r
406 HWND commentDialog = NULL;
\r
407 HWND moveHistoryDialog = NULL;
\r
408 HWND evalGraphDialog = NULL;
\r
409 HWND engineOutputDialog = NULL;
\r
410 HWND gameListDialog = NULL;
\r
411 HWND editTagsDialog = NULL;
\r
413 int commentUp = FALSE;
\r
415 WindowPlacement wpMain;
\r
416 WindowPlacement wpConsole;
\r
417 WindowPlacement wpComment;
\r
418 WindowPlacement wpMoveHistory;
\r
419 WindowPlacement wpEvalGraph;
\r
420 WindowPlacement wpEngineOutput;
\r
421 WindowPlacement wpGameList;
\r
422 WindowPlacement wpTags;
\r
424 VOID EngineOptionsPopup(); // [HGM] settings
\r
426 VOID GothicPopUp(char *title, VariantClass variant);
\r
428 * Setting "frozen" should disable all user input other than deleting
\r
429 * the window. We do this while engines are initializing themselves.
\r
431 static int frozen = 0;
\r
432 static int oldMenuItemState[MENU_BAR_ITEMS];
\r
438 if (frozen) return;
\r
440 hmenu = GetMenu(hwndMain);
\r
441 for (i=0; i<MENU_BAR_ITEMS; i++) {
\r
442 oldMenuItemState[i] = EnableMenuItem(hmenu, i, MF_BYPOSITION|MF_GRAYED);
\r
444 DrawMenuBar(hwndMain);
\r
447 /* Undo a FreezeUI */
\r
453 if (!frozen) return;
\r
455 hmenu = GetMenu(hwndMain);
\r
456 for (i=0; i<MENU_BAR_ITEMS; i++) {
\r
457 EnableMenuItem(hmenu, i, MF_BYPOSITION|oldMenuItemState[i]);
\r
459 DrawMenuBar(hwndMain);
\r
462 /*static*/ int fromX = -1, fromY = -1, toX, toY; // [HGM] moved upstream, so JAWS can use them
\r
464 /* JAWS preparation patch (WinBoard for the sight impaired). Define required insertions as empty */
\r
470 #define JAWS_ALT_INTERCEPT
\r
471 #define JAWS_KB_NAVIGATION
\r
472 #define JAWS_MENU_ITEMS
\r
473 #define JAWS_SILENCE
\r
474 #define JAWS_REPLAY
\r
476 #define JAWS_COPYRIGHT
\r
477 #define JAWS_DELETE(X) X
\r
478 #define SAYMACHINEMOVE()
\r
482 /*---------------------------------------------------------------------------*\
\r
486 \*---------------------------------------------------------------------------*/
\r
489 WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
\r
490 LPSTR lpCmdLine, int nCmdShow)
\r
493 HANDLE hAccelMain, hAccelNoAlt, hAccelNoICS;
\r
494 // INITCOMMONCONTROLSEX ex;
\r
498 LoadLibrary("RICHED32.DLL");
\r
499 consoleCF.cbSize = sizeof(CHARFORMAT);
\r
501 if (!InitApplication(hInstance)) {
\r
504 if (!InitInstance(hInstance, nCmdShow, lpCmdLine)) {
\r
510 // InitCommonControlsEx(&ex);
\r
511 InitCommonControls();
\r
513 hAccelMain = LoadAccelerators (hInstance, szAppName);
\r
514 hAccelNoAlt = LoadAccelerators (hInstance, "NO_ALT");
\r
515 hAccelNoICS = LoadAccelerators( hInstance, "NO_ICS"); /* [AS] No Ctrl-V on ICS!!! */
\r
517 /* Acquire and dispatch messages until a WM_QUIT message is received. */
\r
519 while (GetMessage(&msg, /* message structure */
\r
520 NULL, /* handle of window receiving the message */
\r
521 0, /* lowest message to examine */
\r
522 0)) /* highest message to examine */
\r
525 if(msg.message == WM_CHAR && msg.wParam == '\t') {
\r
526 // [HGM] navigate: switch between all windows with tab
\r
527 HWND e1 = NULL, e2 = NULL, mh = NULL, hInput = NULL, hText = NULL;
\r
528 int i, currentElement = 0;
\r
530 // first determine what element of the chain we come from (if any)
\r
531 if(appData.icsActive) {
\r
532 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
533 hText = GetDlgItem(hwndConsole, OPT_ConsoleText);
\r
535 if(engineOutputDialog && EngineOutputIsUp()) {
\r
536 e1 = GetDlgItem(engineOutputDialog, IDC_EngineMemo1);
\r
537 e2 = GetDlgItem(engineOutputDialog, IDC_EngineMemo2);
\r
539 if(moveHistoryDialog && MoveHistoryIsUp()) {
\r
540 mh = GetDlgItem(moveHistoryDialog, IDC_MoveHistory);
\r
542 if(msg.hwnd == hwndMain) currentElement = 7 ; else
\r
543 if(msg.hwnd == engineOutputDialog) currentElement = 2; else
\r
544 if(msg.hwnd == e1) currentElement = 2; else
\r
545 if(msg.hwnd == e2) currentElement = 3; else
\r
546 if(msg.hwnd == moveHistoryDialog) currentElement = 4; else
\r
547 if(msg.hwnd == mh) currentElement = 4; else
\r
548 if(msg.hwnd == evalGraphDialog) currentElement = 6; else
\r
549 if(msg.hwnd == hText) currentElement = 5; else
\r
550 if(msg.hwnd == hInput) currentElement = 6; else
\r
551 for (i = 0; i < N_BUTTONS; i++) {
\r
552 if (buttonDesc[i].hwnd == msg.hwnd) { currentElement = 1; break; }
\r
555 // determine where to go to
\r
556 if(currentElement) { HWND h = NULL; int direction = GetKeyState(VK_SHIFT) < 0 ? -1 : 1;
\r
558 currentElement = (currentElement + direction) % 7;
\r
559 switch(currentElement) {
\r
561 h = hwndMain; break; // passing this case always makes the loop exit
\r
563 h = buttonDesc[0].hwnd; break; // could be NULL
\r
565 if(!EngineOutputIsUp()) continue; // skip closed auxiliary windows
\r
568 if(!EngineOutputIsUp()) continue;
\r
571 if(!MoveHistoryIsUp()) continue;
\r
573 // case 6: // input to eval graph does not seem to get here!
\r
574 // if(!EvalGraphIsUp()) continue;
\r
575 // h = evalGraphDialog; break;
\r
577 if(!appData.icsActive) continue;
\r
581 if(!appData.icsActive) continue;
\r
587 if(currentElement > 4 && IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
588 if(currentElement < 5 && IsIconic(hwndMain)) ShowWindow(hwndMain, SW_RESTORE); // all open together
\r
591 continue; // this message now has been processed
\r
595 if (!(commentDialog && IsDialogMessage(commentDialog, &msg)) &&
\r
596 !(moveHistoryDialog && IsDialogMessage(moveHistoryDialog, &msg)) &&
\r
597 !(evalGraphDialog && IsDialogMessage(evalGraphDialog, &msg)) &&
\r
598 !(engineOutputDialog && IsDialogMessage(engineOutputDialog, &msg)) &&
\r
599 !(editTagsDialog && IsDialogMessage(editTagsDialog, &msg)) &&
\r
600 !(gameListDialog && IsDialogMessage(gameListDialog, &msg)) &&
\r
601 !(errorDialog && IsDialogMessage(errorDialog, &msg)) &&
\r
602 !(!frozen && TranslateAccelerator(hwndMain, hAccelMain, &msg)) && JAWS_ACCEL
\r
603 !(!hwndConsole && TranslateAccelerator(hwndMain, hAccelNoICS, &msg)) &&
\r
604 !(!hwndConsole && TranslateAccelerator(hwndMain, hAccelNoAlt, &msg))) {
\r
605 int done = 0, i; // [HGM] chat: dispatch cat-box messages
\r
606 for(i=0; i<MAX_CHAT; i++)
\r
607 if(chatHandle[i] && IsDialogMessage(chatHandle[i], &msg)) {
\r
610 if(done) continue; // [HGM] chat: end patch
\r
611 TranslateMessage(&msg); /* Translates virtual key codes */
\r
612 DispatchMessage(&msg); /* Dispatches message to window */
\r
617 return (msg.wParam); /* Returns the value from PostQuitMessage */
\r
620 /*---------------------------------------------------------------------------*\
\r
622 * Initialization functions
\r
624 \*---------------------------------------------------------------------------*/
\r
628 { // update user logo if necessary
\r
629 static char oldUserName[MSG_SIZ], *curName;
\r
631 if(appData.autoLogo) {
\r
632 curName = UserName();
\r
633 if(strcmp(curName, oldUserName)) {
\r
634 sprintf(oldUserName, "logos\\%s.bmp", curName);
\r
635 userLogo = LoadImage( 0, oldUserName, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
636 strcpy(oldUserName, curName);
\r
642 InitApplication(HINSTANCE hInstance)
\r
646 /* Fill in window class structure with parameters that describe the */
\r
649 wc.style = CS_HREDRAW | CS_VREDRAW; /* Class style(s). */
\r
650 wc.lpfnWndProc = (WNDPROC)WndProc; /* Window Procedure */
\r
651 wc.cbClsExtra = 0; /* No per-class extra data. */
\r
652 wc.cbWndExtra = 0; /* No per-window extra data. */
\r
653 wc.hInstance = hInstance; /* Owner of this class */
\r
654 wc.hIcon = LoadIcon(hInstance, "icon_white");
\r
655 wc.hCursor = LoadCursor(NULL, IDC_ARROW); /* Cursor */
\r
656 wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1); /* Default color */
\r
657 wc.lpszMenuName = szAppName; /* Menu name from .RC */
\r
658 wc.lpszClassName = szAppName; /* Name to register as */
\r
660 /* Register the window class and return success/failure code. */
\r
661 if (!RegisterClass(&wc)) return FALSE;
\r
663 wc.style = CS_HREDRAW | CS_VREDRAW;
\r
664 wc.lpfnWndProc = (WNDPROC)ConsoleWndProc;
\r
666 wc.cbWndExtra = DLGWINDOWEXTRA;
\r
667 wc.hInstance = hInstance;
\r
668 wc.hIcon = LoadIcon(hInstance, "icon_white");
\r
669 wc.hCursor = LoadCursor(NULL, IDC_ARROW);
\r
670 wc.hbrBackground = (HBRUSH)(COLOR_MENU+1);
\r
671 wc.lpszMenuName = NULL;
\r
672 wc.lpszClassName = szConsoleName;
\r
674 if (!RegisterClass(&wc)) return FALSE;
\r
679 /* Set by InitInstance, used by EnsureOnScreen */
\r
680 int screenHeight, screenWidth;
\r
683 EnsureOnScreen(int *x, int *y, int minX, int minY)
\r
685 // int gap = GetSystemMetrics(SM_CYFRAME) + GetSystemMetrics(SM_CYCAPTION);
\r
686 /* Be sure window at (x,y) is not off screen (or even mostly off screen) */
\r
687 if (*x > screenWidth - 32) *x = 0;
\r
688 if (*y > screenHeight - 32) *y = 0;
\r
689 if (*x < minX) *x = minX;
\r
690 if (*y < minY) *y = minY;
\r
694 InitInstance(HINSTANCE hInstance, int nCmdShow, LPSTR lpCmdLine)
\r
696 HWND hwnd; /* Main window handle. */
\r
698 WINDOWPLACEMENT wp;
\r
701 hInst = hInstance; /* Store instance handle in our global variable */
\r
702 programName = szAppName;
\r
704 if (SearchPath(NULL, "WinBoard.exe", NULL, MSG_SIZ, installDir, &filepart)) {
\r
705 *filepart = NULLCHAR;
\r
707 GetCurrentDirectory(MSG_SIZ, installDir);
\r
709 gameInfo.boardWidth = gameInfo.boardHeight = 8; // [HGM] won't have open window otherwise
\r
710 screenWidth = screenHeight = 1000; // [HGM] placement: kludge to allow calling EnsureOnScreen from InitAppData
\r
711 InitAppData(lpCmdLine); /* Get run-time parameters */
\r
712 /* xboard, and older WinBoards, controlled the move sound with the
\r
713 appData.ringBellAfterMoves option. In the current WinBoard, we
\r
714 always turn the option on (so that the backend will call us),
\r
715 then let the user turn the sound off by setting it to silence if
\r
716 desired. To accommodate old winboard.ini files saved by old
\r
717 versions of WinBoard, we also turn off the sound if the option
\r
718 was initially set to false. [HGM] taken out of InitAppData */
\r
719 if (!appData.ringBellAfterMoves) {
\r
720 sounds[(int)SoundMove].name = strdup("");
\r
721 appData.ringBellAfterMoves = TRUE;
\r
723 if (appData.debugMode) {
\r
724 debugFP = fopen(appData.nameOfDebugFile, "w");
\r
725 setbuf(debugFP, NULL);
\r
730 // InitEngineUCI( installDir, &first ); // [HGM] incorporated in InitBackEnd1()
\r
731 // InitEngineUCI( installDir, &second );
\r
733 /* Create a main window for this application instance. */
\r
734 hwnd = CreateWindow(szAppName, szTitle,
\r
735 (WS_OVERLAPPEDWINDOW & ~WS_MAXIMIZEBOX),
\r
736 CW_USEDEFAULT, 0, CW_USEDEFAULT, 0,
\r
737 NULL, NULL, hInstance, NULL);
\r
740 /* If window could not be created, return "failure" */
\r
745 /* [HGM] logo: Load logos if specified (must be done before InitDrawingSizes) */
\r
746 if( appData.firstLogo && appData.firstLogo[0] != NULLCHAR) {
\r
747 first.programLogo = LoadImage( 0, appData.firstLogo, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
749 if (first.programLogo == NULL && appData.debugMode) {
\r
750 fprintf( debugFP, "Unable to load logo bitmap '%s'\n", appData.firstLogo );
\r
752 } else if(appData.autoLogo) {
\r
753 if(appData.firstDirectory && appData.firstDirectory[0]) {
\r
755 sprintf(buf, "%s/logo.bmp", appData.firstDirectory);
\r
756 first.programLogo = LoadImage( 0, buf, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
760 if( appData.secondLogo && appData.secondLogo[0] != NULLCHAR) {
\r
761 second.programLogo = LoadImage( 0, appData.secondLogo, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
763 if (second.programLogo == NULL && appData.debugMode) {
\r
764 fprintf( debugFP, "Unable to load logo bitmap '%s'\n", appData.secondLogo );
\r
766 } else if(appData.autoLogo) {
\r
768 if(appData.icsActive) { // [HGM] logo: in ICS mode second can be used for ICS
\r
769 sprintf(buf, "logos\\%s.bmp", appData.icsHost);
\r
770 second.programLogo = LoadImage( 0, buf, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
772 if(appData.secondDirectory && appData.secondDirectory[0]) {
\r
773 sprintf(buf, "%s\\logo.bmp", appData.secondDirectory);
\r
774 second.programLogo = LoadImage( 0, buf, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
780 iconWhite = LoadIcon(hInstance, "icon_white");
\r
781 iconBlack = LoadIcon(hInstance, "icon_black");
\r
782 iconCurrent = iconWhite;
\r
783 InitDrawingColors();
\r
784 screenHeight = GetSystemMetrics(SM_CYSCREEN);
\r
785 screenWidth = GetSystemMetrics(SM_CXSCREEN);
\r
786 for (ibs = (int) NUM_SIZES - 1; ibs >= 0; ibs--) {
\r
787 /* Compute window size for each board size, and use the largest
\r
788 size that fits on this screen as the default. */
\r
789 InitDrawingSizes((BoardSize)(ibs+1000), 0);
\r
790 if (boardSize == (BoardSize)-1 &&
\r
791 winH <= screenHeight
\r
792 - GetSystemMetrics(SM_CYFRAME) - GetSystemMetrics(SM_CYCAPTION) - 10
\r
793 && winW <= screenWidth) {
\r
794 boardSize = (BoardSize)ibs;
\r
798 InitDrawingSizes(boardSize, 0);
\r
800 buttonCount = GetSystemMetrics(SM_CMOUSEBUTTONS);
\r
802 /* [AS] Load textures if specified */
\r
803 ZeroMemory( &backTextureSquareInfo, sizeof(backTextureSquareInfo) );
\r
805 if( appData.liteBackTextureFile && appData.liteBackTextureFile[0] != NULLCHAR && appData.liteBackTextureFile[0] != '*' ) {
\r
806 liteBackTexture = LoadImage( 0, appData.liteBackTextureFile, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
807 liteBackTextureMode = appData.liteBackTextureMode;
\r
809 if (liteBackTexture == NULL && appData.debugMode) {
\r
810 fprintf( debugFP, "Unable to load lite texture bitmap '%s'\n", appData.liteBackTextureFile );
\r
814 if( appData.darkBackTextureFile && appData.darkBackTextureFile[0] != NULLCHAR && appData.darkBackTextureFile[0] != '*' ) {
\r
815 darkBackTexture = LoadImage( 0, appData.darkBackTextureFile, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
816 darkBackTextureMode = appData.darkBackTextureMode;
\r
818 if (darkBackTexture == NULL && appData.debugMode) {
\r
819 fprintf( debugFP, "Unable to load dark texture bitmap '%s'\n", appData.darkBackTextureFile );
\r
823 mysrandom( (unsigned) time(NULL) );
\r
825 /* [AS] Restore layout */
\r
826 if( wpMoveHistory.visible ) {
\r
827 MoveHistoryPopUp();
\r
830 if( wpEvalGraph.visible ) {
\r
834 if( wpEngineOutput.visible ) {
\r
835 EngineOutputPopUp();
\r
840 /* Make the window visible; update its client area; and return "success" */
\r
841 EnsureOnScreen(&wpMain.x, &wpMain.y, minX, minY);
\r
842 wp.length = sizeof(WINDOWPLACEMENT);
\r
844 wp.showCmd = nCmdShow;
\r
845 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
846 wp.rcNormalPosition.left = wpMain.x;
\r
847 wp.rcNormalPosition.right = wpMain.x + wpMain.width;
\r
848 wp.rcNormalPosition.top = wpMain.y;
\r
849 wp.rcNormalPosition.bottom = wpMain.y + wpMain.height;
\r
850 SetWindowPlacement(hwndMain, &wp);
\r
852 if(!appData.noGUI) SetWindowPos(hwndMain, alwaysOnTop ? HWND_TOPMOST : HWND_NOTOPMOST,
\r
853 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE);
\r
857 SetWindowPos(hwndConsole, alwaysOnTop ? HWND_TOPMOST : HWND_NOTOPMOST,
\r
858 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE);
\r
860 ShowWindow(hwndConsole, nCmdShow);
\r
862 if(!appData.noGUI) UpdateWindow(hwnd); else ShowWindow(hwnd, SW_MINIMIZE);
\r
863 if(gameListDialog) SetFocus(gameListDialog); // [HGM] jaws: for if we clicked multi-game game file
\r
872 HMENU hmenu = GetMenu(hwndMain);
\r
874 (void) EnableMenuItem(hmenu, IDM_CommPort,
\r
875 MF_BYCOMMAND|((appData.icsActive &&
\r
876 *appData.icsCommPort != NULLCHAR) ?
\r
877 MF_ENABLED : MF_GRAYED));
\r
878 (void) CheckMenuItem(hmenu, IDM_SaveSettingsOnExit,
\r
879 MF_BYCOMMAND|(saveSettingsOnExit ?
\r
880 MF_CHECKED : MF_UNCHECKED));
\r
883 //---------------------------------------------------------------------------------------------------------
\r
885 #define ICS_TEXT_MENU_SIZE (IDM_CommandXLast - IDM_CommandX + 1)
\r
886 #define XBOARD FALSE
\r
888 #define OPTCHAR "/"
\r
889 #define SEPCHAR "="
\r
893 // front-end part of option handling
\r
896 LFfromMFP(LOGFONT* lf, MyFontParams *mfp)
\r
898 HDC hdc = CreateDC("DISPLAY", NULL, NULL, NULL);
\r
899 lf->lfHeight = -(int)(mfp->pointSize * GetDeviceCaps(hdc, LOGPIXELSY) / 72.0 + 0.5);
\r
902 lf->lfEscapement = 0;
\r
903 lf->lfOrientation = 0;
\r
904 lf->lfWeight = mfp->bold ? FW_BOLD : FW_NORMAL;
\r
905 lf->lfItalic = mfp->italic;
\r
906 lf->lfUnderline = mfp->underline;
\r
907 lf->lfStrikeOut = mfp->strikeout;
\r
908 lf->lfCharSet = mfp->charset;
\r
909 lf->lfOutPrecision = OUT_DEFAULT_PRECIS;
\r
910 lf->lfClipPrecision = CLIP_DEFAULT_PRECIS;
\r
911 lf->lfQuality = DEFAULT_QUALITY;
\r
912 lf->lfPitchAndFamily = DEFAULT_PITCH|FF_DONTCARE;
\r
913 strcpy(lf->lfFaceName, mfp->faceName);
\r
917 CreateFontInMF(MyFont *mf)
\r
919 LFfromMFP(&mf->lf, &mf->mfp);
\r
920 if (mf->hf) DeleteObject(mf->hf);
\r
921 mf->hf = CreateFontIndirect(&mf->lf);
\r
924 // [HGM] This platform-dependent table provides the location for storing the color info
\r
926 colorVariable[] = {
\r
931 &highlightSquareColor,
\r
932 &premoveHighlightColor,
\r
934 &consoleBackgroundColor,
\r
935 &appData.fontForeColorWhite,
\r
936 &appData.fontBackColorWhite,
\r
937 &appData.fontForeColorBlack,
\r
938 &appData.fontBackColorBlack,
\r
939 &appData.evalHistColorWhite,
\r
940 &appData.evalHistColorBlack,
\r
941 &appData.highlightArrowColor,
\r
944 /* Command line font name parser. NULL name means do nothing.
\r
945 Syntax like "Courier New:10.0 bi" or "Arial:10" or "Arial:10b"
\r
946 For backward compatibility, syntax without the colon is also
\r
947 accepted, but font names with digits in them won't work in that case.
\r
950 ParseFontName(char *name, MyFontParams *mfp)
\r
953 if (name == NULL) return;
\r
955 q = strchr(p, ':');
\r
957 if (q - p >= sizeof(mfp->faceName))
\r
958 ExitArgError("Font name too long:", name);
\r
959 memcpy(mfp->faceName, p, q - p);
\r
960 mfp->faceName[q - p] = NULLCHAR;
\r
964 while (*p && !isdigit(*p)) {
\r
966 if (q - mfp->faceName >= sizeof(mfp->faceName))
\r
967 ExitArgError("Font name too long:", name);
\r
969 while (q > mfp->faceName && q[-1] == ' ') q--;
\r
972 if (!*p) ExitArgError("Font point size missing:", name);
\r
973 mfp->pointSize = (float) atof(p);
\r
974 mfp->bold = (strchr(p, 'b') != NULL);
\r
975 mfp->italic = (strchr(p, 'i') != NULL);
\r
976 mfp->underline = (strchr(p, 'u') != NULL);
\r
977 mfp->strikeout = (strchr(p, 's') != NULL);
\r
978 mfp->charset = DEFAULT_CHARSET;
\r
979 q = strchr(p, 'c');
\r
981 mfp->charset = (BYTE) atoi(q+1);
\r
985 ParseFont(char *name, int number)
\r
986 { // wrapper to shield back-end from 'font'
\r
987 ParseFontName(name, &font[boardSize][number]->mfp);
\r
992 { // in WB we have a 2D array of fonts; this initializes their description
\r
994 /* Point font array elements to structures and
\r
995 parse default font names */
\r
996 for (i=0; i<NUM_FONTS; i++) {
\r
997 for (j=0; j<NUM_SIZES; j++) {
\r
998 font[j][i] = &fontRec[j][i];
\r
999 ParseFontName(font[j][i]->def, &font[j][i]->mfp);
\r
1006 { // here we create the actual fonts from the selected descriptions
\r
1008 for (i=0; i<NUM_FONTS; i++) {
\r
1009 for (j=0; j<NUM_SIZES; j++) {
\r
1010 CreateFontInMF(font[j][i]);
\r
1014 /* Color name parser.
\r
1015 X version accepts X color names, but this one
\r
1016 handles only the #rrggbb form (hex) or rrr,ggg,bbb (decimal) */
\r
1018 ParseColorName(char *name)
\r
1020 int red, green, blue, count;
\r
1021 char buf[MSG_SIZ];
\r
1023 count = sscanf(name, "#%2x%2x%2x", &red, &green, &blue);
\r
1025 count = sscanf(name, "%3d%*[^0-9]%3d%*[^0-9]%3d",
\r
1026 &red, &green, &blue);
\r
1029 sprintf(buf, "Can't parse color name %s", name);
\r
1030 DisplayError(buf, 0);
\r
1031 return RGB(0, 0, 0);
\r
1033 return PALETTERGB(red, green, blue);
\r
1037 ParseColor(int n, char *name)
\r
1038 { // for WinBoard the color is an int, which needs to be derived from the string
\r
1039 if(colorVariable[n]) *(int*)colorVariable[n] = ParseColorName(name);
\r
1043 ParseAttribs(COLORREF *color, int *effects, char* argValue)
\r
1045 char *e = argValue;
\r
1049 if (*e == 'b') eff |= CFE_BOLD;
\r
1050 else if (*e == 'i') eff |= CFE_ITALIC;
\r
1051 else if (*e == 'u') eff |= CFE_UNDERLINE;
\r
1052 else if (*e == 's') eff |= CFE_STRIKEOUT;
\r
1053 else if (*e == '#' || isdigit(*e)) break;
\r
1057 *color = ParseColorName(e);
\r
1061 ParseTextAttribs(ColorClass cc, char *s)
\r
1062 { // [HGM] front-end wrapper that does the platform-dependent call
\r
1063 // for XBoard we would set (&appData.colorShout)[cc] = strdup(s);
\r
1064 ParseAttribs(&textAttribs[cc].color, &textAttribs[cc].effects, s);
\r
1068 ParseBoardSize(void *addr, char *name)
\r
1069 { // [HGM] rewritten with return-value ptr to shield back-end from BoardSize
\r
1070 BoardSize bs = SizeTiny;
\r
1071 while (sizeInfo[bs].name != NULL) {
\r
1072 if (StrCaseCmp(name, sizeInfo[bs].name) == 0) {
\r
1073 *(BoardSize *)addr = bs;
\r
1078 ExitArgError("Unrecognized board size value", name);
\r
1083 { // [HGM] import name from appData first
\r
1086 for (cc = (ColorClass)0; cc < ColorNormal; cc++) {
\r
1087 textAttribs[cc].sound.name = strdup((&appData.soundShout)[cc]);
\r
1088 textAttribs[cc].sound.data = NULL;
\r
1089 MyLoadSound(&textAttribs[cc].sound);
\r
1091 for (cc = ColorNormal; cc < NColorClasses; cc++) {
\r
1092 textAttribs[cc].sound.name = strdup("");
\r
1093 textAttribs[cc].sound.data = NULL;
\r
1095 for (sc = (SoundClass)0; sc < NSoundClasses; sc++) {
\r
1096 sounds[sc].name = strdup((&appData.soundMove)[sc]);
\r
1097 sounds[sc].data = NULL;
\r
1098 MyLoadSound(&sounds[sc]);
\r
1103 SetCommPortDefaults()
\r
1105 memset(&dcb, 0, sizeof(DCB)); // required by VS 2002 +
\r
1106 dcb.DCBlength = sizeof(DCB);
\r
1107 dcb.BaudRate = 9600;
\r
1108 dcb.fBinary = TRUE;
\r
1109 dcb.fParity = FALSE;
\r
1110 dcb.fOutxCtsFlow = FALSE;
\r
1111 dcb.fOutxDsrFlow = FALSE;
\r
1112 dcb.fDtrControl = DTR_CONTROL_ENABLE;
\r
1113 dcb.fDsrSensitivity = FALSE;
\r
1114 dcb.fTXContinueOnXoff = TRUE;
\r
1115 dcb.fOutX = FALSE;
\r
1117 dcb.fNull = FALSE;
\r
1118 dcb.fRtsControl = RTS_CONTROL_ENABLE;
\r
1119 dcb.fAbortOnError = FALSE;
\r
1121 dcb.Parity = SPACEPARITY;
\r
1122 dcb.StopBits = ONESTOPBIT;
\r
1125 // [HGM] args: these three cases taken out to stay in front-end
\r
1127 SaveFontArg(FILE *f, ArgDescriptor *ad)
\r
1128 { // in WinBoard every board size has its own font, and the "argLoc" identifies the table,
\r
1129 // while the curent board size determines the element. This system should be ported to XBoard.
\r
1130 // What the table contains pointers to, and how to print the font description, remains platform-dependent
\r
1132 for (bs=0; bs<NUM_SIZES; bs++) {
\r
1133 MyFontParams *mfp = &font[bs][(int) ad->argLoc]->mfp;
\r
1134 fprintf(f, "/size=%s ", sizeInfo[bs].name);
\r
1135 fprintf(f, "/%s=\"%s:%g%s%s%s%s%sc%d\"\n",
\r
1136 ad->argName, mfp->faceName, mfp->pointSize,
\r
1137 mfp->bold || mfp->italic || mfp->underline || mfp->strikeout ? " " : "",
\r
1138 mfp->bold ? "b" : "",
\r
1139 mfp->italic ? "i" : "",
\r
1140 mfp->underline ? "u" : "",
\r
1141 mfp->strikeout ? "s" : "",
\r
1142 (int)mfp->charset);
\r
1148 { // [HGM] copy the names from the internal WB variables to appData
\r
1151 for (cc = (ColorClass)0; cc < ColorNormal; cc++)
\r
1152 (&appData.soundShout)[cc] = textAttribs[cc].sound.name;
\r
1153 for (sc = (SoundClass)0; sc < NSoundClasses; sc++)
\r
1154 (&appData.soundMove)[sc] = sounds[sc].name;
\r
1158 SaveAttribsArg(FILE *f, ArgDescriptor *ad)
\r
1159 { // here the "argLoc" defines a table index. It could have contained the 'ta' pointer itself, though
\r
1160 MyTextAttribs* ta = &textAttribs[(ColorClass)ad->argLoc];
\r
1161 fprintf(f, "/%s=\"%s%s%s%s%s#%02lx%02lx%02lx\"\n", ad->argName,
\r
1162 (ta->effects & CFE_BOLD) ? "b" : "",
\r
1163 (ta->effects & CFE_ITALIC) ? "i" : "",
\r
1164 (ta->effects & CFE_UNDERLINE) ? "u" : "",
\r
1165 (ta->effects & CFE_STRIKEOUT) ? "s" : "",
\r
1166 (ta->effects) ? " " : "",
\r
1167 ta->color&0xff, (ta->color >> 8)&0xff, (ta->color >> 16)&0xff);
\r
1171 SaveColor(FILE *f, ArgDescriptor *ad)
\r
1172 { // in WinBoard the color is an int and has to be converted to text. In X it would be a string already?
\r
1173 COLORREF color = *(COLORREF *)colorVariable[(int)ad->argLoc];
\r
1174 fprintf(f, "/%s=#%02lx%02lx%02lx\n", ad->argName,
\r
1175 color&0xff, (color>>8)&0xff, (color>>16)&0xff);
\r
1179 SaveBoardSize(FILE *f, char *name, void *addr)
\r
1180 { // wrapper to shield back-end from BoardSize & sizeInfo
\r
1181 fprintf(f, "/%s=%s\n", name, sizeInfo[*(BoardSize *)addr].name);
\r
1185 ParseCommPortSettings(char *s)
\r
1186 { // wrapper to keep dcb from back-end
\r
1187 ParseCommSettings(s, &dcb);
\r
1192 { // wrapper to shield use of window handles from back-end (make addressible by number?)
\r
1193 GetActualPlacement(hwndMain, &wpMain);
\r
1194 GetActualPlacement(hwndConsole, &wpConsole);
\r
1195 GetActualPlacement(commentDialog, &wpComment);
\r
1196 GetActualPlacement(editTagsDialog, &wpTags);
\r
1197 GetActualPlacement(gameListDialog, &wpGameList);
\r
1198 GetActualPlacement(moveHistoryDialog, &wpMoveHistory);
\r
1199 GetActualPlacement(evalGraphDialog, &wpEvalGraph);
\r
1200 GetActualPlacement(engineOutputDialog, &wpEngineOutput);
\r
1204 PrintCommPortSettings(FILE *f, char *name)
\r
1205 { // wrapper to shield back-end from DCB
\r
1206 PrintCommSettings(f, name, &dcb);
\r
1210 MySearchPath(char *installDir, char *name, char *fullname)
\r
1213 return (int) SearchPath(installDir, name, NULL, MSG_SIZ, fullname, &dummy);
\r
1217 MyGetFullPathName(char *name, char *fullname)
\r
1220 return (int) GetFullPathName(name, MSG_SIZ, fullname, &dummy);
\r
1225 { // [HGM] args: allows testing if main window is realized from back-end
\r
1226 return hwndMain != NULL;
\r
1230 PopUpStartupDialog()
\r
1234 lpProc = MakeProcInstance((FARPROC)StartupDialog, hInst);
\r
1235 DialogBox(hInst, MAKEINTRESOURCE(DLG_Startup), NULL, (DLGPROC)lpProc);
\r
1236 FreeProcInstance(lpProc);
\r
1239 /*---------------------------------------------------------------------------*\
\r
1241 * GDI board drawing routines
\r
1243 \*---------------------------------------------------------------------------*/
\r
1245 /* [AS] Draw square using background texture */
\r
1246 static void DrawTile( int dx, int dy, int dw, int dh, HDC dst, HDC src, int mode, int sx, int sy )
\r
1251 return; /* Should never happen! */
\r
1254 SetGraphicsMode( dst, GM_ADVANCED );
\r
1261 /* X reflection */
\r
1266 x.eDx = (FLOAT) dw + dx - 1;
\r
1269 SetWorldTransform( dst, &x );
\r
1272 /* Y reflection */
\r
1278 x.eDy = (FLOAT) dh + dy - 1;
\r
1280 SetWorldTransform( dst, &x );
\r
1288 x.eDx = (FLOAT) dx;
\r
1289 x.eDy = (FLOAT) dy;
\r
1292 SetWorldTransform( dst, &x );
\r
1296 BitBlt( dst, dx, dy, dw, dh, src, sx, sy, SRCCOPY );
\r
1304 SetWorldTransform( dst, &x );
\r
1306 ModifyWorldTransform( dst, 0, MWT_IDENTITY );
\r
1309 /* [AS] [HGM] Make room for more piece types, so all pieces can be different */
\r
1311 PM_WP = (int) WhitePawn,
\r
1312 PM_WN = (int) WhiteKnight,
\r
1313 PM_WB = (int) WhiteBishop,
\r
1314 PM_WR = (int) WhiteRook,
\r
1315 PM_WQ = (int) WhiteQueen,
\r
1316 PM_WF = (int) WhiteFerz,
\r
1317 PM_WW = (int) WhiteWazir,
\r
1318 PM_WE = (int) WhiteAlfil,
\r
1319 PM_WM = (int) WhiteMan,
\r
1320 PM_WO = (int) WhiteCannon,
\r
1321 PM_WU = (int) WhiteUnicorn,
\r
1322 PM_WH = (int) WhiteNightrider,
\r
1323 PM_WA = (int) WhiteAngel,
\r
1324 PM_WC = (int) WhiteMarshall,
\r
1325 PM_WAB = (int) WhiteCardinal,
\r
1326 PM_WD = (int) WhiteDragon,
\r
1327 PM_WL = (int) WhiteLance,
\r
1328 PM_WS = (int) WhiteCobra,
\r
1329 PM_WV = (int) WhiteFalcon,
\r
1330 PM_WSG = (int) WhiteSilver,
\r
1331 PM_WG = (int) WhiteGrasshopper,
\r
1332 PM_WK = (int) WhiteKing,
\r
1333 PM_BP = (int) BlackPawn,
\r
1334 PM_BN = (int) BlackKnight,
\r
1335 PM_BB = (int) BlackBishop,
\r
1336 PM_BR = (int) BlackRook,
\r
1337 PM_BQ = (int) BlackQueen,
\r
1338 PM_BF = (int) BlackFerz,
\r
1339 PM_BW = (int) BlackWazir,
\r
1340 PM_BE = (int) BlackAlfil,
\r
1341 PM_BM = (int) BlackMan,
\r
1342 PM_BO = (int) BlackCannon,
\r
1343 PM_BU = (int) BlackUnicorn,
\r
1344 PM_BH = (int) BlackNightrider,
\r
1345 PM_BA = (int) BlackAngel,
\r
1346 PM_BC = (int) BlackMarshall,
\r
1347 PM_BG = (int) BlackGrasshopper,
\r
1348 PM_BAB = (int) BlackCardinal,
\r
1349 PM_BD = (int) BlackDragon,
\r
1350 PM_BL = (int) BlackLance,
\r
1351 PM_BS = (int) BlackCobra,
\r
1352 PM_BV = (int) BlackFalcon,
\r
1353 PM_BSG = (int) BlackSilver,
\r
1354 PM_BK = (int) BlackKing
\r
1357 static HFONT hPieceFont = NULL;
\r
1358 static HBITMAP hPieceMask[(int) EmptySquare];
\r
1359 static HBITMAP hPieceFace[(int) EmptySquare];
\r
1360 static int fontBitmapSquareSize = 0;
\r
1361 static char pieceToFontChar[(int) EmptySquare] =
\r
1362 { 'p', 'n', 'b', 'r', 'q',
\r
1363 'n', 'b', 'p', 'n', 'b', 'r', 'b', 'r', 'q', 'k',
\r
1364 'k', 'o', 'm', 'v', 't', 'w',
\r
1365 'v', 't', 'o', 'm', 'v', 't', 'v', 't', 'w', 'l',
\r
1368 extern BOOL SetCharTable( char *table, const char * map );
\r
1369 /* [HGM] moved to backend.c */
\r
1371 static void SetPieceBackground( HDC hdc, COLORREF color, int mode )
\r
1374 BYTE r1 = GetRValue( color );
\r
1375 BYTE g1 = GetGValue( color );
\r
1376 BYTE b1 = GetBValue( color );
\r
1382 /* Create a uniform background first */
\r
1383 hbrush = CreateSolidBrush( color );
\r
1384 SetRect( &rc, 0, 0, squareSize, squareSize );
\r
1385 FillRect( hdc, &rc, hbrush );
\r
1386 DeleteObject( hbrush );
\r
1389 /* Vertical gradient, good for pawn, knight and rook, less for queen and king */
\r
1390 int steps = squareSize / 2;
\r
1393 for( i=0; i<steps; i++ ) {
\r
1394 BYTE r = r1 - (r1-r2) * i / steps;
\r
1395 BYTE g = g1 - (g1-g2) * i / steps;
\r
1396 BYTE b = b1 - (b1-b2) * i / steps;
\r
1398 hbrush = CreateSolidBrush( RGB(r,g,b) );
\r
1399 SetRect( &rc, i + squareSize - steps, 0, i + squareSize - steps + 1, squareSize );
\r
1400 FillRect( hdc, &rc, hbrush );
\r
1401 DeleteObject(hbrush);
\r
1404 else if( mode == 2 ) {
\r
1405 /* Diagonal gradient, good more or less for every piece */
\r
1406 POINT triangle[3];
\r
1407 HPEN hpen = SelectObject( hdc, GetStockObject(NULL_PEN) );
\r
1408 HBRUSH hbrush_old;
\r
1409 int steps = squareSize;
\r
1412 triangle[0].x = squareSize - steps;
\r
1413 triangle[0].y = squareSize;
\r
1414 triangle[1].x = squareSize;
\r
1415 triangle[1].y = squareSize;
\r
1416 triangle[2].x = squareSize;
\r
1417 triangle[2].y = squareSize - steps;
\r
1419 for( i=0; i<steps; i++ ) {
\r
1420 BYTE r = r1 - (r1-r2) * i / steps;
\r
1421 BYTE g = g1 - (g1-g2) * i / steps;
\r
1422 BYTE b = b1 - (b1-b2) * i / steps;
\r
1424 hbrush = CreateSolidBrush( RGB(r,g,b) );
\r
1425 hbrush_old = SelectObject( hdc, hbrush );
\r
1426 Polygon( hdc, triangle, 3 );
\r
1427 SelectObject( hdc, hbrush_old );
\r
1428 DeleteObject(hbrush);
\r
1433 SelectObject( hdc, hpen );
\r
1438 [AS] The method I use to create the bitmaps it a bit tricky, but it
\r
1439 seems to work ok. The main problem here is to find the "inside" of a chess
\r
1440 piece: follow the steps as explained below.
\r
1442 static void CreatePieceMaskFromFont( HDC hdc_window, HDC hdc, int index )
\r
1446 COLORREF chroma = RGB(0xFF,0x00,0xFF);
\r
1450 int backColor = whitePieceColor;
\r
1451 int foreColor = blackPieceColor;
\r
1453 if( index < (int)BlackPawn && appData.fontBackColorWhite != appData.fontForeColorWhite ) {
\r
1454 backColor = appData.fontBackColorWhite;
\r
1455 foreColor = appData.fontForeColorWhite;
\r
1457 else if( index >= (int)BlackPawn && appData.fontBackColorBlack != appData.fontForeColorBlack ) {
\r
1458 backColor = appData.fontBackColorBlack;
\r
1459 foreColor = appData.fontForeColorBlack;
\r
1463 hbm = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
\r
1465 hbm_old = SelectObject( hdc, hbm );
\r
1469 rc.right = squareSize;
\r
1470 rc.bottom = squareSize;
\r
1472 /* Step 1: background is now black */
\r
1473 FillRect( hdc, &rc, GetStockObject(BLACK_BRUSH) );
\r
1475 GetTextExtentPoint32( hdc, &pieceToFontChar[index], 1, &sz );
\r
1477 pt.x = (squareSize - sz.cx) / 2;
\r
1478 pt.y = (squareSize - sz.cy) / 2;
\r
1480 SetBkMode( hdc, TRANSPARENT );
\r
1481 SetTextColor( hdc, chroma );
\r
1482 /* Step 2: the piece has been drawn in purple, there are now black and purple in this bitmap */
\r
1483 TextOut( hdc, pt.x, pt.y, &pieceToFontChar[appData.allWhite && index >= (int)BlackPawn ? index - (int)BlackPawn : index], 1 );
\r
1485 SelectObject( hdc, GetStockObject(WHITE_BRUSH) );
\r
1486 /* Step 3: the area outside the piece is filled with white */
\r
1487 // FloodFill( hdc, 0, 0, chroma );
\r
1488 ExtFloodFill( hdc, 0, 0, 0, FLOODFILLSURFACE );
\r
1489 ExtFloodFill( hdc, 0, squareSize-1, 0, FLOODFILLSURFACE ); // [HGM] fill from all 4 corners, for if piece too big
\r
1490 ExtFloodFill( hdc, squareSize-1, 0, 0, FLOODFILLSURFACE );
\r
1491 ExtFloodFill( hdc, squareSize-1, squareSize-1, 0, FLOODFILLSURFACE );
\r
1492 SelectObject( hdc, GetStockObject(BLACK_BRUSH) );
\r
1494 Step 4: this is the tricky part, the area inside the piece is filled with black,
\r
1495 but if the start point is not inside the piece we're lost!
\r
1496 There should be a better way to do this... if we could create a region or path
\r
1497 from the fill operation we would be fine for example.
\r
1499 // FloodFill( hdc, squareSize / 2, squareSize / 2, RGB(0xFF,0xFF,0xFF) );
\r
1500 ExtFloodFill( hdc, squareSize / 2, squareSize / 2, RGB(0xFF,0xFF,0xFF), FLOODFILLBORDER );
\r
1502 { /* [HGM] shave off edges of mask, in an attempt to correct for the fact that FloodFill does not work correctly under Win XP */
\r
1503 HDC dc2 = CreateCompatibleDC( hdc_window );
\r
1504 HBITMAP bm2 = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
\r
1506 SelectObject( dc2, bm2 );
\r
1507 BitBlt( dc2, 0, 0, squareSize, squareSize, hdc, 0, 0, SRCCOPY ); // make copy
\r
1508 BitBlt( hdc, 0, 1, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );
\r
1509 BitBlt( hdc, 2, 1, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );
\r
1510 BitBlt( hdc, 1, 0, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );
\r
1511 BitBlt( hdc, 1, 2, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );
\r
1514 DeleteObject( bm2 );
\r
1517 SetTextColor( hdc, 0 );
\r
1519 Step 5: some fonts have "disconnected" areas that are skipped by the fill:
\r
1520 draw the piece again in black for safety.
\r
1522 TextOut( hdc, pt.x, pt.y, &pieceToFontChar[appData.allWhite && index >= (int)BlackPawn ? index - (int)BlackPawn : index], 1 );
\r
1524 SelectObject( hdc, hbm_old );
\r
1526 if( hPieceMask[index] != NULL ) {
\r
1527 DeleteObject( hPieceMask[index] );
\r
1530 hPieceMask[index] = hbm;
\r
1533 hbm = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
\r
1535 SelectObject( hdc, hbm );
\r
1538 HDC dc1 = CreateCompatibleDC( hdc_window );
\r
1539 HDC dc2 = CreateCompatibleDC( hdc_window );
\r
1540 HBITMAP bm2 = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
\r
1542 SelectObject( dc1, hPieceMask[index] );
\r
1543 SelectObject( dc2, bm2 );
\r
1544 FillRect( dc2, &rc, GetStockObject(WHITE_BRUSH) );
\r
1545 BitBlt( dc2, 0, 0, squareSize, squareSize, dc1, 0, 0, SRCINVERT );
\r
1548 Now dc2 contains the inverse of the piece mask, i.e. a mask that preserves
\r
1549 the piece background and deletes (makes transparent) the rest.
\r
1550 Thanks to that mask, we are free to paint the background with the greates
\r
1551 freedom, as we'll be able to mask off the unwanted parts when finished.
\r
1552 We use this, to make gradients and give the pieces a "roundish" look.
\r
1554 SetPieceBackground( hdc, backColor, 2 );
\r
1555 BitBlt( hdc, 0, 0, squareSize, squareSize, dc2, 0, 0, SRCAND );
\r
1559 DeleteObject( bm2 );
\r
1562 SetTextColor( hdc, foreColor );
\r
1563 TextOut( hdc, pt.x, pt.y, &pieceToFontChar[appData.allWhite && index >= (int)BlackPawn ? index - (int)BlackPawn : index], 1 );
\r
1565 SelectObject( hdc, hbm_old );
\r
1567 if( hPieceFace[index] != NULL ) {
\r
1568 DeleteObject( hPieceFace[index] );
\r
1571 hPieceFace[index] = hbm;
\r
1574 static int TranslatePieceToFontPiece( int piece )
\r
1604 case BlackMarshall:
\r
1608 case BlackNightrider:
\r
1614 case BlackUnicorn:
\r
1618 case BlackGrasshopper:
\r
1630 case BlackCardinal:
\r
1637 case WhiteMarshall:
\r
1641 case WhiteNightrider:
\r
1647 case WhiteUnicorn:
\r
1651 case WhiteGrasshopper:
\r
1663 case WhiteCardinal:
\r
1672 void CreatePiecesFromFont()
\r
1675 HDC hdc_window = NULL;
\r
1681 if( fontBitmapSquareSize < 0 ) {
\r
1682 /* Something went seriously wrong in the past: do not try to recreate fonts! */
\r
1686 if( appData.renderPiecesWithFont == NULL || appData.renderPiecesWithFont[0] == NULLCHAR || appData.renderPiecesWithFont[0] == '*' ) {
\r
1687 fontBitmapSquareSize = -1;
\r
1691 if( fontBitmapSquareSize != squareSize ) {
\r
1692 hdc_window = GetDC( hwndMain );
\r
1693 hdc = CreateCompatibleDC( hdc_window );
\r
1695 if( hPieceFont != NULL ) {
\r
1696 DeleteObject( hPieceFont );
\r
1699 for( i=0; i<=(int)BlackKing; i++ ) {
\r
1700 hPieceMask[i] = NULL;
\r
1701 hPieceFace[i] = NULL;
\r
1707 if( appData.fontPieceSize >= 50 && appData.fontPieceSize <= 150 ) {
\r
1708 fontHeight = appData.fontPieceSize;
\r
1711 fontHeight = (fontHeight * squareSize) / 100;
\r
1713 lf.lfHeight = -MulDiv( fontHeight, GetDeviceCaps(hdc, LOGPIXELSY), 72 );
\r
1715 lf.lfEscapement = 0;
\r
1716 lf.lfOrientation = 0;
\r
1717 lf.lfWeight = FW_NORMAL;
\r
1719 lf.lfUnderline = 0;
\r
1720 lf.lfStrikeOut = 0;
\r
1721 lf.lfCharSet = DEFAULT_CHARSET;
\r
1722 lf.lfOutPrecision = OUT_DEFAULT_PRECIS;
\r
1723 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
\r
1724 lf.lfQuality = PROOF_QUALITY;
\r
1725 lf.lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;
\r
1726 strncpy( lf.lfFaceName, appData.renderPiecesWithFont, sizeof(lf.lfFaceName) );
\r
1727 lf.lfFaceName[ sizeof(lf.lfFaceName) - 1 ] = '\0';
\r
1729 hPieceFont = CreateFontIndirect( &lf );
\r
1731 if( hPieceFont == NULL ) {
\r
1732 fontBitmapSquareSize = -2;
\r
1735 /* Setup font-to-piece character table */
\r
1736 if( ! SetCharTable(pieceToFontChar, appData.fontToPieceTable) ) {
\r
1737 /* No (or wrong) global settings, try to detect the font */
\r
1738 if( strstr(lf.lfFaceName,"Alpha") != NULL ) {
\r
1740 SetCharTable(pieceToFontChar, "phbrqkojntwl");
\r
1742 else if( strstr(lf.lfFaceName,"DiagramTT") != NULL ) {
\r
1743 /* DiagramTT* family */
\r
1744 SetCharTable(pieceToFontChar, "PNLRQKpnlrqk");
\r
1746 else if( strstr(lf.lfFaceName,"WinboardF") != NULL ) {
\r
1747 /* Fairy symbols */
\r
1748 SetCharTable(pieceToFontChar, "PNBRQFEACWMOHIJGDVSLUKpnbrqfeacwmohijgdvsluk");
\r
1750 else if( strstr(lf.lfFaceName,"GC2004D") != NULL ) {
\r
1751 /* Good Companion (Some characters get warped as literal :-( */
\r
1752 char s[] = "1cmWG0??S??oYI23wgQU";
\r
1753 s[0]=0xB9; s[1]=0xA9; s[6]=0xB1; s[11]=0xBB; s[12]=0xAB; s[17]=0xB3;
\r
1754 SetCharTable(pieceToFontChar, s);
\r
1757 /* Cases, Condal, Leipzig, Lucena, Marroquin, Merida, Usual */
\r
1758 SetCharTable(pieceToFontChar, "pnbrqkomvtwl");
\r
1762 /* Create bitmaps */
\r
1763 hfont_old = SelectObject( hdc, hPieceFont );
\r
1764 for(i=(int)WhitePawn; i<(int)EmptySquare; i++) /* [HGM] made a loop for this */
\r
1765 if(PieceToChar((ChessSquare)i) != '.') /* skip unused pieces */
\r
1766 CreatePieceMaskFromFont( hdc_window, hdc, i );
\r
1768 SelectObject( hdc, hfont_old );
\r
1770 fontBitmapSquareSize = squareSize;
\r
1774 if( hdc != NULL ) {
\r
1778 if( hdc_window != NULL ) {
\r
1779 ReleaseDC( hwndMain, hdc_window );
\r
1784 DoLoadBitmap(HINSTANCE hinst, char *piece, int squareSize, char *suffix)
\r
1788 sprintf(name, "%s%d%s", piece, squareSize, suffix);
\r
1789 if (gameInfo.event &&
\r
1790 strcmp(gameInfo.event, "Easter Egg Hunt") == 0 &&
\r
1791 strcmp(name, "k80s") == 0) {
\r
1792 strcpy(name, "tim");
\r
1794 return LoadBitmap(hinst, name);
\r
1798 /* Insert a color into the program's logical palette
\r
1799 structure. This code assumes the given color is
\r
1800 the result of the RGB or PALETTERGB macro, and it
\r
1801 knows how those macros work (which is documented).
\r
1804 InsertInPalette(COLORREF color)
\r
1806 LPPALETTEENTRY pe = &(pLogPal->palPalEntry[pLogPal->palNumEntries]);
\r
1808 if (pLogPal->palNumEntries++ >= PALETTESIZE) {
\r
1809 DisplayFatalError("Too many colors", 0, 1);
\r
1810 pLogPal->palNumEntries--;
\r
1814 pe->peFlags = (char) 0;
\r
1815 pe->peRed = (char) (0xFF & color);
\r
1816 pe->peGreen = (char) (0xFF & (color >> 8));
\r
1817 pe->peBlue = (char) (0xFF & (color >> 16));
\r
1823 InitDrawingColors()
\r
1825 if (pLogPal == NULL) {
\r
1826 /* Allocate enough memory for a logical palette with
\r
1827 * PALETTESIZE entries and set the size and version fields
\r
1828 * of the logical palette structure.
\r
1830 pLogPal = (NPLOGPALETTE)
\r
1831 LocalAlloc(LMEM_FIXED, (sizeof(LOGPALETTE) +
\r
1832 (sizeof(PALETTEENTRY) * (PALETTESIZE))));
\r
1833 pLogPal->palVersion = 0x300;
\r
1835 pLogPal->palNumEntries = 0;
\r
1837 InsertInPalette(lightSquareColor);
\r
1838 InsertInPalette(darkSquareColor);
\r
1839 InsertInPalette(whitePieceColor);
\r
1840 InsertInPalette(blackPieceColor);
\r
1841 InsertInPalette(highlightSquareColor);
\r
1842 InsertInPalette(premoveHighlightColor);
\r
1844 /* create a logical color palette according the information
\r
1845 * in the LOGPALETTE structure.
\r
1847 hPal = CreatePalette((LPLOGPALETTE) pLogPal);
\r
1849 lightSquareBrush = CreateSolidBrush(lightSquareColor);
\r
1850 blackSquareBrush = CreateSolidBrush(blackPieceColor);
\r
1851 darkSquareBrush = CreateSolidBrush(darkSquareColor);
\r
1852 whitePieceBrush = CreateSolidBrush(whitePieceColor);
\r
1853 blackPieceBrush = CreateSolidBrush(blackPieceColor);
\r
1854 iconBkgndBrush = CreateSolidBrush(GetSysColor(COLOR_BACKGROUND));
\r
1855 explodeBrush = CreateSolidBrush(highlightSquareColor); // [HGM] atomic
\r
1856 /* [AS] Force rendering of the font-based pieces */
\r
1857 if( fontBitmapSquareSize > 0 ) {
\r
1858 fontBitmapSquareSize = 0;
\r
1864 BoardWidth(int boardSize, int n)
\r
1865 { /* [HGM] argument n added to allow different width and height */
\r
1866 int lineGap = sizeInfo[boardSize].lineGap;
\r
1868 if( appData.overrideLineGap >= 0 && appData.overrideLineGap <= 5 ) {
\r
1869 lineGap = appData.overrideLineGap;
\r
1872 return (n + 1) * lineGap +
\r
1873 n * sizeInfo[boardSize].squareSize;
\r
1876 /* Respond to board resize by dragging edge */
\r
1878 ResizeBoard(int newSizeX, int newSizeY, int flags)
\r
1880 BoardSize newSize = NUM_SIZES - 1;
\r
1881 static int recurse = 0;
\r
1882 if (IsIconic(hwndMain)) return;
\r
1883 if (recurse > 0) return;
\r
1885 while (newSize > 0) {
\r
1886 InitDrawingSizes(newSize+1000, 0); // [HGM] kludge to update sizeInfo without visible effects
\r
1887 if(newSizeX >= sizeInfo[newSize].cliWidth &&
\r
1888 newSizeY >= sizeInfo[newSize].cliHeight) break;
\r
1891 boardSize = newSize;
\r
1892 InitDrawingSizes(boardSize, flags);
\r
1899 InitDrawingSizes(BoardSize boardSize, int flags)
\r
1901 int i, boardWidth, boardHeight; /* [HGM] height treated separately */
\r
1902 ChessSquare piece;
\r
1903 static int oldBoardSize = -1, oldTinyLayout = 0;
\r
1905 SIZE clockSize, messageSize;
\r
1907 char buf[MSG_SIZ];
\r
1909 HMENU hmenu = GetMenu(hwndMain);
\r
1910 RECT crect, wrect, oldRect;
\r
1912 LOGBRUSH logbrush;
\r
1914 int suppressVisibleEffects = 0; // [HGM] kludge to request updating sizeInfo only
\r
1915 if((int)boardSize >= 1000 ) { boardSize -= 1000; suppressVisibleEffects = 1; }
\r
1917 /* [HGM] call with -2 uses old size (for if nr of files, ranks changes) */
\r
1918 if(boardSize == (BoardSize)(-2) ) boardSize = oldBoardSize;
\r
1920 oldRect.left = wpMain.x; //[HGM] placement: remember previous window params
\r
1921 oldRect.top = wpMain.y;
\r
1922 oldRect.right = wpMain.x + wpMain.width;
\r
1923 oldRect.bottom = wpMain.y + wpMain.height;
\r
1925 tinyLayout = sizeInfo[boardSize].tinyLayout;
\r
1926 smallLayout = sizeInfo[boardSize].smallLayout;
\r
1927 squareSize = sizeInfo[boardSize].squareSize;
\r
1928 lineGap = sizeInfo[boardSize].lineGap;
\r
1929 minorSize = 0; /* [HGM] Kludge to see if demagnified pieces need to be shifted */
\r
1931 if( appData.overrideLineGap >= 0 && appData.overrideLineGap <= 5 ) {
\r
1932 lineGap = appData.overrideLineGap;
\r
1935 if (tinyLayout != oldTinyLayout) {
\r
1936 long style = GetWindowLong(hwndMain, GWL_STYLE);
\r
1938 style &= ~WS_SYSMENU;
\r
1939 InsertMenu(hmenu, IDM_Exit, MF_BYCOMMAND, IDM_Minimize,
\r
1940 "&Minimize\tCtrl+F4");
\r
1942 style |= WS_SYSMENU;
\r
1943 RemoveMenu(hmenu, IDM_Minimize, MF_BYCOMMAND);
\r
1945 SetWindowLong(hwndMain, GWL_STYLE, style);
\r
1947 for (i=0; menuBarText[tinyLayout][i]; i++) {
\r
1948 ModifyMenu(hmenu, i, MF_STRING|MF_BYPOSITION|MF_POPUP,
\r
1949 (UINT)GetSubMenu(hmenu, i), menuBarText[tinyLayout][i]);
\r
1951 DrawMenuBar(hwndMain);
\r
1954 boardWidth = BoardWidth(boardSize, BOARD_WIDTH);
\r
1955 boardHeight = BoardWidth(boardSize, BOARD_HEIGHT);
\r
1957 /* Get text area sizes */
\r
1958 hdc = GetDC(hwndMain);
\r
1959 if (appData.clockMode) {
\r
1960 sprintf(buf, "White: %s", TimeString(23*60*60*1000L));
\r
1962 sprintf(buf, "White");
\r
1964 oldFont = SelectObject(hdc, font[boardSize][CLOCK_FONT]->hf);
\r
1965 GetTextExtentPoint(hdc, buf, strlen(buf), &clockSize);
\r
1966 SelectObject(hdc, font[boardSize][MESSAGE_FONT]->hf);
\r
1967 str = "We only care about the height here";
\r
1968 GetTextExtentPoint(hdc, str, strlen(str), &messageSize);
\r
1969 SelectObject(hdc, oldFont);
\r
1970 ReleaseDC(hwndMain, hdc);
\r
1972 /* Compute where everything goes */
\r
1973 if((first.programLogo || second.programLogo) && !tinyLayout) {
\r
1974 /* [HGM] logo: if either logo is on, reserve space for it */
\r
1975 logoHeight = 2*clockSize.cy;
\r
1976 leftLogoRect.left = OUTER_MARGIN;
\r
1977 leftLogoRect.right = leftLogoRect.left + 4*clockSize.cy;
\r
1978 leftLogoRect.top = OUTER_MARGIN;
\r
1979 leftLogoRect.bottom = OUTER_MARGIN + logoHeight;
\r
1981 rightLogoRect.right = OUTER_MARGIN + boardWidth;
\r
1982 rightLogoRect.left = rightLogoRect.right - 4*clockSize.cy;
\r
1983 rightLogoRect.top = OUTER_MARGIN;
\r
1984 rightLogoRect.bottom = OUTER_MARGIN + logoHeight;
\r
1987 whiteRect.left = leftLogoRect.right;
\r
1988 whiteRect.right = OUTER_MARGIN + boardWidth/2 - INNER_MARGIN/2;
\r
1989 whiteRect.top = OUTER_MARGIN;
\r
1990 whiteRect.bottom = whiteRect.top + logoHeight;
\r
1992 blackRect.right = rightLogoRect.left;
\r
1993 blackRect.left = whiteRect.right + INNER_MARGIN;
\r
1994 blackRect.top = whiteRect.top;
\r
1995 blackRect.bottom = whiteRect.bottom;
\r
1997 whiteRect.left = OUTER_MARGIN;
\r
1998 whiteRect.right = whiteRect.left + boardWidth/2 - INNER_MARGIN/2;
\r
1999 whiteRect.top = OUTER_MARGIN;
\r
2000 whiteRect.bottom = whiteRect.top + clockSize.cy;
\r
2002 blackRect.left = whiteRect.right + INNER_MARGIN;
\r
2003 blackRect.right = blackRect.left + boardWidth/2 - 1;
\r
2004 blackRect.top = whiteRect.top;
\r
2005 blackRect.bottom = whiteRect.bottom;
\r
2008 messageRect.left = OUTER_MARGIN + MESSAGE_LINE_LEFTMARGIN;
\r
2009 if (appData.showButtonBar) {
\r
2010 messageRect.right = OUTER_MARGIN + boardWidth // [HGM] logo: expressed independent of clock placement
\r
2011 - N_BUTTONS*BUTTON_WIDTH - MESSAGE_LINE_LEFTMARGIN;
\r
2013 messageRect.right = OUTER_MARGIN + boardWidth;
\r
2015 messageRect.top = whiteRect.bottom + INNER_MARGIN;
\r
2016 messageRect.bottom = messageRect.top + messageSize.cy;
\r
2018 boardRect.left = OUTER_MARGIN;
\r
2019 boardRect.right = boardRect.left + boardWidth;
\r
2020 boardRect.top = messageRect.bottom + INNER_MARGIN;
\r
2021 boardRect.bottom = boardRect.top + boardHeight;
\r
2023 sizeInfo[boardSize].cliWidth = boardRect.right + OUTER_MARGIN;
\r
2024 sizeInfo[boardSize].cliHeight = boardRect.bottom + OUTER_MARGIN;
\r
2025 oldBoardSize = boardSize;
\r
2026 oldTinyLayout = tinyLayout;
\r
2027 winW = 2 * GetSystemMetrics(SM_CXFRAME) + boardRect.right + OUTER_MARGIN;
\r
2028 winH = 2 * GetSystemMetrics(SM_CYFRAME) + GetSystemMetrics(SM_CYMENU) +
\r
2029 GetSystemMetrics(SM_CYCAPTION) + boardRect.bottom + OUTER_MARGIN;
\r
2030 if(suppressVisibleEffects) return; // [HGM] when called for filling sizeInfo only
\r
2031 wpMain.width = winW; // [HGM] placement: set through temporary which can used by initial sizing choice
\r
2032 wpMain.height = winH; // without disturbing window attachments
\r
2033 GetWindowRect(hwndMain, &wrect);
\r
2034 SetWindowPos(hwndMain, NULL, 0, 0, wpMain.width, wpMain.height,
\r
2035 SWP_NOCOPYBITS|SWP_NOZORDER|SWP_NOMOVE);
\r
2037 // [HGM] placement: let attached windows follow size change.
\r
2038 ReattachAfterSize( &oldRect, wpMain.width, wpMain.height, moveHistoryDialog, &wpMoveHistory );
\r
2039 ReattachAfterSize( &oldRect, wpMain.width, wpMain.height, evalGraphDialog, &wpEvalGraph );
\r
2040 ReattachAfterSize( &oldRect, wpMain.width, wpMain.height, engineOutputDialog, &wpEngineOutput );
\r
2041 ReattachAfterSize( &oldRect, wpMain.width, wpMain.height, gameListDialog, &wpGameList );
\r
2042 ReattachAfterSize( &oldRect, wpMain.width, wpMain.height, hwndConsole, &wpConsole );
\r
2044 /* compensate if menu bar wrapped */
\r
2045 GetClientRect(hwndMain, &crect);
\r
2046 offby = boardRect.bottom + OUTER_MARGIN - crect.bottom;
\r
2047 wpMain.height += offby;
\r
2049 case WMSZ_TOPLEFT:
\r
2050 SetWindowPos(hwndMain, NULL,
\r
2051 wrect.right - wpMain.width, wrect.bottom - wpMain.height,
\r
2052 wpMain.width, wpMain.height, SWP_NOCOPYBITS|SWP_NOZORDER);
\r
2055 case WMSZ_TOPRIGHT:
\r
2057 SetWindowPos(hwndMain, NULL,
\r
2058 wrect.left, wrect.bottom - wpMain.height,
\r
2059 wpMain.width, wpMain.height, SWP_NOCOPYBITS|SWP_NOZORDER);
\r
2062 case WMSZ_BOTTOMLEFT:
\r
2064 SetWindowPos(hwndMain, NULL,
\r
2065 wrect.right - wpMain.width, wrect.top,
\r
2066 wpMain.width, wpMain.height, SWP_NOCOPYBITS|SWP_NOZORDER);
\r
2069 case WMSZ_BOTTOMRIGHT:
\r
2073 SetWindowPos(hwndMain, NULL, 0, 0, wpMain.width, wpMain.height,
\r
2074 SWP_NOCOPYBITS|SWP_NOZORDER|SWP_NOMOVE);
\r
2079 for (i = 0; i < N_BUTTONS; i++) {
\r
2080 if (buttonDesc[i].hwnd != NULL) {
\r
2081 DestroyWindow(buttonDesc[i].hwnd);
\r
2082 buttonDesc[i].hwnd = NULL;
\r
2084 if (appData.showButtonBar) {
\r
2085 buttonDesc[i].hwnd =
\r
2086 CreateWindow("BUTTON", buttonDesc[i].label,
\r
2087 WS_VISIBLE | WS_CHILD | BS_PUSHBUTTON,
\r
2088 boardRect.right - BUTTON_WIDTH*(N_BUTTONS-i),
\r
2089 messageRect.top, BUTTON_WIDTH, messageSize.cy, hwndMain,
\r
2090 (HMENU) buttonDesc[i].id,
\r
2091 (HINSTANCE) GetWindowLong(hwndMain, GWL_HINSTANCE), NULL);
\r
2093 SendMessage(buttonDesc[i].hwnd, WM_SETFONT,
\r
2094 (WPARAM)font[boardSize][MESSAGE_FONT]->hf,
\r
2095 MAKELPARAM(FALSE, 0));
\r
2097 if (buttonDesc[i].id == IDM_Pause)
\r
2098 hwndPause = buttonDesc[i].hwnd;
\r
2099 buttonDesc[i].wndproc = (WNDPROC)
\r
2100 SetWindowLong(buttonDesc[i].hwnd, GWL_WNDPROC, (LONG) ButtonProc);
\r
2103 if (gridPen != NULL) DeleteObject(gridPen);
\r
2104 if (highlightPen != NULL) DeleteObject(highlightPen);
\r
2105 if (premovePen != NULL) DeleteObject(premovePen);
\r
2106 if (lineGap != 0) {
\r
2107 logbrush.lbStyle = BS_SOLID;
\r
2108 logbrush.lbColor = RGB(0, 0, 0); /* grid pen color = black */
\r
2110 ExtCreatePen(PS_GEOMETRIC|PS_SOLID|PS_ENDCAP_FLAT|PS_JOIN_MITER,
\r
2111 lineGap, &logbrush, 0, NULL);
\r
2112 logbrush.lbColor = highlightSquareColor;
\r
2114 ExtCreatePen(PS_GEOMETRIC|PS_SOLID|PS_ENDCAP_FLAT|PS_JOIN_MITER,
\r
2115 lineGap, &logbrush, 0, NULL);
\r
2117 logbrush.lbColor = premoveHighlightColor;
\r
2119 ExtCreatePen(PS_GEOMETRIC|PS_SOLID|PS_ENDCAP_FLAT|PS_JOIN_MITER,
\r
2120 lineGap, &logbrush, 0, NULL);
\r
2122 /* [HGM] Loop had to be split in part for vert. and hor. lines */
\r
2123 for (i = 0; i < BOARD_HEIGHT + 1; i++) {
\r
2124 gridEndpoints[i*2].x = boardRect.left + lineGap / 2;
\r
2125 gridEndpoints[i*2].y = gridEndpoints[i*2 + 1].y =
\r
2126 boardRect.top + lineGap / 2 + (i * (squareSize + lineGap));
\r
2127 gridEndpoints[i*2 + 1].x = boardRect.left + lineGap / 2 +
\r
2128 BOARD_WIDTH * (squareSize + lineGap);
\r
2129 gridVertexCounts[i*2] = gridVertexCounts[i*2 + 1] = 2;
\r
2131 for (i = 0; i < BOARD_WIDTH + 1; i++) {
\r
2132 gridEndpoints[i*2 + BOARD_HEIGHT*2 + 2].y = boardRect.top + lineGap / 2;
\r
2133 gridEndpoints[i*2 + BOARD_HEIGHT*2 + 2].x =
\r
2134 gridEndpoints[i*2 + 1 + BOARD_HEIGHT*2 + 2].x = boardRect.left +
\r
2135 lineGap / 2 + (i * (squareSize + lineGap));
\r
2136 gridEndpoints[i*2 + 1 + BOARD_HEIGHT*2 + 2].y =
\r
2137 boardRect.top + BOARD_HEIGHT * (squareSize + lineGap);
\r
2138 gridVertexCounts[i*2] = gridVertexCounts[i*2 + 1] = 2;
\r
2142 /* [HGM] Licensing requirement */
\r
2144 if(gameInfo.variant == VariantGothic) GothicPopUp( GOTHIC, VariantGothic); else
\r
2147 if(gameInfo.variant == VariantFalcon) GothicPopUp( FALCON, VariantFalcon); else
\r
2149 GothicPopUp( "", VariantNormal);
\r
2152 /* if (boardSize == oldBoardSize) return; [HGM] variant might have changed */
\r
2154 /* Load piece bitmaps for this board size */
\r
2155 for (i=0; i<=2; i++) {
\r
2156 for (piece = WhitePawn;
\r
2157 (int) piece < (int) BlackPawn;
\r
2158 piece = (ChessSquare) ((int) piece + 1)) {
\r
2159 if (pieceBitmap[i][piece] != NULL)
\r
2160 DeleteObject(pieceBitmap[i][piece]);
\r
2164 fontBitmapSquareSize = 0; /* [HGM] render: make sure pieces will be recreated, as we might need others now */
\r
2165 // Orthodox Chess pieces
\r
2166 pieceBitmap[0][WhitePawn] = DoLoadBitmap(hInst, "p", squareSize, "s");
\r
2167 pieceBitmap[0][WhiteKnight] = DoLoadBitmap(hInst, "n", squareSize, "s");
\r
2168 pieceBitmap[0][WhiteBishop] = DoLoadBitmap(hInst, "b", squareSize, "s");
\r
2169 pieceBitmap[0][WhiteRook] = DoLoadBitmap(hInst, "r", squareSize, "s");
\r
2170 pieceBitmap[0][WhiteKing] = DoLoadBitmap(hInst, "k", squareSize, "s");
\r
2171 pieceBitmap[1][WhitePawn] = DoLoadBitmap(hInst, "p", squareSize, "o");
\r
2172 pieceBitmap[1][WhiteKnight] = DoLoadBitmap(hInst, "n", squareSize, "o");
\r
2173 pieceBitmap[1][WhiteBishop] = DoLoadBitmap(hInst, "b", squareSize, "o");
\r
2174 pieceBitmap[1][WhiteRook] = DoLoadBitmap(hInst, "r", squareSize, "o");
\r
2175 pieceBitmap[1][WhiteKing] = DoLoadBitmap(hInst, "k", squareSize, "o");
\r
2176 pieceBitmap[2][WhitePawn] = DoLoadBitmap(hInst, "p", squareSize, "w");
\r
2177 pieceBitmap[2][WhiteKnight] = DoLoadBitmap(hInst, "n", squareSize, "w");
\r
2178 pieceBitmap[2][WhiteBishop] = DoLoadBitmap(hInst, "b", squareSize, "w");
\r
2179 pieceBitmap[2][WhiteRook] = DoLoadBitmap(hInst, "r", squareSize, "w");
\r
2180 pieceBitmap[2][WhiteKing] = DoLoadBitmap(hInst, "k", squareSize, "w");
\r
2181 if( !strcmp(appData.variant, "shogi") && (squareSize==72 || squareSize==49)) {
\r
2182 // in Shogi, Hijack the unused Queen for Lance
\r
2183 pieceBitmap[0][WhiteQueen] = DoLoadBitmap(hInst, "l", squareSize, "s");
\r
2184 pieceBitmap[1][WhiteQueen] = DoLoadBitmap(hInst, "l", squareSize, "o");
\r
2185 pieceBitmap[2][WhiteQueen] = DoLoadBitmap(hInst, "l", squareSize, "w");
\r
2187 pieceBitmap[0][WhiteQueen] = DoLoadBitmap(hInst, "q", squareSize, "s");
\r
2188 pieceBitmap[1][WhiteQueen] = DoLoadBitmap(hInst, "q", squareSize, "o");
\r
2189 pieceBitmap[2][WhiteQueen] = DoLoadBitmap(hInst, "q", squareSize, "w");
\r
2192 if(squareSize <= 72 && squareSize >= 33) {
\r
2193 /* A & C are available in most sizes now */
\r
2194 if(squareSize != 49 && squareSize != 72 && squareSize != 33) { // Vortex-like
\r
2195 pieceBitmap[0][WhiteAngel] = DoLoadBitmap(hInst, "a", squareSize, "s");
\r
2196 pieceBitmap[1][WhiteAngel] = DoLoadBitmap(hInst, "a", squareSize, "o");
\r
2197 pieceBitmap[2][WhiteAngel] = DoLoadBitmap(hInst, "a", squareSize, "w");
\r
2198 pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "s");
\r
2199 pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "o");
\r
2200 pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "w");
\r
2201 pieceBitmap[0][WhiteCobra] = DoLoadBitmap(hInst, "cv", squareSize, "s");
\r
2202 pieceBitmap[1][WhiteCobra] = DoLoadBitmap(hInst, "cv", squareSize, "o");
\r
2203 pieceBitmap[2][WhiteCobra] = DoLoadBitmap(hInst, "cv", squareSize, "w");
\r
2204 pieceBitmap[0][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "s");
\r
2205 pieceBitmap[1][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "o");
\r
2206 pieceBitmap[2][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "w");
\r
2207 } else { // Smirf-like
\r
2208 pieceBitmap[0][WhiteAngel] = DoLoadBitmap(hInst, "aa", squareSize, "s");
\r
2209 pieceBitmap[1][WhiteAngel] = DoLoadBitmap(hInst, "aa", squareSize, "o");
\r
2210 pieceBitmap[2][WhiteAngel] = DoLoadBitmap(hInst, "aa", squareSize, "w");
\r
2212 if(gameInfo.variant == VariantGothic) { // Vortex-like
\r
2213 pieceBitmap[0][WhiteMarshall] = DoLoadBitmap(hInst, "cv", squareSize, "s");
\r
2214 pieceBitmap[1][WhiteMarshall] = DoLoadBitmap(hInst, "cv", squareSize, "o");
\r
2215 pieceBitmap[2][WhiteMarshall] = DoLoadBitmap(hInst, "cv", squareSize, "w");
\r
2216 } else { // WinBoard standard
\r
2217 pieceBitmap[0][WhiteMarshall] = DoLoadBitmap(hInst, "c", squareSize, "s");
\r
2218 pieceBitmap[1][WhiteMarshall] = DoLoadBitmap(hInst, "c", squareSize, "o");
\r
2219 pieceBitmap[2][WhiteMarshall] = DoLoadBitmap(hInst, "c", squareSize, "w");
\r
2224 if(squareSize==72 || squareSize==49 || squareSize==33) { /* experiment with some home-made bitmaps */
\r
2225 pieceBitmap[0][WhiteFerz] = DoLoadBitmap(hInst, "f", squareSize, "s");
\r
2226 pieceBitmap[1][WhiteFerz] = DoLoadBitmap(hInst, "f", squareSize, "o");
\r
2227 pieceBitmap[2][WhiteFerz] = DoLoadBitmap(hInst, "f", squareSize, "w");
\r
2228 pieceBitmap[0][WhiteWazir] = DoLoadBitmap(hInst, "w", squareSize, "s");
\r
2229 pieceBitmap[1][WhiteWazir] = DoLoadBitmap(hInst, "w", squareSize, "o");
\r
2230 pieceBitmap[2][WhiteWazir] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
2231 pieceBitmap[0][WhiteAlfil] = DoLoadBitmap(hInst, "e", squareSize, "s");
\r
2232 pieceBitmap[1][WhiteAlfil] = DoLoadBitmap(hInst, "e", squareSize, "o");
\r
2233 pieceBitmap[2][WhiteAlfil] = DoLoadBitmap(hInst, "e", squareSize, "w");
\r
2234 pieceBitmap[0][WhiteMan] = DoLoadBitmap(hInst, "m", squareSize, "s");
\r
2235 pieceBitmap[1][WhiteMan] = DoLoadBitmap(hInst, "m", squareSize, "o");
\r
2236 pieceBitmap[2][WhiteMan] = DoLoadBitmap(hInst, "m", squareSize, "w");
\r
2237 pieceBitmap[0][WhiteCardinal] = DoLoadBitmap(hInst, "a", squareSize, "s");
\r
2238 pieceBitmap[1][WhiteCardinal] = DoLoadBitmap(hInst, "a", squareSize, "o");
\r
2239 pieceBitmap[2][WhiteCardinal] = DoLoadBitmap(hInst, "a", squareSize, "w");
\r
2240 pieceBitmap[0][WhiteDragon] = DoLoadBitmap(hInst, "dk", squareSize, "s");
\r
2241 pieceBitmap[1][WhiteDragon] = DoLoadBitmap(hInst, "dk", squareSize, "o");
\r
2242 pieceBitmap[2][WhiteDragon] = DoLoadBitmap(hInst, "dk", squareSize, "w");
\r
2243 pieceBitmap[0][WhiteFalcon] = DoLoadBitmap(hInst, "v", squareSize, "s");
\r
2244 pieceBitmap[1][WhiteFalcon] = DoLoadBitmap(hInst, "v", squareSize, "o");
\r
2245 pieceBitmap[2][WhiteFalcon] = DoLoadBitmap(hInst, "v", squareSize, "w");
\r
2246 pieceBitmap[0][WhiteCobra] = DoLoadBitmap(hInst, "s", squareSize, "s");
\r
2247 pieceBitmap[1][WhiteCobra] = DoLoadBitmap(hInst, "s", squareSize, "o");
\r
2248 pieceBitmap[2][WhiteCobra] = DoLoadBitmap(hInst, "s", squareSize, "w");
\r
2249 pieceBitmap[0][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "s");
\r
2250 pieceBitmap[1][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "o");
\r
2251 pieceBitmap[2][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "w");
\r
2252 pieceBitmap[0][WhiteUnicorn] = DoLoadBitmap(hInst, "u", squareSize, "s");
\r
2253 pieceBitmap[1][WhiteUnicorn] = DoLoadBitmap(hInst, "u", squareSize, "o");
\r
2254 pieceBitmap[2][WhiteUnicorn] = DoLoadBitmap(hInst, "u", squareSize, "w");
\r
2256 if(gameInfo.variant == VariantShogi) { /* promoted Gold represemtations */
\r
2257 pieceBitmap[0][WhiteCannon] = DoLoadBitmap(hInst, "wp", squareSize, "s");
\r
2258 pieceBitmap[1][WhiteCannon] = DoLoadBitmap(hInst, "wp", squareSize, "o");
\r
2259 pieceBitmap[2][WhiteCannon] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
2260 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "wn", squareSize, "s");
\r
2261 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "wn", squareSize, "o");
\r
2262 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
2263 pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "ws", squareSize, "s");
\r
2264 pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "ws", squareSize, "o");
\r
2265 pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
2266 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "wl", squareSize, "s");
\r
2267 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "wl", squareSize, "o");
\r
2268 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
2270 pieceBitmap[0][WhiteCannon] = DoLoadBitmap(hInst, "o", squareSize, "s");
\r
2271 pieceBitmap[1][WhiteCannon] = DoLoadBitmap(hInst, "o", squareSize, "o");
\r
2272 pieceBitmap[2][WhiteCannon] = DoLoadBitmap(hInst, "o", squareSize, "w");
\r
2273 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "h", squareSize, "s");
\r
2274 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "h", squareSize, "o");
\r
2275 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "h", squareSize, "w");
\r
2276 pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "s");
\r
2277 pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "o");
\r
2278 pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "w");
\r
2279 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "g", squareSize, "s");
\r
2280 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "g", squareSize, "o");
\r
2281 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "g", squareSize, "w");
\r
2284 } else { /* other size, no special bitmaps available. Use smaller symbols */
\r
2285 if((int)boardSize < 2) minorSize = sizeInfo[0].squareSize;
\r
2286 else minorSize = sizeInfo[(int)boardSize - 2].squareSize;
\r
2287 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "n", minorSize, "s");
\r
2288 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "n", minorSize, "o");
\r
2289 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "n", minorSize, "w");
\r
2290 pieceBitmap[0][WhiteCardinal] = DoLoadBitmap(hInst, "b", minorSize, "s");
\r
2291 pieceBitmap[1][WhiteCardinal] = DoLoadBitmap(hInst, "b", minorSize, "o");
\r
2292 pieceBitmap[2][WhiteCardinal] = DoLoadBitmap(hInst, "b", minorSize, "w");
\r
2293 pieceBitmap[0][WhiteDragon] = DoLoadBitmap(hInst, "r", minorSize, "s");
\r
2294 pieceBitmap[1][WhiteDragon] = DoLoadBitmap(hInst, "r", minorSize, "o");
\r
2295 pieceBitmap[2][WhiteDragon] = DoLoadBitmap(hInst, "r", minorSize, "w");
\r
2296 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "q", minorSize, "s");
\r
2297 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "q", minorSize, "o");
\r
2298 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "q", minorSize, "w");
\r
2302 if(gameInfo.variant == VariantShogi && squareSize == 58)
\r
2303 /* special Shogi support in this size */
\r
2304 { for (i=0; i<=2; i++) { /* replace all bitmaps */
\r
2305 for (piece = WhitePawn;
\r
2306 (int) piece < (int) BlackPawn;
\r
2307 piece = (ChessSquare) ((int) piece + 1)) {
\r
2308 if (pieceBitmap[i][piece] != NULL)
\r
2309 DeleteObject(pieceBitmap[i][piece]);
\r
2312 pieceBitmap[0][WhitePawn] = DoLoadBitmap(hInst, "sp", squareSize, "o");
\r
2313 pieceBitmap[0][WhiteKnight] = DoLoadBitmap(hInst, "sn", squareSize, "o");
\r
2314 pieceBitmap[0][WhiteBishop] = DoLoadBitmap(hInst, "sb", squareSize, "o");
\r
2315 pieceBitmap[0][WhiteRook] = DoLoadBitmap(hInst, "sr", squareSize, "o");
\r
2316 pieceBitmap[0][WhiteQueen] = DoLoadBitmap(hInst, "sl", squareSize, "o");
\r
2317 pieceBitmap[0][WhiteKing] = DoLoadBitmap(hInst, "sk", squareSize, "o");
\r
2318 pieceBitmap[0][WhiteFerz] = DoLoadBitmap(hInst, "sf", squareSize, "o");
\r
2319 pieceBitmap[0][WhiteWazir] = DoLoadBitmap(hInst, "sw", squareSize, "o");
\r
2320 pieceBitmap[0][WhiteCannon] = DoLoadBitmap(hInst, "su", squareSize, "o");
\r
2321 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "sh", squareSize, "o");
\r
2322 pieceBitmap[0][WhiteCardinal] = DoLoadBitmap(hInst, "sa", squareSize, "o");
\r
2323 pieceBitmap[0][WhiteDragon] = DoLoadBitmap(hInst, "sc", squareSize, "o");
\r
2324 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "sg", squareSize, "o");
\r
2325 pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "ss", squareSize, "o");
\r
2326 pieceBitmap[1][WhitePawn] = DoLoadBitmap(hInst, "sp", squareSize, "o");
\r
2327 pieceBitmap[1][WhiteKnight] = DoLoadBitmap(hInst, "sn", squareSize, "o");
\r
2328 pieceBitmap[1][WhiteBishop] = DoLoadBitmap(hInst, "sb", squareSize, "o");
\r
2329 pieceBitmap[1][WhiteRook] = DoLoadBitmap(hInst, "sr", squareSize, "o");
\r
2330 pieceBitmap[1][WhiteQueen] = DoLoadBitmap(hInst, "sl", squareSize, "o");
\r
2331 pieceBitmap[1][WhiteKing] = DoLoadBitmap(hInst, "sk", squareSize, "o");
\r
2332 pieceBitmap[1][WhiteFerz] = DoLoadBitmap(hInst, "sf", squareSize, "o");
\r
2333 pieceBitmap[1][WhiteWazir] = DoLoadBitmap(hInst, "sw", squareSize, "o");
\r
2334 pieceBitmap[1][WhiteCannon] = DoLoadBitmap(hInst, "su", squareSize, "o");
\r
2335 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "sh", squareSize, "o");
\r
2336 pieceBitmap[1][WhiteCardinal] = DoLoadBitmap(hInst, "sa", squareSize, "o");
\r
2337 pieceBitmap[1][WhiteDragon] = DoLoadBitmap(hInst, "sc", squareSize, "o");
\r
2338 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "sg", squareSize, "o");
\r
2339 pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "ss", squareSize, "o");
\r
2340 pieceBitmap[2][WhitePawn] = DoLoadBitmap(hInst, "sp", squareSize, "w");
\r
2341 pieceBitmap[2][WhiteKnight] = DoLoadBitmap(hInst, "sn", squareSize, "w");
\r
2342 pieceBitmap[2][WhiteBishop] = DoLoadBitmap(hInst, "sr", squareSize, "w");
\r
2343 pieceBitmap[2][WhiteRook] = DoLoadBitmap(hInst, "sr", squareSize, "w");
\r
2344 pieceBitmap[2][WhiteQueen] = DoLoadBitmap(hInst, "sl", squareSize, "w");
\r
2345 pieceBitmap[2][WhiteKing] = DoLoadBitmap(hInst, "sk", squareSize, "w");
\r
2346 pieceBitmap[2][WhiteFerz] = DoLoadBitmap(hInst, "sw", squareSize, "w");
\r
2347 pieceBitmap[2][WhiteWazir] = DoLoadBitmap(hInst, "sw", squareSize, "w");
\r
2348 pieceBitmap[2][WhiteCannon] = DoLoadBitmap(hInst, "sp", squareSize, "w");
\r
2349 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "sn", squareSize, "w");
\r
2350 pieceBitmap[2][WhiteCardinal] = DoLoadBitmap(hInst, "sr", squareSize, "w");
\r
2351 pieceBitmap[2][WhiteDragon] = DoLoadBitmap(hInst, "sr", squareSize, "w");
\r
2352 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "sl", squareSize, "w");
\r
2353 pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "sw", squareSize, "w");
\r
2359 PieceBitmap(ChessSquare p, int kind)
\r
2361 if ((int) p >= (int) BlackPawn)
\r
2362 p = (ChessSquare) ((int) p - (int) BlackPawn + (int) WhitePawn);
\r
2364 return pieceBitmap[kind][(int) p];
\r
2367 /***************************************************************/
\r
2369 #define MIN(a,b) (((a) < (b)) ? (a) : (b))
\r
2370 #define MAX(a,b) (((a) > (b)) ? (a) : (b))
\r
2372 #define MIN3(a,b,c) (((a) < (b) && (a) < (c)) ? (a) : (((b) < (a) && (b) < (c)) ? (b) : (c)))
\r
2373 #define MAX3(a,b,c) (((a) > (b) && (a) > (c)) ? (a) : (((b) > (a) && (b) > (c)) ? (b) : (c)))
\r
2377 SquareToPos(int row, int column, int * x, int * y)
\r
2380 *x = boardRect.left + lineGap + ((BOARD_WIDTH-1)-column) * (squareSize + lineGap);
\r
2381 *y = boardRect.top + lineGap + row * (squareSize + lineGap);
\r
2383 *x = boardRect.left + lineGap + column * (squareSize + lineGap);
\r
2384 *y = boardRect.top + lineGap + ((BOARD_HEIGHT-1)-row) * (squareSize + lineGap);
\r
2389 DrawCoordsOnDC(HDC hdc)
\r
2391 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
2392 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
2393 char str[2] = { NULLCHAR, NULLCHAR };
\r
2394 int oldMode, oldAlign, x, y, start, i;
\r
2398 if (!appData.showCoords)
\r
2401 start = flipView ? 1-(ONE!='1') : 23+(ONE!='1')-BOARD_HEIGHT;
\r
2403 oldBrush = SelectObject(hdc, GetStockObject(BLACK_BRUSH));
\r
2404 oldMode = SetBkMode(hdc, (appData.monoMode ? OPAQUE : TRANSPARENT));
\r
2405 oldAlign = GetTextAlign(hdc);
\r
2406 oldFont = SelectObject(hdc, font[boardSize][COORD_FONT]->hf);
\r
2408 y = boardRect.top + lineGap;
\r
2409 x = boardRect.left + lineGap + gameInfo.holdingsWidth*(squareSize + lineGap);
\r
2411 SetTextAlign(hdc, TA_LEFT|TA_TOP);
\r
2412 for (i = 0; i < BOARD_HEIGHT; i++) {
\r
2413 str[0] = files[start + i];
\r
2414 ExtTextOut(hdc, x + 2, y + 1, 0, NULL, str, 1, NULL);
\r
2415 y += squareSize + lineGap;
\r
2418 start = flipView ? 12-(BOARD_RGHT-BOARD_LEFT) : 12;
\r
2420 SetTextAlign(hdc, TA_RIGHT|TA_BOTTOM);
\r
2421 for (i = 0; i < BOARD_RGHT - BOARD_LEFT; i++) {
\r
2422 str[0] = ranks[start + i];
\r
2423 ExtTextOut(hdc, x + squareSize - 2, y - 1, 0, NULL, str, 1, NULL);
\r
2424 x += squareSize + lineGap;
\r
2427 SelectObject(hdc, oldBrush);
\r
2428 SetBkMode(hdc, oldMode);
\r
2429 SetTextAlign(hdc, oldAlign);
\r
2430 SelectObject(hdc, oldFont);
\r
2434 DrawGridOnDC(HDC hdc)
\r
2438 if (lineGap != 0) {
\r
2439 oldPen = SelectObject(hdc, gridPen);
\r
2440 PolyPolyline(hdc, gridEndpoints, gridVertexCounts, BOARD_WIDTH+BOARD_HEIGHT + 2);
\r
2441 SelectObject(hdc, oldPen);
\r
2445 #define HIGHLIGHT_PEN 0
\r
2446 #define PREMOVE_PEN 1
\r
2449 DrawHighlightOnDC(HDC hdc, BOOLEAN on, int x, int y, int pen)
\r
2452 HPEN oldPen, hPen;
\r
2453 if (lineGap == 0) return;
\r
2455 x1 = boardRect.left +
\r
2456 lineGap/2 + ((BOARD_WIDTH-1)-x) * (squareSize + lineGap);
\r
2457 y1 = boardRect.top +
\r
2458 lineGap/2 + y * (squareSize + lineGap);
\r
2460 x1 = boardRect.left +
\r
2461 lineGap/2 + x * (squareSize + lineGap);
\r
2462 y1 = boardRect.top +
\r
2463 lineGap/2 + ((BOARD_HEIGHT-1)-y) * (squareSize + lineGap);
\r
2465 hPen = pen ? premovePen : highlightPen;
\r
2466 oldPen = SelectObject(hdc, on ? hPen : gridPen);
\r
2467 MoveToEx(hdc, x1, y1, NULL);
\r
2468 LineTo(hdc, x1 + squareSize + lineGap, y1);
\r
2469 LineTo(hdc, x1 + squareSize + lineGap, y1 + squareSize + lineGap);
\r
2470 LineTo(hdc, x1, y1 + squareSize + lineGap);
\r
2471 LineTo(hdc, x1, y1);
\r
2472 SelectObject(hdc, oldPen);
\r
2476 DrawHighlightsOnDC(HDC hdc)
\r
2479 for (i=0; i<2; i++) {
\r
2480 if (highlightInfo.sq[i].x >= 0 && highlightInfo.sq[i].y >= 0)
\r
2481 DrawHighlightOnDC(hdc, TRUE,
\r
2482 highlightInfo.sq[i].x, highlightInfo.sq[i].y,
\r
2485 for (i=0; i<2; i++) {
\r
2486 if (premoveHighlightInfo.sq[i].x >= 0 &&
\r
2487 premoveHighlightInfo.sq[i].y >= 0) {
\r
2488 DrawHighlightOnDC(hdc, TRUE,
\r
2489 premoveHighlightInfo.sq[i].x,
\r
2490 premoveHighlightInfo.sq[i].y,
\r
2496 /* Note: sqcolor is used only in monoMode */
\r
2497 /* Note that this code is largely duplicated in woptions.c,
\r
2498 function DrawSampleSquare, so that needs to be updated too */
\r
2500 DrawPieceOnDC(HDC hdc, ChessSquare piece, int color, int sqcolor, int x, int y, HDC tmphdc)
\r
2502 HBITMAP oldBitmap;
\r
2506 if (appData.blindfold) return;
\r
2508 /* [AS] Use font-based pieces if needed */
\r
2509 if( fontBitmapSquareSize >= 0 && squareSize > 32 ) {
\r
2510 /* Create piece bitmaps, or do nothing if piece set is up to date */
\r
2511 CreatePiecesFromFont();
\r
2513 if( fontBitmapSquareSize == squareSize ) {
\r
2514 int index = TranslatePieceToFontPiece(piece);
\r
2516 SelectObject( tmphdc, hPieceMask[ index ] );
\r
2520 squareSize, squareSize,
\r
2525 SelectObject( tmphdc, hPieceFace[ index ] );
\r
2529 squareSize, squareSize,
\r
2538 if (appData.monoMode) {
\r
2539 SelectObject(tmphdc, PieceBitmap(piece,
\r
2540 color == sqcolor ? OUTLINE_PIECE : SOLID_PIECE));
\r
2541 BitBlt(hdc, x, y, squareSize, squareSize, tmphdc, 0, 0,
\r
2542 sqcolor ? SRCCOPY : NOTSRCCOPY);
\r
2544 tmpSize = squareSize;
\r
2546 ((piece >= (int)WhiteNightrider && piece <= WhiteGrasshopper) ||
\r
2547 (piece >= (int)BlackNightrider && piece <= BlackGrasshopper)) ) {
\r
2548 /* [HGM] no bitmap available for promoted pieces in Crazyhouse */
\r
2549 /* Bitmaps of smaller size are substituted, but we have to align them */
\r
2550 x += (squareSize - minorSize)>>1;
\r
2551 y += squareSize - minorSize - 2;
\r
2552 tmpSize = minorSize;
\r
2554 if (color || appData.allWhite ) {
\r
2555 oldBitmap = SelectObject(tmphdc, PieceBitmap(piece, WHITE_PIECE));
\r
2557 oldBrush = SelectObject(hdc, whitePieceBrush);
\r
2558 else oldBrush = SelectObject(hdc, blackPieceBrush);
\r
2559 if(appData.upsideDown && color==flipView)
\r
2560 StretchBlt(hdc, x+tmpSize, y+tmpSize, -tmpSize, -tmpSize, tmphdc, 0, 0, tmpSize, tmpSize, 0x00B8074A);
\r
2562 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, 0x00B8074A);
\r
2563 /* Use black for outline of white pieces */
\r
2564 SelectObject(tmphdc, PieceBitmap(piece, OUTLINE_PIECE));
\r
2565 if(appData.upsideDown && color==flipView)
\r
2566 StretchBlt(hdc, x+tmpSize, y+tmpSize, -tmpSize, -tmpSize, tmphdc, 0, 0, tmpSize, tmpSize, SRCAND);
\r
2568 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, SRCAND);
\r
2570 /* Use square color for details of black pieces */
\r
2571 oldBitmap = SelectObject(tmphdc, PieceBitmap(piece, SOLID_PIECE));
\r
2572 oldBrush = SelectObject(hdc, blackPieceBrush);
\r
2573 if(appData.upsideDown && !flipView)
\r
2574 StretchBlt(hdc, x+tmpSize, y+tmpSize, -tmpSize, -tmpSize, tmphdc, 0, 0, tmpSize, tmpSize, 0x00B8074A);
\r
2576 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, 0x00B8074A);
\r
2578 SelectObject(hdc, oldBrush);
\r
2579 SelectObject(tmphdc, oldBitmap);
\r
2583 /* [AS] Compute a drawing mode for a square, based on specified settings (see DrawTile) */
\r
2584 int GetBackTextureMode( int algo )
\r
2586 int result = BACK_TEXTURE_MODE_DISABLED;
\r
2590 case BACK_TEXTURE_MODE_PLAIN:
\r
2591 result = 1; /* Always use identity map */
\r
2593 case BACK_TEXTURE_MODE_FULL_RANDOM:
\r
2594 result = 1 + (myrandom() % 3); /* Pick a transformation at random */
\r
2602 [AS] Compute and save texture drawing info, otherwise we may not be able
\r
2603 to handle redraws cleanly (as random numbers would always be different).
\r
2605 VOID RebuildTextureSquareInfo()
\r
2615 ZeroMemory( &backTextureSquareInfo, sizeof(backTextureSquareInfo) );
\r
2617 if( liteBackTexture != NULL ) {
\r
2618 if( GetObject( liteBackTexture, sizeof(bi), &bi ) > 0 ) {
\r
2619 lite_w = bi.bmWidth;
\r
2620 lite_h = bi.bmHeight;
\r
2624 if( darkBackTexture != NULL ) {
\r
2625 if( GetObject( darkBackTexture, sizeof(bi), &bi ) > 0 ) {
\r
2626 dark_w = bi.bmWidth;
\r
2627 dark_h = bi.bmHeight;
\r
2631 for( row=0; row<BOARD_HEIGHT; row++ ) {
\r
2632 for( col=0; col<BOARD_WIDTH; col++ ) {
\r
2633 if( (col + row) & 1 ) {
\r
2635 if( lite_w >= squareSize && lite_h >= squareSize ) {
\r
2636 backTextureSquareInfo[row][col].x = col * (lite_w - squareSize) / (BOARD_WIDTH-1); /* [HGM] divide by size-1 in stead of size! */
\r
2637 backTextureSquareInfo[row][col].y = (BOARD_HEIGHT-1-row) * (lite_h - squareSize) / (BOARD_HEIGHT-1);
\r
2638 backTextureSquareInfo[row][col].mode = GetBackTextureMode(liteBackTextureMode);
\r
2643 if( dark_w >= squareSize && dark_h >= squareSize ) {
\r
2644 backTextureSquareInfo[row][col].x = col * (dark_w - squareSize) / (BOARD_WIDTH-1);
\r
2645 backTextureSquareInfo[row][col].y = (BOARD_HEIGHT-1-row) * (dark_h - squareSize) / (BOARD_HEIGHT-1);
\r
2646 backTextureSquareInfo[row][col].mode = GetBackTextureMode(darkBackTextureMode);
\r
2653 /* [AS] Arrow highlighting support */
\r
2655 static int A_WIDTH = 5; /* Width of arrow body */
\r
2657 #define A_HEIGHT_FACTOR 6 /* Length of arrow "point", relative to body width */
\r
2658 #define A_WIDTH_FACTOR 3 /* Width of arrow "point", relative to body width */
\r
2660 static double Sqr( double x )
\r
2665 static int Round( double x )
\r
2667 return (int) (x + 0.5);
\r
2670 /* Draw an arrow between two points using current settings */
\r
2671 VOID DrawArrowBetweenPoints( HDC hdc, int s_x, int s_y, int d_x, int d_y )
\r
2674 double dx, dy, j, k, x, y;
\r
2676 if( d_x == s_x ) {
\r
2677 int h = (d_y > s_y) ? +A_WIDTH*A_HEIGHT_FACTOR : -A_WIDTH*A_HEIGHT_FACTOR;
\r
2679 arrow[0].x = s_x + A_WIDTH;
\r
2682 arrow[1].x = s_x + A_WIDTH;
\r
2683 arrow[1].y = d_y - h;
\r
2685 arrow[2].x = s_x + A_WIDTH*A_WIDTH_FACTOR;
\r
2686 arrow[2].y = d_y - h;
\r
2691 arrow[4].x = s_x - A_WIDTH*A_WIDTH_FACTOR;
\r
2692 arrow[4].y = d_y - h;
\r
2694 arrow[5].x = s_x - A_WIDTH;
\r
2695 arrow[5].y = d_y - h;
\r
2697 arrow[6].x = s_x - A_WIDTH;
\r
2700 else if( d_y == s_y ) {
\r
2701 int w = (d_x > s_x) ? +A_WIDTH*A_HEIGHT_FACTOR : -A_WIDTH*A_HEIGHT_FACTOR;
\r
2704 arrow[0].y = s_y + A_WIDTH;
\r
2706 arrow[1].x = d_x - w;
\r
2707 arrow[1].y = s_y + A_WIDTH;
\r
2709 arrow[2].x = d_x - w;
\r
2710 arrow[2].y = s_y + A_WIDTH*A_WIDTH_FACTOR;
\r
2715 arrow[4].x = d_x - w;
\r
2716 arrow[4].y = s_y - A_WIDTH*A_WIDTH_FACTOR;
\r
2718 arrow[5].x = d_x - w;
\r
2719 arrow[5].y = s_y - A_WIDTH;
\r
2722 arrow[6].y = s_y - A_WIDTH;
\r
2725 /* [AS] Needed a lot of paper for this! :-) */
\r
2726 dy = (double) (d_y - s_y) / (double) (d_x - s_x);
\r
2727 dx = (double) (s_x - d_x) / (double) (s_y - d_y);
\r
2729 j = sqrt( Sqr(A_WIDTH) / (1.0 + Sqr(dx)) );
\r
2731 k = sqrt( Sqr(A_WIDTH*A_HEIGHT_FACTOR) / (1.0 + Sqr(dy)) );
\r
2736 arrow[0].x = Round(x - j);
\r
2737 arrow[0].y = Round(y + j*dx);
\r
2739 arrow[1].x = Round(x + j);
\r
2740 arrow[1].y = Round(y - j*dx);
\r
2743 x = (double) d_x - k;
\r
2744 y = (double) d_y - k*dy;
\r
2747 x = (double) d_x + k;
\r
2748 y = (double) d_y + k*dy;
\r
2751 arrow[2].x = Round(x + j);
\r
2752 arrow[2].y = Round(y - j*dx);
\r
2754 arrow[3].x = Round(x + j*A_WIDTH_FACTOR);
\r
2755 arrow[3].y = Round(y - j*A_WIDTH_FACTOR*dx);
\r
2760 arrow[5].x = Round(x - j*A_WIDTH_FACTOR);
\r
2761 arrow[5].y = Round(y + j*A_WIDTH_FACTOR*dx);
\r
2763 arrow[6].x = Round(x - j);
\r
2764 arrow[6].y = Round(y + j*dx);
\r
2767 Polygon( hdc, arrow, 7 );
\r
2770 /* [AS] Draw an arrow between two squares */
\r
2771 VOID DrawArrowBetweenSquares( HDC hdc, int s_col, int s_row, int d_col, int d_row )
\r
2773 int s_x, s_y, d_x, d_y;
\r
2780 if( s_col == d_col && s_row == d_row ) {
\r
2784 /* Get source and destination points */
\r
2785 SquareToPos( s_row, s_col, &s_x, &s_y);
\r
2786 SquareToPos( d_row, d_col, &d_x, &d_y);
\r
2789 d_y += squareSize / 4;
\r
2791 else if( d_y < s_y ) {
\r
2792 d_y += 3 * squareSize / 4;
\r
2795 d_y += squareSize / 2;
\r
2799 d_x += squareSize / 4;
\r
2801 else if( d_x < s_x ) {
\r
2802 d_x += 3 * squareSize / 4;
\r
2805 d_x += squareSize / 2;
\r
2808 s_x += squareSize / 2;
\r
2809 s_y += squareSize / 2;
\r
2811 /* Adjust width */
\r
2812 A_WIDTH = squareSize / 14;
\r
2815 stLB.lbStyle = BS_SOLID;
\r
2816 stLB.lbColor = appData.highlightArrowColor;
\r
2819 hpen = CreatePen( PS_SOLID, 2, RGB(0x00,0x00,0x00) );
\r
2820 holdpen = SelectObject( hdc, hpen );
\r
2821 hbrush = CreateBrushIndirect( &stLB );
\r
2822 holdbrush = SelectObject( hdc, hbrush );
\r
2824 DrawArrowBetweenPoints( hdc, s_x, s_y, d_x, d_y );
\r
2826 SelectObject( hdc, holdpen );
\r
2827 SelectObject( hdc, holdbrush );
\r
2828 DeleteObject( hpen );
\r
2829 DeleteObject( hbrush );
\r
2832 BOOL HasHighlightInfo()
\r
2834 BOOL result = FALSE;
\r
2836 if( highlightInfo.sq[0].x >= 0 && highlightInfo.sq[0].y >= 0 &&
\r
2837 highlightInfo.sq[1].x >= 0 && highlightInfo.sq[1].y >= 0 )
\r
2845 BOOL IsDrawArrowEnabled()
\r
2847 BOOL result = FALSE;
\r
2849 if( appData.highlightMoveWithArrow && squareSize >= 32 ) {
\r
2856 VOID DrawArrowHighlight( HDC hdc )
\r
2858 if( IsDrawArrowEnabled() && HasHighlightInfo() ) {
\r
2859 DrawArrowBetweenSquares( hdc,
\r
2860 highlightInfo.sq[0].x, highlightInfo.sq[0].y,
\r
2861 highlightInfo.sq[1].x, highlightInfo.sq[1].y );
\r
2865 HRGN GetArrowHighlightClipRegion( HDC hdc )
\r
2867 HRGN result = NULL;
\r
2869 if( HasHighlightInfo() ) {
\r
2870 int x1, y1, x2, y2;
\r
2871 int sx, sy, dx, dy;
\r
2873 SquareToPos(highlightInfo.sq[0].y, highlightInfo.sq[0].x, &x1, &y1 );
\r
2874 SquareToPos(highlightInfo.sq[1].y, highlightInfo.sq[1].x, &x2, &y2 );
\r
2876 sx = MIN( x1, x2 );
\r
2877 sy = MIN( y1, y2 );
\r
2878 dx = MAX( x1, x2 ) + squareSize;
\r
2879 dy = MAX( y1, y2 ) + squareSize;
\r
2881 result = CreateRectRgn( sx, sy, dx, dy );
\r
2888 Warning: this function modifies the behavior of several other functions.
\r
2890 Basically, Winboard is optimized to avoid drawing the whole board if not strictly
\r
2891 needed. Unfortunately, the decision whether or not to perform a full or partial
\r
2892 repaint is scattered all over the place, which is not good for features such as
\r
2893 "arrow highlighting" that require a full repaint of the board.
\r
2895 So, I've tried to patch the code where I thought it made sense (e.g. after or during
\r
2896 user interaction, when speed is not so important) but especially to avoid errors
\r
2897 in the displayed graphics.
\r
2899 In such patched places, I always try refer to this function so there is a single
\r
2900 place to maintain knowledge.
\r
2902 To restore the original behavior, just return FALSE unconditionally.
\r
2904 BOOL IsFullRepaintPreferrable()
\r
2906 BOOL result = FALSE;
\r
2908 if( (appData.highlightLastMove || appData.highlightDragging) && IsDrawArrowEnabled() ) {
\r
2909 /* Arrow may appear on the board */
\r
2917 This function is called by DrawPosition to know whether a full repaint must
\r
2920 Only DrawPosition may directly call this function, which makes use of
\r
2921 some state information. Other function should call DrawPosition specifying
\r
2922 the repaint flag, and can use IsFullRepaintPreferrable if needed.
\r
2924 BOOL DrawPositionNeedsFullRepaint()
\r
2926 BOOL result = FALSE;
\r
2929 Probably a slightly better policy would be to trigger a full repaint
\r
2930 when animInfo.piece changes state (i.e. empty -> non-empty and viceversa),
\r
2931 but animation is fast enough that it's difficult to notice.
\r
2933 if( animInfo.piece == EmptySquare ) {
\r
2934 if( (appData.highlightLastMove || appData.highlightDragging) && IsDrawArrowEnabled() /*&& HasHighlightInfo()*/ ) {
\r
2943 DrawBoardOnDC(HDC hdc, Board board, HDC tmphdc)
\r
2945 int row, column, x, y, square_color, piece_color;
\r
2946 ChessSquare piece;
\r
2948 HDC texture_hdc = NULL;
\r
2950 /* [AS] Initialize background textures if needed */
\r
2951 if( liteBackTexture != NULL || darkBackTexture != NULL ) {
\r
2952 static int backTextureBoardSize; /* [HGM] boardsize: also new texture if board format changed */
\r
2953 if( backTextureSquareSize != squareSize
\r
2954 || backTextureBoardSize != BOARD_WIDTH+BOARD_FILES*BOARD_HEIGHT) {
\r
2955 backTextureBoardSize = BOARD_WIDTH+BOARD_FILES*BOARD_HEIGHT;
\r
2956 backTextureSquareSize = squareSize;
\r
2957 RebuildTextureSquareInfo();
\r
2960 texture_hdc = CreateCompatibleDC( hdc );
\r
2963 for (row = 0; row < BOARD_HEIGHT; row++) {
\r
2964 for (column = 0; column < BOARD_WIDTH; column++) {
\r
2966 SquareToPos(row, column, &x, &y);
\r
2968 piece = board[row][column];
\r
2970 square_color = ((column + row) % 2) == 1;
\r
2971 if( gameInfo.variant == VariantXiangqi ) {
\r
2972 square_color = !InPalace(row, column);
\r
2973 if(BOARD_HEIGHT&1) { if(row==BOARD_HEIGHT/2) square_color ^= 1; }
\r
2974 else if(row < BOARD_HEIGHT/2) square_color ^= 1;
\r
2976 piece_color = (int) piece < (int) BlackPawn;
\r
2979 /* [HGM] holdings file: light square or black */
\r
2980 if(column == BOARD_LEFT-2) {
\r
2981 if( row > BOARD_HEIGHT - gameInfo.holdingsSize - 1 )
\r
2984 DisplayHoldingsCount(hdc, x, y, 0, 0); /* black out */
\r
2988 if(column == BOARD_RGHT + 1 ) {
\r
2989 if( row < gameInfo.holdingsSize )
\r
2992 DisplayHoldingsCount(hdc, x, y, 0, 0);
\r
2996 if(column == BOARD_LEFT-1 ) /* left align */
\r
2997 DisplayHoldingsCount(hdc, x, y, flipView, (int) board[row][column]);
\r
2998 else if( column == BOARD_RGHT) /* right align */
\r
2999 DisplayHoldingsCount(hdc, x, y, !flipView, (int) board[row][column]);
\r
3001 if (appData.monoMode) {
\r
3002 if (piece == EmptySquare) {
\r
3003 BitBlt(hdc, x, y, squareSize, squareSize, 0, 0, 0,
\r
3004 square_color ? WHITENESS : BLACKNESS);
\r
3006 DrawPieceOnDC(hdc, piece, piece_color, square_color, x, y, tmphdc);
\r
3009 else if( backTextureSquareInfo[row][column].mode > 0 ) {
\r
3010 /* [AS] Draw the square using a texture bitmap */
\r
3011 HBITMAP hbm = SelectObject( texture_hdc, square_color ? liteBackTexture : darkBackTexture );
\r
3012 int r = row, c = column; // [HGM] do not flip board in flipView
\r
3013 if(flipView) { r = BOARD_HEIGHT-1 - r; c = BOARD_WIDTH-1 - c; }
\r
3016 squareSize, squareSize,
\r
3019 backTextureSquareInfo[r][c].mode,
\r
3020 backTextureSquareInfo[r][c].x,
\r
3021 backTextureSquareInfo[r][c].y );
\r
3023 SelectObject( texture_hdc, hbm );
\r
3025 if (piece != EmptySquare) {
\r
3026 DrawPieceOnDC(hdc, piece, piece_color, -1, x, y, tmphdc);
\r
3030 HBRUSH brush = square_color ? lightSquareBrush : darkSquareBrush;
\r
3032 oldBrush = SelectObject(hdc, brush );
\r
3033 BitBlt(hdc, x, y, squareSize, squareSize, 0, 0, 0, PATCOPY);
\r
3034 SelectObject(hdc, oldBrush);
\r
3035 if (piece != EmptySquare)
\r
3036 DrawPieceOnDC(hdc, piece, piece_color, -1, x, y, tmphdc);
\r
3041 if( texture_hdc != NULL ) {
\r
3042 DeleteDC( texture_hdc );
\r
3046 int saveDiagFlag = 0; FILE *diagFile; // [HGM] diag
\r
3047 void fputDW(FILE *f, int x)
\r
3049 fputc(x & 255, f);
\r
3050 fputc(x>>8 & 255, f);
\r
3051 fputc(x>>16 & 255, f);
\r
3052 fputc(x>>24 & 255, f);
\r
3055 #define MAX_CLIPS 200 /* more than enough */
\r
3058 DrawLogoOnDC(HDC hdc, RECT logoRect, HBITMAP logo)
\r
3060 // HBITMAP bufferBitmap;
\r
3065 int w = 100, h = 50;
\r
3067 if(logo == NULL) return;
\r
3068 // GetClientRect(hwndMain, &Rect);
\r
3069 // bufferBitmap = CreateCompatibleBitmap(hdc, Rect.right-Rect.left+1,
\r
3070 // Rect.bottom-Rect.top+1);
\r
3071 tmphdc = CreateCompatibleDC(hdc);
\r
3072 hbm = SelectObject(tmphdc, logo);
\r
3073 if( GetObject( logo, sizeof(bi), &bi ) > 0 ) {
\r
3077 StretchBlt(hdc, logoRect.left, logoRect.top, logoRect.right - logoRect.left,
\r
3078 logoRect.bottom - logoRect.top, tmphdc, 0, 0, w, h, SRCCOPY);
\r
3079 SelectObject(tmphdc, hbm);
\r
3084 HDCDrawPosition(HDC hdc, BOOLEAN repaint, Board board)
\r
3086 static Board lastReq, lastDrawn;
\r
3087 static HighlightInfo lastDrawnHighlight, lastDrawnPremove;
\r
3088 static int lastDrawnFlipView = 0;
\r
3089 static int lastReqValid = 0, lastDrawnValid = 0;
\r
3090 int releaseDC, x, y, x2, y2, row, column, num_clips = 0, i;
\r
3093 HBITMAP bufferBitmap;
\r
3094 HBITMAP oldBitmap;
\r
3096 HRGN clips[MAX_CLIPS];
\r
3097 ChessSquare dragged_piece = EmptySquare;
\r
3099 /* I'm undecided on this - this function figures out whether a full
\r
3100 * repaint is necessary on its own, so there's no real reason to have the
\r
3101 * caller tell it that. I think this can safely be set to FALSE - but
\r
3102 * if we trust the callers not to request full repaints unnessesarily, then
\r
3103 * we could skip some clipping work. In other words, only request a full
\r
3104 * redraw when the majority of pieces have changed positions (ie. flip,
\r
3105 * gamestart and similar) --Hawk
\r
3107 Boolean fullrepaint = repaint;
\r
3109 if( DrawPositionNeedsFullRepaint() ) {
\r
3110 fullrepaint = TRUE;
\r
3113 if (board == NULL) {
\r
3114 if (!lastReqValid) {
\r
3119 CopyBoard(lastReq, board);
\r
3123 if (doingSizing) {
\r
3127 if (IsIconic(hwndMain)) {
\r
3131 if (hdc == NULL) {
\r
3132 hdc = GetDC(hwndMain);
\r
3133 if (!appData.monoMode) {
\r
3134 SelectPalette(hdc, hPal, FALSE);
\r
3135 RealizePalette(hdc);
\r
3139 releaseDC = FALSE;
\r
3142 /* Create some work-DCs */
\r
3143 hdcmem = CreateCompatibleDC(hdc);
\r
3144 tmphdc = CreateCompatibleDC(hdc);
\r
3146 /* If dragging is in progress, we temporarely remove the piece */
\r
3147 /* [HGM] or temporarily decrease count if stacked */
\r
3148 /* !! Moved to before board compare !! */
\r
3149 if (dragInfo.from.x >= 0 && dragInfo.pos.x >= 0) {
\r
3150 dragged_piece = board[dragInfo.from.y][dragInfo.from.x];
\r
3151 if(dragInfo.from.x == BOARD_LEFT-2 ) {
\r
3152 if(--board[dragInfo.from.y][dragInfo.from.x+1] == 0 )
\r
3153 board[dragInfo.from.y][dragInfo.from.x] = EmptySquare;
\r
3155 if(dragInfo.from.x == BOARD_RGHT+1) {
\r
3156 if(--board[dragInfo.from.y][dragInfo.from.x-1] == 0 )
\r
3157 board[dragInfo.from.y][dragInfo.from.x] = EmptySquare;
\r
3159 board[dragInfo.from.y][dragInfo.from.x] = EmptySquare;
\r
3162 /* Figure out which squares need updating by comparing the
\r
3163 * newest board with the last drawn board and checking if
\r
3164 * flipping has changed.
\r
3166 if (!fullrepaint && lastDrawnValid && lastDrawnFlipView == flipView) {
\r
3167 for (row = 0; row < BOARD_HEIGHT; row++) { /* [HGM] true size, not 8 */
\r
3168 for (column = 0; column < BOARD_WIDTH; column++) {
\r
3169 if (lastDrawn[row][column] != board[row][column]) {
\r
3170 SquareToPos(row, column, &x, &y);
\r
3171 clips[num_clips++] =
\r
3172 CreateRectRgn(x, y, x + squareSize, y + squareSize);
\r
3176 for (i=0; i<2; i++) {
\r
3177 if (lastDrawnHighlight.sq[i].x != highlightInfo.sq[i].x ||
\r
3178 lastDrawnHighlight.sq[i].y != highlightInfo.sq[i].y) {
\r
3179 if (lastDrawnHighlight.sq[i].x >= 0 &&
\r
3180 lastDrawnHighlight.sq[i].y >= 0) {
\r
3181 SquareToPos(lastDrawnHighlight.sq[i].y,
\r
3182 lastDrawnHighlight.sq[i].x, &x, &y);
\r
3183 clips[num_clips++] =
\r
3184 CreateRectRgn(x - lineGap, y - lineGap,
\r
3185 x + squareSize + lineGap, y + squareSize + lineGap);
\r
3187 if (highlightInfo.sq[i].x >= 0 && highlightInfo.sq[i].y >= 0) {
\r
3188 SquareToPos(highlightInfo.sq[i].y, highlightInfo.sq[i].x, &x, &y);
\r
3189 clips[num_clips++] =
\r
3190 CreateRectRgn(x - lineGap, y - lineGap,
\r
3191 x + squareSize + lineGap, y + squareSize + lineGap);
\r
3195 for (i=0; i<2; i++) {
\r
3196 if (lastDrawnPremove.sq[i].x != premoveHighlightInfo.sq[i].x ||
\r
3197 lastDrawnPremove.sq[i].y != premoveHighlightInfo.sq[i].y) {
\r
3198 if (lastDrawnPremove.sq[i].x >= 0 &&
\r
3199 lastDrawnPremove.sq[i].y >= 0) {
\r
3200 SquareToPos(lastDrawnPremove.sq[i].y,
\r
3201 lastDrawnPremove.sq[i].x, &x, &y);
\r
3202 clips[num_clips++] =
\r
3203 CreateRectRgn(x - lineGap, y - lineGap,
\r
3204 x + squareSize + lineGap, y + squareSize + lineGap);
\r
3206 if (premoveHighlightInfo.sq[i].x >= 0 &&
\r
3207 premoveHighlightInfo.sq[i].y >= 0) {
\r
3208 SquareToPos(premoveHighlightInfo.sq[i].y,
\r
3209 premoveHighlightInfo.sq[i].x, &x, &y);
\r
3210 clips[num_clips++] =
\r
3211 CreateRectRgn(x - lineGap, y - lineGap,
\r
3212 x + squareSize + lineGap, y + squareSize + lineGap);
\r
3217 fullrepaint = TRUE;
\r
3220 /* Create a buffer bitmap - this is the actual bitmap
\r
3221 * being written to. When all the work is done, we can
\r
3222 * copy it to the real DC (the screen). This avoids
\r
3223 * the problems with flickering.
\r
3225 GetClientRect(hwndMain, &Rect);
\r
3226 bufferBitmap = CreateCompatibleBitmap(hdc, Rect.right-Rect.left+1,
\r
3227 Rect.bottom-Rect.top+1);
\r
3228 oldBitmap = SelectObject(hdcmem, bufferBitmap);
\r
3229 if (!appData.monoMode) {
\r
3230 SelectPalette(hdcmem, hPal, FALSE);
\r
3233 /* Create clips for dragging */
\r
3234 if (!fullrepaint) {
\r
3235 if (dragInfo.from.x >= 0) {
\r
3236 SquareToPos(dragInfo.from.y, dragInfo.from.x, &x, &y);
\r
3237 clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);
\r
3239 if (dragInfo.start.x >= 0) {
\r
3240 SquareToPos(dragInfo.start.y, dragInfo.start.x, &x, &y);
\r
3241 clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);
\r
3243 if (dragInfo.pos.x >= 0) {
\r
3244 x = dragInfo.pos.x - squareSize / 2;
\r
3245 y = dragInfo.pos.y - squareSize / 2;
\r
3246 clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);
\r
3248 if (dragInfo.lastpos.x >= 0) {
\r
3249 x = dragInfo.lastpos.x - squareSize / 2;
\r
3250 y = dragInfo.lastpos.y - squareSize / 2;
\r
3251 clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);
\r
3255 /* Are we animating a move?
\r
3257 * - remove the piece from the board (temporarely)
\r
3258 * - calculate the clipping region
\r
3260 if (!fullrepaint) {
\r
3261 if (animInfo.piece != EmptySquare) {
\r
3262 board[animInfo.from.y][animInfo.from.x] = EmptySquare;
\r
3263 x = boardRect.left + animInfo.lastpos.x;
\r
3264 y = boardRect.top + animInfo.lastpos.y;
\r
3265 x2 = boardRect.left + animInfo.pos.x;
\r
3266 y2 = boardRect.top + animInfo.pos.y;
\r
3267 clips[num_clips++] = CreateRectRgn(MIN(x,x2), MIN(y,y2), MAX(x,x2)+squareSize, MAX(y,y2)+squareSize);
\r
3268 /* Slight kludge. The real problem is that after AnimateMove is
\r
3269 done, the position on the screen does not match lastDrawn.
\r
3270 This currently causes trouble only on e.p. captures in
\r
3271 atomic, where the piece moves to an empty square and then
\r
3272 explodes. The old and new positions both had an empty square
\r
3273 at the destination, but animation has drawn a piece there and
\r
3274 we have to remember to erase it. [HGM] moved until after setting lastDrawn */
\r
3275 lastDrawn[animInfo.to.y][animInfo.to.x] = animInfo.piece;
\r
3279 /* No clips? Make sure we have fullrepaint set to TRUE */
\r
3280 if (num_clips == 0)
\r
3281 fullrepaint = TRUE;
\r
3283 /* Set clipping on the memory DC */
\r
3284 if (!fullrepaint) {
\r
3285 SelectClipRgn(hdcmem, clips[0]);
\r
3286 for (x = 1; x < num_clips; x++) {
\r
3287 if (ExtSelectClipRgn(hdcmem, clips[x], RGN_OR) == ERROR)
\r
3288 abort(); // this should never ever happen!
\r
3292 /* Do all the drawing to the memory DC */
\r
3293 if(explodeInfo.radius) { // [HGM] atomic
\r
3295 int x, y, r=(explodeInfo.radius * squareSize)/100;
\r
3296 board[explodeInfo.fromY][explodeInfo.fromX] = EmptySquare; // suppress display of capturer
\r
3297 SquareToPos(explodeInfo.toY, explodeInfo.toX, &x, &y);
\r
3298 x += squareSize/2;
\r
3299 y += squareSize/2;
\r
3300 if(!fullrepaint) {
\r
3301 clips[num_clips] = CreateRectRgn(x-r, y-r, x+r, y+r);
\r
3302 ExtSelectClipRgn(hdcmem, clips[num_clips++], RGN_OR);
\r
3304 DrawGridOnDC(hdcmem);
\r
3305 DrawHighlightsOnDC(hdcmem);
\r
3306 DrawBoardOnDC(hdcmem, board, tmphdc);
\r
3307 oldBrush = SelectObject(hdcmem, explodeBrush);
\r
3308 Ellipse(hdcmem, x-r, y-r, x+r, y+r);
\r
3309 SelectObject(hdcmem, oldBrush);
\r
3311 DrawGridOnDC(hdcmem);
\r
3312 DrawHighlightsOnDC(hdcmem);
\r
3313 DrawBoardOnDC(hdcmem, board, tmphdc);
\r
3316 HBITMAP whiteLogo = (HBITMAP) first.programLogo, blackLogo = (HBITMAP) second.programLogo;
\r
3317 if(appData.autoLogo) {
\r
3319 switch(gameMode) { // pick logos based on game mode
\r
3320 case IcsObserving:
\r
3321 whiteLogo = second.programLogo; // ICS logo
\r
3322 blackLogo = second.programLogo;
\r
3325 case IcsPlayingWhite:
\r
3326 if(!appData.zippyPlay) whiteLogo = userLogo;
\r
3327 blackLogo = second.programLogo; // ICS logo
\r
3329 case IcsPlayingBlack:
\r
3330 whiteLogo = second.programLogo; // ICS logo
\r
3331 blackLogo = appData.zippyPlay ? first.programLogo : userLogo;
\r
3333 case TwoMachinesPlay:
\r
3334 if(first.twoMachinesColor[0] == 'b') {
\r
3335 whiteLogo = second.programLogo;
\r
3336 blackLogo = first.programLogo;
\r
3339 case MachinePlaysWhite:
\r
3340 blackLogo = userLogo;
\r
3342 case MachinePlaysBlack:
\r
3343 whiteLogo = userLogo;
\r
3344 blackLogo = first.programLogo;
\r
3347 DrawLogoOnDC(hdc, leftLogoRect, flipClock ? blackLogo : whiteLogo);
\r
3348 DrawLogoOnDC(hdc, rightLogoRect, flipClock ? whiteLogo : blackLogo);
\r
3351 if( appData.highlightMoveWithArrow ) {
\r
3352 DrawArrowHighlight(hdcmem);
\r
3355 DrawCoordsOnDC(hdcmem);
\r
3357 CopyBoard(lastDrawn, board); /* [HGM] Moved to here from end of routine, */
\r
3358 /* to make sure lastDrawn contains what is actually drawn */
\r
3360 /* Put the dragged piece back into place and draw it (out of place!) */
\r
3361 if (dragged_piece != EmptySquare) {
\r
3362 /* [HGM] or restack */
\r
3363 if(dragInfo.from.x == BOARD_LEFT-2 )
\r
3364 board[dragInfo.from.y][dragInfo.from.x+1]++;
\r
3366 if(dragInfo.from.x == BOARD_RGHT+1 )
\r
3367 board[dragInfo.from.y][dragInfo.from.x-1]++;
\r
3368 board[dragInfo.from.y][dragInfo.from.x] = dragged_piece;
\r
3369 x = dragInfo.pos.x - squareSize / 2;
\r
3370 y = dragInfo.pos.y - squareSize / 2;
\r
3371 DrawPieceOnDC(hdcmem, dragged_piece,
\r
3372 ((int) dragged_piece < (int) BlackPawn),
\r
3373 (dragInfo.from.y + dragInfo.from.x) % 2, x, y, tmphdc);
\r
3376 /* Put the animated piece back into place and draw it */
\r
3377 if (animInfo.piece != EmptySquare) {
\r
3378 board[animInfo.from.y][animInfo.from.x] = animInfo.piece;
\r
3379 x = boardRect.left + animInfo.pos.x;
\r
3380 y = boardRect.top + animInfo.pos.y;
\r
3381 DrawPieceOnDC(hdcmem, animInfo.piece,
\r
3382 ((int) animInfo.piece < (int) BlackPawn),
\r
3383 (animInfo.from.y + animInfo.from.x) % 2, x, y, tmphdc);
\r
3386 /* Release the bufferBitmap by selecting in the old bitmap
\r
3387 * and delete the memory DC
\r
3389 SelectObject(hdcmem, oldBitmap);
\r
3392 /* Set clipping on the target DC */
\r
3393 if (!fullrepaint) {
\r
3394 SelectClipRgn(hdc, clips[0]);
\r
3395 for (x = 1; x < num_clips; x++) {
\r
3396 if (ExtSelectClipRgn(hdc, clips[x], RGN_OR) == ERROR)
\r
3397 abort(); // this should never ever happen!
\r
3401 /* Copy the new bitmap onto the screen in one go.
\r
3402 * This way we avoid any flickering
\r
3404 oldBitmap = SelectObject(tmphdc, bufferBitmap);
\r
3405 BitBlt(hdc, boardRect.left, boardRect.top,
\r
3406 boardRect.right - boardRect.left,
\r
3407 boardRect.bottom - boardRect.top,
\r
3408 tmphdc, boardRect.left, boardRect.top, SRCCOPY);
\r
3409 if(saveDiagFlag) {
\r
3410 BITMAP b; int i, j=0, m, w, wb, fac=0; char pData[1000000];
\r
3411 BITMAPINFOHEADER bih; int color[16], nrColors=0;
\r
3413 GetObject(bufferBitmap, sizeof(b), &b);
\r
3414 if(b.bmWidthBytes*b.bmHeight <= 990000) {
\r
3415 bih.biSize = sizeof(BITMAPINFOHEADER);
\r
3416 bih.biWidth = b.bmWidth;
\r
3417 bih.biHeight = b.bmHeight;
\r
3419 bih.biBitCount = b.bmBitsPixel;
\r
3420 bih.biCompression = 0;
\r
3421 bih.biSizeImage = b.bmWidthBytes*b.bmHeight;
\r
3422 bih.biXPelsPerMeter = 0;
\r
3423 bih.biYPelsPerMeter = 0;
\r
3424 bih.biClrUsed = 0;
\r
3425 bih.biClrImportant = 0;
\r
3426 // fprintf(diagFile, "t=%d\nw=%d\nh=%d\nB=%d\nP=%d\nX=%d\n",
\r
3427 // b.bmType, b.bmWidth, b.bmHeight, b.bmWidthBytes, b.bmPlanes, b.bmBitsPixel);
\r
3428 GetDIBits(tmphdc,bufferBitmap,0,b.bmHeight,pData,(BITMAPINFO*)&bih,DIB_RGB_COLORS);
\r
3429 // fprintf(diagFile, "%8x\n", (int) pData);
\r
3431 wb = b.bmWidthBytes;
\r
3433 for(i=0; i<wb*(b.bmHeight - boardRect.top + OUTER_MARGIN)>>2; i++) {
\r
3434 int k = ((int*) pData)[i];
\r
3435 for(j=0; j<nrColors; j++) if(color[j] == k) break;
\r
3436 if(j >= 16) break;
\r
3438 if(j >= nrColors) nrColors = j+1;
\r
3440 if(j<16) { // 16 colors is enough. Compress to 4 bits per pixel
\r
3442 for(i=0; i<b.bmHeight - boardRect.top + OUTER_MARGIN; i++) {
\r
3443 for(w=0; w<(wb>>2); w+=2) {
\r
3444 int k = ((int*) pData)[(wb*i>>2) + w];
\r
3445 for(j=0; j<nrColors; j++) if(color[j] == k) break;
\r
3446 k = ((int*) pData)[(wb*i>>2) + w + 1];
\r
3447 for(m=0; m<nrColors; m++) if(color[m] == k) break;
\r
3448 pData[p++] = m | j<<4;
\r
3450 while(p&3) pData[p++] = 0;
\r
3453 wb = ((wb+31)>>5)<<2;
\r
3455 // write BITMAPFILEHEADER
\r
3456 fprintf(diagFile, "BM");
\r
3457 fputDW(diagFile, wb*(b.bmHeight - boardRect.top + OUTER_MARGIN)+0x36 + (fac?64:0));
\r
3458 fputDW(diagFile, 0);
\r
3459 fputDW(diagFile, 0x36 + (fac?64:0));
\r
3460 // write BITMAPINFOHEADER
\r
3461 fputDW(diagFile, 40);
\r
3462 fputDW(diagFile, b.bmWidth);
\r
3463 fputDW(diagFile, b.bmHeight - boardRect.top + OUTER_MARGIN);
\r
3464 if(fac) fputDW(diagFile, 0x040001); // planes and bits/pixel
\r
3465 else fputDW(diagFile, 0x200001); // planes and bits/pixel
\r
3466 fputDW(diagFile, 0);
\r
3467 fputDW(diagFile, 0);
\r
3468 fputDW(diagFile, 0);
\r
3469 fputDW(diagFile, 0);
\r
3470 fputDW(diagFile, 0);
\r
3471 fputDW(diagFile, 0);
\r
3472 // write color table
\r
3474 for(i=0; i<16; i++) fputDW(diagFile, color[i]);
\r
3475 // write bitmap data
\r
3476 for(i=0; i<wb*(b.bmHeight - boardRect.top + OUTER_MARGIN); i++)
\r
3477 fputc(pData[i], diagFile);
\r
3481 SelectObject(tmphdc, oldBitmap);
\r
3483 /* Massive cleanup */
\r
3484 for (x = 0; x < num_clips; x++)
\r
3485 DeleteObject(clips[x]);
\r
3488 DeleteObject(bufferBitmap);
\r
3491 ReleaseDC(hwndMain, hdc);
\r
3493 if (lastDrawnFlipView != flipView) {
\r
3495 CheckMenuItem(GetMenu(hwndMain),IDM_FlipView, MF_BYCOMMAND|MF_CHECKED);
\r
3497 CheckMenuItem(GetMenu(hwndMain),IDM_FlipView, MF_BYCOMMAND|MF_UNCHECKED);
\r
3500 /* CopyBoard(lastDrawn, board);*/
\r
3501 lastDrawnHighlight = highlightInfo;
\r
3502 lastDrawnPremove = premoveHighlightInfo;
\r
3503 lastDrawnFlipView = flipView;
\r
3504 lastDrawnValid = 1;
\r
3507 /* [HGM] diag: Save the current board display to the given open file and close the file */
\r
3512 saveDiagFlag = 1; diagFile = f;
\r
3513 HDCDrawPosition(NULL, TRUE, NULL);
\r
3517 // if(f != NULL) fprintf(f, "Sorry, but this feature is still in preparation\n");
\r
3524 /*---------------------------------------------------------------------------*\
\r
3525 | CLIENT PAINT PROCEDURE
\r
3526 | This is the main event-handler for the WM_PAINT message.
\r
3528 \*---------------------------------------------------------------------------*/
\r
3530 PaintProc(HWND hwnd)
\r
3536 if((hdc = BeginPaint(hwnd, &ps))) {
\r
3537 if (IsIconic(hwnd)) {
\r
3538 DrawIcon(hdc, 2, 2, iconCurrent);
\r
3540 if (!appData.monoMode) {
\r
3541 SelectPalette(hdc, hPal, FALSE);
\r
3542 RealizePalette(hdc);
\r
3544 HDCDrawPosition(hdc, 1, NULL);
\r
3546 SelectObject(hdc, font[boardSize][MESSAGE_FONT]->hf);
\r
3547 ExtTextOut(hdc, messageRect.left, messageRect.top,
\r
3548 ETO_CLIPPED|ETO_OPAQUE,
\r
3549 &messageRect, messageText, strlen(messageText), NULL);
\r
3550 SelectObject(hdc, oldFont);
\r
3551 DisplayBothClocks();
\r
3553 EndPaint(hwnd,&ps);
\r
3561 * If the user selects on a border boundary, return -1; if off the board,
\r
3562 * return -2. Otherwise map the event coordinate to the square.
\r
3563 * The offset boardRect.left or boardRect.top must already have been
\r
3564 * subtracted from x.
\r
3566 int EventToSquare(x, limit)
\r
3574 if ((x % (squareSize + lineGap)) >= squareSize)
\r
3576 x /= (squareSize + lineGap);
\r
3588 DropEnable dropEnables[] = {
\r
3589 { 'P', DP_Pawn, "Pawn" },
\r
3590 { 'N', DP_Knight, "Knight" },
\r
3591 { 'B', DP_Bishop, "Bishop" },
\r
3592 { 'R', DP_Rook, "Rook" },
\r
3593 { 'Q', DP_Queen, "Queen" },
\r
3597 SetupDropMenu(HMENU hmenu)
\r
3599 int i, count, enable;
\r
3601 extern char white_holding[], black_holding[];
\r
3602 char item[MSG_SIZ];
\r
3604 for (i=0; i<sizeof(dropEnables)/sizeof(DropEnable); i++) {
\r
3605 p = strchr(gameMode == IcsPlayingWhite ? white_holding : black_holding,
\r
3606 dropEnables[i].piece);
\r
3608 while (p && *p++ == dropEnables[i].piece) count++;
\r
3609 sprintf(item, "%s %d", dropEnables[i].name, count);
\r
3610 enable = count > 0 || !appData.testLegality
\r
3611 /*!!temp:*/ || (gameInfo.variant == VariantCrazyhouse
\r
3612 && !appData.icsActive);
\r
3613 ModifyMenu(hmenu, dropEnables[i].command,
\r
3614 MF_BYCOMMAND | (enable ? MF_ENABLED : MF_GRAYED) | MF_STRING,
\r
3615 dropEnables[i].command, item);
\r
3619 void DragPieceBegin(int x, int y)
\r
3621 dragInfo.lastpos.x = boardRect.left + x;
\r
3622 dragInfo.lastpos.y = boardRect.top + y;
\r
3623 dragInfo.from.x = fromX;
\r
3624 dragInfo.from.y = fromY;
\r
3625 dragInfo.start = dragInfo.from;
\r
3626 SetCapture(hwndMain);
\r
3629 void DragPieceEnd(int x, int y)
\r
3632 dragInfo.start.x = dragInfo.start.y = -1;
\r
3633 dragInfo.from = dragInfo.start;
\r
3634 dragInfo.pos = dragInfo.lastpos = dragInfo.start;
\r
3637 /* Event handler for mouse messages */
\r
3639 MouseEvent(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
3643 static int recursive = 0;
\r
3645 BOOLEAN forceFullRepaint = IsFullRepaintPreferrable(); /* [AS] */
\r
3648 if (message == WM_MBUTTONUP) {
\r
3649 /* Hideous kludge to fool TrackPopupMenu into paying attention
\r
3650 to the middle button: we simulate pressing the left button too!
\r
3652 PostMessage(hwnd, WM_LBUTTONDOWN, wParam, lParam);
\r
3653 PostMessage(hwnd, WM_LBUTTONUP, wParam, lParam);
\r
3659 pt.x = LOWORD(lParam);
\r
3660 pt.y = HIWORD(lParam);
\r
3661 x = EventToSquare(pt.x - boardRect.left, BOARD_WIDTH);
\r
3662 y = EventToSquare(pt.y - boardRect.top, BOARD_HEIGHT);
\r
3663 if (!flipView && y >= 0) {
\r
3664 y = BOARD_HEIGHT - 1 - y;
\r
3666 if (flipView && x >= 0) {
\r
3667 x = BOARD_WIDTH - 1 - x;
\r
3670 switch (message) {
\r
3671 case WM_LBUTTONDOWN:
\r
3672 if (PtInRect((LPRECT) &whiteRect, pt)) {
\r
3673 if (gameMode == EditPosition) {
\r
3674 SetWhiteToPlayEvent();
\r
3675 } else if (gameMode == IcsPlayingBlack ||
\r
3676 gameMode == MachinePlaysWhite) {
\r
3678 } else if (gameMode == EditGame) {
\r
3679 AdjustClock(flipClock, -1);
\r
3681 } else if (PtInRect((LPRECT) &blackRect, pt)) {
\r
3682 if (gameMode == EditPosition) {
\r
3683 SetBlackToPlayEvent();
\r
3684 } else if (gameMode == IcsPlayingWhite ||
\r
3685 gameMode == MachinePlaysBlack) {
\r
3687 } else if (gameMode == EditGame) {
\r
3688 AdjustClock(!flipClock, -1);
\r
3691 dragInfo.start.x = dragInfo.start.y = -1;
\r
3692 dragInfo.from = dragInfo.start;
\r
3693 if(fromX == -1 && frozen) { // not sure where this is for
\r
3694 fromX = fromY = -1;
\r
3695 DrawPosition(forceFullRepaint || FALSE, NULL); /* [AS] */
\r
3698 LeftClick(Press, pt.x - boardRect.left, pt.y - boardRect.top);
\r
3699 DrawPosition(TRUE, NULL);
\r
3702 case WM_LBUTTONUP:
\r
3703 LeftClick(Release, pt.x - boardRect.left, pt.y - boardRect.top);
\r
3704 DrawPosition(TRUE, NULL);
\r
3707 case WM_MOUSEMOVE:
\r
3708 if ((appData.animateDragging || appData.highlightDragging)
\r
3709 && (wParam & MK_LBUTTON)
\r
3710 && dragInfo.from.x >= 0)
\r
3712 BOOL full_repaint = FALSE;
\r
3714 if (appData.animateDragging) {
\r
3715 dragInfo.pos = pt;
\r
3717 if (appData.highlightDragging) {
\r
3718 SetHighlights(fromX, fromY, x, y);
\r
3719 if( IsDrawArrowEnabled() && (x < 0 || x >= BOARD_WIDTH || y < 0 || y >= BOARD_HEIGHT) ) {
\r
3720 full_repaint = TRUE;
\r
3724 DrawPosition( full_repaint, NULL);
\r
3726 dragInfo.lastpos = dragInfo.pos;
\r
3730 case WM_MOUSEWHEEL: // [DM]
\r
3731 { static int lastDir = 0; // [HGM] build in some hysteresis to avoid spurious events
\r
3732 /* Mouse Wheel is being rolled forward
\r
3733 * Play moves forward
\r
3735 if((short)HIWORD(wParam) > 0 && currentMove < forwardMostMove)
\r
3736 { if(lastDir == 1) ForwardEvent(); else lastDir = 1; } // [HGM] suppress first event in direction
\r
3737 /* Mouse Wheel is being rolled backward
\r
3738 * Play moves backward
\r
3740 if((short)HIWORD(wParam) < 0 && currentMove > backwardMostMove)
\r
3741 { if(lastDir == -1) BackwardEvent(); else lastDir = -1; }
\r
3745 case WM_MBUTTONDOWN:
\r
3746 case WM_RBUTTONDOWN:
\r
3749 fromX = fromY = -1;
\r
3750 dragInfo.pos.x = dragInfo.pos.y = -1;
\r
3751 dragInfo.start.x = dragInfo.start.y = -1;
\r
3752 dragInfo.from = dragInfo.start;
\r
3753 dragInfo.lastpos = dragInfo.pos;
\r
3754 if (appData.highlightDragging) {
\r
3755 ClearHighlights();
\r
3758 /* [HGM] right mouse button in clock area edit-game mode ups clock */
\r
3759 if (PtInRect((LPRECT) &whiteRect, pt)) {
\r
3760 if (gameMode == EditGame) AdjustClock(flipClock, 1);
\r
3761 } else if (PtInRect((LPRECT) &blackRect, pt)) {
\r
3762 if (gameMode == EditGame) AdjustClock(!flipClock, 1);
\r
3765 DrawPosition(TRUE, NULL);
\r
3767 switch (gameMode) {
\r
3768 case EditPosition:
\r
3769 case IcsExamining:
\r
3770 if (x < 0 || y < 0) break;
\r
3773 if (message == WM_MBUTTONDOWN) {
\r
3774 buttonCount = 3; /* even if system didn't think so */
\r
3775 if (wParam & MK_SHIFT)
\r
3776 MenuPopup(hwnd, pt, LoadMenu(hInst, "BlackPieceMenu"), -1);
\r
3778 MenuPopup(hwnd, pt, LoadMenu(hInst, "WhitePieceMenu"), -1);
\r
3779 } else { /* message == WM_RBUTTONDOWN */
\r
3780 /* Just have one menu, on the right button. Windows users don't
\r
3781 think to try the middle one, and sometimes other software steals
\r
3782 it, or it doesn't really exist. */
\r
3783 if(gameInfo.variant != VariantShogi)
\r
3784 MenuPopup(hwnd, pt, LoadMenu(hInst, "PieceMenu"), -1);
\r
3786 MenuPopup(hwnd, pt, LoadMenu(hInst, "ShogiPieceMenu"), -1);
\r
3789 case IcsPlayingWhite:
\r
3790 case IcsPlayingBlack:
\r
3792 case MachinePlaysWhite:
\r
3793 case MachinePlaysBlack:
\r
3794 if (appData.testLegality &&
\r
3795 gameInfo.variant != VariantBughouse &&
\r
3796 gameInfo.variant != VariantCrazyhouse) break;
\r
3797 if (x < 0 || y < 0) break;
\r
3800 hmenu = LoadMenu(hInst, "DropPieceMenu");
\r
3801 SetupDropMenu(hmenu);
\r
3802 MenuPopup(hwnd, pt, hmenu, -1);
\r
3813 /* Preprocess messages for buttons in main window */
\r
3815 ButtonProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
3817 int id = GetWindowLong(hwnd, GWL_ID);
\r
3820 for (i=0; i<N_BUTTONS; i++) {
\r
3821 if (buttonDesc[i].id == id) break;
\r
3823 if (i == N_BUTTONS) return 0;
\r
3824 switch (message) {
\r
3829 dir = (wParam == VK_LEFT) ? -1 : 1;
\r
3830 SetFocus(buttonDesc[(i + dir + N_BUTTONS) % N_BUTTONS].hwnd);
\r
3837 SendMessage(hwndMain, WM_COMMAND, MAKEWPARAM(buttonDesc[i].id, 0), 0);
\r
3840 if (appData.icsActive && (isalpha((char)wParam) || wParam == '0')) {
\r
3841 // [HGM] movenum: only letters or leading zero should go to ICS input
\r
3842 HWND h = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
3843 if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
3845 SendMessage(h, WM_CHAR, wParam, lParam);
\r
3847 } else if (isalpha((char)wParam) || isdigit((char)wParam)){
\r
3848 PopUpMoveDialog((char)wParam);
\r
3854 return CallWindowProc(buttonDesc[i].wndproc, hwnd, message, wParam, lParam);
\r
3857 /* Process messages for Promotion dialog box */
\r
3859 Promotion(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
3863 switch (message) {
\r
3864 case WM_INITDIALOG: /* message: initialize dialog box */
\r
3865 /* Center the dialog over the application window */
\r
3866 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
3867 ShowWindow(GetDlgItem(hDlg, PB_King),
\r
3868 (!appData.testLegality || gameInfo.variant == VariantSuicide ||
\r
3869 gameInfo.variant == VariantGiveaway || gameInfo.variant == VariantSuper ) ?
\r
3870 SW_SHOW : SW_HIDE);
\r
3871 /* [HGM] Only allow C & A promotions if these pieces are defined */
\r
3872 ShowWindow(GetDlgItem(hDlg, PB_Archbishop),
\r
3873 ((PieceToChar(WhiteAngel) >= 'A' &&
\r
3874 PieceToChar(WhiteAngel) != '~') ||
\r
3875 (PieceToChar(BlackAngel) >= 'A' &&
\r
3876 PieceToChar(BlackAngel) != '~') ) ?
\r
3877 SW_SHOW : SW_HIDE);
\r
3878 ShowWindow(GetDlgItem(hDlg, PB_Chancellor),
\r
3879 ((PieceToChar(WhiteMarshall) >= 'A' &&
\r
3880 PieceToChar(WhiteMarshall) != '~') ||
\r
3881 (PieceToChar(BlackMarshall) >= 'A' &&
\r
3882 PieceToChar(BlackMarshall) != '~') ) ?
\r
3883 SW_SHOW : SW_HIDE);
\r
3884 /* [HGM] Hide B & R button in Shogi, use Q as promote, N as defer */
\r
3885 ShowWindow(GetDlgItem(hDlg, PB_Rook),
\r
3886 gameInfo.variant != VariantShogi ?
\r
3887 SW_SHOW : SW_HIDE);
\r
3888 ShowWindow(GetDlgItem(hDlg, PB_Bishop),
\r
3889 gameInfo.variant != VariantShogi ?
\r
3890 SW_SHOW : SW_HIDE);
\r
3891 ShowWindow(GetDlgItem(hDlg, IDC_Yes),
\r
3892 gameInfo.variant == VariantShogi ?
\r
3893 SW_SHOW : SW_HIDE);
\r
3894 ShowWindow(GetDlgItem(hDlg, IDC_No),
\r
3895 gameInfo.variant == VariantShogi ?
\r
3896 SW_SHOW : SW_HIDE);
\r
3897 ShowWindow(GetDlgItem(hDlg, IDC_Centaur),
\r
3898 gameInfo.variant == VariantSuper ?
\r
3899 SW_SHOW : SW_HIDE);
\r
3902 case WM_COMMAND: /* message: received a command */
\r
3903 switch (LOWORD(wParam)) {
\r
3905 EndDialog(hDlg, TRUE); /* Exit the dialog */
\r
3906 ClearHighlights();
\r
3907 DrawPosition(FALSE, NULL);
\r
3910 promoChar = gameInfo.variant == VariantSuper ? PieceToChar(BlackSilver) : PieceToChar(BlackKing);
\r
3913 promoChar = gameInfo.variant == VariantShogi ? '+' : PieceToChar(BlackQueen);
\r
3916 promoChar = PieceToChar(BlackRook);
\r
3919 promoChar = PieceToChar(BlackBishop);
\r
3921 case PB_Chancellor:
\r
3922 promoChar = PieceToChar(BlackMarshall);
\r
3924 case PB_Archbishop:
\r
3925 promoChar = PieceToChar(BlackAngel);
\r
3928 promoChar = gameInfo.variant == VariantShogi ? '=' : PieceToChar(BlackKnight);
\r
3933 EndDialog(hDlg, TRUE); /* Exit the dialog */
\r
3934 /* [HGM] <popupFix> Call FinishMove rather than UserMoveEvent, as we
\r
3935 only show the popup when we are already sure the move is valid or
\r
3936 legal. We pass a faulty move type, but the kludge is that FinishMove
\r
3937 will figure out it is a promotion from the promoChar. */
\r
3938 UserMoveEvent(fromX, fromY, toX, toY, promoChar);
\r
3939 fromX = fromY = -1;
\r
3940 if (!appData.highlightLastMove) {
\r
3941 ClearHighlights();
\r
3942 DrawPosition(FALSE, NULL);
\r
3949 /* Pop up promotion dialog */
\r
3951 PromotionPopup(HWND hwnd)
\r
3955 lpProc = MakeProcInstance((FARPROC)Promotion, hInst);
\r
3956 DialogBox(hInst, MAKEINTRESOURCE(DLG_PromotionKing),
\r
3957 hwnd, (DLGPROC)lpProc);
\r
3958 FreeProcInstance(lpProc);
\r
3964 DrawPosition(TRUE, NULL);
\r
3965 PromotionPopup(hwndMain);
\r
3968 /* Toggle ShowThinking */
\r
3970 ToggleShowThinking()
\r
3972 appData.showThinking = !appData.showThinking;
\r
3973 ShowThinkingEvent();
\r
3977 LoadGameDialog(HWND hwnd, char* title)
\r
3981 char fileTitle[MSG_SIZ];
\r
3982 f = OpenFileDialog(hwnd, "rb", "",
\r
3983 appData.oldSaveStyle ? "gam" : "pgn",
\r
3985 title, &number, fileTitle, NULL);
\r
3987 cmailMsgLoaded = FALSE;
\r
3988 if (number == 0) {
\r
3989 int error = GameListBuild(f);
\r
3991 DisplayError("Cannot build game list", error);
\r
3992 } else if (!ListEmpty(&gameList) &&
\r
3993 ((ListGame *) gameList.tailPred)->number > 1) {
\r
3994 GameListPopUp(f, fileTitle);
\r
3997 GameListDestroy();
\r
4000 LoadGame(f, number, fileTitle, FALSE);
\r
4004 int get_term_width()
\r
4009 HFONT hfont, hold_font;
\r
4014 hText = GetDlgItem(hwndConsole, OPT_ConsoleText);
\r
4018 // get the text metrics
\r
4019 hdc = GetDC(hText);
\r
4020 lf = font[boardSize][CONSOLE_FONT]->lf;
\r
4021 if (consoleCF.dwEffects & CFE_BOLD)
\r
4022 lf.lfWeight = FW_BOLD;
\r
4023 if (consoleCF.dwEffects & CFE_ITALIC)
\r
4024 lf.lfItalic = TRUE;
\r
4025 if (consoleCF.dwEffects & CFE_STRIKEOUT)
\r
4026 lf.lfStrikeOut = TRUE;
\r
4027 if (consoleCF.dwEffects & CFE_UNDERLINE)
\r
4028 lf.lfUnderline = TRUE;
\r
4029 hfont = CreateFontIndirect(&lf);
\r
4030 hold_font = SelectObject(hdc, hfont);
\r
4031 GetTextMetrics(hdc, &tm);
\r
4032 SelectObject(hdc, hold_font);
\r
4033 DeleteObject(hfont);
\r
4034 ReleaseDC(hText, hdc);
\r
4036 // get the rectangle
\r
4037 SendMessage(hText, EM_GETRECT, 0, (LPARAM)&rc);
\r
4039 return (rc.right-rc.left) / tm.tmAveCharWidth;
\r
4042 void UpdateICSWidth(HWND hText)
\r
4044 LONG old_width, new_width;
\r
4046 new_width = get_term_width(hText, FALSE);
\r
4047 old_width = GetWindowLong(hText, GWL_USERDATA);
\r
4048 if (new_width != old_width)
\r
4050 ics_update_width(new_width);
\r
4051 SetWindowLong(hText, GWL_USERDATA, new_width);
\r
4056 ChangedConsoleFont()
\r
4059 CHARRANGE tmpsel, sel;
\r
4060 MyFont *f = font[boardSize][CONSOLE_FONT];
\r
4061 HWND hText = GetDlgItem(hwndConsole, OPT_ConsoleText);
\r
4062 HWND hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
4065 cfmt.cbSize = sizeof(CHARFORMAT);
\r
4066 cfmt.dwMask = CFM_FACE|CFM_SIZE|CFM_CHARSET;
\r
4067 strcpy(cfmt.szFaceName, font[boardSize][CONSOLE_FONT]->mfp.faceName);
\r
4068 /* yHeight is expressed in twips. A twip is 1/20 of a font's point
\r
4069 * size. This was undocumented in the version of MSVC++ that I had
\r
4070 * when I wrote the code, but is apparently documented now.
\r
4072 cfmt.yHeight = (int)(f->mfp.pointSize * 20.0 + 0.5);
\r
4073 cfmt.bCharSet = f->lf.lfCharSet;
\r
4074 cfmt.bPitchAndFamily = f->lf.lfPitchAndFamily;
\r
4075 SendMessage(hText, EM_SETCHARFORMAT, SCF_ALL, (LPARAM) &cfmt);
\r
4076 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM) &cfmt);
\r
4077 /* Why are the following seemingly needed too? */
\r
4078 SendMessage(hText, EM_SETCHARFORMAT, SCF_DEFAULT, (LPARAM) &cfmt);
\r
4079 SendMessage(hInput, EM_SETCHARFORMAT, SCF_DEFAULT, (LPARAM) &cfmt);
\r
4080 SendMessage(hText, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
4082 tmpsel.cpMax = -1; /*999999?*/
\r
4083 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&tmpsel);
\r
4084 SendMessage(hText, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM) &cfmt);
\r
4085 /* Trying putting this here too. It still seems to tickle a RichEdit
\r
4086 * bug: sometimes RichEdit indents the first line of a paragraph too.
\r
4088 paraf.cbSize = sizeof(paraf);
\r
4089 paraf.dwMask = PFM_OFFSET | PFM_STARTINDENT;
\r
4090 paraf.dxStartIndent = 0;
\r
4091 paraf.dxOffset = WRAP_INDENT;
\r
4092 SendMessage(hText, EM_SETPARAFORMAT, 0, (LPARAM) ¶f);
\r
4093 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
4094 UpdateICSWidth(hText);
\r
4097 /*---------------------------------------------------------------------------*\
\r
4099 * Window Proc for main window
\r
4101 \*---------------------------------------------------------------------------*/
\r
4103 /* Process messages for main window, etc. */
\r
4105 WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
4108 int wmId, wmEvent;
\r
4112 char fileTitle[MSG_SIZ];
\r
4113 char buf[MSG_SIZ];
\r
4114 static SnapData sd;
\r
4116 switch (message) {
\r
4118 case WM_PAINT: /* message: repaint portion of window */
\r
4122 case WM_ERASEBKGND:
\r
4123 if (IsIconic(hwnd)) {
\r
4124 /* Cheat; change the message */
\r
4125 return (DefWindowProc(hwnd, WM_ICONERASEBKGND, wParam, lParam));
\r
4127 return (DefWindowProc(hwnd, message, wParam, lParam));
\r
4131 case WM_LBUTTONDOWN:
\r
4132 case WM_MBUTTONDOWN:
\r
4133 case WM_RBUTTONDOWN:
\r
4134 case WM_LBUTTONUP:
\r
4135 case WM_MBUTTONUP:
\r
4136 case WM_RBUTTONUP:
\r
4137 case WM_MOUSEMOVE:
\r
4138 case WM_MOUSEWHEEL:
\r
4139 MouseEvent(hwnd, message, wParam, lParam);
\r
4142 JAWS_KB_NAVIGATION
\r
4146 JAWS_ALT_INTERCEPT
\r
4148 if (appData.icsActive && ((char)wParam == '\r' || (char)wParam > ' ' && !((char)wParam >= '1' && (char)wParam <= '9'))) {
\r
4149 // [HGM] movenum: for non-zero digits we always do type-in dialog
\r
4150 HWND h = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
4151 if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
4153 SendMessage(h, message, wParam, lParam);
\r
4154 } else if(lParam != KF_REPEAT) {
\r
4155 if (isalpha((char)wParam) || isdigit((char)wParam)) {
\r
4156 PopUpMoveDialog((char)wParam);
\r
4157 } else if((char)wParam == 003) CopyGameToClipboard();
\r
4158 else if((char)wParam == 026) PasteGameOrFENFromClipboard();
\r
4163 case WM_PALETTECHANGED:
\r
4164 if (hwnd != (HWND)wParam && !appData.monoMode) {
\r
4166 HDC hdc = GetDC(hwndMain);
\r
4167 SelectPalette(hdc, hPal, TRUE);
\r
4168 nnew = RealizePalette(hdc);
\r
4170 paletteChanged = TRUE;
\r
4171 InvalidateRect(hwnd, &boardRect, FALSE);
\r
4173 ReleaseDC(hwnd, hdc);
\r
4177 case WM_QUERYNEWPALETTE:
\r
4178 if (!appData.monoMode /*&& paletteChanged*/) {
\r
4180 HDC hdc = GetDC(hwndMain);
\r
4181 paletteChanged = FALSE;
\r
4182 SelectPalette(hdc, hPal, FALSE);
\r
4183 nnew = RealizePalette(hdc);
\r
4185 InvalidateRect(hwnd, &boardRect, FALSE);
\r
4187 ReleaseDC(hwnd, hdc);
\r
4192 case WM_COMMAND: /* message: command from application menu */
\r
4193 wmId = LOWORD(wParam);
\r
4194 wmEvent = HIWORD(wParam);
\r
4199 SAY("new game enter a move to play against the computer with white");
\r
4202 case IDM_NewGameFRC:
\r
4203 if( NewGameFRC() == 0 ) {
\r
4208 case IDM_NewVariant:
\r
4209 NewVariantPopup(hwnd);
\r
4212 case IDM_LoadGame:
\r
4213 LoadGameDialog(hwnd, "Load Game from File");
\r
4216 case IDM_LoadNextGame:
\r
4220 case IDM_LoadPrevGame:
\r
4224 case IDM_ReloadGame:
\r
4228 case IDM_LoadPosition:
\r
4229 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile) {
\r
4230 Reset(FALSE, TRUE);
\r
4233 f = OpenFileDialog(hwnd, "rb", "",
\r
4234 appData.oldSaveStyle ? "pos" : "fen",
\r
4236 "Load Position from File", &number, fileTitle, NULL);
\r
4238 LoadPosition(f, number, fileTitle);
\r
4242 case IDM_LoadNextPosition:
\r
4243 ReloadPosition(1);
\r
4246 case IDM_LoadPrevPosition:
\r
4247 ReloadPosition(-1);
\r
4250 case IDM_ReloadPosition:
\r
4251 ReloadPosition(0);
\r
4254 case IDM_SaveGame:
\r
4255 defName = DefaultFileName(appData.oldSaveStyle ? "gam" : "pgn");
\r
4256 f = OpenFileDialog(hwnd, "a", defName,
\r
4257 appData.oldSaveStyle ? "gam" : "pgn",
\r
4259 "Save Game to File", NULL, fileTitle, NULL);
\r
4261 SaveGame(f, 0, "");
\r
4265 case IDM_SavePosition:
\r
4266 defName = DefaultFileName(appData.oldSaveStyle ? "pos" : "fen");
\r
4267 f = OpenFileDialog(hwnd, "a", defName,
\r
4268 appData.oldSaveStyle ? "pos" : "fen",
\r
4270 "Save Position to File", NULL, fileTitle, NULL);
\r
4272 SavePosition(f, 0, "");
\r
4276 case IDM_SaveDiagram:
\r
4277 defName = "diagram";
\r
4278 f = OpenFileDialog(hwnd, "wb", defName,
\r
4281 "Save Diagram to File", NULL, fileTitle, NULL);
\r
4287 case IDM_CopyGame:
\r
4288 CopyGameToClipboard();
\r
4291 case IDM_PasteGame:
\r
4292 PasteGameFromClipboard();
\r
4295 case IDM_CopyGameListToClipboard:
\r
4296 CopyGameListToClipboard();
\r
4299 /* [AS] Autodetect FEN or PGN data */
\r
4300 case IDM_PasteAny:
\r
4301 PasteGameOrFENFromClipboard();
\r
4304 /* [AS] Move history */
\r
4305 case IDM_ShowMoveHistory:
\r
4306 if( MoveHistoryIsUp() ) {
\r
4307 MoveHistoryPopDown();
\r
4310 MoveHistoryPopUp();
\r
4314 /* [AS] Eval graph */
\r
4315 case IDM_ShowEvalGraph:
\r
4316 if( EvalGraphIsUp() ) {
\r
4317 EvalGraphPopDown();
\r
4321 SetFocus(hwndMain);
\r
4325 /* [AS] Engine output */
\r
4326 case IDM_ShowEngineOutput:
\r
4327 if( EngineOutputIsUp() ) {
\r
4328 EngineOutputPopDown();
\r
4331 EngineOutputPopUp();
\r
4335 /* [AS] User adjudication */
\r
4336 case IDM_UserAdjudication_White:
\r
4337 UserAdjudicationEvent( +1 );
\r
4340 case IDM_UserAdjudication_Black:
\r
4341 UserAdjudicationEvent( -1 );
\r
4344 case IDM_UserAdjudication_Draw:
\r
4345 UserAdjudicationEvent( 0 );
\r
4348 /* [AS] Game list options dialog */
\r
4349 case IDM_GameListOptions:
\r
4350 GameListOptions();
\r
4357 case IDM_CopyPosition:
\r
4358 CopyFENToClipboard();
\r
4361 case IDM_PastePosition:
\r
4362 PasteFENFromClipboard();
\r
4365 case IDM_MailMove:
\r
4369 case IDM_ReloadCMailMsg:
\r
4370 Reset(TRUE, TRUE);
\r
4371 ReloadCmailMsgEvent(FALSE);
\r
4374 case IDM_Minimize:
\r
4375 ShowWindow(hwnd, SW_MINIMIZE);
\r
4382 case IDM_MachineWhite:
\r
4383 MachineWhiteEvent();
\r
4385 * refresh the tags dialog only if it's visible
\r
4387 if (gameMode == MachinePlaysWhite && IsWindowVisible(editTagsDialog)) {
\r
4389 tags = PGNTags(&gameInfo);
\r
4390 TagsPopUp(tags, CmailMsg());
\r
4393 SAY("computer starts playing white");
\r
4396 case IDM_MachineBlack:
\r
4397 MachineBlackEvent();
\r
4399 * refresh the tags dialog only if it's visible
\r
4401 if (gameMode == MachinePlaysBlack && IsWindowVisible(editTagsDialog)) {
\r
4403 tags = PGNTags(&gameInfo);
\r
4404 TagsPopUp(tags, CmailMsg());
\r
4407 SAY("computer starts playing black");
\r
4410 case IDM_TwoMachines:
\r
4411 TwoMachinesEvent();
\r
4413 * refresh the tags dialog only if it's visible
\r
4415 if (gameMode == TwoMachinesPlay && IsWindowVisible(editTagsDialog)) {
\r
4417 tags = PGNTags(&gameInfo);
\r
4418 TagsPopUp(tags, CmailMsg());
\r
4421 SAY("programs start playing each other");
\r
4424 case IDM_AnalysisMode:
\r
4425 if (!first.analysisSupport) {
\r
4426 sprintf(buf, "%s does not support analysis", first.tidy);
\r
4427 DisplayError(buf, 0);
\r
4429 SAY("analyzing current position");
\r
4430 /* [DM] icsEngineAnlyze [HGM] Why is this front-end??? */
\r
4431 if (appData.icsActive) {
\r
4432 if (gameMode != IcsObserving) {
\r
4433 sprintf(buf, "You are not observing a game");
\r
4434 DisplayError(buf, 0);
\r
4435 /* secure check */
\r
4436 if (appData.icsEngineAnalyze) {
\r
4437 if (appData.debugMode)
\r
4438 fprintf(debugFP, "Found unexpected active ICS engine analyze \n");
\r
4439 ExitAnalyzeMode();
\r
4445 /* if enable, user want disable icsEngineAnalyze */
\r
4446 if (appData.icsEngineAnalyze) {
\r
4447 ExitAnalyzeMode();
\r
4451 appData.icsEngineAnalyze = TRUE;
\r
4452 if (appData.debugMode) fprintf(debugFP, "ICS engine analyze starting...\n");
\r
4455 if (!appData.showThinking) ToggleShowThinking();
\r
4456 AnalyzeModeEvent();
\r
4460 case IDM_AnalyzeFile:
\r
4461 if (!first.analysisSupport) {
\r
4462 char buf[MSG_SIZ];
\r
4463 sprintf(buf, "%s does not support analysis", first.tidy);
\r
4464 DisplayError(buf, 0);
\r
4466 if (!appData.showThinking) ToggleShowThinking();
\r
4467 AnalyzeFileEvent();
\r
4468 LoadGameDialog(hwnd, "Analyze Game from File");
\r
4469 AnalysisPeriodicEvent(1);
\r
4473 case IDM_IcsClient:
\r
4477 case IDM_EditGame:
\r
4482 case IDM_EditPosition:
\r
4483 EditPositionEvent();
\r
4484 SAY("to set up a position type a FEN");
\r
4487 case IDM_Training:
\r
4491 case IDM_ShowGameList:
\r
4492 ShowGameListProc();
\r
4495 case IDM_EditTags:
\r
4499 case IDM_EditComment:
\r
4500 if (commentUp && editComment) {
\r
4503 EditCommentEvent();
\r
4523 case IDM_CallFlag:
\r
4543 case IDM_StopObserving:
\r
4544 StopObservingEvent();
\r
4547 case IDM_StopExamining:
\r
4548 StopExaminingEvent();
\r
4551 case IDM_TypeInMove:
\r
4552 PopUpMoveDialog('\000');
\r
4555 case IDM_TypeInName:
\r
4556 PopUpNameDialog('\000');
\r
4559 case IDM_Backward:
\r
4561 SetFocus(hwndMain);
\r
4568 SetFocus(hwndMain);
\r
4573 SetFocus(hwndMain);
\r
4578 SetFocus(hwndMain);
\r
4585 case IDM_TruncateGame:
\r
4586 TruncateGameEvent();
\r
4593 case IDM_RetractMove:
\r
4594 RetractMoveEvent();
\r
4597 case IDM_FlipView:
\r
4598 flipView = !flipView;
\r
4599 DrawPosition(FALSE, NULL);
\r
4602 case IDM_FlipClock:
\r
4603 flipClock = !flipClock;
\r
4604 DisplayBothClocks();
\r
4605 DrawPosition(FALSE, NULL);
\r
4608 case IDM_MuteSounds:
\r
4609 mute = !mute; // [HGM] mute: keep track of global muting variable
\r
4610 CheckMenuItem(GetMenu(hwndMain),IDM_MuteSounds,
\r
4611 MF_BYCOMMAND|(mute?MF_CHECKED:MF_UNCHECKED));
\r
4614 case IDM_GeneralOptions:
\r
4615 GeneralOptionsPopup(hwnd);
\r
4616 DrawPosition(TRUE, NULL);
\r
4619 case IDM_BoardOptions:
\r
4620 BoardOptionsPopup(hwnd);
\r
4623 case IDM_EnginePlayOptions:
\r
4624 EnginePlayOptionsPopup(hwnd);
\r
4627 case IDM_Engine1Options:
\r
4628 EngineOptionsPopup(hwnd, &first);
\r
4631 case IDM_Engine2Options:
\r
4632 EngineOptionsPopup(hwnd, &second);
\r
4635 case IDM_OptionsUCI:
\r
4636 UciOptionsPopup(hwnd);
\r
4639 case IDM_IcsOptions:
\r
4640 IcsOptionsPopup(hwnd);
\r
4644 FontsOptionsPopup(hwnd);
\r
4648 SoundOptionsPopup(hwnd);
\r
4651 case IDM_CommPort:
\r
4652 CommPortOptionsPopup(hwnd);
\r
4655 case IDM_LoadOptions:
\r
4656 LoadOptionsPopup(hwnd);
\r
4659 case IDM_SaveOptions:
\r
4660 SaveOptionsPopup(hwnd);
\r
4663 case IDM_TimeControl:
\r
4664 TimeControlOptionsPopup(hwnd);
\r
4667 case IDM_SaveSettings:
\r
4668 SaveSettings(settingsFileName);
\r
4671 case IDM_SaveSettingsOnExit:
\r
4672 saveSettingsOnExit = !saveSettingsOnExit;
\r
4673 (void) CheckMenuItem(GetMenu(hwndMain), IDM_SaveSettingsOnExit,
\r
4674 MF_BYCOMMAND|(saveSettingsOnExit ?
\r
4675 MF_CHECKED : MF_UNCHECKED));
\r
4686 case IDM_AboutGame:
\r
4691 appData.debugMode = !appData.debugMode;
\r
4692 if (appData.debugMode) {
\r
4693 char dir[MSG_SIZ];
\r
4694 GetCurrentDirectory(MSG_SIZ, dir);
\r
4695 SetCurrentDirectory(installDir);
\r
4696 debugFP = fopen(appData.nameOfDebugFile, "w");
\r
4697 SetCurrentDirectory(dir);
\r
4698 setbuf(debugFP, NULL);
\r
4705 case IDM_HELPCONTENTS:
\r
4706 if (!MyHelp (hwnd, "winboard.hlp", HELP_KEY,(DWORD)(LPSTR)"CONTENTS") &&
\r
4707 !HtmlHelp(hwnd, "winboard.chm", 0, 0) ) {
\r
4708 MessageBox (GetFocus(),
\r
4709 "Unable to activate help",
\r
4710 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
4714 case IDM_HELPSEARCH:
\r
4715 if (!MyHelp (hwnd, "winboard.hlp", HELP_PARTIALKEY, (DWORD)(LPSTR)"") &&
\r
4716 !HtmlHelp(hwnd, "winboard.chm", 0, 0) ) {
\r
4717 MessageBox (GetFocus(),
\r
4718 "Unable to activate help",
\r
4719 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
4723 case IDM_HELPHELP:
\r
4724 if(!WinHelp(hwnd, (LPSTR)NULL, HELP_HELPONHELP, 0)) {
\r
4725 MessageBox (GetFocus(),
\r
4726 "Unable to activate help",
\r
4727 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
4732 lpProc = MakeProcInstance((FARPROC)About, hInst);
\r
4734 (gameInfo.event && strcmp(gameInfo.event, "Easter Egg Hunt") == 0) ?
\r
4735 "AboutBox2" : "AboutBox", hwnd, (DLGPROC)lpProc);
\r
4736 FreeProcInstance(lpProc);
\r
4739 case IDM_DirectCommand1:
\r
4740 AskQuestionEvent("Direct Command",
\r
4741 "Send to chess program:", "", "1");
\r
4743 case IDM_DirectCommand2:
\r
4744 AskQuestionEvent("Direct Command",
\r
4745 "Send to second chess program:", "", "2");
\r
4748 case EP_WhitePawn:
\r
4749 EditPositionMenuEvent(WhitePawn, fromX, fromY);
\r
4750 fromX = fromY = -1;
\r
4753 case EP_WhiteKnight:
\r
4754 EditPositionMenuEvent(WhiteKnight, fromX, fromY);
\r
4755 fromX = fromY = -1;
\r
4758 case EP_WhiteBishop:
\r
4759 EditPositionMenuEvent(WhiteBishop, fromX, fromY);
\r
4760 fromX = fromY = -1;
\r
4763 case EP_WhiteRook:
\r
4764 EditPositionMenuEvent(WhiteRook, fromX, fromY);
\r
4765 fromX = fromY = -1;
\r
4768 case EP_WhiteQueen:
\r
4769 EditPositionMenuEvent(WhiteQueen, fromX, fromY);
\r
4770 fromX = fromY = -1;
\r
4773 case EP_WhiteFerz:
\r
4774 EditPositionMenuEvent(WhiteFerz, fromX, fromY);
\r
4775 fromX = fromY = -1;
\r
4778 case EP_WhiteWazir:
\r
4779 EditPositionMenuEvent(WhiteWazir, fromX, fromY);
\r
4780 fromX = fromY = -1;
\r
4783 case EP_WhiteAlfil:
\r
4784 EditPositionMenuEvent(WhiteAlfil, fromX, fromY);
\r
4785 fromX = fromY = -1;
\r
4788 case EP_WhiteCannon:
\r
4789 EditPositionMenuEvent(WhiteCannon, fromX, fromY);
\r
4790 fromX = fromY = -1;
\r
4793 case EP_WhiteCardinal:
\r
4794 EditPositionMenuEvent(WhiteAngel, fromX, fromY);
\r
4795 fromX = fromY = -1;
\r
4798 case EP_WhiteMarshall:
\r
4799 EditPositionMenuEvent(WhiteMarshall, fromX, fromY);
\r
4800 fromX = fromY = -1;
\r
4803 case EP_WhiteKing:
\r
4804 EditPositionMenuEvent(WhiteKing, fromX, fromY);
\r
4805 fromX = fromY = -1;
\r
4808 case EP_BlackPawn:
\r
4809 EditPositionMenuEvent(BlackPawn, fromX, fromY);
\r
4810 fromX = fromY = -1;
\r
4813 case EP_BlackKnight:
\r
4814 EditPositionMenuEvent(BlackKnight, fromX, fromY);
\r
4815 fromX = fromY = -1;
\r
4818 case EP_BlackBishop:
\r
4819 EditPositionMenuEvent(BlackBishop, fromX, fromY);
\r
4820 fromX = fromY = -1;
\r
4823 case EP_BlackRook:
\r
4824 EditPositionMenuEvent(BlackRook, fromX, fromY);
\r
4825 fromX = fromY = -1;
\r
4828 case EP_BlackQueen:
\r
4829 EditPositionMenuEvent(BlackQueen, fromX, fromY);
\r
4830 fromX = fromY = -1;
\r
4833 case EP_BlackFerz:
\r
4834 EditPositionMenuEvent(BlackFerz, fromX, fromY);
\r
4835 fromX = fromY = -1;
\r
4838 case EP_BlackWazir:
\r
4839 EditPositionMenuEvent(BlackWazir, fromX, fromY);
\r
4840 fromX = fromY = -1;
\r
4843 case EP_BlackAlfil:
\r
4844 EditPositionMenuEvent(BlackAlfil, fromX, fromY);
\r
4845 fromX = fromY = -1;
\r
4848 case EP_BlackCannon:
\r
4849 EditPositionMenuEvent(BlackCannon, fromX, fromY);
\r
4850 fromX = fromY = -1;
\r
4853 case EP_BlackCardinal:
\r
4854 EditPositionMenuEvent(BlackAngel, fromX, fromY);
\r
4855 fromX = fromY = -1;
\r
4858 case EP_BlackMarshall:
\r
4859 EditPositionMenuEvent(BlackMarshall, fromX, fromY);
\r
4860 fromX = fromY = -1;
\r
4863 case EP_BlackKing:
\r
4864 EditPositionMenuEvent(BlackKing, fromX, fromY);
\r
4865 fromX = fromY = -1;
\r
4868 case EP_EmptySquare:
\r
4869 EditPositionMenuEvent(EmptySquare, fromX, fromY);
\r
4870 fromX = fromY = -1;
\r
4873 case EP_ClearBoard:
\r
4874 EditPositionMenuEvent(ClearBoard, fromX, fromY);
\r
4875 fromX = fromY = -1;
\r
4879 EditPositionMenuEvent(WhitePlay, fromX, fromY);
\r
4880 fromX = fromY = -1;
\r
4884 EditPositionMenuEvent(BlackPlay, fromX, fromY);
\r
4885 fromX = fromY = -1;
\r
4889 EditPositionMenuEvent(PromotePiece, fromX, fromY);
\r
4890 fromX = fromY = -1;
\r
4894 EditPositionMenuEvent(DemotePiece, fromX, fromY);
\r
4895 fromX = fromY = -1;
\r
4899 DropMenuEvent(WhitePawn, fromX, fromY);
\r
4900 fromX = fromY = -1;
\r
4904 DropMenuEvent(WhiteKnight, fromX, fromY);
\r
4905 fromX = fromY = -1;
\r
4909 DropMenuEvent(WhiteBishop, fromX, fromY);
\r
4910 fromX = fromY = -1;
\r
4914 DropMenuEvent(WhiteRook, fromX, fromY);
\r
4915 fromX = fromY = -1;
\r
4919 DropMenuEvent(WhiteQueen, fromX, fromY);
\r
4920 fromX = fromY = -1;
\r
4924 return (DefWindowProc(hwnd, message, wParam, lParam));
\r
4930 case CLOCK_TIMER_ID:
\r
4931 KillTimer(hwnd, clockTimerEvent); /* Simulate one-shot timer as in X */
\r
4932 clockTimerEvent = 0;
\r
4933 DecrementClocks(); /* call into back end */
\r
4935 case LOAD_GAME_TIMER_ID:
\r
4936 KillTimer(hwnd, loadGameTimerEvent); /* Simulate one-shot timer as in X*/
\r
4937 loadGameTimerEvent = 0;
\r
4938 AutoPlayGameLoop(); /* call into back end */
\r
4940 case ANALYSIS_TIMER_ID:
\r
4941 if ((gameMode == AnalyzeMode || gameMode == AnalyzeFile
\r
4942 || appData.icsEngineAnalyze) && appData.periodicUpdates) {
\r
4943 AnalysisPeriodicEvent(0);
\r
4945 KillTimer(hwnd, analysisTimerEvent);
\r
4946 analysisTimerEvent = 0;
\r
4949 case DELAYED_TIMER_ID:
\r
4950 KillTimer(hwnd, delayedTimerEvent);
\r
4951 delayedTimerEvent = 0;
\r
4952 delayedTimerCallback();
\r
4957 case WM_USER_Input:
\r
4958 InputEvent(hwnd, message, wParam, lParam);
\r
4961 /* [AS] Also move "attached" child windows */
\r
4962 case WM_WINDOWPOSCHANGING:
\r
4964 if( hwnd == hwndMain && appData.useStickyWindows ) {
\r
4965 LPWINDOWPOS lpwp = (LPWINDOWPOS) lParam;
\r
4967 if( ((lpwp->flags & SWP_NOMOVE) == 0) && ((lpwp->flags & SWP_NOSIZE) != 0) ) {
\r
4968 /* Window is moving */
\r
4971 // GetWindowRect( hwnd, &rcMain ); //[HGM] sticky: in XP this returned new position, not old
\r
4972 rcMain.left = wpMain.x; // replace by these 4 lines to reconstruct old rect
\r
4973 rcMain.right = wpMain.x + wpMain.width;
\r
4974 rcMain.top = wpMain.y;
\r
4975 rcMain.bottom = wpMain.y + wpMain.height;
\r
4977 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, moveHistoryDialog, &wpMoveHistory );
\r
4978 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, evalGraphDialog, &wpEvalGraph );
\r
4979 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, engineOutputDialog, &wpEngineOutput );
\r
4980 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, gameListDialog, &wpGameList );
\r
4981 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, hwndConsole, &wpConsole );
\r
4982 wpMain.x = lpwp->x;
\r
4983 wpMain.y = lpwp->y;
\r
4988 /* [AS] Snapping */
\r
4989 case WM_ENTERSIZEMOVE:
\r
4990 if(appData.debugMode) { fprintf(debugFP, "size-move\n"); }
\r
4991 if (hwnd == hwndMain) {
\r
4992 doingSizing = TRUE;
\r
4995 return OnEnterSizeMove( &sd, hwnd, wParam, lParam );
\r
4999 if(appData.debugMode) { fprintf(debugFP, "sizing\n"); }
\r
5000 if (hwnd == hwndMain) {
\r
5001 lastSizing = wParam;
\r
5006 if(appData.debugMode) { fprintf(debugFP, "moving\n"); }
\r
5007 return OnMoving( &sd, hwnd, wParam, lParam );
\r
5009 case WM_EXITSIZEMOVE:
\r
5010 if(appData.debugMode) { fprintf(debugFP, "exit size-move, size = %d\n", squareSize); }
\r
5011 if (hwnd == hwndMain) {
\r
5013 doingSizing = FALSE;
\r
5014 InvalidateRect(hwnd, &boardRect, FALSE);
\r
5015 GetClientRect(hwnd, &client);
\r
5016 ResizeBoard(client.right, client.bottom, lastSizing);
\r
5018 if(appData.debugMode) { fprintf(debugFP, "square size = %d\n", squareSize); }
\r
5020 return OnExitSizeMove( &sd, hwnd, wParam, lParam );
\r
5023 case WM_DESTROY: /* message: window being destroyed */
\r
5024 PostQuitMessage(0);
\r
5028 if (hwnd == hwndMain) {
\r
5033 default: /* Passes it on if unprocessed */
\r
5034 return (DefWindowProc(hwnd, message, wParam, lParam));
\r
5039 /*---------------------------------------------------------------------------*\
\r
5041 * Misc utility routines
\r
5043 \*---------------------------------------------------------------------------*/
\r
5046 * Decent random number generator, at least not as bad as Windows
\r
5047 * standard rand, which returns a value in the range 0 to 0x7fff.
\r
5049 unsigned int randstate;
\r
5054 randstate = randstate * 1664525 + 1013904223;
\r
5055 return (int) randstate & 0x7fffffff;
\r
5059 mysrandom(unsigned int seed)
\r
5066 * returns TRUE if user selects a different color, FALSE otherwise
\r
5070 ChangeColor(HWND hwnd, COLORREF *which)
\r
5072 static BOOL firstTime = TRUE;
\r
5073 static DWORD customColors[16];
\r
5075 COLORREF newcolor;
\r
5080 /* Make initial colors in use available as custom colors */
\r
5081 /* Should we put the compiled-in defaults here instead? */
\r
5083 customColors[i++] = lightSquareColor & 0xffffff;
\r
5084 customColors[i++] = darkSquareColor & 0xffffff;
\r
5085 customColors[i++] = whitePieceColor & 0xffffff;
\r
5086 customColors[i++] = blackPieceColor & 0xffffff;
\r
5087 customColors[i++] = highlightSquareColor & 0xffffff;
\r
5088 customColors[i++] = premoveHighlightColor & 0xffffff;
\r
5090 for (ccl = (ColorClass) 0; ccl < NColorClasses && i < 16; ccl++) {
\r
5091 customColors[i++] = textAttribs[ccl].color;
\r
5093 while (i < 16) customColors[i++] = RGB(255, 255, 255);
\r
5094 firstTime = FALSE;
\r
5097 cc.lStructSize = sizeof(cc);
\r
5098 cc.hwndOwner = hwnd;
\r
5099 cc.hInstance = NULL;
\r
5100 cc.rgbResult = (DWORD) (*which & 0xffffff);
\r
5101 cc.lpCustColors = (LPDWORD) customColors;
\r
5102 cc.Flags = CC_RGBINIT|CC_FULLOPEN;
\r
5104 if (!ChooseColor(&cc)) return FALSE;
\r
5106 newcolor = (COLORREF) (0x2000000 | cc.rgbResult);
\r
5107 if (newcolor == *which) return FALSE;
\r
5108 *which = newcolor;
\r
5112 InitDrawingColors();
\r
5113 InvalidateRect(hwnd, &boardRect, FALSE);
\r
5118 MyLoadSound(MySound *ms)
\r
5124 if (ms->data) free(ms->data);
\r
5127 switch (ms->name[0]) {
\r
5133 /* System sound from Control Panel. Don't preload here. */
\r
5137 if (ms->name[1] == NULLCHAR) {
\r
5138 /* "!" alone = silence */
\r
5141 /* Builtin wave resource. Error if not found. */
\r
5142 HANDLE h = FindResource(hInst, ms->name + 1, "WAVE");
\r
5143 if (h == NULL) break;
\r
5144 ms->data = (void *)LoadResource(hInst, h);
\r
5145 if (h == NULL) break;
\r
5150 /* .wav file. Error if not found. */
\r
5151 f = fopen(ms->name, "rb");
\r
5152 if (f == NULL) break;
\r
5153 if (fstat(fileno(f), &st) < 0) break;
\r
5154 ms->data = malloc(st.st_size);
\r
5155 if (fread(ms->data, st.st_size, 1, f) < 1) break;
\r
5161 char buf[MSG_SIZ];
\r
5162 sprintf(buf, "Error loading sound %s", ms->name);
\r
5163 DisplayError(buf, GetLastError());
\r
5169 MyPlaySound(MySound *ms)
\r
5171 BOOLEAN ok = FALSE;
\r
5173 if(mute) return TRUE; // [HGM] mute: suppress all sound play when muted
\r
5174 switch (ms->name[0]) {
\r
5176 if(appData.debugMode) fprintf(debugFP, "silence\n");
\r
5181 /* System sound from Control Panel (deprecated feature).
\r
5182 "$" alone or an unset sound name gets default beep (still in use). */
\r
5183 if (ms->name[1]) {
\r
5184 ok = PlaySound(ms->name + 1, NULL, SND_ALIAS|SND_ASYNC);
\r
5186 if (!ok) ok = MessageBeep(MB_OK);
\r
5189 /* Builtin wave resource, or "!" alone for silence */
\r
5190 if (ms->name[1]) {
\r
5191 if (ms->data == NULL) return FALSE;
\r
5192 ok = PlaySound(ms->data, NULL, SND_MEMORY|SND_ASYNC);
\r
5198 /* .wav file. Error if not found. */
\r
5199 if (ms->data == NULL) return FALSE;
\r
5200 ok = PlaySound(ms->data, NULL, SND_MEMORY|SND_ASYNC);
\r
5203 /* Don't print an error: this can happen innocently if the sound driver
\r
5204 is busy; for instance, if another instance of WinBoard is playing
\r
5205 a sound at about the same time. */
\r
5211 OldOpenFileHook(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
5214 OPENFILENAME *ofn;
\r
5215 static UINT *number; /* gross that this is static */
\r
5217 switch (message) {
\r
5218 case WM_INITDIALOG: /* message: initialize dialog box */
\r
5219 /* Center the dialog over the application window */
\r
5220 ofn = (OPENFILENAME *) lParam;
\r
5221 if (ofn->Flags & OFN_ENABLETEMPLATE) {
\r
5222 number = (UINT *) ofn->lCustData;
\r
5223 SendMessage(GetDlgItem(hDlg, edt2), WM_SETTEXT, 0, (LPARAM) "");
\r
5227 CenterWindow (hDlg, GetWindow (hDlg, GW_OWNER));
\r
5228 return FALSE; /* Allow for further processing */
\r
5231 if ((LOWORD(wParam) == IDOK) && (number != NULL)) {
\r
5232 *number = GetDlgItemInt(hDlg, OPT_IndexNumberOld, &ok, FALSE);
\r
5234 return FALSE; /* Allow for further processing */
\r
5240 OpenFileHook(HWND hdlg, UINT uiMsg, WPARAM wParam, LPARAM lParam)
\r
5242 static UINT *number;
\r
5243 OPENFILENAME *ofname;
\r
5246 case WM_INITDIALOG:
\r
5247 ofname = (OPENFILENAME *)lParam;
\r
5248 number = (UINT *)(ofname->lCustData);
\r
5251 ofnot = (OFNOTIFY *)lParam;
\r
5252 if (ofnot->hdr.code == CDN_FILEOK) {
\r
5253 *number = GetDlgItemInt(hdlg, OPT_IndexNumber, NULL, FALSE);
\r
5262 OpenFileDialog(HWND hwnd, char *write, char *defName, char *defExt, // [HGM] diag: type of 'write' now string
\r
5263 char *nameFilt, char *dlgTitle, UINT *number,
\r
5264 char fileTitle[MSG_SIZ], char fileName[MSG_SIZ])
\r
5266 OPENFILENAME openFileName;
\r
5267 char buf1[MSG_SIZ];
\r
5270 if (fileName == NULL) fileName = buf1;
\r
5271 if (defName == NULL) {
\r
5272 strcpy(fileName, "*.");
\r
5273 strcat(fileName, defExt);
\r
5275 strcpy(fileName, defName);
\r
5277 if (fileTitle) strcpy(fileTitle, "");
\r
5278 if (number) *number = 0;
\r
5280 openFileName.lStructSize = sizeof(OPENFILENAME);
\r
5281 openFileName.hwndOwner = hwnd;
\r
5282 openFileName.hInstance = (HANDLE) hInst;
\r
5283 openFileName.lpstrFilter = nameFilt;
\r
5284 openFileName.lpstrCustomFilter = (LPSTR) NULL;
\r
5285 openFileName.nMaxCustFilter = 0L;
\r
5286 openFileName.nFilterIndex = 1L;
\r
5287 openFileName.lpstrFile = fileName;
\r
5288 openFileName.nMaxFile = MSG_SIZ;
\r
5289 openFileName.lpstrFileTitle = fileTitle;
\r
5290 openFileName.nMaxFileTitle = fileTitle ? MSG_SIZ : 0;
\r
5291 openFileName.lpstrInitialDir = NULL;
\r
5292 openFileName.lpstrTitle = dlgTitle;
\r
5293 openFileName.Flags = OFN_PATHMUSTEXIST | OFN_HIDEREADONLY
\r
5294 | (write[0] != 'r' ? 0 : OFN_FILEMUSTEXIST)
\r
5295 | (number ? OFN_ENABLETEMPLATE | OFN_ENABLEHOOK: 0)
\r
5296 | (oldDialog ? 0 : OFN_EXPLORER);
\r
5297 openFileName.nFileOffset = 0;
\r
5298 openFileName.nFileExtension = 0;
\r
5299 openFileName.lpstrDefExt = defExt;
\r
5300 openFileName.lCustData = (LONG) number;
\r
5301 openFileName.lpfnHook = oldDialog ?
\r
5302 (LPOFNHOOKPROC) OldOpenFileHook : (LPOFNHOOKPROC) OpenFileHook;
\r
5303 openFileName.lpTemplateName = (LPSTR)(oldDialog ? 1536 : DLG_IndexNumber);
\r
5305 if (write[0] != 'r' ? GetSaveFileName(&openFileName) :
\r
5306 GetOpenFileName(&openFileName)) {
\r
5307 /* open the file */
\r
5308 f = fopen(openFileName.lpstrFile, write);
\r
5310 MessageBox(hwnd, "File open failed", NULL,
\r
5311 MB_OK|MB_ICONEXCLAMATION);
\r
5315 int err = CommDlgExtendedError();
\r
5316 if (err != 0) DisplayError("Internal error in file dialog box", err);
\r
5325 MenuPopup(HWND hwnd, POINT pt, HMENU hmenu, UINT def)
\r
5327 HMENU hmenuTrackPopup; /* floating pop-up menu */
\r
5330 * Get the first pop-up menu in the menu template. This is the
\r
5331 * menu that TrackPopupMenu displays.
\r
5333 hmenuTrackPopup = GetSubMenu(hmenu, 0);
\r
5335 SetMenuDefaultItem(hmenuTrackPopup, def, FALSE);
\r
5338 * TrackPopup uses screen coordinates, so convert the
\r
5339 * coordinates of the mouse click to screen coordinates.
\r
5341 ClientToScreen(hwnd, (LPPOINT) &pt);
\r
5343 /* Draw and track the floating pop-up menu. */
\r
5344 TrackPopupMenu(hmenuTrackPopup, TPM_CENTERALIGN | TPM_RIGHTBUTTON,
\r
5345 pt.x, pt.y, 0, hwnd, NULL);
\r
5347 /* Destroy the menu.*/
\r
5348 DestroyMenu(hmenu);
\r
5353 int sizeX, sizeY, newSizeX, newSizeY;
\r
5355 } ResizeEditPlusButtonsClosure;
\r
5358 ResizeEditPlusButtonsCallback(HWND hChild, LPARAM lparam)
\r
5360 ResizeEditPlusButtonsClosure *cl = (ResizeEditPlusButtonsClosure *)lparam;
\r
5364 if (hChild == cl->hText) return TRUE;
\r
5365 GetWindowRect(hChild, &rect); /* gives screen coords */
\r
5366 pt.x = rect.left + (cl->newSizeX - cl->sizeX)/2;
\r
5367 pt.y = rect.top + cl->newSizeY - cl->sizeY;
\r
5368 ScreenToClient(cl->hDlg, &pt);
\r
5369 cl->hdwp = DeferWindowPos(cl->hdwp, hChild, NULL,
\r
5370 pt.x, pt.y, rect.right - rect.left, rect.bottom - rect.top, SWP_NOZORDER);
\r
5374 /* Resize a dialog that has a (rich) edit field filling most of
\r
5375 the top, with a row of buttons below */
\r
5377 ResizeEditPlusButtons(HWND hDlg, HWND hText, int sizeX, int sizeY, int newSizeX, int newSizeY)
\r
5380 int newTextHeight, newTextWidth;
\r
5381 ResizeEditPlusButtonsClosure cl;
\r
5383 /*if (IsIconic(hDlg)) return;*/
\r
5384 if (newSizeX == sizeX && newSizeY == sizeY) return;
\r
5386 cl.hdwp = BeginDeferWindowPos(8);
\r
5388 GetWindowRect(hText, &rectText); /* gives screen coords */
\r
5389 newTextWidth = rectText.right - rectText.left + newSizeX - sizeX;
\r
5390 newTextHeight = rectText.bottom - rectText.top + newSizeY - sizeY;
\r
5391 if (newTextHeight < 0) {
\r
5392 newSizeY += -newTextHeight;
\r
5393 newTextHeight = 0;
\r
5395 cl.hdwp = DeferWindowPos(cl.hdwp, hText, NULL, 0, 0,
\r
5396 newTextWidth, newTextHeight, SWP_NOZORDER|SWP_NOMOVE);
\r
5402 cl.newSizeX = newSizeX;
\r
5403 cl.newSizeY = newSizeY;
\r
5404 EnumChildWindows(hDlg, ResizeEditPlusButtonsCallback, (LPARAM)&cl);
\r
5406 EndDeferWindowPos(cl.hdwp);
\r
5409 BOOL CenterWindowEx(HWND hwndChild, HWND hwndParent, int mode)
\r
5411 RECT rChild, rParent;
\r
5412 int wChild, hChild, wParent, hParent;
\r
5413 int wScreen, hScreen, xNew, yNew;
\r
5416 /* Get the Height and Width of the child window */
\r
5417 GetWindowRect (hwndChild, &rChild);
\r
5418 wChild = rChild.right - rChild.left;
\r
5419 hChild = rChild.bottom - rChild.top;
\r
5421 /* Get the Height and Width of the parent window */
\r
5422 GetWindowRect (hwndParent, &rParent);
\r
5423 wParent = rParent.right - rParent.left;
\r
5424 hParent = rParent.bottom - rParent.top;
\r
5426 /* Get the display limits */
\r
5427 hdc = GetDC (hwndChild);
\r
5428 wScreen = GetDeviceCaps (hdc, HORZRES);
\r
5429 hScreen = GetDeviceCaps (hdc, VERTRES);
\r
5430 ReleaseDC(hwndChild, hdc);
\r
5432 /* Calculate new X position, then adjust for screen */
\r
5433 xNew = rParent.left + ((wParent - wChild) /2);
\r
5436 } else if ((xNew+wChild) > wScreen) {
\r
5437 xNew = wScreen - wChild;
\r
5440 /* Calculate new Y position, then adjust for screen */
\r
5442 yNew = rParent.top + ((hParent - hChild) /2);
\r
5445 yNew = rParent.top + GetSystemMetrics( SM_CYCAPTION ) * 2 / 3;
\r
5450 } else if ((yNew+hChild) > hScreen) {
\r
5451 yNew = hScreen - hChild;
\r
5454 /* Set it, and return */
\r
5455 return SetWindowPos (hwndChild, NULL,
\r
5456 xNew, yNew, 0, 0, SWP_NOSIZE | SWP_NOZORDER);
\r
5459 /* Center one window over another */
\r
5460 BOOL CenterWindow (HWND hwndChild, HWND hwndParent)
\r
5462 return CenterWindowEx( hwndChild, hwndParent, 0 );
\r
5465 /*---------------------------------------------------------------------------*\
\r
5467 * Startup Dialog functions
\r
5469 \*---------------------------------------------------------------------------*/
\r
5471 InitComboStrings(HANDLE hwndCombo, char **cd)
\r
5473 SendMessage(hwndCombo, CB_RESETCONTENT, 0, 0);
\r
5475 while (*cd != NULL) {
\r
5476 SendMessage(hwndCombo, CB_ADDSTRING, 0, (LPARAM) *cd);
\r
5482 InitComboStringsFromOption(HANDLE hwndCombo, char *str)
\r
5484 char buf1[MAX_ARG_LEN];
\r
5487 if (str[0] == '@') {
\r
5488 FILE* f = fopen(str + 1, "r");
\r
5490 DisplayFatalError(str + 1, errno, 2);
\r
5493 len = fread(buf1, 1, sizeof(buf1)-1, f);
\r
5495 buf1[len] = NULLCHAR;
\r
5499 SendMessage(hwndCombo, CB_RESETCONTENT, 0, 0);
\r
5502 char buf[MSG_SIZ];
\r
5503 char *end = strchr(str, '\n');
\r
5504 if (end == NULL) return;
\r
5505 memcpy(buf, str, end - str);
\r
5506 buf[end - str] = NULLCHAR;
\r
5507 SendMessage(hwndCombo, CB_ADDSTRING, 0, (LPARAM) buf);
\r
5513 SetStartupDialogEnables(HWND hDlg)
\r
5515 EnableWindow(GetDlgItem(hDlg, OPT_ChessEngineName),
\r
5516 IsDlgButtonChecked(hDlg, OPT_ChessEngine) ||
\r
5517 (appData.zippyPlay && IsDlgButtonChecked(hDlg, OPT_ChessServer)));
\r
5518 EnableWindow(GetDlgItem(hDlg, OPT_SecondChessEngineName),
\r
5519 IsDlgButtonChecked(hDlg, OPT_ChessEngine));
\r
5520 EnableWindow(GetDlgItem(hDlg, OPT_ChessServerName),
\r
5521 IsDlgButtonChecked(hDlg, OPT_ChessServer));
\r
5522 EnableWindow(GetDlgItem(hDlg, OPT_AdditionalOptions),
\r
5523 IsDlgButtonChecked(hDlg, OPT_AnyAdditional));
\r
5524 EnableWindow(GetDlgItem(hDlg, IDOK),
\r
5525 IsDlgButtonChecked(hDlg, OPT_ChessEngine) ||
\r
5526 IsDlgButtonChecked(hDlg, OPT_ChessServer) ||
\r
5527 IsDlgButtonChecked(hDlg, OPT_View));
\r
5531 QuoteForFilename(char *filename)
\r
5533 int dquote, space;
\r
5534 dquote = strchr(filename, '"') != NULL;
\r
5535 space = strchr(filename, ' ') != NULL;
\r
5536 if (dquote || space) {
\r
5548 InitEngineBox(HWND hDlg, HWND hwndCombo, char* nthcp, char* nthd, char* nthdir, char *nthnames)
\r
5550 char buf[MSG_SIZ];
\r
5553 InitComboStringsFromOption(hwndCombo, nthnames);
\r
5554 q = QuoteForFilename(nthcp);
\r
5555 sprintf(buf, "%s%s%s", q, nthcp, q);
\r
5556 if (*nthdir != NULLCHAR) {
\r
5557 q = QuoteForFilename(nthdir);
\r
5558 sprintf(buf + strlen(buf), " /%s=%s%s%s", nthd, q, nthdir, q);
\r
5560 if (*nthcp == NULLCHAR) {
\r
5561 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) 0, (LPARAM) 0);
\r
5562 } else if (SendMessage(hwndCombo, CB_SELECTSTRING, (WPARAM) -1, (LPARAM) buf) == CB_ERR) {
\r
5563 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) -1, (LPARAM) 0);
\r
5564 SendMessage(hwndCombo, WM_SETTEXT, (WPARAM) 0, (LPARAM) buf);
\r
5569 StartupDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
5571 char buf[MSG_SIZ];
\r
5575 switch (message) {
\r
5576 case WM_INITDIALOG:
\r
5577 /* Center the dialog */
\r
5578 CenterWindow (hDlg, GetDesktopWindow());
\r
5579 /* Initialize the dialog items */
\r
5580 InitEngineBox(hDlg, GetDlgItem(hDlg, OPT_ChessEngineName),
\r
5581 appData.firstChessProgram, "fd", appData.firstDirectory,
\r
5582 firstChessProgramNames);
\r
5583 InitEngineBox(hDlg, GetDlgItem(hDlg, OPT_SecondChessEngineName),
\r
5584 appData.secondChessProgram, "sd", appData.secondDirectory,
\r
5585 secondChessProgramNames);
\r
5586 hwndCombo = GetDlgItem(hDlg, OPT_ChessServerName);
\r
5587 InitComboStringsFromOption(hwndCombo, icsNames);
\r
5588 sprintf(buf, "%s /icsport=%s", appData.icsHost, appData.icsPort);
\r
5589 if (*appData.icsHelper != NULLCHAR) {
\r
5590 char *q = QuoteForFilename(appData.icsHelper);
\r
5591 sprintf(buf + strlen(buf), " /icshelper=%s%s%s", q, appData.icsHelper, q);
\r
5593 if (*appData.icsHost == NULLCHAR) {
\r
5594 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) 0, (LPARAM) 0);
\r
5595 /*SendMessage(hwndCombo, CB_SHOWDROPDOWN, (WPARAM) TRUE, (LPARAM) 0); !!too soon */
\r
5596 } else if (SendMessage(hwndCombo, CB_SELECTSTRING, (WPARAM) -1, (LPARAM) buf) == CB_ERR) {
\r
5597 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) -1, (LPARAM) 0);
\r
5598 SendMessage(hwndCombo, WM_SETTEXT, (WPARAM) 0, (LPARAM) buf);
\r
5601 if (appData.icsActive) {
\r
5602 CheckDlgButton(hDlg, OPT_ChessServer, BST_CHECKED);
\r
5604 else if (appData.noChessProgram) {
\r
5605 CheckDlgButton(hDlg, OPT_View, BST_CHECKED);
\r
5608 CheckDlgButton(hDlg, OPT_ChessEngine, BST_CHECKED);
\r
5611 SetStartupDialogEnables(hDlg);
\r
5615 switch (LOWORD(wParam)) {
\r
5617 if (IsDlgButtonChecked(hDlg, OPT_ChessEngine)) {
\r
5618 strcpy(buf, "/fcp=");
\r
5619 GetDlgItemText(hDlg, OPT_ChessEngineName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
5621 ParseArgs(StringGet, &p);
\r
5622 strcpy(buf, "/scp=");
\r
5623 GetDlgItemText(hDlg, OPT_SecondChessEngineName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
5625 ParseArgs(StringGet, &p);
\r
5626 appData.noChessProgram = FALSE;
\r
5627 appData.icsActive = FALSE;
\r
5628 } else if (IsDlgButtonChecked(hDlg, OPT_ChessServer)) {
\r
5629 strcpy(buf, "/ics /icshost=");
\r
5630 GetDlgItemText(hDlg, OPT_ChessServerName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
5632 ParseArgs(StringGet, &p);
\r
5633 if (appData.zippyPlay) {
\r
5634 strcpy(buf, "/fcp=");
\r
5635 GetDlgItemText(hDlg, OPT_ChessEngineName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
5637 ParseArgs(StringGet, &p);
\r
5639 } else if (IsDlgButtonChecked(hDlg, OPT_View)) {
\r
5640 appData.noChessProgram = TRUE;
\r
5641 appData.icsActive = FALSE;
\r
5643 MessageBox(hDlg, "Choose an option, or cancel to exit",
\r
5644 "Option Error", MB_OK|MB_ICONEXCLAMATION);
\r
5647 if (IsDlgButtonChecked(hDlg, OPT_AnyAdditional)) {
\r
5648 GetDlgItemText(hDlg, OPT_AdditionalOptions, buf, sizeof(buf));
\r
5650 ParseArgs(StringGet, &p);
\r
5652 EndDialog(hDlg, TRUE);
\r
5659 case IDM_HELPCONTENTS:
\r
5660 if (!WinHelp (hDlg, "winboard.hlp", HELP_KEY,(DWORD)(LPSTR)"CONTENTS")) {
\r
5661 MessageBox (GetFocus(),
\r
5662 "Unable to activate help",
\r
5663 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
5668 SetStartupDialogEnables(hDlg);
\r
5676 /*---------------------------------------------------------------------------*\
\r
5678 * About box dialog functions
\r
5680 \*---------------------------------------------------------------------------*/
\r
5682 /* Process messages for "About" dialog box */
\r
5684 About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
5686 switch (message) {
\r
5687 case WM_INITDIALOG: /* message: initialize dialog box */
\r
5688 /* Center the dialog over the application window */
\r
5689 CenterWindow (hDlg, GetWindow (hDlg, GW_OWNER));
\r
5690 SetDlgItemText(hDlg, ABOUTBOX_Version, programVersion);
\r
5694 case WM_COMMAND: /* message: received a command */
\r
5695 if (LOWORD(wParam) == IDOK /* "OK" box selected? */
\r
5696 || LOWORD(wParam) == IDCANCEL) { /* System menu close command? */
\r
5697 EndDialog(hDlg, TRUE); /* Exit the dialog */
\r
5705 /*---------------------------------------------------------------------------*\
\r
5707 * Comment Dialog functions
\r
5709 \*---------------------------------------------------------------------------*/
\r
5712 CommentDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
5714 static HANDLE hwndText = NULL;
\r
5715 int len, newSizeX, newSizeY, flags;
\r
5716 static int sizeX, sizeY;
\r
5721 switch (message) {
\r
5722 case WM_INITDIALOG: /* message: initialize dialog box */
\r
5723 /* Initialize the dialog items */
\r
5724 hwndText = GetDlgItem(hDlg, OPT_CommentText);
\r
5725 SetDlgItemText(hDlg, OPT_CommentText, commentText);
\r
5726 EnableWindow(GetDlgItem(hDlg, OPT_CancelComment), editComment);
\r
5727 EnableWindow(GetDlgItem(hDlg, OPT_ClearComment), editComment);
\r
5728 EnableWindow(GetDlgItem(hDlg, OPT_EditComment), !editComment);
\r
5729 SendMessage(hwndText, EM_SETREADONLY, !editComment, 0);
\r
5730 SetWindowText(hDlg, commentTitle);
\r
5731 if (editComment) {
\r
5732 SetFocus(hwndText);
\r
5734 SetFocus(GetDlgItem(hDlg, IDOK));
\r
5736 SendMessage(GetDlgItem(hDlg, OPT_CommentText),
\r
5737 WM_SETFONT, (WPARAM)font[boardSize][COMMENT_FONT]->hf,
\r
5738 MAKELPARAM(FALSE, 0));
\r
5739 /* Size and position the dialog */
\r
5740 if (!commentDialog) {
\r
5741 commentDialog = hDlg;
\r
5742 flags = SWP_NOZORDER;
\r
5743 GetClientRect(hDlg, &rect);
\r
5744 sizeX = rect.right;
\r
5745 sizeY = rect.bottom;
\r
5746 if (wpComment.x != CW_USEDEFAULT && wpComment.y != CW_USEDEFAULT &&
\r
5747 wpComment.width != CW_USEDEFAULT && wpComment.height != CW_USEDEFAULT) {
\r
5748 WINDOWPLACEMENT wp;
\r
5749 EnsureOnScreen(&wpComment.x, &wpComment.y, 0, 0);
\r
5750 wp.length = sizeof(WINDOWPLACEMENT);
\r
5752 wp.showCmd = SW_SHOW;
\r
5753 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
5754 wp.rcNormalPosition.left = wpComment.x;
\r
5755 wp.rcNormalPosition.right = wpComment.x + wpComment.width;
\r
5756 wp.rcNormalPosition.top = wpComment.y;
\r
5757 wp.rcNormalPosition.bottom = wpComment.y + wpComment.height;
\r
5758 SetWindowPlacement(hDlg, &wp);
\r
5760 GetClientRect(hDlg, &rect);
\r
5761 newSizeX = rect.right;
\r
5762 newSizeY = rect.bottom;
\r
5763 ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY,
\r
5764 newSizeX, newSizeY);
\r
5771 case WM_COMMAND: /* message: received a command */
\r
5772 switch (LOWORD(wParam)) {
\r
5774 if (editComment) {
\r
5776 /* Read changed options from the dialog box */
\r
5777 hwndText = GetDlgItem(hDlg, OPT_CommentText);
\r
5778 len = GetWindowTextLength(hwndText);
\r
5779 str = (char *) malloc(len + 1);
\r
5780 GetWindowText(hwndText, str, len + 1);
\r
5789 ReplaceComment(commentIndex, str);
\r
5796 case OPT_CancelComment:
\r
5800 case OPT_ClearComment:
\r
5801 SetDlgItemText(hDlg, OPT_CommentText, "");
\r
5804 case OPT_EditComment:
\r
5805 EditCommentEvent();
\r
5814 newSizeX = LOWORD(lParam);
\r
5815 newSizeY = HIWORD(lParam);
\r
5816 ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY, newSizeX, newSizeY);
\r
5821 case WM_GETMINMAXINFO:
\r
5822 /* Prevent resizing window too small */
\r
5823 mmi = (MINMAXINFO *) lParam;
\r
5824 mmi->ptMinTrackSize.x = 100;
\r
5825 mmi->ptMinTrackSize.y = 100;
\r
5832 EitherCommentPopUp(int index, char *title, char *str, BOOLEAN edit)
\r
5837 CheckMenuItem(GetMenu(hwndMain), IDM_EditComment, edit ? MF_CHECKED : MF_UNCHECKED);
\r
5839 if (str == NULL) str = "";
\r
5840 p = (char *) malloc(2 * strlen(str) + 2);
\r
5843 if (*str == '\n') *q++ = '\r';
\r
5847 if (commentText != NULL) free(commentText);
\r
5849 commentIndex = index;
\r
5850 commentTitle = title;
\r
5852 editComment = edit;
\r
5854 if (commentDialog) {
\r
5855 SendMessage(commentDialog, WM_INITDIALOG, 0, 0);
\r
5856 if (!commentUp) ShowWindow(commentDialog, SW_SHOW);
\r
5858 lpProc = MakeProcInstance((FARPROC)CommentDialog, hInst);
\r
5859 CreateDialog(hInst, MAKEINTRESOURCE(DLG_EditComment),
\r
5860 hwndMain, (DLGPROC)lpProc);
\r
5861 FreeProcInstance(lpProc);
\r
5867 /*---------------------------------------------------------------------------*\
\r
5869 * Type-in move dialog functions
\r
5871 \*---------------------------------------------------------------------------*/
\r
5874 TypeInMoveDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
5876 char move[MSG_SIZ];
\r
5878 ChessMove moveType;
\r
5879 int fromX, fromY, toX, toY;
\r
5882 switch (message) {
\r
5883 case WM_INITDIALOG:
\r
5884 move[0] = (char) lParam;
\r
5885 move[1] = NULLCHAR;
\r
5886 CenterWindowEx(hDlg, GetWindow(hDlg, GW_OWNER), 1 );
\r
5887 hInput = GetDlgItem(hDlg, OPT_Move);
\r
5888 SetWindowText(hInput, move);
\r
5890 SendMessage(hInput, EM_SETSEL, (WPARAM)9999, (LPARAM)9999);
\r
5894 switch (LOWORD(wParam)) {
\r
5896 GetDlgItemText(hDlg, OPT_Move, move, sizeof(move));
\r
5897 { int n; Board board;
\r
5899 if(gameMode == EditPosition && ParseFEN(board, &n, move) ) {
\r
5900 EditPositionPasteFEN(move);
\r
5901 EndDialog(hDlg, TRUE);
\r
5904 // [HGM] movenum: allow move number to be typed in any mode
\r
5905 if(sscanf(move, "%d", &n) == 1 && n != 0 ) {
\r
5907 EndDialog(hDlg, TRUE);
\r
5911 if (gameMode != EditGame && currentMove != forwardMostMove &&
\r
5912 gameMode != Training) {
\r
5913 DisplayMoveError("Displayed move is not current");
\r
5915 // GetDlgItemText(hDlg, OPT_Move, move, sizeof(move)); // moved upstream
\r
5916 int ok = ParseOneMove(move, gameMode == EditPosition ? blackPlaysFirst : currentMove,
\r
5917 &moveType, &fromX, &fromY, &toX, &toY, &promoChar);
\r
5918 if(!ok && move[0] >= 'a') { move[0] += 'A' - 'a'; ok = 2; } // [HGM] try also capitalized
\r
5919 if (ok==1 || ok && ParseOneMove(move, gameMode == EditPosition ? blackPlaysFirst : currentMove,
\r
5920 &moveType, &fromX, &fromY, &toX, &toY, &promoChar)) {
\r
5921 if (gameMode != Training)
\r
5922 forwardMostMove = currentMove;
\r
5923 UserMoveEvent(fromX, fromY, toX, toY, promoChar);
\r
5925 DisplayMoveError("Could not parse move");
\r
5928 EndDialog(hDlg, TRUE);
\r
5931 EndDialog(hDlg, FALSE);
\r
5942 PopUpMoveDialog(char firstchar)
\r
5946 if ((gameMode == BeginningOfGame && !appData.icsActive) ||
\r
5947 gameMode == MachinePlaysWhite || gameMode == MachinePlaysBlack ||
\r
5948 gameMode == AnalyzeMode || gameMode == EditGame ||
\r
5949 gameMode == EditPosition || gameMode == IcsExamining ||
\r
5950 gameMode == IcsPlayingWhite || gameMode == IcsPlayingBlack ||
\r
5951 isdigit(firstchar) && // [HGM] movenum: allow typing in of move nr in 'passive' modes
\r
5952 ( gameMode == AnalyzeFile || gameMode == PlayFromGameFile ||
\r
5953 gameMode == IcsObserving || gameMode == TwoMachinesPlay ) ||
\r
5954 gameMode == Training) {
\r
5955 lpProc = MakeProcInstance((FARPROC)TypeInMoveDialog, hInst);
\r
5956 DialogBoxParam(hInst, MAKEINTRESOURCE(DLG_TypeInMove),
\r
5957 hwndMain, (DLGPROC)lpProc, (LPARAM)firstchar);
\r
5958 FreeProcInstance(lpProc);
\r
5962 /*---------------------------------------------------------------------------*\
\r
5964 * Type-in name dialog functions
\r
5966 \*---------------------------------------------------------------------------*/
\r
5969 TypeInNameDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
5971 char move[MSG_SIZ];
\r
5974 switch (message) {
\r
5975 case WM_INITDIALOG:
\r
5976 move[0] = (char) lParam;
\r
5977 move[1] = NULLCHAR;
\r
5978 CenterWindowEx(hDlg, GetWindow(hDlg, GW_OWNER), 1 );
\r
5979 hInput = GetDlgItem(hDlg, OPT_Name);
\r
5980 SetWindowText(hInput, move);
\r
5982 SendMessage(hInput, EM_SETSEL, (WPARAM)9999, (LPARAM)9999);
\r
5986 switch (LOWORD(wParam)) {
\r
5988 GetDlgItemText(hDlg, OPT_Name, move, sizeof(move));
\r
5989 appData.userName = strdup(move);
\r
5992 EndDialog(hDlg, TRUE);
\r
5995 EndDialog(hDlg, FALSE);
\r
6006 PopUpNameDialog(char firstchar)
\r
6010 lpProc = MakeProcInstance((FARPROC)TypeInNameDialog, hInst);
\r
6011 DialogBoxParam(hInst, MAKEINTRESOURCE(DLG_TypeInName),
\r
6012 hwndMain, (DLGPROC)lpProc, (LPARAM)firstchar);
\r
6013 FreeProcInstance(lpProc);
\r
6016 /*---------------------------------------------------------------------------*\
\r
6020 \*---------------------------------------------------------------------------*/
\r
6022 /* Nonmodal error box */
\r
6023 LRESULT CALLBACK ErrorDialog(HWND hDlg, UINT message,
\r
6024 WPARAM wParam, LPARAM lParam);
\r
6027 ErrorPopUp(char *title, char *content)
\r
6031 BOOLEAN modal = hwndMain == NULL;
\r
6049 strncpy(errorTitle, title, sizeof(errorTitle));
\r
6050 errorTitle[sizeof(errorTitle) - 1] = '\0';
\r
6053 MessageBox(NULL, errorMessage, errorTitle, MB_OK|MB_ICONEXCLAMATION);
\r
6055 lpProc = MakeProcInstance((FARPROC)ErrorDialog, hInst);
\r
6056 CreateDialog(hInst, MAKEINTRESOURCE(DLG_Error),
\r
6057 hwndMain, (DLGPROC)lpProc);
\r
6058 FreeProcInstance(lpProc);
\r
6065 if (!appData.popupMoveErrors && moveErrorMessageUp) DisplayMessage("", "");
\r
6066 if (errorDialog == NULL) return;
\r
6067 DestroyWindow(errorDialog);
\r
6068 errorDialog = NULL;
\r
6072 ErrorDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
6077 switch (message) {
\r
6078 case WM_INITDIALOG:
\r
6079 GetWindowRect(hDlg, &rChild);
\r
6082 SetWindowPos(hDlg, NULL, rChild.left,
\r
6083 rChild.top + boardRect.top - (rChild.bottom - rChild.top),
\r
6084 0, 0, SWP_NOZORDER|SWP_NOSIZE);
\r
6088 [AS] It seems that the above code wants to move the dialog up in the "caption
\r
6089 area" of the main window, but it uses the dialog height as an hard-coded constant,
\r
6090 and it doesn't work when you resize the dialog.
\r
6091 For now, just give it a default position.
\r
6093 SetWindowPos(hDlg, NULL, boardRect.left+8, boardRect.top+8, 0, 0, SWP_NOZORDER|SWP_NOSIZE);
\r
6095 errorDialog = hDlg;
\r
6096 SetWindowText(hDlg, errorTitle);
\r
6097 hwndText = GetDlgItem(hDlg, OPT_ErrorText);
\r
6098 SetDlgItemText(hDlg, OPT_ErrorText, errorMessage);
\r
6102 switch (LOWORD(wParam)) {
\r
6105 if (errorDialog == hDlg) errorDialog = NULL;
\r
6106 DestroyWindow(hDlg);
\r
6118 HWND gothicDialog = NULL;
\r
6121 GothicDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
6125 int height = GetSystemMetrics(SM_CYCAPTION)+GetSystemMetrics(SM_CYFRAME);
\r
6127 switch (message) {
\r
6128 case WM_INITDIALOG:
\r
6129 GetWindowRect(hDlg, &rChild);
\r
6131 SetWindowPos(hDlg, NULL, wpMain.x, wpMain.y-height, wpMain.width, height,
\r
6135 [AS] It seems that the above code wants to move the dialog up in the "caption
\r
6136 area" of the main window, but it uses the dialog height as an hard-coded constant,
\r
6137 and it doesn't work when you resize the dialog.
\r
6138 For now, just give it a default position.
\r
6140 gothicDialog = hDlg;
\r
6141 SetWindowText(hDlg, errorTitle);
\r
6142 hwndText = GetDlgItem(hDlg, OPT_ErrorText);
\r
6143 SetDlgItemText(hDlg, OPT_ErrorText, errorMessage);
\r
6147 switch (LOWORD(wParam)) {
\r
6150 if (errorDialog == hDlg) errorDialog = NULL;
\r
6151 DestroyWindow(hDlg);
\r
6163 GothicPopUp(char *title, VariantClass variant)
\r
6166 static char *lastTitle;
\r
6168 strncpy(errorTitle, title, sizeof(errorTitle));
\r
6169 errorTitle[sizeof(errorTitle) - 1] = '\0';
\r
6171 if(lastTitle != title && gothicDialog != NULL) {
\r
6172 DestroyWindow(gothicDialog);
\r
6173 gothicDialog = NULL;
\r
6175 if(variant != VariantNormal && gothicDialog == NULL) {
\r
6176 title = lastTitle;
\r
6177 lpProc = MakeProcInstance((FARPROC)GothicDialog, hInst);
\r
6178 CreateDialog(hInst, MAKEINTRESOURCE(DLG_Error),
\r
6179 hwndMain, (DLGPROC)lpProc);
\r
6180 FreeProcInstance(lpProc);
\r
6185 /*---------------------------------------------------------------------------*\
\r
6187 * Ics Interaction console functions
\r
6189 \*---------------------------------------------------------------------------*/
\r
6191 #define HISTORY_SIZE 64
\r
6192 static char *history[HISTORY_SIZE];
\r
6193 int histIn = 0, histP = 0;
\r
6196 SaveInHistory(char *cmd)
\r
6198 if (history[histIn] != NULL) {
\r
6199 free(history[histIn]);
\r
6200 history[histIn] = NULL;
\r
6202 if (*cmd == NULLCHAR) return;
\r
6203 history[histIn] = StrSave(cmd);
\r
6204 histIn = (histIn + 1) % HISTORY_SIZE;
\r
6205 if (history[histIn] != NULL) {
\r
6206 free(history[histIn]);
\r
6207 history[histIn] = NULL;
\r
6213 PrevInHistory(char *cmd)
\r
6216 if (histP == histIn) {
\r
6217 if (history[histIn] != NULL) free(history[histIn]);
\r
6218 history[histIn] = StrSave(cmd);
\r
6220 newhp = (histP - 1 + HISTORY_SIZE) % HISTORY_SIZE;
\r
6221 if (newhp == histIn || history[newhp] == NULL) return NULL;
\r
6223 return history[histP];
\r
6229 if (histP == histIn) return NULL;
\r
6230 histP = (histP + 1) % HISTORY_SIZE;
\r
6231 return history[histP];
\r
6235 LoadIcsTextMenu(IcsTextMenuEntry *e)
\r
6239 hmenu = LoadMenu(hInst, "TextMenu");
\r
6240 h = GetSubMenu(hmenu, 0);
\r
6242 if (strcmp(e->item, "-") == 0) {
\r
6243 AppendMenu(h, MF_SEPARATOR, 0, 0);
\r
6245 if (e->item[0] == '|') {
\r
6246 AppendMenu(h, MF_STRING|MF_MENUBARBREAK,
\r
6247 IDM_CommandX + i, &e->item[1]);
\r
6249 AppendMenu(h, MF_STRING, IDM_CommandX + i, e->item);
\r
6258 WNDPROC consoleTextWindowProc;
\r
6261 CommandX(HWND hwnd, char *command, BOOLEAN getname, BOOLEAN immediate)
\r
6263 char buf[MSG_SIZ], name[MSG_SIZ];
\r
6264 HWND hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
6268 SetWindowText(hInput, command);
\r
6270 SendMessage(hInput, WM_CHAR, '\r', 0);
\r
6272 sel.cpMin = 999999;
\r
6273 sel.cpMax = 999999;
\r
6274 SendMessage(hInput, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
6279 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
6280 if (sel.cpMin == sel.cpMax) {
\r
6281 /* Expand to surrounding word */
\r
6284 tr.chrg.cpMax = sel.cpMin;
\r
6285 tr.chrg.cpMin = --sel.cpMin;
\r
6286 if (sel.cpMin < 0) break;
\r
6287 tr.lpstrText = name;
\r
6288 SendMessage(hwnd, EM_GETTEXTRANGE, 0, (LPARAM) &tr);
\r
6289 } while (isalpha(name[0]) || isdigit(name[0]) || name[0] == '-');
\r
6293 tr.chrg.cpMin = sel.cpMax;
\r
6294 tr.chrg.cpMax = ++sel.cpMax;
\r
6295 tr.lpstrText = name;
\r
6296 if (SendMessage(hwnd, EM_GETTEXTRANGE, 0, (LPARAM) &tr) < 1) break;
\r
6297 } while (isalpha(name[0]) || isdigit(name[0]) || name[0] == '-');
\r
6300 if (sel.cpMax == sel.cpMin || sel.cpMax - sel.cpMin > MSG_SIZ/2) {
\r
6301 MessageBeep(MB_ICONEXCLAMATION);
\r
6305 tr.lpstrText = name;
\r
6306 SendMessage(hwnd, EM_GETTEXTRANGE, 0, (LPARAM) &tr);
\r
6308 if (sel.cpMax - sel.cpMin > MSG_SIZ/2) {
\r
6309 MessageBeep(MB_ICONEXCLAMATION);
\r
6312 SendMessage(hwnd, EM_GETSELTEXT, 0, (LPARAM) name);
\r
6315 sprintf(buf, "%s %s", command, name);
\r
6316 SetWindowText(hInput, buf);
\r
6317 SendMessage(hInput, WM_CHAR, '\r', 0);
\r
6319 sprintf(buf, "%s %s ", command, name); /* trailing space */
\r
6320 SetWindowText(hInput, buf);
\r
6321 sel.cpMin = 999999;
\r
6322 sel.cpMax = 999999;
\r
6323 SendMessage(hInput, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
6329 ConsoleTextSubclass(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
6334 switch (message) {
\r
6336 if (!(GetKeyState(VK_CONTROL) & ~1)) break;
\r
6339 SendMessage(hwnd, EM_LINESCROLL, 0, -999999);
\r
6342 sel.cpMin = 999999;
\r
6343 sel.cpMax = 999999;
\r
6344 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
6345 SendMessage(hwnd, EM_SCROLLCARET, 0, 0);
\r
6350 if(wParam != '\022') {
\r
6351 if (wParam == '\t') {
\r
6352 if (GetKeyState(VK_SHIFT) < 0) {
\r
6354 if (IsIconic(hwndMain)) ShowWindow(hwndMain, SW_RESTORE);
\r
6355 if (buttonDesc[0].hwnd) {
\r
6356 SetFocus(buttonDesc[0].hwnd);
\r
6358 SetFocus(hwndMain);
\r
6362 SetFocus(GetDlgItem(hwndConsole, OPT_ConsoleInput));
\r
6365 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
6366 JAWS_DELETE( SetFocus(hInput); )
\r
6367 SendMessage(hInput, message, wParam, lParam);
\r
6370 } // [HGM] navigate: for Ctrl+R, flow into nex case (moved up here) to summon up menu
\r
6371 case WM_RBUTTONUP:
\r
6372 if (GetKeyState(VK_SHIFT) & ~1) {
\r
6373 SendDlgItemMessage(hwndConsole, OPT_ConsoleText,
\r
6374 WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
6377 HMENU hmenu = LoadIcsTextMenu(icsTextMenuEntry);
\r
6378 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
6379 if (sel.cpMin == sel.cpMax) {
\r
6380 EnableMenuItem(hmenu, IDM_Copy, MF_BYCOMMAND|MF_GRAYED);
\r
6381 EnableMenuItem(hmenu, IDM_QuickPaste, MF_BYCOMMAND|MF_GRAYED);
\r
6383 if (!IsClipboardFormatAvailable(CF_TEXT)) {
\r
6384 EnableMenuItem(hmenu, IDM_Paste, MF_BYCOMMAND|MF_GRAYED);
\r
6386 pt.x = LOWORD(lParam);
\r
6387 pt.y = HIWORD(lParam);
\r
6388 MenuPopup(hwnd, pt, hmenu, -1);
\r
6392 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
6394 return SendMessage(hInput, message, wParam, lParam);
\r
6395 case WM_MBUTTONDOWN:
\r
6396 return SendMessage(hwnd, WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
6397 case WM_RBUTTONDOWN:
\r
6398 if (!(GetKeyState(VK_SHIFT) & ~1)) {
\r
6399 /* Move selection here if it was empty */
\r
6401 pt.x = LOWORD(lParam);
\r
6402 pt.y = HIWORD(lParam);
\r
6403 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
6404 if (sel.cpMin == sel.cpMax) {
\r
6405 sel.cpMin = SendMessage(hwnd, EM_CHARFROMPOS, 0, (LPARAM)&pt); /*doc is wrong*/
\r
6406 sel.cpMax = sel.cpMin;
\r
6407 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
6409 SendMessage(hwnd, EM_HIDESELECTION, FALSE, FALSE);
\r
6413 switch (LOWORD(wParam)) {
\r
6414 case IDM_QuickPaste:
\r
6416 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
6417 if (sel.cpMin == sel.cpMax) {
\r
6418 MessageBeep(MB_ICONEXCLAMATION);
\r
6421 SendMessage(hwnd, WM_COPY, 0, 0);
\r
6422 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
6423 SendMessage(hInput, WM_PASTE, 0, 0);
\r
6428 SendMessage(hwnd, WM_CUT, 0, 0);
\r
6431 SendMessage(hwnd, WM_PASTE, 0, 0);
\r
6434 SendMessage(hwnd, WM_COPY, 0, 0);
\r
6438 int i = LOWORD(wParam) - IDM_CommandX;
\r
6439 if (i >= 0 && i < ICS_TEXT_MENU_SIZE &&
\r
6440 icsTextMenuEntry[i].command != NULL) {
\r
6441 CommandX(hwnd, icsTextMenuEntry[i].command,
\r
6442 icsTextMenuEntry[i].getname,
\r
6443 icsTextMenuEntry[i].immediate);
\r
6451 return (*consoleTextWindowProc)(hwnd, message, wParam, lParam);
\r
6454 WNDPROC consoleInputWindowProc;
\r
6457 ConsoleInputSubclass(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
6459 char buf[MSG_SIZ];
\r
6461 static BOOL sendNextChar = FALSE;
\r
6462 static BOOL quoteNextChar = FALSE;
\r
6463 InputSource *is = consoleInputSource;
\r
6467 switch (message) {
\r
6469 if (!appData.localLineEditing || sendNextChar) {
\r
6470 is->buf[0] = (CHAR) wParam;
\r
6472 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
6473 sendNextChar = FALSE;
\r
6476 if (quoteNextChar) {
\r
6477 buf[0] = (char) wParam;
\r
6478 buf[1] = NULLCHAR;
\r
6479 SendMessage(hwnd, EM_REPLACESEL, TRUE, (LPARAM) buf);
\r
6480 quoteNextChar = FALSE;
\r
6484 case '\r': /* Enter key */
\r
6485 is->count = GetWindowText(hwnd, is->buf, INPUT_SOURCE_BUF_SIZE-1);
\r
6486 if (consoleEcho) SaveInHistory(is->buf);
\r
6487 is->buf[is->count++] = '\n';
\r
6488 is->buf[is->count] = NULLCHAR;
\r
6489 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
6490 if (consoleEcho) {
\r
6491 ConsoleOutput(is->buf, is->count, TRUE);
\r
6492 } else if (appData.localLineEditing) {
\r
6493 ConsoleOutput("\n", 1, TRUE);
\r
6496 case '\033': /* Escape key */
\r
6497 SetWindowText(hwnd, "");
\r
6498 cf.cbSize = sizeof(CHARFORMAT);
\r
6499 cf.dwMask = CFM_COLOR|CFM_BOLD|CFM_ITALIC|CFM_UNDERLINE|CFM_STRIKEOUT;
\r
6500 if (consoleEcho) {
\r
6501 cf.crTextColor = textAttribs[ColorNormal].color;
\r
6503 cf.crTextColor = COLOR_ECHOOFF;
\r
6505 cf.dwEffects = textAttribs[ColorNormal].effects;
\r
6506 SendMessage(hwnd, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&cf);
\r
6508 case '\t': /* Tab key */
\r
6509 if (GetKeyState(VK_SHIFT) < 0) {
\r
6511 SetFocus(GetDlgItem(hwndConsole, OPT_ConsoleText));
\r
6514 if (IsIconic(hwndMain)) ShowWindow(hwndMain, SW_RESTORE);
\r
6515 if (buttonDesc[0].hwnd) {
\r
6516 SetFocus(buttonDesc[0].hwnd);
\r
6518 SetFocus(hwndMain);
\r
6522 case '\023': /* Ctrl+S */
\r
6523 sendNextChar = TRUE;
\r
6525 case '\021': /* Ctrl+Q */
\r
6526 quoteNextChar = TRUE;
\r
6536 GetWindowText(hwnd, buf, MSG_SIZ);
\r
6537 p = PrevInHistory(buf);
\r
6539 SetWindowText(hwnd, p);
\r
6540 sel.cpMin = 999999;
\r
6541 sel.cpMax = 999999;
\r
6542 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
6547 p = NextInHistory();
\r
6549 SetWindowText(hwnd, p);
\r
6550 sel.cpMin = 999999;
\r
6551 sel.cpMax = 999999;
\r
6552 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
6558 if (!(GetKeyState(VK_CONTROL) & ~1)) break;
\r
6562 SendDlgItemMessage(hwndConsole, OPT_ConsoleText, message, wParam, lParam);
\r
6566 case WM_MBUTTONDOWN:
\r
6567 SendDlgItemMessage(hwndConsole, OPT_ConsoleText,
\r
6568 WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
6570 case WM_RBUTTONUP:
\r
6571 if (GetKeyState(VK_SHIFT) & ~1) {
\r
6572 SendDlgItemMessage(hwndConsole, OPT_ConsoleText,
\r
6573 WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
6577 hmenu = LoadMenu(hInst, "InputMenu");
\r
6578 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
6579 if (sel.cpMin == sel.cpMax) {
\r
6580 EnableMenuItem(hmenu, IDM_Copy, MF_BYCOMMAND|MF_GRAYED);
\r
6581 EnableMenuItem(hmenu, IDM_Cut, MF_BYCOMMAND|MF_GRAYED);
\r
6583 if (!IsClipboardFormatAvailable(CF_TEXT)) {
\r
6584 EnableMenuItem(hmenu, IDM_Paste, MF_BYCOMMAND|MF_GRAYED);
\r
6586 pt.x = LOWORD(lParam);
\r
6587 pt.y = HIWORD(lParam);
\r
6588 MenuPopup(hwnd, pt, hmenu, -1);
\r
6592 switch (LOWORD(wParam)) {
\r
6594 SendMessage(hwnd, EM_UNDO, 0, 0);
\r
6596 case IDM_SelectAll:
\r
6598 sel.cpMax = -1; /*999999?*/
\r
6599 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
6602 SendMessage(hwnd, WM_CUT, 0, 0);
\r
6605 SendMessage(hwnd, WM_PASTE, 0, 0);
\r
6608 SendMessage(hwnd, WM_COPY, 0, 0);
\r
6613 return (*consoleInputWindowProc)(hwnd, message, wParam, lParam);
\r
6616 #define CO_MAX 100000
\r
6617 #define CO_TRIM 1000
\r
6620 ConsoleWndProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
6622 static SnapData sd;
\r
6623 HWND hText, hInput;
\r
6625 static int sizeX, sizeY;
\r
6626 int newSizeX, newSizeY;
\r
6630 hText = GetDlgItem(hDlg, OPT_ConsoleText);
\r
6631 hInput = GetDlgItem(hDlg, OPT_ConsoleInput);
\r
6633 switch (message) {
\r
6635 if (((NMHDR*)lParam)->code == EN_LINK)
\r
6637 ENLINK *pLink = (ENLINK*)lParam;
\r
6638 if (pLink->msg == WM_LBUTTONUP)
\r
6642 tr.chrg = pLink->chrg;
\r
6643 tr.lpstrText = malloc(1+tr.chrg.cpMax-tr.chrg.cpMin);
\r
6644 SendMessage(hText, EM_GETTEXTRANGE, 0, (LPARAM)&tr);
\r
6645 ShellExecute(NULL, "open", tr.lpstrText, NULL, NULL, SW_SHOW);
\r
6646 free(tr.lpstrText);
\r
6650 case WM_INITDIALOG: /* message: initialize dialog box */
\r
6651 hwndConsole = hDlg;
\r
6653 consoleTextWindowProc = (WNDPROC)
\r
6654 SetWindowLong(hText, GWL_WNDPROC, (LONG) ConsoleTextSubclass);
\r
6655 SendMessage(hText, EM_SETBKGNDCOLOR, FALSE, consoleBackgroundColor);
\r
6656 consoleInputWindowProc = (WNDPROC)
\r
6657 SetWindowLong(hInput, GWL_WNDPROC, (LONG) ConsoleInputSubclass);
\r
6658 SendMessage(hInput, EM_SETBKGNDCOLOR, FALSE, consoleBackgroundColor);
\r
6659 Colorize(ColorNormal, TRUE);
\r
6660 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM) &consoleCF);
\r
6661 ChangedConsoleFont();
\r
6662 GetClientRect(hDlg, &rect);
\r
6663 sizeX = rect.right;
\r
6664 sizeY = rect.bottom;
\r
6665 if (wpConsole.x != CW_USEDEFAULT && wpConsole.y != CW_USEDEFAULT &&
\r
6666 wpConsole.width != CW_USEDEFAULT && wpConsole.height != CW_USEDEFAULT) {
\r
6667 WINDOWPLACEMENT wp;
\r
6668 EnsureOnScreen(&wpConsole.x, &wpConsole.y, 0, 0);
\r
6669 wp.length = sizeof(WINDOWPLACEMENT);
\r
6671 wp.showCmd = SW_SHOW;
\r
6672 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
6673 wp.rcNormalPosition.left = wpConsole.x;
\r
6674 wp.rcNormalPosition.right = wpConsole.x + wpConsole.width;
\r
6675 wp.rcNormalPosition.top = wpConsole.y;
\r
6676 wp.rcNormalPosition.bottom = wpConsole.y + wpConsole.height;
\r
6677 SetWindowPlacement(hDlg, &wp);
\r
6680 // [HGM] Chessknight's change 2004-07-13
\r
6681 else { /* Determine Defaults */
\r
6682 WINDOWPLACEMENT wp;
\r
6683 wpConsole.x = wpMain.width + 1;
\r
6684 wpConsole.y = wpMain.y;
\r
6685 wpConsole.width = screenWidth - wpMain.width;
\r
6686 wpConsole.height = wpMain.height;
\r
6687 EnsureOnScreen(&wpConsole.x, &wpConsole.y, 0, 0);
\r
6688 wp.length = sizeof(WINDOWPLACEMENT);
\r
6690 wp.showCmd = SW_SHOW;
\r
6691 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
6692 wp.rcNormalPosition.left = wpConsole.x;
\r
6693 wp.rcNormalPosition.right = wpConsole.x + wpConsole.width;
\r
6694 wp.rcNormalPosition.top = wpConsole.y;
\r
6695 wp.rcNormalPosition.bottom = wpConsole.y + wpConsole.height;
\r
6696 SetWindowPlacement(hDlg, &wp);
\r
6699 // Allow hText to highlight URLs and send notifications on them
\r
6700 wMask = (WORD) SendMessage(hText, EM_GETEVENTMASK, 0, 0L);
\r
6701 SendMessage(hText, EM_SETEVENTMASK, 0, wMask | ENM_LINK);
\r
6702 SendMessage(hText, EM_AUTOURLDETECT, TRUE, 0L);
\r
6703 SetWindowLong(hText, GWL_USERDATA, 79); // initialize the text window's width
\r
6717 if (IsIconic(hDlg)) break;
\r
6718 newSizeX = LOWORD(lParam);
\r
6719 newSizeY = HIWORD(lParam);
\r
6720 if (sizeX != newSizeX || sizeY != newSizeY) {
\r
6721 RECT rectText, rectInput;
\r
6723 int newTextHeight, newTextWidth;
\r
6724 GetWindowRect(hText, &rectText);
\r
6725 newTextWidth = rectText.right - rectText.left + newSizeX - sizeX;
\r
6726 newTextHeight = rectText.bottom - rectText.top + newSizeY - sizeY;
\r
6727 if (newTextHeight < 0) {
\r
6728 newSizeY += -newTextHeight;
\r
6729 newTextHeight = 0;
\r
6731 SetWindowPos(hText, NULL, 0, 0,
\r
6732 newTextWidth, newTextHeight, SWP_NOZORDER|SWP_NOMOVE);
\r
6733 GetWindowRect(hInput, &rectInput); /* gives screen coords */
\r
6734 pt.x = rectInput.left;
\r
6735 pt.y = rectInput.top + newSizeY - sizeY;
\r
6736 ScreenToClient(hDlg, &pt);
\r
6737 SetWindowPos(hInput, NULL,
\r
6738 pt.x, pt.y, /* needs client coords */
\r
6739 rectInput.right - rectInput.left + newSizeX - sizeX,
\r
6740 rectInput.bottom - rectInput.top, SWP_NOZORDER);
\r
6746 case WM_GETMINMAXINFO:
\r
6747 /* Prevent resizing window too small */
\r
6748 mmi = (MINMAXINFO *) lParam;
\r
6749 mmi->ptMinTrackSize.x = 100;
\r
6750 mmi->ptMinTrackSize.y = 100;
\r
6753 /* [AS] Snapping */
\r
6754 case WM_ENTERSIZEMOVE:
\r
6755 return OnEnterSizeMove( &sd, hDlg, wParam, lParam );
\r
6758 return OnSizing( &sd, hDlg, wParam, lParam );
\r
6761 return OnMoving( &sd, hDlg, wParam, lParam );
\r
6763 case WM_EXITSIZEMOVE:
\r
6764 UpdateICSWidth(hText);
\r
6765 return OnExitSizeMove( &sd, hDlg, wParam, lParam );
\r
6768 return DefWindowProc(hDlg, message, wParam, lParam);
\r
6776 if (hwndConsole) return;
\r
6777 hCons = CreateDialog(hInst, szConsoleName, 0, NULL);
\r
6778 SendMessage(hCons, WM_INITDIALOG, 0, 0);
\r
6783 ConsoleOutput(char* data, int length, int forceVisible)
\r
6788 char buf[CO_MAX+1];
\r
6791 static int delayLF = 0;
\r
6792 CHARRANGE savesel, sel;
\r
6794 if (hwndConsole == NULL || length > CO_MAX-100 || length == 0) return;
\r
6802 while (length--) {
\r
6810 } else if (*p == '\007') {
\r
6811 MyPlaySound(&sounds[(int)SoundBell]);
\r
6818 hText = GetDlgItem(hwndConsole, OPT_ConsoleText);
\r
6819 SendMessage(hText, EM_HIDESELECTION, TRUE, FALSE);
\r
6820 /* Save current selection */
\r
6821 SendMessage(hText, EM_EXGETSEL, 0, (LPARAM)&savesel);
\r
6822 exlen = GetWindowTextLength(hText);
\r
6823 /* Find out whether current end of text is visible */
\r
6824 SendMessage(hText, EM_GETRECT, 0, (LPARAM) &rect);
\r
6825 SendMessage(hText, EM_POSFROMCHAR, (WPARAM) &pEnd, exlen);
\r
6826 /* Trim existing text if it's too long */
\r
6827 if (exlen + (q - buf) > CO_MAX) {
\r
6828 trim = (CO_TRIM > (q - buf)) ? CO_TRIM : (q - buf);
\r
6831 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
6832 SendMessage(hText, EM_REPLACESEL, 0, (LPARAM)"");
\r
6834 savesel.cpMin -= trim;
\r
6835 savesel.cpMax -= trim;
\r
6836 if (exlen < 0) exlen = 0;
\r
6837 if (savesel.cpMin < 0) savesel.cpMin = 0;
\r
6838 if (savesel.cpMax < savesel.cpMin) savesel.cpMax = savesel.cpMin;
\r
6840 /* Append the new text */
\r
6841 sel.cpMin = exlen;
\r
6842 sel.cpMax = exlen;
\r
6843 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
6844 SendMessage(hText, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&consoleCF);
\r
6845 SendMessage(hText, EM_REPLACESEL, 0, (LPARAM) buf);
\r
6846 if (forceVisible || exlen == 0 ||
\r
6847 (rect.left <= pEnd.x && pEnd.x < rect.right &&
\r
6848 rect.top <= pEnd.y && pEnd.y < rect.bottom)) {
\r
6849 /* Scroll to make new end of text visible if old end of text
\r
6850 was visible or new text is an echo of user typein */
\r
6851 sel.cpMin = 9999999;
\r
6852 sel.cpMax = 9999999;
\r
6853 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
6854 SendMessage(hText, EM_HIDESELECTION, FALSE, FALSE);
\r
6855 SendMessage(hText, EM_SCROLLCARET, 0, 0);
\r
6856 SendMessage(hText, EM_HIDESELECTION, TRUE, FALSE);
\r
6858 if (savesel.cpMax == exlen || forceVisible) {
\r
6859 /* Move insert point to new end of text if it was at the old
\r
6860 end of text or if the new text is an echo of user typein */
\r
6861 sel.cpMin = 9999999;
\r
6862 sel.cpMax = 9999999;
\r
6863 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
6865 /* Restore previous selection */
\r
6866 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&savesel);
\r
6868 SendMessage(hText, EM_HIDESELECTION, FALSE, FALSE);
\r
6875 DisplayHoldingsCount(HDC hdc, int x, int y, int rightAlign, int copyNumber)
\r
6879 COLORREF oldFg, oldBg;
\r
6883 if(copyNumber > 1) sprintf(buf, "%d", copyNumber); else buf[0] = 0;
\r
6885 oldFg = SetTextColor(hdc, RGB(255, 255, 255)); /* white */
\r
6886 oldBg = SetBkColor(hdc, RGB(0, 0, 0)); /* black */
\r
6887 oldFont = SelectObject(hdc, font[boardSize][CLOCK_FONT]->hf);
\r
6890 rect.right = x + squareSize;
\r
6892 rect.bottom = y + squareSize;
\r
6895 ExtTextOut(hdc, x + MESSAGE_LINE_LEFTMARGIN
\r
6896 + (rightAlign ? (squareSize*2)/3 : 0),
\r
6897 y, ETO_CLIPPED|ETO_OPAQUE,
\r
6898 &rect, str, strlen(str), NULL);
\r
6900 (void) SetTextColor(hdc, oldFg);
\r
6901 (void) SetBkColor(hdc, oldBg);
\r
6902 (void) SelectObject(hdc, oldFont);
\r
6906 DisplayAClock(HDC hdc, int timeRemaining, int highlight,
\r
6907 RECT *rect, char *color, char *flagFell)
\r
6911 COLORREF oldFg, oldBg;
\r
6914 if (appData.clockMode) {
\r
6916 sprintf(buf, "%c %s %s", color[0], TimeString(timeRemaining), flagFell);
\r
6918 sprintf(buf, "%s:%c%s %s", color, (logoHeight>0 ? 0 : ' '), TimeString(timeRemaining), flagFell);
\r
6925 oldFg = SetTextColor(hdc, RGB(255, 255, 255)); /* white */
\r
6926 oldBg = SetBkColor(hdc, RGB(0, 0, 0)); /* black */
\r
6928 oldFg = SetTextColor(hdc, RGB(0, 0, 0)); /* black */
\r
6929 oldBg = SetBkColor(hdc, RGB(255, 255, 255)); /* white */
\r
6931 oldFont = SelectObject(hdc, font[boardSize][CLOCK_FONT]->hf);
\r
6935 ExtTextOut(hdc, rect->left + MESSAGE_LINE_LEFTMARGIN,
\r
6936 rect->top, ETO_CLIPPED|ETO_OPAQUE,
\r
6937 rect, str, strlen(str), NULL);
\r
6938 if(logoHeight > 0 && appData.clockMode) {
\r
6940 sprintf(buf, "%s %s", buf+7, flagFell);
\r
6941 r.top = rect->top + logoHeight/2;
\r
6942 r.left = rect->left;
\r
6943 r.right = rect->right;
\r
6944 r.bottom = rect->bottom;
\r
6945 ExtTextOut(hdc, rect->left + MESSAGE_LINE_LEFTMARGIN,
\r
6946 r.top, ETO_CLIPPED|ETO_OPAQUE,
\r
6947 &r, str, strlen(str), NULL);
\r
6949 (void) SetTextColor(hdc, oldFg);
\r
6950 (void) SetBkColor(hdc, oldBg);
\r
6951 (void) SelectObject(hdc, oldFont);
\r
6956 DoReadFile(HANDLE hFile, char *buf, int count, DWORD *outCount,
\r
6962 if( count <= 0 ) {
\r
6963 if (appData.debugMode) {
\r
6964 fprintf( debugFP, "DoReadFile: trying to read past end of buffer, overflow = %d\n", count );
\r
6967 return ERROR_INVALID_USER_BUFFER;
\r
6970 ResetEvent(ovl->hEvent);
\r
6971 ovl->Offset = ovl->OffsetHigh = 0;
\r
6972 ok = ReadFile(hFile, buf, count, outCount, ovl);
\r
6976 err = GetLastError();
\r
6977 if (err == ERROR_IO_PENDING) {
\r
6978 ok = GetOverlappedResult(hFile, ovl, outCount, TRUE);
\r
6982 err = GetLastError();
\r
6989 DoWriteFile(HANDLE hFile, char *buf, int count, DWORD *outCount,
\r
6994 ResetEvent(ovl->hEvent);
\r
6995 ovl->Offset = ovl->OffsetHigh = 0;
\r
6996 ok = WriteFile(hFile, buf, count, outCount, ovl);
\r
7000 err = GetLastError();
\r
7001 if (err == ERROR_IO_PENDING) {
\r
7002 ok = GetOverlappedResult(hFile, ovl, outCount, TRUE);
\r
7006 err = GetLastError();
\r
7012 /* [AS] If input is line by line and a line exceed the buffer size, force an error */
\r
7013 void CheckForInputBufferFull( InputSource * is )
\r
7015 if( is->lineByLine && (is->next - is->buf) >= INPUT_SOURCE_BUF_SIZE ) {
\r
7016 /* Look for end of line */
\r
7017 char * p = is->buf;
\r
7019 while( p < is->next && *p != '\n' ) {
\r
7023 if( p >= is->next ) {
\r
7024 if (appData.debugMode) {
\r
7025 fprintf( debugFP, "Input line exceeded buffer size (source id=%lu)\n", is->id );
\r
7028 is->error = ERROR_BROKEN_PIPE; /* [AS] Just any non-successful code! */
\r
7029 is->count = (DWORD) -1;
\r
7030 is->next = is->buf;
\r
7036 InputThread(LPVOID arg)
\r
7041 is = (InputSource *) arg;
\r
7042 ovl.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
\r
7043 ovl.Internal = ovl.InternalHigh = ovl.Offset = ovl.OffsetHigh = 0;
\r
7044 while (is->hThread != NULL) {
\r
7045 is->error = DoReadFile(is->hFile, is->next,
\r
7046 INPUT_SOURCE_BUF_SIZE - (is->next - is->buf),
\r
7047 &is->count, &ovl);
\r
7048 if (is->error == NO_ERROR) {
\r
7049 is->next += is->count;
\r
7051 if (is->error == ERROR_BROKEN_PIPE) {
\r
7052 /* Correct for MS brain damage. EOF reading a pipe is not an error. */
\r
7055 is->count = (DWORD) -1;
\r
7056 /* [AS] The (is->count <= 0) check below is not useful for unsigned values! */
\r
7061 CheckForInputBufferFull( is );
\r
7063 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
7065 if( is->count == ((DWORD) -1) ) break; /* [AS] */
\r
7067 if (is->count <= 0) break; /* Quit on EOF or error */
\r
7070 CloseHandle(ovl.hEvent);
\r
7071 CloseHandle(is->hFile);
\r
7073 if (appData.debugMode) {
\r
7074 fprintf( debugFP, "Input thread terminated (id=%lu, error=%d, count=%ld)\n", is->id, is->error, is->count );
\r
7081 /* Windows 95 beta 2 won't let you do overlapped i/o on a console or pipe */
\r
7083 NonOvlInputThread(LPVOID arg)
\r
7090 is = (InputSource *) arg;
\r
7091 while (is->hThread != NULL) {
\r
7092 is->error = ReadFile(is->hFile, is->next,
\r
7093 INPUT_SOURCE_BUF_SIZE - (is->next - is->buf),
\r
7094 &is->count, NULL) ? NO_ERROR : GetLastError();
\r
7095 if (is->error == NO_ERROR) {
\r
7096 /* Change CRLF to LF */
\r
7097 if (is->next > is->buf) {
\r
7099 i = is->count + 1;
\r
7107 if (prev == '\r' && *p == '\n') {
\r
7119 if (is->error == ERROR_BROKEN_PIPE) {
\r
7120 /* Correct for MS brain damage. EOF reading a pipe is not an error. */
\r
7123 is->count = (DWORD) -1;
\r
7127 CheckForInputBufferFull( is );
\r
7129 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
7131 if( is->count == ((DWORD) -1) ) break; /* [AS] */
\r
7133 if (is->count < 0) break; /* Quit on error */
\r
7135 CloseHandle(is->hFile);
\r
7140 SocketInputThread(LPVOID arg)
\r
7144 is = (InputSource *) arg;
\r
7145 while (is->hThread != NULL) {
\r
7146 is->count = recv(is->sock, is->buf, INPUT_SOURCE_BUF_SIZE, 0);
\r
7147 if ((int)is->count == SOCKET_ERROR) {
\r
7148 is->count = (DWORD) -1;
\r
7149 is->error = WSAGetLastError();
\r
7151 is->error = NO_ERROR;
\r
7152 is->next += is->count;
\r
7153 if (is->count == 0 && is->second == is) {
\r
7154 /* End of file on stderr; quit with no message */
\r
7158 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
7160 if( is->count == ((DWORD) -1) ) break; /* [AS] */
\r
7162 if (is->count <= 0) break; /* Quit on EOF or error */
\r
7168 InputEvent(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
7172 is = (InputSource *) lParam;
\r
7173 if (is->lineByLine) {
\r
7174 /* Feed in lines one by one */
\r
7175 char *p = is->buf;
\r
7177 while (q < is->next) {
\r
7178 if (*q++ == '\n') {
\r
7179 (is->func)(is, is->closure, p, q - p, NO_ERROR);
\r
7184 /* Move any partial line to the start of the buffer */
\r
7186 while (p < is->next) {
\r
7191 if (is->error != NO_ERROR || is->count == 0) {
\r
7192 /* Notify backend of the error. Note: If there was a partial
\r
7193 line at the end, it is not flushed through. */
\r
7194 (is->func)(is, is->closure, is->buf, is->count, is->error);
\r
7197 /* Feed in the whole chunk of input at once */
\r
7198 (is->func)(is, is->closure, is->buf, is->count, is->error);
\r
7199 is->next = is->buf;
\r
7203 /*---------------------------------------------------------------------------*\
\r
7205 * Menu enables. Used when setting various modes.
\r
7207 \*---------------------------------------------------------------------------*/
\r
7215 GreyRevert(Boolean grey)
\r
7216 { // [HGM] vari: for retracting variations in local mode
\r
7217 HMENU hmenu = GetMenu(hwndMain);
\r
7218 EnableMenuItem(hmenu, IDM_Revert, MF_BYCOMMAND|(grey ? MF_GRAYED : MF_ENABLED));
\r
7222 SetMenuEnables(HMENU hmenu, Enables *enab)
\r
7224 while (enab->item > 0) {
\r
7225 (void) EnableMenuItem(hmenu, enab->item, enab->flags);
\r
7230 Enables gnuEnables[] = {
\r
7231 { IDM_MailMove, MF_BYCOMMAND|MF_GRAYED },
\r
7232 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_GRAYED },
\r
7233 { IDM_IcsClient, MF_BYCOMMAND|MF_GRAYED },
\r
7234 { IDM_Accept, MF_BYCOMMAND|MF_GRAYED },
\r
7235 { IDM_Decline, MF_BYCOMMAND|MF_GRAYED },
\r
7236 { IDM_Rematch, MF_BYCOMMAND|MF_GRAYED },
\r
7237 { IDM_Adjourn, MF_BYCOMMAND|MF_GRAYED },
\r
7238 { IDM_StopExamining, MF_BYCOMMAND|MF_GRAYED },
\r
7239 { IDM_StopObserving, MF_BYCOMMAND|MF_GRAYED },
\r
7240 { IDM_Revert, MF_BYCOMMAND|MF_GRAYED },
\r
7241 { IDM_NewChat, MF_BYCOMMAND|MF_GRAYED },
\r
7245 Enables icsEnables[] = {
\r
7246 { IDM_MailMove, MF_BYCOMMAND|MF_GRAYED },
\r
7247 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_GRAYED },
\r
7248 { IDM_MachineWhite, MF_BYCOMMAND|MF_GRAYED },
\r
7249 { IDM_MachineBlack, MF_BYCOMMAND|MF_GRAYED },
\r
7250 { IDM_TwoMachines, MF_BYCOMMAND|MF_GRAYED },
\r
7251 { IDM_MachineBoth, MF_BYCOMMAND|MF_GRAYED },
\r
7252 { IDM_AnalysisMode, MF_BYCOMMAND|MF_ENABLED },
\r
7253 { IDM_AnalyzeFile, MF_BYCOMMAND|MF_GRAYED },
\r
7254 { IDM_TimeControl, MF_BYCOMMAND|MF_GRAYED },
\r
7255 { IDM_MoveNow, MF_BYCOMMAND|MF_GRAYED },
\r
7256 { IDM_Hint, MF_BYCOMMAND|MF_GRAYED },
\r
7257 { IDM_Book, MF_BYCOMMAND|MF_GRAYED },
\r
7258 { IDM_IcsOptions, MF_BYCOMMAND|MF_ENABLED },
\r
7259 { IDM_Engine1Options, MF_BYCOMMAND|MF_GRAYED },
\r
7260 { IDM_Engine2Options, MF_BYCOMMAND|MF_GRAYED },
\r
7265 Enables zippyEnables[] = {
\r
7266 { IDM_MoveNow, MF_BYCOMMAND|MF_ENABLED },
\r
7267 { IDM_Hint, MF_BYCOMMAND|MF_ENABLED },
\r
7268 { IDM_Book, MF_BYCOMMAND|MF_ENABLED },
\r
7269 { IDM_Engine1Options, MF_BYCOMMAND|MF_ENABLED },
\r
7274 Enables ncpEnables[] = {
\r
7275 { IDM_MailMove, MF_BYCOMMAND|MF_GRAYED },
\r
7276 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_GRAYED },
\r
7277 { IDM_MachineWhite, MF_BYCOMMAND|MF_GRAYED },
\r
7278 { IDM_MachineBlack, MF_BYCOMMAND|MF_GRAYED },
\r
7279 { IDM_TwoMachines, MF_BYCOMMAND|MF_GRAYED },
\r
7280 { IDM_AnalysisMode, MF_BYCOMMAND|MF_GRAYED },
\r
7281 { IDM_AnalyzeFile, MF_BYCOMMAND|MF_GRAYED },
\r
7282 { IDM_IcsClient, MF_BYCOMMAND|MF_GRAYED },
\r
7283 { ACTION_POS, MF_BYPOSITION|MF_GRAYED },
\r
7284 { IDM_Revert, MF_BYCOMMAND|MF_GRAYED },
\r
7285 { IDM_MoveNow, MF_BYCOMMAND|MF_GRAYED },
\r
7286 { IDM_RetractMove, MF_BYCOMMAND|MF_GRAYED },
\r
7287 { IDM_TimeControl, MF_BYCOMMAND|MF_GRAYED },
\r
7288 { IDM_Hint, MF_BYCOMMAND|MF_GRAYED },
\r
7289 { IDM_Book, MF_BYCOMMAND|MF_GRAYED },
\r
7290 { IDM_MachineBoth, MF_BYCOMMAND|MF_GRAYED },
\r
7291 { IDM_NewChat, MF_BYCOMMAND|MF_GRAYED },
\r
7292 { IDM_Engine1Options, MF_BYCOMMAND|MF_GRAYED },
\r
7293 { IDM_Engine2Options, MF_BYCOMMAND|MF_GRAYED },
\r
7297 Enables trainingOnEnables[] = {
\r
7298 { IDM_EditComment, MF_BYCOMMAND|MF_GRAYED },
\r
7299 { IDM_Pause, MF_BYCOMMAND|MF_GRAYED },
\r
7300 { IDM_Forward, MF_BYCOMMAND|MF_GRAYED },
\r
7301 { IDM_Backward, MF_BYCOMMAND|MF_GRAYED },
\r
7302 { IDM_ToEnd, MF_BYCOMMAND|MF_GRAYED },
\r
7303 { IDM_ToStart, MF_BYCOMMAND|MF_GRAYED },
\r
7304 { IDM_MoveNow, MF_BYCOMMAND|MF_GRAYED },
\r
7305 { IDM_TruncateGame, MF_BYCOMMAND|MF_GRAYED },
\r
7309 Enables trainingOffEnables[] = {
\r
7310 { IDM_EditComment, MF_BYCOMMAND|MF_ENABLED },
\r
7311 { IDM_Pause, MF_BYCOMMAND|MF_ENABLED },
\r
7312 { IDM_Forward, MF_BYCOMMAND|MF_ENABLED },
\r
7313 { IDM_Backward, MF_BYCOMMAND|MF_ENABLED },
\r
7314 { IDM_ToEnd, MF_BYCOMMAND|MF_ENABLED },
\r
7315 { IDM_ToStart, MF_BYCOMMAND|MF_ENABLED },
\r
7316 { IDM_MoveNow, MF_BYCOMMAND|MF_ENABLED },
\r
7317 { IDM_TruncateGame, MF_BYCOMMAND|MF_ENABLED },
\r
7321 /* These modify either ncpEnables or gnuEnables */
\r
7322 Enables cmailEnables[] = {
\r
7323 { IDM_MailMove, MF_BYCOMMAND|MF_ENABLED },
\r
7324 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_ENABLED },
\r
7325 { ACTION_POS, MF_BYPOSITION|MF_ENABLED },
\r
7326 { IDM_CallFlag, MF_BYCOMMAND|MF_GRAYED },
\r
7327 { IDM_Draw, MF_BYCOMMAND|MF_ENABLED },
\r
7328 { IDM_Adjourn, MF_BYCOMMAND|MF_GRAYED },
\r
7329 { IDM_Abort, MF_BYCOMMAND|MF_GRAYED },
\r
7333 Enables machineThinkingEnables[] = {
\r
7334 { IDM_LoadGame, MF_BYCOMMAND|MF_GRAYED },
\r
7335 { IDM_LoadNextGame, MF_BYCOMMAND|MF_GRAYED },
\r
7336 { IDM_LoadPrevGame, MF_BYCOMMAND|MF_GRAYED },
\r
7337 { IDM_ReloadGame, MF_BYCOMMAND|MF_GRAYED },
\r
7338 { IDM_PasteGame, MF_BYCOMMAND|MF_GRAYED },
\r
7339 { IDM_LoadPosition, MF_BYCOMMAND|MF_GRAYED },
\r
7340 { IDM_LoadNextPosition, MF_BYCOMMAND|MF_GRAYED },
\r
7341 { IDM_LoadPrevPosition, MF_BYCOMMAND|MF_GRAYED },
\r
7342 { IDM_ReloadPosition, MF_BYCOMMAND|MF_GRAYED },
\r
7343 { IDM_PastePosition, MF_BYCOMMAND|MF_GRAYED },
\r
7344 { IDM_MachineWhite, MF_BYCOMMAND|MF_GRAYED },
\r
7345 { IDM_MachineBlack, MF_BYCOMMAND|MF_GRAYED },
\r
7346 { IDM_TwoMachines, MF_BYCOMMAND|MF_GRAYED },
\r
7347 { IDM_TypeInMove, MF_BYCOMMAND|MF_GRAYED },
\r
7348 { IDM_RetractMove, MF_BYCOMMAND|MF_GRAYED },
\r
7352 Enables userThinkingEnables[] = {
\r
7353 { IDM_LoadGame, MF_BYCOMMAND|MF_ENABLED },
\r
7354 { IDM_LoadNextGame, MF_BYCOMMAND|MF_ENABLED },
\r
7355 { IDM_LoadPrevGame, MF_BYCOMMAND|MF_ENABLED },
\r
7356 { IDM_ReloadGame, MF_BYCOMMAND|MF_ENABLED },
\r
7357 { IDM_PasteGame, MF_BYCOMMAND|MF_ENABLED },
\r
7358 { IDM_LoadPosition, MF_BYCOMMAND|MF_ENABLED },
\r
7359 { IDM_LoadNextPosition, MF_BYCOMMAND|MF_ENABLED },
\r
7360 { IDM_LoadPrevPosition, MF_BYCOMMAND|MF_ENABLED },
\r
7361 { IDM_ReloadPosition, MF_BYCOMMAND|MF_ENABLED },
\r
7362 { IDM_PastePosition, MF_BYCOMMAND|MF_ENABLED },
\r
7363 { IDM_MachineWhite, MF_BYCOMMAND|MF_ENABLED },
\r
7364 { IDM_MachineBlack, MF_BYCOMMAND|MF_ENABLED },
\r
7365 { IDM_TwoMachines, MF_BYCOMMAND|MF_ENABLED },
\r
7366 { IDM_TypeInMove, MF_BYCOMMAND|MF_ENABLED },
\r
7367 { IDM_RetractMove, MF_BYCOMMAND|MF_ENABLED },
\r
7371 /*---------------------------------------------------------------------------*\
\r
7373 * Front-end interface functions exported by XBoard.
\r
7374 * Functions appear in same order as prototypes in frontend.h.
\r
7376 \*---------------------------------------------------------------------------*/
\r
7380 static UINT prevChecked = 0;
\r
7381 static int prevPausing = 0;
\r
7384 if (pausing != prevPausing) {
\r
7385 prevPausing = pausing;
\r
7386 (void) CheckMenuItem(GetMenu(hwndMain), IDM_Pause,
\r
7387 MF_BYCOMMAND|(pausing ? MF_CHECKED : MF_UNCHECKED));
\r
7388 if (hwndPause) SetWindowText(hwndPause, pausing ? "C" : "P");
\r
7391 switch (gameMode) {
\r
7392 case BeginningOfGame:
\r
7393 if (appData.icsActive)
\r
7394 nowChecked = IDM_IcsClient;
\r
7395 else if (appData.noChessProgram)
\r
7396 nowChecked = IDM_EditGame;
\r
7398 nowChecked = IDM_MachineBlack;
\r
7400 case MachinePlaysBlack:
\r
7401 nowChecked = IDM_MachineBlack;
\r
7403 case MachinePlaysWhite:
\r
7404 nowChecked = IDM_MachineWhite;
\r
7406 case TwoMachinesPlay:
\r
7407 nowChecked = IDM_TwoMachines;
\r
7410 nowChecked = IDM_AnalysisMode;
\r
7413 nowChecked = IDM_AnalyzeFile;
\r
7416 nowChecked = IDM_EditGame;
\r
7418 case PlayFromGameFile:
\r
7419 nowChecked = IDM_LoadGame;
\r
7421 case EditPosition:
\r
7422 nowChecked = IDM_EditPosition;
\r
7425 nowChecked = IDM_Training;
\r
7427 case IcsPlayingWhite:
\r
7428 case IcsPlayingBlack:
\r
7429 case IcsObserving:
\r
7431 nowChecked = IDM_IcsClient;
\r
7438 if (prevChecked != 0)
\r
7439 (void) CheckMenuItem(GetMenu(hwndMain),
\r
7440 prevChecked, MF_BYCOMMAND|MF_UNCHECKED);
\r
7441 if (nowChecked != 0)
\r
7442 (void) CheckMenuItem(GetMenu(hwndMain),
\r
7443 nowChecked, MF_BYCOMMAND|MF_CHECKED);
\r
7445 if (nowChecked == IDM_LoadGame || nowChecked == IDM_Training) {
\r
7446 (void) EnableMenuItem(GetMenu(hwndMain), IDM_Training,
\r
7447 MF_BYCOMMAND|MF_ENABLED);
\r
7449 (void) EnableMenuItem(GetMenu(hwndMain),
\r
7450 IDM_Training, MF_BYCOMMAND|MF_GRAYED);
\r
7453 prevChecked = nowChecked;
\r
7455 /* [DM] icsEngineAnalyze - Do a sceure check too */
\r
7456 if (appData.icsActive) {
\r
7457 if (appData.icsEngineAnalyze) {
\r
7458 (void) CheckMenuItem(GetMenu(hwndMain), IDM_AnalysisMode,
\r
7459 MF_BYCOMMAND|MF_CHECKED);
\r
7461 (void) CheckMenuItem(GetMenu(hwndMain), IDM_AnalysisMode,
\r
7462 MF_BYCOMMAND|MF_UNCHECKED);
\r
7470 HMENU hmenu = GetMenu(hwndMain);
\r
7471 SetMenuEnables(hmenu, icsEnables);
\r
7472 EnableMenuItem(GetSubMenu(hmenu, OPTIONS_POS), ICS_POS,
\r
7473 MF_BYPOSITION|MF_ENABLED);
\r
7475 if (appData.zippyPlay) {
\r
7476 SetMenuEnables(hmenu, zippyEnables);
\r
7477 if (!appData.noChessProgram) /* [DM] icsEngineAnalyze */
\r
7478 (void) EnableMenuItem(GetMenu(hwndMain), IDM_AnalysisMode,
\r
7479 MF_BYCOMMAND|MF_ENABLED);
\r
7487 SetMenuEnables(GetMenu(hwndMain), gnuEnables);
\r
7493 HMENU hmenu = GetMenu(hwndMain);
\r
7494 SetMenuEnables(hmenu, ncpEnables);
\r
7495 EnableMenuItem(GetSubMenu(hmenu, OPTIONS_POS), SOUNDS_POS,
\r
7496 MF_BYPOSITION|MF_GRAYED);
\r
7497 DrawMenuBar(hwndMain);
\r
7503 SetMenuEnables(GetMenu(hwndMain), cmailEnables);
\r
7507 SetTrainingModeOn()
\r
7510 SetMenuEnables(GetMenu(hwndMain), trainingOnEnables);
\r
7511 for (i = 0; i < N_BUTTONS; i++) {
\r
7512 if (buttonDesc[i].hwnd != NULL)
\r
7513 EnableWindow(buttonDesc[i].hwnd, FALSE);
\r
7518 VOID SetTrainingModeOff()
\r
7521 SetMenuEnables(GetMenu(hwndMain), trainingOffEnables);
\r
7522 for (i = 0; i < N_BUTTONS; i++) {
\r
7523 if (buttonDesc[i].hwnd != NULL)
\r
7524 EnableWindow(buttonDesc[i].hwnd, TRUE);
\r
7530 SetUserThinkingEnables()
\r
7532 SetMenuEnables(GetMenu(hwndMain), userThinkingEnables);
\r
7536 SetMachineThinkingEnables()
\r
7538 HMENU hMenu = GetMenu(hwndMain);
\r
7539 int flags = MF_BYCOMMAND|MF_ENABLED;
\r
7541 SetMenuEnables(hMenu, machineThinkingEnables);
\r
7543 if (gameMode == MachinePlaysBlack) {
\r
7544 (void)EnableMenuItem(hMenu, IDM_MachineBlack, flags);
\r
7545 } else if (gameMode == MachinePlaysWhite) {
\r
7546 (void)EnableMenuItem(hMenu, IDM_MachineWhite, flags);
\r
7547 } else if (gameMode == TwoMachinesPlay) {
\r
7548 (void)EnableMenuItem(hMenu, IDM_TwoMachines, flags);
\r
7554 DisplayTitle(char *str)
\r
7556 char title[MSG_SIZ], *host;
\r
7557 if (str[0] != NULLCHAR) {
\r
7558 strcpy(title, str);
\r
7559 } else if (appData.icsActive) {
\r
7560 if (appData.icsCommPort[0] != NULLCHAR)
\r
7563 host = appData.icsHost;
\r
7564 sprintf(title, "%s: %s", szTitle, host);
\r
7565 } else if (appData.noChessProgram) {
\r
7566 strcpy(title, szTitle);
\r
7568 strcpy(title, szTitle);
\r
7569 strcat(title, ": ");
\r
7570 strcat(title, first.tidy);
\r
7572 SetWindowText(hwndMain, title);
\r
7577 DisplayMessage(char *str1, char *str2)
\r
7581 int remain = MESSAGE_TEXT_MAX - 1;
\r
7584 moveErrorMessageUp = FALSE; /* turned on later by caller if needed */
\r
7585 messageText[0] = NULLCHAR;
\r
7587 len = strlen(str1);
\r
7588 if (len > remain) len = remain;
\r
7589 strncpy(messageText, str1, len);
\r
7590 messageText[len] = NULLCHAR;
\r
7593 if (*str2 && remain >= 2) {
\r
7595 strcat(messageText, " ");
\r
7598 len = strlen(str2);
\r
7599 if (len > remain) len = remain;
\r
7600 strncat(messageText, str2, len);
\r
7602 messageText[MESSAGE_TEXT_MAX - 1] = NULLCHAR;
\r
7604 if (hwndMain == NULL || IsIconic(hwndMain)) return;
\r
7608 hdc = GetDC(hwndMain);
\r
7609 oldFont = SelectObject(hdc, font[boardSize][MESSAGE_FONT]->hf);
\r
7610 ExtTextOut(hdc, messageRect.left, messageRect.top, ETO_CLIPPED|ETO_OPAQUE,
\r
7611 &messageRect, messageText, strlen(messageText), NULL);
\r
7612 (void) SelectObject(hdc, oldFont);
\r
7613 (void) ReleaseDC(hwndMain, hdc);
\r
7617 DisplayError(char *str, int error)
\r
7619 char buf[MSG_SIZ*2], buf2[MSG_SIZ];
\r
7625 len = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
\r
7626 NULL, error, LANG_NEUTRAL,
\r
7627 (LPSTR) buf2, MSG_SIZ, NULL);
\r
7629 sprintf(buf, "%s:\n%s", str, buf2);
\r
7631 ErrorMap *em = errmap;
\r
7632 while (em->err != 0 && em->err != error) em++;
\r
7633 if (em->err != 0) {
\r
7634 sprintf(buf, "%s:\n%s", str, em->msg);
\r
7636 sprintf(buf, "%s:\nError code %d", str, error);
\r
7641 ErrorPopUp("Error", buf);
\r
7646 DisplayMoveError(char *str)
\r
7648 fromX = fromY = -1;
\r
7649 ClearHighlights();
\r
7650 DrawPosition(FALSE, NULL);
\r
7651 if (appData.popupMoveErrors) {
\r
7652 ErrorPopUp("Error", str);
\r
7654 DisplayMessage(str, "");
\r
7655 moveErrorMessageUp = TRUE;
\r
7660 DisplayFatalError(char *str, int error, int exitStatus)
\r
7662 char buf[2*MSG_SIZ], buf2[MSG_SIZ];
\r
7664 char *label = exitStatus ? "Fatal Error" : "Exiting";
\r
7667 len = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
\r
7668 NULL, error, LANG_NEUTRAL,
\r
7669 (LPSTR) buf2, MSG_SIZ, NULL);
\r
7671 sprintf(buf, "%s:\n%s", str, buf2);
\r
7673 ErrorMap *em = errmap;
\r
7674 while (em->err != 0 && em->err != error) em++;
\r
7675 if (em->err != 0) {
\r
7676 sprintf(buf, "%s:\n%s", str, em->msg);
\r
7678 sprintf(buf, "%s:\nError code %d", str, error);
\r
7683 if (appData.debugMode) {
\r
7684 fprintf(debugFP, "%s: %s\n", label, str);
\r
7686 if (appData.popupExitMessage) {
\r
7687 (void) MessageBox(hwndMain, str, label, MB_OK|
\r
7688 (exitStatus ? MB_ICONSTOP : MB_ICONINFORMATION));
\r
7690 ExitEvent(exitStatus);
\r
7695 DisplayInformation(char *str)
\r
7697 (void) MessageBox(hwndMain, str, "Information", MB_OK|MB_ICONINFORMATION);
\r
7702 DisplayNote(char *str)
\r
7704 ErrorPopUp("Note", str);
\r
7709 char *title, *question, *replyPrefix;
\r
7714 QuestionDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7716 static QuestionParams *qp;
\r
7717 char reply[MSG_SIZ];
\r
7720 switch (message) {
\r
7721 case WM_INITDIALOG:
\r
7722 qp = (QuestionParams *) lParam;
\r
7723 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
7724 SetWindowText(hDlg, qp->title);
\r
7725 SetDlgItemText(hDlg, OPT_QuestionText, qp->question);
\r
7726 SetFocus(GetDlgItem(hDlg, OPT_QuestionInput));
\r
7730 switch (LOWORD(wParam)) {
\r
7732 strcpy(reply, qp->replyPrefix);
\r
7733 if (*reply) strcat(reply, " ");
\r
7734 len = strlen(reply);
\r
7735 GetDlgItemText(hDlg, OPT_QuestionInput, reply + len, sizeof(reply) - len);
\r
7736 strcat(reply, "\n");
\r
7737 OutputToProcess(qp->pr, reply, strlen(reply), &err);
\r
7738 EndDialog(hDlg, TRUE);
\r
7739 if (err) DisplayFatalError("Error writing to chess program", err, 1);
\r
7742 EndDialog(hDlg, FALSE);
\r
7753 AskQuestion(char* title, char *question, char *replyPrefix, ProcRef pr)
\r
7755 QuestionParams qp;
\r
7759 qp.question = question;
\r
7760 qp.replyPrefix = replyPrefix;
\r
7762 lpProc = MakeProcInstance((FARPROC)QuestionDialog, hInst);
\r
7763 DialogBoxParam(hInst, MAKEINTRESOURCE(DLG_Question),
\r
7764 hwndMain, (DLGPROC)lpProc, (LPARAM)&qp);
\r
7765 FreeProcInstance(lpProc);
\r
7768 /* [AS] Pick FRC position */
\r
7769 LRESULT CALLBACK NewGameFRC_Proc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7771 static int * lpIndexFRC;
\r
7777 case WM_INITDIALOG:
\r
7778 lpIndexFRC = (int *) lParam;
\r
7780 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
7782 SendDlgItemMessage( hDlg, IDC_NFG_Edit, EM_SETLIMITTEXT, sizeof(buf)-1, 0 );
\r
7783 SetDlgItemInt( hDlg, IDC_NFG_Edit, *lpIndexFRC, TRUE );
\r
7784 SendDlgItemMessage( hDlg, IDC_NFG_Edit, EM_SETSEL, 0, -1 );
\r
7785 SetFocus(GetDlgItem(hDlg, IDC_NFG_Edit));
\r
7790 switch( LOWORD(wParam) ) {
\r
7792 *lpIndexFRC = GetDlgItemInt(hDlg, IDC_NFG_Edit, &index_is_ok, TRUE );
\r
7793 EndDialog( hDlg, 0 );
\r
7794 shuffleOpenings = TRUE; /* [HGM] shuffle: switch shuffling on for as long as we stay in current variant */
\r
7797 EndDialog( hDlg, 1 );
\r
7799 case IDC_NFG_Edit:
\r
7800 if( HIWORD(wParam) == EN_CHANGE ) {
\r
7801 GetDlgItemInt(hDlg, IDC_NFG_Edit, &index_is_ok, TRUE );
\r
7803 EnableWindow( GetDlgItem(hDlg, IDOK), index_is_ok );
\r
7806 case IDC_NFG_Random:
\r
7807 sprintf( buf, "%d", myrandom() ); /* [HGM] shuffle: no longer limit to 960 */
\r
7808 SetDlgItemText(hDlg, IDC_NFG_Edit, buf );
\r
7821 int index = appData.defaultFrcPosition;
\r
7822 FARPROC lpProc = MakeProcInstance( (FARPROC) NewGameFRC_Proc, hInst );
\r
7824 result = DialogBoxParam( hInst, MAKEINTRESOURCE(DLG_NewGameFRC), hwndMain, (DLGPROC)lpProc, (LPARAM)&index );
\r
7826 if( result == 0 ) {
\r
7827 appData.defaultFrcPosition = index;
\r
7833 /* [AS] Game list options */
\r
7839 static GLT_Item GLT_ItemInfo[] = {
\r
7840 { GLT_EVENT, "Event" },
\r
7841 { GLT_SITE, "Site" },
\r
7842 { GLT_DATE, "Date" },
\r
7843 { GLT_ROUND, "Round" },
\r
7844 { GLT_PLAYERS, "Players" },
\r
7845 { GLT_RESULT, "Result" },
\r
7846 { GLT_WHITE_ELO, "White Rating" },
\r
7847 { GLT_BLACK_ELO, "Black Rating" },
\r
7848 { GLT_TIME_CONTROL,"Time Control" },
\r
7849 { GLT_VARIANT, "Variant" },
\r
7850 { GLT_OUT_OF_BOOK,PGN_OUT_OF_BOOK },
\r
7851 { GLT_RESULT_COMMENT, "Result Comment" }, // [HGM] rescom
\r
7855 const char * GLT_FindItem( char id )
\r
7857 const char * result = 0;
\r
7859 GLT_Item * list = GLT_ItemInfo;
\r
7861 while( list->id != 0 ) {
\r
7862 if( list->id == id ) {
\r
7863 result = list->name;
\r
7873 void GLT_AddToList( HWND hDlg, int iDlgItem, char id, int index )
\r
7875 const char * name = GLT_FindItem( id );
\r
7878 if( index >= 0 ) {
\r
7879 SendDlgItemMessage( hDlg, iDlgItem, LB_INSERTSTRING, index, (LPARAM) name );
\r
7882 SendDlgItemMessage( hDlg, iDlgItem, LB_ADDSTRING, 0, (LPARAM) name );
\r
7887 void GLT_TagsToList( HWND hDlg, char * tags )
\r
7891 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_RESETCONTENT, 0, 0 );
\r
7894 GLT_AddToList( hDlg, IDC_GameListTags, *pc, -1 );
\r
7898 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_ADDSTRING, 0, (LPARAM) "\t --- Hidden tags ---" );
\r
7900 pc = GLT_ALL_TAGS;
\r
7903 if( strchr( tags, *pc ) == 0 ) {
\r
7904 GLT_AddToList( hDlg, IDC_GameListTags, *pc, -1 );
\r
7909 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_SETCURSEL, 0, 0 );
\r
7912 char GLT_ListItemToTag( HWND hDlg, int index )
\r
7914 char result = '\0';
\r
7917 GLT_Item * list = GLT_ItemInfo;
\r
7919 if( SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETTEXT, index, (LPARAM) name ) != LB_ERR ) {
\r
7920 while( list->id != 0 ) {
\r
7921 if( strcmp( list->name, name ) == 0 ) {
\r
7922 result = list->id;
\r
7933 void GLT_MoveSelection( HWND hDlg, int delta )
\r
7935 int idx1 = (int) SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETCURSEL, 0, 0 );
\r
7936 int idx2 = idx1 + delta;
\r
7937 int count = (int) SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETCOUNT, 0, 0 );
\r
7939 if( idx1 >=0 && idx1 < count && idx2 >= 0 && idx2 < count ) {
\r
7942 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETTEXT, idx1, (LPARAM) buf );
\r
7943 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_DELETESTRING, idx1, 0 );
\r
7944 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_INSERTSTRING, idx2, (LPARAM) buf );
\r
7945 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_SETCURSEL, idx2, 0 );
\r
7949 LRESULT CALLBACK GameListOptions_Proc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7951 static char glt[64];
\r
7952 static char * lpUserGLT;
\r
7956 case WM_INITDIALOG:
\r
7957 lpUserGLT = (char *) lParam;
\r
7959 strcpy( glt, lpUserGLT );
\r
7961 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
7963 /* Initialize list */
\r
7964 GLT_TagsToList( hDlg, glt );
\r
7966 SetFocus( GetDlgItem(hDlg, IDC_GameListTags) );
\r
7971 switch( LOWORD(wParam) ) {
\r
7974 char * pc = lpUserGLT;
\r
7976 // int cnt = (int) SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETCOUNT, 0, 0 );
\r
7980 id = GLT_ListItemToTag( hDlg, idx );
\r
7984 } while( id != '\0' );
\r
7986 EndDialog( hDlg, 0 );
\r
7989 EndDialog( hDlg, 1 );
\r
7992 case IDC_GLT_Default:
\r
7993 strcpy( glt, GLT_DEFAULT_TAGS );
\r
7994 GLT_TagsToList( hDlg, glt );
\r
7997 case IDC_GLT_Restore:
\r
7998 strcpy( glt, lpUserGLT );
\r
7999 GLT_TagsToList( hDlg, glt );
\r
8003 GLT_MoveSelection( hDlg, -1 );
\r
8006 case IDC_GLT_Down:
\r
8007 GLT_MoveSelection( hDlg, +1 );
\r
8017 int GameListOptions()
\r
8021 FARPROC lpProc = MakeProcInstance( (FARPROC) GameListOptions_Proc, hInst );
\r
8023 strcpy( glt, appData.gameListTags );
\r
8025 result = DialogBoxParam( hInst, MAKEINTRESOURCE(DLG_GameListOptions), hwndMain, (DLGPROC)lpProc, (LPARAM)glt );
\r
8027 if( result == 0 ) {
\r
8028 /* [AS] Memory leak here! */
\r
8029 appData.gameListTags = strdup( glt );
\r
8037 DisplayIcsInteractionTitle(char *str)
\r
8039 char consoleTitle[MSG_SIZ];
\r
8041 sprintf(consoleTitle, "%s: %s", szConsoleTitle, str);
\r
8042 SetWindowText(hwndConsole, consoleTitle);
\r
8046 DrawPosition(int fullRedraw, Board board)
\r
8048 HDCDrawPosition(NULL, (BOOLEAN) fullRedraw, board);
\r
8051 void NotifyFrontendLogin()
\r
8054 UpdateICSWidth(GetDlgItem(hwndConsole, OPT_ConsoleText));
\r
8060 fromX = fromY = -1;
\r
8061 if (dragInfo.pos.x != -1 || dragInfo.pos.y != -1) {
\r
8062 dragInfo.pos.x = dragInfo.pos.y = -1;
\r
8063 dragInfo.pos.x = dragInfo.pos.y = -1;
\r
8064 dragInfo.lastpos = dragInfo.pos;
\r
8065 dragInfo.start.x = dragInfo.start.y = -1;
\r
8066 dragInfo.from = dragInfo.start;
\r
8068 DrawPosition(TRUE, NULL);
\r
8074 CommentPopUp(char *title, char *str)
\r
8076 HWND hwnd = GetActiveWindow();
\r
8077 EitherCommentPopUp(0, title, str, FALSE);
\r
8079 SetActiveWindow(hwnd);
\r
8083 CommentPopDown(void)
\r
8085 CheckMenuItem(GetMenu(hwndMain), IDM_EditComment, MF_UNCHECKED);
\r
8086 if (commentDialog) {
\r
8087 ShowWindow(commentDialog, SW_HIDE);
\r
8089 commentUp = FALSE;
\r
8093 EditCommentPopUp(int index, char *title, char *str)
\r
8095 EitherCommentPopUp(index, title, str, TRUE);
\r
8102 MyPlaySound(&sounds[(int)SoundMove]);
\r
8105 VOID PlayIcsWinSound()
\r
8107 MyPlaySound(&sounds[(int)SoundIcsWin]);
\r
8110 VOID PlayIcsLossSound()
\r
8112 MyPlaySound(&sounds[(int)SoundIcsLoss]);
\r
8115 VOID PlayIcsDrawSound()
\r
8117 MyPlaySound(&sounds[(int)SoundIcsDraw]);
\r
8120 VOID PlayIcsUnfinishedSound()
\r
8122 MyPlaySound(&sounds[(int)SoundIcsUnfinished]);
\r
8128 MyPlaySound(&sounds[(int)SoundAlarm]);
\r
8136 consoleEcho = TRUE;
\r
8137 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
8138 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&consoleCF);
\r
8139 SendMessage(hInput, EM_SETBKGNDCOLOR, FALSE, consoleBackgroundColor);
\r
8148 consoleEcho = FALSE;
\r
8149 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
8150 /* This works OK: set text and background both to the same color */
\r
8152 cf.crTextColor = COLOR_ECHOOFF;
\r
8153 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&cf);
\r
8154 SendMessage(hInput, EM_SETBKGNDCOLOR, FALSE, cf.crTextColor);
\r
8157 /* No Raw()...? */
\r
8159 void Colorize(ColorClass cc, int continuation)
\r
8161 currentColorClass = cc;
\r
8162 consoleCF.dwMask = CFM_COLOR|CFM_BOLD|CFM_ITALIC|CFM_UNDERLINE|CFM_STRIKEOUT;
\r
8163 consoleCF.crTextColor = textAttribs[cc].color;
\r
8164 consoleCF.dwEffects = textAttribs[cc].effects;
\r
8165 if (!continuation) MyPlaySound(&textAttribs[cc].sound);
\r
8171 static char buf[MSG_SIZ];
\r
8172 DWORD bufsiz = MSG_SIZ;
\r
8174 if(appData.userName != NULL && appData.userName[0] != 0) {
\r
8175 return appData.userName; /* [HGM] username: prefer name selected by user over his system login */
\r
8177 if (!GetUserName(buf, &bufsiz)) {
\r
8178 /*DisplayError("Error getting user name", GetLastError());*/
\r
8179 strcpy(buf, "User");
\r
8187 static char buf[MSG_SIZ];
\r
8188 DWORD bufsiz = MSG_SIZ;
\r
8190 if (!GetComputerName(buf, &bufsiz)) {
\r
8191 /*DisplayError("Error getting host name", GetLastError());*/
\r
8192 strcpy(buf, "Unknown");
\r
8199 ClockTimerRunning()
\r
8201 return clockTimerEvent != 0;
\r
8207 if (clockTimerEvent == 0) return FALSE;
\r
8208 KillTimer(hwndMain, clockTimerEvent);
\r
8209 clockTimerEvent = 0;
\r
8214 StartClockTimer(long millisec)
\r
8216 clockTimerEvent = SetTimer(hwndMain, (UINT) CLOCK_TIMER_ID,
\r
8217 (UINT) millisec, NULL);
\r
8221 DisplayWhiteClock(long timeRemaining, int highlight)
\r
8224 char *flag = whiteFlag && gameMode == TwoMachinesPlay ? "(!)" : "";
\r
8226 if(appData.noGUI) return;
\r
8227 hdc = GetDC(hwndMain);
\r
8228 if (!IsIconic(hwndMain)) {
\r
8229 DisplayAClock(hdc, timeRemaining, highlight,
\r
8230 flipClock ? &blackRect : &whiteRect, "White", flag);
\r
8232 if (highlight && iconCurrent == iconBlack) {
\r
8233 iconCurrent = iconWhite;
\r
8234 PostMessage(hwndMain, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
8235 if (IsIconic(hwndMain)) {
\r
8236 DrawIcon(hdc, 2, 2, iconCurrent);
\r
8239 (void) ReleaseDC(hwndMain, hdc);
\r
8241 PostMessage(hwndConsole, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
8245 DisplayBlackClock(long timeRemaining, int highlight)
\r
8248 char *flag = blackFlag && gameMode == TwoMachinesPlay ? "(!)" : "";
\r
8250 if(appData.noGUI) return;
\r
8251 hdc = GetDC(hwndMain);
\r
8252 if (!IsIconic(hwndMain)) {
\r
8253 DisplayAClock(hdc, timeRemaining, highlight,
\r
8254 flipClock ? &whiteRect : &blackRect, "Black", flag);
\r
8256 if (highlight && iconCurrent == iconWhite) {
\r
8257 iconCurrent = iconBlack;
\r
8258 PostMessage(hwndMain, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
8259 if (IsIconic(hwndMain)) {
\r
8260 DrawIcon(hdc, 2, 2, iconCurrent);
\r
8263 (void) ReleaseDC(hwndMain, hdc);
\r
8265 PostMessage(hwndConsole, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
8270 LoadGameTimerRunning()
\r
8272 return loadGameTimerEvent != 0;
\r
8276 StopLoadGameTimer()
\r
8278 if (loadGameTimerEvent == 0) return FALSE;
\r
8279 KillTimer(hwndMain, loadGameTimerEvent);
\r
8280 loadGameTimerEvent = 0;
\r
8285 StartLoadGameTimer(long millisec)
\r
8287 loadGameTimerEvent = SetTimer(hwndMain, (UINT) LOAD_GAME_TIMER_ID,
\r
8288 (UINT) millisec, NULL);
\r
8296 char fileTitle[MSG_SIZ];
\r
8298 defName = DefaultFileName(appData.oldSaveStyle ? "gam" : "pgn");
\r
8299 f = OpenFileDialog(hwndMain, "a", defName,
\r
8300 appData.oldSaveStyle ? "gam" : "pgn",
\r
8302 "Save Game to File", NULL, fileTitle, NULL);
\r
8304 SaveGame(f, 0, "");
\r
8311 ScheduleDelayedEvent(DelayedEventCallback cb, long millisec)
\r
8313 if (delayedTimerEvent != 0) {
\r
8314 if (appData.debugMode && cb != delayedTimerCallback) { // [HGM] alive: not too much debug
\r
8315 fprintf(debugFP, "ScheduleDelayedEvent: event already scheduled\n");
\r
8317 KillTimer(hwndMain, delayedTimerEvent);
\r
8318 delayedTimerEvent = 0;
\r
8319 if(delayedTimerCallback != cb) // [HGM] alive: do not "flush" same event, just postpone it
\r
8320 delayedTimerCallback();
\r
8322 delayedTimerCallback = cb;
\r
8323 delayedTimerEvent = SetTimer(hwndMain, (UINT) DELAYED_TIMER_ID,
\r
8324 (UINT) millisec, NULL);
\r
8327 DelayedEventCallback
\r
8330 if (delayedTimerEvent) {
\r
8331 return delayedTimerCallback;
\r
8338 CancelDelayedEvent()
\r
8340 if (delayedTimerEvent) {
\r
8341 KillTimer(hwndMain, delayedTimerEvent);
\r
8342 delayedTimerEvent = 0;
\r
8346 DWORD GetWin32Priority(int nice)
\r
8347 { // [HGM] nice: translate Unix nice() value to indows priority class. (Code stolen from Polyglot 1.4w11)
\r
8349 REALTIME_PRIORITY_CLASS 0x00000100
\r
8350 HIGH_PRIORITY_CLASS 0x00000080
\r
8351 ABOVE_NORMAL_PRIORITY_CLASS 0x00008000
\r
8352 NORMAL_PRIORITY_CLASS 0x00000020
\r
8353 BELOW_NORMAL_PRIORITY_CLASS 0x00004000
\r
8354 IDLE_PRIORITY_CLASS 0x00000040
\r
8356 if (nice < -15) return 0x00000080;
\r
8357 if (nice < 0) return 0x00008000;
\r
8358 if (nice == 0) return 0x00000020;
\r
8359 if (nice < 15) return 0x00004000;
\r
8360 return 0x00000040;
\r
8363 /* Start a child process running the given program.
\r
8364 The process's standard output can be read from "from", and its
\r
8365 standard input can be written to "to".
\r
8366 Exit with fatal error if anything goes wrong.
\r
8367 Returns an opaque pointer that can be used to destroy the process
\r
8371 StartChildProcess(char *cmdLine, char *dir, ProcRef *pr)
\r
8373 #define BUFSIZE 4096
\r
8375 HANDLE hChildStdinRd, hChildStdinWr,
\r
8376 hChildStdoutRd, hChildStdoutWr;
\r
8377 HANDLE hChildStdinWrDup, hChildStdoutRdDup;
\r
8378 SECURITY_ATTRIBUTES saAttr;
\r
8380 PROCESS_INFORMATION piProcInfo;
\r
8381 STARTUPINFO siStartInfo;
\r
8383 char buf[MSG_SIZ];
\r
8386 if (appData.debugMode) {
\r
8387 fprintf(debugFP, "StartChildProcess (dir=\"%s\") %s\n", dir, cmdLine);
\r
8392 /* Set the bInheritHandle flag so pipe handles are inherited. */
\r
8393 saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
\r
8394 saAttr.bInheritHandle = TRUE;
\r
8395 saAttr.lpSecurityDescriptor = NULL;
\r
8398 * The steps for redirecting child's STDOUT:
\r
8399 * 1. Create anonymous pipe to be STDOUT for child.
\r
8400 * 2. Create a noninheritable duplicate of read handle,
\r
8401 * and close the inheritable read handle.
\r
8404 /* Create a pipe for the child's STDOUT. */
\r
8405 if (! CreatePipe(&hChildStdoutRd, &hChildStdoutWr, &saAttr, 0)) {
\r
8406 return GetLastError();
\r
8409 /* Duplicate the read handle to the pipe, so it is not inherited. */
\r
8410 fSuccess = DuplicateHandle(GetCurrentProcess(), hChildStdoutRd,
\r
8411 GetCurrentProcess(), &hChildStdoutRdDup, 0,
\r
8412 FALSE, /* not inherited */
\r
8413 DUPLICATE_SAME_ACCESS);
\r
8415 return GetLastError();
\r
8417 CloseHandle(hChildStdoutRd);
\r
8420 * The steps for redirecting child's STDIN:
\r
8421 * 1. Create anonymous pipe to be STDIN for child.
\r
8422 * 2. Create a noninheritable duplicate of write handle,
\r
8423 * and close the inheritable write handle.
\r
8426 /* Create a pipe for the child's STDIN. */
\r
8427 if (! CreatePipe(&hChildStdinRd, &hChildStdinWr, &saAttr, 0)) {
\r
8428 return GetLastError();
\r
8431 /* Duplicate the write handle to the pipe, so it is not inherited. */
\r
8432 fSuccess = DuplicateHandle(GetCurrentProcess(), hChildStdinWr,
\r
8433 GetCurrentProcess(), &hChildStdinWrDup, 0,
\r
8434 FALSE, /* not inherited */
\r
8435 DUPLICATE_SAME_ACCESS);
\r
8437 return GetLastError();
\r
8439 CloseHandle(hChildStdinWr);
\r
8441 /* Arrange to (1) look in dir for the child .exe file, and
\r
8442 * (2) have dir be the child's working directory. Interpret
\r
8443 * dir relative to the directory WinBoard loaded from. */
\r
8444 GetCurrentDirectory(MSG_SIZ, buf);
\r
8445 SetCurrentDirectory(installDir);
\r
8446 SetCurrentDirectory(dir);
\r
8448 /* Now create the child process. */
\r
8450 siStartInfo.cb = sizeof(STARTUPINFO);
\r
8451 siStartInfo.lpReserved = NULL;
\r
8452 siStartInfo.lpDesktop = NULL;
\r
8453 siStartInfo.lpTitle = NULL;
\r
8454 siStartInfo.dwFlags = STARTF_USESTDHANDLES;
\r
8455 siStartInfo.cbReserved2 = 0;
\r
8456 siStartInfo.lpReserved2 = NULL;
\r
8457 siStartInfo.hStdInput = hChildStdinRd;
\r
8458 siStartInfo.hStdOutput = hChildStdoutWr;
\r
8459 siStartInfo.hStdError = hChildStdoutWr;
\r
8461 fSuccess = CreateProcess(NULL,
\r
8462 cmdLine, /* command line */
\r
8463 NULL, /* process security attributes */
\r
8464 NULL, /* primary thread security attrs */
\r
8465 TRUE, /* handles are inherited */
\r
8466 DETACHED_PROCESS|CREATE_NEW_PROCESS_GROUP,
\r
8467 NULL, /* use parent's environment */
\r
8469 &siStartInfo, /* STARTUPINFO pointer */
\r
8470 &piProcInfo); /* receives PROCESS_INFORMATION */
\r
8472 err = GetLastError();
\r
8473 SetCurrentDirectory(buf); /* return to prev directory */
\r
8478 if (appData.niceEngines){ // [HGM] nice: adjust engine proc priority
\r
8479 if(appData.debugMode) fprintf(debugFP, "nice engine proc to %d\n", appData.niceEngines);
\r
8480 SetPriorityClass(piProcInfo.hProcess, GetWin32Priority(appData.niceEngines));
\r
8483 /* Close the handles we don't need in the parent */
\r
8484 CloseHandle(piProcInfo.hThread);
\r
8485 CloseHandle(hChildStdinRd);
\r
8486 CloseHandle(hChildStdoutWr);
\r
8488 /* Prepare return value */
\r
8489 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
8490 cp->kind = CPReal;
\r
8491 cp->hProcess = piProcInfo.hProcess;
\r
8492 cp->pid = piProcInfo.dwProcessId;
\r
8493 cp->hFrom = hChildStdoutRdDup;
\r
8494 cp->hTo = hChildStdinWrDup;
\r
8496 *pr = (void *) cp;
\r
8498 /* Klaus Friedel says that this Sleep solves a problem under Windows
\r
8499 2000 where engines sometimes don't see the initial command(s)
\r
8500 from WinBoard and hang. I don't understand how that can happen,
\r
8501 but the Sleep is harmless, so I've put it in. Others have also
\r
8502 reported what may be the same problem, so hopefully this will fix
\r
8503 it for them too. */
\r
8511 DestroyChildProcess(ProcRef pr, int/*boolean*/ signal)
\r
8513 ChildProc *cp; int result;
\r
8515 cp = (ChildProc *) pr;
\r
8516 if (cp == NULL) return;
\r
8518 switch (cp->kind) {
\r
8520 /* TerminateProcess is considered harmful, so... */
\r
8521 CloseHandle(cp->hTo); /* Closing this will give the child an EOF and hopefully kill it */
\r
8522 if (cp->hFrom) CloseHandle(cp->hFrom); /* if NULL, InputThread will close it */
\r
8523 /* The following doesn't work because the chess program
\r
8524 doesn't "have the same console" as WinBoard. Maybe
\r
8525 we could arrange for this even though neither WinBoard
\r
8526 nor the chess program uses a console for stdio? */
\r
8527 /*!!if (signal) GenerateConsoleCtrlEvent(CTRL_BREAK_EVENT, cp->pid);*/
\r
8529 /* [AS] Special termination modes for misbehaving programs... */
\r
8530 if( signal == 9 ) {
\r
8531 result = TerminateProcess( cp->hProcess, 0 );
\r
8533 if ( appData.debugMode) {
\r
8534 fprintf( debugFP, "Terminating process %lu, result=%d\n", cp->pid, result );
\r
8537 else if( signal == 10 ) {
\r
8538 DWORD dw = WaitForSingleObject( cp->hProcess, 3*1000 ); // Wait 3 seconds at most
\r
8540 if( dw != WAIT_OBJECT_0 ) {
\r
8541 result = TerminateProcess( cp->hProcess, 0 );
\r
8543 if ( appData.debugMode) {
\r
8544 fprintf( debugFP, "Process %lu still alive after timeout, killing... result=%d\n", cp->pid, result );
\r
8550 CloseHandle(cp->hProcess);
\r
8554 if (cp->hFrom) CloseHandle(cp->hFrom);
\r
8558 closesocket(cp->sock);
\r
8563 if (signal) send(cp->sock2, "\017", 1, 0); /* 017 = 15 = SIGTERM */
\r
8564 closesocket(cp->sock);
\r
8565 closesocket(cp->sock2);
\r
8573 InterruptChildProcess(ProcRef pr)
\r
8577 cp = (ChildProc *) pr;
\r
8578 if (cp == NULL) return;
\r
8579 switch (cp->kind) {
\r
8581 /* The following doesn't work because the chess program
\r
8582 doesn't "have the same console" as WinBoard. Maybe
\r
8583 we could arrange for this even though neither WinBoard
\r
8584 nor the chess program uses a console for stdio */
\r
8585 /*!!GenerateConsoleCtrlEvent(CTRL_C_EVENT, cp->pid);*/
\r
8590 /* Can't interrupt */
\r
8594 send(cp->sock2, "\002", 1, 0); /* 2 = SIGINT */
\r
8601 OpenTelnet(char *host, char *port, ProcRef *pr)
\r
8603 char cmdLine[MSG_SIZ];
\r
8605 if (port[0] == NULLCHAR) {
\r
8606 sprintf(cmdLine, "%s %s", appData.telnetProgram, host);
\r
8608 sprintf(cmdLine, "%s %s %s", appData.telnetProgram, host, port);
\r
8610 return StartChildProcess(cmdLine, "", pr);
\r
8614 /* Code to open TCP sockets */
\r
8617 OpenTCP(char *host, char *port, ProcRef *pr)
\r
8622 struct sockaddr_in sa, mysa;
\r
8623 struct hostent FAR *hp;
\r
8624 unsigned short uport;
\r
8625 WORD wVersionRequested;
\r
8628 /* Initialize socket DLL */
\r
8629 wVersionRequested = MAKEWORD(1, 1);
\r
8630 err = WSAStartup(wVersionRequested, &wsaData);
\r
8631 if (err != 0) return err;
\r
8634 if ((s = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
\r
8635 err = WSAGetLastError();
\r
8640 /* Bind local address using (mostly) don't-care values.
\r
8642 memset((char *) &mysa, 0, sizeof(struct sockaddr_in));
\r
8643 mysa.sin_family = AF_INET;
\r
8644 mysa.sin_addr.s_addr = INADDR_ANY;
\r
8645 uport = (unsigned short) 0;
\r
8646 mysa.sin_port = htons(uport);
\r
8647 if (bind(s, (struct sockaddr *) &mysa, sizeof(struct sockaddr_in))
\r
8648 == SOCKET_ERROR) {
\r
8649 err = WSAGetLastError();
\r
8654 /* Resolve remote host name */
\r
8655 memset((char *) &sa, 0, sizeof(struct sockaddr_in));
\r
8656 if (!(hp = gethostbyname(host))) {
\r
8657 unsigned int b0, b1, b2, b3;
\r
8659 err = WSAGetLastError();
\r
8661 if (sscanf(host, "%u.%u.%u.%u", &b0, &b1, &b2, &b3) == 4) {
\r
8662 hp = (struct hostent *) calloc(1, sizeof(struct hostent));
\r
8663 hp->h_addrtype = AF_INET;
\r
8665 hp->h_addr_list = (char **) calloc(2, sizeof(char *));
\r
8666 hp->h_addr_list[0] = (char *) malloc(4);
\r
8667 hp->h_addr_list[0][0] = (char) b0;
\r
8668 hp->h_addr_list[0][1] = (char) b1;
\r
8669 hp->h_addr_list[0][2] = (char) b2;
\r
8670 hp->h_addr_list[0][3] = (char) b3;
\r
8676 sa.sin_family = hp->h_addrtype;
\r
8677 uport = (unsigned short) atoi(port);
\r
8678 sa.sin_port = htons(uport);
\r
8679 memcpy((char *) &sa.sin_addr, hp->h_addr, hp->h_length);
\r
8681 /* Make connection */
\r
8682 if (connect(s, (struct sockaddr *) &sa,
\r
8683 sizeof(struct sockaddr_in)) == SOCKET_ERROR) {
\r
8684 err = WSAGetLastError();
\r
8689 /* Prepare return value */
\r
8690 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
8691 cp->kind = CPSock;
\r
8693 *pr = (ProcRef *) cp;
\r
8699 OpenCommPort(char *name, ProcRef *pr)
\r
8704 char fullname[MSG_SIZ];
\r
8706 if (*name != '\\')
\r
8707 sprintf(fullname, "\\\\.\\%s", name);
\r
8709 strcpy(fullname, name);
\r
8711 h = CreateFile(name, GENERIC_READ | GENERIC_WRITE,
\r
8712 0, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
\r
8713 if (h == (HANDLE) -1) {
\r
8714 return GetLastError();
\r
8718 if (!SetCommState(h, (LPDCB) &dcb)) return GetLastError();
\r
8720 /* Accumulate characters until a 100ms pause, then parse */
\r
8721 ct.ReadIntervalTimeout = 100;
\r
8722 ct.ReadTotalTimeoutMultiplier = 0;
\r
8723 ct.ReadTotalTimeoutConstant = 0;
\r
8724 ct.WriteTotalTimeoutMultiplier = 0;
\r
8725 ct.WriteTotalTimeoutConstant = 0;
\r
8726 if (!SetCommTimeouts(h, (LPCOMMTIMEOUTS) &ct)) return GetLastError();
\r
8728 /* Prepare return value */
\r
8729 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
8730 cp->kind = CPComm;
\r
8733 *pr = (ProcRef *) cp;
\r
8739 OpenLoopback(ProcRef *pr)
\r
8741 DisplayFatalError("Not implemented", 0, 1);
\r
8747 OpenRcmd(char* host, char* user, char* cmd, ProcRef* pr)
\r
8752 struct sockaddr_in sa, mysa;
\r
8753 struct hostent FAR *hp;
\r
8754 unsigned short uport;
\r
8755 WORD wVersionRequested;
\r
8758 char stderrPortStr[MSG_SIZ];
\r
8760 /* Initialize socket DLL */
\r
8761 wVersionRequested = MAKEWORD(1, 1);
\r
8762 err = WSAStartup(wVersionRequested, &wsaData);
\r
8763 if (err != 0) return err;
\r
8765 /* Resolve remote host name */
\r
8766 memset((char *) &sa, 0, sizeof(struct sockaddr_in));
\r
8767 if (!(hp = gethostbyname(host))) {
\r
8768 unsigned int b0, b1, b2, b3;
\r
8770 err = WSAGetLastError();
\r
8772 if (sscanf(host, "%u.%u.%u.%u", &b0, &b1, &b2, &b3) == 4) {
\r
8773 hp = (struct hostent *) calloc(1, sizeof(struct hostent));
\r
8774 hp->h_addrtype = AF_INET;
\r
8776 hp->h_addr_list = (char **) calloc(2, sizeof(char *));
\r
8777 hp->h_addr_list[0] = (char *) malloc(4);
\r
8778 hp->h_addr_list[0][0] = (char) b0;
\r
8779 hp->h_addr_list[0][1] = (char) b1;
\r
8780 hp->h_addr_list[0][2] = (char) b2;
\r
8781 hp->h_addr_list[0][3] = (char) b3;
\r
8787 sa.sin_family = hp->h_addrtype;
\r
8788 uport = (unsigned short) 514;
\r
8789 sa.sin_port = htons(uport);
\r
8790 memcpy((char *) &sa.sin_addr, hp->h_addr, hp->h_length);
\r
8792 /* Bind local socket to unused "privileged" port address
\r
8794 s = INVALID_SOCKET;
\r
8795 memset((char *) &mysa, 0, sizeof(struct sockaddr_in));
\r
8796 mysa.sin_family = AF_INET;
\r
8797 mysa.sin_addr.s_addr = INADDR_ANY;
\r
8798 for (fromPort = 1023;; fromPort--) {
\r
8799 if (fromPort < 0) {
\r
8801 return WSAEADDRINUSE;
\r
8803 if (s == INVALID_SOCKET) {
\r
8804 if ((s = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
\r
8805 err = WSAGetLastError();
\r
8810 uport = (unsigned short) fromPort;
\r
8811 mysa.sin_port = htons(uport);
\r
8812 if (bind(s, (struct sockaddr *) &mysa, sizeof(struct sockaddr_in))
\r
8813 == SOCKET_ERROR) {
\r
8814 err = WSAGetLastError();
\r
8815 if (err == WSAEADDRINUSE) continue;
\r
8819 if (connect(s, (struct sockaddr *) &sa,
\r
8820 sizeof(struct sockaddr_in)) == SOCKET_ERROR) {
\r
8821 err = WSAGetLastError();
\r
8822 if (err == WSAEADDRINUSE) {
\r
8833 /* Bind stderr local socket to unused "privileged" port address
\r
8835 s2 = INVALID_SOCKET;
\r
8836 memset((char *) &mysa, 0, sizeof(struct sockaddr_in));
\r
8837 mysa.sin_family = AF_INET;
\r
8838 mysa.sin_addr.s_addr = INADDR_ANY;
\r
8839 for (fromPort = 1023;; fromPort--) {
\r
8840 if (fromPort == prevStderrPort) continue; // don't reuse port
\r
8841 if (fromPort < 0) {
\r
8842 (void) closesocket(s);
\r
8844 return WSAEADDRINUSE;
\r
8846 if (s2 == INVALID_SOCKET) {
\r
8847 if ((s2 = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
\r
8848 err = WSAGetLastError();
\r
8854 uport = (unsigned short) fromPort;
\r
8855 mysa.sin_port = htons(uport);
\r
8856 if (bind(s2, (struct sockaddr *) &mysa, sizeof(struct sockaddr_in))
\r
8857 == SOCKET_ERROR) {
\r
8858 err = WSAGetLastError();
\r
8859 if (err == WSAEADDRINUSE) continue;
\r
8860 (void) closesocket(s);
\r
8864 if (listen(s2, 1) == SOCKET_ERROR) {
\r
8865 err = WSAGetLastError();
\r
8866 if (err == WSAEADDRINUSE) {
\r
8868 s2 = INVALID_SOCKET;
\r
8871 (void) closesocket(s);
\r
8872 (void) closesocket(s2);
\r
8878 prevStderrPort = fromPort; // remember port used
\r
8879 sprintf(stderrPortStr, "%d", fromPort);
\r
8881 if (send(s, stderrPortStr, strlen(stderrPortStr) + 1, 0) == SOCKET_ERROR) {
\r
8882 err = WSAGetLastError();
\r
8883 (void) closesocket(s);
\r
8884 (void) closesocket(s2);
\r
8889 if (send(s, UserName(), strlen(UserName()) + 1, 0) == SOCKET_ERROR) {
\r
8890 err = WSAGetLastError();
\r
8891 (void) closesocket(s);
\r
8892 (void) closesocket(s2);
\r
8896 if (*user == NULLCHAR) user = UserName();
\r
8897 if (send(s, user, strlen(user) + 1, 0) == SOCKET_ERROR) {
\r
8898 err = WSAGetLastError();
\r
8899 (void) closesocket(s);
\r
8900 (void) closesocket(s2);
\r
8904 if (send(s, cmd, strlen(cmd) + 1, 0) == SOCKET_ERROR) {
\r
8905 err = WSAGetLastError();
\r
8906 (void) closesocket(s);
\r
8907 (void) closesocket(s2);
\r
8912 if ((s3 = accept(s2, NULL, NULL)) == INVALID_SOCKET) {
\r
8913 err = WSAGetLastError();
\r
8914 (void) closesocket(s);
\r
8915 (void) closesocket(s2);
\r
8919 (void) closesocket(s2); /* Stop listening */
\r
8921 /* Prepare return value */
\r
8922 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
8923 cp->kind = CPRcmd;
\r
8926 *pr = (ProcRef *) cp;
\r
8933 AddInputSource(ProcRef pr, int lineByLine,
\r
8934 InputCallback func, VOIDSTAR closure)
\r
8936 InputSource *is, *is2 = NULL;
\r
8937 ChildProc *cp = (ChildProc *) pr;
\r
8939 is = (InputSource *) calloc(1, sizeof(InputSource));
\r
8940 is->lineByLine = lineByLine;
\r
8942 is->closure = closure;
\r
8943 is->second = NULL;
\r
8944 is->next = is->buf;
\r
8945 if (pr == NoProc) {
\r
8946 is->kind = CPReal;
\r
8947 consoleInputSource = is;
\r
8949 is->kind = cp->kind;
\r
8951 [AS] Try to avoid a race condition if the thread is given control too early:
\r
8952 we create all threads suspended so that the is->hThread variable can be
\r
8953 safely assigned, then let the threads start with ResumeThread.
\r
8955 switch (cp->kind) {
\r
8957 is->hFile = cp->hFrom;
\r
8958 cp->hFrom = NULL; /* now owned by InputThread */
\r
8960 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) NonOvlInputThread,
\r
8961 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
8965 is->hFile = cp->hFrom;
\r
8966 cp->hFrom = NULL; /* now owned by InputThread */
\r
8968 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) InputThread,
\r
8969 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
8973 is->sock = cp->sock;
\r
8975 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SocketInputThread,
\r
8976 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
8980 is2 = (InputSource *) calloc(1, sizeof(InputSource));
\r
8982 is->sock = cp->sock;
\r
8984 is2->sock = cp->sock2;
\r
8985 is2->second = is2;
\r
8987 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SocketInputThread,
\r
8988 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
8990 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SocketInputThread,
\r
8991 (LPVOID) is2, CREATE_SUSPENDED, &is2->id);
\r
8995 if( is->hThread != NULL ) {
\r
8996 ResumeThread( is->hThread );
\r
8999 if( is2 != NULL && is2->hThread != NULL ) {
\r
9000 ResumeThread( is2->hThread );
\r
9004 return (InputSourceRef) is;
\r
9008 RemoveInputSource(InputSourceRef isr)
\r
9012 is = (InputSource *) isr;
\r
9013 is->hThread = NULL; /* tell thread to stop */
\r
9014 CloseHandle(is->hThread);
\r
9015 if (is->second != NULL) {
\r
9016 is->second->hThread = NULL;
\r
9017 CloseHandle(is->second->hThread);
\r
9021 int no_wrap(char *message, int count)
\r
9023 ConsoleOutput(message, count, FALSE);
\r
9028 OutputToProcess(ProcRef pr, char *message, int count, int *outError)
\r
9031 int outCount = SOCKET_ERROR;
\r
9032 ChildProc *cp = (ChildProc *) pr;
\r
9033 static OVERLAPPED ovl;
\r
9034 static int line = 0;
\r
9038 if (appData.noJoin || !appData.useInternalWrap)
\r
9039 return no_wrap(message, count);
\r
9042 int width = get_term_width();
\r
9043 int len = wrap(NULL, message, count, width, &line);
\r
9044 char *msg = malloc(len);
\r
9048 return no_wrap(message, count);
\r
9051 dbgchk = wrap(msg, message, count, width, &line);
\r
9052 if (dbgchk != len && appData.debugMode)
\r
9053 fprintf(debugFP, "wrap(): dbgchk(%d) != len(%d)\n", dbgchk, len);
\r
9054 ConsoleOutput(msg, len, FALSE);
\r
9061 if (ovl.hEvent == NULL) {
\r
9062 ovl.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
\r
9064 ovl.Internal = ovl.InternalHigh = ovl.Offset = ovl.OffsetHigh = 0;
\r
9066 switch (cp->kind) {
\r
9069 outCount = send(cp->sock, message, count, 0);
\r
9070 if (outCount == SOCKET_ERROR) {
\r
9071 *outError = WSAGetLastError();
\r
9073 *outError = NO_ERROR;
\r
9078 if (WriteFile(((ChildProc *)pr)->hTo, message, count,
\r
9079 &dOutCount, NULL)) {
\r
9080 *outError = NO_ERROR;
\r
9081 outCount = (int) dOutCount;
\r
9083 *outError = GetLastError();
\r
9088 *outError = DoWriteFile(((ChildProc *)pr)->hTo, message, count,
\r
9089 &dOutCount, &ovl);
\r
9090 if (*outError == NO_ERROR) {
\r
9091 outCount = (int) dOutCount;
\r
9099 OutputToProcessDelayed(ProcRef pr, char *message, int count, int *outError,
\r
9102 /* Ignore delay, not implemented for WinBoard */
\r
9103 return OutputToProcess(pr, message, count, outError);
\r
9108 CmailSigHandlerCallBack(InputSourceRef isr, VOIDSTAR closure,
\r
9109 char *buf, int count, int error)
\r
9111 DisplayFatalError("Not implemented", 0, 1);
\r
9114 /* see wgamelist.c for Game List functions */
\r
9115 /* see wedittags.c for Edit Tags functions */
\r
9122 char buf[MSG_SIZ];
\r
9125 if (SearchPath(installDir, appData.icsLogon, NULL, MSG_SIZ, buf, &dummy)) {
\r
9126 f = fopen(buf, "r");
\r
9128 ProcessICSInitScript(f);
\r
9136 StartAnalysisClock()
\r
9138 if (analysisTimerEvent) return;
\r
9139 analysisTimerEvent = SetTimer(hwndMain, (UINT) ANALYSIS_TIMER_ID,
\r
9140 (UINT) 2000, NULL);
\r
9144 SetHighlights(int fromX, int fromY, int toX, int toY)
\r
9146 highlightInfo.sq[0].x = fromX;
\r
9147 highlightInfo.sq[0].y = fromY;
\r
9148 highlightInfo.sq[1].x = toX;
\r
9149 highlightInfo.sq[1].y = toY;
\r
9155 highlightInfo.sq[0].x = highlightInfo.sq[0].y =
\r
9156 highlightInfo.sq[1].x = highlightInfo.sq[1].y = -1;
\r
9160 SetPremoveHighlights(int fromX, int fromY, int toX, int toY)
\r
9162 premoveHighlightInfo.sq[0].x = fromX;
\r
9163 premoveHighlightInfo.sq[0].y = fromY;
\r
9164 premoveHighlightInfo.sq[1].x = toX;
\r
9165 premoveHighlightInfo.sq[1].y = toY;
\r
9169 ClearPremoveHighlights()
\r
9171 premoveHighlightInfo.sq[0].x = premoveHighlightInfo.sq[0].y =
\r
9172 premoveHighlightInfo.sq[1].x = premoveHighlightInfo.sq[1].y = -1;
\r
9176 ShutDownFrontEnd()
\r
9178 if (saveSettingsOnExit) SaveSettings(settingsFileName);
\r
9179 DeleteClipboardTempFiles();
\r
9185 if (IsIconic(hwndMain))
\r
9186 ShowWindow(hwndMain, SW_RESTORE);
\r
9188 SetActiveWindow(hwndMain);
\r
9192 * Prototypes for animation support routines
\r
9194 static void ScreenSquare(int column, int row, POINT * pt);
\r
9195 static void Tween( POINT * start, POINT * mid, POINT * finish, int factor,
\r
9196 POINT frames[], int * nFrames);
\r
9200 AnimateAtomicCapture(int fromX, int fromY, int toX, int toY, int nFrames)
\r
9201 { // [HGM] atomic: animate blast wave
\r
9203 if(appData.debugMode) fprintf(debugFP, "exploding (%d,%d)\n", toX, toY);
\r
9204 explodeInfo.fromX = fromX;
\r
9205 explodeInfo.fromY = fromY;
\r
9206 explodeInfo.toX = toX;
\r
9207 explodeInfo.toY = toY;
\r
9208 for(i=1; i<nFrames; i++) {
\r
9209 explodeInfo.radius = (i*180)/(nFrames-1);
\r
9210 DrawPosition(FALSE, NULL);
\r
9211 Sleep(appData.animSpeed);
\r
9213 explodeInfo.radius = 0;
\r
9214 DrawPosition(TRUE, NULL);
\r
9220 AnimateMove(board, fromX, fromY, toX, toY)
\r
9227 ChessSquare piece;
\r
9228 POINT start, finish, mid;
\r
9229 POINT frames[kFactor * 2 + 1];
\r
9232 if (!appData.animate) return;
\r
9233 if (doingSizing) return;
\r
9234 if (fromY < 0 || fromX < 0) return;
\r
9235 piece = board[fromY][fromX];
\r
9236 if (piece >= EmptySquare) return;
\r
9238 ScreenSquare(fromX, fromY, &start);
\r
9239 ScreenSquare(toX, toY, &finish);
\r
9241 /* All pieces except knights move in straight line */
\r
9242 if (piece != WhiteKnight && piece != BlackKnight) {
\r
9243 mid.x = start.x + (finish.x - start.x) / 2;
\r
9244 mid.y = start.y + (finish.y - start.y) / 2;
\r
9246 /* Knight: make diagonal movement then straight */
\r
9247 if (abs(toY - fromY) < abs(toX - fromX)) {
\r
9248 mid.x = start.x + (finish.x - start.x) / 2;
\r
9252 mid.y = start.y + (finish.y - start.y) / 2;
\r
9256 /* Don't use as many frames for very short moves */
\r
9257 if (abs(toY - fromY) + abs(toX - fromX) <= 2)
\r
9258 Tween(&start, &mid, &finish, kFactor - 1, frames, &nFrames);
\r
9260 Tween(&start, &mid, &finish, kFactor, frames, &nFrames);
\r
9262 animInfo.from.x = fromX;
\r
9263 animInfo.from.y = fromY;
\r
9264 animInfo.to.x = toX;
\r
9265 animInfo.to.y = toY;
\r
9266 animInfo.lastpos = start;
\r
9267 animInfo.piece = piece;
\r
9268 for (n = 0; n < nFrames; n++) {
\r
9269 animInfo.pos = frames[n];
\r
9270 DrawPosition(FALSE, NULL);
\r
9271 animInfo.lastpos = animInfo.pos;
\r
9272 Sleep(appData.animSpeed);
\r
9274 animInfo.pos = finish;
\r
9275 DrawPosition(FALSE, NULL);
\r
9276 animInfo.piece = EmptySquare;
\r
9277 if(gameInfo.variant == VariantAtomic &&
\r
9278 (board[toY][toX] != EmptySquare || fromX != toX && (piece == WhitePawn || piece == BlackPawn) ) )
\r
9279 AnimateAtomicCapture(fromX, fromY, toX, toY, 2*nFrames);
\r
9282 /* Convert board position to corner of screen rect and color */
\r
9285 ScreenSquare(column, row, pt)
\r
9286 int column; int row; POINT * pt;
\r
9289 pt->x = lineGap + ((BOARD_WIDTH-1)-column) * (squareSize + lineGap);
\r
9290 pt->y = lineGap + row * (squareSize + lineGap);
\r
9292 pt->x = lineGap + column * (squareSize + lineGap);
\r
9293 pt->y = lineGap + ((BOARD_HEIGHT-1)-row) * (squareSize + lineGap);
\r
9297 /* Generate a series of frame coords from start->mid->finish.
\r
9298 The movement rate doubles until the half way point is
\r
9299 reached, then halves back down to the final destination,
\r
9300 which gives a nice slow in/out effect. The algorithmn
\r
9301 may seem to generate too many intermediates for short
\r
9302 moves, but remember that the purpose is to attract the
\r
9303 viewers attention to the piece about to be moved and
\r
9304 then to where it ends up. Too few frames would be less
\r
9308 Tween(start, mid, finish, factor, frames, nFrames)
\r
9309 POINT * start; POINT * mid;
\r
9310 POINT * finish; int factor;
\r
9311 POINT frames[]; int * nFrames;
\r
9313 int n, fraction = 1, count = 0;
\r
9315 /* Slow in, stepping 1/16th, then 1/8th, ... */
\r
9316 for (n = 0; n < factor; n++)
\r
9318 for (n = 0; n < factor; n++) {
\r
9319 frames[count].x = start->x + (mid->x - start->x) / fraction;
\r
9320 frames[count].y = start->y + (mid->y - start->y) / fraction;
\r
9322 fraction = fraction / 2;
\r
9326 frames[count] = *mid;
\r
9329 /* Slow out, stepping 1/2, then 1/4, ... */
\r
9331 for (n = 0; n < factor; n++) {
\r
9332 frames[count].x = finish->x - (finish->x - mid->x) / fraction;
\r
9333 frames[count].y = finish->y - (finish->y - mid->y) / fraction;
\r
9335 fraction = fraction * 2;
\r
9341 HistorySet( char movelist[][2*MOVE_LEN], int first, int last, int current )
\r
9343 MoveHistorySet( movelist, first, last, current, pvInfoList );
\r
9345 EvalGraphSet( first, last, current, pvInfoList );
\r