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
6069 if(errorExitStatus) ExitEvent(errorExitStatus);
\r
6073 ErrorDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
6078 switch (message) {
\r
6079 case WM_INITDIALOG:
\r
6080 GetWindowRect(hDlg, &rChild);
\r
6083 SetWindowPos(hDlg, NULL, rChild.left,
\r
6084 rChild.top + boardRect.top - (rChild.bottom - rChild.top),
\r
6085 0, 0, SWP_NOZORDER|SWP_NOSIZE);
\r
6089 [AS] It seems that the above code wants to move the dialog up in the "caption
\r
6090 area" of the main window, but it uses the dialog height as an hard-coded constant,
\r
6091 and it doesn't work when you resize the dialog.
\r
6092 For now, just give it a default position.
\r
6094 SetWindowPos(hDlg, NULL, boardRect.left+8, boardRect.top+8, 0, 0, SWP_NOZORDER|SWP_NOSIZE);
\r
6096 errorDialog = hDlg;
\r
6097 SetWindowText(hDlg, errorTitle);
\r
6098 hwndText = GetDlgItem(hDlg, OPT_ErrorText);
\r
6099 SetDlgItemText(hDlg, OPT_ErrorText, errorMessage);
\r
6103 switch (LOWORD(wParam)) {
\r
6106 if (errorDialog == hDlg) errorDialog = NULL;
\r
6107 DestroyWindow(hDlg);
\r
6119 HWND gothicDialog = NULL;
\r
6122 GothicDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
6126 int height = GetSystemMetrics(SM_CYCAPTION)+GetSystemMetrics(SM_CYFRAME);
\r
6128 switch (message) {
\r
6129 case WM_INITDIALOG:
\r
6130 GetWindowRect(hDlg, &rChild);
\r
6132 SetWindowPos(hDlg, NULL, wpMain.x, wpMain.y-height, wpMain.width, height,
\r
6136 [AS] It seems that the above code wants to move the dialog up in the "caption
\r
6137 area" of the main window, but it uses the dialog height as an hard-coded constant,
\r
6138 and it doesn't work when you resize the dialog.
\r
6139 For now, just give it a default position.
\r
6141 gothicDialog = hDlg;
\r
6142 SetWindowText(hDlg, errorTitle);
\r
6143 hwndText = GetDlgItem(hDlg, OPT_ErrorText);
\r
6144 SetDlgItemText(hDlg, OPT_ErrorText, errorMessage);
\r
6148 switch (LOWORD(wParam)) {
\r
6151 if (errorDialog == hDlg) errorDialog = NULL;
\r
6152 DestroyWindow(hDlg);
\r
6164 GothicPopUp(char *title, VariantClass variant)
\r
6167 static char *lastTitle;
\r
6169 strncpy(errorTitle, title, sizeof(errorTitle));
\r
6170 errorTitle[sizeof(errorTitle) - 1] = '\0';
\r
6172 if(lastTitle != title && gothicDialog != NULL) {
\r
6173 DestroyWindow(gothicDialog);
\r
6174 gothicDialog = NULL;
\r
6176 if(variant != VariantNormal && gothicDialog == NULL) {
\r
6177 title = lastTitle;
\r
6178 lpProc = MakeProcInstance((FARPROC)GothicDialog, hInst);
\r
6179 CreateDialog(hInst, MAKEINTRESOURCE(DLG_Error),
\r
6180 hwndMain, (DLGPROC)lpProc);
\r
6181 FreeProcInstance(lpProc);
\r
6186 /*---------------------------------------------------------------------------*\
\r
6188 * Ics Interaction console functions
\r
6190 \*---------------------------------------------------------------------------*/
\r
6192 #define HISTORY_SIZE 64
\r
6193 static char *history[HISTORY_SIZE];
\r
6194 int histIn = 0, histP = 0;
\r
6197 SaveInHistory(char *cmd)
\r
6199 if (history[histIn] != NULL) {
\r
6200 free(history[histIn]);
\r
6201 history[histIn] = NULL;
\r
6203 if (*cmd == NULLCHAR) return;
\r
6204 history[histIn] = StrSave(cmd);
\r
6205 histIn = (histIn + 1) % HISTORY_SIZE;
\r
6206 if (history[histIn] != NULL) {
\r
6207 free(history[histIn]);
\r
6208 history[histIn] = NULL;
\r
6214 PrevInHistory(char *cmd)
\r
6217 if (histP == histIn) {
\r
6218 if (history[histIn] != NULL) free(history[histIn]);
\r
6219 history[histIn] = StrSave(cmd);
\r
6221 newhp = (histP - 1 + HISTORY_SIZE) % HISTORY_SIZE;
\r
6222 if (newhp == histIn || history[newhp] == NULL) return NULL;
\r
6224 return history[histP];
\r
6230 if (histP == histIn) return NULL;
\r
6231 histP = (histP + 1) % HISTORY_SIZE;
\r
6232 return history[histP];
\r
6236 LoadIcsTextMenu(IcsTextMenuEntry *e)
\r
6240 hmenu = LoadMenu(hInst, "TextMenu");
\r
6241 h = GetSubMenu(hmenu, 0);
\r
6243 if (strcmp(e->item, "-") == 0) {
\r
6244 AppendMenu(h, MF_SEPARATOR, 0, 0);
\r
6246 if (e->item[0] == '|') {
\r
6247 AppendMenu(h, MF_STRING|MF_MENUBARBREAK,
\r
6248 IDM_CommandX + i, &e->item[1]);
\r
6250 AppendMenu(h, MF_STRING, IDM_CommandX + i, e->item);
\r
6259 WNDPROC consoleTextWindowProc;
\r
6262 CommandX(HWND hwnd, char *command, BOOLEAN getname, BOOLEAN immediate)
\r
6264 char buf[MSG_SIZ], name[MSG_SIZ];
\r
6265 HWND hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
6269 SetWindowText(hInput, command);
\r
6271 SendMessage(hInput, WM_CHAR, '\r', 0);
\r
6273 sel.cpMin = 999999;
\r
6274 sel.cpMax = 999999;
\r
6275 SendMessage(hInput, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
6280 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
6281 if (sel.cpMin == sel.cpMax) {
\r
6282 /* Expand to surrounding word */
\r
6285 tr.chrg.cpMax = sel.cpMin;
\r
6286 tr.chrg.cpMin = --sel.cpMin;
\r
6287 if (sel.cpMin < 0) break;
\r
6288 tr.lpstrText = name;
\r
6289 SendMessage(hwnd, EM_GETTEXTRANGE, 0, (LPARAM) &tr);
\r
6290 } while (isalpha(name[0]) || isdigit(name[0]) || name[0] == '-');
\r
6294 tr.chrg.cpMin = sel.cpMax;
\r
6295 tr.chrg.cpMax = ++sel.cpMax;
\r
6296 tr.lpstrText = name;
\r
6297 if (SendMessage(hwnd, EM_GETTEXTRANGE, 0, (LPARAM) &tr) < 1) break;
\r
6298 } while (isalpha(name[0]) || isdigit(name[0]) || name[0] == '-');
\r
6301 if (sel.cpMax == sel.cpMin || sel.cpMax - sel.cpMin > MSG_SIZ/2) {
\r
6302 MessageBeep(MB_ICONEXCLAMATION);
\r
6306 tr.lpstrText = name;
\r
6307 SendMessage(hwnd, EM_GETTEXTRANGE, 0, (LPARAM) &tr);
\r
6309 if (sel.cpMax - sel.cpMin > MSG_SIZ/2) {
\r
6310 MessageBeep(MB_ICONEXCLAMATION);
\r
6313 SendMessage(hwnd, EM_GETSELTEXT, 0, (LPARAM) name);
\r
6316 sprintf(buf, "%s %s", command, name);
\r
6317 SetWindowText(hInput, buf);
\r
6318 SendMessage(hInput, WM_CHAR, '\r', 0);
\r
6320 sprintf(buf, "%s %s ", command, name); /* trailing space */
\r
6321 SetWindowText(hInput, buf);
\r
6322 sel.cpMin = 999999;
\r
6323 sel.cpMax = 999999;
\r
6324 SendMessage(hInput, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
6330 ConsoleTextSubclass(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
6335 switch (message) {
\r
6337 if (!(GetKeyState(VK_CONTROL) & ~1)) break;
\r
6340 SendMessage(hwnd, EM_LINESCROLL, 0, -999999);
\r
6343 sel.cpMin = 999999;
\r
6344 sel.cpMax = 999999;
\r
6345 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
6346 SendMessage(hwnd, EM_SCROLLCARET, 0, 0);
\r
6351 if(wParam != '\022') {
\r
6352 if (wParam == '\t') {
\r
6353 if (GetKeyState(VK_SHIFT) < 0) {
\r
6355 if (IsIconic(hwndMain)) ShowWindow(hwndMain, SW_RESTORE);
\r
6356 if (buttonDesc[0].hwnd) {
\r
6357 SetFocus(buttonDesc[0].hwnd);
\r
6359 SetFocus(hwndMain);
\r
6363 SetFocus(GetDlgItem(hwndConsole, OPT_ConsoleInput));
\r
6366 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
6367 JAWS_DELETE( SetFocus(hInput); )
\r
6368 SendMessage(hInput, message, wParam, lParam);
\r
6371 } // [HGM] navigate: for Ctrl+R, flow into nex case (moved up here) to summon up menu
\r
6372 case WM_RBUTTONUP:
\r
6373 if (GetKeyState(VK_SHIFT) & ~1) {
\r
6374 SendDlgItemMessage(hwndConsole, OPT_ConsoleText,
\r
6375 WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
6378 HMENU hmenu = LoadIcsTextMenu(icsTextMenuEntry);
\r
6379 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
6380 if (sel.cpMin == sel.cpMax) {
\r
6381 EnableMenuItem(hmenu, IDM_Copy, MF_BYCOMMAND|MF_GRAYED);
\r
6382 EnableMenuItem(hmenu, IDM_QuickPaste, MF_BYCOMMAND|MF_GRAYED);
\r
6384 if (!IsClipboardFormatAvailable(CF_TEXT)) {
\r
6385 EnableMenuItem(hmenu, IDM_Paste, MF_BYCOMMAND|MF_GRAYED);
\r
6387 pt.x = LOWORD(lParam);
\r
6388 pt.y = HIWORD(lParam);
\r
6389 MenuPopup(hwnd, pt, hmenu, -1);
\r
6393 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
6395 return SendMessage(hInput, message, wParam, lParam);
\r
6396 case WM_MBUTTONDOWN:
\r
6397 return SendMessage(hwnd, WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
6398 case WM_RBUTTONDOWN:
\r
6399 if (!(GetKeyState(VK_SHIFT) & ~1)) {
\r
6400 /* Move selection here if it was empty */
\r
6402 pt.x = LOWORD(lParam);
\r
6403 pt.y = HIWORD(lParam);
\r
6404 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
6405 if (sel.cpMin == sel.cpMax) {
\r
6406 sel.cpMin = SendMessage(hwnd, EM_CHARFROMPOS, 0, (LPARAM)&pt); /*doc is wrong*/
\r
6407 sel.cpMax = sel.cpMin;
\r
6408 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
6410 SendMessage(hwnd, EM_HIDESELECTION, FALSE, FALSE);
\r
6414 switch (LOWORD(wParam)) {
\r
6415 case IDM_QuickPaste:
\r
6417 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
6418 if (sel.cpMin == sel.cpMax) {
\r
6419 MessageBeep(MB_ICONEXCLAMATION);
\r
6422 SendMessage(hwnd, WM_COPY, 0, 0);
\r
6423 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
6424 SendMessage(hInput, WM_PASTE, 0, 0);
\r
6429 SendMessage(hwnd, WM_CUT, 0, 0);
\r
6432 SendMessage(hwnd, WM_PASTE, 0, 0);
\r
6435 SendMessage(hwnd, WM_COPY, 0, 0);
\r
6439 int i = LOWORD(wParam) - IDM_CommandX;
\r
6440 if (i >= 0 && i < ICS_TEXT_MENU_SIZE &&
\r
6441 icsTextMenuEntry[i].command != NULL) {
\r
6442 CommandX(hwnd, icsTextMenuEntry[i].command,
\r
6443 icsTextMenuEntry[i].getname,
\r
6444 icsTextMenuEntry[i].immediate);
\r
6452 return (*consoleTextWindowProc)(hwnd, message, wParam, lParam);
\r
6455 WNDPROC consoleInputWindowProc;
\r
6458 ConsoleInputSubclass(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
6460 char buf[MSG_SIZ];
\r
6462 static BOOL sendNextChar = FALSE;
\r
6463 static BOOL quoteNextChar = FALSE;
\r
6464 InputSource *is = consoleInputSource;
\r
6468 switch (message) {
\r
6470 if (!appData.localLineEditing || sendNextChar) {
\r
6471 is->buf[0] = (CHAR) wParam;
\r
6473 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
6474 sendNextChar = FALSE;
\r
6477 if (quoteNextChar) {
\r
6478 buf[0] = (char) wParam;
\r
6479 buf[1] = NULLCHAR;
\r
6480 SendMessage(hwnd, EM_REPLACESEL, TRUE, (LPARAM) buf);
\r
6481 quoteNextChar = FALSE;
\r
6485 case '\r': /* Enter key */
\r
6486 is->count = GetWindowText(hwnd, is->buf, INPUT_SOURCE_BUF_SIZE-1);
\r
6487 if (consoleEcho) SaveInHistory(is->buf);
\r
6488 is->buf[is->count++] = '\n';
\r
6489 is->buf[is->count] = NULLCHAR;
\r
6490 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
6491 if (consoleEcho) {
\r
6492 ConsoleOutput(is->buf, is->count, TRUE);
\r
6493 } else if (appData.localLineEditing) {
\r
6494 ConsoleOutput("\n", 1, TRUE);
\r
6497 case '\033': /* Escape key */
\r
6498 SetWindowText(hwnd, "");
\r
6499 cf.cbSize = sizeof(CHARFORMAT);
\r
6500 cf.dwMask = CFM_COLOR|CFM_BOLD|CFM_ITALIC|CFM_UNDERLINE|CFM_STRIKEOUT;
\r
6501 if (consoleEcho) {
\r
6502 cf.crTextColor = textAttribs[ColorNormal].color;
\r
6504 cf.crTextColor = COLOR_ECHOOFF;
\r
6506 cf.dwEffects = textAttribs[ColorNormal].effects;
\r
6507 SendMessage(hwnd, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&cf);
\r
6509 case '\t': /* Tab key */
\r
6510 if (GetKeyState(VK_SHIFT) < 0) {
\r
6512 SetFocus(GetDlgItem(hwndConsole, OPT_ConsoleText));
\r
6515 if (IsIconic(hwndMain)) ShowWindow(hwndMain, SW_RESTORE);
\r
6516 if (buttonDesc[0].hwnd) {
\r
6517 SetFocus(buttonDesc[0].hwnd);
\r
6519 SetFocus(hwndMain);
\r
6523 case '\023': /* Ctrl+S */
\r
6524 sendNextChar = TRUE;
\r
6526 case '\021': /* Ctrl+Q */
\r
6527 quoteNextChar = TRUE;
\r
6537 GetWindowText(hwnd, buf, MSG_SIZ);
\r
6538 p = PrevInHistory(buf);
\r
6540 SetWindowText(hwnd, p);
\r
6541 sel.cpMin = 999999;
\r
6542 sel.cpMax = 999999;
\r
6543 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
6548 p = NextInHistory();
\r
6550 SetWindowText(hwnd, p);
\r
6551 sel.cpMin = 999999;
\r
6552 sel.cpMax = 999999;
\r
6553 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
6559 if (!(GetKeyState(VK_CONTROL) & ~1)) break;
\r
6563 SendDlgItemMessage(hwndConsole, OPT_ConsoleText, message, wParam, lParam);
\r
6567 case WM_MBUTTONDOWN:
\r
6568 SendDlgItemMessage(hwndConsole, OPT_ConsoleText,
\r
6569 WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
6571 case WM_RBUTTONUP:
\r
6572 if (GetKeyState(VK_SHIFT) & ~1) {
\r
6573 SendDlgItemMessage(hwndConsole, OPT_ConsoleText,
\r
6574 WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
6578 hmenu = LoadMenu(hInst, "InputMenu");
\r
6579 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
6580 if (sel.cpMin == sel.cpMax) {
\r
6581 EnableMenuItem(hmenu, IDM_Copy, MF_BYCOMMAND|MF_GRAYED);
\r
6582 EnableMenuItem(hmenu, IDM_Cut, MF_BYCOMMAND|MF_GRAYED);
\r
6584 if (!IsClipboardFormatAvailable(CF_TEXT)) {
\r
6585 EnableMenuItem(hmenu, IDM_Paste, MF_BYCOMMAND|MF_GRAYED);
\r
6587 pt.x = LOWORD(lParam);
\r
6588 pt.y = HIWORD(lParam);
\r
6589 MenuPopup(hwnd, pt, hmenu, -1);
\r
6593 switch (LOWORD(wParam)) {
\r
6595 SendMessage(hwnd, EM_UNDO, 0, 0);
\r
6597 case IDM_SelectAll:
\r
6599 sel.cpMax = -1; /*999999?*/
\r
6600 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
6603 SendMessage(hwnd, WM_CUT, 0, 0);
\r
6606 SendMessage(hwnd, WM_PASTE, 0, 0);
\r
6609 SendMessage(hwnd, WM_COPY, 0, 0);
\r
6614 return (*consoleInputWindowProc)(hwnd, message, wParam, lParam);
\r
6617 #define CO_MAX 100000
\r
6618 #define CO_TRIM 1000
\r
6621 ConsoleWndProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
6623 static SnapData sd;
\r
6624 HWND hText, hInput;
\r
6626 static int sizeX, sizeY;
\r
6627 int newSizeX, newSizeY;
\r
6631 hText = GetDlgItem(hDlg, OPT_ConsoleText);
\r
6632 hInput = GetDlgItem(hDlg, OPT_ConsoleInput);
\r
6634 switch (message) {
\r
6636 if (((NMHDR*)lParam)->code == EN_LINK)
\r
6638 ENLINK *pLink = (ENLINK*)lParam;
\r
6639 if (pLink->msg == WM_LBUTTONUP)
\r
6643 tr.chrg = pLink->chrg;
\r
6644 tr.lpstrText = malloc(1+tr.chrg.cpMax-tr.chrg.cpMin);
\r
6645 SendMessage(hText, EM_GETTEXTRANGE, 0, (LPARAM)&tr);
\r
6646 ShellExecute(NULL, "open", tr.lpstrText, NULL, NULL, SW_SHOW);
\r
6647 free(tr.lpstrText);
\r
6651 case WM_INITDIALOG: /* message: initialize dialog box */
\r
6652 hwndConsole = hDlg;
\r
6654 consoleTextWindowProc = (WNDPROC)
\r
6655 SetWindowLong(hText, GWL_WNDPROC, (LONG) ConsoleTextSubclass);
\r
6656 SendMessage(hText, EM_SETBKGNDCOLOR, FALSE, consoleBackgroundColor);
\r
6657 consoleInputWindowProc = (WNDPROC)
\r
6658 SetWindowLong(hInput, GWL_WNDPROC, (LONG) ConsoleInputSubclass);
\r
6659 SendMessage(hInput, EM_SETBKGNDCOLOR, FALSE, consoleBackgroundColor);
\r
6660 Colorize(ColorNormal, TRUE);
\r
6661 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM) &consoleCF);
\r
6662 ChangedConsoleFont();
\r
6663 GetClientRect(hDlg, &rect);
\r
6664 sizeX = rect.right;
\r
6665 sizeY = rect.bottom;
\r
6666 if (wpConsole.x != CW_USEDEFAULT && wpConsole.y != CW_USEDEFAULT &&
\r
6667 wpConsole.width != CW_USEDEFAULT && wpConsole.height != CW_USEDEFAULT) {
\r
6668 WINDOWPLACEMENT wp;
\r
6669 EnsureOnScreen(&wpConsole.x, &wpConsole.y, 0, 0);
\r
6670 wp.length = sizeof(WINDOWPLACEMENT);
\r
6672 wp.showCmd = SW_SHOW;
\r
6673 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
6674 wp.rcNormalPosition.left = wpConsole.x;
\r
6675 wp.rcNormalPosition.right = wpConsole.x + wpConsole.width;
\r
6676 wp.rcNormalPosition.top = wpConsole.y;
\r
6677 wp.rcNormalPosition.bottom = wpConsole.y + wpConsole.height;
\r
6678 SetWindowPlacement(hDlg, &wp);
\r
6681 // [HGM] Chessknight's change 2004-07-13
\r
6682 else { /* Determine Defaults */
\r
6683 WINDOWPLACEMENT wp;
\r
6684 wpConsole.x = wpMain.width + 1;
\r
6685 wpConsole.y = wpMain.y;
\r
6686 wpConsole.width = screenWidth - wpMain.width;
\r
6687 wpConsole.height = wpMain.height;
\r
6688 EnsureOnScreen(&wpConsole.x, &wpConsole.y, 0, 0);
\r
6689 wp.length = sizeof(WINDOWPLACEMENT);
\r
6691 wp.showCmd = SW_SHOW;
\r
6692 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
6693 wp.rcNormalPosition.left = wpConsole.x;
\r
6694 wp.rcNormalPosition.right = wpConsole.x + wpConsole.width;
\r
6695 wp.rcNormalPosition.top = wpConsole.y;
\r
6696 wp.rcNormalPosition.bottom = wpConsole.y + wpConsole.height;
\r
6697 SetWindowPlacement(hDlg, &wp);
\r
6700 // Allow hText to highlight URLs and send notifications on them
\r
6701 wMask = (WORD) SendMessage(hText, EM_GETEVENTMASK, 0, 0L);
\r
6702 SendMessage(hText, EM_SETEVENTMASK, 0, wMask | ENM_LINK);
\r
6703 SendMessage(hText, EM_AUTOURLDETECT, TRUE, 0L);
\r
6704 SetWindowLong(hText, GWL_USERDATA, 79); // initialize the text window's width
\r
6718 if (IsIconic(hDlg)) break;
\r
6719 newSizeX = LOWORD(lParam);
\r
6720 newSizeY = HIWORD(lParam);
\r
6721 if (sizeX != newSizeX || sizeY != newSizeY) {
\r
6722 RECT rectText, rectInput;
\r
6724 int newTextHeight, newTextWidth;
\r
6725 GetWindowRect(hText, &rectText);
\r
6726 newTextWidth = rectText.right - rectText.left + newSizeX - sizeX;
\r
6727 newTextHeight = rectText.bottom - rectText.top + newSizeY - sizeY;
\r
6728 if (newTextHeight < 0) {
\r
6729 newSizeY += -newTextHeight;
\r
6730 newTextHeight = 0;
\r
6732 SetWindowPos(hText, NULL, 0, 0,
\r
6733 newTextWidth, newTextHeight, SWP_NOZORDER|SWP_NOMOVE);
\r
6734 GetWindowRect(hInput, &rectInput); /* gives screen coords */
\r
6735 pt.x = rectInput.left;
\r
6736 pt.y = rectInput.top + newSizeY - sizeY;
\r
6737 ScreenToClient(hDlg, &pt);
\r
6738 SetWindowPos(hInput, NULL,
\r
6739 pt.x, pt.y, /* needs client coords */
\r
6740 rectInput.right - rectInput.left + newSizeX - sizeX,
\r
6741 rectInput.bottom - rectInput.top, SWP_NOZORDER);
\r
6747 case WM_GETMINMAXINFO:
\r
6748 /* Prevent resizing window too small */
\r
6749 mmi = (MINMAXINFO *) lParam;
\r
6750 mmi->ptMinTrackSize.x = 100;
\r
6751 mmi->ptMinTrackSize.y = 100;
\r
6754 /* [AS] Snapping */
\r
6755 case WM_ENTERSIZEMOVE:
\r
6756 return OnEnterSizeMove( &sd, hDlg, wParam, lParam );
\r
6759 return OnSizing( &sd, hDlg, wParam, lParam );
\r
6762 return OnMoving( &sd, hDlg, wParam, lParam );
\r
6764 case WM_EXITSIZEMOVE:
\r
6765 UpdateICSWidth(hText);
\r
6766 return OnExitSizeMove( &sd, hDlg, wParam, lParam );
\r
6769 return DefWindowProc(hDlg, message, wParam, lParam);
\r
6777 if (hwndConsole) return;
\r
6778 hCons = CreateDialog(hInst, szConsoleName, 0, NULL);
\r
6779 SendMessage(hCons, WM_INITDIALOG, 0, 0);
\r
6784 ConsoleOutput(char* data, int length, int forceVisible)
\r
6789 char buf[CO_MAX+1];
\r
6792 static int delayLF = 0;
\r
6793 CHARRANGE savesel, sel;
\r
6795 if (hwndConsole == NULL || length > CO_MAX-100 || length == 0) return;
\r
6803 while (length--) {
\r
6811 } else if (*p == '\007') {
\r
6812 MyPlaySound(&sounds[(int)SoundBell]);
\r
6819 hText = GetDlgItem(hwndConsole, OPT_ConsoleText);
\r
6820 SendMessage(hText, EM_HIDESELECTION, TRUE, FALSE);
\r
6821 /* Save current selection */
\r
6822 SendMessage(hText, EM_EXGETSEL, 0, (LPARAM)&savesel);
\r
6823 exlen = GetWindowTextLength(hText);
\r
6824 /* Find out whether current end of text is visible */
\r
6825 SendMessage(hText, EM_GETRECT, 0, (LPARAM) &rect);
\r
6826 SendMessage(hText, EM_POSFROMCHAR, (WPARAM) &pEnd, exlen);
\r
6827 /* Trim existing text if it's too long */
\r
6828 if (exlen + (q - buf) > CO_MAX) {
\r
6829 trim = (CO_TRIM > (q - buf)) ? CO_TRIM : (q - buf);
\r
6832 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
6833 SendMessage(hText, EM_REPLACESEL, 0, (LPARAM)"");
\r
6835 savesel.cpMin -= trim;
\r
6836 savesel.cpMax -= trim;
\r
6837 if (exlen < 0) exlen = 0;
\r
6838 if (savesel.cpMin < 0) savesel.cpMin = 0;
\r
6839 if (savesel.cpMax < savesel.cpMin) savesel.cpMax = savesel.cpMin;
\r
6841 /* Append the new text */
\r
6842 sel.cpMin = exlen;
\r
6843 sel.cpMax = exlen;
\r
6844 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
6845 SendMessage(hText, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&consoleCF);
\r
6846 SendMessage(hText, EM_REPLACESEL, 0, (LPARAM) buf);
\r
6847 if (forceVisible || exlen == 0 ||
\r
6848 (rect.left <= pEnd.x && pEnd.x < rect.right &&
\r
6849 rect.top <= pEnd.y && pEnd.y < rect.bottom)) {
\r
6850 /* Scroll to make new end of text visible if old end of text
\r
6851 was visible or new text is an echo of user typein */
\r
6852 sel.cpMin = 9999999;
\r
6853 sel.cpMax = 9999999;
\r
6854 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
6855 SendMessage(hText, EM_HIDESELECTION, FALSE, FALSE);
\r
6856 SendMessage(hText, EM_SCROLLCARET, 0, 0);
\r
6857 SendMessage(hText, EM_HIDESELECTION, TRUE, FALSE);
\r
6859 if (savesel.cpMax == exlen || forceVisible) {
\r
6860 /* Move insert point to new end of text if it was at the old
\r
6861 end of text or if the new text is an echo of user typein */
\r
6862 sel.cpMin = 9999999;
\r
6863 sel.cpMax = 9999999;
\r
6864 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
6866 /* Restore previous selection */
\r
6867 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&savesel);
\r
6869 SendMessage(hText, EM_HIDESELECTION, FALSE, FALSE);
\r
6876 DisplayHoldingsCount(HDC hdc, int x, int y, int rightAlign, int copyNumber)
\r
6880 COLORREF oldFg, oldBg;
\r
6884 if(copyNumber > 1) sprintf(buf, "%d", copyNumber); else buf[0] = 0;
\r
6886 oldFg = SetTextColor(hdc, RGB(255, 255, 255)); /* white */
\r
6887 oldBg = SetBkColor(hdc, RGB(0, 0, 0)); /* black */
\r
6888 oldFont = SelectObject(hdc, font[boardSize][CLOCK_FONT]->hf);
\r
6891 rect.right = x + squareSize;
\r
6893 rect.bottom = y + squareSize;
\r
6896 ExtTextOut(hdc, x + MESSAGE_LINE_LEFTMARGIN
\r
6897 + (rightAlign ? (squareSize*2)/3 : 0),
\r
6898 y, ETO_CLIPPED|ETO_OPAQUE,
\r
6899 &rect, str, strlen(str), NULL);
\r
6901 (void) SetTextColor(hdc, oldFg);
\r
6902 (void) SetBkColor(hdc, oldBg);
\r
6903 (void) SelectObject(hdc, oldFont);
\r
6907 DisplayAClock(HDC hdc, int timeRemaining, int highlight,
\r
6908 RECT *rect, char *color, char *flagFell)
\r
6912 COLORREF oldFg, oldBg;
\r
6915 if (appData.clockMode) {
\r
6917 sprintf(buf, "%c %s %s", color[0], TimeString(timeRemaining), flagFell);
\r
6919 sprintf(buf, "%s:%c%s %s", color, (logoHeight>0 ? 0 : ' '), TimeString(timeRemaining), flagFell);
\r
6926 oldFg = SetTextColor(hdc, RGB(255, 255, 255)); /* white */
\r
6927 oldBg = SetBkColor(hdc, RGB(0, 0, 0)); /* black */
\r
6929 oldFg = SetTextColor(hdc, RGB(0, 0, 0)); /* black */
\r
6930 oldBg = SetBkColor(hdc, RGB(255, 255, 255)); /* white */
\r
6932 oldFont = SelectObject(hdc, font[boardSize][CLOCK_FONT]->hf);
\r
6936 ExtTextOut(hdc, rect->left + MESSAGE_LINE_LEFTMARGIN,
\r
6937 rect->top, ETO_CLIPPED|ETO_OPAQUE,
\r
6938 rect, str, strlen(str), NULL);
\r
6939 if(logoHeight > 0 && appData.clockMode) {
\r
6941 sprintf(buf, "%s %s", buf+7, flagFell);
\r
6942 r.top = rect->top + logoHeight/2;
\r
6943 r.left = rect->left;
\r
6944 r.right = rect->right;
\r
6945 r.bottom = rect->bottom;
\r
6946 ExtTextOut(hdc, rect->left + MESSAGE_LINE_LEFTMARGIN,
\r
6947 r.top, ETO_CLIPPED|ETO_OPAQUE,
\r
6948 &r, str, strlen(str), NULL);
\r
6950 (void) SetTextColor(hdc, oldFg);
\r
6951 (void) SetBkColor(hdc, oldBg);
\r
6952 (void) SelectObject(hdc, oldFont);
\r
6957 DoReadFile(HANDLE hFile, char *buf, int count, DWORD *outCount,
\r
6963 if( count <= 0 ) {
\r
6964 if (appData.debugMode) {
\r
6965 fprintf( debugFP, "DoReadFile: trying to read past end of buffer, overflow = %d\n", count );
\r
6968 return ERROR_INVALID_USER_BUFFER;
\r
6971 ResetEvent(ovl->hEvent);
\r
6972 ovl->Offset = ovl->OffsetHigh = 0;
\r
6973 ok = ReadFile(hFile, buf, count, outCount, ovl);
\r
6977 err = GetLastError();
\r
6978 if (err == ERROR_IO_PENDING) {
\r
6979 ok = GetOverlappedResult(hFile, ovl, outCount, TRUE);
\r
6983 err = GetLastError();
\r
6990 DoWriteFile(HANDLE hFile, char *buf, int count, DWORD *outCount,
\r
6995 ResetEvent(ovl->hEvent);
\r
6996 ovl->Offset = ovl->OffsetHigh = 0;
\r
6997 ok = WriteFile(hFile, buf, count, outCount, ovl);
\r
7001 err = GetLastError();
\r
7002 if (err == ERROR_IO_PENDING) {
\r
7003 ok = GetOverlappedResult(hFile, ovl, outCount, TRUE);
\r
7007 err = GetLastError();
\r
7013 /* [AS] If input is line by line and a line exceed the buffer size, force an error */
\r
7014 void CheckForInputBufferFull( InputSource * is )
\r
7016 if( is->lineByLine && (is->next - is->buf) >= INPUT_SOURCE_BUF_SIZE ) {
\r
7017 /* Look for end of line */
\r
7018 char * p = is->buf;
\r
7020 while( p < is->next && *p != '\n' ) {
\r
7024 if( p >= is->next ) {
\r
7025 if (appData.debugMode) {
\r
7026 fprintf( debugFP, "Input line exceeded buffer size (source id=%lu)\n", is->id );
\r
7029 is->error = ERROR_BROKEN_PIPE; /* [AS] Just any non-successful code! */
\r
7030 is->count = (DWORD) -1;
\r
7031 is->next = is->buf;
\r
7037 InputThread(LPVOID arg)
\r
7042 is = (InputSource *) arg;
\r
7043 ovl.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
\r
7044 ovl.Internal = ovl.InternalHigh = ovl.Offset = ovl.OffsetHigh = 0;
\r
7045 while (is->hThread != NULL) {
\r
7046 is->error = DoReadFile(is->hFile, is->next,
\r
7047 INPUT_SOURCE_BUF_SIZE - (is->next - is->buf),
\r
7048 &is->count, &ovl);
\r
7049 if (is->error == NO_ERROR) {
\r
7050 is->next += is->count;
\r
7052 if (is->error == ERROR_BROKEN_PIPE) {
\r
7053 /* Correct for MS brain damage. EOF reading a pipe is not an error. */
\r
7056 is->count = (DWORD) -1;
\r
7057 /* [AS] The (is->count <= 0) check below is not useful for unsigned values! */
\r
7062 CheckForInputBufferFull( is );
\r
7064 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
7066 if( is->count == ((DWORD) -1) ) break; /* [AS] */
\r
7068 if (is->count <= 0) break; /* Quit on EOF or error */
\r
7071 CloseHandle(ovl.hEvent);
\r
7072 CloseHandle(is->hFile);
\r
7074 if (appData.debugMode) {
\r
7075 fprintf( debugFP, "Input thread terminated (id=%lu, error=%d, count=%ld)\n", is->id, is->error, is->count );
\r
7082 /* Windows 95 beta 2 won't let you do overlapped i/o on a console or pipe */
\r
7084 NonOvlInputThread(LPVOID arg)
\r
7091 is = (InputSource *) arg;
\r
7092 while (is->hThread != NULL) {
\r
7093 is->error = ReadFile(is->hFile, is->next,
\r
7094 INPUT_SOURCE_BUF_SIZE - (is->next - is->buf),
\r
7095 &is->count, NULL) ? NO_ERROR : GetLastError();
\r
7096 if (is->error == NO_ERROR) {
\r
7097 /* Change CRLF to LF */
\r
7098 if (is->next > is->buf) {
\r
7100 i = is->count + 1;
\r
7108 if (prev == '\r' && *p == '\n') {
\r
7120 if (is->error == ERROR_BROKEN_PIPE) {
\r
7121 /* Correct for MS brain damage. EOF reading a pipe is not an error. */
\r
7124 is->count = (DWORD) -1;
\r
7128 CheckForInputBufferFull( is );
\r
7130 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
7132 if( is->count == ((DWORD) -1) ) break; /* [AS] */
\r
7134 if (is->count < 0) break; /* Quit on error */
\r
7136 CloseHandle(is->hFile);
\r
7141 SocketInputThread(LPVOID arg)
\r
7145 is = (InputSource *) arg;
\r
7146 while (is->hThread != NULL) {
\r
7147 is->count = recv(is->sock, is->buf, INPUT_SOURCE_BUF_SIZE, 0);
\r
7148 if ((int)is->count == SOCKET_ERROR) {
\r
7149 is->count = (DWORD) -1;
\r
7150 is->error = WSAGetLastError();
\r
7152 is->error = NO_ERROR;
\r
7153 is->next += is->count;
\r
7154 if (is->count == 0 && is->second == is) {
\r
7155 /* End of file on stderr; quit with no message */
\r
7159 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
7161 if( is->count == ((DWORD) -1) ) break; /* [AS] */
\r
7163 if (is->count <= 0) break; /* Quit on EOF or error */
\r
7169 InputEvent(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
7173 is = (InputSource *) lParam;
\r
7174 if (is->lineByLine) {
\r
7175 /* Feed in lines one by one */
\r
7176 char *p = is->buf;
\r
7178 while (q < is->next) {
\r
7179 if (*q++ == '\n') {
\r
7180 (is->func)(is, is->closure, p, q - p, NO_ERROR);
\r
7185 /* Move any partial line to the start of the buffer */
\r
7187 while (p < is->next) {
\r
7192 if (is->error != NO_ERROR || is->count == 0) {
\r
7193 /* Notify backend of the error. Note: If there was a partial
\r
7194 line at the end, it is not flushed through. */
\r
7195 (is->func)(is, is->closure, is->buf, is->count, is->error);
\r
7198 /* Feed in the whole chunk of input at once */
\r
7199 (is->func)(is, is->closure, is->buf, is->count, is->error);
\r
7200 is->next = is->buf;
\r
7204 /*---------------------------------------------------------------------------*\
\r
7206 * Menu enables. Used when setting various modes.
\r
7208 \*---------------------------------------------------------------------------*/
\r
7216 GreyRevert(Boolean grey)
\r
7217 { // [HGM] vari: for retracting variations in local mode
\r
7218 HMENU hmenu = GetMenu(hwndMain);
\r
7219 EnableMenuItem(hmenu, IDM_Revert, MF_BYCOMMAND|(grey ? MF_GRAYED : MF_ENABLED));
\r
7223 SetMenuEnables(HMENU hmenu, Enables *enab)
\r
7225 while (enab->item > 0) {
\r
7226 (void) EnableMenuItem(hmenu, enab->item, enab->flags);
\r
7231 Enables gnuEnables[] = {
\r
7232 { IDM_MailMove, MF_BYCOMMAND|MF_GRAYED },
\r
7233 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_GRAYED },
\r
7234 { IDM_IcsClient, MF_BYCOMMAND|MF_GRAYED },
\r
7235 { IDM_Accept, MF_BYCOMMAND|MF_GRAYED },
\r
7236 { IDM_Decline, MF_BYCOMMAND|MF_GRAYED },
\r
7237 { IDM_Rematch, MF_BYCOMMAND|MF_GRAYED },
\r
7238 { IDM_Adjourn, MF_BYCOMMAND|MF_GRAYED },
\r
7239 { IDM_StopExamining, MF_BYCOMMAND|MF_GRAYED },
\r
7240 { IDM_StopObserving, MF_BYCOMMAND|MF_GRAYED },
\r
7241 { IDM_Revert, MF_BYCOMMAND|MF_GRAYED },
\r
7242 { IDM_NewChat, MF_BYCOMMAND|MF_GRAYED },
\r
7246 Enables icsEnables[] = {
\r
7247 { IDM_MailMove, MF_BYCOMMAND|MF_GRAYED },
\r
7248 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_GRAYED },
\r
7249 { IDM_MachineWhite, MF_BYCOMMAND|MF_GRAYED },
\r
7250 { IDM_MachineBlack, MF_BYCOMMAND|MF_GRAYED },
\r
7251 { IDM_TwoMachines, MF_BYCOMMAND|MF_GRAYED },
\r
7252 { IDM_MachineBoth, MF_BYCOMMAND|MF_GRAYED },
\r
7253 { IDM_AnalysisMode, MF_BYCOMMAND|MF_ENABLED },
\r
7254 { IDM_AnalyzeFile, MF_BYCOMMAND|MF_GRAYED },
\r
7255 { IDM_TimeControl, MF_BYCOMMAND|MF_GRAYED },
\r
7256 { IDM_MoveNow, MF_BYCOMMAND|MF_GRAYED },
\r
7257 { IDM_Hint, MF_BYCOMMAND|MF_GRAYED },
\r
7258 { IDM_Book, MF_BYCOMMAND|MF_GRAYED },
\r
7259 { IDM_IcsOptions, MF_BYCOMMAND|MF_ENABLED },
\r
7260 { IDM_Engine1Options, MF_BYCOMMAND|MF_GRAYED },
\r
7261 { IDM_Engine2Options, MF_BYCOMMAND|MF_GRAYED },
\r
7266 Enables zippyEnables[] = {
\r
7267 { IDM_MoveNow, MF_BYCOMMAND|MF_ENABLED },
\r
7268 { IDM_Hint, MF_BYCOMMAND|MF_ENABLED },
\r
7269 { IDM_Book, MF_BYCOMMAND|MF_ENABLED },
\r
7270 { IDM_Engine1Options, MF_BYCOMMAND|MF_ENABLED },
\r
7275 Enables ncpEnables[] = {
\r
7276 { IDM_MailMove, MF_BYCOMMAND|MF_GRAYED },
\r
7277 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_GRAYED },
\r
7278 { IDM_MachineWhite, MF_BYCOMMAND|MF_GRAYED },
\r
7279 { IDM_MachineBlack, MF_BYCOMMAND|MF_GRAYED },
\r
7280 { IDM_TwoMachines, MF_BYCOMMAND|MF_GRAYED },
\r
7281 { IDM_AnalysisMode, MF_BYCOMMAND|MF_GRAYED },
\r
7282 { IDM_AnalyzeFile, MF_BYCOMMAND|MF_GRAYED },
\r
7283 { IDM_IcsClient, MF_BYCOMMAND|MF_GRAYED },
\r
7284 { ACTION_POS, MF_BYPOSITION|MF_GRAYED },
\r
7285 { IDM_Revert, MF_BYCOMMAND|MF_GRAYED },
\r
7286 { IDM_MoveNow, MF_BYCOMMAND|MF_GRAYED },
\r
7287 { IDM_RetractMove, MF_BYCOMMAND|MF_GRAYED },
\r
7288 { IDM_TimeControl, MF_BYCOMMAND|MF_GRAYED },
\r
7289 { IDM_Hint, MF_BYCOMMAND|MF_GRAYED },
\r
7290 { IDM_Book, MF_BYCOMMAND|MF_GRAYED },
\r
7291 { IDM_MachineBoth, MF_BYCOMMAND|MF_GRAYED },
\r
7292 { IDM_NewChat, MF_BYCOMMAND|MF_GRAYED },
\r
7293 { IDM_Engine1Options, MF_BYCOMMAND|MF_GRAYED },
\r
7294 { IDM_Engine2Options, MF_BYCOMMAND|MF_GRAYED },
\r
7298 Enables trainingOnEnables[] = {
\r
7299 { IDM_EditComment, MF_BYCOMMAND|MF_GRAYED },
\r
7300 { IDM_Pause, MF_BYCOMMAND|MF_GRAYED },
\r
7301 { IDM_Forward, MF_BYCOMMAND|MF_GRAYED },
\r
7302 { IDM_Backward, MF_BYCOMMAND|MF_GRAYED },
\r
7303 { IDM_ToEnd, MF_BYCOMMAND|MF_GRAYED },
\r
7304 { IDM_ToStart, MF_BYCOMMAND|MF_GRAYED },
\r
7305 { IDM_MoveNow, MF_BYCOMMAND|MF_GRAYED },
\r
7306 { IDM_TruncateGame, MF_BYCOMMAND|MF_GRAYED },
\r
7310 Enables trainingOffEnables[] = {
\r
7311 { IDM_EditComment, MF_BYCOMMAND|MF_ENABLED },
\r
7312 { IDM_Pause, MF_BYCOMMAND|MF_ENABLED },
\r
7313 { IDM_Forward, MF_BYCOMMAND|MF_ENABLED },
\r
7314 { IDM_Backward, MF_BYCOMMAND|MF_ENABLED },
\r
7315 { IDM_ToEnd, MF_BYCOMMAND|MF_ENABLED },
\r
7316 { IDM_ToStart, MF_BYCOMMAND|MF_ENABLED },
\r
7317 { IDM_MoveNow, MF_BYCOMMAND|MF_ENABLED },
\r
7318 { IDM_TruncateGame, MF_BYCOMMAND|MF_ENABLED },
\r
7322 /* These modify either ncpEnables or gnuEnables */
\r
7323 Enables cmailEnables[] = {
\r
7324 { IDM_MailMove, MF_BYCOMMAND|MF_ENABLED },
\r
7325 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_ENABLED },
\r
7326 { ACTION_POS, MF_BYPOSITION|MF_ENABLED },
\r
7327 { IDM_CallFlag, MF_BYCOMMAND|MF_GRAYED },
\r
7328 { IDM_Draw, MF_BYCOMMAND|MF_ENABLED },
\r
7329 { IDM_Adjourn, MF_BYCOMMAND|MF_GRAYED },
\r
7330 { IDM_Abort, MF_BYCOMMAND|MF_GRAYED },
\r
7334 Enables machineThinkingEnables[] = {
\r
7335 { IDM_LoadGame, MF_BYCOMMAND|MF_GRAYED },
\r
7336 { IDM_LoadNextGame, MF_BYCOMMAND|MF_GRAYED },
\r
7337 { IDM_LoadPrevGame, MF_BYCOMMAND|MF_GRAYED },
\r
7338 { IDM_ReloadGame, MF_BYCOMMAND|MF_GRAYED },
\r
7339 { IDM_PasteGame, MF_BYCOMMAND|MF_GRAYED },
\r
7340 { IDM_LoadPosition, MF_BYCOMMAND|MF_GRAYED },
\r
7341 { IDM_LoadNextPosition, MF_BYCOMMAND|MF_GRAYED },
\r
7342 { IDM_LoadPrevPosition, MF_BYCOMMAND|MF_GRAYED },
\r
7343 { IDM_ReloadPosition, MF_BYCOMMAND|MF_GRAYED },
\r
7344 { IDM_PastePosition, MF_BYCOMMAND|MF_GRAYED },
\r
7345 { IDM_MachineWhite, MF_BYCOMMAND|MF_GRAYED },
\r
7346 { IDM_MachineBlack, MF_BYCOMMAND|MF_GRAYED },
\r
7347 { IDM_TwoMachines, MF_BYCOMMAND|MF_GRAYED },
\r
7348 { IDM_TypeInMove, MF_BYCOMMAND|MF_GRAYED },
\r
7349 { IDM_RetractMove, MF_BYCOMMAND|MF_GRAYED },
\r
7353 Enables userThinkingEnables[] = {
\r
7354 { IDM_LoadGame, MF_BYCOMMAND|MF_ENABLED },
\r
7355 { IDM_LoadNextGame, MF_BYCOMMAND|MF_ENABLED },
\r
7356 { IDM_LoadPrevGame, MF_BYCOMMAND|MF_ENABLED },
\r
7357 { IDM_ReloadGame, MF_BYCOMMAND|MF_ENABLED },
\r
7358 { IDM_PasteGame, MF_BYCOMMAND|MF_ENABLED },
\r
7359 { IDM_LoadPosition, MF_BYCOMMAND|MF_ENABLED },
\r
7360 { IDM_LoadNextPosition, MF_BYCOMMAND|MF_ENABLED },
\r
7361 { IDM_LoadPrevPosition, MF_BYCOMMAND|MF_ENABLED },
\r
7362 { IDM_ReloadPosition, MF_BYCOMMAND|MF_ENABLED },
\r
7363 { IDM_PastePosition, MF_BYCOMMAND|MF_ENABLED },
\r
7364 { IDM_MachineWhite, MF_BYCOMMAND|MF_ENABLED },
\r
7365 { IDM_MachineBlack, MF_BYCOMMAND|MF_ENABLED },
\r
7366 { IDM_TwoMachines, MF_BYCOMMAND|MF_ENABLED },
\r
7367 { IDM_TypeInMove, MF_BYCOMMAND|MF_ENABLED },
\r
7368 { IDM_RetractMove, MF_BYCOMMAND|MF_ENABLED },
\r
7372 /*---------------------------------------------------------------------------*\
\r
7374 * Front-end interface functions exported by XBoard.
\r
7375 * Functions appear in same order as prototypes in frontend.h.
\r
7377 \*---------------------------------------------------------------------------*/
\r
7381 static UINT prevChecked = 0;
\r
7382 static int prevPausing = 0;
\r
7385 if (pausing != prevPausing) {
\r
7386 prevPausing = pausing;
\r
7387 (void) CheckMenuItem(GetMenu(hwndMain), IDM_Pause,
\r
7388 MF_BYCOMMAND|(pausing ? MF_CHECKED : MF_UNCHECKED));
\r
7389 if (hwndPause) SetWindowText(hwndPause, pausing ? "C" : "P");
\r
7392 switch (gameMode) {
\r
7393 case BeginningOfGame:
\r
7394 if (appData.icsActive)
\r
7395 nowChecked = IDM_IcsClient;
\r
7396 else if (appData.noChessProgram)
\r
7397 nowChecked = IDM_EditGame;
\r
7399 nowChecked = IDM_MachineBlack;
\r
7401 case MachinePlaysBlack:
\r
7402 nowChecked = IDM_MachineBlack;
\r
7404 case MachinePlaysWhite:
\r
7405 nowChecked = IDM_MachineWhite;
\r
7407 case TwoMachinesPlay:
\r
7408 nowChecked = IDM_TwoMachines;
\r
7411 nowChecked = IDM_AnalysisMode;
\r
7414 nowChecked = IDM_AnalyzeFile;
\r
7417 nowChecked = IDM_EditGame;
\r
7419 case PlayFromGameFile:
\r
7420 nowChecked = IDM_LoadGame;
\r
7422 case EditPosition:
\r
7423 nowChecked = IDM_EditPosition;
\r
7426 nowChecked = IDM_Training;
\r
7428 case IcsPlayingWhite:
\r
7429 case IcsPlayingBlack:
\r
7430 case IcsObserving:
\r
7432 nowChecked = IDM_IcsClient;
\r
7439 if (prevChecked != 0)
\r
7440 (void) CheckMenuItem(GetMenu(hwndMain),
\r
7441 prevChecked, MF_BYCOMMAND|MF_UNCHECKED);
\r
7442 if (nowChecked != 0)
\r
7443 (void) CheckMenuItem(GetMenu(hwndMain),
\r
7444 nowChecked, MF_BYCOMMAND|MF_CHECKED);
\r
7446 if (nowChecked == IDM_LoadGame || nowChecked == IDM_Training) {
\r
7447 (void) EnableMenuItem(GetMenu(hwndMain), IDM_Training,
\r
7448 MF_BYCOMMAND|MF_ENABLED);
\r
7450 (void) EnableMenuItem(GetMenu(hwndMain),
\r
7451 IDM_Training, MF_BYCOMMAND|MF_GRAYED);
\r
7454 prevChecked = nowChecked;
\r
7456 /* [DM] icsEngineAnalyze - Do a sceure check too */
\r
7457 if (appData.icsActive) {
\r
7458 if (appData.icsEngineAnalyze) {
\r
7459 (void) CheckMenuItem(GetMenu(hwndMain), IDM_AnalysisMode,
\r
7460 MF_BYCOMMAND|MF_CHECKED);
\r
7462 (void) CheckMenuItem(GetMenu(hwndMain), IDM_AnalysisMode,
\r
7463 MF_BYCOMMAND|MF_UNCHECKED);
\r
7471 HMENU hmenu = GetMenu(hwndMain);
\r
7472 SetMenuEnables(hmenu, icsEnables);
\r
7473 EnableMenuItem(GetSubMenu(hmenu, OPTIONS_POS), ICS_POS,
\r
7474 MF_BYPOSITION|MF_ENABLED);
\r
7476 if (appData.zippyPlay) {
\r
7477 SetMenuEnables(hmenu, zippyEnables);
\r
7478 if (!appData.noChessProgram) /* [DM] icsEngineAnalyze */
\r
7479 (void) EnableMenuItem(GetMenu(hwndMain), IDM_AnalysisMode,
\r
7480 MF_BYCOMMAND|MF_ENABLED);
\r
7488 SetMenuEnables(GetMenu(hwndMain), gnuEnables);
\r
7494 HMENU hmenu = GetMenu(hwndMain);
\r
7495 SetMenuEnables(hmenu, ncpEnables);
\r
7496 EnableMenuItem(GetSubMenu(hmenu, OPTIONS_POS), SOUNDS_POS,
\r
7497 MF_BYPOSITION|MF_GRAYED);
\r
7498 DrawMenuBar(hwndMain);
\r
7504 SetMenuEnables(GetMenu(hwndMain), cmailEnables);
\r
7508 SetTrainingModeOn()
\r
7511 SetMenuEnables(GetMenu(hwndMain), trainingOnEnables);
\r
7512 for (i = 0; i < N_BUTTONS; i++) {
\r
7513 if (buttonDesc[i].hwnd != NULL)
\r
7514 EnableWindow(buttonDesc[i].hwnd, FALSE);
\r
7519 VOID SetTrainingModeOff()
\r
7522 SetMenuEnables(GetMenu(hwndMain), trainingOffEnables);
\r
7523 for (i = 0; i < N_BUTTONS; i++) {
\r
7524 if (buttonDesc[i].hwnd != NULL)
\r
7525 EnableWindow(buttonDesc[i].hwnd, TRUE);
\r
7531 SetUserThinkingEnables()
\r
7533 SetMenuEnables(GetMenu(hwndMain), userThinkingEnables);
\r
7537 SetMachineThinkingEnables()
\r
7539 HMENU hMenu = GetMenu(hwndMain);
\r
7540 int flags = MF_BYCOMMAND|MF_ENABLED;
\r
7542 SetMenuEnables(hMenu, machineThinkingEnables);
\r
7544 if (gameMode == MachinePlaysBlack) {
\r
7545 (void)EnableMenuItem(hMenu, IDM_MachineBlack, flags);
\r
7546 } else if (gameMode == MachinePlaysWhite) {
\r
7547 (void)EnableMenuItem(hMenu, IDM_MachineWhite, flags);
\r
7548 } else if (gameMode == TwoMachinesPlay) {
\r
7549 (void)EnableMenuItem(hMenu, IDM_TwoMachines, flags);
\r
7555 DisplayTitle(char *str)
\r
7557 char title[MSG_SIZ], *host;
\r
7558 if (str[0] != NULLCHAR) {
\r
7559 strcpy(title, str);
\r
7560 } else if (appData.icsActive) {
\r
7561 if (appData.icsCommPort[0] != NULLCHAR)
\r
7564 host = appData.icsHost;
\r
7565 sprintf(title, "%s: %s", szTitle, host);
\r
7566 } else if (appData.noChessProgram) {
\r
7567 strcpy(title, szTitle);
\r
7569 strcpy(title, szTitle);
\r
7570 strcat(title, ": ");
\r
7571 strcat(title, first.tidy);
\r
7573 SetWindowText(hwndMain, title);
\r
7578 DisplayMessage(char *str1, char *str2)
\r
7582 int remain = MESSAGE_TEXT_MAX - 1;
\r
7585 moveErrorMessageUp = FALSE; /* turned on later by caller if needed */
\r
7586 messageText[0] = NULLCHAR;
\r
7588 len = strlen(str1);
\r
7589 if (len > remain) len = remain;
\r
7590 strncpy(messageText, str1, len);
\r
7591 messageText[len] = NULLCHAR;
\r
7594 if (*str2 && remain >= 2) {
\r
7596 strcat(messageText, " ");
\r
7599 len = strlen(str2);
\r
7600 if (len > remain) len = remain;
\r
7601 strncat(messageText, str2, len);
\r
7603 messageText[MESSAGE_TEXT_MAX - 1] = NULLCHAR;
\r
7605 if (hwndMain == NULL || IsIconic(hwndMain)) return;
\r
7609 hdc = GetDC(hwndMain);
\r
7610 oldFont = SelectObject(hdc, font[boardSize][MESSAGE_FONT]->hf);
\r
7611 ExtTextOut(hdc, messageRect.left, messageRect.top, ETO_CLIPPED|ETO_OPAQUE,
\r
7612 &messageRect, messageText, strlen(messageText), NULL);
\r
7613 (void) SelectObject(hdc, oldFont);
\r
7614 (void) ReleaseDC(hwndMain, hdc);
\r
7618 DisplayError(char *str, int error)
\r
7620 char buf[MSG_SIZ*2], buf2[MSG_SIZ];
\r
7626 len = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
\r
7627 NULL, error, LANG_NEUTRAL,
\r
7628 (LPSTR) buf2, MSG_SIZ, NULL);
\r
7630 sprintf(buf, "%s:\n%s", str, buf2);
\r
7632 ErrorMap *em = errmap;
\r
7633 while (em->err != 0 && em->err != error) em++;
\r
7634 if (em->err != 0) {
\r
7635 sprintf(buf, "%s:\n%s", str, em->msg);
\r
7637 sprintf(buf, "%s:\nError code %d", str, error);
\r
7642 ErrorPopUp("Error", buf);
\r
7647 DisplayMoveError(char *str)
\r
7649 fromX = fromY = -1;
\r
7650 ClearHighlights();
\r
7651 DrawPosition(FALSE, NULL);
\r
7652 if (appData.popupMoveErrors) {
\r
7653 ErrorPopUp("Error", str);
\r
7655 DisplayMessage(str, "");
\r
7656 moveErrorMessageUp = TRUE;
\r
7661 DisplayFatalError(char *str, int error, int exitStatus)
\r
7663 char buf[2*MSG_SIZ], buf2[MSG_SIZ];
\r
7665 char *label = exitStatus ? "Fatal Error" : "Exiting";
\r
7668 len = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
\r
7669 NULL, error, LANG_NEUTRAL,
\r
7670 (LPSTR) buf2, MSG_SIZ, NULL);
\r
7672 sprintf(buf, "%s:\n%s", str, buf2);
\r
7674 ErrorMap *em = errmap;
\r
7675 while (em->err != 0 && em->err != error) em++;
\r
7676 if (em->err != 0) {
\r
7677 sprintf(buf, "%s:\n%s", str, em->msg);
\r
7679 sprintf(buf, "%s:\nError code %d", str, error);
\r
7684 if (appData.debugMode) {
\r
7685 fprintf(debugFP, "%s: %s\n", label, str);
\r
7687 if (appData.popupExitMessage) {
\r
7688 (void) MessageBox(hwndMain, str, label, MB_OK|
\r
7689 (exitStatus ? MB_ICONSTOP : MB_ICONINFORMATION));
\r
7691 ExitEvent(exitStatus);
\r
7696 DisplayInformation(char *str)
\r
7698 (void) MessageBox(hwndMain, str, "Information", MB_OK|MB_ICONINFORMATION);
\r
7703 DisplayNote(char *str)
\r
7705 ErrorPopUp("Note", str);
\r
7710 char *title, *question, *replyPrefix;
\r
7715 QuestionDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7717 static QuestionParams *qp;
\r
7718 char reply[MSG_SIZ];
\r
7721 switch (message) {
\r
7722 case WM_INITDIALOG:
\r
7723 qp = (QuestionParams *) lParam;
\r
7724 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
7725 SetWindowText(hDlg, qp->title);
\r
7726 SetDlgItemText(hDlg, OPT_QuestionText, qp->question);
\r
7727 SetFocus(GetDlgItem(hDlg, OPT_QuestionInput));
\r
7731 switch (LOWORD(wParam)) {
\r
7733 strcpy(reply, qp->replyPrefix);
\r
7734 if (*reply) strcat(reply, " ");
\r
7735 len = strlen(reply);
\r
7736 GetDlgItemText(hDlg, OPT_QuestionInput, reply + len, sizeof(reply) - len);
\r
7737 strcat(reply, "\n");
\r
7738 OutputToProcess(qp->pr, reply, strlen(reply), &err);
\r
7739 EndDialog(hDlg, TRUE);
\r
7740 if (err) DisplayFatalError("Error writing to chess program", err, 1);
\r
7743 EndDialog(hDlg, FALSE);
\r
7754 AskQuestion(char* title, char *question, char *replyPrefix, ProcRef pr)
\r
7756 QuestionParams qp;
\r
7760 qp.question = question;
\r
7761 qp.replyPrefix = replyPrefix;
\r
7763 lpProc = MakeProcInstance((FARPROC)QuestionDialog, hInst);
\r
7764 DialogBoxParam(hInst, MAKEINTRESOURCE(DLG_Question),
\r
7765 hwndMain, (DLGPROC)lpProc, (LPARAM)&qp);
\r
7766 FreeProcInstance(lpProc);
\r
7769 /* [AS] Pick FRC position */
\r
7770 LRESULT CALLBACK NewGameFRC_Proc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7772 static int * lpIndexFRC;
\r
7778 case WM_INITDIALOG:
\r
7779 lpIndexFRC = (int *) lParam;
\r
7781 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
7783 SendDlgItemMessage( hDlg, IDC_NFG_Edit, EM_SETLIMITTEXT, sizeof(buf)-1, 0 );
\r
7784 SetDlgItemInt( hDlg, IDC_NFG_Edit, *lpIndexFRC, TRUE );
\r
7785 SendDlgItemMessage( hDlg, IDC_NFG_Edit, EM_SETSEL, 0, -1 );
\r
7786 SetFocus(GetDlgItem(hDlg, IDC_NFG_Edit));
\r
7791 switch( LOWORD(wParam) ) {
\r
7793 *lpIndexFRC = GetDlgItemInt(hDlg, IDC_NFG_Edit, &index_is_ok, TRUE );
\r
7794 EndDialog( hDlg, 0 );
\r
7795 shuffleOpenings = TRUE; /* [HGM] shuffle: switch shuffling on for as long as we stay in current variant */
\r
7798 EndDialog( hDlg, 1 );
\r
7800 case IDC_NFG_Edit:
\r
7801 if( HIWORD(wParam) == EN_CHANGE ) {
\r
7802 GetDlgItemInt(hDlg, IDC_NFG_Edit, &index_is_ok, TRUE );
\r
7804 EnableWindow( GetDlgItem(hDlg, IDOK), index_is_ok );
\r
7807 case IDC_NFG_Random:
\r
7808 sprintf( buf, "%d", myrandom() ); /* [HGM] shuffle: no longer limit to 960 */
\r
7809 SetDlgItemText(hDlg, IDC_NFG_Edit, buf );
\r
7822 int index = appData.defaultFrcPosition;
\r
7823 FARPROC lpProc = MakeProcInstance( (FARPROC) NewGameFRC_Proc, hInst );
\r
7825 result = DialogBoxParam( hInst, MAKEINTRESOURCE(DLG_NewGameFRC), hwndMain, (DLGPROC)lpProc, (LPARAM)&index );
\r
7827 if( result == 0 ) {
\r
7828 appData.defaultFrcPosition = index;
\r
7834 /* [AS] Game list options */
\r
7840 static GLT_Item GLT_ItemInfo[] = {
\r
7841 { GLT_EVENT, "Event" },
\r
7842 { GLT_SITE, "Site" },
\r
7843 { GLT_DATE, "Date" },
\r
7844 { GLT_ROUND, "Round" },
\r
7845 { GLT_PLAYERS, "Players" },
\r
7846 { GLT_RESULT, "Result" },
\r
7847 { GLT_WHITE_ELO, "White Rating" },
\r
7848 { GLT_BLACK_ELO, "Black Rating" },
\r
7849 { GLT_TIME_CONTROL,"Time Control" },
\r
7850 { GLT_VARIANT, "Variant" },
\r
7851 { GLT_OUT_OF_BOOK,PGN_OUT_OF_BOOK },
\r
7852 { GLT_RESULT_COMMENT, "Result Comment" }, // [HGM] rescom
\r
7856 const char * GLT_FindItem( char id )
\r
7858 const char * result = 0;
\r
7860 GLT_Item * list = GLT_ItemInfo;
\r
7862 while( list->id != 0 ) {
\r
7863 if( list->id == id ) {
\r
7864 result = list->name;
\r
7874 void GLT_AddToList( HWND hDlg, int iDlgItem, char id, int index )
\r
7876 const char * name = GLT_FindItem( id );
\r
7879 if( index >= 0 ) {
\r
7880 SendDlgItemMessage( hDlg, iDlgItem, LB_INSERTSTRING, index, (LPARAM) name );
\r
7883 SendDlgItemMessage( hDlg, iDlgItem, LB_ADDSTRING, 0, (LPARAM) name );
\r
7888 void GLT_TagsToList( HWND hDlg, char * tags )
\r
7892 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_RESETCONTENT, 0, 0 );
\r
7895 GLT_AddToList( hDlg, IDC_GameListTags, *pc, -1 );
\r
7899 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_ADDSTRING, 0, (LPARAM) "\t --- Hidden tags ---" );
\r
7901 pc = GLT_ALL_TAGS;
\r
7904 if( strchr( tags, *pc ) == 0 ) {
\r
7905 GLT_AddToList( hDlg, IDC_GameListTags, *pc, -1 );
\r
7910 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_SETCURSEL, 0, 0 );
\r
7913 char GLT_ListItemToTag( HWND hDlg, int index )
\r
7915 char result = '\0';
\r
7918 GLT_Item * list = GLT_ItemInfo;
\r
7920 if( SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETTEXT, index, (LPARAM) name ) != LB_ERR ) {
\r
7921 while( list->id != 0 ) {
\r
7922 if( strcmp( list->name, name ) == 0 ) {
\r
7923 result = list->id;
\r
7934 void GLT_MoveSelection( HWND hDlg, int delta )
\r
7936 int idx1 = (int) SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETCURSEL, 0, 0 );
\r
7937 int idx2 = idx1 + delta;
\r
7938 int count = (int) SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETCOUNT, 0, 0 );
\r
7940 if( idx1 >=0 && idx1 < count && idx2 >= 0 && idx2 < count ) {
\r
7943 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETTEXT, idx1, (LPARAM) buf );
\r
7944 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_DELETESTRING, idx1, 0 );
\r
7945 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_INSERTSTRING, idx2, (LPARAM) buf );
\r
7946 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_SETCURSEL, idx2, 0 );
\r
7950 LRESULT CALLBACK GameListOptions_Proc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7952 static char glt[64];
\r
7953 static char * lpUserGLT;
\r
7957 case WM_INITDIALOG:
\r
7958 lpUserGLT = (char *) lParam;
\r
7960 strcpy( glt, lpUserGLT );
\r
7962 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
7964 /* Initialize list */
\r
7965 GLT_TagsToList( hDlg, glt );
\r
7967 SetFocus( GetDlgItem(hDlg, IDC_GameListTags) );
\r
7972 switch( LOWORD(wParam) ) {
\r
7975 char * pc = lpUserGLT;
\r
7977 // int cnt = (int) SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETCOUNT, 0, 0 );
\r
7981 id = GLT_ListItemToTag( hDlg, idx );
\r
7985 } while( id != '\0' );
\r
7987 EndDialog( hDlg, 0 );
\r
7990 EndDialog( hDlg, 1 );
\r
7993 case IDC_GLT_Default:
\r
7994 strcpy( glt, GLT_DEFAULT_TAGS );
\r
7995 GLT_TagsToList( hDlg, glt );
\r
7998 case IDC_GLT_Restore:
\r
7999 strcpy( glt, lpUserGLT );
\r
8000 GLT_TagsToList( hDlg, glt );
\r
8004 GLT_MoveSelection( hDlg, -1 );
\r
8007 case IDC_GLT_Down:
\r
8008 GLT_MoveSelection( hDlg, +1 );
\r
8018 int GameListOptions()
\r
8022 FARPROC lpProc = MakeProcInstance( (FARPROC) GameListOptions_Proc, hInst );
\r
8024 strcpy( glt, appData.gameListTags );
\r
8026 result = DialogBoxParam( hInst, MAKEINTRESOURCE(DLG_GameListOptions), hwndMain, (DLGPROC)lpProc, (LPARAM)glt );
\r
8028 if( result == 0 ) {
\r
8029 /* [AS] Memory leak here! */
\r
8030 appData.gameListTags = strdup( glt );
\r
8038 DisplayIcsInteractionTitle(char *str)
\r
8040 char consoleTitle[MSG_SIZ];
\r
8042 sprintf(consoleTitle, "%s: %s", szConsoleTitle, str);
\r
8043 SetWindowText(hwndConsole, consoleTitle);
\r
8047 DrawPosition(int fullRedraw, Board board)
\r
8049 HDCDrawPosition(NULL, (BOOLEAN) fullRedraw, board);
\r
8052 void NotifyFrontendLogin()
\r
8055 UpdateICSWidth(GetDlgItem(hwndConsole, OPT_ConsoleText));
\r
8061 fromX = fromY = -1;
\r
8062 if (dragInfo.pos.x != -1 || dragInfo.pos.y != -1) {
\r
8063 dragInfo.pos.x = dragInfo.pos.y = -1;
\r
8064 dragInfo.pos.x = dragInfo.pos.y = -1;
\r
8065 dragInfo.lastpos = dragInfo.pos;
\r
8066 dragInfo.start.x = dragInfo.start.y = -1;
\r
8067 dragInfo.from = dragInfo.start;
\r
8069 DrawPosition(TRUE, NULL);
\r
8075 CommentPopUp(char *title, char *str)
\r
8077 HWND hwnd = GetActiveWindow();
\r
8078 EitherCommentPopUp(0, title, str, FALSE);
\r
8080 SetActiveWindow(hwnd);
\r
8084 CommentPopDown(void)
\r
8086 CheckMenuItem(GetMenu(hwndMain), IDM_EditComment, MF_UNCHECKED);
\r
8087 if (commentDialog) {
\r
8088 ShowWindow(commentDialog, SW_HIDE);
\r
8090 commentUp = FALSE;
\r
8094 EditCommentPopUp(int index, char *title, char *str)
\r
8096 EitherCommentPopUp(index, title, str, TRUE);
\r
8103 MyPlaySound(&sounds[(int)SoundMove]);
\r
8106 VOID PlayIcsWinSound()
\r
8108 MyPlaySound(&sounds[(int)SoundIcsWin]);
\r
8111 VOID PlayIcsLossSound()
\r
8113 MyPlaySound(&sounds[(int)SoundIcsLoss]);
\r
8116 VOID PlayIcsDrawSound()
\r
8118 MyPlaySound(&sounds[(int)SoundIcsDraw]);
\r
8121 VOID PlayIcsUnfinishedSound()
\r
8123 MyPlaySound(&sounds[(int)SoundIcsUnfinished]);
\r
8129 MyPlaySound(&sounds[(int)SoundAlarm]);
\r
8137 consoleEcho = TRUE;
\r
8138 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
8139 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&consoleCF);
\r
8140 SendMessage(hInput, EM_SETBKGNDCOLOR, FALSE, consoleBackgroundColor);
\r
8149 consoleEcho = FALSE;
\r
8150 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
8151 /* This works OK: set text and background both to the same color */
\r
8153 cf.crTextColor = COLOR_ECHOOFF;
\r
8154 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&cf);
\r
8155 SendMessage(hInput, EM_SETBKGNDCOLOR, FALSE, cf.crTextColor);
\r
8158 /* No Raw()...? */
\r
8160 void Colorize(ColorClass cc, int continuation)
\r
8162 currentColorClass = cc;
\r
8163 consoleCF.dwMask = CFM_COLOR|CFM_BOLD|CFM_ITALIC|CFM_UNDERLINE|CFM_STRIKEOUT;
\r
8164 consoleCF.crTextColor = textAttribs[cc].color;
\r
8165 consoleCF.dwEffects = textAttribs[cc].effects;
\r
8166 if (!continuation) MyPlaySound(&textAttribs[cc].sound);
\r
8172 static char buf[MSG_SIZ];
\r
8173 DWORD bufsiz = MSG_SIZ;
\r
8175 if(appData.userName != NULL && appData.userName[0] != 0) {
\r
8176 return appData.userName; /* [HGM] username: prefer name selected by user over his system login */
\r
8178 if (!GetUserName(buf, &bufsiz)) {
\r
8179 /*DisplayError("Error getting user name", GetLastError());*/
\r
8180 strcpy(buf, "User");
\r
8188 static char buf[MSG_SIZ];
\r
8189 DWORD bufsiz = MSG_SIZ;
\r
8191 if (!GetComputerName(buf, &bufsiz)) {
\r
8192 /*DisplayError("Error getting host name", GetLastError());*/
\r
8193 strcpy(buf, "Unknown");
\r
8200 ClockTimerRunning()
\r
8202 return clockTimerEvent != 0;
\r
8208 if (clockTimerEvent == 0) return FALSE;
\r
8209 KillTimer(hwndMain, clockTimerEvent);
\r
8210 clockTimerEvent = 0;
\r
8215 StartClockTimer(long millisec)
\r
8217 clockTimerEvent = SetTimer(hwndMain, (UINT) CLOCK_TIMER_ID,
\r
8218 (UINT) millisec, NULL);
\r
8222 DisplayWhiteClock(long timeRemaining, int highlight)
\r
8225 char *flag = whiteFlag && gameMode == TwoMachinesPlay ? "(!)" : "";
\r
8227 if(appData.noGUI) return;
\r
8228 hdc = GetDC(hwndMain);
\r
8229 if (!IsIconic(hwndMain)) {
\r
8230 DisplayAClock(hdc, timeRemaining, highlight,
\r
8231 flipClock ? &blackRect : &whiteRect, "White", flag);
\r
8233 if (highlight && iconCurrent == iconBlack) {
\r
8234 iconCurrent = iconWhite;
\r
8235 PostMessage(hwndMain, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
8236 if (IsIconic(hwndMain)) {
\r
8237 DrawIcon(hdc, 2, 2, iconCurrent);
\r
8240 (void) ReleaseDC(hwndMain, hdc);
\r
8242 PostMessage(hwndConsole, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
8246 DisplayBlackClock(long timeRemaining, int highlight)
\r
8249 char *flag = blackFlag && gameMode == TwoMachinesPlay ? "(!)" : "";
\r
8251 if(appData.noGUI) return;
\r
8252 hdc = GetDC(hwndMain);
\r
8253 if (!IsIconic(hwndMain)) {
\r
8254 DisplayAClock(hdc, timeRemaining, highlight,
\r
8255 flipClock ? &whiteRect : &blackRect, "Black", flag);
\r
8257 if (highlight && iconCurrent == iconWhite) {
\r
8258 iconCurrent = iconBlack;
\r
8259 PostMessage(hwndMain, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
8260 if (IsIconic(hwndMain)) {
\r
8261 DrawIcon(hdc, 2, 2, iconCurrent);
\r
8264 (void) ReleaseDC(hwndMain, hdc);
\r
8266 PostMessage(hwndConsole, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
8271 LoadGameTimerRunning()
\r
8273 return loadGameTimerEvent != 0;
\r
8277 StopLoadGameTimer()
\r
8279 if (loadGameTimerEvent == 0) return FALSE;
\r
8280 KillTimer(hwndMain, loadGameTimerEvent);
\r
8281 loadGameTimerEvent = 0;
\r
8286 StartLoadGameTimer(long millisec)
\r
8288 loadGameTimerEvent = SetTimer(hwndMain, (UINT) LOAD_GAME_TIMER_ID,
\r
8289 (UINT) millisec, NULL);
\r
8297 char fileTitle[MSG_SIZ];
\r
8299 defName = DefaultFileName(appData.oldSaveStyle ? "gam" : "pgn");
\r
8300 f = OpenFileDialog(hwndMain, "a", defName,
\r
8301 appData.oldSaveStyle ? "gam" : "pgn",
\r
8303 "Save Game to File", NULL, fileTitle, NULL);
\r
8305 SaveGame(f, 0, "");
\r
8312 ScheduleDelayedEvent(DelayedEventCallback cb, long millisec)
\r
8314 if (delayedTimerEvent != 0) {
\r
8315 if (appData.debugMode && cb != delayedTimerCallback) { // [HGM] alive: not too much debug
\r
8316 fprintf(debugFP, "ScheduleDelayedEvent: event already scheduled\n");
\r
8318 KillTimer(hwndMain, delayedTimerEvent);
\r
8319 delayedTimerEvent = 0;
\r
8320 if(delayedTimerCallback != cb) // [HGM] alive: do not "flush" same event, just postpone it
\r
8321 delayedTimerCallback();
\r
8323 delayedTimerCallback = cb;
\r
8324 delayedTimerEvent = SetTimer(hwndMain, (UINT) DELAYED_TIMER_ID,
\r
8325 (UINT) millisec, NULL);
\r
8328 DelayedEventCallback
\r
8331 if (delayedTimerEvent) {
\r
8332 return delayedTimerCallback;
\r
8339 CancelDelayedEvent()
\r
8341 if (delayedTimerEvent) {
\r
8342 KillTimer(hwndMain, delayedTimerEvent);
\r
8343 delayedTimerEvent = 0;
\r
8347 DWORD GetWin32Priority(int nice)
\r
8348 { // [HGM] nice: translate Unix nice() value to indows priority class. (Code stolen from Polyglot 1.4w11)
\r
8350 REALTIME_PRIORITY_CLASS 0x00000100
\r
8351 HIGH_PRIORITY_CLASS 0x00000080
\r
8352 ABOVE_NORMAL_PRIORITY_CLASS 0x00008000
\r
8353 NORMAL_PRIORITY_CLASS 0x00000020
\r
8354 BELOW_NORMAL_PRIORITY_CLASS 0x00004000
\r
8355 IDLE_PRIORITY_CLASS 0x00000040
\r
8357 if (nice < -15) return 0x00000080;
\r
8358 if (nice < 0) return 0x00008000;
\r
8359 if (nice == 0) return 0x00000020;
\r
8360 if (nice < 15) return 0x00004000;
\r
8361 return 0x00000040;
\r
8364 /* Start a child process running the given program.
\r
8365 The process's standard output can be read from "from", and its
\r
8366 standard input can be written to "to".
\r
8367 Exit with fatal error if anything goes wrong.
\r
8368 Returns an opaque pointer that can be used to destroy the process
\r
8372 StartChildProcess(char *cmdLine, char *dir, ProcRef *pr)
\r
8374 #define BUFSIZE 4096
\r
8376 HANDLE hChildStdinRd, hChildStdinWr,
\r
8377 hChildStdoutRd, hChildStdoutWr;
\r
8378 HANDLE hChildStdinWrDup, hChildStdoutRdDup;
\r
8379 SECURITY_ATTRIBUTES saAttr;
\r
8381 PROCESS_INFORMATION piProcInfo;
\r
8382 STARTUPINFO siStartInfo;
\r
8384 char buf[MSG_SIZ];
\r
8387 if (appData.debugMode) {
\r
8388 fprintf(debugFP, "StartChildProcess (dir=\"%s\") %s\n", dir, cmdLine);
\r
8393 /* Set the bInheritHandle flag so pipe handles are inherited. */
\r
8394 saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
\r
8395 saAttr.bInheritHandle = TRUE;
\r
8396 saAttr.lpSecurityDescriptor = NULL;
\r
8399 * The steps for redirecting child's STDOUT:
\r
8400 * 1. Create anonymous pipe to be STDOUT for child.
\r
8401 * 2. Create a noninheritable duplicate of read handle,
\r
8402 * and close the inheritable read handle.
\r
8405 /* Create a pipe for the child's STDOUT. */
\r
8406 if (! CreatePipe(&hChildStdoutRd, &hChildStdoutWr, &saAttr, 0)) {
\r
8407 return GetLastError();
\r
8410 /* Duplicate the read handle to the pipe, so it is not inherited. */
\r
8411 fSuccess = DuplicateHandle(GetCurrentProcess(), hChildStdoutRd,
\r
8412 GetCurrentProcess(), &hChildStdoutRdDup, 0,
\r
8413 FALSE, /* not inherited */
\r
8414 DUPLICATE_SAME_ACCESS);
\r
8416 return GetLastError();
\r
8418 CloseHandle(hChildStdoutRd);
\r
8421 * The steps for redirecting child's STDIN:
\r
8422 * 1. Create anonymous pipe to be STDIN for child.
\r
8423 * 2. Create a noninheritable duplicate of write handle,
\r
8424 * and close the inheritable write handle.
\r
8427 /* Create a pipe for the child's STDIN. */
\r
8428 if (! CreatePipe(&hChildStdinRd, &hChildStdinWr, &saAttr, 0)) {
\r
8429 return GetLastError();
\r
8432 /* Duplicate the write handle to the pipe, so it is not inherited. */
\r
8433 fSuccess = DuplicateHandle(GetCurrentProcess(), hChildStdinWr,
\r
8434 GetCurrentProcess(), &hChildStdinWrDup, 0,
\r
8435 FALSE, /* not inherited */
\r
8436 DUPLICATE_SAME_ACCESS);
\r
8438 return GetLastError();
\r
8440 CloseHandle(hChildStdinWr);
\r
8442 /* Arrange to (1) look in dir for the child .exe file, and
\r
8443 * (2) have dir be the child's working directory. Interpret
\r
8444 * dir relative to the directory WinBoard loaded from. */
\r
8445 GetCurrentDirectory(MSG_SIZ, buf);
\r
8446 SetCurrentDirectory(installDir);
\r
8447 SetCurrentDirectory(dir);
\r
8449 /* Now create the child process. */
\r
8451 siStartInfo.cb = sizeof(STARTUPINFO);
\r
8452 siStartInfo.lpReserved = NULL;
\r
8453 siStartInfo.lpDesktop = NULL;
\r
8454 siStartInfo.lpTitle = NULL;
\r
8455 siStartInfo.dwFlags = STARTF_USESTDHANDLES;
\r
8456 siStartInfo.cbReserved2 = 0;
\r
8457 siStartInfo.lpReserved2 = NULL;
\r
8458 siStartInfo.hStdInput = hChildStdinRd;
\r
8459 siStartInfo.hStdOutput = hChildStdoutWr;
\r
8460 siStartInfo.hStdError = hChildStdoutWr;
\r
8462 fSuccess = CreateProcess(NULL,
\r
8463 cmdLine, /* command line */
\r
8464 NULL, /* process security attributes */
\r
8465 NULL, /* primary thread security attrs */
\r
8466 TRUE, /* handles are inherited */
\r
8467 DETACHED_PROCESS|CREATE_NEW_PROCESS_GROUP,
\r
8468 NULL, /* use parent's environment */
\r
8470 &siStartInfo, /* STARTUPINFO pointer */
\r
8471 &piProcInfo); /* receives PROCESS_INFORMATION */
\r
8473 err = GetLastError();
\r
8474 SetCurrentDirectory(buf); /* return to prev directory */
\r
8479 if (appData.niceEngines){ // [HGM] nice: adjust engine proc priority
\r
8480 if(appData.debugMode) fprintf(debugFP, "nice engine proc to %d\n", appData.niceEngines);
\r
8481 SetPriorityClass(piProcInfo.hProcess, GetWin32Priority(appData.niceEngines));
\r
8484 /* Close the handles we don't need in the parent */
\r
8485 CloseHandle(piProcInfo.hThread);
\r
8486 CloseHandle(hChildStdinRd);
\r
8487 CloseHandle(hChildStdoutWr);
\r
8489 /* Prepare return value */
\r
8490 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
8491 cp->kind = CPReal;
\r
8492 cp->hProcess = piProcInfo.hProcess;
\r
8493 cp->pid = piProcInfo.dwProcessId;
\r
8494 cp->hFrom = hChildStdoutRdDup;
\r
8495 cp->hTo = hChildStdinWrDup;
\r
8497 *pr = (void *) cp;
\r
8499 /* Klaus Friedel says that this Sleep solves a problem under Windows
\r
8500 2000 where engines sometimes don't see the initial command(s)
\r
8501 from WinBoard and hang. I don't understand how that can happen,
\r
8502 but the Sleep is harmless, so I've put it in. Others have also
\r
8503 reported what may be the same problem, so hopefully this will fix
\r
8504 it for them too. */
\r
8512 DestroyChildProcess(ProcRef pr, int/*boolean*/ signal)
\r
8514 ChildProc *cp; int result;
\r
8516 cp = (ChildProc *) pr;
\r
8517 if (cp == NULL) return;
\r
8519 switch (cp->kind) {
\r
8521 /* TerminateProcess is considered harmful, so... */
\r
8522 CloseHandle(cp->hTo); /* Closing this will give the child an EOF and hopefully kill it */
\r
8523 if (cp->hFrom) CloseHandle(cp->hFrom); /* if NULL, InputThread will close it */
\r
8524 /* The following doesn't work because the chess program
\r
8525 doesn't "have the same console" as WinBoard. Maybe
\r
8526 we could arrange for this even though neither WinBoard
\r
8527 nor the chess program uses a console for stdio? */
\r
8528 /*!!if (signal) GenerateConsoleCtrlEvent(CTRL_BREAK_EVENT, cp->pid);*/
\r
8530 /* [AS] Special termination modes for misbehaving programs... */
\r
8531 if( signal == 9 ) {
\r
8532 result = TerminateProcess( cp->hProcess, 0 );
\r
8534 if ( appData.debugMode) {
\r
8535 fprintf( debugFP, "Terminating process %lu, result=%d\n", cp->pid, result );
\r
8538 else if( signal == 10 ) {
\r
8539 DWORD dw = WaitForSingleObject( cp->hProcess, 3*1000 ); // Wait 3 seconds at most
\r
8541 if( dw != WAIT_OBJECT_0 ) {
\r
8542 result = TerminateProcess( cp->hProcess, 0 );
\r
8544 if ( appData.debugMode) {
\r
8545 fprintf( debugFP, "Process %lu still alive after timeout, killing... result=%d\n", cp->pid, result );
\r
8551 CloseHandle(cp->hProcess);
\r
8555 if (cp->hFrom) CloseHandle(cp->hFrom);
\r
8559 closesocket(cp->sock);
\r
8564 if (signal) send(cp->sock2, "\017", 1, 0); /* 017 = 15 = SIGTERM */
\r
8565 closesocket(cp->sock);
\r
8566 closesocket(cp->sock2);
\r
8574 InterruptChildProcess(ProcRef pr)
\r
8578 cp = (ChildProc *) pr;
\r
8579 if (cp == NULL) return;
\r
8580 switch (cp->kind) {
\r
8582 /* The following doesn't work because the chess program
\r
8583 doesn't "have the same console" as WinBoard. Maybe
\r
8584 we could arrange for this even though neither WinBoard
\r
8585 nor the chess program uses a console for stdio */
\r
8586 /*!!GenerateConsoleCtrlEvent(CTRL_C_EVENT, cp->pid);*/
\r
8591 /* Can't interrupt */
\r
8595 send(cp->sock2, "\002", 1, 0); /* 2 = SIGINT */
\r
8602 OpenTelnet(char *host, char *port, ProcRef *pr)
\r
8604 char cmdLine[MSG_SIZ];
\r
8606 if (port[0] == NULLCHAR) {
\r
8607 sprintf(cmdLine, "%s %s", appData.telnetProgram, host);
\r
8609 sprintf(cmdLine, "%s %s %s", appData.telnetProgram, host, port);
\r
8611 return StartChildProcess(cmdLine, "", pr);
\r
8615 /* Code to open TCP sockets */
\r
8618 OpenTCP(char *host, char *port, ProcRef *pr)
\r
8623 struct sockaddr_in sa, mysa;
\r
8624 struct hostent FAR *hp;
\r
8625 unsigned short uport;
\r
8626 WORD wVersionRequested;
\r
8629 /* Initialize socket DLL */
\r
8630 wVersionRequested = MAKEWORD(1, 1);
\r
8631 err = WSAStartup(wVersionRequested, &wsaData);
\r
8632 if (err != 0) return err;
\r
8635 if ((s = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
\r
8636 err = WSAGetLastError();
\r
8641 /* Bind local address using (mostly) don't-care values.
\r
8643 memset((char *) &mysa, 0, sizeof(struct sockaddr_in));
\r
8644 mysa.sin_family = AF_INET;
\r
8645 mysa.sin_addr.s_addr = INADDR_ANY;
\r
8646 uport = (unsigned short) 0;
\r
8647 mysa.sin_port = htons(uport);
\r
8648 if (bind(s, (struct sockaddr *) &mysa, sizeof(struct sockaddr_in))
\r
8649 == SOCKET_ERROR) {
\r
8650 err = WSAGetLastError();
\r
8655 /* Resolve remote host name */
\r
8656 memset((char *) &sa, 0, sizeof(struct sockaddr_in));
\r
8657 if (!(hp = gethostbyname(host))) {
\r
8658 unsigned int b0, b1, b2, b3;
\r
8660 err = WSAGetLastError();
\r
8662 if (sscanf(host, "%u.%u.%u.%u", &b0, &b1, &b2, &b3) == 4) {
\r
8663 hp = (struct hostent *) calloc(1, sizeof(struct hostent));
\r
8664 hp->h_addrtype = AF_INET;
\r
8666 hp->h_addr_list = (char **) calloc(2, sizeof(char *));
\r
8667 hp->h_addr_list[0] = (char *) malloc(4);
\r
8668 hp->h_addr_list[0][0] = (char) b0;
\r
8669 hp->h_addr_list[0][1] = (char) b1;
\r
8670 hp->h_addr_list[0][2] = (char) b2;
\r
8671 hp->h_addr_list[0][3] = (char) b3;
\r
8677 sa.sin_family = hp->h_addrtype;
\r
8678 uport = (unsigned short) atoi(port);
\r
8679 sa.sin_port = htons(uport);
\r
8680 memcpy((char *) &sa.sin_addr, hp->h_addr, hp->h_length);
\r
8682 /* Make connection */
\r
8683 if (connect(s, (struct sockaddr *) &sa,
\r
8684 sizeof(struct sockaddr_in)) == SOCKET_ERROR) {
\r
8685 err = WSAGetLastError();
\r
8690 /* Prepare return value */
\r
8691 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
8692 cp->kind = CPSock;
\r
8694 *pr = (ProcRef *) cp;
\r
8700 OpenCommPort(char *name, ProcRef *pr)
\r
8705 char fullname[MSG_SIZ];
\r
8707 if (*name != '\\')
\r
8708 sprintf(fullname, "\\\\.\\%s", name);
\r
8710 strcpy(fullname, name);
\r
8712 h = CreateFile(name, GENERIC_READ | GENERIC_WRITE,
\r
8713 0, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
\r
8714 if (h == (HANDLE) -1) {
\r
8715 return GetLastError();
\r
8719 if (!SetCommState(h, (LPDCB) &dcb)) return GetLastError();
\r
8721 /* Accumulate characters until a 100ms pause, then parse */
\r
8722 ct.ReadIntervalTimeout = 100;
\r
8723 ct.ReadTotalTimeoutMultiplier = 0;
\r
8724 ct.ReadTotalTimeoutConstant = 0;
\r
8725 ct.WriteTotalTimeoutMultiplier = 0;
\r
8726 ct.WriteTotalTimeoutConstant = 0;
\r
8727 if (!SetCommTimeouts(h, (LPCOMMTIMEOUTS) &ct)) return GetLastError();
\r
8729 /* Prepare return value */
\r
8730 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
8731 cp->kind = CPComm;
\r
8734 *pr = (ProcRef *) cp;
\r
8740 OpenLoopback(ProcRef *pr)
\r
8742 DisplayFatalError("Not implemented", 0, 1);
\r
8748 OpenRcmd(char* host, char* user, char* cmd, ProcRef* pr)
\r
8753 struct sockaddr_in sa, mysa;
\r
8754 struct hostent FAR *hp;
\r
8755 unsigned short uport;
\r
8756 WORD wVersionRequested;
\r
8759 char stderrPortStr[MSG_SIZ];
\r
8761 /* Initialize socket DLL */
\r
8762 wVersionRequested = MAKEWORD(1, 1);
\r
8763 err = WSAStartup(wVersionRequested, &wsaData);
\r
8764 if (err != 0) return err;
\r
8766 /* Resolve remote host name */
\r
8767 memset((char *) &sa, 0, sizeof(struct sockaddr_in));
\r
8768 if (!(hp = gethostbyname(host))) {
\r
8769 unsigned int b0, b1, b2, b3;
\r
8771 err = WSAGetLastError();
\r
8773 if (sscanf(host, "%u.%u.%u.%u", &b0, &b1, &b2, &b3) == 4) {
\r
8774 hp = (struct hostent *) calloc(1, sizeof(struct hostent));
\r
8775 hp->h_addrtype = AF_INET;
\r
8777 hp->h_addr_list = (char **) calloc(2, sizeof(char *));
\r
8778 hp->h_addr_list[0] = (char *) malloc(4);
\r
8779 hp->h_addr_list[0][0] = (char) b0;
\r
8780 hp->h_addr_list[0][1] = (char) b1;
\r
8781 hp->h_addr_list[0][2] = (char) b2;
\r
8782 hp->h_addr_list[0][3] = (char) b3;
\r
8788 sa.sin_family = hp->h_addrtype;
\r
8789 uport = (unsigned short) 514;
\r
8790 sa.sin_port = htons(uport);
\r
8791 memcpy((char *) &sa.sin_addr, hp->h_addr, hp->h_length);
\r
8793 /* Bind local socket to unused "privileged" port address
\r
8795 s = INVALID_SOCKET;
\r
8796 memset((char *) &mysa, 0, sizeof(struct sockaddr_in));
\r
8797 mysa.sin_family = AF_INET;
\r
8798 mysa.sin_addr.s_addr = INADDR_ANY;
\r
8799 for (fromPort = 1023;; fromPort--) {
\r
8800 if (fromPort < 0) {
\r
8802 return WSAEADDRINUSE;
\r
8804 if (s == INVALID_SOCKET) {
\r
8805 if ((s = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
\r
8806 err = WSAGetLastError();
\r
8811 uport = (unsigned short) fromPort;
\r
8812 mysa.sin_port = htons(uport);
\r
8813 if (bind(s, (struct sockaddr *) &mysa, sizeof(struct sockaddr_in))
\r
8814 == SOCKET_ERROR) {
\r
8815 err = WSAGetLastError();
\r
8816 if (err == WSAEADDRINUSE) continue;
\r
8820 if (connect(s, (struct sockaddr *) &sa,
\r
8821 sizeof(struct sockaddr_in)) == SOCKET_ERROR) {
\r
8822 err = WSAGetLastError();
\r
8823 if (err == WSAEADDRINUSE) {
\r
8834 /* Bind stderr local socket to unused "privileged" port address
\r
8836 s2 = INVALID_SOCKET;
\r
8837 memset((char *) &mysa, 0, sizeof(struct sockaddr_in));
\r
8838 mysa.sin_family = AF_INET;
\r
8839 mysa.sin_addr.s_addr = INADDR_ANY;
\r
8840 for (fromPort = 1023;; fromPort--) {
\r
8841 if (fromPort == prevStderrPort) continue; // don't reuse port
\r
8842 if (fromPort < 0) {
\r
8843 (void) closesocket(s);
\r
8845 return WSAEADDRINUSE;
\r
8847 if (s2 == INVALID_SOCKET) {
\r
8848 if ((s2 = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
\r
8849 err = WSAGetLastError();
\r
8855 uport = (unsigned short) fromPort;
\r
8856 mysa.sin_port = htons(uport);
\r
8857 if (bind(s2, (struct sockaddr *) &mysa, sizeof(struct sockaddr_in))
\r
8858 == SOCKET_ERROR) {
\r
8859 err = WSAGetLastError();
\r
8860 if (err == WSAEADDRINUSE) continue;
\r
8861 (void) closesocket(s);
\r
8865 if (listen(s2, 1) == SOCKET_ERROR) {
\r
8866 err = WSAGetLastError();
\r
8867 if (err == WSAEADDRINUSE) {
\r
8869 s2 = INVALID_SOCKET;
\r
8872 (void) closesocket(s);
\r
8873 (void) closesocket(s2);
\r
8879 prevStderrPort = fromPort; // remember port used
\r
8880 sprintf(stderrPortStr, "%d", fromPort);
\r
8882 if (send(s, stderrPortStr, strlen(stderrPortStr) + 1, 0) == SOCKET_ERROR) {
\r
8883 err = WSAGetLastError();
\r
8884 (void) closesocket(s);
\r
8885 (void) closesocket(s2);
\r
8890 if (send(s, UserName(), strlen(UserName()) + 1, 0) == SOCKET_ERROR) {
\r
8891 err = WSAGetLastError();
\r
8892 (void) closesocket(s);
\r
8893 (void) closesocket(s2);
\r
8897 if (*user == NULLCHAR) user = UserName();
\r
8898 if (send(s, user, strlen(user) + 1, 0) == SOCKET_ERROR) {
\r
8899 err = WSAGetLastError();
\r
8900 (void) closesocket(s);
\r
8901 (void) closesocket(s2);
\r
8905 if (send(s, cmd, strlen(cmd) + 1, 0) == SOCKET_ERROR) {
\r
8906 err = WSAGetLastError();
\r
8907 (void) closesocket(s);
\r
8908 (void) closesocket(s2);
\r
8913 if ((s3 = accept(s2, NULL, NULL)) == INVALID_SOCKET) {
\r
8914 err = WSAGetLastError();
\r
8915 (void) closesocket(s);
\r
8916 (void) closesocket(s2);
\r
8920 (void) closesocket(s2); /* Stop listening */
\r
8922 /* Prepare return value */
\r
8923 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
8924 cp->kind = CPRcmd;
\r
8927 *pr = (ProcRef *) cp;
\r
8934 AddInputSource(ProcRef pr, int lineByLine,
\r
8935 InputCallback func, VOIDSTAR closure)
\r
8937 InputSource *is, *is2 = NULL;
\r
8938 ChildProc *cp = (ChildProc *) pr;
\r
8940 is = (InputSource *) calloc(1, sizeof(InputSource));
\r
8941 is->lineByLine = lineByLine;
\r
8943 is->closure = closure;
\r
8944 is->second = NULL;
\r
8945 is->next = is->buf;
\r
8946 if (pr == NoProc) {
\r
8947 is->kind = CPReal;
\r
8948 consoleInputSource = is;
\r
8950 is->kind = cp->kind;
\r
8952 [AS] Try to avoid a race condition if the thread is given control too early:
\r
8953 we create all threads suspended so that the is->hThread variable can be
\r
8954 safely assigned, then let the threads start with ResumeThread.
\r
8956 switch (cp->kind) {
\r
8958 is->hFile = cp->hFrom;
\r
8959 cp->hFrom = NULL; /* now owned by InputThread */
\r
8961 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) NonOvlInputThread,
\r
8962 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
8966 is->hFile = cp->hFrom;
\r
8967 cp->hFrom = NULL; /* now owned by InputThread */
\r
8969 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) InputThread,
\r
8970 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
8974 is->sock = cp->sock;
\r
8976 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SocketInputThread,
\r
8977 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
8981 is2 = (InputSource *) calloc(1, sizeof(InputSource));
\r
8983 is->sock = cp->sock;
\r
8985 is2->sock = cp->sock2;
\r
8986 is2->second = is2;
\r
8988 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SocketInputThread,
\r
8989 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
8991 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SocketInputThread,
\r
8992 (LPVOID) is2, CREATE_SUSPENDED, &is2->id);
\r
8996 if( is->hThread != NULL ) {
\r
8997 ResumeThread( is->hThread );
\r
9000 if( is2 != NULL && is2->hThread != NULL ) {
\r
9001 ResumeThread( is2->hThread );
\r
9005 return (InputSourceRef) is;
\r
9009 RemoveInputSource(InputSourceRef isr)
\r
9013 is = (InputSource *) isr;
\r
9014 is->hThread = NULL; /* tell thread to stop */
\r
9015 CloseHandle(is->hThread);
\r
9016 if (is->second != NULL) {
\r
9017 is->second->hThread = NULL;
\r
9018 CloseHandle(is->second->hThread);
\r
9022 int no_wrap(char *message, int count)
\r
9024 ConsoleOutput(message, count, FALSE);
\r
9029 OutputToProcess(ProcRef pr, char *message, int count, int *outError)
\r
9032 int outCount = SOCKET_ERROR;
\r
9033 ChildProc *cp = (ChildProc *) pr;
\r
9034 static OVERLAPPED ovl;
\r
9035 static int line = 0;
\r
9039 if (appData.noJoin || !appData.useInternalWrap)
\r
9040 return no_wrap(message, count);
\r
9043 int width = get_term_width();
\r
9044 int len = wrap(NULL, message, count, width, &line);
\r
9045 char *msg = malloc(len);
\r
9049 return no_wrap(message, count);
\r
9052 dbgchk = wrap(msg, message, count, width, &line);
\r
9053 if (dbgchk != len && appData.debugMode)
\r
9054 fprintf(debugFP, "wrap(): dbgchk(%d) != len(%d)\n", dbgchk, len);
\r
9055 ConsoleOutput(msg, len, FALSE);
\r
9062 if (ovl.hEvent == NULL) {
\r
9063 ovl.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
\r
9065 ovl.Internal = ovl.InternalHigh = ovl.Offset = ovl.OffsetHigh = 0;
\r
9067 switch (cp->kind) {
\r
9070 outCount = send(cp->sock, message, count, 0);
\r
9071 if (outCount == SOCKET_ERROR) {
\r
9072 *outError = WSAGetLastError();
\r
9074 *outError = NO_ERROR;
\r
9079 if (WriteFile(((ChildProc *)pr)->hTo, message, count,
\r
9080 &dOutCount, NULL)) {
\r
9081 *outError = NO_ERROR;
\r
9082 outCount = (int) dOutCount;
\r
9084 *outError = GetLastError();
\r
9089 *outError = DoWriteFile(((ChildProc *)pr)->hTo, message, count,
\r
9090 &dOutCount, &ovl);
\r
9091 if (*outError == NO_ERROR) {
\r
9092 outCount = (int) dOutCount;
\r
9100 OutputToProcessDelayed(ProcRef pr, char *message, int count, int *outError,
\r
9103 /* Ignore delay, not implemented for WinBoard */
\r
9104 return OutputToProcess(pr, message, count, outError);
\r
9109 CmailSigHandlerCallBack(InputSourceRef isr, VOIDSTAR closure,
\r
9110 char *buf, int count, int error)
\r
9112 DisplayFatalError("Not implemented", 0, 1);
\r
9115 /* see wgamelist.c for Game List functions */
\r
9116 /* see wedittags.c for Edit Tags functions */
\r
9123 char buf[MSG_SIZ];
\r
9126 if (SearchPath(installDir, appData.icsLogon, NULL, MSG_SIZ, buf, &dummy)) {
\r
9127 f = fopen(buf, "r");
\r
9129 ProcessICSInitScript(f);
\r
9137 StartAnalysisClock()
\r
9139 if (analysisTimerEvent) return;
\r
9140 analysisTimerEvent = SetTimer(hwndMain, (UINT) ANALYSIS_TIMER_ID,
\r
9141 (UINT) 2000, NULL);
\r
9145 SetHighlights(int fromX, int fromY, int toX, int toY)
\r
9147 highlightInfo.sq[0].x = fromX;
\r
9148 highlightInfo.sq[0].y = fromY;
\r
9149 highlightInfo.sq[1].x = toX;
\r
9150 highlightInfo.sq[1].y = toY;
\r
9156 highlightInfo.sq[0].x = highlightInfo.sq[0].y =
\r
9157 highlightInfo.sq[1].x = highlightInfo.sq[1].y = -1;
\r
9161 SetPremoveHighlights(int fromX, int fromY, int toX, int toY)
\r
9163 premoveHighlightInfo.sq[0].x = fromX;
\r
9164 premoveHighlightInfo.sq[0].y = fromY;
\r
9165 premoveHighlightInfo.sq[1].x = toX;
\r
9166 premoveHighlightInfo.sq[1].y = toY;
\r
9170 ClearPremoveHighlights()
\r
9172 premoveHighlightInfo.sq[0].x = premoveHighlightInfo.sq[0].y =
\r
9173 premoveHighlightInfo.sq[1].x = premoveHighlightInfo.sq[1].y = -1;
\r
9177 ShutDownFrontEnd()
\r
9179 if (saveSettingsOnExit) SaveSettings(settingsFileName);
\r
9180 DeleteClipboardTempFiles();
\r
9186 if (IsIconic(hwndMain))
\r
9187 ShowWindow(hwndMain, SW_RESTORE);
\r
9189 SetActiveWindow(hwndMain);
\r
9193 * Prototypes for animation support routines
\r
9195 static void ScreenSquare(int column, int row, POINT * pt);
\r
9196 static void Tween( POINT * start, POINT * mid, POINT * finish, int factor,
\r
9197 POINT frames[], int * nFrames);
\r
9201 AnimateAtomicCapture(int fromX, int fromY, int toX, int toY, int nFrames)
\r
9202 { // [HGM] atomic: animate blast wave
\r
9204 if(appData.debugMode) fprintf(debugFP, "exploding (%d,%d)\n", toX, toY);
\r
9205 explodeInfo.fromX = fromX;
\r
9206 explodeInfo.fromY = fromY;
\r
9207 explodeInfo.toX = toX;
\r
9208 explodeInfo.toY = toY;
\r
9209 for(i=1; i<nFrames; i++) {
\r
9210 explodeInfo.radius = (i*180)/(nFrames-1);
\r
9211 DrawPosition(FALSE, NULL);
\r
9212 Sleep(appData.animSpeed);
\r
9214 explodeInfo.radius = 0;
\r
9215 DrawPosition(TRUE, NULL);
\r
9221 AnimateMove(board, fromX, fromY, toX, toY)
\r
9228 ChessSquare piece;
\r
9229 POINT start, finish, mid;
\r
9230 POINT frames[kFactor * 2 + 1];
\r
9233 if (!appData.animate) return;
\r
9234 if (doingSizing) return;
\r
9235 if (fromY < 0 || fromX < 0) return;
\r
9236 piece = board[fromY][fromX];
\r
9237 if (piece >= EmptySquare) return;
\r
9239 ScreenSquare(fromX, fromY, &start);
\r
9240 ScreenSquare(toX, toY, &finish);
\r
9242 /* All pieces except knights move in straight line */
\r
9243 if (piece != WhiteKnight && piece != BlackKnight) {
\r
9244 mid.x = start.x + (finish.x - start.x) / 2;
\r
9245 mid.y = start.y + (finish.y - start.y) / 2;
\r
9247 /* Knight: make diagonal movement then straight */
\r
9248 if (abs(toY - fromY) < abs(toX - fromX)) {
\r
9249 mid.x = start.x + (finish.x - start.x) / 2;
\r
9253 mid.y = start.y + (finish.y - start.y) / 2;
\r
9257 /* Don't use as many frames for very short moves */
\r
9258 if (abs(toY - fromY) + abs(toX - fromX) <= 2)
\r
9259 Tween(&start, &mid, &finish, kFactor - 1, frames, &nFrames);
\r
9261 Tween(&start, &mid, &finish, kFactor, frames, &nFrames);
\r
9263 animInfo.from.x = fromX;
\r
9264 animInfo.from.y = fromY;
\r
9265 animInfo.to.x = toX;
\r
9266 animInfo.to.y = toY;
\r
9267 animInfo.lastpos = start;
\r
9268 animInfo.piece = piece;
\r
9269 for (n = 0; n < nFrames; n++) {
\r
9270 animInfo.pos = frames[n];
\r
9271 DrawPosition(FALSE, NULL);
\r
9272 animInfo.lastpos = animInfo.pos;
\r
9273 Sleep(appData.animSpeed);
\r
9275 animInfo.pos = finish;
\r
9276 DrawPosition(FALSE, NULL);
\r
9277 animInfo.piece = EmptySquare;
\r
9278 if(gameInfo.variant == VariantAtomic &&
\r
9279 (board[toY][toX] != EmptySquare || fromX != toX && (piece == WhitePawn || piece == BlackPawn) ) )
\r
9280 AnimateAtomicCapture(fromX, fromY, toX, toY, 2*nFrames);
\r
9283 /* Convert board position to corner of screen rect and color */
\r
9286 ScreenSquare(column, row, pt)
\r
9287 int column; int row; POINT * pt;
\r
9290 pt->x = lineGap + ((BOARD_WIDTH-1)-column) * (squareSize + lineGap);
\r
9291 pt->y = lineGap + row * (squareSize + lineGap);
\r
9293 pt->x = lineGap + column * (squareSize + lineGap);
\r
9294 pt->y = lineGap + ((BOARD_HEIGHT-1)-row) * (squareSize + lineGap);
\r
9298 /* Generate a series of frame coords from start->mid->finish.
\r
9299 The movement rate doubles until the half way point is
\r
9300 reached, then halves back down to the final destination,
\r
9301 which gives a nice slow in/out effect. The algorithmn
\r
9302 may seem to generate too many intermediates for short
\r
9303 moves, but remember that the purpose is to attract the
\r
9304 viewers attention to the piece about to be moved and
\r
9305 then to where it ends up. Too few frames would be less
\r
9309 Tween(start, mid, finish, factor, frames, nFrames)
\r
9310 POINT * start; POINT * mid;
\r
9311 POINT * finish; int factor;
\r
9312 POINT frames[]; int * nFrames;
\r
9314 int n, fraction = 1, count = 0;
\r
9316 /* Slow in, stepping 1/16th, then 1/8th, ... */
\r
9317 for (n = 0; n < factor; n++)
\r
9319 for (n = 0; n < factor; n++) {
\r
9320 frames[count].x = start->x + (mid->x - start->x) / fraction;
\r
9321 frames[count].y = start->y + (mid->y - start->y) / fraction;
\r
9323 fraction = fraction / 2;
\r
9327 frames[count] = *mid;
\r
9330 /* Slow out, stepping 1/2, then 1/4, ... */
\r
9332 for (n = 0; n < factor; n++) {
\r
9333 frames[count].x = finish->x - (finish->x - mid->x) / fraction;
\r
9334 frames[count].y = finish->y - (finish->y - mid->y) / fraction;
\r
9336 fraction = fraction * 2;
\r
9342 HistorySet( char movelist[][2*MOVE_LEN], int first, int last, int current )
\r
9344 MoveHistorySet( movelist, first, last, current, pvInfoList );
\r
9346 EvalGraphSet( first, last, current, pvInfoList );
\r