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
157 BoardSize boardSize;
\r
158 Boolean chessProgram;
\r
159 //static int boardX, boardY;
\r
160 int minX, minY; // [HGM] placement: volatile limits on upper-left corner
\r
161 static int squareSize, lineGap, minorSize;
\r
162 static int winW, winH;
\r
163 static RECT messageRect, whiteRect, blackRect, leftLogoRect, rightLogoRect; // [HGM] logo
\r
164 static int logoHeight = 0;
\r
165 static char messageText[MESSAGE_TEXT_MAX];
\r
166 static int clockTimerEvent = 0;
\r
167 static int loadGameTimerEvent = 0;
\r
168 static int analysisTimerEvent = 0;
\r
169 static DelayedEventCallback delayedTimerCallback;
\r
170 static int delayedTimerEvent = 0;
\r
171 static int buttonCount = 2;
\r
172 char *icsTextMenuString;
\r
174 char *firstChessProgramNames;
\r
175 char *secondChessProgramNames;
\r
177 #define PALETTESIZE 256
\r
179 HINSTANCE hInst; /* current instance */
\r
180 Boolean alwaysOnTop = FALSE;
\r
182 COLORREF lightSquareColor, darkSquareColor, whitePieceColor,
\r
183 blackPieceColor, highlightSquareColor, premoveHighlightColor;
\r
185 ColorClass currentColorClass;
\r
187 HWND hCommPort = NULL; /* currently open comm port */
\r
188 static HWND hwndPause; /* pause button */
\r
189 static HBITMAP pieceBitmap[3][(int) BlackPawn]; /* [HGM] nr of bitmaps referred to bP in stead of wK */
\r
190 static HBRUSH lightSquareBrush, darkSquareBrush,
\r
191 blackSquareBrush, /* [HGM] for band between board and holdings */
\r
192 explodeBrush, /* [HGM] atomic */
\r
193 whitePieceBrush, blackPieceBrush, iconBkgndBrush /*, outlineBrush*/;
\r
194 static POINT gridEndpoints[(BOARD_RANKS + BOARD_FILES + 2) * 2];
\r
195 static DWORD gridVertexCounts[BOARD_RANKS + BOARD_FILES + 2];
\r
196 static HPEN gridPen = NULL;
\r
197 static HPEN highlightPen = NULL;
\r
198 static HPEN premovePen = NULL;
\r
199 static NPLOGPALETTE pLogPal;
\r
200 static BOOL paletteChanged = FALSE;
\r
201 static HICON iconWhite, iconBlack, iconCurrent;
\r
202 static int doingSizing = FALSE;
\r
203 static int lastSizing = 0;
\r
204 static int prevStderrPort;
\r
205 static HBITMAP userLogo;
\r
207 static HBITMAP liteBackTexture = NULL;
\r
208 static HBITMAP darkBackTexture = NULL;
\r
209 static int liteBackTextureMode = BACK_TEXTURE_MODE_PLAIN;
\r
210 static int darkBackTextureMode = BACK_TEXTURE_MODE_PLAIN;
\r
211 static int backTextureSquareSize = 0;
\r
212 static struct { int x; int y; int mode; } backTextureSquareInfo[BOARD_RANKS][BOARD_FILES];
\r
214 #if __GNUC__ && !defined(_winmajor)
\r
215 #define oldDialog 0 /* cygwin doesn't define _winmajor; mingw does */
\r
217 #if defined(_winmajor)
\r
218 #define oldDialog (_winmajor < 4)
\r
220 #define oldDialog 0
\r
230 int cliWidth, cliHeight;
\r
233 SizeInfo sizeInfo[] =
\r
235 { "tiny", 21, 0, 1, 1, 0, 0 },
\r
236 { "teeny", 25, 1, 1, 1, 0, 0 },
\r
237 { "dinky", 29, 1, 1, 1, 0, 0 },
\r
238 { "petite", 33, 1, 1, 1, 0, 0 },
\r
239 { "slim", 37, 2, 1, 0, 0, 0 },
\r
240 { "small", 40, 2, 1, 0, 0, 0 },
\r
241 { "mediocre", 45, 2, 1, 0, 0, 0 },
\r
242 { "middling", 49, 2, 0, 0, 0, 0 },
\r
243 { "average", 54, 2, 0, 0, 0, 0 },
\r
244 { "moderate", 58, 3, 0, 0, 0, 0 },
\r
245 { "medium", 64, 3, 0, 0, 0, 0 },
\r
246 { "bulky", 72, 3, 0, 0, 0, 0 },
\r
247 { "large", 80, 3, 0, 0, 0, 0 },
\r
248 { "big", 87, 3, 0, 0, 0, 0 },
\r
249 { "huge", 95, 3, 0, 0, 0, 0 },
\r
250 { "giant", 108, 3, 0, 0, 0, 0 },
\r
251 { "colossal", 116, 4, 0, 0, 0, 0 },
\r
252 { "titanic", 129, 4, 0, 0, 0, 0 },
\r
253 { NULL, 0, 0, 0, 0, 0, 0 }
\r
256 #define MF(x) {x, {{0,}, 0. }, {0, }, 0}
\r
257 MyFont fontRec[NUM_SIZES][NUM_FONTS] =
\r
259 { 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
260 { 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
261 { 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
262 { 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
263 { 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
264 { 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
265 { 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
266 { 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
267 { 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
268 { 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
269 { 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
270 { 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
271 { 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
272 { 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
273 { 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
274 { 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
275 { 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
276 { 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
279 MyFont *font[NUM_SIZES][NUM_FONTS];
\r
288 #define BUTTON_WIDTH (tinyLayout ? 16 : 32)
\r
289 #define N_BUTTONS 5
\r
291 MyButtonDesc buttonDesc[N_BUTTONS] =
\r
293 {"<<", IDM_ToStart, NULL, NULL},
\r
294 {"<", IDM_Backward, NULL, NULL},
\r
295 {"P", IDM_Pause, NULL, NULL},
\r
296 {">", IDM_Forward, NULL, NULL},
\r
297 {">>", IDM_ToEnd, NULL, NULL},
\r
300 int tinyLayout = 0, smallLayout = 0;
\r
301 #define MENU_BAR_ITEMS 7
\r
302 char *menuBarText[2][MENU_BAR_ITEMS+1] = {
\r
303 { "&File", "&Mode", "&Action", "&Step", "&Options", "&Help", NULL },
\r
304 { "&F", "&M", "&A", "&S", "&O", "&H", NULL },
\r
308 MySound sounds[(int)NSoundClasses];
\r
309 MyTextAttribs textAttribs[(int)NColorClasses];
\r
311 MyColorizeAttribs colorizeAttribs[] = {
\r
312 { (COLORREF)0, 0, "Shout Text" },
\r
313 { (COLORREF)0, 0, "SShout/CShout" },
\r
314 { (COLORREF)0, 0, "Channel 1 Text" },
\r
315 { (COLORREF)0, 0, "Channel Text" },
\r
316 { (COLORREF)0, 0, "Kibitz Text" },
\r
317 { (COLORREF)0, 0, "Tell Text" },
\r
318 { (COLORREF)0, 0, "Challenge Text" },
\r
319 { (COLORREF)0, 0, "Request Text" },
\r
320 { (COLORREF)0, 0, "Seek Text" },
\r
321 { (COLORREF)0, 0, "Normal Text" },
\r
322 { (COLORREF)0, 0, "None" }
\r
327 static char *commentTitle;
\r
328 static char *commentText;
\r
329 static int commentIndex;
\r
330 static Boolean editComment = FALSE;
\r
333 char errorTitle[MSG_SIZ];
\r
334 char errorMessage[2*MSG_SIZ];
\r
335 HWND errorDialog = NULL;
\r
336 BOOLEAN moveErrorMessageUp = FALSE;
\r
337 BOOLEAN consoleEcho = TRUE;
\r
338 CHARFORMAT consoleCF;
\r
339 COLORREF consoleBackgroundColor;
\r
341 char *programVersion;
\r
347 typedef int CPKind;
\r
356 SOCKET sock2; /* stderr socket for OpenRcmd */
\r
359 #define INPUT_SOURCE_BUF_SIZE 4096
\r
361 typedef struct _InputSource {
\r
368 char buf[INPUT_SOURCE_BUF_SIZE];
\r
372 InputCallback func;
\r
373 struct _InputSource *second; /* for stderr thread on CPRcmd */
\r
377 InputSource *consoleInputSource;
\r
382 VOID ConsoleOutput(char* data, int length, int forceVisible);
\r
383 VOID ConsoleCreate();
\r
385 ConsoleWndProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);
\r
386 VOID ColorizeTextPopup(HWND hwnd, ColorClass cc);
\r
387 VOID PrintCommSettings(FILE *f, char *name, DCB *dcb);
\r
388 VOID ParseCommSettings(char *arg, DCB *dcb);
\r
390 StartupDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);
\r
391 VOID APIENTRY MenuPopup(HWND hwnd, POINT pt, HMENU hmenu, UINT def);
\r
392 void ParseIcsTextMenu(char *icsTextMenuString);
\r
393 VOID PopUpMoveDialog(char firstchar);
\r
394 VOID PopUpNameDialog(char firstchar);
\r
395 VOID UpdateSampleText(HWND hDlg, int id, MyColorizeAttribs *mca);
\r
399 int GameListOptions();
\r
401 int dummy; // [HGM] for obsolete args
\r
403 HWND hwndMain = NULL; /* root window*/
\r
404 HWND hwndConsole = NULL;
\r
405 HWND commentDialog = NULL;
\r
406 HWND moveHistoryDialog = NULL;
\r
407 HWND evalGraphDialog = NULL;
\r
408 HWND engineOutputDialog = NULL;
\r
409 HWND gameListDialog = NULL;
\r
410 HWND editTagsDialog = NULL;
\r
412 int commentUp = FALSE;
\r
414 WindowPlacement wpMain;
\r
415 WindowPlacement wpConsole;
\r
416 WindowPlacement wpComment;
\r
417 WindowPlacement wpMoveHistory;
\r
418 WindowPlacement wpEvalGraph;
\r
419 WindowPlacement wpEngineOutput;
\r
420 WindowPlacement wpGameList;
\r
421 WindowPlacement wpTags;
\r
423 VOID EngineOptionsPopup(); // [HGM] settings
\r
425 VOID GothicPopUp(char *title, VariantClass variant);
\r
427 * Setting "frozen" should disable all user input other than deleting
\r
428 * the window. We do this while engines are initializing themselves.
\r
430 static int frozen = 0;
\r
431 static int oldMenuItemState[MENU_BAR_ITEMS];
\r
437 if (frozen) return;
\r
439 hmenu = GetMenu(hwndMain);
\r
440 for (i=0; i<MENU_BAR_ITEMS; i++) {
\r
441 oldMenuItemState[i] = EnableMenuItem(hmenu, i, MF_BYPOSITION|MF_GRAYED);
\r
443 DrawMenuBar(hwndMain);
\r
446 /* Undo a FreezeUI */
\r
452 if (!frozen) return;
\r
454 hmenu = GetMenu(hwndMain);
\r
455 for (i=0; i<MENU_BAR_ITEMS; i++) {
\r
456 EnableMenuItem(hmenu, i, MF_BYPOSITION|oldMenuItemState[i]);
\r
458 DrawMenuBar(hwndMain);
\r
461 /*static*/ int fromX = -1, fromY = -1, toX, toY; // [HGM] moved upstream, so JAWS can use them
\r
463 /* JAWS preparation patch (WinBoard for the sight impaired). Define required insertions as empty */
\r
469 #define JAWS_ALT_INTERCEPT
\r
470 #define JAWS_KB_NAVIGATION
\r
471 #define JAWS_MENU_ITEMS
\r
472 #define JAWS_SILENCE
\r
473 #define JAWS_REPLAY
\r
475 #define JAWS_COPYRIGHT
\r
476 #define JAWS_DELETE(X) X
\r
477 #define SAYMACHINEMOVE()
\r
481 /*---------------------------------------------------------------------------*\
\r
485 \*---------------------------------------------------------------------------*/
\r
488 WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
\r
489 LPSTR lpCmdLine, int nCmdShow)
\r
492 HANDLE hAccelMain, hAccelNoAlt, hAccelNoICS;
\r
493 // INITCOMMONCONTROLSEX ex;
\r
497 LoadLibrary("RICHED32.DLL");
\r
498 consoleCF.cbSize = sizeof(CHARFORMAT);
\r
500 if (!InitApplication(hInstance)) {
\r
503 if (!InitInstance(hInstance, nCmdShow, lpCmdLine)) {
\r
509 // InitCommonControlsEx(&ex);
\r
510 InitCommonControls();
\r
512 hAccelMain = LoadAccelerators (hInstance, szAppName);
\r
513 hAccelNoAlt = LoadAccelerators (hInstance, "NO_ALT");
\r
514 hAccelNoICS = LoadAccelerators( hInstance, "NO_ICS"); /* [AS] No Ctrl-V on ICS!!! */
\r
516 /* Acquire and dispatch messages until a WM_QUIT message is received. */
\r
518 while (GetMessage(&msg, /* message structure */
\r
519 NULL, /* handle of window receiving the message */
\r
520 0, /* lowest message to examine */
\r
521 0)) /* highest message to examine */
\r
524 if(msg.message == WM_CHAR && msg.wParam == '\t') {
\r
525 // [HGM] navigate: switch between all windows with tab
\r
526 HWND e1 = NULL, e2 = NULL, mh = NULL, hInput = NULL, hText = NULL;
\r
527 int i, currentElement = 0;
\r
529 // first determine what element of the chain we come from (if any)
\r
530 if(appData.icsActive) {
\r
531 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
532 hText = GetDlgItem(hwndConsole, OPT_ConsoleText);
\r
534 if(engineOutputDialog && EngineOutputIsUp()) {
\r
535 e1 = GetDlgItem(engineOutputDialog, IDC_EngineMemo1);
\r
536 e2 = GetDlgItem(engineOutputDialog, IDC_EngineMemo2);
\r
538 if(moveHistoryDialog && MoveHistoryIsUp()) {
\r
539 mh = GetDlgItem(moveHistoryDialog, IDC_MoveHistory);
\r
541 if(msg.hwnd == hwndMain) currentElement = 7 ; else
\r
542 if(msg.hwnd == engineOutputDialog) currentElement = 2; else
\r
543 if(msg.hwnd == e1) currentElement = 2; else
\r
544 if(msg.hwnd == e2) currentElement = 3; else
\r
545 if(msg.hwnd == moveHistoryDialog) currentElement = 4; else
\r
546 if(msg.hwnd == mh) currentElement = 4; else
\r
547 if(msg.hwnd == evalGraphDialog) currentElement = 6; else
\r
548 if(msg.hwnd == hText) currentElement = 5; else
\r
549 if(msg.hwnd == hInput) currentElement = 6; else
\r
550 for (i = 0; i < N_BUTTONS; i++) {
\r
551 if (buttonDesc[i].hwnd == msg.hwnd) { currentElement = 1; break; }
\r
554 // determine where to go to
\r
555 if(currentElement) { HWND h = NULL; int direction = GetKeyState(VK_SHIFT) < 0 ? -1 : 1;
\r
557 currentElement = (currentElement + direction) % 7;
\r
558 switch(currentElement) {
\r
560 h = hwndMain; break; // passing this case always makes the loop exit
\r
562 h = buttonDesc[0].hwnd; break; // could be NULL
\r
564 if(!EngineOutputIsUp()) continue; // skip closed auxiliary windows
\r
567 if(!EngineOutputIsUp()) continue;
\r
570 if(!MoveHistoryIsUp()) continue;
\r
572 // case 6: // input to eval graph does not seem to get here!
\r
573 // if(!EvalGraphIsUp()) continue;
\r
574 // h = evalGraphDialog; break;
\r
576 if(!appData.icsActive) continue;
\r
580 if(!appData.icsActive) continue;
\r
586 if(currentElement > 4 && IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
587 if(currentElement < 5 && IsIconic(hwndMain)) ShowWindow(hwndMain, SW_RESTORE); // all open together
\r
590 continue; // this message now has been processed
\r
594 if (!(commentDialog && IsDialogMessage(commentDialog, &msg)) &&
\r
595 !(moveHistoryDialog && IsDialogMessage(moveHistoryDialog, &msg)) &&
\r
596 !(evalGraphDialog && IsDialogMessage(evalGraphDialog, &msg)) &&
\r
597 !(engineOutputDialog && IsDialogMessage(engineOutputDialog, &msg)) &&
\r
598 !(editTagsDialog && IsDialogMessage(editTagsDialog, &msg)) &&
\r
599 !(gameListDialog && IsDialogMessage(gameListDialog, &msg)) &&
\r
600 !(errorDialog && IsDialogMessage(errorDialog, &msg)) &&
\r
601 !(!frozen && TranslateAccelerator(hwndMain, hAccelMain, &msg)) && JAWS_ACCEL
\r
602 !(!hwndConsole && TranslateAccelerator(hwndMain, hAccelNoICS, &msg)) &&
\r
603 !(!hwndConsole && TranslateAccelerator(hwndMain, hAccelNoAlt, &msg))) {
\r
604 int done = 0, i; // [HGM] chat: dispatch cat-box messages
\r
605 for(i=0; i<MAX_CHAT; i++)
\r
606 if(chatHandle[i] && IsDialogMessage(chatHandle[i], &msg)) {
\r
609 if(done) continue; // [HGM] chat: end patch
\r
610 TranslateMessage(&msg); /* Translates virtual key codes */
\r
611 DispatchMessage(&msg); /* Dispatches message to window */
\r
616 return (msg.wParam); /* Returns the value from PostQuitMessage */
\r
619 /*---------------------------------------------------------------------------*\
\r
621 * Initialization functions
\r
623 \*---------------------------------------------------------------------------*/
\r
627 { // update user logo if necessary
\r
628 static char oldUserName[MSG_SIZ], *curName;
\r
630 if(appData.autoLogo) {
\r
631 curName = UserName();
\r
632 if(strcmp(curName, oldUserName)) {
\r
633 sprintf(oldUserName, "logos\\%s.bmp", curName);
\r
634 userLogo = LoadImage( 0, oldUserName, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
635 strcpy(oldUserName, curName);
\r
641 InitApplication(HINSTANCE hInstance)
\r
645 /* Fill in window class structure with parameters that describe the */
\r
648 wc.style = CS_HREDRAW | CS_VREDRAW; /* Class style(s). */
\r
649 wc.lpfnWndProc = (WNDPROC)WndProc; /* Window Procedure */
\r
650 wc.cbClsExtra = 0; /* No per-class extra data. */
\r
651 wc.cbWndExtra = 0; /* No per-window extra data. */
\r
652 wc.hInstance = hInstance; /* Owner of this class */
\r
653 wc.hIcon = LoadIcon(hInstance, "icon_white");
\r
654 wc.hCursor = LoadCursor(NULL, IDC_ARROW); /* Cursor */
\r
655 wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1); /* Default color */
\r
656 wc.lpszMenuName = szAppName; /* Menu name from .RC */
\r
657 wc.lpszClassName = szAppName; /* Name to register as */
\r
659 /* Register the window class and return success/failure code. */
\r
660 if (!RegisterClass(&wc)) return FALSE;
\r
662 wc.style = CS_HREDRAW | CS_VREDRAW;
\r
663 wc.lpfnWndProc = (WNDPROC)ConsoleWndProc;
\r
665 wc.cbWndExtra = DLGWINDOWEXTRA;
\r
666 wc.hInstance = hInstance;
\r
667 wc.hIcon = LoadIcon(hInstance, "icon_white");
\r
668 wc.hCursor = LoadCursor(NULL, IDC_ARROW);
\r
669 wc.hbrBackground = (HBRUSH)(COLOR_MENU+1);
\r
670 wc.lpszMenuName = NULL;
\r
671 wc.lpszClassName = szConsoleName;
\r
673 if (!RegisterClass(&wc)) return FALSE;
\r
678 /* Set by InitInstance, used by EnsureOnScreen */
\r
679 int screenHeight, screenWidth;
\r
682 EnsureOnScreen(int *x, int *y, int minX, int minY)
\r
684 // int gap = GetSystemMetrics(SM_CYFRAME) + GetSystemMetrics(SM_CYCAPTION);
\r
685 /* Be sure window at (x,y) is not off screen (or even mostly off screen) */
\r
686 if (*x > screenWidth - 32) *x = 0;
\r
687 if (*y > screenHeight - 32) *y = 0;
\r
688 if (*x < minX) *x = minX;
\r
689 if (*y < minY) *y = minY;
\r
693 InitInstance(HINSTANCE hInstance, int nCmdShow, LPSTR lpCmdLine)
\r
695 HWND hwnd; /* Main window handle. */
\r
697 WINDOWPLACEMENT wp;
\r
700 hInst = hInstance; /* Store instance handle in our global variable */
\r
701 programName = szAppName;
\r
703 if (SearchPath(NULL, "WinBoard.exe", NULL, MSG_SIZ, installDir, &filepart)) {
\r
704 *filepart = NULLCHAR;
\r
706 GetCurrentDirectory(MSG_SIZ, installDir);
\r
708 gameInfo.boardWidth = gameInfo.boardHeight = 8; // [HGM] won't have open window otherwise
\r
709 screenWidth = screenHeight = 1000; // [HGM] placement: kludge to allow calling EnsureOnScreen from InitAppData
\r
710 InitAppData(lpCmdLine); /* Get run-time parameters */
\r
711 /* xboard, and older WinBoards, controlled the move sound with the
\r
712 appData.ringBellAfterMoves option. In the current WinBoard, we
\r
713 always turn the option on (so that the backend will call us),
\r
714 then let the user turn the sound off by setting it to silence if
\r
715 desired. To accommodate old winboard.ini files saved by old
\r
716 versions of WinBoard, we also turn off the sound if the option
\r
717 was initially set to false. [HGM] taken out of InitAppData */
\r
718 if (!appData.ringBellAfterMoves) {
\r
719 sounds[(int)SoundMove].name = strdup("");
\r
720 appData.ringBellAfterMoves = TRUE;
\r
722 if (appData.debugMode) {
\r
723 debugFP = fopen(appData.nameOfDebugFile, "w");
\r
724 setbuf(debugFP, NULL);
\r
729 // InitEngineUCI( installDir, &first ); // [HGM] incorporated in InitBackEnd1()
\r
730 // InitEngineUCI( installDir, &second );
\r
732 /* Create a main window for this application instance. */
\r
733 hwnd = CreateWindow(szAppName, szTitle,
\r
734 (WS_OVERLAPPEDWINDOW & ~WS_MAXIMIZEBOX),
\r
735 CW_USEDEFAULT, 0, CW_USEDEFAULT, 0,
\r
736 NULL, NULL, hInstance, NULL);
\r
739 /* If window could not be created, return "failure" */
\r
744 /* [HGM] logo: Load logos if specified (must be done before InitDrawingSizes) */
\r
745 if( appData.firstLogo && appData.firstLogo[0] != NULLCHAR) {
\r
746 first.programLogo = LoadImage( 0, appData.firstLogo, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
748 if (first.programLogo == NULL && appData.debugMode) {
\r
749 fprintf( debugFP, "Unable to load logo bitmap '%s'\n", appData.firstLogo );
\r
751 } else if(appData.autoLogo) {
\r
752 if(appData.firstDirectory && appData.firstDirectory[0]) {
\r
754 sprintf(buf, "%s/logo.bmp", appData.firstDirectory);
\r
755 first.programLogo = LoadImage( 0, buf, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
759 if( appData.secondLogo && appData.secondLogo[0] != NULLCHAR) {
\r
760 second.programLogo = LoadImage( 0, appData.secondLogo, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
762 if (second.programLogo == NULL && appData.debugMode) {
\r
763 fprintf( debugFP, "Unable to load logo bitmap '%s'\n", appData.secondLogo );
\r
765 } else if(appData.autoLogo) {
\r
767 if(appData.icsActive) { // [HGM] logo: in ICS mode second can be used for ICS
\r
768 sprintf(buf, "logos\\%s.bmp", appData.icsHost);
\r
769 second.programLogo = LoadImage( 0, buf, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
771 if(appData.secondDirectory && appData.secondDirectory[0]) {
\r
772 sprintf(buf, "%s\\logo.bmp", appData.secondDirectory);
\r
773 second.programLogo = LoadImage( 0, buf, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
779 iconWhite = LoadIcon(hInstance, "icon_white");
\r
780 iconBlack = LoadIcon(hInstance, "icon_black");
\r
781 iconCurrent = iconWhite;
\r
782 InitDrawingColors();
\r
783 screenHeight = GetSystemMetrics(SM_CYSCREEN);
\r
784 screenWidth = GetSystemMetrics(SM_CXSCREEN);
\r
785 for (ibs = (int) NUM_SIZES - 1; ibs >= 0; ibs--) {
\r
786 /* Compute window size for each board size, and use the largest
\r
787 size that fits on this screen as the default. */
\r
788 InitDrawingSizes((BoardSize)(ibs+1000), 0);
\r
789 if (boardSize == (BoardSize)-1 &&
\r
790 winH <= screenHeight
\r
791 - GetSystemMetrics(SM_CYFRAME) - GetSystemMetrics(SM_CYCAPTION) - 10
\r
792 && winW <= screenWidth) {
\r
793 boardSize = (BoardSize)ibs;
\r
797 InitDrawingSizes(boardSize, 0);
\r
799 buttonCount = GetSystemMetrics(SM_CMOUSEBUTTONS);
\r
801 /* [AS] Load textures if specified */
\r
802 ZeroMemory( &backTextureSquareInfo, sizeof(backTextureSquareInfo) );
\r
804 if( appData.liteBackTextureFile && appData.liteBackTextureFile[0] != NULLCHAR && appData.liteBackTextureFile[0] != '*' ) {
\r
805 liteBackTexture = LoadImage( 0, appData.liteBackTextureFile, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
806 liteBackTextureMode = appData.liteBackTextureMode;
\r
808 if (liteBackTexture == NULL && appData.debugMode) {
\r
809 fprintf( debugFP, "Unable to load lite texture bitmap '%s'\n", appData.liteBackTextureFile );
\r
813 if( appData.darkBackTextureFile && appData.darkBackTextureFile[0] != NULLCHAR && appData.darkBackTextureFile[0] != '*' ) {
\r
814 darkBackTexture = LoadImage( 0, appData.darkBackTextureFile, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
815 darkBackTextureMode = appData.darkBackTextureMode;
\r
817 if (darkBackTexture == NULL && appData.debugMode) {
\r
818 fprintf( debugFP, "Unable to load dark texture bitmap '%s'\n", appData.darkBackTextureFile );
\r
822 mysrandom( (unsigned) time(NULL) );
\r
824 /* [AS] Restore layout */
\r
825 if( wpMoveHistory.visible ) {
\r
826 MoveHistoryPopUp();
\r
829 if( wpEvalGraph.visible ) {
\r
833 if( wpEngineOutput.visible ) {
\r
834 EngineOutputPopUp();
\r
839 /* Make the window visible; update its client area; and return "success" */
\r
840 EnsureOnScreen(&wpMain.x, &wpMain.y, minX, minY);
\r
841 wp.length = sizeof(WINDOWPLACEMENT);
\r
843 wp.showCmd = nCmdShow;
\r
844 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
845 wp.rcNormalPosition.left = wpMain.x;
\r
846 wp.rcNormalPosition.right = wpMain.x + wpMain.width;
\r
847 wp.rcNormalPosition.top = wpMain.y;
\r
848 wp.rcNormalPosition.bottom = wpMain.y + wpMain.height;
\r
849 SetWindowPlacement(hwndMain, &wp);
\r
851 if(!appData.noGUI) SetWindowPos(hwndMain, alwaysOnTop ? HWND_TOPMOST : HWND_NOTOPMOST,
\r
852 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE);
\r
856 SetWindowPos(hwndConsole, alwaysOnTop ? HWND_TOPMOST : HWND_NOTOPMOST,
\r
857 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE);
\r
859 ShowWindow(hwndConsole, nCmdShow);
\r
861 if(!appData.noGUI) UpdateWindow(hwnd); else ShowWindow(hwnd, SW_MINIMIZE);
\r
862 if(gameListDialog) SetFocus(gameListDialog); // [HGM] jaws: for if we clicked multi-game game file
\r
871 HMENU hmenu = GetMenu(hwndMain);
\r
873 (void) EnableMenuItem(hmenu, IDM_CommPort,
\r
874 MF_BYCOMMAND|((appData.icsActive &&
\r
875 *appData.icsCommPort != NULLCHAR) ?
\r
876 MF_ENABLED : MF_GRAYED));
\r
877 (void) CheckMenuItem(hmenu, IDM_SaveSettingsOnExit,
\r
878 MF_BYCOMMAND|(saveSettingsOnExit ?
\r
879 MF_CHECKED : MF_UNCHECKED));
\r
882 //---------------------------------------------------------------------------------------------------------
\r
884 #define ICS_TEXT_MENU_SIZE (IDM_CommandXLast - IDM_CommandX + 1)
\r
885 #define XBOARD FALSE
\r
887 #define OPTCHAR "/"
\r
888 #define SEPCHAR "="
\r
892 // front-end part of option handling
\r
895 LFfromMFP(LOGFONT* lf, MyFontParams *mfp)
\r
897 HDC hdc = CreateDC("DISPLAY", NULL, NULL, NULL);
\r
898 lf->lfHeight = -(int)(mfp->pointSize * GetDeviceCaps(hdc, LOGPIXELSY) / 72.0 + 0.5);
\r
901 lf->lfEscapement = 0;
\r
902 lf->lfOrientation = 0;
\r
903 lf->lfWeight = mfp->bold ? FW_BOLD : FW_NORMAL;
\r
904 lf->lfItalic = mfp->italic;
\r
905 lf->lfUnderline = mfp->underline;
\r
906 lf->lfStrikeOut = mfp->strikeout;
\r
907 lf->lfCharSet = mfp->charset;
\r
908 lf->lfOutPrecision = OUT_DEFAULT_PRECIS;
\r
909 lf->lfClipPrecision = CLIP_DEFAULT_PRECIS;
\r
910 lf->lfQuality = DEFAULT_QUALITY;
\r
911 lf->lfPitchAndFamily = DEFAULT_PITCH|FF_DONTCARE;
\r
912 strcpy(lf->lfFaceName, mfp->faceName);
\r
916 CreateFontInMF(MyFont *mf)
\r
918 LFfromMFP(&mf->lf, &mf->mfp);
\r
919 if (mf->hf) DeleteObject(mf->hf);
\r
920 mf->hf = CreateFontIndirect(&mf->lf);
\r
923 // [HGM] This platform-dependent table provides the location for storing the color info
\r
925 colorVariable[] = {
\r
930 &highlightSquareColor,
\r
931 &premoveHighlightColor,
\r
933 &consoleBackgroundColor,
\r
934 &appData.fontForeColorWhite,
\r
935 &appData.fontBackColorWhite,
\r
936 &appData.fontForeColorBlack,
\r
937 &appData.fontBackColorBlack,
\r
938 &appData.evalHistColorWhite,
\r
939 &appData.evalHistColorBlack,
\r
940 &appData.highlightArrowColor,
\r
943 /* Command line font name parser. NULL name means do nothing.
\r
944 Syntax like "Courier New:10.0 bi" or "Arial:10" or "Arial:10b"
\r
945 For backward compatibility, syntax without the colon is also
\r
946 accepted, but font names with digits in them won't work in that case.
\r
949 ParseFontName(char *name, MyFontParams *mfp)
\r
952 if (name == NULL) return;
\r
954 q = strchr(p, ':');
\r
956 if (q - p >= sizeof(mfp->faceName))
\r
957 ExitArgError("Font name too long:", name);
\r
958 memcpy(mfp->faceName, p, q - p);
\r
959 mfp->faceName[q - p] = NULLCHAR;
\r
963 while (*p && !isdigit(*p)) {
\r
965 if (q - mfp->faceName >= sizeof(mfp->faceName))
\r
966 ExitArgError("Font name too long:", name);
\r
968 while (q > mfp->faceName && q[-1] == ' ') q--;
\r
971 if (!*p) ExitArgError("Font point size missing:", name);
\r
972 mfp->pointSize = (float) atof(p);
\r
973 mfp->bold = (strchr(p, 'b') != NULL);
\r
974 mfp->italic = (strchr(p, 'i') != NULL);
\r
975 mfp->underline = (strchr(p, 'u') != NULL);
\r
976 mfp->strikeout = (strchr(p, 's') != NULL);
\r
977 mfp->charset = DEFAULT_CHARSET;
\r
978 q = strchr(p, 'c');
\r
980 mfp->charset = (BYTE) atoi(q+1);
\r
984 ParseFont(char *name, int number)
\r
985 { // wrapper to shield back-end from 'font'
\r
986 ParseFontName(name, &font[boardSize][number]->mfp);
\r
991 { // in WB we have a 2D array of fonts; this initializes their description
\r
993 /* Point font array elements to structures and
\r
994 parse default font names */
\r
995 for (i=0; i<NUM_FONTS; i++) {
\r
996 for (j=0; j<NUM_SIZES; j++) {
\r
997 font[j][i] = &fontRec[j][i];
\r
998 ParseFontName(font[j][i]->def, &font[j][i]->mfp);
\r
1005 { // here we create the actual fonts from the selected descriptions
\r
1007 for (i=0; i<NUM_FONTS; i++) {
\r
1008 for (j=0; j<NUM_SIZES; j++) {
\r
1009 CreateFontInMF(font[j][i]);
\r
1013 /* Color name parser.
\r
1014 X version accepts X color names, but this one
\r
1015 handles only the #rrggbb form (hex) or rrr,ggg,bbb (decimal) */
\r
1017 ParseColorName(char *name)
\r
1019 int red, green, blue, count;
\r
1020 char buf[MSG_SIZ];
\r
1022 count = sscanf(name, "#%2x%2x%2x", &red, &green, &blue);
\r
1024 count = sscanf(name, "%3d%*[^0-9]%3d%*[^0-9]%3d",
\r
1025 &red, &green, &blue);
\r
1028 sprintf(buf, "Can't parse color name %s", name);
\r
1029 DisplayError(buf, 0);
\r
1030 return RGB(0, 0, 0);
\r
1032 return PALETTERGB(red, green, blue);
\r
1036 ParseColor(int n, char *name)
\r
1037 { // for WinBoard the color is an int, which needs to be derived from the string
\r
1038 if(colorVariable[n]) *(int*)colorVariable[n] = ParseColorName(name);
\r
1042 ParseAttribs(COLORREF *color, int *effects, char* argValue)
\r
1044 char *e = argValue;
\r
1048 if (*e == 'b') eff |= CFE_BOLD;
\r
1049 else if (*e == 'i') eff |= CFE_ITALIC;
\r
1050 else if (*e == 'u') eff |= CFE_UNDERLINE;
\r
1051 else if (*e == 's') eff |= CFE_STRIKEOUT;
\r
1052 else if (*e == '#' || isdigit(*e)) break;
\r
1056 *color = ParseColorName(e);
\r
1060 ParseTextAttribs(ColorClass cc, char *s)
\r
1061 { // [HGM] front-end wrapper that does the platform-dependent call
\r
1062 // for XBoard we would set (&appData.colorShout)[cc] = strdup(s);
\r
1063 ParseAttribs(&textAttribs[cc].color, &textAttribs[cc].effects, s);
\r
1067 ParseBoardSize(void *addr, char *name)
\r
1068 { // [HGM] rewritten with return-value ptr to shield back-end from BoardSize
\r
1069 BoardSize bs = SizeTiny;
\r
1070 while (sizeInfo[bs].name != NULL) {
\r
1071 if (StrCaseCmp(name, sizeInfo[bs].name) == 0) {
\r
1072 *(BoardSize *)addr = bs;
\r
1077 ExitArgError("Unrecognized board size value", name);
\r
1082 { // [HGM] import name from appData first
\r
1085 for (cc = (ColorClass)0; cc < ColorNormal; cc++) {
\r
1086 textAttribs[cc].sound.name = strdup((&appData.soundShout)[cc]);
\r
1087 textAttribs[cc].sound.data = NULL;
\r
1088 MyLoadSound(&textAttribs[cc].sound);
\r
1090 for (cc = ColorNormal; cc < NColorClasses; cc++) {
\r
1091 textAttribs[cc].sound.name = strdup("");
\r
1092 textAttribs[cc].sound.data = NULL;
\r
1094 for (sc = (SoundClass)0; sc < NSoundClasses; sc++) {
\r
1095 sounds[sc].name = strdup((&appData.soundMove)[sc]);
\r
1096 sounds[sc].data = NULL;
\r
1097 MyLoadSound(&sounds[sc]);
\r
1102 SetCommPortDefaults()
\r
1104 memset(&dcb, 0, sizeof(DCB)); // required by VS 2002 +
\r
1105 dcb.DCBlength = sizeof(DCB);
\r
1106 dcb.BaudRate = 9600;
\r
1107 dcb.fBinary = TRUE;
\r
1108 dcb.fParity = FALSE;
\r
1109 dcb.fOutxCtsFlow = FALSE;
\r
1110 dcb.fOutxDsrFlow = FALSE;
\r
1111 dcb.fDtrControl = DTR_CONTROL_ENABLE;
\r
1112 dcb.fDsrSensitivity = FALSE;
\r
1113 dcb.fTXContinueOnXoff = TRUE;
\r
1114 dcb.fOutX = FALSE;
\r
1116 dcb.fNull = FALSE;
\r
1117 dcb.fRtsControl = RTS_CONTROL_ENABLE;
\r
1118 dcb.fAbortOnError = FALSE;
\r
1120 dcb.Parity = SPACEPARITY;
\r
1121 dcb.StopBits = ONESTOPBIT;
\r
1124 // [HGM] args: these three cases taken out to stay in front-end
\r
1126 SaveFontArg(FILE *f, ArgDescriptor *ad)
\r
1127 { // in WinBoard every board size has its own font, and the "argLoc" identifies the table,
\r
1128 // while the curent board size determines the element. This system should be ported to XBoard.
\r
1129 // What the table contains pointers to, and how to print the font description, remains platform-dependent
\r
1131 for (bs=0; bs<NUM_SIZES; bs++) {
\r
1132 MyFontParams *mfp = &font[bs][(int) ad->argLoc]->mfp;
\r
1133 fprintf(f, "/size=%s ", sizeInfo[bs].name);
\r
1134 fprintf(f, "/%s=\"%s:%g%s%s%s%s%sc%d\"\n",
\r
1135 ad->argName, mfp->faceName, mfp->pointSize,
\r
1136 mfp->bold || mfp->italic || mfp->underline || mfp->strikeout ? " " : "",
\r
1137 mfp->bold ? "b" : "",
\r
1138 mfp->italic ? "i" : "",
\r
1139 mfp->underline ? "u" : "",
\r
1140 mfp->strikeout ? "s" : "",
\r
1141 (int)mfp->charset);
\r
1147 { // [HGM] copy the names from the internal WB variables to appData
\r
1150 for (cc = (ColorClass)0; cc < ColorNormal; cc++)
\r
1151 (&appData.soundShout)[cc] = textAttribs[cc].sound.name;
\r
1152 for (sc = (SoundClass)0; sc < NSoundClasses; sc++)
\r
1153 (&appData.soundMove)[sc] = sounds[sc].name;
\r
1157 SaveAttribsArg(FILE *f, ArgDescriptor *ad)
\r
1158 { // here the "argLoc" defines a table index. It could have contained the 'ta' pointer itself, though
\r
1159 MyTextAttribs* ta = &textAttribs[(ColorClass)ad->argLoc];
\r
1160 fprintf(f, "/%s=\"%s%s%s%s%s#%02lx%02lx%02lx\"\n", ad->argName,
\r
1161 (ta->effects & CFE_BOLD) ? "b" : "",
\r
1162 (ta->effects & CFE_ITALIC) ? "i" : "",
\r
1163 (ta->effects & CFE_UNDERLINE) ? "u" : "",
\r
1164 (ta->effects & CFE_STRIKEOUT) ? "s" : "",
\r
1165 (ta->effects) ? " " : "",
\r
1166 ta->color&0xff, (ta->color >> 8)&0xff, (ta->color >> 16)&0xff);
\r
1170 SaveColor(FILE *f, ArgDescriptor *ad)
\r
1171 { // in WinBoard the color is an int and has to be converted to text. In X it would be a string already?
\r
1172 COLORREF color = *(COLORREF *)colorVariable[(int)ad->argLoc];
\r
1173 fprintf(f, "/%s=#%02lx%02lx%02lx\n", ad->argName,
\r
1174 color&0xff, (color>>8)&0xff, (color>>16)&0xff);
\r
1178 SaveBoardSize(FILE *f, char *name, void *addr)
\r
1179 { // wrapper to shield back-end from BoardSize & sizeInfo
\r
1180 fprintf(f, "/%s=%s\n", name, sizeInfo[*(BoardSize *)addr].name);
\r
1184 ParseCommPortSettings(char *s)
\r
1185 { // wrapper to keep dcb from back-end
\r
1186 ParseCommSettings(s, &dcb);
\r
1191 { // wrapper to shield use of window handles from back-end (make addressible by number?)
\r
1192 GetActualPlacement(hwndMain, &wpMain);
\r
1193 GetActualPlacement(hwndConsole, &wpConsole);
\r
1194 GetActualPlacement(commentDialog, &wpComment);
\r
1195 GetActualPlacement(editTagsDialog, &wpTags);
\r
1196 GetActualPlacement(gameListDialog, &wpGameList);
\r
1197 GetActualPlacement(moveHistoryDialog, &wpMoveHistory);
\r
1198 GetActualPlacement(evalGraphDialog, &wpEvalGraph);
\r
1199 GetActualPlacement(engineOutputDialog, &wpEngineOutput);
\r
1203 PrintCommPortSettings(FILE *f, char *name)
\r
1204 { // wrapper to shield back-end from DCB
\r
1205 PrintCommSettings(f, name, &dcb);
\r
1209 MySearchPath(char *installDir, char *name, char *fullname)
\r
1212 return (int) SearchPath(installDir, name, NULL, MSG_SIZ, fullname, &dummy);
\r
1216 MyGetFullPathName(char *name, char *fullname)
\r
1219 return (int) GetFullPathName(name, MSG_SIZ, fullname, &dummy);
\r
1224 { // [HGM] args: allows testing if main window is realized from back-end
\r
1225 return hwndMain != NULL;
\r
1229 PopUpStartupDialog()
\r
1233 lpProc = MakeProcInstance((FARPROC)StartupDialog, hInst);
\r
1234 DialogBox(hInst, MAKEINTRESOURCE(DLG_Startup), NULL, (DLGPROC)lpProc);
\r
1235 FreeProcInstance(lpProc);
\r
1238 /*---------------------------------------------------------------------------*\
\r
1240 * GDI board drawing routines
\r
1242 \*---------------------------------------------------------------------------*/
\r
1244 /* [AS] Draw square using background texture */
\r
1245 static void DrawTile( int dx, int dy, int dw, int dh, HDC dst, HDC src, int mode, int sx, int sy )
\r
1250 return; /* Should never happen! */
\r
1253 SetGraphicsMode( dst, GM_ADVANCED );
\r
1260 /* X reflection */
\r
1265 x.eDx = (FLOAT) dw + dx - 1;
\r
1268 SetWorldTransform( dst, &x );
\r
1271 /* Y reflection */
\r
1277 x.eDy = (FLOAT) dh + dy - 1;
\r
1279 SetWorldTransform( dst, &x );
\r
1287 x.eDx = (FLOAT) dx;
\r
1288 x.eDy = (FLOAT) dy;
\r
1291 SetWorldTransform( dst, &x );
\r
1295 BitBlt( dst, dx, dy, dw, dh, src, sx, sy, SRCCOPY );
\r
1303 SetWorldTransform( dst, &x );
\r
1305 ModifyWorldTransform( dst, 0, MWT_IDENTITY );
\r
1308 /* [AS] [HGM] Make room for more piece types, so all pieces can be different */
\r
1310 PM_WP = (int) WhitePawn,
\r
1311 PM_WN = (int) WhiteKnight,
\r
1312 PM_WB = (int) WhiteBishop,
\r
1313 PM_WR = (int) WhiteRook,
\r
1314 PM_WQ = (int) WhiteQueen,
\r
1315 PM_WF = (int) WhiteFerz,
\r
1316 PM_WW = (int) WhiteWazir,
\r
1317 PM_WE = (int) WhiteAlfil,
\r
1318 PM_WM = (int) WhiteMan,
\r
1319 PM_WO = (int) WhiteCannon,
\r
1320 PM_WU = (int) WhiteUnicorn,
\r
1321 PM_WH = (int) WhiteNightrider,
\r
1322 PM_WA = (int) WhiteAngel,
\r
1323 PM_WC = (int) WhiteMarshall,
\r
1324 PM_WAB = (int) WhiteCardinal,
\r
1325 PM_WD = (int) WhiteDragon,
\r
1326 PM_WL = (int) WhiteLance,
\r
1327 PM_WS = (int) WhiteCobra,
\r
1328 PM_WV = (int) WhiteFalcon,
\r
1329 PM_WSG = (int) WhiteSilver,
\r
1330 PM_WG = (int) WhiteGrasshopper,
\r
1331 PM_WK = (int) WhiteKing,
\r
1332 PM_BP = (int) BlackPawn,
\r
1333 PM_BN = (int) BlackKnight,
\r
1334 PM_BB = (int) BlackBishop,
\r
1335 PM_BR = (int) BlackRook,
\r
1336 PM_BQ = (int) BlackQueen,
\r
1337 PM_BF = (int) BlackFerz,
\r
1338 PM_BW = (int) BlackWazir,
\r
1339 PM_BE = (int) BlackAlfil,
\r
1340 PM_BM = (int) BlackMan,
\r
1341 PM_BO = (int) BlackCannon,
\r
1342 PM_BU = (int) BlackUnicorn,
\r
1343 PM_BH = (int) BlackNightrider,
\r
1344 PM_BA = (int) BlackAngel,
\r
1345 PM_BC = (int) BlackMarshall,
\r
1346 PM_BG = (int) BlackGrasshopper,
\r
1347 PM_BAB = (int) BlackCardinal,
\r
1348 PM_BD = (int) BlackDragon,
\r
1349 PM_BL = (int) BlackLance,
\r
1350 PM_BS = (int) BlackCobra,
\r
1351 PM_BV = (int) BlackFalcon,
\r
1352 PM_BSG = (int) BlackSilver,
\r
1353 PM_BK = (int) BlackKing
\r
1356 static HFONT hPieceFont = NULL;
\r
1357 static HBITMAP hPieceMask[(int) EmptySquare];
\r
1358 static HBITMAP hPieceFace[(int) EmptySquare];
\r
1359 static int fontBitmapSquareSize = 0;
\r
1360 static char pieceToFontChar[(int) EmptySquare] =
\r
1361 { 'p', 'n', 'b', 'r', 'q',
\r
1362 'n', 'b', 'p', 'n', 'b', 'r', 'b', 'r', 'q', 'k',
\r
1363 'k', 'o', 'm', 'v', 't', 'w',
\r
1364 'v', 't', 'o', 'm', 'v', 't', 'v', 't', 'w', 'l',
\r
1367 extern BOOL SetCharTable( char *table, const char * map );
\r
1368 /* [HGM] moved to backend.c */
\r
1370 static void SetPieceBackground( HDC hdc, COLORREF color, int mode )
\r
1373 BYTE r1 = GetRValue( color );
\r
1374 BYTE g1 = GetGValue( color );
\r
1375 BYTE b1 = GetBValue( color );
\r
1381 /* Create a uniform background first */
\r
1382 hbrush = CreateSolidBrush( color );
\r
1383 SetRect( &rc, 0, 0, squareSize, squareSize );
\r
1384 FillRect( hdc, &rc, hbrush );
\r
1385 DeleteObject( hbrush );
\r
1388 /* Vertical gradient, good for pawn, knight and rook, less for queen and king */
\r
1389 int steps = squareSize / 2;
\r
1392 for( i=0; i<steps; i++ ) {
\r
1393 BYTE r = r1 - (r1-r2) * i / steps;
\r
1394 BYTE g = g1 - (g1-g2) * i / steps;
\r
1395 BYTE b = b1 - (b1-b2) * i / steps;
\r
1397 hbrush = CreateSolidBrush( RGB(r,g,b) );
\r
1398 SetRect( &rc, i + squareSize - steps, 0, i + squareSize - steps + 1, squareSize );
\r
1399 FillRect( hdc, &rc, hbrush );
\r
1400 DeleteObject(hbrush);
\r
1403 else if( mode == 2 ) {
\r
1404 /* Diagonal gradient, good more or less for every piece */
\r
1405 POINT triangle[3];
\r
1406 HPEN hpen = SelectObject( hdc, GetStockObject(NULL_PEN) );
\r
1407 HBRUSH hbrush_old;
\r
1408 int steps = squareSize;
\r
1411 triangle[0].x = squareSize - steps;
\r
1412 triangle[0].y = squareSize;
\r
1413 triangle[1].x = squareSize;
\r
1414 triangle[1].y = squareSize;
\r
1415 triangle[2].x = squareSize;
\r
1416 triangle[2].y = squareSize - steps;
\r
1418 for( i=0; i<steps; i++ ) {
\r
1419 BYTE r = r1 - (r1-r2) * i / steps;
\r
1420 BYTE g = g1 - (g1-g2) * i / steps;
\r
1421 BYTE b = b1 - (b1-b2) * i / steps;
\r
1423 hbrush = CreateSolidBrush( RGB(r,g,b) );
\r
1424 hbrush_old = SelectObject( hdc, hbrush );
\r
1425 Polygon( hdc, triangle, 3 );
\r
1426 SelectObject( hdc, hbrush_old );
\r
1427 DeleteObject(hbrush);
\r
1432 SelectObject( hdc, hpen );
\r
1437 [AS] The method I use to create the bitmaps it a bit tricky, but it
\r
1438 seems to work ok. The main problem here is to find the "inside" of a chess
\r
1439 piece: follow the steps as explained below.
\r
1441 static void CreatePieceMaskFromFont( HDC hdc_window, HDC hdc, int index )
\r
1445 COLORREF chroma = RGB(0xFF,0x00,0xFF);
\r
1449 int backColor = whitePieceColor;
\r
1450 int foreColor = blackPieceColor;
\r
1452 if( index < (int)BlackPawn && appData.fontBackColorWhite != appData.fontForeColorWhite ) {
\r
1453 backColor = appData.fontBackColorWhite;
\r
1454 foreColor = appData.fontForeColorWhite;
\r
1456 else if( index >= (int)BlackPawn && appData.fontBackColorBlack != appData.fontForeColorBlack ) {
\r
1457 backColor = appData.fontBackColorBlack;
\r
1458 foreColor = appData.fontForeColorBlack;
\r
1462 hbm = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
\r
1464 hbm_old = SelectObject( hdc, hbm );
\r
1468 rc.right = squareSize;
\r
1469 rc.bottom = squareSize;
\r
1471 /* Step 1: background is now black */
\r
1472 FillRect( hdc, &rc, GetStockObject(BLACK_BRUSH) );
\r
1474 GetTextExtentPoint32( hdc, &pieceToFontChar[index], 1, &sz );
\r
1476 pt.x = (squareSize - sz.cx) / 2;
\r
1477 pt.y = (squareSize - sz.cy) / 2;
\r
1479 SetBkMode( hdc, TRANSPARENT );
\r
1480 SetTextColor( hdc, chroma );
\r
1481 /* Step 2: the piece has been drawn in purple, there are now black and purple in this bitmap */
\r
1482 TextOut( hdc, pt.x, pt.y, &pieceToFontChar[appData.allWhite && index >= (int)BlackPawn ? index - (int)BlackPawn : index], 1 );
\r
1484 SelectObject( hdc, GetStockObject(WHITE_BRUSH) );
\r
1485 /* Step 3: the area outside the piece is filled with white */
\r
1486 // FloodFill( hdc, 0, 0, chroma );
\r
1487 ExtFloodFill( hdc, 0, 0, 0, FLOODFILLSURFACE );
\r
1488 ExtFloodFill( hdc, 0, squareSize-1, 0, FLOODFILLSURFACE ); // [HGM] fill from all 4 corners, for if piece too big
\r
1489 ExtFloodFill( hdc, squareSize-1, 0, 0, FLOODFILLSURFACE );
\r
1490 ExtFloodFill( hdc, squareSize-1, squareSize-1, 0, FLOODFILLSURFACE );
\r
1491 SelectObject( hdc, GetStockObject(BLACK_BRUSH) );
\r
1493 Step 4: this is the tricky part, the area inside the piece is filled with black,
\r
1494 but if the start point is not inside the piece we're lost!
\r
1495 There should be a better way to do this... if we could create a region or path
\r
1496 from the fill operation we would be fine for example.
\r
1498 // FloodFill( hdc, squareSize / 2, squareSize / 2, RGB(0xFF,0xFF,0xFF) );
\r
1499 ExtFloodFill( hdc, squareSize / 2, squareSize / 2, RGB(0xFF,0xFF,0xFF), FLOODFILLBORDER );
\r
1501 { /* [HGM] shave off edges of mask, in an attempt to correct for the fact that FloodFill does not work correctly under Win XP */
\r
1502 HDC dc2 = CreateCompatibleDC( hdc_window );
\r
1503 HBITMAP bm2 = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
\r
1505 SelectObject( dc2, bm2 );
\r
1506 BitBlt( dc2, 0, 0, squareSize, squareSize, hdc, 0, 0, SRCCOPY ); // make copy
\r
1507 BitBlt( hdc, 0, 1, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );
\r
1508 BitBlt( hdc, 2, 1, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );
\r
1509 BitBlt( hdc, 1, 0, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );
\r
1510 BitBlt( hdc, 1, 2, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );
\r
1513 DeleteObject( bm2 );
\r
1516 SetTextColor( hdc, 0 );
\r
1518 Step 5: some fonts have "disconnected" areas that are skipped by the fill:
\r
1519 draw the piece again in black for safety.
\r
1521 TextOut( hdc, pt.x, pt.y, &pieceToFontChar[appData.allWhite && index >= (int)BlackPawn ? index - (int)BlackPawn : index], 1 );
\r
1523 SelectObject( hdc, hbm_old );
\r
1525 if( hPieceMask[index] != NULL ) {
\r
1526 DeleteObject( hPieceMask[index] );
\r
1529 hPieceMask[index] = hbm;
\r
1532 hbm = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
\r
1534 SelectObject( hdc, hbm );
\r
1537 HDC dc1 = CreateCompatibleDC( hdc_window );
\r
1538 HDC dc2 = CreateCompatibleDC( hdc_window );
\r
1539 HBITMAP bm2 = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
\r
1541 SelectObject( dc1, hPieceMask[index] );
\r
1542 SelectObject( dc2, bm2 );
\r
1543 FillRect( dc2, &rc, GetStockObject(WHITE_BRUSH) );
\r
1544 BitBlt( dc2, 0, 0, squareSize, squareSize, dc1, 0, 0, SRCINVERT );
\r
1547 Now dc2 contains the inverse of the piece mask, i.e. a mask that preserves
\r
1548 the piece background and deletes (makes transparent) the rest.
\r
1549 Thanks to that mask, we are free to paint the background with the greates
\r
1550 freedom, as we'll be able to mask off the unwanted parts when finished.
\r
1551 We use this, to make gradients and give the pieces a "roundish" look.
\r
1553 SetPieceBackground( hdc, backColor, 2 );
\r
1554 BitBlt( hdc, 0, 0, squareSize, squareSize, dc2, 0, 0, SRCAND );
\r
1558 DeleteObject( bm2 );
\r
1561 SetTextColor( hdc, foreColor );
\r
1562 TextOut( hdc, pt.x, pt.y, &pieceToFontChar[appData.allWhite && index >= (int)BlackPawn ? index - (int)BlackPawn : index], 1 );
\r
1564 SelectObject( hdc, hbm_old );
\r
1566 if( hPieceFace[index] != NULL ) {
\r
1567 DeleteObject( hPieceFace[index] );
\r
1570 hPieceFace[index] = hbm;
\r
1573 static int TranslatePieceToFontPiece( int piece )
\r
1603 case BlackMarshall:
\r
1607 case BlackNightrider:
\r
1613 case BlackUnicorn:
\r
1617 case BlackGrasshopper:
\r
1629 case BlackCardinal:
\r
1636 case WhiteMarshall:
\r
1640 case WhiteNightrider:
\r
1646 case WhiteUnicorn:
\r
1650 case WhiteGrasshopper:
\r
1662 case WhiteCardinal:
\r
1671 void CreatePiecesFromFont()
\r
1674 HDC hdc_window = NULL;
\r
1680 if( fontBitmapSquareSize < 0 ) {
\r
1681 /* Something went seriously wrong in the past: do not try to recreate fonts! */
\r
1685 if( appData.renderPiecesWithFont == NULL || appData.renderPiecesWithFont[0] == NULLCHAR || appData.renderPiecesWithFont[0] == '*' ) {
\r
1686 fontBitmapSquareSize = -1;
\r
1690 if( fontBitmapSquareSize != squareSize ) {
\r
1691 hdc_window = GetDC( hwndMain );
\r
1692 hdc = CreateCompatibleDC( hdc_window );
\r
1694 if( hPieceFont != NULL ) {
\r
1695 DeleteObject( hPieceFont );
\r
1698 for( i=0; i<=(int)BlackKing; i++ ) {
\r
1699 hPieceMask[i] = NULL;
\r
1700 hPieceFace[i] = NULL;
\r
1706 if( appData.fontPieceSize >= 50 && appData.fontPieceSize <= 150 ) {
\r
1707 fontHeight = appData.fontPieceSize;
\r
1710 fontHeight = (fontHeight * squareSize) / 100;
\r
1712 lf.lfHeight = -MulDiv( fontHeight, GetDeviceCaps(hdc, LOGPIXELSY), 72 );
\r
1714 lf.lfEscapement = 0;
\r
1715 lf.lfOrientation = 0;
\r
1716 lf.lfWeight = FW_NORMAL;
\r
1718 lf.lfUnderline = 0;
\r
1719 lf.lfStrikeOut = 0;
\r
1720 lf.lfCharSet = DEFAULT_CHARSET;
\r
1721 lf.lfOutPrecision = OUT_DEFAULT_PRECIS;
\r
1722 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
\r
1723 lf.lfQuality = PROOF_QUALITY;
\r
1724 lf.lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;
\r
1725 strncpy( lf.lfFaceName, appData.renderPiecesWithFont, sizeof(lf.lfFaceName) );
\r
1726 lf.lfFaceName[ sizeof(lf.lfFaceName) - 1 ] = '\0';
\r
1728 hPieceFont = CreateFontIndirect( &lf );
\r
1730 if( hPieceFont == NULL ) {
\r
1731 fontBitmapSquareSize = -2;
\r
1734 /* Setup font-to-piece character table */
\r
1735 if( ! SetCharTable(pieceToFontChar, appData.fontToPieceTable) ) {
\r
1736 /* No (or wrong) global settings, try to detect the font */
\r
1737 if( strstr(lf.lfFaceName,"Alpha") != NULL ) {
\r
1739 SetCharTable(pieceToFontChar, "phbrqkojntwl");
\r
1741 else if( strstr(lf.lfFaceName,"DiagramTT") != NULL ) {
\r
1742 /* DiagramTT* family */
\r
1743 SetCharTable(pieceToFontChar, "PNLRQKpnlrqk");
\r
1745 else if( strstr(lf.lfFaceName,"WinboardF") != NULL ) {
\r
1746 /* Fairy symbols */
\r
1747 SetCharTable(pieceToFontChar, "PNBRQFEACWMOHIJGDVSLUKpnbrqfeacwmohijgdvsluk");
\r
1749 else if( strstr(lf.lfFaceName,"GC2004D") != NULL ) {
\r
1750 /* Good Companion (Some characters get warped as literal :-( */
\r
1751 char s[] = "1cmWG0??S??oYI23wgQU";
\r
1752 s[0]=0xB9; s[1]=0xA9; s[6]=0xB1; s[11]=0xBB; s[12]=0xAB; s[17]=0xB3;
\r
1753 SetCharTable(pieceToFontChar, s);
\r
1756 /* Cases, Condal, Leipzig, Lucena, Marroquin, Merida, Usual */
\r
1757 SetCharTable(pieceToFontChar, "pnbrqkomvtwl");
\r
1761 /* Create bitmaps */
\r
1762 hfont_old = SelectObject( hdc, hPieceFont );
\r
1763 for(i=(int)WhitePawn; i<(int)EmptySquare; i++) /* [HGM] made a loop for this */
\r
1764 if(PieceToChar((ChessSquare)i) != '.') /* skip unused pieces */
\r
1765 CreatePieceMaskFromFont( hdc_window, hdc, i );
\r
1767 SelectObject( hdc, hfont_old );
\r
1769 fontBitmapSquareSize = squareSize;
\r
1773 if( hdc != NULL ) {
\r
1777 if( hdc_window != NULL ) {
\r
1778 ReleaseDC( hwndMain, hdc_window );
\r
1783 DoLoadBitmap(HINSTANCE hinst, char *piece, int squareSize, char *suffix)
\r
1787 sprintf(name, "%s%d%s", piece, squareSize, suffix);
\r
1788 if (gameInfo.event &&
\r
1789 strcmp(gameInfo.event, "Easter Egg Hunt") == 0 &&
\r
1790 strcmp(name, "k80s") == 0) {
\r
1791 strcpy(name, "tim");
\r
1793 return LoadBitmap(hinst, name);
\r
1797 /* Insert a color into the program's logical palette
\r
1798 structure. This code assumes the given color is
\r
1799 the result of the RGB or PALETTERGB macro, and it
\r
1800 knows how those macros work (which is documented).
\r
1803 InsertInPalette(COLORREF color)
\r
1805 LPPALETTEENTRY pe = &(pLogPal->palPalEntry[pLogPal->palNumEntries]);
\r
1807 if (pLogPal->palNumEntries++ >= PALETTESIZE) {
\r
1808 DisplayFatalError("Too many colors", 0, 1);
\r
1809 pLogPal->palNumEntries--;
\r
1813 pe->peFlags = (char) 0;
\r
1814 pe->peRed = (char) (0xFF & color);
\r
1815 pe->peGreen = (char) (0xFF & (color >> 8));
\r
1816 pe->peBlue = (char) (0xFF & (color >> 16));
\r
1822 InitDrawingColors()
\r
1824 if (pLogPal == NULL) {
\r
1825 /* Allocate enough memory for a logical palette with
\r
1826 * PALETTESIZE entries and set the size and version fields
\r
1827 * of the logical palette structure.
\r
1829 pLogPal = (NPLOGPALETTE)
\r
1830 LocalAlloc(LMEM_FIXED, (sizeof(LOGPALETTE) +
\r
1831 (sizeof(PALETTEENTRY) * (PALETTESIZE))));
\r
1832 pLogPal->palVersion = 0x300;
\r
1834 pLogPal->palNumEntries = 0;
\r
1836 InsertInPalette(lightSquareColor);
\r
1837 InsertInPalette(darkSquareColor);
\r
1838 InsertInPalette(whitePieceColor);
\r
1839 InsertInPalette(blackPieceColor);
\r
1840 InsertInPalette(highlightSquareColor);
\r
1841 InsertInPalette(premoveHighlightColor);
\r
1843 /* create a logical color palette according the information
\r
1844 * in the LOGPALETTE structure.
\r
1846 hPal = CreatePalette((LPLOGPALETTE) pLogPal);
\r
1848 lightSquareBrush = CreateSolidBrush(lightSquareColor);
\r
1849 blackSquareBrush = CreateSolidBrush(blackPieceColor);
\r
1850 darkSquareBrush = CreateSolidBrush(darkSquareColor);
\r
1851 whitePieceBrush = CreateSolidBrush(whitePieceColor);
\r
1852 blackPieceBrush = CreateSolidBrush(blackPieceColor);
\r
1853 iconBkgndBrush = CreateSolidBrush(GetSysColor(COLOR_BACKGROUND));
\r
1854 explodeBrush = CreateSolidBrush(highlightSquareColor); // [HGM] atomic
\r
1855 /* [AS] Force rendering of the font-based pieces */
\r
1856 if( fontBitmapSquareSize > 0 ) {
\r
1857 fontBitmapSquareSize = 0;
\r
1863 BoardWidth(int boardSize, int n)
\r
1864 { /* [HGM] argument n added to allow different width and height */
\r
1865 int lineGap = sizeInfo[boardSize].lineGap;
\r
1867 if( appData.overrideLineGap >= 0 && appData.overrideLineGap <= 5 ) {
\r
1868 lineGap = appData.overrideLineGap;
\r
1871 return (n + 1) * lineGap +
\r
1872 n * sizeInfo[boardSize].squareSize;
\r
1875 /* Respond to board resize by dragging edge */
\r
1877 ResizeBoard(int newSizeX, int newSizeY, int flags)
\r
1879 BoardSize newSize = NUM_SIZES - 1;
\r
1880 static int recurse = 0;
\r
1881 if (IsIconic(hwndMain)) return;
\r
1882 if (recurse > 0) return;
\r
1884 while (newSize > 0) {
\r
1885 InitDrawingSizes(newSize+1000, 0); // [HGM] kludge to update sizeInfo without visible effects
\r
1886 if(newSizeX >= sizeInfo[newSize].cliWidth &&
\r
1887 newSizeY >= sizeInfo[newSize].cliHeight) break;
\r
1890 boardSize = newSize;
\r
1891 InitDrawingSizes(boardSize, flags);
\r
1898 InitDrawingSizes(BoardSize boardSize, int flags)
\r
1900 int i, boardWidth, boardHeight; /* [HGM] height treated separately */
\r
1901 ChessSquare piece;
\r
1902 static int oldBoardSize = -1, oldTinyLayout = 0;
\r
1904 SIZE clockSize, messageSize;
\r
1906 char buf[MSG_SIZ];
\r
1908 HMENU hmenu = GetMenu(hwndMain);
\r
1909 RECT crect, wrect, oldRect;
\r
1911 LOGBRUSH logbrush;
\r
1913 int suppressVisibleEffects = 0; // [HGM] kludge to request updating sizeInfo only
\r
1914 if((int)boardSize >= 1000 ) { boardSize -= 1000; suppressVisibleEffects = 1; }
\r
1916 /* [HGM] call with -2 uses old size (for if nr of files, ranks changes) */
\r
1917 if(boardSize == (BoardSize)(-2) ) boardSize = oldBoardSize;
\r
1919 oldRect.left = wpMain.x; //[HGM] placement: remember previous window params
\r
1920 oldRect.top = wpMain.y;
\r
1921 oldRect.right = wpMain.x + wpMain.width;
\r
1922 oldRect.bottom = wpMain.y + wpMain.height;
\r
1924 tinyLayout = sizeInfo[boardSize].tinyLayout;
\r
1925 smallLayout = sizeInfo[boardSize].smallLayout;
\r
1926 squareSize = sizeInfo[boardSize].squareSize;
\r
1927 lineGap = sizeInfo[boardSize].lineGap;
\r
1928 minorSize = 0; /* [HGM] Kludge to see if demagnified pieces need to be shifted */
\r
1930 if( appData.overrideLineGap >= 0 && appData.overrideLineGap <= 5 ) {
\r
1931 lineGap = appData.overrideLineGap;
\r
1934 if (tinyLayout != oldTinyLayout) {
\r
1935 long style = GetWindowLong(hwndMain, GWL_STYLE);
\r
1937 style &= ~WS_SYSMENU;
\r
1938 InsertMenu(hmenu, IDM_Exit, MF_BYCOMMAND, IDM_Minimize,
\r
1939 "&Minimize\tCtrl+F4");
\r
1941 style |= WS_SYSMENU;
\r
1942 RemoveMenu(hmenu, IDM_Minimize, MF_BYCOMMAND);
\r
1944 SetWindowLong(hwndMain, GWL_STYLE, style);
\r
1946 for (i=0; menuBarText[tinyLayout][i]; i++) {
\r
1947 ModifyMenu(hmenu, i, MF_STRING|MF_BYPOSITION|MF_POPUP,
\r
1948 (UINT)GetSubMenu(hmenu, i), menuBarText[tinyLayout][i]);
\r
1950 DrawMenuBar(hwndMain);
\r
1953 boardWidth = BoardWidth(boardSize, BOARD_WIDTH);
\r
1954 boardHeight = BoardWidth(boardSize, BOARD_HEIGHT);
\r
1956 /* Get text area sizes */
\r
1957 hdc = GetDC(hwndMain);
\r
1958 if (appData.clockMode) {
\r
1959 sprintf(buf, "White: %s", TimeString(23*60*60*1000L));
\r
1961 sprintf(buf, "White");
\r
1963 oldFont = SelectObject(hdc, font[boardSize][CLOCK_FONT]->hf);
\r
1964 GetTextExtentPoint(hdc, buf, strlen(buf), &clockSize);
\r
1965 SelectObject(hdc, font[boardSize][MESSAGE_FONT]->hf);
\r
1966 str = "We only care about the height here";
\r
1967 GetTextExtentPoint(hdc, str, strlen(str), &messageSize);
\r
1968 SelectObject(hdc, oldFont);
\r
1969 ReleaseDC(hwndMain, hdc);
\r
1971 /* Compute where everything goes */
\r
1972 if((first.programLogo || second.programLogo) && !tinyLayout) {
\r
1973 /* [HGM] logo: if either logo is on, reserve space for it */
\r
1974 logoHeight = 2*clockSize.cy;
\r
1975 leftLogoRect.left = OUTER_MARGIN;
\r
1976 leftLogoRect.right = leftLogoRect.left + 4*clockSize.cy;
\r
1977 leftLogoRect.top = OUTER_MARGIN;
\r
1978 leftLogoRect.bottom = OUTER_MARGIN + logoHeight;
\r
1980 rightLogoRect.right = OUTER_MARGIN + boardWidth;
\r
1981 rightLogoRect.left = rightLogoRect.right - 4*clockSize.cy;
\r
1982 rightLogoRect.top = OUTER_MARGIN;
\r
1983 rightLogoRect.bottom = OUTER_MARGIN + logoHeight;
\r
1986 whiteRect.left = leftLogoRect.right;
\r
1987 whiteRect.right = OUTER_MARGIN + boardWidth/2 - INNER_MARGIN/2;
\r
1988 whiteRect.top = OUTER_MARGIN;
\r
1989 whiteRect.bottom = whiteRect.top + logoHeight;
\r
1991 blackRect.right = rightLogoRect.left;
\r
1992 blackRect.left = whiteRect.right + INNER_MARGIN;
\r
1993 blackRect.top = whiteRect.top;
\r
1994 blackRect.bottom = whiteRect.bottom;
\r
1996 whiteRect.left = OUTER_MARGIN;
\r
1997 whiteRect.right = whiteRect.left + boardWidth/2 - INNER_MARGIN/2;
\r
1998 whiteRect.top = OUTER_MARGIN;
\r
1999 whiteRect.bottom = whiteRect.top + clockSize.cy;
\r
2001 blackRect.left = whiteRect.right + INNER_MARGIN;
\r
2002 blackRect.right = blackRect.left + boardWidth/2 - 1;
\r
2003 blackRect.top = whiteRect.top;
\r
2004 blackRect.bottom = whiteRect.bottom;
\r
2007 messageRect.left = OUTER_MARGIN + MESSAGE_LINE_LEFTMARGIN;
\r
2008 if (appData.showButtonBar) {
\r
2009 messageRect.right = OUTER_MARGIN + boardWidth // [HGM] logo: expressed independent of clock placement
\r
2010 - N_BUTTONS*BUTTON_WIDTH - MESSAGE_LINE_LEFTMARGIN;
\r
2012 messageRect.right = OUTER_MARGIN + boardWidth;
\r
2014 messageRect.top = whiteRect.bottom + INNER_MARGIN;
\r
2015 messageRect.bottom = messageRect.top + messageSize.cy;
\r
2017 boardRect.left = OUTER_MARGIN;
\r
2018 boardRect.right = boardRect.left + boardWidth;
\r
2019 boardRect.top = messageRect.bottom + INNER_MARGIN;
\r
2020 boardRect.bottom = boardRect.top + boardHeight;
\r
2022 sizeInfo[boardSize].cliWidth = boardRect.right + OUTER_MARGIN;
\r
2023 sizeInfo[boardSize].cliHeight = boardRect.bottom + OUTER_MARGIN;
\r
2024 oldBoardSize = boardSize;
\r
2025 oldTinyLayout = tinyLayout;
\r
2026 winW = 2 * GetSystemMetrics(SM_CXFRAME) + boardRect.right + OUTER_MARGIN;
\r
2027 winH = 2 * GetSystemMetrics(SM_CYFRAME) + GetSystemMetrics(SM_CYMENU) +
\r
2028 GetSystemMetrics(SM_CYCAPTION) + boardRect.bottom + OUTER_MARGIN;
\r
2029 if(suppressVisibleEffects) return; // [HGM] when called for filling sizeInfo only
\r
2030 wpMain.width = winW; // [HGM] placement: set through temporary which can used by initial sizing choice
\r
2031 wpMain.height = winH; // without disturbing window attachments
\r
2032 GetWindowRect(hwndMain, &wrect);
\r
2033 SetWindowPos(hwndMain, NULL, 0, 0, wpMain.width, wpMain.height,
\r
2034 SWP_NOCOPYBITS|SWP_NOZORDER|SWP_NOMOVE);
\r
2036 // [HGM] placement: let attached windows follow size change.
\r
2037 ReattachAfterSize( &oldRect, wpMain.width, wpMain.height, moveHistoryDialog, &wpMoveHistory );
\r
2038 ReattachAfterSize( &oldRect, wpMain.width, wpMain.height, evalGraphDialog, &wpEvalGraph );
\r
2039 ReattachAfterSize( &oldRect, wpMain.width, wpMain.height, engineOutputDialog, &wpEngineOutput );
\r
2040 ReattachAfterSize( &oldRect, wpMain.width, wpMain.height, gameListDialog, &wpGameList );
\r
2041 ReattachAfterSize( &oldRect, wpMain.width, wpMain.height, hwndConsole, &wpConsole );
\r
2043 /* compensate if menu bar wrapped */
\r
2044 GetClientRect(hwndMain, &crect);
\r
2045 offby = boardRect.bottom + OUTER_MARGIN - crect.bottom;
\r
2046 wpMain.height += offby;
\r
2048 case WMSZ_TOPLEFT:
\r
2049 SetWindowPos(hwndMain, NULL,
\r
2050 wrect.right - wpMain.width, wrect.bottom - wpMain.height,
\r
2051 wpMain.width, wpMain.height, SWP_NOCOPYBITS|SWP_NOZORDER);
\r
2054 case WMSZ_TOPRIGHT:
\r
2056 SetWindowPos(hwndMain, NULL,
\r
2057 wrect.left, wrect.bottom - wpMain.height,
\r
2058 wpMain.width, wpMain.height, SWP_NOCOPYBITS|SWP_NOZORDER);
\r
2061 case WMSZ_BOTTOMLEFT:
\r
2063 SetWindowPos(hwndMain, NULL,
\r
2064 wrect.right - wpMain.width, wrect.top,
\r
2065 wpMain.width, wpMain.height, SWP_NOCOPYBITS|SWP_NOZORDER);
\r
2068 case WMSZ_BOTTOMRIGHT:
\r
2072 SetWindowPos(hwndMain, NULL, 0, 0, wpMain.width, wpMain.height,
\r
2073 SWP_NOCOPYBITS|SWP_NOZORDER|SWP_NOMOVE);
\r
2078 for (i = 0; i < N_BUTTONS; i++) {
\r
2079 if (buttonDesc[i].hwnd != NULL) {
\r
2080 DestroyWindow(buttonDesc[i].hwnd);
\r
2081 buttonDesc[i].hwnd = NULL;
\r
2083 if (appData.showButtonBar) {
\r
2084 buttonDesc[i].hwnd =
\r
2085 CreateWindow("BUTTON", buttonDesc[i].label,
\r
2086 WS_VISIBLE | WS_CHILD | BS_PUSHBUTTON,
\r
2087 boardRect.right - BUTTON_WIDTH*(N_BUTTONS-i),
\r
2088 messageRect.top, BUTTON_WIDTH, messageSize.cy, hwndMain,
\r
2089 (HMENU) buttonDesc[i].id,
\r
2090 (HINSTANCE) GetWindowLong(hwndMain, GWL_HINSTANCE), NULL);
\r
2092 SendMessage(buttonDesc[i].hwnd, WM_SETFONT,
\r
2093 (WPARAM)font[boardSize][MESSAGE_FONT]->hf,
\r
2094 MAKELPARAM(FALSE, 0));
\r
2096 if (buttonDesc[i].id == IDM_Pause)
\r
2097 hwndPause = buttonDesc[i].hwnd;
\r
2098 buttonDesc[i].wndproc = (WNDPROC)
\r
2099 SetWindowLong(buttonDesc[i].hwnd, GWL_WNDPROC, (LONG) ButtonProc);
\r
2102 if (gridPen != NULL) DeleteObject(gridPen);
\r
2103 if (highlightPen != NULL) DeleteObject(highlightPen);
\r
2104 if (premovePen != NULL) DeleteObject(premovePen);
\r
2105 if (lineGap != 0) {
\r
2106 logbrush.lbStyle = BS_SOLID;
\r
2107 logbrush.lbColor = RGB(0, 0, 0); /* grid pen color = black */
\r
2109 ExtCreatePen(PS_GEOMETRIC|PS_SOLID|PS_ENDCAP_FLAT|PS_JOIN_MITER,
\r
2110 lineGap, &logbrush, 0, NULL);
\r
2111 logbrush.lbColor = highlightSquareColor;
\r
2113 ExtCreatePen(PS_GEOMETRIC|PS_SOLID|PS_ENDCAP_FLAT|PS_JOIN_MITER,
\r
2114 lineGap, &logbrush, 0, NULL);
\r
2116 logbrush.lbColor = premoveHighlightColor;
\r
2118 ExtCreatePen(PS_GEOMETRIC|PS_SOLID|PS_ENDCAP_FLAT|PS_JOIN_MITER,
\r
2119 lineGap, &logbrush, 0, NULL);
\r
2121 /* [HGM] Loop had to be split in part for vert. and hor. lines */
\r
2122 for (i = 0; i < BOARD_HEIGHT + 1; i++) {
\r
2123 gridEndpoints[i*2].x = boardRect.left + lineGap / 2;
\r
2124 gridEndpoints[i*2].y = gridEndpoints[i*2 + 1].y =
\r
2125 boardRect.top + lineGap / 2 + (i * (squareSize + lineGap));
\r
2126 gridEndpoints[i*2 + 1].x = boardRect.left + lineGap / 2 +
\r
2127 BOARD_WIDTH * (squareSize + lineGap);
\r
2128 gridVertexCounts[i*2] = gridVertexCounts[i*2 + 1] = 2;
\r
2130 for (i = 0; i < BOARD_WIDTH + 1; i++) {
\r
2131 gridEndpoints[i*2 + BOARD_HEIGHT*2 + 2].y = boardRect.top + lineGap / 2;
\r
2132 gridEndpoints[i*2 + BOARD_HEIGHT*2 + 2].x =
\r
2133 gridEndpoints[i*2 + 1 + BOARD_HEIGHT*2 + 2].x = boardRect.left +
\r
2134 lineGap / 2 + (i * (squareSize + lineGap));
\r
2135 gridEndpoints[i*2 + 1 + BOARD_HEIGHT*2 + 2].y =
\r
2136 boardRect.top + BOARD_HEIGHT * (squareSize + lineGap);
\r
2137 gridVertexCounts[i*2] = gridVertexCounts[i*2 + 1] = 2;
\r
2141 /* [HGM] Licensing requirement */
\r
2143 if(gameInfo.variant == VariantGothic) GothicPopUp( GOTHIC, VariantGothic); else
\r
2146 if(gameInfo.variant == VariantFalcon) GothicPopUp( FALCON, VariantFalcon); else
\r
2148 GothicPopUp( "", VariantNormal);
\r
2151 /* if (boardSize == oldBoardSize) return; [HGM] variant might have changed */
\r
2153 /* Load piece bitmaps for this board size */
\r
2154 for (i=0; i<=2; i++) {
\r
2155 for (piece = WhitePawn;
\r
2156 (int) piece < (int) BlackPawn;
\r
2157 piece = (ChessSquare) ((int) piece + 1)) {
\r
2158 if (pieceBitmap[i][piece] != NULL)
\r
2159 DeleteObject(pieceBitmap[i][piece]);
\r
2163 fontBitmapSquareSize = 0; /* [HGM] render: make sure pieces will be recreated, as we might need others now */
\r
2164 // Orthodox Chess pieces
\r
2165 pieceBitmap[0][WhitePawn] = DoLoadBitmap(hInst, "p", squareSize, "s");
\r
2166 pieceBitmap[0][WhiteKnight] = DoLoadBitmap(hInst, "n", squareSize, "s");
\r
2167 pieceBitmap[0][WhiteBishop] = DoLoadBitmap(hInst, "b", squareSize, "s");
\r
2168 pieceBitmap[0][WhiteRook] = DoLoadBitmap(hInst, "r", squareSize, "s");
\r
2169 pieceBitmap[0][WhiteKing] = DoLoadBitmap(hInst, "k", squareSize, "s");
\r
2170 pieceBitmap[1][WhitePawn] = DoLoadBitmap(hInst, "p", squareSize, "o");
\r
2171 pieceBitmap[1][WhiteKnight] = DoLoadBitmap(hInst, "n", squareSize, "o");
\r
2172 pieceBitmap[1][WhiteBishop] = DoLoadBitmap(hInst, "b", squareSize, "o");
\r
2173 pieceBitmap[1][WhiteRook] = DoLoadBitmap(hInst, "r", squareSize, "o");
\r
2174 pieceBitmap[1][WhiteKing] = DoLoadBitmap(hInst, "k", squareSize, "o");
\r
2175 pieceBitmap[2][WhitePawn] = DoLoadBitmap(hInst, "p", squareSize, "w");
\r
2176 pieceBitmap[2][WhiteKnight] = DoLoadBitmap(hInst, "n", squareSize, "w");
\r
2177 pieceBitmap[2][WhiteBishop] = DoLoadBitmap(hInst, "b", squareSize, "w");
\r
2178 pieceBitmap[2][WhiteRook] = DoLoadBitmap(hInst, "r", squareSize, "w");
\r
2179 pieceBitmap[2][WhiteKing] = DoLoadBitmap(hInst, "k", squareSize, "w");
\r
2180 if( !strcmp(appData.variant, "shogi") && (squareSize==72 || squareSize==49)) {
\r
2181 // in Shogi, Hijack the unused Queen for Lance
\r
2182 pieceBitmap[0][WhiteQueen] = DoLoadBitmap(hInst, "l", squareSize, "s");
\r
2183 pieceBitmap[1][WhiteQueen] = DoLoadBitmap(hInst, "l", squareSize, "o");
\r
2184 pieceBitmap[2][WhiteQueen] = DoLoadBitmap(hInst, "l", squareSize, "w");
\r
2186 pieceBitmap[0][WhiteQueen] = DoLoadBitmap(hInst, "q", squareSize, "s");
\r
2187 pieceBitmap[1][WhiteQueen] = DoLoadBitmap(hInst, "q", squareSize, "o");
\r
2188 pieceBitmap[2][WhiteQueen] = DoLoadBitmap(hInst, "q", squareSize, "w");
\r
2191 if(squareSize <= 72 && squareSize >= 33) {
\r
2192 /* A & C are available in most sizes now */
\r
2193 if(squareSize != 49 && squareSize != 72 && squareSize != 33) { // Vortex-like
\r
2194 pieceBitmap[0][WhiteAngel] = DoLoadBitmap(hInst, "a", squareSize, "s");
\r
2195 pieceBitmap[1][WhiteAngel] = DoLoadBitmap(hInst, "a", squareSize, "o");
\r
2196 pieceBitmap[2][WhiteAngel] = DoLoadBitmap(hInst, "a", squareSize, "w");
\r
2197 pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "s");
\r
2198 pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "o");
\r
2199 pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "w");
\r
2200 pieceBitmap[0][WhiteCobra] = DoLoadBitmap(hInst, "cv", squareSize, "s");
\r
2201 pieceBitmap[1][WhiteCobra] = DoLoadBitmap(hInst, "cv", squareSize, "o");
\r
2202 pieceBitmap[2][WhiteCobra] = DoLoadBitmap(hInst, "cv", squareSize, "w");
\r
2203 pieceBitmap[0][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "s");
\r
2204 pieceBitmap[1][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "o");
\r
2205 pieceBitmap[2][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "w");
\r
2206 } else { // Smirf-like
\r
2207 pieceBitmap[0][WhiteAngel] = DoLoadBitmap(hInst, "aa", squareSize, "s");
\r
2208 pieceBitmap[1][WhiteAngel] = DoLoadBitmap(hInst, "aa", squareSize, "o");
\r
2209 pieceBitmap[2][WhiteAngel] = DoLoadBitmap(hInst, "aa", squareSize, "w");
\r
2211 if(gameInfo.variant == VariantGothic) { // Vortex-like
\r
2212 pieceBitmap[0][WhiteMarshall] = DoLoadBitmap(hInst, "cv", squareSize, "s");
\r
2213 pieceBitmap[1][WhiteMarshall] = DoLoadBitmap(hInst, "cv", squareSize, "o");
\r
2214 pieceBitmap[2][WhiteMarshall] = DoLoadBitmap(hInst, "cv", squareSize, "w");
\r
2215 } else { // WinBoard standard
\r
2216 pieceBitmap[0][WhiteMarshall] = DoLoadBitmap(hInst, "c", squareSize, "s");
\r
2217 pieceBitmap[1][WhiteMarshall] = DoLoadBitmap(hInst, "c", squareSize, "o");
\r
2218 pieceBitmap[2][WhiteMarshall] = DoLoadBitmap(hInst, "c", squareSize, "w");
\r
2223 if(squareSize==72 || squareSize==49 || squareSize==33) { /* experiment with some home-made bitmaps */
\r
2224 pieceBitmap[0][WhiteFerz] = DoLoadBitmap(hInst, "f", squareSize, "s");
\r
2225 pieceBitmap[1][WhiteFerz] = DoLoadBitmap(hInst, "f", squareSize, "o");
\r
2226 pieceBitmap[2][WhiteFerz] = DoLoadBitmap(hInst, "f", squareSize, "w");
\r
2227 pieceBitmap[0][WhiteWazir] = DoLoadBitmap(hInst, "w", squareSize, "s");
\r
2228 pieceBitmap[1][WhiteWazir] = DoLoadBitmap(hInst, "w", squareSize, "o");
\r
2229 pieceBitmap[2][WhiteWazir] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
2230 pieceBitmap[0][WhiteAlfil] = DoLoadBitmap(hInst, "e", squareSize, "s");
\r
2231 pieceBitmap[1][WhiteAlfil] = DoLoadBitmap(hInst, "e", squareSize, "o");
\r
2232 pieceBitmap[2][WhiteAlfil] = DoLoadBitmap(hInst, "e", squareSize, "w");
\r
2233 pieceBitmap[0][WhiteMan] = DoLoadBitmap(hInst, "m", squareSize, "s");
\r
2234 pieceBitmap[1][WhiteMan] = DoLoadBitmap(hInst, "m", squareSize, "o");
\r
2235 pieceBitmap[2][WhiteMan] = DoLoadBitmap(hInst, "m", squareSize, "w");
\r
2236 pieceBitmap[0][WhiteCardinal] = DoLoadBitmap(hInst, "a", squareSize, "s");
\r
2237 pieceBitmap[1][WhiteCardinal] = DoLoadBitmap(hInst, "a", squareSize, "o");
\r
2238 pieceBitmap[2][WhiteCardinal] = DoLoadBitmap(hInst, "a", squareSize, "w");
\r
2239 pieceBitmap[0][WhiteDragon] = DoLoadBitmap(hInst, "dk", squareSize, "s");
\r
2240 pieceBitmap[1][WhiteDragon] = DoLoadBitmap(hInst, "dk", squareSize, "o");
\r
2241 pieceBitmap[2][WhiteDragon] = DoLoadBitmap(hInst, "dk", squareSize, "w");
\r
2242 pieceBitmap[0][WhiteFalcon] = DoLoadBitmap(hInst, "v", squareSize, "s");
\r
2243 pieceBitmap[1][WhiteFalcon] = DoLoadBitmap(hInst, "v", squareSize, "o");
\r
2244 pieceBitmap[2][WhiteFalcon] = DoLoadBitmap(hInst, "v", squareSize, "w");
\r
2245 pieceBitmap[0][WhiteCobra] = DoLoadBitmap(hInst, "s", squareSize, "s");
\r
2246 pieceBitmap[1][WhiteCobra] = DoLoadBitmap(hInst, "s", squareSize, "o");
\r
2247 pieceBitmap[2][WhiteCobra] = DoLoadBitmap(hInst, "s", squareSize, "w");
\r
2248 pieceBitmap[0][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "s");
\r
2249 pieceBitmap[1][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "o");
\r
2250 pieceBitmap[2][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "w");
\r
2251 pieceBitmap[0][WhiteUnicorn] = DoLoadBitmap(hInst, "u", squareSize, "s");
\r
2252 pieceBitmap[1][WhiteUnicorn] = DoLoadBitmap(hInst, "u", squareSize, "o");
\r
2253 pieceBitmap[2][WhiteUnicorn] = DoLoadBitmap(hInst, "u", squareSize, "w");
\r
2255 if(gameInfo.variant == VariantShogi) { /* promoted Gold represemtations */
\r
2256 pieceBitmap[0][WhiteCannon] = DoLoadBitmap(hInst, "wp", squareSize, "s");
\r
2257 pieceBitmap[1][WhiteCannon] = DoLoadBitmap(hInst, "wp", squareSize, "o");
\r
2258 pieceBitmap[2][WhiteCannon] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
2259 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "wn", squareSize, "s");
\r
2260 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "wn", squareSize, "o");
\r
2261 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
2262 pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "ws", squareSize, "s");
\r
2263 pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "ws", squareSize, "o");
\r
2264 pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
2265 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "wl", squareSize, "s");
\r
2266 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "wl", squareSize, "o");
\r
2267 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
2269 pieceBitmap[0][WhiteCannon] = DoLoadBitmap(hInst, "o", squareSize, "s");
\r
2270 pieceBitmap[1][WhiteCannon] = DoLoadBitmap(hInst, "o", squareSize, "o");
\r
2271 pieceBitmap[2][WhiteCannon] = DoLoadBitmap(hInst, "o", squareSize, "w");
\r
2272 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "h", squareSize, "s");
\r
2273 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "h", squareSize, "o");
\r
2274 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "h", squareSize, "w");
\r
2275 pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "s");
\r
2276 pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "o");
\r
2277 pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "w");
\r
2278 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "g", squareSize, "s");
\r
2279 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "g", squareSize, "o");
\r
2280 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "g", squareSize, "w");
\r
2283 } else { /* other size, no special bitmaps available. Use smaller symbols */
\r
2284 if((int)boardSize < 2) minorSize = sizeInfo[0].squareSize;
\r
2285 else minorSize = sizeInfo[(int)boardSize - 2].squareSize;
\r
2286 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "n", minorSize, "s");
\r
2287 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "n", minorSize, "o");
\r
2288 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "n", minorSize, "w");
\r
2289 pieceBitmap[0][WhiteCardinal] = DoLoadBitmap(hInst, "b", minorSize, "s");
\r
2290 pieceBitmap[1][WhiteCardinal] = DoLoadBitmap(hInst, "b", minorSize, "o");
\r
2291 pieceBitmap[2][WhiteCardinal] = DoLoadBitmap(hInst, "b", minorSize, "w");
\r
2292 pieceBitmap[0][WhiteDragon] = DoLoadBitmap(hInst, "r", minorSize, "s");
\r
2293 pieceBitmap[1][WhiteDragon] = DoLoadBitmap(hInst, "r", minorSize, "o");
\r
2294 pieceBitmap[2][WhiteDragon] = DoLoadBitmap(hInst, "r", minorSize, "w");
\r
2295 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "q", minorSize, "s");
\r
2296 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "q", minorSize, "o");
\r
2297 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "q", minorSize, "w");
\r
2301 if(gameInfo.variant == VariantShogi && squareSize == 58)
\r
2302 /* special Shogi support in this size */
\r
2303 { for (i=0; i<=2; i++) { /* replace all bitmaps */
\r
2304 for (piece = WhitePawn;
\r
2305 (int) piece < (int) BlackPawn;
\r
2306 piece = (ChessSquare) ((int) piece + 1)) {
\r
2307 if (pieceBitmap[i][piece] != NULL)
\r
2308 DeleteObject(pieceBitmap[i][piece]);
\r
2311 pieceBitmap[0][WhitePawn] = DoLoadBitmap(hInst, "sp", squareSize, "o");
\r
2312 pieceBitmap[0][WhiteKnight] = DoLoadBitmap(hInst, "sn", squareSize, "o");
\r
2313 pieceBitmap[0][WhiteBishop] = DoLoadBitmap(hInst, "sb", squareSize, "o");
\r
2314 pieceBitmap[0][WhiteRook] = DoLoadBitmap(hInst, "sr", squareSize, "o");
\r
2315 pieceBitmap[0][WhiteQueen] = DoLoadBitmap(hInst, "sl", squareSize, "o");
\r
2316 pieceBitmap[0][WhiteKing] = DoLoadBitmap(hInst, "sk", squareSize, "o");
\r
2317 pieceBitmap[0][WhiteFerz] = DoLoadBitmap(hInst, "sf", squareSize, "o");
\r
2318 pieceBitmap[0][WhiteWazir] = DoLoadBitmap(hInst, "sw", squareSize, "o");
\r
2319 pieceBitmap[0][WhiteCannon] = DoLoadBitmap(hInst, "su", squareSize, "o");
\r
2320 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "sh", squareSize, "o");
\r
2321 pieceBitmap[0][WhiteCardinal] = DoLoadBitmap(hInst, "sa", squareSize, "o");
\r
2322 pieceBitmap[0][WhiteDragon] = DoLoadBitmap(hInst, "sc", squareSize, "o");
\r
2323 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "sg", squareSize, "o");
\r
2324 pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "ss", squareSize, "o");
\r
2325 pieceBitmap[1][WhitePawn] = DoLoadBitmap(hInst, "sp", squareSize, "o");
\r
2326 pieceBitmap[1][WhiteKnight] = DoLoadBitmap(hInst, "sn", squareSize, "o");
\r
2327 pieceBitmap[1][WhiteBishop] = DoLoadBitmap(hInst, "sb", squareSize, "o");
\r
2328 pieceBitmap[1][WhiteRook] = DoLoadBitmap(hInst, "sr", squareSize, "o");
\r
2329 pieceBitmap[1][WhiteQueen] = DoLoadBitmap(hInst, "sl", squareSize, "o");
\r
2330 pieceBitmap[1][WhiteKing] = DoLoadBitmap(hInst, "sk", squareSize, "o");
\r
2331 pieceBitmap[1][WhiteFerz] = DoLoadBitmap(hInst, "sf", squareSize, "o");
\r
2332 pieceBitmap[1][WhiteWazir] = DoLoadBitmap(hInst, "sw", squareSize, "o");
\r
2333 pieceBitmap[1][WhiteCannon] = DoLoadBitmap(hInst, "su", squareSize, "o");
\r
2334 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "sh", squareSize, "o");
\r
2335 pieceBitmap[1][WhiteCardinal] = DoLoadBitmap(hInst, "sa", squareSize, "o");
\r
2336 pieceBitmap[1][WhiteDragon] = DoLoadBitmap(hInst, "sc", squareSize, "o");
\r
2337 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "sg", squareSize, "o");
\r
2338 pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "ss", squareSize, "o");
\r
2339 pieceBitmap[2][WhitePawn] = DoLoadBitmap(hInst, "sp", squareSize, "w");
\r
2340 pieceBitmap[2][WhiteKnight] = DoLoadBitmap(hInst, "sn", squareSize, "w");
\r
2341 pieceBitmap[2][WhiteBishop] = DoLoadBitmap(hInst, "sr", squareSize, "w");
\r
2342 pieceBitmap[2][WhiteRook] = DoLoadBitmap(hInst, "sr", squareSize, "w");
\r
2343 pieceBitmap[2][WhiteQueen] = DoLoadBitmap(hInst, "sl", squareSize, "w");
\r
2344 pieceBitmap[2][WhiteKing] = DoLoadBitmap(hInst, "sk", squareSize, "w");
\r
2345 pieceBitmap[2][WhiteFerz] = DoLoadBitmap(hInst, "sw", squareSize, "w");
\r
2346 pieceBitmap[2][WhiteWazir] = DoLoadBitmap(hInst, "sw", squareSize, "w");
\r
2347 pieceBitmap[2][WhiteCannon] = DoLoadBitmap(hInst, "sp", squareSize, "w");
\r
2348 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "sn", squareSize, "w");
\r
2349 pieceBitmap[2][WhiteCardinal] = DoLoadBitmap(hInst, "sr", squareSize, "w");
\r
2350 pieceBitmap[2][WhiteDragon] = DoLoadBitmap(hInst, "sr", squareSize, "w");
\r
2351 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "sl", squareSize, "w");
\r
2352 pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "sw", squareSize, "w");
\r
2358 PieceBitmap(ChessSquare p, int kind)
\r
2360 if ((int) p >= (int) BlackPawn)
\r
2361 p = (ChessSquare) ((int) p - (int) BlackPawn + (int) WhitePawn);
\r
2363 return pieceBitmap[kind][(int) p];
\r
2366 /***************************************************************/
\r
2368 #define MIN(a,b) (((a) < (b)) ? (a) : (b))
\r
2369 #define MAX(a,b) (((a) > (b)) ? (a) : (b))
\r
2371 #define MIN3(a,b,c) (((a) < (b) && (a) < (c)) ? (a) : (((b) < (a) && (b) < (c)) ? (b) : (c)))
\r
2372 #define MAX3(a,b,c) (((a) > (b) && (a) > (c)) ? (a) : (((b) > (a) && (b) > (c)) ? (b) : (c)))
\r
2376 SquareToPos(int row, int column, int * x, int * y)
\r
2379 *x = boardRect.left + lineGap + ((BOARD_WIDTH-1)-column) * (squareSize + lineGap);
\r
2380 *y = boardRect.top + lineGap + row * (squareSize + lineGap);
\r
2382 *x = boardRect.left + lineGap + column * (squareSize + lineGap);
\r
2383 *y = boardRect.top + lineGap + ((BOARD_HEIGHT-1)-row) * (squareSize + lineGap);
\r
2388 DrawCoordsOnDC(HDC hdc)
\r
2390 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
2391 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
2392 char str[2] = { NULLCHAR, NULLCHAR };
\r
2393 int oldMode, oldAlign, x, y, start, i;
\r
2397 if (!appData.showCoords)
\r
2400 start = flipView ? 1-(ONE!='1') : 23+(ONE!='1')-BOARD_HEIGHT;
\r
2402 oldBrush = SelectObject(hdc, GetStockObject(BLACK_BRUSH));
\r
2403 oldMode = SetBkMode(hdc, (appData.monoMode ? OPAQUE : TRANSPARENT));
\r
2404 oldAlign = GetTextAlign(hdc);
\r
2405 oldFont = SelectObject(hdc, font[boardSize][COORD_FONT]->hf);
\r
2407 y = boardRect.top + lineGap;
\r
2408 x = boardRect.left + lineGap + gameInfo.holdingsWidth*(squareSize + lineGap);
\r
2410 SetTextAlign(hdc, TA_LEFT|TA_TOP);
\r
2411 for (i = 0; i < BOARD_HEIGHT; i++) {
\r
2412 str[0] = files[start + i];
\r
2413 ExtTextOut(hdc, x + 2, y + 1, 0, NULL, str, 1, NULL);
\r
2414 y += squareSize + lineGap;
\r
2417 start = flipView ? 12-(BOARD_RGHT-BOARD_LEFT) : 12;
\r
2419 SetTextAlign(hdc, TA_RIGHT|TA_BOTTOM);
\r
2420 for (i = 0; i < BOARD_RGHT - BOARD_LEFT; i++) {
\r
2421 str[0] = ranks[start + i];
\r
2422 ExtTextOut(hdc, x + squareSize - 2, y - 1, 0, NULL, str, 1, NULL);
\r
2423 x += squareSize + lineGap;
\r
2426 SelectObject(hdc, oldBrush);
\r
2427 SetBkMode(hdc, oldMode);
\r
2428 SetTextAlign(hdc, oldAlign);
\r
2429 SelectObject(hdc, oldFont);
\r
2433 DrawGridOnDC(HDC hdc)
\r
2437 if (lineGap != 0) {
\r
2438 oldPen = SelectObject(hdc, gridPen);
\r
2439 PolyPolyline(hdc, gridEndpoints, gridVertexCounts, BOARD_WIDTH+BOARD_HEIGHT + 2);
\r
2440 SelectObject(hdc, oldPen);
\r
2444 #define HIGHLIGHT_PEN 0
\r
2445 #define PREMOVE_PEN 1
\r
2448 DrawHighlightOnDC(HDC hdc, BOOLEAN on, int x, int y, int pen)
\r
2451 HPEN oldPen, hPen;
\r
2452 if (lineGap == 0) return;
\r
2454 x1 = boardRect.left +
\r
2455 lineGap/2 + ((BOARD_WIDTH-1)-x) * (squareSize + lineGap);
\r
2456 y1 = boardRect.top +
\r
2457 lineGap/2 + y * (squareSize + lineGap);
\r
2459 x1 = boardRect.left +
\r
2460 lineGap/2 + x * (squareSize + lineGap);
\r
2461 y1 = boardRect.top +
\r
2462 lineGap/2 + ((BOARD_HEIGHT-1)-y) * (squareSize + lineGap);
\r
2464 hPen = pen ? premovePen : highlightPen;
\r
2465 oldPen = SelectObject(hdc, on ? hPen : gridPen);
\r
2466 MoveToEx(hdc, x1, y1, NULL);
\r
2467 LineTo(hdc, x1 + squareSize + lineGap, y1);
\r
2468 LineTo(hdc, x1 + squareSize + lineGap, y1 + squareSize + lineGap);
\r
2469 LineTo(hdc, x1, y1 + squareSize + lineGap);
\r
2470 LineTo(hdc, x1, y1);
\r
2471 SelectObject(hdc, oldPen);
\r
2475 DrawHighlightsOnDC(HDC hdc)
\r
2478 for (i=0; i<2; i++) {
\r
2479 if (highlightInfo.sq[i].x >= 0 && highlightInfo.sq[i].y >= 0)
\r
2480 DrawHighlightOnDC(hdc, TRUE,
\r
2481 highlightInfo.sq[i].x, highlightInfo.sq[i].y,
\r
2484 for (i=0; i<2; i++) {
\r
2485 if (premoveHighlightInfo.sq[i].x >= 0 &&
\r
2486 premoveHighlightInfo.sq[i].y >= 0) {
\r
2487 DrawHighlightOnDC(hdc, TRUE,
\r
2488 premoveHighlightInfo.sq[i].x,
\r
2489 premoveHighlightInfo.sq[i].y,
\r
2495 /* Note: sqcolor is used only in monoMode */
\r
2496 /* Note that this code is largely duplicated in woptions.c,
\r
2497 function DrawSampleSquare, so that needs to be updated too */
\r
2499 DrawPieceOnDC(HDC hdc, ChessSquare piece, int color, int sqcolor, int x, int y, HDC tmphdc)
\r
2501 HBITMAP oldBitmap;
\r
2505 if (appData.blindfold) return;
\r
2507 /* [AS] Use font-based pieces if needed */
\r
2508 if( fontBitmapSquareSize >= 0 && squareSize > 32 ) {
\r
2509 /* Create piece bitmaps, or do nothing if piece set is up to date */
\r
2510 CreatePiecesFromFont();
\r
2512 if( fontBitmapSquareSize == squareSize ) {
\r
2513 int index = TranslatePieceToFontPiece(piece);
\r
2515 SelectObject( tmphdc, hPieceMask[ index ] );
\r
2519 squareSize, squareSize,
\r
2524 SelectObject( tmphdc, hPieceFace[ index ] );
\r
2528 squareSize, squareSize,
\r
2537 if (appData.monoMode) {
\r
2538 SelectObject(tmphdc, PieceBitmap(piece,
\r
2539 color == sqcolor ? OUTLINE_PIECE : SOLID_PIECE));
\r
2540 BitBlt(hdc, x, y, squareSize, squareSize, tmphdc, 0, 0,
\r
2541 sqcolor ? SRCCOPY : NOTSRCCOPY);
\r
2543 tmpSize = squareSize;
\r
2545 ((piece >= (int)WhiteNightrider && piece <= WhiteGrasshopper) ||
\r
2546 (piece >= (int)BlackNightrider && piece <= BlackGrasshopper)) ) {
\r
2547 /* [HGM] no bitmap available for promoted pieces in Crazyhouse */
\r
2548 /* Bitmaps of smaller size are substituted, but we have to align them */
\r
2549 x += (squareSize - minorSize)>>1;
\r
2550 y += squareSize - minorSize - 2;
\r
2551 tmpSize = minorSize;
\r
2553 if (color || appData.allWhite ) {
\r
2554 oldBitmap = SelectObject(tmphdc, PieceBitmap(piece, WHITE_PIECE));
\r
2556 oldBrush = SelectObject(hdc, whitePieceBrush);
\r
2557 else oldBrush = SelectObject(hdc, blackPieceBrush);
\r
2558 if(appData.upsideDown && color==flipView)
\r
2559 StretchBlt(hdc, x+tmpSize, y+tmpSize, -tmpSize, -tmpSize, tmphdc, 0, 0, tmpSize, tmpSize, 0x00B8074A);
\r
2561 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, 0x00B8074A);
\r
2562 /* Use black for outline of white pieces */
\r
2563 SelectObject(tmphdc, PieceBitmap(piece, OUTLINE_PIECE));
\r
2564 if(appData.upsideDown && color==flipView)
\r
2565 StretchBlt(hdc, x+tmpSize, y+tmpSize, -tmpSize, -tmpSize, tmphdc, 0, 0, tmpSize, tmpSize, SRCAND);
\r
2567 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, SRCAND);
\r
2569 /* Use square color for details of black pieces */
\r
2570 oldBitmap = SelectObject(tmphdc, PieceBitmap(piece, SOLID_PIECE));
\r
2571 oldBrush = SelectObject(hdc, blackPieceBrush);
\r
2572 if(appData.upsideDown && !flipView)
\r
2573 StretchBlt(hdc, x+tmpSize, y+tmpSize, -tmpSize, -tmpSize, tmphdc, 0, 0, tmpSize, tmpSize, 0x00B8074A);
\r
2575 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, 0x00B8074A);
\r
2577 SelectObject(hdc, oldBrush);
\r
2578 SelectObject(tmphdc, oldBitmap);
\r
2582 /* [AS] Compute a drawing mode for a square, based on specified settings (see DrawTile) */
\r
2583 int GetBackTextureMode( int algo )
\r
2585 int result = BACK_TEXTURE_MODE_DISABLED;
\r
2589 case BACK_TEXTURE_MODE_PLAIN:
\r
2590 result = 1; /* Always use identity map */
\r
2592 case BACK_TEXTURE_MODE_FULL_RANDOM:
\r
2593 result = 1 + (myrandom() % 3); /* Pick a transformation at random */
\r
2601 [AS] Compute and save texture drawing info, otherwise we may not be able
\r
2602 to handle redraws cleanly (as random numbers would always be different).
\r
2604 VOID RebuildTextureSquareInfo()
\r
2614 ZeroMemory( &backTextureSquareInfo, sizeof(backTextureSquareInfo) );
\r
2616 if( liteBackTexture != NULL ) {
\r
2617 if( GetObject( liteBackTexture, sizeof(bi), &bi ) > 0 ) {
\r
2618 lite_w = bi.bmWidth;
\r
2619 lite_h = bi.bmHeight;
\r
2623 if( darkBackTexture != NULL ) {
\r
2624 if( GetObject( darkBackTexture, sizeof(bi), &bi ) > 0 ) {
\r
2625 dark_w = bi.bmWidth;
\r
2626 dark_h = bi.bmHeight;
\r
2630 for( row=0; row<BOARD_HEIGHT; row++ ) {
\r
2631 for( col=0; col<BOARD_WIDTH; col++ ) {
\r
2632 if( (col + row) & 1 ) {
\r
2634 if( lite_w >= squareSize && lite_h >= squareSize ) {
\r
2635 backTextureSquareInfo[row][col].x = col * (lite_w - squareSize) / (BOARD_WIDTH-1); /* [HGM] divide by size-1 in stead of size! */
\r
2636 backTextureSquareInfo[row][col].y = (BOARD_HEIGHT-1-row) * (lite_h - squareSize) / (BOARD_HEIGHT-1);
\r
2637 backTextureSquareInfo[row][col].mode = GetBackTextureMode(liteBackTextureMode);
\r
2642 if( dark_w >= squareSize && dark_h >= squareSize ) {
\r
2643 backTextureSquareInfo[row][col].x = col * (dark_w - squareSize) / (BOARD_WIDTH-1);
\r
2644 backTextureSquareInfo[row][col].y = (BOARD_HEIGHT-1-row) * (dark_h - squareSize) / (BOARD_HEIGHT-1);
\r
2645 backTextureSquareInfo[row][col].mode = GetBackTextureMode(darkBackTextureMode);
\r
2652 /* [AS] Arrow highlighting support */
\r
2654 static int A_WIDTH = 5; /* Width of arrow body */
\r
2656 #define A_HEIGHT_FACTOR 6 /* Length of arrow "point", relative to body width */
\r
2657 #define A_WIDTH_FACTOR 3 /* Width of arrow "point", relative to body width */
\r
2659 static double Sqr( double x )
\r
2664 static int Round( double x )
\r
2666 return (int) (x + 0.5);
\r
2669 /* Draw an arrow between two points using current settings */
\r
2670 VOID DrawArrowBetweenPoints( HDC hdc, int s_x, int s_y, int d_x, int d_y )
\r
2673 double dx, dy, j, k, x, y;
\r
2675 if( d_x == s_x ) {
\r
2676 int h = (d_y > s_y) ? +A_WIDTH*A_HEIGHT_FACTOR : -A_WIDTH*A_HEIGHT_FACTOR;
\r
2678 arrow[0].x = s_x + A_WIDTH;
\r
2681 arrow[1].x = s_x + A_WIDTH;
\r
2682 arrow[1].y = d_y - h;
\r
2684 arrow[2].x = s_x + A_WIDTH*A_WIDTH_FACTOR;
\r
2685 arrow[2].y = d_y - h;
\r
2690 arrow[4].x = s_x - A_WIDTH*A_WIDTH_FACTOR;
\r
2691 arrow[4].y = d_y - h;
\r
2693 arrow[5].x = s_x - A_WIDTH;
\r
2694 arrow[5].y = d_y - h;
\r
2696 arrow[6].x = s_x - A_WIDTH;
\r
2699 else if( d_y == s_y ) {
\r
2700 int w = (d_x > s_x) ? +A_WIDTH*A_HEIGHT_FACTOR : -A_WIDTH*A_HEIGHT_FACTOR;
\r
2703 arrow[0].y = s_y + A_WIDTH;
\r
2705 arrow[1].x = d_x - w;
\r
2706 arrow[1].y = s_y + A_WIDTH;
\r
2708 arrow[2].x = d_x - w;
\r
2709 arrow[2].y = s_y + A_WIDTH*A_WIDTH_FACTOR;
\r
2714 arrow[4].x = d_x - w;
\r
2715 arrow[4].y = s_y - A_WIDTH*A_WIDTH_FACTOR;
\r
2717 arrow[5].x = d_x - w;
\r
2718 arrow[5].y = s_y - A_WIDTH;
\r
2721 arrow[6].y = s_y - A_WIDTH;
\r
2724 /* [AS] Needed a lot of paper for this! :-) */
\r
2725 dy = (double) (d_y - s_y) / (double) (d_x - s_x);
\r
2726 dx = (double) (s_x - d_x) / (double) (s_y - d_y);
\r
2728 j = sqrt( Sqr(A_WIDTH) / (1.0 + Sqr(dx)) );
\r
2730 k = sqrt( Sqr(A_WIDTH*A_HEIGHT_FACTOR) / (1.0 + Sqr(dy)) );
\r
2735 arrow[0].x = Round(x - j);
\r
2736 arrow[0].y = Round(y + j*dx);
\r
2738 arrow[1].x = Round(x + j);
\r
2739 arrow[1].y = Round(y - j*dx);
\r
2742 x = (double) d_x - k;
\r
2743 y = (double) d_y - k*dy;
\r
2746 x = (double) d_x + k;
\r
2747 y = (double) d_y + k*dy;
\r
2750 arrow[2].x = Round(x + j);
\r
2751 arrow[2].y = Round(y - j*dx);
\r
2753 arrow[3].x = Round(x + j*A_WIDTH_FACTOR);
\r
2754 arrow[3].y = Round(y - j*A_WIDTH_FACTOR*dx);
\r
2759 arrow[5].x = Round(x - j*A_WIDTH_FACTOR);
\r
2760 arrow[5].y = Round(y + j*A_WIDTH_FACTOR*dx);
\r
2762 arrow[6].x = Round(x - j);
\r
2763 arrow[6].y = Round(y + j*dx);
\r
2766 Polygon( hdc, arrow, 7 );
\r
2769 /* [AS] Draw an arrow between two squares */
\r
2770 VOID DrawArrowBetweenSquares( HDC hdc, int s_col, int s_row, int d_col, int d_row )
\r
2772 int s_x, s_y, d_x, d_y;
\r
2779 if( s_col == d_col && s_row == d_row ) {
\r
2783 /* Get source and destination points */
\r
2784 SquareToPos( s_row, s_col, &s_x, &s_y);
\r
2785 SquareToPos( d_row, d_col, &d_x, &d_y);
\r
2788 d_y += squareSize / 4;
\r
2790 else if( d_y < s_y ) {
\r
2791 d_y += 3 * squareSize / 4;
\r
2794 d_y += squareSize / 2;
\r
2798 d_x += squareSize / 4;
\r
2800 else if( d_x < s_x ) {
\r
2801 d_x += 3 * squareSize / 4;
\r
2804 d_x += squareSize / 2;
\r
2807 s_x += squareSize / 2;
\r
2808 s_y += squareSize / 2;
\r
2810 /* Adjust width */
\r
2811 A_WIDTH = squareSize / 14;
\r
2814 stLB.lbStyle = BS_SOLID;
\r
2815 stLB.lbColor = appData.highlightArrowColor;
\r
2818 hpen = CreatePen( PS_SOLID, 2, RGB(0x00,0x00,0x00) );
\r
2819 holdpen = SelectObject( hdc, hpen );
\r
2820 hbrush = CreateBrushIndirect( &stLB );
\r
2821 holdbrush = SelectObject( hdc, hbrush );
\r
2823 DrawArrowBetweenPoints( hdc, s_x, s_y, d_x, d_y );
\r
2825 SelectObject( hdc, holdpen );
\r
2826 SelectObject( hdc, holdbrush );
\r
2827 DeleteObject( hpen );
\r
2828 DeleteObject( hbrush );
\r
2831 BOOL HasHighlightInfo()
\r
2833 BOOL result = FALSE;
\r
2835 if( highlightInfo.sq[0].x >= 0 && highlightInfo.sq[0].y >= 0 &&
\r
2836 highlightInfo.sq[1].x >= 0 && highlightInfo.sq[1].y >= 0 )
\r
2844 BOOL IsDrawArrowEnabled()
\r
2846 BOOL result = FALSE;
\r
2848 if( appData.highlightMoveWithArrow && squareSize >= 32 ) {
\r
2855 VOID DrawArrowHighlight( HDC hdc )
\r
2857 if( IsDrawArrowEnabled() && HasHighlightInfo() ) {
\r
2858 DrawArrowBetweenSquares( hdc,
\r
2859 highlightInfo.sq[0].x, highlightInfo.sq[0].y,
\r
2860 highlightInfo.sq[1].x, highlightInfo.sq[1].y );
\r
2864 HRGN GetArrowHighlightClipRegion( HDC hdc )
\r
2866 HRGN result = NULL;
\r
2868 if( HasHighlightInfo() ) {
\r
2869 int x1, y1, x2, y2;
\r
2870 int sx, sy, dx, dy;
\r
2872 SquareToPos(highlightInfo.sq[0].y, highlightInfo.sq[0].x, &x1, &y1 );
\r
2873 SquareToPos(highlightInfo.sq[1].y, highlightInfo.sq[1].x, &x2, &y2 );
\r
2875 sx = MIN( x1, x2 );
\r
2876 sy = MIN( y1, y2 );
\r
2877 dx = MAX( x1, x2 ) + squareSize;
\r
2878 dy = MAX( y1, y2 ) + squareSize;
\r
2880 result = CreateRectRgn( sx, sy, dx, dy );
\r
2887 Warning: this function modifies the behavior of several other functions.
\r
2889 Basically, Winboard is optimized to avoid drawing the whole board if not strictly
\r
2890 needed. Unfortunately, the decision whether or not to perform a full or partial
\r
2891 repaint is scattered all over the place, which is not good for features such as
\r
2892 "arrow highlighting" that require a full repaint of the board.
\r
2894 So, I've tried to patch the code where I thought it made sense (e.g. after or during
\r
2895 user interaction, when speed is not so important) but especially to avoid errors
\r
2896 in the displayed graphics.
\r
2898 In such patched places, I always try refer to this function so there is a single
\r
2899 place to maintain knowledge.
\r
2901 To restore the original behavior, just return FALSE unconditionally.
\r
2903 BOOL IsFullRepaintPreferrable()
\r
2905 BOOL result = FALSE;
\r
2907 if( (appData.highlightLastMove || appData.highlightDragging) && IsDrawArrowEnabled() ) {
\r
2908 /* Arrow may appear on the board */
\r
2916 This function is called by DrawPosition to know whether a full repaint must
\r
2919 Only DrawPosition may directly call this function, which makes use of
\r
2920 some state information. Other function should call DrawPosition specifying
\r
2921 the repaint flag, and can use IsFullRepaintPreferrable if needed.
\r
2923 BOOL DrawPositionNeedsFullRepaint()
\r
2925 BOOL result = FALSE;
\r
2928 Probably a slightly better policy would be to trigger a full repaint
\r
2929 when animInfo.piece changes state (i.e. empty -> non-empty and viceversa),
\r
2930 but animation is fast enough that it's difficult to notice.
\r
2932 if( animInfo.piece == EmptySquare ) {
\r
2933 if( (appData.highlightLastMove || appData.highlightDragging) && IsDrawArrowEnabled() /*&& HasHighlightInfo()*/ ) {
\r
2942 DrawBoardOnDC(HDC hdc, Board board, HDC tmphdc)
\r
2944 int row, column, x, y, square_color, piece_color;
\r
2945 ChessSquare piece;
\r
2947 HDC texture_hdc = NULL;
\r
2949 /* [AS] Initialize background textures if needed */
\r
2950 if( liteBackTexture != NULL || darkBackTexture != NULL ) {
\r
2951 static int backTextureBoardSize; /* [HGM] boardsize: also new texture if board format changed */
\r
2952 if( backTextureSquareSize != squareSize
\r
2953 || backTextureBoardSize != BOARD_WIDTH+BOARD_FILES*BOARD_HEIGHT) {
\r
2954 backTextureBoardSize = BOARD_WIDTH+BOARD_FILES*BOARD_HEIGHT;
\r
2955 backTextureSquareSize = squareSize;
\r
2956 RebuildTextureSquareInfo();
\r
2959 texture_hdc = CreateCompatibleDC( hdc );
\r
2962 for (row = 0; row < BOARD_HEIGHT; row++) {
\r
2963 for (column = 0; column < BOARD_WIDTH; column++) {
\r
2965 SquareToPos(row, column, &x, &y);
\r
2967 piece = board[row][column];
\r
2969 square_color = ((column + row) % 2) == 1;
\r
2970 if( gameInfo.variant == VariantXiangqi ) {
\r
2971 square_color = !InPalace(row, column);
\r
2972 if(BOARD_HEIGHT&1) { if(row==BOARD_HEIGHT/2) square_color ^= 1; }
\r
2973 else if(row < BOARD_HEIGHT/2) square_color ^= 1;
\r
2975 piece_color = (int) piece < (int) BlackPawn;
\r
2978 /* [HGM] holdings file: light square or black */
\r
2979 if(column == BOARD_LEFT-2) {
\r
2980 if( row > BOARD_HEIGHT - gameInfo.holdingsSize - 1 )
\r
2983 DisplayHoldingsCount(hdc, x, y, 0, 0); /* black out */
\r
2987 if(column == BOARD_RGHT + 1 ) {
\r
2988 if( row < gameInfo.holdingsSize )
\r
2991 DisplayHoldingsCount(hdc, x, y, 0, 0);
\r
2995 if(column == BOARD_LEFT-1 ) /* left align */
\r
2996 DisplayHoldingsCount(hdc, x, y, flipView, (int) board[row][column]);
\r
2997 else if( column == BOARD_RGHT) /* right align */
\r
2998 DisplayHoldingsCount(hdc, x, y, !flipView, (int) board[row][column]);
\r
3000 if (appData.monoMode) {
\r
3001 if (piece == EmptySquare) {
\r
3002 BitBlt(hdc, x, y, squareSize, squareSize, 0, 0, 0,
\r
3003 square_color ? WHITENESS : BLACKNESS);
\r
3005 DrawPieceOnDC(hdc, piece, piece_color, square_color, x, y, tmphdc);
\r
3008 else if( backTextureSquareInfo[row][column].mode > 0 ) {
\r
3009 /* [AS] Draw the square using a texture bitmap */
\r
3010 HBITMAP hbm = SelectObject( texture_hdc, square_color ? liteBackTexture : darkBackTexture );
\r
3011 int r = row, c = column; // [HGM] do not flip board in flipView
\r
3012 if(flipView) { r = BOARD_HEIGHT-1 - r; c = BOARD_WIDTH-1 - c; }
\r
3015 squareSize, squareSize,
\r
3018 backTextureSquareInfo[r][c].mode,
\r
3019 backTextureSquareInfo[r][c].x,
\r
3020 backTextureSquareInfo[r][c].y );
\r
3022 SelectObject( texture_hdc, hbm );
\r
3024 if (piece != EmptySquare) {
\r
3025 DrawPieceOnDC(hdc, piece, piece_color, -1, x, y, tmphdc);
\r
3029 HBRUSH brush = square_color ? lightSquareBrush : darkSquareBrush;
\r
3031 oldBrush = SelectObject(hdc, brush );
\r
3032 BitBlt(hdc, x, y, squareSize, squareSize, 0, 0, 0, PATCOPY);
\r
3033 SelectObject(hdc, oldBrush);
\r
3034 if (piece != EmptySquare)
\r
3035 DrawPieceOnDC(hdc, piece, piece_color, -1, x, y, tmphdc);
\r
3040 if( texture_hdc != NULL ) {
\r
3041 DeleteDC( texture_hdc );
\r
3045 int saveDiagFlag = 0; FILE *diagFile; // [HGM] diag
\r
3046 void fputDW(FILE *f, int x)
\r
3048 fputc(x & 255, f);
\r
3049 fputc(x>>8 & 255, f);
\r
3050 fputc(x>>16 & 255, f);
\r
3051 fputc(x>>24 & 255, f);
\r
3054 #define MAX_CLIPS 200 /* more than enough */
\r
3057 DrawLogoOnDC(HDC hdc, RECT logoRect, HBITMAP logo)
\r
3059 // HBITMAP bufferBitmap;
\r
3064 int w = 100, h = 50;
\r
3066 if(logo == NULL) return;
\r
3067 // GetClientRect(hwndMain, &Rect);
\r
3068 // bufferBitmap = CreateCompatibleBitmap(hdc, Rect.right-Rect.left+1,
\r
3069 // Rect.bottom-Rect.top+1);
\r
3070 tmphdc = CreateCompatibleDC(hdc);
\r
3071 hbm = SelectObject(tmphdc, logo);
\r
3072 if( GetObject( logo, sizeof(bi), &bi ) > 0 ) {
\r
3076 StretchBlt(hdc, logoRect.left, logoRect.top, logoRect.right - logoRect.left,
\r
3077 logoRect.bottom - logoRect.top, tmphdc, 0, 0, w, h, SRCCOPY);
\r
3078 SelectObject(tmphdc, hbm);
\r
3083 HDCDrawPosition(HDC hdc, BOOLEAN repaint, Board board)
\r
3085 static Board lastReq, lastDrawn;
\r
3086 static HighlightInfo lastDrawnHighlight, lastDrawnPremove;
\r
3087 static int lastDrawnFlipView = 0;
\r
3088 static int lastReqValid = 0, lastDrawnValid = 0;
\r
3089 int releaseDC, x, y, x2, y2, row, column, num_clips = 0, i;
\r
3092 HBITMAP bufferBitmap;
\r
3093 HBITMAP oldBitmap;
\r
3095 HRGN clips[MAX_CLIPS];
\r
3096 ChessSquare dragged_piece = EmptySquare;
\r
3098 /* I'm undecided on this - this function figures out whether a full
\r
3099 * repaint is necessary on its own, so there's no real reason to have the
\r
3100 * caller tell it that. I think this can safely be set to FALSE - but
\r
3101 * if we trust the callers not to request full repaints unnessesarily, then
\r
3102 * we could skip some clipping work. In other words, only request a full
\r
3103 * redraw when the majority of pieces have changed positions (ie. flip,
\r
3104 * gamestart and similar) --Hawk
\r
3106 Boolean fullrepaint = repaint;
\r
3108 if( DrawPositionNeedsFullRepaint() ) {
\r
3109 fullrepaint = TRUE;
\r
3112 if (board == NULL) {
\r
3113 if (!lastReqValid) {
\r
3118 CopyBoard(lastReq, board);
\r
3122 if (doingSizing) {
\r
3126 if (IsIconic(hwndMain)) {
\r
3130 if (hdc == NULL) {
\r
3131 hdc = GetDC(hwndMain);
\r
3132 if (!appData.monoMode) {
\r
3133 SelectPalette(hdc, hPal, FALSE);
\r
3134 RealizePalette(hdc);
\r
3138 releaseDC = FALSE;
\r
3141 /* Create some work-DCs */
\r
3142 hdcmem = CreateCompatibleDC(hdc);
\r
3143 tmphdc = CreateCompatibleDC(hdc);
\r
3145 /* If dragging is in progress, we temporarely remove the piece */
\r
3146 /* [HGM] or temporarily decrease count if stacked */
\r
3147 /* !! Moved to before board compare !! */
\r
3148 if (dragInfo.from.x >= 0 && dragInfo.pos.x >= 0) {
\r
3149 dragged_piece = board[dragInfo.from.y][dragInfo.from.x];
\r
3150 if(dragInfo.from.x == BOARD_LEFT-2 ) {
\r
3151 if(--board[dragInfo.from.y][dragInfo.from.x+1] == 0 )
\r
3152 board[dragInfo.from.y][dragInfo.from.x] = EmptySquare;
\r
3154 if(dragInfo.from.x == BOARD_RGHT+1) {
\r
3155 if(--board[dragInfo.from.y][dragInfo.from.x-1] == 0 )
\r
3156 board[dragInfo.from.y][dragInfo.from.x] = EmptySquare;
\r
3158 board[dragInfo.from.y][dragInfo.from.x] = EmptySquare;
\r
3161 /* Figure out which squares need updating by comparing the
\r
3162 * newest board with the last drawn board and checking if
\r
3163 * flipping has changed.
\r
3165 if (!fullrepaint && lastDrawnValid && lastDrawnFlipView == flipView) {
\r
3166 for (row = 0; row < BOARD_HEIGHT; row++) { /* [HGM] true size, not 8 */
\r
3167 for (column = 0; column < BOARD_WIDTH; column++) {
\r
3168 if (lastDrawn[row][column] != board[row][column]) {
\r
3169 SquareToPos(row, column, &x, &y);
\r
3170 clips[num_clips++] =
\r
3171 CreateRectRgn(x, y, x + squareSize, y + squareSize);
\r
3175 for (i=0; i<2; i++) {
\r
3176 if (lastDrawnHighlight.sq[i].x != highlightInfo.sq[i].x ||
\r
3177 lastDrawnHighlight.sq[i].y != highlightInfo.sq[i].y) {
\r
3178 if (lastDrawnHighlight.sq[i].x >= 0 &&
\r
3179 lastDrawnHighlight.sq[i].y >= 0) {
\r
3180 SquareToPos(lastDrawnHighlight.sq[i].y,
\r
3181 lastDrawnHighlight.sq[i].x, &x, &y);
\r
3182 clips[num_clips++] =
\r
3183 CreateRectRgn(x - lineGap, y - lineGap,
\r
3184 x + squareSize + lineGap, y + squareSize + lineGap);
\r
3186 if (highlightInfo.sq[i].x >= 0 && highlightInfo.sq[i].y >= 0) {
\r
3187 SquareToPos(highlightInfo.sq[i].y, highlightInfo.sq[i].x, &x, &y);
\r
3188 clips[num_clips++] =
\r
3189 CreateRectRgn(x - lineGap, y - lineGap,
\r
3190 x + squareSize + lineGap, y + squareSize + lineGap);
\r
3194 for (i=0; i<2; i++) {
\r
3195 if (lastDrawnPremove.sq[i].x != premoveHighlightInfo.sq[i].x ||
\r
3196 lastDrawnPremove.sq[i].y != premoveHighlightInfo.sq[i].y) {
\r
3197 if (lastDrawnPremove.sq[i].x >= 0 &&
\r
3198 lastDrawnPremove.sq[i].y >= 0) {
\r
3199 SquareToPos(lastDrawnPremove.sq[i].y,
\r
3200 lastDrawnPremove.sq[i].x, &x, &y);
\r
3201 clips[num_clips++] =
\r
3202 CreateRectRgn(x - lineGap, y - lineGap,
\r
3203 x + squareSize + lineGap, y + squareSize + lineGap);
\r
3205 if (premoveHighlightInfo.sq[i].x >= 0 &&
\r
3206 premoveHighlightInfo.sq[i].y >= 0) {
\r
3207 SquareToPos(premoveHighlightInfo.sq[i].y,
\r
3208 premoveHighlightInfo.sq[i].x, &x, &y);
\r
3209 clips[num_clips++] =
\r
3210 CreateRectRgn(x - lineGap, y - lineGap,
\r
3211 x + squareSize + lineGap, y + squareSize + lineGap);
\r
3216 fullrepaint = TRUE;
\r
3219 /* Create a buffer bitmap - this is the actual bitmap
\r
3220 * being written to. When all the work is done, we can
\r
3221 * copy it to the real DC (the screen). This avoids
\r
3222 * the problems with flickering.
\r
3224 GetClientRect(hwndMain, &Rect);
\r
3225 bufferBitmap = CreateCompatibleBitmap(hdc, Rect.right-Rect.left+1,
\r
3226 Rect.bottom-Rect.top+1);
\r
3227 oldBitmap = SelectObject(hdcmem, bufferBitmap);
\r
3228 if (!appData.monoMode) {
\r
3229 SelectPalette(hdcmem, hPal, FALSE);
\r
3232 /* Create clips for dragging */
\r
3233 if (!fullrepaint) {
\r
3234 if (dragInfo.from.x >= 0) {
\r
3235 SquareToPos(dragInfo.from.y, dragInfo.from.x, &x, &y);
\r
3236 clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);
\r
3238 if (dragInfo.start.x >= 0) {
\r
3239 SquareToPos(dragInfo.start.y, dragInfo.start.x, &x, &y);
\r
3240 clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);
\r
3242 if (dragInfo.pos.x >= 0) {
\r
3243 x = dragInfo.pos.x - squareSize / 2;
\r
3244 y = dragInfo.pos.y - squareSize / 2;
\r
3245 clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);
\r
3247 if (dragInfo.lastpos.x >= 0) {
\r
3248 x = dragInfo.lastpos.x - squareSize / 2;
\r
3249 y = dragInfo.lastpos.y - squareSize / 2;
\r
3250 clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);
\r
3254 /* Are we animating a move?
\r
3256 * - remove the piece from the board (temporarely)
\r
3257 * - calculate the clipping region
\r
3259 if (!fullrepaint) {
\r
3260 if (animInfo.piece != EmptySquare) {
\r
3261 board[animInfo.from.y][animInfo.from.x] = EmptySquare;
\r
3262 x = boardRect.left + animInfo.lastpos.x;
\r
3263 y = boardRect.top + animInfo.lastpos.y;
\r
3264 x2 = boardRect.left + animInfo.pos.x;
\r
3265 y2 = boardRect.top + animInfo.pos.y;
\r
3266 clips[num_clips++] = CreateRectRgn(MIN(x,x2), MIN(y,y2), MAX(x,x2)+squareSize, MAX(y,y2)+squareSize);
\r
3267 /* Slight kludge. The real problem is that after AnimateMove is
\r
3268 done, the position on the screen does not match lastDrawn.
\r
3269 This currently causes trouble only on e.p. captures in
\r
3270 atomic, where the piece moves to an empty square and then
\r
3271 explodes. The old and new positions both had an empty square
\r
3272 at the destination, but animation has drawn a piece there and
\r
3273 we have to remember to erase it. [HGM] moved until after setting lastDrawn */
\r
3274 lastDrawn[animInfo.to.y][animInfo.to.x] = animInfo.piece;
\r
3278 /* No clips? Make sure we have fullrepaint set to TRUE */
\r
3279 if (num_clips == 0)
\r
3280 fullrepaint = TRUE;
\r
3282 /* Set clipping on the memory DC */
\r
3283 if (!fullrepaint) {
\r
3284 SelectClipRgn(hdcmem, clips[0]);
\r
3285 for (x = 1; x < num_clips; x++) {
\r
3286 if (ExtSelectClipRgn(hdcmem, clips[x], RGN_OR) == ERROR)
\r
3287 abort(); // this should never ever happen!
\r
3291 /* Do all the drawing to the memory DC */
\r
3292 if(explodeInfo.radius) { // [HGM] atomic
\r
3294 int x, y, r=(explodeInfo.radius * squareSize)/100;
\r
3295 board[explodeInfo.fromY][explodeInfo.fromX] = EmptySquare; // suppress display of capturer
\r
3296 SquareToPos(explodeInfo.toY, explodeInfo.toX, &x, &y);
\r
3297 x += squareSize/2;
\r
3298 y += squareSize/2;
\r
3299 if(!fullrepaint) {
\r
3300 clips[num_clips] = CreateRectRgn(x-r, y-r, x+r, y+r);
\r
3301 ExtSelectClipRgn(hdcmem, clips[num_clips++], RGN_OR);
\r
3303 DrawGridOnDC(hdcmem);
\r
3304 DrawHighlightsOnDC(hdcmem);
\r
3305 DrawBoardOnDC(hdcmem, board, tmphdc);
\r
3306 oldBrush = SelectObject(hdcmem, explodeBrush);
\r
3307 Ellipse(hdcmem, x-r, y-r, x+r, y+r);
\r
3308 SelectObject(hdcmem, oldBrush);
\r
3310 DrawGridOnDC(hdcmem);
\r
3311 DrawHighlightsOnDC(hdcmem);
\r
3312 DrawBoardOnDC(hdcmem, board, tmphdc);
\r
3315 HBITMAP whiteLogo = (HBITMAP) first.programLogo, blackLogo = (HBITMAP) second.programLogo;
\r
3316 if(appData.autoLogo) {
\r
3318 switch(gameMode) { // pick logos based on game mode
\r
3319 case IcsObserving:
\r
3320 whiteLogo = second.programLogo; // ICS logo
\r
3321 blackLogo = second.programLogo;
\r
3324 case IcsPlayingWhite:
\r
3325 if(!appData.zippyPlay) whiteLogo = userLogo;
\r
3326 blackLogo = second.programLogo; // ICS logo
\r
3328 case IcsPlayingBlack:
\r
3329 whiteLogo = second.programLogo; // ICS logo
\r
3330 blackLogo = appData.zippyPlay ? first.programLogo : userLogo;
\r
3332 case TwoMachinesPlay:
\r
3333 if(first.twoMachinesColor[0] == 'b') {
\r
3334 whiteLogo = second.programLogo;
\r
3335 blackLogo = first.programLogo;
\r
3338 case MachinePlaysWhite:
\r
3339 blackLogo = userLogo;
\r
3341 case MachinePlaysBlack:
\r
3342 whiteLogo = userLogo;
\r
3343 blackLogo = first.programLogo;
\r
3346 DrawLogoOnDC(hdc, leftLogoRect, flipClock ? blackLogo : whiteLogo);
\r
3347 DrawLogoOnDC(hdc, rightLogoRect, flipClock ? whiteLogo : blackLogo);
\r
3350 if( appData.highlightMoveWithArrow ) {
\r
3351 DrawArrowHighlight(hdcmem);
\r
3354 DrawCoordsOnDC(hdcmem);
\r
3356 CopyBoard(lastDrawn, board); /* [HGM] Moved to here from end of routine, */
\r
3357 /* to make sure lastDrawn contains what is actually drawn */
\r
3359 /* Put the dragged piece back into place and draw it (out of place!) */
\r
3360 if (dragged_piece != EmptySquare) {
\r
3361 /* [HGM] or restack */
\r
3362 if(dragInfo.from.x == BOARD_LEFT-2 )
\r
3363 board[dragInfo.from.y][dragInfo.from.x+1]++;
\r
3365 if(dragInfo.from.x == BOARD_RGHT+1 )
\r
3366 board[dragInfo.from.y][dragInfo.from.x-1]++;
\r
3367 board[dragInfo.from.y][dragInfo.from.x] = dragged_piece;
\r
3368 x = dragInfo.pos.x - squareSize / 2;
\r
3369 y = dragInfo.pos.y - squareSize / 2;
\r
3370 DrawPieceOnDC(hdcmem, dragged_piece,
\r
3371 ((int) dragged_piece < (int) BlackPawn),
\r
3372 (dragInfo.from.y + dragInfo.from.x) % 2, x, y, tmphdc);
\r
3375 /* Put the animated piece back into place and draw it */
\r
3376 if (animInfo.piece != EmptySquare) {
\r
3377 board[animInfo.from.y][animInfo.from.x] = animInfo.piece;
\r
3378 x = boardRect.left + animInfo.pos.x;
\r
3379 y = boardRect.top + animInfo.pos.y;
\r
3380 DrawPieceOnDC(hdcmem, animInfo.piece,
\r
3381 ((int) animInfo.piece < (int) BlackPawn),
\r
3382 (animInfo.from.y + animInfo.from.x) % 2, x, y, tmphdc);
\r
3385 /* Release the bufferBitmap by selecting in the old bitmap
\r
3386 * and delete the memory DC
\r
3388 SelectObject(hdcmem, oldBitmap);
\r
3391 /* Set clipping on the target DC */
\r
3392 if (!fullrepaint) {
\r
3393 SelectClipRgn(hdc, clips[0]);
\r
3394 for (x = 1; x < num_clips; x++) {
\r
3395 if (ExtSelectClipRgn(hdc, clips[x], RGN_OR) == ERROR)
\r
3396 abort(); // this should never ever happen!
\r
3400 /* Copy the new bitmap onto the screen in one go.
\r
3401 * This way we avoid any flickering
\r
3403 oldBitmap = SelectObject(tmphdc, bufferBitmap);
\r
3404 BitBlt(hdc, boardRect.left, boardRect.top,
\r
3405 boardRect.right - boardRect.left,
\r
3406 boardRect.bottom - boardRect.top,
\r
3407 tmphdc, boardRect.left, boardRect.top, SRCCOPY);
\r
3408 if(saveDiagFlag) {
\r
3409 BITMAP b; int i, j=0, m, w, wb, fac=0; char pData[1000000];
\r
3410 BITMAPINFOHEADER bih; int color[16], nrColors=0;
\r
3412 GetObject(bufferBitmap, sizeof(b), &b);
\r
3413 if(b.bmWidthBytes*b.bmHeight <= 990000) {
\r
3414 bih.biSize = sizeof(BITMAPINFOHEADER);
\r
3415 bih.biWidth = b.bmWidth;
\r
3416 bih.biHeight = b.bmHeight;
\r
3418 bih.biBitCount = b.bmBitsPixel;
\r
3419 bih.biCompression = 0;
\r
3420 bih.biSizeImage = b.bmWidthBytes*b.bmHeight;
\r
3421 bih.biXPelsPerMeter = 0;
\r
3422 bih.biYPelsPerMeter = 0;
\r
3423 bih.biClrUsed = 0;
\r
3424 bih.biClrImportant = 0;
\r
3425 // fprintf(diagFile, "t=%d\nw=%d\nh=%d\nB=%d\nP=%d\nX=%d\n",
\r
3426 // b.bmType, b.bmWidth, b.bmHeight, b.bmWidthBytes, b.bmPlanes, b.bmBitsPixel);
\r
3427 GetDIBits(tmphdc,bufferBitmap,0,b.bmHeight,pData,(BITMAPINFO*)&bih,DIB_RGB_COLORS);
\r
3428 // fprintf(diagFile, "%8x\n", (int) pData);
\r
3430 wb = b.bmWidthBytes;
\r
3432 for(i=0; i<wb*(b.bmHeight - boardRect.top + OUTER_MARGIN)>>2; i++) {
\r
3433 int k = ((int*) pData)[i];
\r
3434 for(j=0; j<nrColors; j++) if(color[j] == k) break;
\r
3435 if(j >= 16) break;
\r
3437 if(j >= nrColors) nrColors = j+1;
\r
3439 if(j<16) { // 16 colors is enough. Compress to 4 bits per pixel
\r
3441 for(i=0; i<b.bmHeight - boardRect.top + OUTER_MARGIN; i++) {
\r
3442 for(w=0; w<(wb>>2); w+=2) {
\r
3443 int k = ((int*) pData)[(wb*i>>2) + w];
\r
3444 for(j=0; j<nrColors; j++) if(color[j] == k) break;
\r
3445 k = ((int*) pData)[(wb*i>>2) + w + 1];
\r
3446 for(m=0; m<nrColors; m++) if(color[m] == k) break;
\r
3447 pData[p++] = m | j<<4;
\r
3449 while(p&3) pData[p++] = 0;
\r
3452 wb = ((wb+31)>>5)<<2;
\r
3454 // write BITMAPFILEHEADER
\r
3455 fprintf(diagFile, "BM");
\r
3456 fputDW(diagFile, wb*(b.bmHeight - boardRect.top + OUTER_MARGIN)+0x36 + (fac?64:0));
\r
3457 fputDW(diagFile, 0);
\r
3458 fputDW(diagFile, 0x36 + (fac?64:0));
\r
3459 // write BITMAPINFOHEADER
\r
3460 fputDW(diagFile, 40);
\r
3461 fputDW(diagFile, b.bmWidth);
\r
3462 fputDW(diagFile, b.bmHeight - boardRect.top + OUTER_MARGIN);
\r
3463 if(fac) fputDW(diagFile, 0x040001); // planes and bits/pixel
\r
3464 else fputDW(diagFile, 0x200001); // planes and bits/pixel
\r
3465 fputDW(diagFile, 0);
\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 // write color table
\r
3473 for(i=0; i<16; i++) fputDW(diagFile, color[i]);
\r
3474 // write bitmap data
\r
3475 for(i=0; i<wb*(b.bmHeight - boardRect.top + OUTER_MARGIN); i++)
\r
3476 fputc(pData[i], diagFile);
\r
3480 SelectObject(tmphdc, oldBitmap);
\r
3482 /* Massive cleanup */
\r
3483 for (x = 0; x < num_clips; x++)
\r
3484 DeleteObject(clips[x]);
\r
3487 DeleteObject(bufferBitmap);
\r
3490 ReleaseDC(hwndMain, hdc);
\r
3492 if (lastDrawnFlipView != flipView) {
\r
3494 CheckMenuItem(GetMenu(hwndMain),IDM_FlipView, MF_BYCOMMAND|MF_CHECKED);
\r
3496 CheckMenuItem(GetMenu(hwndMain),IDM_FlipView, MF_BYCOMMAND|MF_UNCHECKED);
\r
3499 /* CopyBoard(lastDrawn, board);*/
\r
3500 lastDrawnHighlight = highlightInfo;
\r
3501 lastDrawnPremove = premoveHighlightInfo;
\r
3502 lastDrawnFlipView = flipView;
\r
3503 lastDrawnValid = 1;
\r
3506 /* [HGM] diag: Save the current board display to the given open file and close the file */
\r
3511 saveDiagFlag = 1; diagFile = f;
\r
3512 HDCDrawPosition(NULL, TRUE, NULL);
\r
3516 // if(f != NULL) fprintf(f, "Sorry, but this feature is still in preparation\n");
\r
3523 /*---------------------------------------------------------------------------*\
\r
3524 | CLIENT PAINT PROCEDURE
\r
3525 | This is the main event-handler for the WM_PAINT message.
\r
3527 \*---------------------------------------------------------------------------*/
\r
3529 PaintProc(HWND hwnd)
\r
3535 if((hdc = BeginPaint(hwnd, &ps))) {
\r
3536 if (IsIconic(hwnd)) {
\r
3537 DrawIcon(hdc, 2, 2, iconCurrent);
\r
3539 if (!appData.monoMode) {
\r
3540 SelectPalette(hdc, hPal, FALSE);
\r
3541 RealizePalette(hdc);
\r
3543 HDCDrawPosition(hdc, 1, NULL);
\r
3545 SelectObject(hdc, font[boardSize][MESSAGE_FONT]->hf);
\r
3546 ExtTextOut(hdc, messageRect.left, messageRect.top,
\r
3547 ETO_CLIPPED|ETO_OPAQUE,
\r
3548 &messageRect, messageText, strlen(messageText), NULL);
\r
3549 SelectObject(hdc, oldFont);
\r
3550 DisplayBothClocks();
\r
3552 EndPaint(hwnd,&ps);
\r
3560 * If the user selects on a border boundary, return -1; if off the board,
\r
3561 * return -2. Otherwise map the event coordinate to the square.
\r
3562 * The offset boardRect.left or boardRect.top must already have been
\r
3563 * subtracted from x.
\r
3565 int EventToSquare(x, limit)
\r
3573 if ((x % (squareSize + lineGap)) >= squareSize)
\r
3575 x /= (squareSize + lineGap);
\r
3587 DropEnable dropEnables[] = {
\r
3588 { 'P', DP_Pawn, "Pawn" },
\r
3589 { 'N', DP_Knight, "Knight" },
\r
3590 { 'B', DP_Bishop, "Bishop" },
\r
3591 { 'R', DP_Rook, "Rook" },
\r
3592 { 'Q', DP_Queen, "Queen" },
\r
3596 SetupDropMenu(HMENU hmenu)
\r
3598 int i, count, enable;
\r
3600 extern char white_holding[], black_holding[];
\r
3601 char item[MSG_SIZ];
\r
3603 for (i=0; i<sizeof(dropEnables)/sizeof(DropEnable); i++) {
\r
3604 p = strchr(gameMode == IcsPlayingWhite ? white_holding : black_holding,
\r
3605 dropEnables[i].piece);
\r
3607 while (p && *p++ == dropEnables[i].piece) count++;
\r
3608 sprintf(item, "%s %d", dropEnables[i].name, count);
\r
3609 enable = count > 0 || !appData.testLegality
\r
3610 /*!!temp:*/ || (gameInfo.variant == VariantCrazyhouse
\r
3611 && !appData.icsActive);
\r
3612 ModifyMenu(hmenu, dropEnables[i].command,
\r
3613 MF_BYCOMMAND | (enable ? MF_ENABLED : MF_GRAYED) | MF_STRING,
\r
3614 dropEnables[i].command, item);
\r
3618 void DragPieceBegin(int x, int y)
\r
3620 dragInfo.lastpos.x = boardRect.left + x;
\r
3621 dragInfo.lastpos.y = boardRect.top + y;
\r
3622 dragInfo.from.x = fromX;
\r
3623 dragInfo.from.y = fromY;
\r
3624 dragInfo.start = dragInfo.from;
\r
3625 SetCapture(hwndMain);
\r
3628 void DragPieceEnd(int x, int y)
\r
3631 dragInfo.start.x = dragInfo.start.y = -1;
\r
3632 dragInfo.from = dragInfo.start;
\r
3633 dragInfo.pos = dragInfo.lastpos = dragInfo.start;
\r
3636 /* Event handler for mouse messages */
\r
3638 MouseEvent(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
3642 static int recursive = 0;
\r
3644 BOOLEAN forceFullRepaint = IsFullRepaintPreferrable(); /* [AS] */
\r
3647 if (message == WM_MBUTTONUP) {
\r
3648 /* Hideous kludge to fool TrackPopupMenu into paying attention
\r
3649 to the middle button: we simulate pressing the left button too!
\r
3651 PostMessage(hwnd, WM_LBUTTONDOWN, wParam, lParam);
\r
3652 PostMessage(hwnd, WM_LBUTTONUP, wParam, lParam);
\r
3658 pt.x = LOWORD(lParam);
\r
3659 pt.y = HIWORD(lParam);
\r
3660 x = EventToSquare(pt.x - boardRect.left, BOARD_WIDTH);
\r
3661 y = EventToSquare(pt.y - boardRect.top, BOARD_HEIGHT);
\r
3662 if (!flipView && y >= 0) {
\r
3663 y = BOARD_HEIGHT - 1 - y;
\r
3665 if (flipView && x >= 0) {
\r
3666 x = BOARD_WIDTH - 1 - x;
\r
3669 switch (message) {
\r
3670 case WM_LBUTTONDOWN:
\r
3671 if (PtInRect((LPRECT) &whiteRect, pt)) {
\r
3672 if (gameMode == EditPosition) {
\r
3673 SetWhiteToPlayEvent();
\r
3674 } else if (gameMode == IcsPlayingBlack ||
\r
3675 gameMode == MachinePlaysWhite) {
\r
3677 } else if (gameMode == EditGame) {
\r
3678 AdjustClock(flipClock, -1);
\r
3680 } else if (PtInRect((LPRECT) &blackRect, pt)) {
\r
3681 if (gameMode == EditPosition) {
\r
3682 SetBlackToPlayEvent();
\r
3683 } else if (gameMode == IcsPlayingWhite ||
\r
3684 gameMode == MachinePlaysBlack) {
\r
3686 } else if (gameMode == EditGame) {
\r
3687 AdjustClock(!flipClock, -1);
\r
3690 dragInfo.start.x = dragInfo.start.y = -1;
\r
3691 dragInfo.from = dragInfo.start;
\r
3692 if(fromX == -1 && frozen) { // not sure where this is for
\r
3693 fromX = fromY = -1;
\r
3694 DrawPosition(forceFullRepaint || FALSE, NULL); /* [AS] */
\r
3697 LeftClick(Press, pt.x - boardRect.left, pt.y - boardRect.top);
\r
3698 DrawPosition(TRUE, NULL);
\r
3701 case WM_LBUTTONUP:
\r
3702 LeftClick(Release, pt.x - boardRect.left, pt.y - boardRect.top);
\r
3703 DrawPosition(TRUE, NULL);
\r
3706 case WM_MOUSEMOVE:
\r
3707 if ((appData.animateDragging || appData.highlightDragging)
\r
3708 && (wParam & MK_LBUTTON)
\r
3709 && dragInfo.from.x >= 0)
\r
3711 BOOL full_repaint = FALSE;
\r
3713 if (appData.animateDragging) {
\r
3714 dragInfo.pos = pt;
\r
3716 if (appData.highlightDragging) {
\r
3717 SetHighlights(fromX, fromY, x, y);
\r
3718 if( IsDrawArrowEnabled() && (x < 0 || x >= BOARD_WIDTH || y < 0 || y >= BOARD_HEIGHT) ) {
\r
3719 full_repaint = TRUE;
\r
3723 DrawPosition( full_repaint, NULL);
\r
3725 dragInfo.lastpos = dragInfo.pos;
\r
3729 case WM_MOUSEWHEEL: // [DM]
\r
3730 { static int lastDir = 0; // [HGM] build in some hysteresis to avoid spurious events
\r
3731 /* Mouse Wheel is being rolled forward
\r
3732 * Play moves forward
\r
3734 if((short)HIWORD(wParam) > 0 && currentMove < forwardMostMove)
\r
3735 { if(lastDir == 1) ForwardEvent(); else lastDir = 1; } // [HGM] suppress first event in direction
\r
3736 /* Mouse Wheel is being rolled backward
\r
3737 * Play moves backward
\r
3739 if((short)HIWORD(wParam) < 0 && currentMove > backwardMostMove)
\r
3740 { if(lastDir == -1) BackwardEvent(); else lastDir = -1; }
\r
3744 case WM_MBUTTONDOWN:
\r
3745 case WM_RBUTTONDOWN:
\r
3748 fromX = fromY = -1;
\r
3749 dragInfo.pos.x = dragInfo.pos.y = -1;
\r
3750 dragInfo.start.x = dragInfo.start.y = -1;
\r
3751 dragInfo.from = dragInfo.start;
\r
3752 dragInfo.lastpos = dragInfo.pos;
\r
3753 if (appData.highlightDragging) {
\r
3754 ClearHighlights();
\r
3757 /* [HGM] right mouse button in clock area edit-game mode ups clock */
\r
3758 if (PtInRect((LPRECT) &whiteRect, pt)) {
\r
3759 if (gameMode == EditGame) AdjustClock(flipClock, 1);
\r
3760 } else if (PtInRect((LPRECT) &blackRect, pt)) {
\r
3761 if (gameMode == EditGame) AdjustClock(!flipClock, 1);
\r
3764 DrawPosition(TRUE, NULL);
\r
3766 switch (gameMode) {
\r
3767 case EditPosition:
\r
3768 case IcsExamining:
\r
3769 if (x < 0 || y < 0) break;
\r
3772 if (message == WM_MBUTTONDOWN) {
\r
3773 buttonCount = 3; /* even if system didn't think so */
\r
3774 if (wParam & MK_SHIFT)
\r
3775 MenuPopup(hwnd, pt, LoadMenu(hInst, "BlackPieceMenu"), -1);
\r
3777 MenuPopup(hwnd, pt, LoadMenu(hInst, "WhitePieceMenu"), -1);
\r
3778 } else { /* message == WM_RBUTTONDOWN */
\r
3779 /* Just have one menu, on the right button. Windows users don't
\r
3780 think to try the middle one, and sometimes other software steals
\r
3781 it, or it doesn't really exist. */
\r
3782 if(gameInfo.variant != VariantShogi)
\r
3783 MenuPopup(hwnd, pt, LoadMenu(hInst, "PieceMenu"), -1);
\r
3785 MenuPopup(hwnd, pt, LoadMenu(hInst, "ShogiPieceMenu"), -1);
\r
3788 case IcsPlayingWhite:
\r
3789 case IcsPlayingBlack:
\r
3791 case MachinePlaysWhite:
\r
3792 case MachinePlaysBlack:
\r
3793 if (appData.testLegality &&
\r
3794 gameInfo.variant != VariantBughouse &&
\r
3795 gameInfo.variant != VariantCrazyhouse) break;
\r
3796 if (x < 0 || y < 0) break;
\r
3799 hmenu = LoadMenu(hInst, "DropPieceMenu");
\r
3800 SetupDropMenu(hmenu);
\r
3801 MenuPopup(hwnd, pt, hmenu, -1);
\r
3812 /* Preprocess messages for buttons in main window */
\r
3814 ButtonProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
3816 int id = GetWindowLong(hwnd, GWL_ID);
\r
3819 for (i=0; i<N_BUTTONS; i++) {
\r
3820 if (buttonDesc[i].id == id) break;
\r
3822 if (i == N_BUTTONS) return 0;
\r
3823 switch (message) {
\r
3828 dir = (wParam == VK_LEFT) ? -1 : 1;
\r
3829 SetFocus(buttonDesc[(i + dir + N_BUTTONS) % N_BUTTONS].hwnd);
\r
3836 SendMessage(hwndMain, WM_COMMAND, MAKEWPARAM(buttonDesc[i].id, 0), 0);
\r
3839 if (appData.icsActive && (isalpha((char)wParam) || wParam == '0')) {
\r
3840 // [HGM] movenum: only letters or leading zero should go to ICS input
\r
3841 HWND h = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
3842 if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
3844 SendMessage(h, WM_CHAR, wParam, lParam);
\r
3846 } else if (isalpha((char)wParam) || isdigit((char)wParam)){
\r
3847 PopUpMoveDialog((char)wParam);
\r
3853 return CallWindowProc(buttonDesc[i].wndproc, hwnd, message, wParam, lParam);
\r
3856 /* Process messages for Promotion dialog box */
\r
3858 Promotion(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
3862 switch (message) {
\r
3863 case WM_INITDIALOG: /* message: initialize dialog box */
\r
3864 /* Center the dialog over the application window */
\r
3865 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
3866 ShowWindow(GetDlgItem(hDlg, PB_King),
\r
3867 (!appData.testLegality || gameInfo.variant == VariantSuicide ||
\r
3868 gameInfo.variant == VariantGiveaway || gameInfo.variant == VariantSuper ) ?
\r
3869 SW_SHOW : SW_HIDE);
\r
3870 /* [HGM] Only allow C & A promotions if these pieces are defined */
\r
3871 ShowWindow(GetDlgItem(hDlg, PB_Archbishop),
\r
3872 ((PieceToChar(WhiteAngel) >= 'A' &&
\r
3873 PieceToChar(WhiteAngel) != '~') ||
\r
3874 (PieceToChar(BlackAngel) >= 'A' &&
\r
3875 PieceToChar(BlackAngel) != '~') ) ?
\r
3876 SW_SHOW : SW_HIDE);
\r
3877 ShowWindow(GetDlgItem(hDlg, PB_Chancellor),
\r
3878 ((PieceToChar(WhiteMarshall) >= 'A' &&
\r
3879 PieceToChar(WhiteMarshall) != '~') ||
\r
3880 (PieceToChar(BlackMarshall) >= 'A' &&
\r
3881 PieceToChar(BlackMarshall) != '~') ) ?
\r
3882 SW_SHOW : SW_HIDE);
\r
3883 /* [HGM] Hide B & R button in Shogi, use Q as promote, N as defer */
\r
3884 ShowWindow(GetDlgItem(hDlg, PB_Rook),
\r
3885 gameInfo.variant != VariantShogi ?
\r
3886 SW_SHOW : SW_HIDE);
\r
3887 ShowWindow(GetDlgItem(hDlg, PB_Bishop),
\r
3888 gameInfo.variant != VariantShogi ?
\r
3889 SW_SHOW : SW_HIDE);
\r
3890 ShowWindow(GetDlgItem(hDlg, IDC_Yes),
\r
3891 gameInfo.variant == VariantShogi ?
\r
3892 SW_SHOW : SW_HIDE);
\r
3893 ShowWindow(GetDlgItem(hDlg, IDC_No),
\r
3894 gameInfo.variant == VariantShogi ?
\r
3895 SW_SHOW : SW_HIDE);
\r
3896 ShowWindow(GetDlgItem(hDlg, IDC_Centaur),
\r
3897 gameInfo.variant == VariantSuper ?
\r
3898 SW_SHOW : SW_HIDE);
\r
3901 case WM_COMMAND: /* message: received a command */
\r
3902 switch (LOWORD(wParam)) {
\r
3904 EndDialog(hDlg, TRUE); /* Exit the dialog */
\r
3905 ClearHighlights();
\r
3906 DrawPosition(FALSE, NULL);
\r
3909 promoChar = gameInfo.variant == VariantSuper ? PieceToChar(BlackSilver) : PieceToChar(BlackKing);
\r
3912 promoChar = gameInfo.variant == VariantShogi ? '+' : PieceToChar(BlackQueen);
\r
3915 promoChar = PieceToChar(BlackRook);
\r
3918 promoChar = PieceToChar(BlackBishop);
\r
3920 case PB_Chancellor:
\r
3921 promoChar = PieceToChar(BlackMarshall);
\r
3923 case PB_Archbishop:
\r
3924 promoChar = PieceToChar(BlackAngel);
\r
3927 promoChar = gameInfo.variant == VariantShogi ? '=' : PieceToChar(BlackKnight);
\r
3932 EndDialog(hDlg, TRUE); /* Exit the dialog */
\r
3933 /* [HGM] <popupFix> Call FinishMove rather than UserMoveEvent, as we
\r
3934 only show the popup when we are already sure the move is valid or
\r
3935 legal. We pass a faulty move type, but the kludge is that FinishMove
\r
3936 will figure out it is a promotion from the promoChar. */
\r
3937 UserMoveEvent(fromX, fromY, toX, toY, promoChar);
\r
3938 fromX = fromY = -1;
\r
3939 if (!appData.highlightLastMove) {
\r
3940 ClearHighlights();
\r
3941 DrawPosition(FALSE, NULL);
\r
3948 /* Pop up promotion dialog */
\r
3950 PromotionPopup(HWND hwnd)
\r
3954 lpProc = MakeProcInstance((FARPROC)Promotion, hInst);
\r
3955 DialogBox(hInst, MAKEINTRESOURCE(DLG_PromotionKing),
\r
3956 hwnd, (DLGPROC)lpProc);
\r
3957 FreeProcInstance(lpProc);
\r
3963 DrawPosition(TRUE, NULL);
\r
3964 PromotionPopup(hwndMain);
\r
3967 /* Toggle ShowThinking */
\r
3969 ToggleShowThinking()
\r
3971 appData.showThinking = !appData.showThinking;
\r
3972 ShowThinkingEvent();
\r
3976 LoadGameDialog(HWND hwnd, char* title)
\r
3980 char fileTitle[MSG_SIZ];
\r
3981 f = OpenFileDialog(hwnd, "rb", "",
\r
3982 appData.oldSaveStyle ? "gam" : "pgn",
\r
3984 title, &number, fileTitle, NULL);
\r
3986 cmailMsgLoaded = FALSE;
\r
3987 if (number == 0) {
\r
3988 int error = GameListBuild(f);
\r
3990 DisplayError("Cannot build game list", error);
\r
3991 } else if (!ListEmpty(&gameList) &&
\r
3992 ((ListGame *) gameList.tailPred)->number > 1) {
\r
3993 GameListPopUp(f, fileTitle);
\r
3996 GameListDestroy();
\r
3999 LoadGame(f, number, fileTitle, FALSE);
\r
4003 int get_term_width()
\r
4008 HFONT hfont, hold_font;
\r
4013 hText = GetDlgItem(hwndConsole, OPT_ConsoleText);
\r
4017 // get the text metrics
\r
4018 hdc = GetDC(hText);
\r
4019 lf = font[boardSize][CONSOLE_FONT]->lf;
\r
4020 if (consoleCF.dwEffects & CFE_BOLD)
\r
4021 lf.lfWeight = FW_BOLD;
\r
4022 if (consoleCF.dwEffects & CFE_ITALIC)
\r
4023 lf.lfItalic = TRUE;
\r
4024 if (consoleCF.dwEffects & CFE_STRIKEOUT)
\r
4025 lf.lfStrikeOut = TRUE;
\r
4026 if (consoleCF.dwEffects & CFE_UNDERLINE)
\r
4027 lf.lfUnderline = TRUE;
\r
4028 hfont = CreateFontIndirect(&lf);
\r
4029 hold_font = SelectObject(hdc, hfont);
\r
4030 GetTextMetrics(hdc, &tm);
\r
4031 SelectObject(hdc, hold_font);
\r
4032 DeleteObject(hfont);
\r
4033 ReleaseDC(hText, hdc);
\r
4035 // get the rectangle
\r
4036 SendMessage(hText, EM_GETRECT, 0, (LPARAM)&rc);
\r
4038 return (rc.right-rc.left) / tm.tmAveCharWidth;
\r
4041 void UpdateICSWidth(HWND hText)
\r
4043 LONG old_width, new_width;
\r
4045 new_width = get_term_width(hText, FALSE);
\r
4046 old_width = GetWindowLong(hText, GWL_USERDATA);
\r
4047 if (new_width != old_width)
\r
4049 ics_update_width(new_width);
\r
4050 SetWindowLong(hText, GWL_USERDATA, new_width);
\r
4055 ChangedConsoleFont()
\r
4058 CHARRANGE tmpsel, sel;
\r
4059 MyFont *f = font[boardSize][CONSOLE_FONT];
\r
4060 HWND hText = GetDlgItem(hwndConsole, OPT_ConsoleText);
\r
4061 HWND hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
4064 cfmt.cbSize = sizeof(CHARFORMAT);
\r
4065 cfmt.dwMask = CFM_FACE|CFM_SIZE|CFM_CHARSET;
\r
4066 strcpy(cfmt.szFaceName, font[boardSize][CONSOLE_FONT]->mfp.faceName);
\r
4067 /* yHeight is expressed in twips. A twip is 1/20 of a font's point
\r
4068 * size. This was undocumented in the version of MSVC++ that I had
\r
4069 * when I wrote the code, but is apparently documented now.
\r
4071 cfmt.yHeight = (int)(f->mfp.pointSize * 20.0 + 0.5);
\r
4072 cfmt.bCharSet = f->lf.lfCharSet;
\r
4073 cfmt.bPitchAndFamily = f->lf.lfPitchAndFamily;
\r
4074 SendMessage(hText, EM_SETCHARFORMAT, SCF_ALL, (LPARAM) &cfmt);
\r
4075 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM) &cfmt);
\r
4076 /* Why are the following seemingly needed too? */
\r
4077 SendMessage(hText, EM_SETCHARFORMAT, SCF_DEFAULT, (LPARAM) &cfmt);
\r
4078 SendMessage(hInput, EM_SETCHARFORMAT, SCF_DEFAULT, (LPARAM) &cfmt);
\r
4079 SendMessage(hText, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
4081 tmpsel.cpMax = -1; /*999999?*/
\r
4082 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&tmpsel);
\r
4083 SendMessage(hText, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM) &cfmt);
\r
4084 /* Trying putting this here too. It still seems to tickle a RichEdit
\r
4085 * bug: sometimes RichEdit indents the first line of a paragraph too.
\r
4087 paraf.cbSize = sizeof(paraf);
\r
4088 paraf.dwMask = PFM_OFFSET | PFM_STARTINDENT;
\r
4089 paraf.dxStartIndent = 0;
\r
4090 paraf.dxOffset = WRAP_INDENT;
\r
4091 SendMessage(hText, EM_SETPARAFORMAT, 0, (LPARAM) ¶f);
\r
4092 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
4093 UpdateICSWidth(hText);
\r
4096 /*---------------------------------------------------------------------------*\
\r
4098 * Window Proc for main window
\r
4100 \*---------------------------------------------------------------------------*/
\r
4102 /* Process messages for main window, etc. */
\r
4104 WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
4107 int wmId, wmEvent;
\r
4111 char fileTitle[MSG_SIZ];
\r
4112 char buf[MSG_SIZ];
\r
4113 static SnapData sd;
\r
4115 switch (message) {
\r
4117 case WM_PAINT: /* message: repaint portion of window */
\r
4121 case WM_ERASEBKGND:
\r
4122 if (IsIconic(hwnd)) {
\r
4123 /* Cheat; change the message */
\r
4124 return (DefWindowProc(hwnd, WM_ICONERASEBKGND, wParam, lParam));
\r
4126 return (DefWindowProc(hwnd, message, wParam, lParam));
\r
4130 case WM_LBUTTONDOWN:
\r
4131 case WM_MBUTTONDOWN:
\r
4132 case WM_RBUTTONDOWN:
\r
4133 case WM_LBUTTONUP:
\r
4134 case WM_MBUTTONUP:
\r
4135 case WM_RBUTTONUP:
\r
4136 case WM_MOUSEMOVE:
\r
4137 case WM_MOUSEWHEEL:
\r
4138 MouseEvent(hwnd, message, wParam, lParam);
\r
4141 JAWS_KB_NAVIGATION
\r
4145 JAWS_ALT_INTERCEPT
\r
4147 if (appData.icsActive && ((char)wParam == '\r' || (char)wParam > ' ' && !((char)wParam >= '1' && (char)wParam <= '9'))) {
\r
4148 // [HGM] movenum: for non-zero digits we always do type-in dialog
\r
4149 HWND h = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
4150 if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
4152 SendMessage(h, message, wParam, lParam);
\r
4153 } else if(lParam != KF_REPEAT) {
\r
4154 if (isalpha((char)wParam) || isdigit((char)wParam)) {
\r
4155 PopUpMoveDialog((char)wParam);
\r
4156 } else if((char)wParam == 003) CopyGameToClipboard();
\r
4157 else if((char)wParam == 026) PasteGameOrFENFromClipboard();
\r
4162 case WM_PALETTECHANGED:
\r
4163 if (hwnd != (HWND)wParam && !appData.monoMode) {
\r
4165 HDC hdc = GetDC(hwndMain);
\r
4166 SelectPalette(hdc, hPal, TRUE);
\r
4167 nnew = RealizePalette(hdc);
\r
4169 paletteChanged = TRUE;
\r
4170 InvalidateRect(hwnd, &boardRect, FALSE);
\r
4172 ReleaseDC(hwnd, hdc);
\r
4176 case WM_QUERYNEWPALETTE:
\r
4177 if (!appData.monoMode /*&& paletteChanged*/) {
\r
4179 HDC hdc = GetDC(hwndMain);
\r
4180 paletteChanged = FALSE;
\r
4181 SelectPalette(hdc, hPal, FALSE);
\r
4182 nnew = RealizePalette(hdc);
\r
4184 InvalidateRect(hwnd, &boardRect, FALSE);
\r
4186 ReleaseDC(hwnd, hdc);
\r
4191 case WM_COMMAND: /* message: command from application menu */
\r
4192 wmId = LOWORD(wParam);
\r
4193 wmEvent = HIWORD(wParam);
\r
4198 SAY("new game enter a move to play against the computer with white");
\r
4201 case IDM_NewGameFRC:
\r
4202 if( NewGameFRC() == 0 ) {
\r
4207 case IDM_NewVariant:
\r
4208 NewVariantPopup(hwnd);
\r
4211 case IDM_LoadGame:
\r
4212 LoadGameDialog(hwnd, "Load Game from File");
\r
4215 case IDM_LoadNextGame:
\r
4219 case IDM_LoadPrevGame:
\r
4223 case IDM_ReloadGame:
\r
4227 case IDM_LoadPosition:
\r
4228 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile) {
\r
4229 Reset(FALSE, TRUE);
\r
4232 f = OpenFileDialog(hwnd, "rb", "",
\r
4233 appData.oldSaveStyle ? "pos" : "fen",
\r
4235 "Load Position from File", &number, fileTitle, NULL);
\r
4237 LoadPosition(f, number, fileTitle);
\r
4241 case IDM_LoadNextPosition:
\r
4242 ReloadPosition(1);
\r
4245 case IDM_LoadPrevPosition:
\r
4246 ReloadPosition(-1);
\r
4249 case IDM_ReloadPosition:
\r
4250 ReloadPosition(0);
\r
4253 case IDM_SaveGame:
\r
4254 defName = DefaultFileName(appData.oldSaveStyle ? "gam" : "pgn");
\r
4255 f = OpenFileDialog(hwnd, "a", defName,
\r
4256 appData.oldSaveStyle ? "gam" : "pgn",
\r
4258 "Save Game to File", NULL, fileTitle, NULL);
\r
4260 SaveGame(f, 0, "");
\r
4264 case IDM_SavePosition:
\r
4265 defName = DefaultFileName(appData.oldSaveStyle ? "pos" : "fen");
\r
4266 f = OpenFileDialog(hwnd, "a", defName,
\r
4267 appData.oldSaveStyle ? "pos" : "fen",
\r
4269 "Save Position to File", NULL, fileTitle, NULL);
\r
4271 SavePosition(f, 0, "");
\r
4275 case IDM_SaveDiagram:
\r
4276 defName = "diagram";
\r
4277 f = OpenFileDialog(hwnd, "wb", defName,
\r
4280 "Save Diagram to File", NULL, fileTitle, NULL);
\r
4286 case IDM_CopyGame:
\r
4287 CopyGameToClipboard();
\r
4290 case IDM_PasteGame:
\r
4291 PasteGameFromClipboard();
\r
4294 case IDM_CopyGameListToClipboard:
\r
4295 CopyGameListToClipboard();
\r
4298 /* [AS] Autodetect FEN or PGN data */
\r
4299 case IDM_PasteAny:
\r
4300 PasteGameOrFENFromClipboard();
\r
4303 /* [AS] Move history */
\r
4304 case IDM_ShowMoveHistory:
\r
4305 if( MoveHistoryIsUp() ) {
\r
4306 MoveHistoryPopDown();
\r
4309 MoveHistoryPopUp();
\r
4313 /* [AS] Eval graph */
\r
4314 case IDM_ShowEvalGraph:
\r
4315 if( EvalGraphIsUp() ) {
\r
4316 EvalGraphPopDown();
\r
4320 SetFocus(hwndMain);
\r
4324 /* [AS] Engine output */
\r
4325 case IDM_ShowEngineOutput:
\r
4326 if( EngineOutputIsUp() ) {
\r
4327 EngineOutputPopDown();
\r
4330 EngineOutputPopUp();
\r
4334 /* [AS] User adjudication */
\r
4335 case IDM_UserAdjudication_White:
\r
4336 UserAdjudicationEvent( +1 );
\r
4339 case IDM_UserAdjudication_Black:
\r
4340 UserAdjudicationEvent( -1 );
\r
4343 case IDM_UserAdjudication_Draw:
\r
4344 UserAdjudicationEvent( 0 );
\r
4347 /* [AS] Game list options dialog */
\r
4348 case IDM_GameListOptions:
\r
4349 GameListOptions();
\r
4356 case IDM_CopyPosition:
\r
4357 CopyFENToClipboard();
\r
4360 case IDM_PastePosition:
\r
4361 PasteFENFromClipboard();
\r
4364 case IDM_MailMove:
\r
4368 case IDM_ReloadCMailMsg:
\r
4369 Reset(TRUE, TRUE);
\r
4370 ReloadCmailMsgEvent(FALSE);
\r
4373 case IDM_Minimize:
\r
4374 ShowWindow(hwnd, SW_MINIMIZE);
\r
4381 case IDM_MachineWhite:
\r
4382 MachineWhiteEvent();
\r
4384 * refresh the tags dialog only if it's visible
\r
4386 if (gameMode == MachinePlaysWhite && IsWindowVisible(editTagsDialog)) {
\r
4388 tags = PGNTags(&gameInfo);
\r
4389 TagsPopUp(tags, CmailMsg());
\r
4392 SAY("computer starts playing white");
\r
4395 case IDM_MachineBlack:
\r
4396 MachineBlackEvent();
\r
4398 * refresh the tags dialog only if it's visible
\r
4400 if (gameMode == MachinePlaysBlack && IsWindowVisible(editTagsDialog)) {
\r
4402 tags = PGNTags(&gameInfo);
\r
4403 TagsPopUp(tags, CmailMsg());
\r
4406 SAY("computer starts playing black");
\r
4409 case IDM_TwoMachines:
\r
4410 TwoMachinesEvent();
\r
4412 * refresh the tags dialog only if it's visible
\r
4414 if (gameMode == TwoMachinesPlay && IsWindowVisible(editTagsDialog)) {
\r
4416 tags = PGNTags(&gameInfo);
\r
4417 TagsPopUp(tags, CmailMsg());
\r
4420 SAY("programs start playing each other");
\r
4423 case IDM_AnalysisMode:
\r
4424 if (!first.analysisSupport) {
\r
4425 sprintf(buf, "%s does not support analysis", first.tidy);
\r
4426 DisplayError(buf, 0);
\r
4428 SAY("analyzing current position");
\r
4429 /* [DM] icsEngineAnlyze [HGM] Why is this front-end??? */
\r
4430 if (appData.icsActive) {
\r
4431 if (gameMode != IcsObserving) {
\r
4432 sprintf(buf, "You are not observing a game");
\r
4433 DisplayError(buf, 0);
\r
4434 /* secure check */
\r
4435 if (appData.icsEngineAnalyze) {
\r
4436 if (appData.debugMode)
\r
4437 fprintf(debugFP, "Found unexpected active ICS engine analyze \n");
\r
4438 ExitAnalyzeMode();
\r
4444 /* if enable, user want disable icsEngineAnalyze */
\r
4445 if (appData.icsEngineAnalyze) {
\r
4446 ExitAnalyzeMode();
\r
4450 appData.icsEngineAnalyze = TRUE;
\r
4451 if (appData.debugMode) fprintf(debugFP, "ICS engine analyze starting...\n");
\r
4454 if (!appData.showThinking) ToggleShowThinking();
\r
4455 AnalyzeModeEvent();
\r
4459 case IDM_AnalyzeFile:
\r
4460 if (!first.analysisSupport) {
\r
4461 char buf[MSG_SIZ];
\r
4462 sprintf(buf, "%s does not support analysis", first.tidy);
\r
4463 DisplayError(buf, 0);
\r
4465 if (!appData.showThinking) ToggleShowThinking();
\r
4466 AnalyzeFileEvent();
\r
4467 LoadGameDialog(hwnd, "Analyze Game from File");
\r
4468 AnalysisPeriodicEvent(1);
\r
4472 case IDM_IcsClient:
\r
4476 case IDM_EditGame:
\r
4481 case IDM_EditPosition:
\r
4482 EditPositionEvent();
\r
4483 SAY("to set up a position type a FEN");
\r
4486 case IDM_Training:
\r
4490 case IDM_ShowGameList:
\r
4491 ShowGameListProc();
\r
4494 case IDM_EditTags:
\r
4498 case IDM_EditComment:
\r
4499 if (commentUp && editComment) {
\r
4502 EditCommentEvent();
\r
4522 case IDM_CallFlag:
\r
4542 case IDM_StopObserving:
\r
4543 StopObservingEvent();
\r
4546 case IDM_StopExamining:
\r
4547 StopExaminingEvent();
\r
4550 case IDM_TypeInMove:
\r
4551 PopUpMoveDialog('\000');
\r
4554 case IDM_TypeInName:
\r
4555 PopUpNameDialog('\000');
\r
4558 case IDM_Backward:
\r
4560 SetFocus(hwndMain);
\r
4567 SetFocus(hwndMain);
\r
4572 SetFocus(hwndMain);
\r
4577 SetFocus(hwndMain);
\r
4584 case IDM_TruncateGame:
\r
4585 TruncateGameEvent();
\r
4592 case IDM_RetractMove:
\r
4593 RetractMoveEvent();
\r
4596 case IDM_FlipView:
\r
4597 flipView = !flipView;
\r
4598 DrawPosition(FALSE, NULL);
\r
4601 case IDM_FlipClock:
\r
4602 flipClock = !flipClock;
\r
4603 DisplayBothClocks();
\r
4604 DrawPosition(FALSE, NULL);
\r
4607 case IDM_MuteSounds:
\r
4608 mute = !mute; // [HGM] mute: keep track of global muting variable
\r
4609 CheckMenuItem(GetMenu(hwndMain),IDM_MuteSounds,
\r
4610 MF_BYCOMMAND|(mute?MF_CHECKED:MF_UNCHECKED));
\r
4613 case IDM_GeneralOptions:
\r
4614 GeneralOptionsPopup(hwnd);
\r
4615 DrawPosition(TRUE, NULL);
\r
4618 case IDM_BoardOptions:
\r
4619 BoardOptionsPopup(hwnd);
\r
4622 case IDM_EnginePlayOptions:
\r
4623 EnginePlayOptionsPopup(hwnd);
\r
4626 case IDM_Engine1Options:
\r
4627 EngineOptionsPopup(hwnd, &first);
\r
4630 case IDM_Engine2Options:
\r
4631 EngineOptionsPopup(hwnd, &second);
\r
4634 case IDM_OptionsUCI:
\r
4635 UciOptionsPopup(hwnd);
\r
4638 case IDM_IcsOptions:
\r
4639 IcsOptionsPopup(hwnd);
\r
4643 FontsOptionsPopup(hwnd);
\r
4647 SoundOptionsPopup(hwnd);
\r
4650 case IDM_CommPort:
\r
4651 CommPortOptionsPopup(hwnd);
\r
4654 case IDM_LoadOptions:
\r
4655 LoadOptionsPopup(hwnd);
\r
4658 case IDM_SaveOptions:
\r
4659 SaveOptionsPopup(hwnd);
\r
4662 case IDM_TimeControl:
\r
4663 TimeControlOptionsPopup(hwnd);
\r
4666 case IDM_SaveSettings:
\r
4667 SaveSettings(settingsFileName);
\r
4670 case IDM_SaveSettingsOnExit:
\r
4671 saveSettingsOnExit = !saveSettingsOnExit;
\r
4672 (void) CheckMenuItem(GetMenu(hwndMain), IDM_SaveSettingsOnExit,
\r
4673 MF_BYCOMMAND|(saveSettingsOnExit ?
\r
4674 MF_CHECKED : MF_UNCHECKED));
\r
4685 case IDM_AboutGame:
\r
4690 appData.debugMode = !appData.debugMode;
\r
4691 if (appData.debugMode) {
\r
4692 char dir[MSG_SIZ];
\r
4693 GetCurrentDirectory(MSG_SIZ, dir);
\r
4694 SetCurrentDirectory(installDir);
\r
4695 debugFP = fopen(appData.nameOfDebugFile, "w");
\r
4696 SetCurrentDirectory(dir);
\r
4697 setbuf(debugFP, NULL);
\r
4704 case IDM_HELPCONTENTS:
\r
4705 if (!MyHelp (hwnd, "winboard.hlp", HELP_KEY,(DWORD)(LPSTR)"CONTENTS") &&
\r
4706 !HtmlHelp(hwnd, "winboard.chm", 0, 0) ) {
\r
4707 MessageBox (GetFocus(),
\r
4708 "Unable to activate help",
\r
4709 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
4713 case IDM_HELPSEARCH:
\r
4714 if (!MyHelp (hwnd, "winboard.hlp", HELP_PARTIALKEY, (DWORD)(LPSTR)"") &&
\r
4715 !HtmlHelp(hwnd, "winboard.chm", 0, 0) ) {
\r
4716 MessageBox (GetFocus(),
\r
4717 "Unable to activate help",
\r
4718 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
4722 case IDM_HELPHELP:
\r
4723 if(!WinHelp(hwnd, (LPSTR)NULL, HELP_HELPONHELP, 0)) {
\r
4724 MessageBox (GetFocus(),
\r
4725 "Unable to activate help",
\r
4726 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
4731 lpProc = MakeProcInstance((FARPROC)About, hInst);
\r
4733 (gameInfo.event && strcmp(gameInfo.event, "Easter Egg Hunt") == 0) ?
\r
4734 "AboutBox2" : "AboutBox", hwnd, (DLGPROC)lpProc);
\r
4735 FreeProcInstance(lpProc);
\r
4738 case IDM_DirectCommand1:
\r
4739 AskQuestionEvent("Direct Command",
\r
4740 "Send to chess program:", "", "1");
\r
4742 case IDM_DirectCommand2:
\r
4743 AskQuestionEvent("Direct Command",
\r
4744 "Send to second chess program:", "", "2");
\r
4747 case EP_WhitePawn:
\r
4748 EditPositionMenuEvent(WhitePawn, fromX, fromY);
\r
4749 fromX = fromY = -1;
\r
4752 case EP_WhiteKnight:
\r
4753 EditPositionMenuEvent(WhiteKnight, fromX, fromY);
\r
4754 fromX = fromY = -1;
\r
4757 case EP_WhiteBishop:
\r
4758 EditPositionMenuEvent(WhiteBishop, fromX, fromY);
\r
4759 fromX = fromY = -1;
\r
4762 case EP_WhiteRook:
\r
4763 EditPositionMenuEvent(WhiteRook, fromX, fromY);
\r
4764 fromX = fromY = -1;
\r
4767 case EP_WhiteQueen:
\r
4768 EditPositionMenuEvent(WhiteQueen, fromX, fromY);
\r
4769 fromX = fromY = -1;
\r
4772 case EP_WhiteFerz:
\r
4773 EditPositionMenuEvent(WhiteFerz, fromX, fromY);
\r
4774 fromX = fromY = -1;
\r
4777 case EP_WhiteWazir:
\r
4778 EditPositionMenuEvent(WhiteWazir, fromX, fromY);
\r
4779 fromX = fromY = -1;
\r
4782 case EP_WhiteAlfil:
\r
4783 EditPositionMenuEvent(WhiteAlfil, fromX, fromY);
\r
4784 fromX = fromY = -1;
\r
4787 case EP_WhiteCannon:
\r
4788 EditPositionMenuEvent(WhiteCannon, fromX, fromY);
\r
4789 fromX = fromY = -1;
\r
4792 case EP_WhiteCardinal:
\r
4793 EditPositionMenuEvent(WhiteAngel, fromX, fromY);
\r
4794 fromX = fromY = -1;
\r
4797 case EP_WhiteMarshall:
\r
4798 EditPositionMenuEvent(WhiteMarshall, fromX, fromY);
\r
4799 fromX = fromY = -1;
\r
4802 case EP_WhiteKing:
\r
4803 EditPositionMenuEvent(WhiteKing, fromX, fromY);
\r
4804 fromX = fromY = -1;
\r
4807 case EP_BlackPawn:
\r
4808 EditPositionMenuEvent(BlackPawn, fromX, fromY);
\r
4809 fromX = fromY = -1;
\r
4812 case EP_BlackKnight:
\r
4813 EditPositionMenuEvent(BlackKnight, fromX, fromY);
\r
4814 fromX = fromY = -1;
\r
4817 case EP_BlackBishop:
\r
4818 EditPositionMenuEvent(BlackBishop, fromX, fromY);
\r
4819 fromX = fromY = -1;
\r
4822 case EP_BlackRook:
\r
4823 EditPositionMenuEvent(BlackRook, fromX, fromY);
\r
4824 fromX = fromY = -1;
\r
4827 case EP_BlackQueen:
\r
4828 EditPositionMenuEvent(BlackQueen, fromX, fromY);
\r
4829 fromX = fromY = -1;
\r
4832 case EP_BlackFerz:
\r
4833 EditPositionMenuEvent(BlackFerz, fromX, fromY);
\r
4834 fromX = fromY = -1;
\r
4837 case EP_BlackWazir:
\r
4838 EditPositionMenuEvent(BlackWazir, fromX, fromY);
\r
4839 fromX = fromY = -1;
\r
4842 case EP_BlackAlfil:
\r
4843 EditPositionMenuEvent(BlackAlfil, fromX, fromY);
\r
4844 fromX = fromY = -1;
\r
4847 case EP_BlackCannon:
\r
4848 EditPositionMenuEvent(BlackCannon, fromX, fromY);
\r
4849 fromX = fromY = -1;
\r
4852 case EP_BlackCardinal:
\r
4853 EditPositionMenuEvent(BlackAngel, fromX, fromY);
\r
4854 fromX = fromY = -1;
\r
4857 case EP_BlackMarshall:
\r
4858 EditPositionMenuEvent(BlackMarshall, fromX, fromY);
\r
4859 fromX = fromY = -1;
\r
4862 case EP_BlackKing:
\r
4863 EditPositionMenuEvent(BlackKing, fromX, fromY);
\r
4864 fromX = fromY = -1;
\r
4867 case EP_EmptySquare:
\r
4868 EditPositionMenuEvent(EmptySquare, fromX, fromY);
\r
4869 fromX = fromY = -1;
\r
4872 case EP_ClearBoard:
\r
4873 EditPositionMenuEvent(ClearBoard, fromX, fromY);
\r
4874 fromX = fromY = -1;
\r
4878 EditPositionMenuEvent(WhitePlay, fromX, fromY);
\r
4879 fromX = fromY = -1;
\r
4883 EditPositionMenuEvent(BlackPlay, fromX, fromY);
\r
4884 fromX = fromY = -1;
\r
4888 EditPositionMenuEvent(PromotePiece, fromX, fromY);
\r
4889 fromX = fromY = -1;
\r
4893 EditPositionMenuEvent(DemotePiece, fromX, fromY);
\r
4894 fromX = fromY = -1;
\r
4898 DropMenuEvent(WhitePawn, fromX, fromY);
\r
4899 fromX = fromY = -1;
\r
4903 DropMenuEvent(WhiteKnight, fromX, fromY);
\r
4904 fromX = fromY = -1;
\r
4908 DropMenuEvent(WhiteBishop, fromX, fromY);
\r
4909 fromX = fromY = -1;
\r
4913 DropMenuEvent(WhiteRook, fromX, fromY);
\r
4914 fromX = fromY = -1;
\r
4918 DropMenuEvent(WhiteQueen, fromX, fromY);
\r
4919 fromX = fromY = -1;
\r
4923 return (DefWindowProc(hwnd, message, wParam, lParam));
\r
4929 case CLOCK_TIMER_ID:
\r
4930 KillTimer(hwnd, clockTimerEvent); /* Simulate one-shot timer as in X */
\r
4931 clockTimerEvent = 0;
\r
4932 DecrementClocks(); /* call into back end */
\r
4934 case LOAD_GAME_TIMER_ID:
\r
4935 KillTimer(hwnd, loadGameTimerEvent); /* Simulate one-shot timer as in X*/
\r
4936 loadGameTimerEvent = 0;
\r
4937 AutoPlayGameLoop(); /* call into back end */
\r
4939 case ANALYSIS_TIMER_ID:
\r
4940 if ((gameMode == AnalyzeMode || gameMode == AnalyzeFile
\r
4941 || appData.icsEngineAnalyze) && appData.periodicUpdates) {
\r
4942 AnalysisPeriodicEvent(0);
\r
4944 KillTimer(hwnd, analysisTimerEvent);
\r
4945 analysisTimerEvent = 0;
\r
4948 case DELAYED_TIMER_ID:
\r
4949 KillTimer(hwnd, delayedTimerEvent);
\r
4950 delayedTimerEvent = 0;
\r
4951 delayedTimerCallback();
\r
4956 case WM_USER_Input:
\r
4957 InputEvent(hwnd, message, wParam, lParam);
\r
4960 /* [AS] Also move "attached" child windows */
\r
4961 case WM_WINDOWPOSCHANGING:
\r
4963 if( hwnd == hwndMain && appData.useStickyWindows ) {
\r
4964 LPWINDOWPOS lpwp = (LPWINDOWPOS) lParam;
\r
4966 if( ((lpwp->flags & SWP_NOMOVE) == 0) && ((lpwp->flags & SWP_NOSIZE) != 0) ) {
\r
4967 /* Window is moving */
\r
4970 // GetWindowRect( hwnd, &rcMain ); //[HGM] sticky: in XP this returned new position, not old
\r
4971 rcMain.left = wpMain.x; // replace by these 4 lines to reconstruct old rect
\r
4972 rcMain.right = wpMain.x + wpMain.width;
\r
4973 rcMain.top = wpMain.y;
\r
4974 rcMain.bottom = wpMain.y + wpMain.height;
\r
4976 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, moveHistoryDialog, &wpMoveHistory );
\r
4977 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, evalGraphDialog, &wpEvalGraph );
\r
4978 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, engineOutputDialog, &wpEngineOutput );
\r
4979 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, gameListDialog, &wpGameList );
\r
4980 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, hwndConsole, &wpConsole );
\r
4981 wpMain.x = lpwp->x;
\r
4982 wpMain.y = lpwp->y;
\r
4987 /* [AS] Snapping */
\r
4988 case WM_ENTERSIZEMOVE:
\r
4989 if(appData.debugMode) { fprintf(debugFP, "size-move\n"); }
\r
4990 if (hwnd == hwndMain) {
\r
4991 doingSizing = TRUE;
\r
4994 return OnEnterSizeMove( &sd, hwnd, wParam, lParam );
\r
4998 if(appData.debugMode) { fprintf(debugFP, "sizing\n"); }
\r
4999 if (hwnd == hwndMain) {
\r
5000 lastSizing = wParam;
\r
5005 if(appData.debugMode) { fprintf(debugFP, "moving\n"); }
\r
5006 return OnMoving( &sd, hwnd, wParam, lParam );
\r
5008 case WM_EXITSIZEMOVE:
\r
5009 if(appData.debugMode) { fprintf(debugFP, "exit size-move, size = %d\n", squareSize); }
\r
5010 if (hwnd == hwndMain) {
\r
5012 doingSizing = FALSE;
\r
5013 InvalidateRect(hwnd, &boardRect, FALSE);
\r
5014 GetClientRect(hwnd, &client);
\r
5015 ResizeBoard(client.right, client.bottom, lastSizing);
\r
5017 if(appData.debugMode) { fprintf(debugFP, "square size = %d\n", squareSize); }
\r
5019 return OnExitSizeMove( &sd, hwnd, wParam, lParam );
\r
5022 case WM_DESTROY: /* message: window being destroyed */
\r
5023 PostQuitMessage(0);
\r
5027 if (hwnd == hwndMain) {
\r
5032 default: /* Passes it on if unprocessed */
\r
5033 return (DefWindowProc(hwnd, message, wParam, lParam));
\r
5038 /*---------------------------------------------------------------------------*\
\r
5040 * Misc utility routines
\r
5042 \*---------------------------------------------------------------------------*/
\r
5045 * Decent random number generator, at least not as bad as Windows
\r
5046 * standard rand, which returns a value in the range 0 to 0x7fff.
\r
5048 unsigned int randstate;
\r
5053 randstate = randstate * 1664525 + 1013904223;
\r
5054 return (int) randstate & 0x7fffffff;
\r
5058 mysrandom(unsigned int seed)
\r
5065 * returns TRUE if user selects a different color, FALSE otherwise
\r
5069 ChangeColor(HWND hwnd, COLORREF *which)
\r
5071 static BOOL firstTime = TRUE;
\r
5072 static DWORD customColors[16];
\r
5074 COLORREF newcolor;
\r
5079 /* Make initial colors in use available as custom colors */
\r
5080 /* Should we put the compiled-in defaults here instead? */
\r
5082 customColors[i++] = lightSquareColor & 0xffffff;
\r
5083 customColors[i++] = darkSquareColor & 0xffffff;
\r
5084 customColors[i++] = whitePieceColor & 0xffffff;
\r
5085 customColors[i++] = blackPieceColor & 0xffffff;
\r
5086 customColors[i++] = highlightSquareColor & 0xffffff;
\r
5087 customColors[i++] = premoveHighlightColor & 0xffffff;
\r
5089 for (ccl = (ColorClass) 0; ccl < NColorClasses && i < 16; ccl++) {
\r
5090 customColors[i++] = textAttribs[ccl].color;
\r
5092 while (i < 16) customColors[i++] = RGB(255, 255, 255);
\r
5093 firstTime = FALSE;
\r
5096 cc.lStructSize = sizeof(cc);
\r
5097 cc.hwndOwner = hwnd;
\r
5098 cc.hInstance = NULL;
\r
5099 cc.rgbResult = (DWORD) (*which & 0xffffff);
\r
5100 cc.lpCustColors = (LPDWORD) customColors;
\r
5101 cc.Flags = CC_RGBINIT|CC_FULLOPEN;
\r
5103 if (!ChooseColor(&cc)) return FALSE;
\r
5105 newcolor = (COLORREF) (0x2000000 | cc.rgbResult);
\r
5106 if (newcolor == *which) return FALSE;
\r
5107 *which = newcolor;
\r
5111 InitDrawingColors();
\r
5112 InvalidateRect(hwnd, &boardRect, FALSE);
\r
5117 MyLoadSound(MySound *ms)
\r
5123 if (ms->data) free(ms->data);
\r
5126 switch (ms->name[0]) {
\r
5132 /* System sound from Control Panel. Don't preload here. */
\r
5136 if (ms->name[1] == NULLCHAR) {
\r
5137 /* "!" alone = silence */
\r
5140 /* Builtin wave resource. Error if not found. */
\r
5141 HANDLE h = FindResource(hInst, ms->name + 1, "WAVE");
\r
5142 if (h == NULL) break;
\r
5143 ms->data = (void *)LoadResource(hInst, h);
\r
5144 if (h == NULL) break;
\r
5149 /* .wav file. Error if not found. */
\r
5150 f = fopen(ms->name, "rb");
\r
5151 if (f == NULL) break;
\r
5152 if (fstat(fileno(f), &st) < 0) break;
\r
5153 ms->data = malloc(st.st_size);
\r
5154 if (fread(ms->data, st.st_size, 1, f) < 1) break;
\r
5160 char buf[MSG_SIZ];
\r
5161 sprintf(buf, "Error loading sound %s", ms->name);
\r
5162 DisplayError(buf, GetLastError());
\r
5168 MyPlaySound(MySound *ms)
\r
5170 BOOLEAN ok = FALSE;
\r
5172 if(mute) return TRUE; // [HGM] mute: suppress all sound play when muted
\r
5173 switch (ms->name[0]) {
\r
5175 if(appData.debugMode) fprintf(debugFP, "silence\n");
\r
5180 /* System sound from Control Panel (deprecated feature).
\r
5181 "$" alone or an unset sound name gets default beep (still in use). */
\r
5182 if (ms->name[1]) {
\r
5183 ok = PlaySound(ms->name + 1, NULL, SND_ALIAS|SND_ASYNC);
\r
5185 if (!ok) ok = MessageBeep(MB_OK);
\r
5188 /* Builtin wave resource, or "!" alone for silence */
\r
5189 if (ms->name[1]) {
\r
5190 if (ms->data == NULL) return FALSE;
\r
5191 ok = PlaySound(ms->data, NULL, SND_MEMORY|SND_ASYNC);
\r
5197 /* .wav file. Error if not found. */
\r
5198 if (ms->data == NULL) return FALSE;
\r
5199 ok = PlaySound(ms->data, NULL, SND_MEMORY|SND_ASYNC);
\r
5202 /* Don't print an error: this can happen innocently if the sound driver
\r
5203 is busy; for instance, if another instance of WinBoard is playing
\r
5204 a sound at about the same time. */
\r
5210 OldOpenFileHook(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
5213 OPENFILENAME *ofn;
\r
5214 static UINT *number; /* gross that this is static */
\r
5216 switch (message) {
\r
5217 case WM_INITDIALOG: /* message: initialize dialog box */
\r
5218 /* Center the dialog over the application window */
\r
5219 ofn = (OPENFILENAME *) lParam;
\r
5220 if (ofn->Flags & OFN_ENABLETEMPLATE) {
\r
5221 number = (UINT *) ofn->lCustData;
\r
5222 SendMessage(GetDlgItem(hDlg, edt2), WM_SETTEXT, 0, (LPARAM) "");
\r
5226 CenterWindow (hDlg, GetWindow (hDlg, GW_OWNER));
\r
5227 return FALSE; /* Allow for further processing */
\r
5230 if ((LOWORD(wParam) == IDOK) && (number != NULL)) {
\r
5231 *number = GetDlgItemInt(hDlg, OPT_IndexNumberOld, &ok, FALSE);
\r
5233 return FALSE; /* Allow for further processing */
\r
5239 OpenFileHook(HWND hdlg, UINT uiMsg, WPARAM wParam, LPARAM lParam)
\r
5241 static UINT *number;
\r
5242 OPENFILENAME *ofname;
\r
5245 case WM_INITDIALOG:
\r
5246 ofname = (OPENFILENAME *)lParam;
\r
5247 number = (UINT *)(ofname->lCustData);
\r
5250 ofnot = (OFNOTIFY *)lParam;
\r
5251 if (ofnot->hdr.code == CDN_FILEOK) {
\r
5252 *number = GetDlgItemInt(hdlg, OPT_IndexNumber, NULL, FALSE);
\r
5261 OpenFileDialog(HWND hwnd, char *write, char *defName, char *defExt, // [HGM] diag: type of 'write' now string
\r
5262 char *nameFilt, char *dlgTitle, UINT *number,
\r
5263 char fileTitle[MSG_SIZ], char fileName[MSG_SIZ])
\r
5265 OPENFILENAME openFileName;
\r
5266 char buf1[MSG_SIZ];
\r
5269 if (fileName == NULL) fileName = buf1;
\r
5270 if (defName == NULL) {
\r
5271 strcpy(fileName, "*.");
\r
5272 strcat(fileName, defExt);
\r
5274 strcpy(fileName, defName);
\r
5276 if (fileTitle) strcpy(fileTitle, "");
\r
5277 if (number) *number = 0;
\r
5279 openFileName.lStructSize = sizeof(OPENFILENAME);
\r
5280 openFileName.hwndOwner = hwnd;
\r
5281 openFileName.hInstance = (HANDLE) hInst;
\r
5282 openFileName.lpstrFilter = nameFilt;
\r
5283 openFileName.lpstrCustomFilter = (LPSTR) NULL;
\r
5284 openFileName.nMaxCustFilter = 0L;
\r
5285 openFileName.nFilterIndex = 1L;
\r
5286 openFileName.lpstrFile = fileName;
\r
5287 openFileName.nMaxFile = MSG_SIZ;
\r
5288 openFileName.lpstrFileTitle = fileTitle;
\r
5289 openFileName.nMaxFileTitle = fileTitle ? MSG_SIZ : 0;
\r
5290 openFileName.lpstrInitialDir = NULL;
\r
5291 openFileName.lpstrTitle = dlgTitle;
\r
5292 openFileName.Flags = OFN_PATHMUSTEXIST | OFN_HIDEREADONLY
\r
5293 | (write[0] != 'r' ? 0 : OFN_FILEMUSTEXIST)
\r
5294 | (number ? OFN_ENABLETEMPLATE | OFN_ENABLEHOOK: 0)
\r
5295 | (oldDialog ? 0 : OFN_EXPLORER);
\r
5296 openFileName.nFileOffset = 0;
\r
5297 openFileName.nFileExtension = 0;
\r
5298 openFileName.lpstrDefExt = defExt;
\r
5299 openFileName.lCustData = (LONG) number;
\r
5300 openFileName.lpfnHook = oldDialog ?
\r
5301 (LPOFNHOOKPROC) OldOpenFileHook : (LPOFNHOOKPROC) OpenFileHook;
\r
5302 openFileName.lpTemplateName = (LPSTR)(oldDialog ? 1536 : DLG_IndexNumber);
\r
5304 if (write[0] != 'r' ? GetSaveFileName(&openFileName) :
\r
5305 GetOpenFileName(&openFileName)) {
\r
5306 /* open the file */
\r
5307 f = fopen(openFileName.lpstrFile, write);
\r
5309 MessageBox(hwnd, "File open failed", NULL,
\r
5310 MB_OK|MB_ICONEXCLAMATION);
\r
5314 int err = CommDlgExtendedError();
\r
5315 if (err != 0) DisplayError("Internal error in file dialog box", err);
\r
5324 MenuPopup(HWND hwnd, POINT pt, HMENU hmenu, UINT def)
\r
5326 HMENU hmenuTrackPopup; /* floating pop-up menu */
\r
5329 * Get the first pop-up menu in the menu template. This is the
\r
5330 * menu that TrackPopupMenu displays.
\r
5332 hmenuTrackPopup = GetSubMenu(hmenu, 0);
\r
5334 SetMenuDefaultItem(hmenuTrackPopup, def, FALSE);
\r
5337 * TrackPopup uses screen coordinates, so convert the
\r
5338 * coordinates of the mouse click to screen coordinates.
\r
5340 ClientToScreen(hwnd, (LPPOINT) &pt);
\r
5342 /* Draw and track the floating pop-up menu. */
\r
5343 TrackPopupMenu(hmenuTrackPopup, TPM_CENTERALIGN | TPM_RIGHTBUTTON,
\r
5344 pt.x, pt.y, 0, hwnd, NULL);
\r
5346 /* Destroy the menu.*/
\r
5347 DestroyMenu(hmenu);
\r
5352 int sizeX, sizeY, newSizeX, newSizeY;
\r
5354 } ResizeEditPlusButtonsClosure;
\r
5357 ResizeEditPlusButtonsCallback(HWND hChild, LPARAM lparam)
\r
5359 ResizeEditPlusButtonsClosure *cl = (ResizeEditPlusButtonsClosure *)lparam;
\r
5363 if (hChild == cl->hText) return TRUE;
\r
5364 GetWindowRect(hChild, &rect); /* gives screen coords */
\r
5365 pt.x = rect.left + (cl->newSizeX - cl->sizeX)/2;
\r
5366 pt.y = rect.top + cl->newSizeY - cl->sizeY;
\r
5367 ScreenToClient(cl->hDlg, &pt);
\r
5368 cl->hdwp = DeferWindowPos(cl->hdwp, hChild, NULL,
\r
5369 pt.x, pt.y, rect.right - rect.left, rect.bottom - rect.top, SWP_NOZORDER);
\r
5373 /* Resize a dialog that has a (rich) edit field filling most of
\r
5374 the top, with a row of buttons below */
\r
5376 ResizeEditPlusButtons(HWND hDlg, HWND hText, int sizeX, int sizeY, int newSizeX, int newSizeY)
\r
5379 int newTextHeight, newTextWidth;
\r
5380 ResizeEditPlusButtonsClosure cl;
\r
5382 /*if (IsIconic(hDlg)) return;*/
\r
5383 if (newSizeX == sizeX && newSizeY == sizeY) return;
\r
5385 cl.hdwp = BeginDeferWindowPos(8);
\r
5387 GetWindowRect(hText, &rectText); /* gives screen coords */
\r
5388 newTextWidth = rectText.right - rectText.left + newSizeX - sizeX;
\r
5389 newTextHeight = rectText.bottom - rectText.top + newSizeY - sizeY;
\r
5390 if (newTextHeight < 0) {
\r
5391 newSizeY += -newTextHeight;
\r
5392 newTextHeight = 0;
\r
5394 cl.hdwp = DeferWindowPos(cl.hdwp, hText, NULL, 0, 0,
\r
5395 newTextWidth, newTextHeight, SWP_NOZORDER|SWP_NOMOVE);
\r
5401 cl.newSizeX = newSizeX;
\r
5402 cl.newSizeY = newSizeY;
\r
5403 EnumChildWindows(hDlg, ResizeEditPlusButtonsCallback, (LPARAM)&cl);
\r
5405 EndDeferWindowPos(cl.hdwp);
\r
5408 BOOL CenterWindowEx(HWND hwndChild, HWND hwndParent, int mode)
\r
5410 RECT rChild, rParent;
\r
5411 int wChild, hChild, wParent, hParent;
\r
5412 int wScreen, hScreen, xNew, yNew;
\r
5415 /* Get the Height and Width of the child window */
\r
5416 GetWindowRect (hwndChild, &rChild);
\r
5417 wChild = rChild.right - rChild.left;
\r
5418 hChild = rChild.bottom - rChild.top;
\r
5420 /* Get the Height and Width of the parent window */
\r
5421 GetWindowRect (hwndParent, &rParent);
\r
5422 wParent = rParent.right - rParent.left;
\r
5423 hParent = rParent.bottom - rParent.top;
\r
5425 /* Get the display limits */
\r
5426 hdc = GetDC (hwndChild);
\r
5427 wScreen = GetDeviceCaps (hdc, HORZRES);
\r
5428 hScreen = GetDeviceCaps (hdc, VERTRES);
\r
5429 ReleaseDC(hwndChild, hdc);
\r
5431 /* Calculate new X position, then adjust for screen */
\r
5432 xNew = rParent.left + ((wParent - wChild) /2);
\r
5435 } else if ((xNew+wChild) > wScreen) {
\r
5436 xNew = wScreen - wChild;
\r
5439 /* Calculate new Y position, then adjust for screen */
\r
5441 yNew = rParent.top + ((hParent - hChild) /2);
\r
5444 yNew = rParent.top + GetSystemMetrics( SM_CYCAPTION ) * 2 / 3;
\r
5449 } else if ((yNew+hChild) > hScreen) {
\r
5450 yNew = hScreen - hChild;
\r
5453 /* Set it, and return */
\r
5454 return SetWindowPos (hwndChild, NULL,
\r
5455 xNew, yNew, 0, 0, SWP_NOSIZE | SWP_NOZORDER);
\r
5458 /* Center one window over another */
\r
5459 BOOL CenterWindow (HWND hwndChild, HWND hwndParent)
\r
5461 return CenterWindowEx( hwndChild, hwndParent, 0 );
\r
5464 /*---------------------------------------------------------------------------*\
\r
5466 * Startup Dialog functions
\r
5468 \*---------------------------------------------------------------------------*/
\r
5470 InitComboStrings(HANDLE hwndCombo, char **cd)
\r
5472 SendMessage(hwndCombo, CB_RESETCONTENT, 0, 0);
\r
5474 while (*cd != NULL) {
\r
5475 SendMessage(hwndCombo, CB_ADDSTRING, 0, (LPARAM) *cd);
\r
5481 InitComboStringsFromOption(HANDLE hwndCombo, char *str)
\r
5483 char buf1[MAX_ARG_LEN];
\r
5486 if (str[0] == '@') {
\r
5487 FILE* f = fopen(str + 1, "r");
\r
5489 DisplayFatalError(str + 1, errno, 2);
\r
5492 len = fread(buf1, 1, sizeof(buf1)-1, f);
\r
5494 buf1[len] = NULLCHAR;
\r
5498 SendMessage(hwndCombo, CB_RESETCONTENT, 0, 0);
\r
5501 char buf[MSG_SIZ];
\r
5502 char *end = strchr(str, '\n');
\r
5503 if (end == NULL) return;
\r
5504 memcpy(buf, str, end - str);
\r
5505 buf[end - str] = NULLCHAR;
\r
5506 SendMessage(hwndCombo, CB_ADDSTRING, 0, (LPARAM) buf);
\r
5512 SetStartupDialogEnables(HWND hDlg)
\r
5514 EnableWindow(GetDlgItem(hDlg, OPT_ChessEngineName),
\r
5515 IsDlgButtonChecked(hDlg, OPT_ChessEngine) ||
\r
5516 (appData.zippyPlay && IsDlgButtonChecked(hDlg, OPT_ChessServer)));
\r
5517 EnableWindow(GetDlgItem(hDlg, OPT_SecondChessEngineName),
\r
5518 IsDlgButtonChecked(hDlg, OPT_ChessEngine));
\r
5519 EnableWindow(GetDlgItem(hDlg, OPT_ChessServerName),
\r
5520 IsDlgButtonChecked(hDlg, OPT_ChessServer));
\r
5521 EnableWindow(GetDlgItem(hDlg, OPT_AdditionalOptions),
\r
5522 IsDlgButtonChecked(hDlg, OPT_AnyAdditional));
\r
5523 EnableWindow(GetDlgItem(hDlg, IDOK),
\r
5524 IsDlgButtonChecked(hDlg, OPT_ChessEngine) ||
\r
5525 IsDlgButtonChecked(hDlg, OPT_ChessServer) ||
\r
5526 IsDlgButtonChecked(hDlg, OPT_View));
\r
5530 QuoteForFilename(char *filename)
\r
5532 int dquote, space;
\r
5533 dquote = strchr(filename, '"') != NULL;
\r
5534 space = strchr(filename, ' ') != NULL;
\r
5535 if (dquote || space) {
\r
5547 InitEngineBox(HWND hDlg, HWND hwndCombo, char* nthcp, char* nthd, char* nthdir, char *nthnames)
\r
5549 char buf[MSG_SIZ];
\r
5552 InitComboStringsFromOption(hwndCombo, nthnames);
\r
5553 q = QuoteForFilename(nthcp);
\r
5554 sprintf(buf, "%s%s%s", q, nthcp, q);
\r
5555 if (*nthdir != NULLCHAR) {
\r
5556 q = QuoteForFilename(nthdir);
\r
5557 sprintf(buf + strlen(buf), " /%s=%s%s%s", nthd, q, nthdir, q);
\r
5559 if (*nthcp == NULLCHAR) {
\r
5560 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) 0, (LPARAM) 0);
\r
5561 } else if (SendMessage(hwndCombo, CB_SELECTSTRING, (WPARAM) -1, (LPARAM) buf) == CB_ERR) {
\r
5562 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) -1, (LPARAM) 0);
\r
5563 SendMessage(hwndCombo, WM_SETTEXT, (WPARAM) 0, (LPARAM) buf);
\r
5568 StartupDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
5570 char buf[MSG_SIZ];
\r
5574 switch (message) {
\r
5575 case WM_INITDIALOG:
\r
5576 /* Center the dialog */
\r
5577 CenterWindow (hDlg, GetDesktopWindow());
\r
5578 /* Initialize the dialog items */
\r
5579 InitEngineBox(hDlg, GetDlgItem(hDlg, OPT_ChessEngineName),
\r
5580 appData.firstChessProgram, "fd", appData.firstDirectory,
\r
5581 firstChessProgramNames);
\r
5582 InitEngineBox(hDlg, GetDlgItem(hDlg, OPT_SecondChessEngineName),
\r
5583 appData.secondChessProgram, "sd", appData.secondDirectory,
\r
5584 secondChessProgramNames);
\r
5585 hwndCombo = GetDlgItem(hDlg, OPT_ChessServerName);
\r
5586 InitComboStringsFromOption(hwndCombo, icsNames);
\r
5587 sprintf(buf, "%s /icsport=%s", appData.icsHost, appData.icsPort);
\r
5588 if (*appData.icsHelper != NULLCHAR) {
\r
5589 char *q = QuoteForFilename(appData.icsHelper);
\r
5590 sprintf(buf + strlen(buf), " /icshelper=%s%s%s", q, appData.icsHelper, q);
\r
5592 if (*appData.icsHost == NULLCHAR) {
\r
5593 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) 0, (LPARAM) 0);
\r
5594 /*SendMessage(hwndCombo, CB_SHOWDROPDOWN, (WPARAM) TRUE, (LPARAM) 0); !!too soon */
\r
5595 } else if (SendMessage(hwndCombo, CB_SELECTSTRING, (WPARAM) -1, (LPARAM) buf) == CB_ERR) {
\r
5596 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) -1, (LPARAM) 0);
\r
5597 SendMessage(hwndCombo, WM_SETTEXT, (WPARAM) 0, (LPARAM) buf);
\r
5600 if (appData.icsActive) {
\r
5601 CheckDlgButton(hDlg, OPT_ChessServer, BST_CHECKED);
\r
5603 else if (appData.noChessProgram) {
\r
5604 CheckDlgButton(hDlg, OPT_View, BST_CHECKED);
\r
5607 CheckDlgButton(hDlg, OPT_ChessEngine, BST_CHECKED);
\r
5610 SetStartupDialogEnables(hDlg);
\r
5614 switch (LOWORD(wParam)) {
\r
5616 if (IsDlgButtonChecked(hDlg, OPT_ChessEngine)) {
\r
5617 strcpy(buf, "/fcp=");
\r
5618 GetDlgItemText(hDlg, OPT_ChessEngineName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
5620 ParseArgs(StringGet, &p);
\r
5621 strcpy(buf, "/scp=");
\r
5622 GetDlgItemText(hDlg, OPT_SecondChessEngineName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
5624 ParseArgs(StringGet, &p);
\r
5625 appData.noChessProgram = FALSE;
\r
5626 appData.icsActive = FALSE;
\r
5627 } else if (IsDlgButtonChecked(hDlg, OPT_ChessServer)) {
\r
5628 strcpy(buf, "/ics /icshost=");
\r
5629 GetDlgItemText(hDlg, OPT_ChessServerName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
5631 ParseArgs(StringGet, &p);
\r
5632 if (appData.zippyPlay) {
\r
5633 strcpy(buf, "/fcp=");
\r
5634 GetDlgItemText(hDlg, OPT_ChessEngineName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
5636 ParseArgs(StringGet, &p);
\r
5638 } else if (IsDlgButtonChecked(hDlg, OPT_View)) {
\r
5639 appData.noChessProgram = TRUE;
\r
5640 appData.icsActive = FALSE;
\r
5642 MessageBox(hDlg, "Choose an option, or cancel to exit",
\r
5643 "Option Error", MB_OK|MB_ICONEXCLAMATION);
\r
5646 if (IsDlgButtonChecked(hDlg, OPT_AnyAdditional)) {
\r
5647 GetDlgItemText(hDlg, OPT_AdditionalOptions, buf, sizeof(buf));
\r
5649 ParseArgs(StringGet, &p);
\r
5651 EndDialog(hDlg, TRUE);
\r
5658 case IDM_HELPCONTENTS:
\r
5659 if (!WinHelp (hDlg, "winboard.hlp", HELP_KEY,(DWORD)(LPSTR)"CONTENTS")) {
\r
5660 MessageBox (GetFocus(),
\r
5661 "Unable to activate help",
\r
5662 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
5667 SetStartupDialogEnables(hDlg);
\r
5675 /*---------------------------------------------------------------------------*\
\r
5677 * About box dialog functions
\r
5679 \*---------------------------------------------------------------------------*/
\r
5681 /* Process messages for "About" dialog box */
\r
5683 About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
5685 switch (message) {
\r
5686 case WM_INITDIALOG: /* message: initialize dialog box */
\r
5687 /* Center the dialog over the application window */
\r
5688 CenterWindow (hDlg, GetWindow (hDlg, GW_OWNER));
\r
5689 SetDlgItemText(hDlg, ABOUTBOX_Version, programVersion);
\r
5693 case WM_COMMAND: /* message: received a command */
\r
5694 if (LOWORD(wParam) == IDOK /* "OK" box selected? */
\r
5695 || LOWORD(wParam) == IDCANCEL) { /* System menu close command? */
\r
5696 EndDialog(hDlg, TRUE); /* Exit the dialog */
\r
5704 /*---------------------------------------------------------------------------*\
\r
5706 * Comment Dialog functions
\r
5708 \*---------------------------------------------------------------------------*/
\r
5711 CommentDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
5713 static HANDLE hwndText = NULL;
\r
5714 int len, newSizeX, newSizeY, flags;
\r
5715 static int sizeX, sizeY;
\r
5720 switch (message) {
\r
5721 case WM_INITDIALOG: /* message: initialize dialog box */
\r
5722 /* Initialize the dialog items */
\r
5723 hwndText = GetDlgItem(hDlg, OPT_CommentText);
\r
5724 SetDlgItemText(hDlg, OPT_CommentText, commentText);
\r
5725 EnableWindow(GetDlgItem(hDlg, OPT_CancelComment), editComment);
\r
5726 EnableWindow(GetDlgItem(hDlg, OPT_ClearComment), editComment);
\r
5727 EnableWindow(GetDlgItem(hDlg, OPT_EditComment), !editComment);
\r
5728 SendMessage(hwndText, EM_SETREADONLY, !editComment, 0);
\r
5729 SetWindowText(hDlg, commentTitle);
\r
5730 if (editComment) {
\r
5731 SetFocus(hwndText);
\r
5733 SetFocus(GetDlgItem(hDlg, IDOK));
\r
5735 SendMessage(GetDlgItem(hDlg, OPT_CommentText),
\r
5736 WM_SETFONT, (WPARAM)font[boardSize][COMMENT_FONT]->hf,
\r
5737 MAKELPARAM(FALSE, 0));
\r
5738 /* Size and position the dialog */
\r
5739 if (!commentDialog) {
\r
5740 commentDialog = hDlg;
\r
5741 flags = SWP_NOZORDER;
\r
5742 GetClientRect(hDlg, &rect);
\r
5743 sizeX = rect.right;
\r
5744 sizeY = rect.bottom;
\r
5745 if (wpComment.x != CW_USEDEFAULT && wpComment.y != CW_USEDEFAULT &&
\r
5746 wpComment.width != CW_USEDEFAULT && wpComment.height != CW_USEDEFAULT) {
\r
5747 WINDOWPLACEMENT wp;
\r
5748 EnsureOnScreen(&wpComment.x, &wpComment.y, 0, 0);
\r
5749 wp.length = sizeof(WINDOWPLACEMENT);
\r
5751 wp.showCmd = SW_SHOW;
\r
5752 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
5753 wp.rcNormalPosition.left = wpComment.x;
\r
5754 wp.rcNormalPosition.right = wpComment.x + wpComment.width;
\r
5755 wp.rcNormalPosition.top = wpComment.y;
\r
5756 wp.rcNormalPosition.bottom = wpComment.y + wpComment.height;
\r
5757 SetWindowPlacement(hDlg, &wp);
\r
5759 GetClientRect(hDlg, &rect);
\r
5760 newSizeX = rect.right;
\r
5761 newSizeY = rect.bottom;
\r
5762 ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY,
\r
5763 newSizeX, newSizeY);
\r
5770 case WM_COMMAND: /* message: received a command */
\r
5771 switch (LOWORD(wParam)) {
\r
5773 if (editComment) {
\r
5775 /* Read changed options from the dialog box */
\r
5776 hwndText = GetDlgItem(hDlg, OPT_CommentText);
\r
5777 len = GetWindowTextLength(hwndText);
\r
5778 str = (char *) malloc(len + 1);
\r
5779 GetWindowText(hwndText, str, len + 1);
\r
5788 ReplaceComment(commentIndex, str);
\r
5795 case OPT_CancelComment:
\r
5799 case OPT_ClearComment:
\r
5800 SetDlgItemText(hDlg, OPT_CommentText, "");
\r
5803 case OPT_EditComment:
\r
5804 EditCommentEvent();
\r
5813 newSizeX = LOWORD(lParam);
\r
5814 newSizeY = HIWORD(lParam);
\r
5815 ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY, newSizeX, newSizeY);
\r
5820 case WM_GETMINMAXINFO:
\r
5821 /* Prevent resizing window too small */
\r
5822 mmi = (MINMAXINFO *) lParam;
\r
5823 mmi->ptMinTrackSize.x = 100;
\r
5824 mmi->ptMinTrackSize.y = 100;
\r
5831 EitherCommentPopUp(int index, char *title, char *str, BOOLEAN edit)
\r
5836 CheckMenuItem(GetMenu(hwndMain), IDM_EditComment, edit ? MF_CHECKED : MF_UNCHECKED);
\r
5838 if (str == NULL) str = "";
\r
5839 p = (char *) malloc(2 * strlen(str) + 2);
\r
5842 if (*str == '\n') *q++ = '\r';
\r
5846 if (commentText != NULL) free(commentText);
\r
5848 commentIndex = index;
\r
5849 commentTitle = title;
\r
5851 editComment = edit;
\r
5853 if (commentDialog) {
\r
5854 SendMessage(commentDialog, WM_INITDIALOG, 0, 0);
\r
5855 if (!commentUp) ShowWindow(commentDialog, SW_SHOW);
\r
5857 lpProc = MakeProcInstance((FARPROC)CommentDialog, hInst);
\r
5858 CreateDialog(hInst, MAKEINTRESOURCE(DLG_EditComment),
\r
5859 hwndMain, (DLGPROC)lpProc);
\r
5860 FreeProcInstance(lpProc);
\r
5866 /*---------------------------------------------------------------------------*\
\r
5868 * Type-in move dialog functions
\r
5870 \*---------------------------------------------------------------------------*/
\r
5873 TypeInMoveDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
5875 char move[MSG_SIZ];
\r
5877 ChessMove moveType;
\r
5878 int fromX, fromY, toX, toY;
\r
5881 switch (message) {
\r
5882 case WM_INITDIALOG:
\r
5883 move[0] = (char) lParam;
\r
5884 move[1] = NULLCHAR;
\r
5885 CenterWindowEx(hDlg, GetWindow(hDlg, GW_OWNER), 1 );
\r
5886 hInput = GetDlgItem(hDlg, OPT_Move);
\r
5887 SetWindowText(hInput, move);
\r
5889 SendMessage(hInput, EM_SETSEL, (WPARAM)9999, (LPARAM)9999);
\r
5893 switch (LOWORD(wParam)) {
\r
5895 GetDlgItemText(hDlg, OPT_Move, move, sizeof(move));
\r
5896 { int n; Board board;
\r
5898 if(gameMode == EditPosition && ParseFEN(board, &n, move) ) {
\r
5899 EditPositionPasteFEN(move);
\r
5900 EndDialog(hDlg, TRUE);
\r
5903 // [HGM] movenum: allow move number to be typed in any mode
\r
5904 if(sscanf(move, "%d", &n) == 1 && n != 0 ) {
\r
5906 EndDialog(hDlg, TRUE);
\r
5910 if (gameMode != EditGame && currentMove != forwardMostMove &&
\r
5911 gameMode != Training) {
\r
5912 DisplayMoveError("Displayed move is not current");
\r
5914 // GetDlgItemText(hDlg, OPT_Move, move, sizeof(move)); // moved upstream
\r
5915 int ok = ParseOneMove(move, gameMode == EditPosition ? blackPlaysFirst : currentMove,
\r
5916 &moveType, &fromX, &fromY, &toX, &toY, &promoChar);
\r
5917 if(!ok && move[0] >= 'a') { move[0] += 'A' - 'a'; ok = 2; } // [HGM] try also capitalized
\r
5918 if (ok==1 || ok && ParseOneMove(move, gameMode == EditPosition ? blackPlaysFirst : currentMove,
\r
5919 &moveType, &fromX, &fromY, &toX, &toY, &promoChar)) {
\r
5920 if (gameMode != Training)
\r
5921 forwardMostMove = currentMove;
\r
5922 UserMoveEvent(fromX, fromY, toX, toY, promoChar);
\r
5924 DisplayMoveError("Could not parse move");
\r
5927 EndDialog(hDlg, TRUE);
\r
5930 EndDialog(hDlg, FALSE);
\r
5941 PopUpMoveDialog(char firstchar)
\r
5945 if ((gameMode == BeginningOfGame && !appData.icsActive) ||
\r
5946 gameMode == MachinePlaysWhite || gameMode == MachinePlaysBlack ||
\r
5947 gameMode == AnalyzeMode || gameMode == EditGame ||
\r
5948 gameMode == EditPosition || gameMode == IcsExamining ||
\r
5949 gameMode == IcsPlayingWhite || gameMode == IcsPlayingBlack ||
\r
5950 isdigit(firstchar) && // [HGM] movenum: allow typing in of move nr in 'passive' modes
\r
5951 ( gameMode == AnalyzeFile || gameMode == PlayFromGameFile ||
\r
5952 gameMode == IcsObserving || gameMode == TwoMachinesPlay ) ||
\r
5953 gameMode == Training) {
\r
5954 lpProc = MakeProcInstance((FARPROC)TypeInMoveDialog, hInst);
\r
5955 DialogBoxParam(hInst, MAKEINTRESOURCE(DLG_TypeInMove),
\r
5956 hwndMain, (DLGPROC)lpProc, (LPARAM)firstchar);
\r
5957 FreeProcInstance(lpProc);
\r
5961 /*---------------------------------------------------------------------------*\
\r
5963 * Type-in name dialog functions
\r
5965 \*---------------------------------------------------------------------------*/
\r
5968 TypeInNameDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
5970 char move[MSG_SIZ];
\r
5973 switch (message) {
\r
5974 case WM_INITDIALOG:
\r
5975 move[0] = (char) lParam;
\r
5976 move[1] = NULLCHAR;
\r
5977 CenterWindowEx(hDlg, GetWindow(hDlg, GW_OWNER), 1 );
\r
5978 hInput = GetDlgItem(hDlg, OPT_Name);
\r
5979 SetWindowText(hInput, move);
\r
5981 SendMessage(hInput, EM_SETSEL, (WPARAM)9999, (LPARAM)9999);
\r
5985 switch (LOWORD(wParam)) {
\r
5987 GetDlgItemText(hDlg, OPT_Name, move, sizeof(move));
\r
5988 appData.userName = strdup(move);
\r
5991 EndDialog(hDlg, TRUE);
\r
5994 EndDialog(hDlg, FALSE);
\r
6005 PopUpNameDialog(char firstchar)
\r
6009 lpProc = MakeProcInstance((FARPROC)TypeInNameDialog, hInst);
\r
6010 DialogBoxParam(hInst, MAKEINTRESOURCE(DLG_TypeInName),
\r
6011 hwndMain, (DLGPROC)lpProc, (LPARAM)firstchar);
\r
6012 FreeProcInstance(lpProc);
\r
6015 /*---------------------------------------------------------------------------*\
\r
6019 \*---------------------------------------------------------------------------*/
\r
6021 /* Nonmodal error box */
\r
6022 LRESULT CALLBACK ErrorDialog(HWND hDlg, UINT message,
\r
6023 WPARAM wParam, LPARAM lParam);
\r
6026 ErrorPopUp(char *title, char *content)
\r
6030 BOOLEAN modal = hwndMain == NULL;
\r
6048 strncpy(errorTitle, title, sizeof(errorTitle));
\r
6049 errorTitle[sizeof(errorTitle) - 1] = '\0';
\r
6052 MessageBox(NULL, errorMessage, errorTitle, MB_OK|MB_ICONEXCLAMATION);
\r
6054 lpProc = MakeProcInstance((FARPROC)ErrorDialog, hInst);
\r
6055 CreateDialog(hInst, MAKEINTRESOURCE(DLG_Error),
\r
6056 hwndMain, (DLGPROC)lpProc);
\r
6057 FreeProcInstance(lpProc);
\r
6064 if (!appData.popupMoveErrors && moveErrorMessageUp) DisplayMessage("", "");
\r
6065 if (errorDialog == NULL) return;
\r
6066 DestroyWindow(errorDialog);
\r
6067 errorDialog = NULL;
\r
6068 if(errorExitStatus) ExitEvent(errorExitStatus);
\r
6072 ErrorDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
6077 switch (message) {
\r
6078 case WM_INITDIALOG:
\r
6079 GetWindowRect(hDlg, &rChild);
\r
6082 SetWindowPos(hDlg, NULL, rChild.left,
\r
6083 rChild.top + boardRect.top - (rChild.bottom - rChild.top),
\r
6084 0, 0, SWP_NOZORDER|SWP_NOSIZE);
\r
6088 [AS] It seems that the above code wants to move the dialog up in the "caption
\r
6089 area" of the main window, but it uses the dialog height as an hard-coded constant,
\r
6090 and it doesn't work when you resize the dialog.
\r
6091 For now, just give it a default position.
\r
6093 SetWindowPos(hDlg, NULL, boardRect.left+8, boardRect.top+8, 0, 0, SWP_NOZORDER|SWP_NOSIZE);
\r
6095 errorDialog = hDlg;
\r
6096 SetWindowText(hDlg, errorTitle);
\r
6097 hwndText = GetDlgItem(hDlg, OPT_ErrorText);
\r
6098 SetDlgItemText(hDlg, OPT_ErrorText, errorMessage);
\r
6102 switch (LOWORD(wParam)) {
\r
6105 if (errorDialog == hDlg) errorDialog = NULL;
\r
6106 DestroyWindow(hDlg);
\r
6118 HWND gothicDialog = NULL;
\r
6121 GothicDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
6125 int height = GetSystemMetrics(SM_CYCAPTION)+GetSystemMetrics(SM_CYFRAME);
\r
6127 switch (message) {
\r
6128 case WM_INITDIALOG:
\r
6129 GetWindowRect(hDlg, &rChild);
\r
6131 SetWindowPos(hDlg, NULL, wpMain.x, wpMain.y-height, wpMain.width, height,
\r
6135 [AS] It seems that the above code wants to move the dialog up in the "caption
\r
6136 area" of the main window, but it uses the dialog height as an hard-coded constant,
\r
6137 and it doesn't work when you resize the dialog.
\r
6138 For now, just give it a default position.
\r
6140 gothicDialog = hDlg;
\r
6141 SetWindowText(hDlg, errorTitle);
\r
6142 hwndText = GetDlgItem(hDlg, OPT_ErrorText);
\r
6143 SetDlgItemText(hDlg, OPT_ErrorText, errorMessage);
\r
6147 switch (LOWORD(wParam)) {
\r
6150 if (errorDialog == hDlg) errorDialog = NULL;
\r
6151 DestroyWindow(hDlg);
\r
6163 GothicPopUp(char *title, VariantClass variant)
\r
6166 static char *lastTitle;
\r
6168 strncpy(errorTitle, title, sizeof(errorTitle));
\r
6169 errorTitle[sizeof(errorTitle) - 1] = '\0';
\r
6171 if(lastTitle != title && gothicDialog != NULL) {
\r
6172 DestroyWindow(gothicDialog);
\r
6173 gothicDialog = NULL;
\r
6175 if(variant != VariantNormal && gothicDialog == NULL) {
\r
6176 title = lastTitle;
\r
6177 lpProc = MakeProcInstance((FARPROC)GothicDialog, hInst);
\r
6178 CreateDialog(hInst, MAKEINTRESOURCE(DLG_Error),
\r
6179 hwndMain, (DLGPROC)lpProc);
\r
6180 FreeProcInstance(lpProc);
\r
6185 /*---------------------------------------------------------------------------*\
\r
6187 * Ics Interaction console functions
\r
6189 \*---------------------------------------------------------------------------*/
\r
6191 #define HISTORY_SIZE 64
\r
6192 static char *history[HISTORY_SIZE];
\r
6193 int histIn = 0, histP = 0;
\r
6196 SaveInHistory(char *cmd)
\r
6198 if (history[histIn] != NULL) {
\r
6199 free(history[histIn]);
\r
6200 history[histIn] = NULL;
\r
6202 if (*cmd == NULLCHAR) return;
\r
6203 history[histIn] = StrSave(cmd);
\r
6204 histIn = (histIn + 1) % HISTORY_SIZE;
\r
6205 if (history[histIn] != NULL) {
\r
6206 free(history[histIn]);
\r
6207 history[histIn] = NULL;
\r
6213 PrevInHistory(char *cmd)
\r
6216 if (histP == histIn) {
\r
6217 if (history[histIn] != NULL) free(history[histIn]);
\r
6218 history[histIn] = StrSave(cmd);
\r
6220 newhp = (histP - 1 + HISTORY_SIZE) % HISTORY_SIZE;
\r
6221 if (newhp == histIn || history[newhp] == NULL) return NULL;
\r
6223 return history[histP];
\r
6229 if (histP == histIn) return NULL;
\r
6230 histP = (histP + 1) % HISTORY_SIZE;
\r
6231 return history[histP];
\r
6235 LoadIcsTextMenu(IcsTextMenuEntry *e)
\r
6239 hmenu = LoadMenu(hInst, "TextMenu");
\r
6240 h = GetSubMenu(hmenu, 0);
\r
6242 if (strcmp(e->item, "-") == 0) {
\r
6243 AppendMenu(h, MF_SEPARATOR, 0, 0);
\r
6245 if (e->item[0] == '|') {
\r
6246 AppendMenu(h, MF_STRING|MF_MENUBARBREAK,
\r
6247 IDM_CommandX + i, &e->item[1]);
\r
6249 AppendMenu(h, MF_STRING, IDM_CommandX + i, e->item);
\r
6258 WNDPROC consoleTextWindowProc;
\r
6261 CommandX(HWND hwnd, char *command, BOOLEAN getname, BOOLEAN immediate)
\r
6263 char buf[MSG_SIZ], name[MSG_SIZ];
\r
6264 HWND hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
6268 SetWindowText(hInput, command);
\r
6270 SendMessage(hInput, WM_CHAR, '\r', 0);
\r
6272 sel.cpMin = 999999;
\r
6273 sel.cpMax = 999999;
\r
6274 SendMessage(hInput, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
6279 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
6280 if (sel.cpMin == sel.cpMax) {
\r
6281 /* Expand to surrounding word */
\r
6284 tr.chrg.cpMax = sel.cpMin;
\r
6285 tr.chrg.cpMin = --sel.cpMin;
\r
6286 if (sel.cpMin < 0) break;
\r
6287 tr.lpstrText = name;
\r
6288 SendMessage(hwnd, EM_GETTEXTRANGE, 0, (LPARAM) &tr);
\r
6289 } while (isalpha(name[0]) || isdigit(name[0]) || name[0] == '-');
\r
6293 tr.chrg.cpMin = sel.cpMax;
\r
6294 tr.chrg.cpMax = ++sel.cpMax;
\r
6295 tr.lpstrText = name;
\r
6296 if (SendMessage(hwnd, EM_GETTEXTRANGE, 0, (LPARAM) &tr) < 1) break;
\r
6297 } while (isalpha(name[0]) || isdigit(name[0]) || name[0] == '-');
\r
6300 if (sel.cpMax == sel.cpMin || sel.cpMax - sel.cpMin > MSG_SIZ/2) {
\r
6301 MessageBeep(MB_ICONEXCLAMATION);
\r
6305 tr.lpstrText = name;
\r
6306 SendMessage(hwnd, EM_GETTEXTRANGE, 0, (LPARAM) &tr);
\r
6308 if (sel.cpMax - sel.cpMin > MSG_SIZ/2) {
\r
6309 MessageBeep(MB_ICONEXCLAMATION);
\r
6312 SendMessage(hwnd, EM_GETSELTEXT, 0, (LPARAM) name);
\r
6315 sprintf(buf, "%s %s", command, name);
\r
6316 SetWindowText(hInput, buf);
\r
6317 SendMessage(hInput, WM_CHAR, '\r', 0);
\r
6319 sprintf(buf, "%s %s ", command, name); /* trailing space */
\r
6320 SetWindowText(hInput, buf);
\r
6321 sel.cpMin = 999999;
\r
6322 sel.cpMax = 999999;
\r
6323 SendMessage(hInput, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
6329 ConsoleTextSubclass(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
6334 switch (message) {
\r
6336 if (!(GetKeyState(VK_CONTROL) & ~1)) break;
\r
6339 SendMessage(hwnd, EM_LINESCROLL, 0, -999999);
\r
6342 sel.cpMin = 999999;
\r
6343 sel.cpMax = 999999;
\r
6344 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
6345 SendMessage(hwnd, EM_SCROLLCARET, 0, 0);
\r
6350 if(wParam != '\022') {
\r
6351 if (wParam == '\t') {
\r
6352 if (GetKeyState(VK_SHIFT) < 0) {
\r
6354 if (IsIconic(hwndMain)) ShowWindow(hwndMain, SW_RESTORE);
\r
6355 if (buttonDesc[0].hwnd) {
\r
6356 SetFocus(buttonDesc[0].hwnd);
\r
6358 SetFocus(hwndMain);
\r
6362 SetFocus(GetDlgItem(hwndConsole, OPT_ConsoleInput));
\r
6365 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
6366 JAWS_DELETE( SetFocus(hInput); )
\r
6367 SendMessage(hInput, message, wParam, lParam);
\r
6370 } // [HGM] navigate: for Ctrl+R, flow into nex case (moved up here) to summon up menu
\r
6371 case WM_RBUTTONUP:
\r
6372 if (GetKeyState(VK_SHIFT) & ~1) {
\r
6373 SendDlgItemMessage(hwndConsole, OPT_ConsoleText,
\r
6374 WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
6377 HMENU hmenu = LoadIcsTextMenu(icsTextMenuEntry);
\r
6378 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
6379 if (sel.cpMin == sel.cpMax) {
\r
6380 EnableMenuItem(hmenu, IDM_Copy, MF_BYCOMMAND|MF_GRAYED);
\r
6381 EnableMenuItem(hmenu, IDM_QuickPaste, MF_BYCOMMAND|MF_GRAYED);
\r
6383 if (!IsClipboardFormatAvailable(CF_TEXT)) {
\r
6384 EnableMenuItem(hmenu, IDM_Paste, MF_BYCOMMAND|MF_GRAYED);
\r
6386 pt.x = LOWORD(lParam);
\r
6387 pt.y = HIWORD(lParam);
\r
6388 MenuPopup(hwnd, pt, hmenu, -1);
\r
6392 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
6394 return SendMessage(hInput, message, wParam, lParam);
\r
6395 case WM_MBUTTONDOWN:
\r
6396 return SendMessage(hwnd, WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
6397 case WM_RBUTTONDOWN:
\r
6398 if (!(GetKeyState(VK_SHIFT) & ~1)) {
\r
6399 /* Move selection here if it was empty */
\r
6401 pt.x = LOWORD(lParam);
\r
6402 pt.y = HIWORD(lParam);
\r
6403 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
6404 if (sel.cpMin == sel.cpMax) {
\r
6405 sel.cpMin = SendMessage(hwnd, EM_CHARFROMPOS, 0, (LPARAM)&pt); /*doc is wrong*/
\r
6406 sel.cpMax = sel.cpMin;
\r
6407 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
6409 SendMessage(hwnd, EM_HIDESELECTION, FALSE, FALSE);
\r
6413 switch (LOWORD(wParam)) {
\r
6414 case IDM_QuickPaste:
\r
6416 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
6417 if (sel.cpMin == sel.cpMax) {
\r
6418 MessageBeep(MB_ICONEXCLAMATION);
\r
6421 SendMessage(hwnd, WM_COPY, 0, 0);
\r
6422 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
6423 SendMessage(hInput, WM_PASTE, 0, 0);
\r
6428 SendMessage(hwnd, WM_CUT, 0, 0);
\r
6431 SendMessage(hwnd, WM_PASTE, 0, 0);
\r
6434 SendMessage(hwnd, WM_COPY, 0, 0);
\r
6438 int i = LOWORD(wParam) - IDM_CommandX;
\r
6439 if (i >= 0 && i < ICS_TEXT_MENU_SIZE &&
\r
6440 icsTextMenuEntry[i].command != NULL) {
\r
6441 CommandX(hwnd, icsTextMenuEntry[i].command,
\r
6442 icsTextMenuEntry[i].getname,
\r
6443 icsTextMenuEntry[i].immediate);
\r
6451 return (*consoleTextWindowProc)(hwnd, message, wParam, lParam);
\r
6454 WNDPROC consoleInputWindowProc;
\r
6457 ConsoleInputSubclass(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
6459 char buf[MSG_SIZ];
\r
6461 static BOOL sendNextChar = FALSE;
\r
6462 static BOOL quoteNextChar = FALSE;
\r
6463 InputSource *is = consoleInputSource;
\r
6467 switch (message) {
\r
6469 if (!appData.localLineEditing || sendNextChar) {
\r
6470 is->buf[0] = (CHAR) wParam;
\r
6472 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
6473 sendNextChar = FALSE;
\r
6476 if (quoteNextChar) {
\r
6477 buf[0] = (char) wParam;
\r
6478 buf[1] = NULLCHAR;
\r
6479 SendMessage(hwnd, EM_REPLACESEL, TRUE, (LPARAM) buf);
\r
6480 quoteNextChar = FALSE;
\r
6484 case '\r': /* Enter key */
\r
6485 is->count = GetWindowText(hwnd, is->buf, INPUT_SOURCE_BUF_SIZE-1);
\r
6486 if (consoleEcho) SaveInHistory(is->buf);
\r
6487 is->buf[is->count++] = '\n';
\r
6488 is->buf[is->count] = NULLCHAR;
\r
6489 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
6490 if (consoleEcho) {
\r
6491 ConsoleOutput(is->buf, is->count, TRUE);
\r
6492 } else if (appData.localLineEditing) {
\r
6493 ConsoleOutput("\n", 1, TRUE);
\r
6496 case '\033': /* Escape key */
\r
6497 SetWindowText(hwnd, "");
\r
6498 cf.cbSize = sizeof(CHARFORMAT);
\r
6499 cf.dwMask = CFM_COLOR|CFM_BOLD|CFM_ITALIC|CFM_UNDERLINE|CFM_STRIKEOUT;
\r
6500 if (consoleEcho) {
\r
6501 cf.crTextColor = textAttribs[ColorNormal].color;
\r
6503 cf.crTextColor = COLOR_ECHOOFF;
\r
6505 cf.dwEffects = textAttribs[ColorNormal].effects;
\r
6506 SendMessage(hwnd, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&cf);
\r
6508 case '\t': /* Tab key */
\r
6509 if (GetKeyState(VK_SHIFT) < 0) {
\r
6511 SetFocus(GetDlgItem(hwndConsole, OPT_ConsoleText));
\r
6514 if (IsIconic(hwndMain)) ShowWindow(hwndMain, SW_RESTORE);
\r
6515 if (buttonDesc[0].hwnd) {
\r
6516 SetFocus(buttonDesc[0].hwnd);
\r
6518 SetFocus(hwndMain);
\r
6522 case '\023': /* Ctrl+S */
\r
6523 sendNextChar = TRUE;
\r
6525 case '\021': /* Ctrl+Q */
\r
6526 quoteNextChar = TRUE;
\r
6536 GetWindowText(hwnd, buf, MSG_SIZ);
\r
6537 p = PrevInHistory(buf);
\r
6539 SetWindowText(hwnd, p);
\r
6540 sel.cpMin = 999999;
\r
6541 sel.cpMax = 999999;
\r
6542 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
6547 p = NextInHistory();
\r
6549 SetWindowText(hwnd, p);
\r
6550 sel.cpMin = 999999;
\r
6551 sel.cpMax = 999999;
\r
6552 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
6558 if (!(GetKeyState(VK_CONTROL) & ~1)) break;
\r
6562 SendDlgItemMessage(hwndConsole, OPT_ConsoleText, message, wParam, lParam);
\r
6566 case WM_MBUTTONDOWN:
\r
6567 SendDlgItemMessage(hwndConsole, OPT_ConsoleText,
\r
6568 WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
6570 case WM_RBUTTONUP:
\r
6571 if (GetKeyState(VK_SHIFT) & ~1) {
\r
6572 SendDlgItemMessage(hwndConsole, OPT_ConsoleText,
\r
6573 WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
6577 hmenu = LoadMenu(hInst, "InputMenu");
\r
6578 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
6579 if (sel.cpMin == sel.cpMax) {
\r
6580 EnableMenuItem(hmenu, IDM_Copy, MF_BYCOMMAND|MF_GRAYED);
\r
6581 EnableMenuItem(hmenu, IDM_Cut, MF_BYCOMMAND|MF_GRAYED);
\r
6583 if (!IsClipboardFormatAvailable(CF_TEXT)) {
\r
6584 EnableMenuItem(hmenu, IDM_Paste, MF_BYCOMMAND|MF_GRAYED);
\r
6586 pt.x = LOWORD(lParam);
\r
6587 pt.y = HIWORD(lParam);
\r
6588 MenuPopup(hwnd, pt, hmenu, -1);
\r
6592 switch (LOWORD(wParam)) {
\r
6594 SendMessage(hwnd, EM_UNDO, 0, 0);
\r
6596 case IDM_SelectAll:
\r
6598 sel.cpMax = -1; /*999999?*/
\r
6599 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
6602 SendMessage(hwnd, WM_CUT, 0, 0);
\r
6605 SendMessage(hwnd, WM_PASTE, 0, 0);
\r
6608 SendMessage(hwnd, WM_COPY, 0, 0);
\r
6613 return (*consoleInputWindowProc)(hwnd, message, wParam, lParam);
\r
6616 #define CO_MAX 100000
\r
6617 #define CO_TRIM 1000
\r
6620 ConsoleWndProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
6622 static SnapData sd;
\r
6623 HWND hText, hInput;
\r
6625 static int sizeX, sizeY;
\r
6626 int newSizeX, newSizeY;
\r
6630 hText = GetDlgItem(hDlg, OPT_ConsoleText);
\r
6631 hInput = GetDlgItem(hDlg, OPT_ConsoleInput);
\r
6633 switch (message) {
\r
6635 if (((NMHDR*)lParam)->code == EN_LINK)
\r
6637 ENLINK *pLink = (ENLINK*)lParam;
\r
6638 if (pLink->msg == WM_LBUTTONUP)
\r
6642 tr.chrg = pLink->chrg;
\r
6643 tr.lpstrText = malloc(1+tr.chrg.cpMax-tr.chrg.cpMin);
\r
6644 SendMessage(hText, EM_GETTEXTRANGE, 0, (LPARAM)&tr);
\r
6645 ShellExecute(NULL, "open", tr.lpstrText, NULL, NULL, SW_SHOW);
\r
6646 free(tr.lpstrText);
\r
6650 case WM_INITDIALOG: /* message: initialize dialog box */
\r
6651 hwndConsole = hDlg;
\r
6653 consoleTextWindowProc = (WNDPROC)
\r
6654 SetWindowLong(hText, GWL_WNDPROC, (LONG) ConsoleTextSubclass);
\r
6655 SendMessage(hText, EM_SETBKGNDCOLOR, FALSE, consoleBackgroundColor);
\r
6656 consoleInputWindowProc = (WNDPROC)
\r
6657 SetWindowLong(hInput, GWL_WNDPROC, (LONG) ConsoleInputSubclass);
\r
6658 SendMessage(hInput, EM_SETBKGNDCOLOR, FALSE, consoleBackgroundColor);
\r
6659 Colorize(ColorNormal, TRUE);
\r
6660 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM) &consoleCF);
\r
6661 ChangedConsoleFont();
\r
6662 GetClientRect(hDlg, &rect);
\r
6663 sizeX = rect.right;
\r
6664 sizeY = rect.bottom;
\r
6665 if (wpConsole.x != CW_USEDEFAULT && wpConsole.y != CW_USEDEFAULT &&
\r
6666 wpConsole.width != CW_USEDEFAULT && wpConsole.height != CW_USEDEFAULT) {
\r
6667 WINDOWPLACEMENT wp;
\r
6668 EnsureOnScreen(&wpConsole.x, &wpConsole.y, 0, 0);
\r
6669 wp.length = sizeof(WINDOWPLACEMENT);
\r
6671 wp.showCmd = SW_SHOW;
\r
6672 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
6673 wp.rcNormalPosition.left = wpConsole.x;
\r
6674 wp.rcNormalPosition.right = wpConsole.x + wpConsole.width;
\r
6675 wp.rcNormalPosition.top = wpConsole.y;
\r
6676 wp.rcNormalPosition.bottom = wpConsole.y + wpConsole.height;
\r
6677 SetWindowPlacement(hDlg, &wp);
\r
6680 // [HGM] Chessknight's change 2004-07-13
\r
6681 else { /* Determine Defaults */
\r
6682 WINDOWPLACEMENT wp;
\r
6683 wpConsole.x = wpMain.width + 1;
\r
6684 wpConsole.y = wpMain.y;
\r
6685 wpConsole.width = screenWidth - wpMain.width;
\r
6686 wpConsole.height = wpMain.height;
\r
6687 EnsureOnScreen(&wpConsole.x, &wpConsole.y, 0, 0);
\r
6688 wp.length = sizeof(WINDOWPLACEMENT);
\r
6690 wp.showCmd = SW_SHOW;
\r
6691 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
6692 wp.rcNormalPosition.left = wpConsole.x;
\r
6693 wp.rcNormalPosition.right = wpConsole.x + wpConsole.width;
\r
6694 wp.rcNormalPosition.top = wpConsole.y;
\r
6695 wp.rcNormalPosition.bottom = wpConsole.y + wpConsole.height;
\r
6696 SetWindowPlacement(hDlg, &wp);
\r
6699 // Allow hText to highlight URLs and send notifications on them
\r
6700 wMask = (WORD) SendMessage(hText, EM_GETEVENTMASK, 0, 0L);
\r
6701 SendMessage(hText, EM_SETEVENTMASK, 0, wMask | ENM_LINK);
\r
6702 SendMessage(hText, EM_AUTOURLDETECT, TRUE, 0L);
\r
6703 SetWindowLong(hText, GWL_USERDATA, 79); // initialize the text window's width
\r
6717 if (IsIconic(hDlg)) break;
\r
6718 newSizeX = LOWORD(lParam);
\r
6719 newSizeY = HIWORD(lParam);
\r
6720 if (sizeX != newSizeX || sizeY != newSizeY) {
\r
6721 RECT rectText, rectInput;
\r
6723 int newTextHeight, newTextWidth;
\r
6724 GetWindowRect(hText, &rectText);
\r
6725 newTextWidth = rectText.right - rectText.left + newSizeX - sizeX;
\r
6726 newTextHeight = rectText.bottom - rectText.top + newSizeY - sizeY;
\r
6727 if (newTextHeight < 0) {
\r
6728 newSizeY += -newTextHeight;
\r
6729 newTextHeight = 0;
\r
6731 SetWindowPos(hText, NULL, 0, 0,
\r
6732 newTextWidth, newTextHeight, SWP_NOZORDER|SWP_NOMOVE);
\r
6733 GetWindowRect(hInput, &rectInput); /* gives screen coords */
\r
6734 pt.x = rectInput.left;
\r
6735 pt.y = rectInput.top + newSizeY - sizeY;
\r
6736 ScreenToClient(hDlg, &pt);
\r
6737 SetWindowPos(hInput, NULL,
\r
6738 pt.x, pt.y, /* needs client coords */
\r
6739 rectInput.right - rectInput.left + newSizeX - sizeX,
\r
6740 rectInput.bottom - rectInput.top, SWP_NOZORDER);
\r
6746 case WM_GETMINMAXINFO:
\r
6747 /* Prevent resizing window too small */
\r
6748 mmi = (MINMAXINFO *) lParam;
\r
6749 mmi->ptMinTrackSize.x = 100;
\r
6750 mmi->ptMinTrackSize.y = 100;
\r
6753 /* [AS] Snapping */
\r
6754 case WM_ENTERSIZEMOVE:
\r
6755 return OnEnterSizeMove( &sd, hDlg, wParam, lParam );
\r
6758 return OnSizing( &sd, hDlg, wParam, lParam );
\r
6761 return OnMoving( &sd, hDlg, wParam, lParam );
\r
6763 case WM_EXITSIZEMOVE:
\r
6764 UpdateICSWidth(hText);
\r
6765 return OnExitSizeMove( &sd, hDlg, wParam, lParam );
\r
6768 return DefWindowProc(hDlg, message, wParam, lParam);
\r
6776 if (hwndConsole) return;
\r
6777 hCons = CreateDialog(hInst, szConsoleName, 0, NULL);
\r
6778 SendMessage(hCons, WM_INITDIALOG, 0, 0);
\r
6783 ConsoleOutput(char* data, int length, int forceVisible)
\r
6788 char buf[CO_MAX+1];
\r
6791 static int delayLF = 0;
\r
6792 CHARRANGE savesel, sel;
\r
6794 if (hwndConsole == NULL || length > CO_MAX-100 || length == 0) return;
\r
6802 while (length--) {
\r
6810 } else if (*p == '\007') {
\r
6811 MyPlaySound(&sounds[(int)SoundBell]);
\r
6818 hText = GetDlgItem(hwndConsole, OPT_ConsoleText);
\r
6819 SendMessage(hText, EM_HIDESELECTION, TRUE, FALSE);
\r
6820 /* Save current selection */
\r
6821 SendMessage(hText, EM_EXGETSEL, 0, (LPARAM)&savesel);
\r
6822 exlen = GetWindowTextLength(hText);
\r
6823 /* Find out whether current end of text is visible */
\r
6824 SendMessage(hText, EM_GETRECT, 0, (LPARAM) &rect);
\r
6825 SendMessage(hText, EM_POSFROMCHAR, (WPARAM) &pEnd, exlen);
\r
6826 /* Trim existing text if it's too long */
\r
6827 if (exlen + (q - buf) > CO_MAX) {
\r
6828 trim = (CO_TRIM > (q - buf)) ? CO_TRIM : (q - buf);
\r
6831 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
6832 SendMessage(hText, EM_REPLACESEL, 0, (LPARAM)"");
\r
6834 savesel.cpMin -= trim;
\r
6835 savesel.cpMax -= trim;
\r
6836 if (exlen < 0) exlen = 0;
\r
6837 if (savesel.cpMin < 0) savesel.cpMin = 0;
\r
6838 if (savesel.cpMax < savesel.cpMin) savesel.cpMax = savesel.cpMin;
\r
6840 /* Append the new text */
\r
6841 sel.cpMin = exlen;
\r
6842 sel.cpMax = exlen;
\r
6843 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
6844 SendMessage(hText, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&consoleCF);
\r
6845 SendMessage(hText, EM_REPLACESEL, 0, (LPARAM) buf);
\r
6846 if (forceVisible || exlen == 0 ||
\r
6847 (rect.left <= pEnd.x && pEnd.x < rect.right &&
\r
6848 rect.top <= pEnd.y && pEnd.y < rect.bottom)) {
\r
6849 /* Scroll to make new end of text visible if old end of text
\r
6850 was visible or new text is an echo of user typein */
\r
6851 sel.cpMin = 9999999;
\r
6852 sel.cpMax = 9999999;
\r
6853 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
6854 SendMessage(hText, EM_HIDESELECTION, FALSE, FALSE);
\r
6855 SendMessage(hText, EM_SCROLLCARET, 0, 0);
\r
6856 SendMessage(hText, EM_HIDESELECTION, TRUE, FALSE);
\r
6858 if (savesel.cpMax == exlen || forceVisible) {
\r
6859 /* Move insert point to new end of text if it was at the old
\r
6860 end of text or if the new text is an echo of user typein */
\r
6861 sel.cpMin = 9999999;
\r
6862 sel.cpMax = 9999999;
\r
6863 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
6865 /* Restore previous selection */
\r
6866 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&savesel);
\r
6868 SendMessage(hText, EM_HIDESELECTION, FALSE, FALSE);
\r
6875 DisplayHoldingsCount(HDC hdc, int x, int y, int rightAlign, int copyNumber)
\r
6879 COLORREF oldFg, oldBg;
\r
6883 if(copyNumber > 1) sprintf(buf, "%d", copyNumber); else buf[0] = 0;
\r
6885 oldFg = SetTextColor(hdc, RGB(255, 255, 255)); /* white */
\r
6886 oldBg = SetBkColor(hdc, RGB(0, 0, 0)); /* black */
\r
6887 oldFont = SelectObject(hdc, font[boardSize][CLOCK_FONT]->hf);
\r
6890 rect.right = x + squareSize;
\r
6892 rect.bottom = y + squareSize;
\r
6895 ExtTextOut(hdc, x + MESSAGE_LINE_LEFTMARGIN
\r
6896 + (rightAlign ? (squareSize*2)/3 : 0),
\r
6897 y, ETO_CLIPPED|ETO_OPAQUE,
\r
6898 &rect, str, strlen(str), NULL);
\r
6900 (void) SetTextColor(hdc, oldFg);
\r
6901 (void) SetBkColor(hdc, oldBg);
\r
6902 (void) SelectObject(hdc, oldFont);
\r
6906 DisplayAClock(HDC hdc, int timeRemaining, int highlight,
\r
6907 RECT *rect, char *color, char *flagFell)
\r
6911 COLORREF oldFg, oldBg;
\r
6914 if (appData.clockMode) {
\r
6916 sprintf(buf, "%c %s %s", color[0], TimeString(timeRemaining), flagFell);
\r
6918 sprintf(buf, "%s:%c%s %s", color, (logoHeight>0 ? 0 : ' '), TimeString(timeRemaining), flagFell);
\r
6925 oldFg = SetTextColor(hdc, RGB(255, 255, 255)); /* white */
\r
6926 oldBg = SetBkColor(hdc, RGB(0, 0, 0)); /* black */
\r
6928 oldFg = SetTextColor(hdc, RGB(0, 0, 0)); /* black */
\r
6929 oldBg = SetBkColor(hdc, RGB(255, 255, 255)); /* white */
\r
6931 oldFont = SelectObject(hdc, font[boardSize][CLOCK_FONT]->hf);
\r
6935 ExtTextOut(hdc, rect->left + MESSAGE_LINE_LEFTMARGIN,
\r
6936 rect->top, ETO_CLIPPED|ETO_OPAQUE,
\r
6937 rect, str, strlen(str), NULL);
\r
6938 if(logoHeight > 0 && appData.clockMode) {
\r
6940 sprintf(buf, "%s %s", buf+7, flagFell);
\r
6941 r.top = rect->top + logoHeight/2;
\r
6942 r.left = rect->left;
\r
6943 r.right = rect->right;
\r
6944 r.bottom = rect->bottom;
\r
6945 ExtTextOut(hdc, rect->left + MESSAGE_LINE_LEFTMARGIN,
\r
6946 r.top, ETO_CLIPPED|ETO_OPAQUE,
\r
6947 &r, str, strlen(str), NULL);
\r
6949 (void) SetTextColor(hdc, oldFg);
\r
6950 (void) SetBkColor(hdc, oldBg);
\r
6951 (void) SelectObject(hdc, oldFont);
\r
6956 DoReadFile(HANDLE hFile, char *buf, int count, DWORD *outCount,
\r
6962 if( count <= 0 ) {
\r
6963 if (appData.debugMode) {
\r
6964 fprintf( debugFP, "DoReadFile: trying to read past end of buffer, overflow = %d\n", count );
\r
6967 return ERROR_INVALID_USER_BUFFER;
\r
6970 ResetEvent(ovl->hEvent);
\r
6971 ovl->Offset = ovl->OffsetHigh = 0;
\r
6972 ok = ReadFile(hFile, buf, count, outCount, ovl);
\r
6976 err = GetLastError();
\r
6977 if (err == ERROR_IO_PENDING) {
\r
6978 ok = GetOverlappedResult(hFile, ovl, outCount, TRUE);
\r
6982 err = GetLastError();
\r
6989 DoWriteFile(HANDLE hFile, char *buf, int count, DWORD *outCount,
\r
6994 ResetEvent(ovl->hEvent);
\r
6995 ovl->Offset = ovl->OffsetHigh = 0;
\r
6996 ok = WriteFile(hFile, buf, count, outCount, ovl);
\r
7000 err = GetLastError();
\r
7001 if (err == ERROR_IO_PENDING) {
\r
7002 ok = GetOverlappedResult(hFile, ovl, outCount, TRUE);
\r
7006 err = GetLastError();
\r
7012 /* [AS] If input is line by line and a line exceed the buffer size, force an error */
\r
7013 void CheckForInputBufferFull( InputSource * is )
\r
7015 if( is->lineByLine && (is->next - is->buf) >= INPUT_SOURCE_BUF_SIZE ) {
\r
7016 /* Look for end of line */
\r
7017 char * p = is->buf;
\r
7019 while( p < is->next && *p != '\n' ) {
\r
7023 if( p >= is->next ) {
\r
7024 if (appData.debugMode) {
\r
7025 fprintf( debugFP, "Input line exceeded buffer size (source id=%lu)\n", is->id );
\r
7028 is->error = ERROR_BROKEN_PIPE; /* [AS] Just any non-successful code! */
\r
7029 is->count = (DWORD) -1;
\r
7030 is->next = is->buf;
\r
7036 InputThread(LPVOID arg)
\r
7041 is = (InputSource *) arg;
\r
7042 ovl.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
\r
7043 ovl.Internal = ovl.InternalHigh = ovl.Offset = ovl.OffsetHigh = 0;
\r
7044 while (is->hThread != NULL) {
\r
7045 is->error = DoReadFile(is->hFile, is->next,
\r
7046 INPUT_SOURCE_BUF_SIZE - (is->next - is->buf),
\r
7047 &is->count, &ovl);
\r
7048 if (is->error == NO_ERROR) {
\r
7049 is->next += is->count;
\r
7051 if (is->error == ERROR_BROKEN_PIPE) {
\r
7052 /* Correct for MS brain damage. EOF reading a pipe is not an error. */
\r
7055 is->count = (DWORD) -1;
\r
7056 /* [AS] The (is->count <= 0) check below is not useful for unsigned values! */
\r
7061 CheckForInputBufferFull( is );
\r
7063 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
7065 if( is->count == ((DWORD) -1) ) break; /* [AS] */
\r
7067 if (is->count <= 0) break; /* Quit on EOF or error */
\r
7070 CloseHandle(ovl.hEvent);
\r
7071 CloseHandle(is->hFile);
\r
7073 if (appData.debugMode) {
\r
7074 fprintf( debugFP, "Input thread terminated (id=%lu, error=%d, count=%ld)\n", is->id, is->error, is->count );
\r
7081 /* Windows 95 beta 2 won't let you do overlapped i/o on a console or pipe */
\r
7083 NonOvlInputThread(LPVOID arg)
\r
7090 is = (InputSource *) arg;
\r
7091 while (is->hThread != NULL) {
\r
7092 is->error = ReadFile(is->hFile, is->next,
\r
7093 INPUT_SOURCE_BUF_SIZE - (is->next - is->buf),
\r
7094 &is->count, NULL) ? NO_ERROR : GetLastError();
\r
7095 if (is->error == NO_ERROR) {
\r
7096 /* Change CRLF to LF */
\r
7097 if (is->next > is->buf) {
\r
7099 i = is->count + 1;
\r
7107 if (prev == '\r' && *p == '\n') {
\r
7119 if (is->error == ERROR_BROKEN_PIPE) {
\r
7120 /* Correct for MS brain damage. EOF reading a pipe is not an error. */
\r
7123 is->count = (DWORD) -1;
\r
7127 CheckForInputBufferFull( is );
\r
7129 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
7131 if( is->count == ((DWORD) -1) ) break; /* [AS] */
\r
7133 if (is->count < 0) break; /* Quit on error */
\r
7135 CloseHandle(is->hFile);
\r
7140 SocketInputThread(LPVOID arg)
\r
7144 is = (InputSource *) arg;
\r
7145 while (is->hThread != NULL) {
\r
7146 is->count = recv(is->sock, is->buf, INPUT_SOURCE_BUF_SIZE, 0);
\r
7147 if ((int)is->count == SOCKET_ERROR) {
\r
7148 is->count = (DWORD) -1;
\r
7149 is->error = WSAGetLastError();
\r
7151 is->error = NO_ERROR;
\r
7152 is->next += is->count;
\r
7153 if (is->count == 0 && is->second == is) {
\r
7154 /* End of file on stderr; quit with no message */
\r
7158 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
7160 if( is->count == ((DWORD) -1) ) break; /* [AS] */
\r
7162 if (is->count <= 0) break; /* Quit on EOF or error */
\r
7168 InputEvent(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
7172 is = (InputSource *) lParam;
\r
7173 if (is->lineByLine) {
\r
7174 /* Feed in lines one by one */
\r
7175 char *p = is->buf;
\r
7177 while (q < is->next) {
\r
7178 if (*q++ == '\n') {
\r
7179 (is->func)(is, is->closure, p, q - p, NO_ERROR);
\r
7184 /* Move any partial line to the start of the buffer */
\r
7186 while (p < is->next) {
\r
7191 if (is->error != NO_ERROR || is->count == 0) {
\r
7192 /* Notify backend of the error. Note: If there was a partial
\r
7193 line at the end, it is not flushed through. */
\r
7194 (is->func)(is, is->closure, is->buf, is->count, is->error);
\r
7197 /* Feed in the whole chunk of input at once */
\r
7198 (is->func)(is, is->closure, is->buf, is->count, is->error);
\r
7199 is->next = is->buf;
\r
7203 /*---------------------------------------------------------------------------*\
\r
7205 * Menu enables. Used when setting various modes.
\r
7207 \*---------------------------------------------------------------------------*/
\r
7215 GreyRevert(Boolean grey)
\r
7216 { // [HGM] vari: for retracting variations in local mode
\r
7217 HMENU hmenu = GetMenu(hwndMain);
\r
7218 EnableMenuItem(hmenu, IDM_Revert, MF_BYCOMMAND|(grey ? MF_GRAYED : MF_ENABLED));
\r
7222 SetMenuEnables(HMENU hmenu, Enables *enab)
\r
7224 while (enab->item > 0) {
\r
7225 (void) EnableMenuItem(hmenu, enab->item, enab->flags);
\r
7230 Enables gnuEnables[] = {
\r
7231 { IDM_MailMove, MF_BYCOMMAND|MF_GRAYED },
\r
7232 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_GRAYED },
\r
7233 { IDM_IcsClient, MF_BYCOMMAND|MF_GRAYED },
\r
7234 { IDM_Accept, MF_BYCOMMAND|MF_GRAYED },
\r
7235 { IDM_Decline, MF_BYCOMMAND|MF_GRAYED },
\r
7236 { IDM_Rematch, MF_BYCOMMAND|MF_GRAYED },
\r
7237 { IDM_Adjourn, MF_BYCOMMAND|MF_GRAYED },
\r
7238 { IDM_StopExamining, MF_BYCOMMAND|MF_GRAYED },
\r
7239 { IDM_StopObserving, MF_BYCOMMAND|MF_GRAYED },
\r
7240 { IDM_Revert, MF_BYCOMMAND|MF_GRAYED },
\r
7241 { IDM_NewChat, MF_BYCOMMAND|MF_GRAYED },
\r
7245 Enables icsEnables[] = {
\r
7246 { IDM_MailMove, MF_BYCOMMAND|MF_GRAYED },
\r
7247 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_GRAYED },
\r
7248 { IDM_MachineWhite, MF_BYCOMMAND|MF_GRAYED },
\r
7249 { IDM_MachineBlack, MF_BYCOMMAND|MF_GRAYED },
\r
7250 { IDM_TwoMachines, MF_BYCOMMAND|MF_GRAYED },
\r
7251 { IDM_MachineBoth, MF_BYCOMMAND|MF_GRAYED },
\r
7252 { IDM_AnalysisMode, MF_BYCOMMAND|MF_ENABLED },
\r
7253 { IDM_AnalyzeFile, MF_BYCOMMAND|MF_GRAYED },
\r
7254 { IDM_TimeControl, MF_BYCOMMAND|MF_GRAYED },
\r
7255 { IDM_MoveNow, MF_BYCOMMAND|MF_GRAYED },
\r
7256 { IDM_Hint, MF_BYCOMMAND|MF_GRAYED },
\r
7257 { IDM_Book, MF_BYCOMMAND|MF_GRAYED },
\r
7258 { IDM_IcsOptions, MF_BYCOMMAND|MF_ENABLED },
\r
7259 { IDM_Engine1Options, MF_BYCOMMAND|MF_GRAYED },
\r
7260 { IDM_Engine2Options, MF_BYCOMMAND|MF_GRAYED },
\r
7265 Enables zippyEnables[] = {
\r
7266 { IDM_MoveNow, MF_BYCOMMAND|MF_ENABLED },
\r
7267 { IDM_Hint, MF_BYCOMMAND|MF_ENABLED },
\r
7268 { IDM_Book, MF_BYCOMMAND|MF_ENABLED },
\r
7269 { IDM_Engine1Options, MF_BYCOMMAND|MF_ENABLED },
\r
7274 Enables ncpEnables[] = {
\r
7275 { IDM_MailMove, MF_BYCOMMAND|MF_GRAYED },
\r
7276 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_GRAYED },
\r
7277 { IDM_MachineWhite, MF_BYCOMMAND|MF_GRAYED },
\r
7278 { IDM_MachineBlack, MF_BYCOMMAND|MF_GRAYED },
\r
7279 { IDM_TwoMachines, MF_BYCOMMAND|MF_GRAYED },
\r
7280 { IDM_AnalysisMode, MF_BYCOMMAND|MF_GRAYED },
\r
7281 { IDM_AnalyzeFile, MF_BYCOMMAND|MF_GRAYED },
\r
7282 { IDM_IcsClient, MF_BYCOMMAND|MF_GRAYED },
\r
7283 { ACTION_POS, MF_BYPOSITION|MF_GRAYED },
\r
7284 { IDM_Revert, MF_BYCOMMAND|MF_GRAYED },
\r
7285 { IDM_MoveNow, MF_BYCOMMAND|MF_GRAYED },
\r
7286 { IDM_RetractMove, MF_BYCOMMAND|MF_GRAYED },
\r
7287 { IDM_TimeControl, MF_BYCOMMAND|MF_GRAYED },
\r
7288 { IDM_Hint, MF_BYCOMMAND|MF_GRAYED },
\r
7289 { IDM_Book, MF_BYCOMMAND|MF_GRAYED },
\r
7290 { IDM_MachineBoth, MF_BYCOMMAND|MF_GRAYED },
\r
7291 { IDM_NewChat, MF_BYCOMMAND|MF_GRAYED },
\r
7292 { IDM_Engine1Options, MF_BYCOMMAND|MF_GRAYED },
\r
7293 { IDM_Engine2Options, MF_BYCOMMAND|MF_GRAYED },
\r
7297 Enables trainingOnEnables[] = {
\r
7298 { IDM_EditComment, MF_BYCOMMAND|MF_GRAYED },
\r
7299 { IDM_Pause, MF_BYCOMMAND|MF_GRAYED },
\r
7300 { IDM_Forward, MF_BYCOMMAND|MF_GRAYED },
\r
7301 { IDM_Backward, MF_BYCOMMAND|MF_GRAYED },
\r
7302 { IDM_ToEnd, MF_BYCOMMAND|MF_GRAYED },
\r
7303 { IDM_ToStart, MF_BYCOMMAND|MF_GRAYED },
\r
7304 { IDM_MoveNow, MF_BYCOMMAND|MF_GRAYED },
\r
7305 { IDM_TruncateGame, MF_BYCOMMAND|MF_GRAYED },
\r
7309 Enables trainingOffEnables[] = {
\r
7310 { IDM_EditComment, MF_BYCOMMAND|MF_ENABLED },
\r
7311 { IDM_Pause, MF_BYCOMMAND|MF_ENABLED },
\r
7312 { IDM_Forward, MF_BYCOMMAND|MF_ENABLED },
\r
7313 { IDM_Backward, MF_BYCOMMAND|MF_ENABLED },
\r
7314 { IDM_ToEnd, MF_BYCOMMAND|MF_ENABLED },
\r
7315 { IDM_ToStart, MF_BYCOMMAND|MF_ENABLED },
\r
7316 { IDM_MoveNow, MF_BYCOMMAND|MF_ENABLED },
\r
7317 { IDM_TruncateGame, MF_BYCOMMAND|MF_ENABLED },
\r
7321 /* These modify either ncpEnables or gnuEnables */
\r
7322 Enables cmailEnables[] = {
\r
7323 { IDM_MailMove, MF_BYCOMMAND|MF_ENABLED },
\r
7324 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_ENABLED },
\r
7325 { ACTION_POS, MF_BYPOSITION|MF_ENABLED },
\r
7326 { IDM_CallFlag, MF_BYCOMMAND|MF_GRAYED },
\r
7327 { IDM_Draw, MF_BYCOMMAND|MF_ENABLED },
\r
7328 { IDM_Adjourn, MF_BYCOMMAND|MF_GRAYED },
\r
7329 { IDM_Abort, MF_BYCOMMAND|MF_GRAYED },
\r
7333 Enables machineThinkingEnables[] = {
\r
7334 { IDM_LoadGame, MF_BYCOMMAND|MF_GRAYED },
\r
7335 { IDM_LoadNextGame, MF_BYCOMMAND|MF_GRAYED },
\r
7336 { IDM_LoadPrevGame, MF_BYCOMMAND|MF_GRAYED },
\r
7337 { IDM_ReloadGame, MF_BYCOMMAND|MF_GRAYED },
\r
7338 { IDM_PasteGame, MF_BYCOMMAND|MF_GRAYED },
\r
7339 { IDM_LoadPosition, MF_BYCOMMAND|MF_GRAYED },
\r
7340 { IDM_LoadNextPosition, MF_BYCOMMAND|MF_GRAYED },
\r
7341 { IDM_LoadPrevPosition, MF_BYCOMMAND|MF_GRAYED },
\r
7342 { IDM_ReloadPosition, MF_BYCOMMAND|MF_GRAYED },
\r
7343 { IDM_PastePosition, MF_BYCOMMAND|MF_GRAYED },
\r
7344 { IDM_MachineWhite, MF_BYCOMMAND|MF_GRAYED },
\r
7345 { IDM_MachineBlack, MF_BYCOMMAND|MF_GRAYED },
\r
7346 { IDM_TwoMachines, MF_BYCOMMAND|MF_GRAYED },
\r
7347 { IDM_TypeInMove, MF_BYCOMMAND|MF_GRAYED },
\r
7348 { IDM_RetractMove, MF_BYCOMMAND|MF_GRAYED },
\r
7352 Enables userThinkingEnables[] = {
\r
7353 { IDM_LoadGame, MF_BYCOMMAND|MF_ENABLED },
\r
7354 { IDM_LoadNextGame, MF_BYCOMMAND|MF_ENABLED },
\r
7355 { IDM_LoadPrevGame, MF_BYCOMMAND|MF_ENABLED },
\r
7356 { IDM_ReloadGame, MF_BYCOMMAND|MF_ENABLED },
\r
7357 { IDM_PasteGame, MF_BYCOMMAND|MF_ENABLED },
\r
7358 { IDM_LoadPosition, MF_BYCOMMAND|MF_ENABLED },
\r
7359 { IDM_LoadNextPosition, MF_BYCOMMAND|MF_ENABLED },
\r
7360 { IDM_LoadPrevPosition, MF_BYCOMMAND|MF_ENABLED },
\r
7361 { IDM_ReloadPosition, MF_BYCOMMAND|MF_ENABLED },
\r
7362 { IDM_PastePosition, MF_BYCOMMAND|MF_ENABLED },
\r
7363 { IDM_MachineWhite, MF_BYCOMMAND|MF_ENABLED },
\r
7364 { IDM_MachineBlack, MF_BYCOMMAND|MF_ENABLED },
\r
7365 { IDM_TwoMachines, MF_BYCOMMAND|MF_ENABLED },
\r
7366 { IDM_TypeInMove, MF_BYCOMMAND|MF_ENABLED },
\r
7367 { IDM_RetractMove, MF_BYCOMMAND|MF_ENABLED },
\r
7371 /*---------------------------------------------------------------------------*\
\r
7373 * Front-end interface functions exported by XBoard.
\r
7374 * Functions appear in same order as prototypes in frontend.h.
\r
7376 \*---------------------------------------------------------------------------*/
\r
7380 static UINT prevChecked = 0;
\r
7381 static int prevPausing = 0;
\r
7384 if (pausing != prevPausing) {
\r
7385 prevPausing = pausing;
\r
7386 (void) CheckMenuItem(GetMenu(hwndMain), IDM_Pause,
\r
7387 MF_BYCOMMAND|(pausing ? MF_CHECKED : MF_UNCHECKED));
\r
7388 if (hwndPause) SetWindowText(hwndPause, pausing ? "C" : "P");
\r
7391 switch (gameMode) {
\r
7392 case BeginningOfGame:
\r
7393 if (appData.icsActive)
\r
7394 nowChecked = IDM_IcsClient;
\r
7395 else if (appData.noChessProgram)
\r
7396 nowChecked = IDM_EditGame;
\r
7398 nowChecked = IDM_MachineBlack;
\r
7400 case MachinePlaysBlack:
\r
7401 nowChecked = IDM_MachineBlack;
\r
7403 case MachinePlaysWhite:
\r
7404 nowChecked = IDM_MachineWhite;
\r
7406 case TwoMachinesPlay:
\r
7407 nowChecked = IDM_TwoMachines;
\r
7410 nowChecked = IDM_AnalysisMode;
\r
7413 nowChecked = IDM_AnalyzeFile;
\r
7416 nowChecked = IDM_EditGame;
\r
7418 case PlayFromGameFile:
\r
7419 nowChecked = IDM_LoadGame;
\r
7421 case EditPosition:
\r
7422 nowChecked = IDM_EditPosition;
\r
7425 nowChecked = IDM_Training;
\r
7427 case IcsPlayingWhite:
\r
7428 case IcsPlayingBlack:
\r
7429 case IcsObserving:
\r
7431 nowChecked = IDM_IcsClient;
\r
7438 if (prevChecked != 0)
\r
7439 (void) CheckMenuItem(GetMenu(hwndMain),
\r
7440 prevChecked, MF_BYCOMMAND|MF_UNCHECKED);
\r
7441 if (nowChecked != 0)
\r
7442 (void) CheckMenuItem(GetMenu(hwndMain),
\r
7443 nowChecked, MF_BYCOMMAND|MF_CHECKED);
\r
7445 if (nowChecked == IDM_LoadGame || nowChecked == IDM_Training) {
\r
7446 (void) EnableMenuItem(GetMenu(hwndMain), IDM_Training,
\r
7447 MF_BYCOMMAND|MF_ENABLED);
\r
7449 (void) EnableMenuItem(GetMenu(hwndMain),
\r
7450 IDM_Training, MF_BYCOMMAND|MF_GRAYED);
\r
7453 prevChecked = nowChecked;
\r
7455 /* [DM] icsEngineAnalyze - Do a sceure check too */
\r
7456 if (appData.icsActive) {
\r
7457 if (appData.icsEngineAnalyze) {
\r
7458 (void) CheckMenuItem(GetMenu(hwndMain), IDM_AnalysisMode,
\r
7459 MF_BYCOMMAND|MF_CHECKED);
\r
7461 (void) CheckMenuItem(GetMenu(hwndMain), IDM_AnalysisMode,
\r
7462 MF_BYCOMMAND|MF_UNCHECKED);
\r
7470 HMENU hmenu = GetMenu(hwndMain);
\r
7471 SetMenuEnables(hmenu, icsEnables);
\r
7472 EnableMenuItem(GetSubMenu(hmenu, OPTIONS_POS), ICS_POS,
\r
7473 MF_BYPOSITION|MF_ENABLED);
\r
7475 if (appData.zippyPlay) {
\r
7476 SetMenuEnables(hmenu, zippyEnables);
\r
7477 if (!appData.noChessProgram) /* [DM] icsEngineAnalyze */
\r
7478 (void) EnableMenuItem(GetMenu(hwndMain), IDM_AnalysisMode,
\r
7479 MF_BYCOMMAND|MF_ENABLED);
\r
7487 SetMenuEnables(GetMenu(hwndMain), gnuEnables);
\r
7493 HMENU hmenu = GetMenu(hwndMain);
\r
7494 SetMenuEnables(hmenu, ncpEnables);
\r
7495 EnableMenuItem(GetSubMenu(hmenu, OPTIONS_POS), SOUNDS_POS,
\r
7496 MF_BYPOSITION|MF_GRAYED);
\r
7497 DrawMenuBar(hwndMain);
\r
7503 SetMenuEnables(GetMenu(hwndMain), cmailEnables);
\r
7507 SetTrainingModeOn()
\r
7510 SetMenuEnables(GetMenu(hwndMain), trainingOnEnables);
\r
7511 for (i = 0; i < N_BUTTONS; i++) {
\r
7512 if (buttonDesc[i].hwnd != NULL)
\r
7513 EnableWindow(buttonDesc[i].hwnd, FALSE);
\r
7518 VOID SetTrainingModeOff()
\r
7521 SetMenuEnables(GetMenu(hwndMain), trainingOffEnables);
\r
7522 for (i = 0; i < N_BUTTONS; i++) {
\r
7523 if (buttonDesc[i].hwnd != NULL)
\r
7524 EnableWindow(buttonDesc[i].hwnd, TRUE);
\r
7530 SetUserThinkingEnables()
\r
7532 SetMenuEnables(GetMenu(hwndMain), userThinkingEnables);
\r
7536 SetMachineThinkingEnables()
\r
7538 HMENU hMenu = GetMenu(hwndMain);
\r
7539 int flags = MF_BYCOMMAND|MF_ENABLED;
\r
7541 SetMenuEnables(hMenu, machineThinkingEnables);
\r
7543 if (gameMode == MachinePlaysBlack) {
\r
7544 (void)EnableMenuItem(hMenu, IDM_MachineBlack, flags);
\r
7545 } else if (gameMode == MachinePlaysWhite) {
\r
7546 (void)EnableMenuItem(hMenu, IDM_MachineWhite, flags);
\r
7547 } else if (gameMode == TwoMachinesPlay) {
\r
7548 (void)EnableMenuItem(hMenu, IDM_TwoMachines, flags);
\r
7554 DisplayTitle(char *str)
\r
7556 char title[MSG_SIZ], *host;
\r
7557 if (str[0] != NULLCHAR) {
\r
7558 strcpy(title, str);
\r
7559 } else if (appData.icsActive) {
\r
7560 if (appData.icsCommPort[0] != NULLCHAR)
\r
7563 host = appData.icsHost;
\r
7564 sprintf(title, "%s: %s", szTitle, host);
\r
7565 } else if (appData.noChessProgram) {
\r
7566 strcpy(title, szTitle);
\r
7568 strcpy(title, szTitle);
\r
7569 strcat(title, ": ");
\r
7570 strcat(title, first.tidy);
\r
7572 SetWindowText(hwndMain, title);
\r
7577 DisplayMessage(char *str1, char *str2)
\r
7581 int remain = MESSAGE_TEXT_MAX - 1;
\r
7584 moveErrorMessageUp = FALSE; /* turned on later by caller if needed */
\r
7585 messageText[0] = NULLCHAR;
\r
7587 len = strlen(str1);
\r
7588 if (len > remain) len = remain;
\r
7589 strncpy(messageText, str1, len);
\r
7590 messageText[len] = NULLCHAR;
\r
7593 if (*str2 && remain >= 2) {
\r
7595 strcat(messageText, " ");
\r
7598 len = strlen(str2);
\r
7599 if (len > remain) len = remain;
\r
7600 strncat(messageText, str2, len);
\r
7602 messageText[MESSAGE_TEXT_MAX - 1] = NULLCHAR;
\r
7604 if (hwndMain == NULL || IsIconic(hwndMain)) return;
\r
7608 hdc = GetDC(hwndMain);
\r
7609 oldFont = SelectObject(hdc, font[boardSize][MESSAGE_FONT]->hf);
\r
7610 ExtTextOut(hdc, messageRect.left, messageRect.top, ETO_CLIPPED|ETO_OPAQUE,
\r
7611 &messageRect, messageText, strlen(messageText), NULL);
\r
7612 (void) SelectObject(hdc, oldFont);
\r
7613 (void) ReleaseDC(hwndMain, hdc);
\r
7617 DisplayError(char *str, int error)
\r
7619 char buf[MSG_SIZ*2], buf2[MSG_SIZ];
\r
7625 len = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
\r
7626 NULL, error, LANG_NEUTRAL,
\r
7627 (LPSTR) buf2, MSG_SIZ, NULL);
\r
7629 sprintf(buf, "%s:\n%s", str, buf2);
\r
7631 ErrorMap *em = errmap;
\r
7632 while (em->err != 0 && em->err != error) em++;
\r
7633 if (em->err != 0) {
\r
7634 sprintf(buf, "%s:\n%s", str, em->msg);
\r
7636 sprintf(buf, "%s:\nError code %d", str, error);
\r
7641 ErrorPopUp("Error", buf);
\r
7646 DisplayMoveError(char *str)
\r
7648 fromX = fromY = -1;
\r
7649 ClearHighlights();
\r
7650 DrawPosition(FALSE, NULL);
\r
7651 if (appData.popupMoveErrors) {
\r
7652 ErrorPopUp("Error", str);
\r
7654 DisplayMessage(str, "");
\r
7655 moveErrorMessageUp = TRUE;
\r
7660 DisplayFatalError(char *str, int error, int exitStatus)
\r
7662 char buf[2*MSG_SIZ], buf2[MSG_SIZ];
\r
7664 char *label = exitStatus ? "Fatal Error" : "Exiting";
\r
7667 len = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
\r
7668 NULL, error, LANG_NEUTRAL,
\r
7669 (LPSTR) buf2, MSG_SIZ, NULL);
\r
7671 sprintf(buf, "%s:\n%s", str, buf2);
\r
7673 ErrorMap *em = errmap;
\r
7674 while (em->err != 0 && em->err != error) em++;
\r
7675 if (em->err != 0) {
\r
7676 sprintf(buf, "%s:\n%s", str, em->msg);
\r
7678 sprintf(buf, "%s:\nError code %d", str, error);
\r
7683 if (appData.debugMode) {
\r
7684 fprintf(debugFP, "%s: %s\n", label, str);
\r
7686 if (appData.popupExitMessage) {
\r
7687 (void) MessageBox(hwndMain, str, label, MB_OK|
\r
7688 (exitStatus ? MB_ICONSTOP : MB_ICONINFORMATION));
\r
7690 ExitEvent(exitStatus);
\r
7695 DisplayInformation(char *str)
\r
7697 (void) MessageBox(hwndMain, str, "Information", MB_OK|MB_ICONINFORMATION);
\r
7702 DisplayNote(char *str)
\r
7704 ErrorPopUp("Note", str);
\r
7709 char *title, *question, *replyPrefix;
\r
7714 QuestionDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7716 static QuestionParams *qp;
\r
7717 char reply[MSG_SIZ];
\r
7720 switch (message) {
\r
7721 case WM_INITDIALOG:
\r
7722 qp = (QuestionParams *) lParam;
\r
7723 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
7724 SetWindowText(hDlg, qp->title);
\r
7725 SetDlgItemText(hDlg, OPT_QuestionText, qp->question);
\r
7726 SetFocus(GetDlgItem(hDlg, OPT_QuestionInput));
\r
7730 switch (LOWORD(wParam)) {
\r
7732 strcpy(reply, qp->replyPrefix);
\r
7733 if (*reply) strcat(reply, " ");
\r
7734 len = strlen(reply);
\r
7735 GetDlgItemText(hDlg, OPT_QuestionInput, reply + len, sizeof(reply) - len);
\r
7736 strcat(reply, "\n");
\r
7737 OutputToProcess(qp->pr, reply, strlen(reply), &err);
\r
7738 EndDialog(hDlg, TRUE);
\r
7739 if (err) DisplayFatalError("Error writing to chess program", err, 1);
\r
7742 EndDialog(hDlg, FALSE);
\r
7753 AskQuestion(char* title, char *question, char *replyPrefix, ProcRef pr)
\r
7755 QuestionParams qp;
\r
7759 qp.question = question;
\r
7760 qp.replyPrefix = replyPrefix;
\r
7762 lpProc = MakeProcInstance((FARPROC)QuestionDialog, hInst);
\r
7763 DialogBoxParam(hInst, MAKEINTRESOURCE(DLG_Question),
\r
7764 hwndMain, (DLGPROC)lpProc, (LPARAM)&qp);
\r
7765 FreeProcInstance(lpProc);
\r
7768 /* [AS] Pick FRC position */
\r
7769 LRESULT CALLBACK NewGameFRC_Proc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7771 static int * lpIndexFRC;
\r
7777 case WM_INITDIALOG:
\r
7778 lpIndexFRC = (int *) lParam;
\r
7780 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
7782 SendDlgItemMessage( hDlg, IDC_NFG_Edit, EM_SETLIMITTEXT, sizeof(buf)-1, 0 );
\r
7783 SetDlgItemInt( hDlg, IDC_NFG_Edit, *lpIndexFRC, TRUE );
\r
7784 SendDlgItemMessage( hDlg, IDC_NFG_Edit, EM_SETSEL, 0, -1 );
\r
7785 SetFocus(GetDlgItem(hDlg, IDC_NFG_Edit));
\r
7790 switch( LOWORD(wParam) ) {
\r
7792 *lpIndexFRC = GetDlgItemInt(hDlg, IDC_NFG_Edit, &index_is_ok, TRUE );
\r
7793 EndDialog( hDlg, 0 );
\r
7794 shuffleOpenings = TRUE; /* [HGM] shuffle: switch shuffling on for as long as we stay in current variant */
\r
7797 EndDialog( hDlg, 1 );
\r
7799 case IDC_NFG_Edit:
\r
7800 if( HIWORD(wParam) == EN_CHANGE ) {
\r
7801 GetDlgItemInt(hDlg, IDC_NFG_Edit, &index_is_ok, TRUE );
\r
7803 EnableWindow( GetDlgItem(hDlg, IDOK), index_is_ok );
\r
7806 case IDC_NFG_Random:
\r
7807 sprintf( buf, "%d", myrandom() ); /* [HGM] shuffle: no longer limit to 960 */
\r
7808 SetDlgItemText(hDlg, IDC_NFG_Edit, buf );
\r
7821 int index = appData.defaultFrcPosition;
\r
7822 FARPROC lpProc = MakeProcInstance( (FARPROC) NewGameFRC_Proc, hInst );
\r
7824 result = DialogBoxParam( hInst, MAKEINTRESOURCE(DLG_NewGameFRC), hwndMain, (DLGPROC)lpProc, (LPARAM)&index );
\r
7826 if( result == 0 ) {
\r
7827 appData.defaultFrcPosition = index;
\r
7833 /* [AS] Game list options */
\r
7839 static GLT_Item GLT_ItemInfo[] = {
\r
7840 { GLT_EVENT, "Event" },
\r
7841 { GLT_SITE, "Site" },
\r
7842 { GLT_DATE, "Date" },
\r
7843 { GLT_ROUND, "Round" },
\r
7844 { GLT_PLAYERS, "Players" },
\r
7845 { GLT_RESULT, "Result" },
\r
7846 { GLT_WHITE_ELO, "White Rating" },
\r
7847 { GLT_BLACK_ELO, "Black Rating" },
\r
7848 { GLT_TIME_CONTROL,"Time Control" },
\r
7849 { GLT_VARIANT, "Variant" },
\r
7850 { GLT_OUT_OF_BOOK,PGN_OUT_OF_BOOK },
\r
7851 { GLT_RESULT_COMMENT, "Result Comment" }, // [HGM] rescom
\r
7855 const char * GLT_FindItem( char id )
\r
7857 const char * result = 0;
\r
7859 GLT_Item * list = GLT_ItemInfo;
\r
7861 while( list->id != 0 ) {
\r
7862 if( list->id == id ) {
\r
7863 result = list->name;
\r
7873 void GLT_AddToList( HWND hDlg, int iDlgItem, char id, int index )
\r
7875 const char * name = GLT_FindItem( id );
\r
7878 if( index >= 0 ) {
\r
7879 SendDlgItemMessage( hDlg, iDlgItem, LB_INSERTSTRING, index, (LPARAM) name );
\r
7882 SendDlgItemMessage( hDlg, iDlgItem, LB_ADDSTRING, 0, (LPARAM) name );
\r
7887 void GLT_TagsToList( HWND hDlg, char * tags )
\r
7891 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_RESETCONTENT, 0, 0 );
\r
7894 GLT_AddToList( hDlg, IDC_GameListTags, *pc, -1 );
\r
7898 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_ADDSTRING, 0, (LPARAM) "\t --- Hidden tags ---" );
\r
7900 pc = GLT_ALL_TAGS;
\r
7903 if( strchr( tags, *pc ) == 0 ) {
\r
7904 GLT_AddToList( hDlg, IDC_GameListTags, *pc, -1 );
\r
7909 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_SETCURSEL, 0, 0 );
\r
7912 char GLT_ListItemToTag( HWND hDlg, int index )
\r
7914 char result = '\0';
\r
7917 GLT_Item * list = GLT_ItemInfo;
\r
7919 if( SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETTEXT, index, (LPARAM) name ) != LB_ERR ) {
\r
7920 while( list->id != 0 ) {
\r
7921 if( strcmp( list->name, name ) == 0 ) {
\r
7922 result = list->id;
\r
7933 void GLT_MoveSelection( HWND hDlg, int delta )
\r
7935 int idx1 = (int) SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETCURSEL, 0, 0 );
\r
7936 int idx2 = idx1 + delta;
\r
7937 int count = (int) SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETCOUNT, 0, 0 );
\r
7939 if( idx1 >=0 && idx1 < count && idx2 >= 0 && idx2 < count ) {
\r
7942 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETTEXT, idx1, (LPARAM) buf );
\r
7943 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_DELETESTRING, idx1, 0 );
\r
7944 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_INSERTSTRING, idx2, (LPARAM) buf );
\r
7945 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_SETCURSEL, idx2, 0 );
\r
7949 LRESULT CALLBACK GameListOptions_Proc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7951 static char glt[64];
\r
7952 static char * lpUserGLT;
\r
7956 case WM_INITDIALOG:
\r
7957 lpUserGLT = (char *) lParam;
\r
7959 strcpy( glt, lpUserGLT );
\r
7961 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
7963 /* Initialize list */
\r
7964 GLT_TagsToList( hDlg, glt );
\r
7966 SetFocus( GetDlgItem(hDlg, IDC_GameListTags) );
\r
7971 switch( LOWORD(wParam) ) {
\r
7974 char * pc = lpUserGLT;
\r
7976 // int cnt = (int) SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETCOUNT, 0, 0 );
\r
7980 id = GLT_ListItemToTag( hDlg, idx );
\r
7984 } while( id != '\0' );
\r
7986 EndDialog( hDlg, 0 );
\r
7989 EndDialog( hDlg, 1 );
\r
7992 case IDC_GLT_Default:
\r
7993 strcpy( glt, GLT_DEFAULT_TAGS );
\r
7994 GLT_TagsToList( hDlg, glt );
\r
7997 case IDC_GLT_Restore:
\r
7998 strcpy( glt, lpUserGLT );
\r
7999 GLT_TagsToList( hDlg, glt );
\r
8003 GLT_MoveSelection( hDlg, -1 );
\r
8006 case IDC_GLT_Down:
\r
8007 GLT_MoveSelection( hDlg, +1 );
\r
8017 int GameListOptions()
\r
8021 FARPROC lpProc = MakeProcInstance( (FARPROC) GameListOptions_Proc, hInst );
\r
8023 strcpy( glt, appData.gameListTags );
\r
8025 result = DialogBoxParam( hInst, MAKEINTRESOURCE(DLG_GameListOptions), hwndMain, (DLGPROC)lpProc, (LPARAM)glt );
\r
8027 if( result == 0 ) {
\r
8028 /* [AS] Memory leak here! */
\r
8029 appData.gameListTags = strdup( glt );
\r
8037 DisplayIcsInteractionTitle(char *str)
\r
8039 char consoleTitle[MSG_SIZ];
\r
8041 sprintf(consoleTitle, "%s: %s", szConsoleTitle, str);
\r
8042 SetWindowText(hwndConsole, consoleTitle);
\r
8046 DrawPosition(int fullRedraw, Board board)
\r
8048 HDCDrawPosition(NULL, (BOOLEAN) fullRedraw, board);
\r
8051 void NotifyFrontendLogin()
\r
8054 UpdateICSWidth(GetDlgItem(hwndConsole, OPT_ConsoleText));
\r
8060 fromX = fromY = -1;
\r
8061 if (dragInfo.pos.x != -1 || dragInfo.pos.y != -1) {
\r
8062 dragInfo.pos.x = dragInfo.pos.y = -1;
\r
8063 dragInfo.pos.x = dragInfo.pos.y = -1;
\r
8064 dragInfo.lastpos = dragInfo.pos;
\r
8065 dragInfo.start.x = dragInfo.start.y = -1;
\r
8066 dragInfo.from = dragInfo.start;
\r
8068 DrawPosition(TRUE, NULL);
\r
8074 CommentPopUp(char *title, char *str)
\r
8076 HWND hwnd = GetActiveWindow();
\r
8077 EitherCommentPopUp(0, title, str, FALSE);
\r
8079 SetActiveWindow(hwnd);
\r
8083 CommentPopDown(void)
\r
8085 CheckMenuItem(GetMenu(hwndMain), IDM_EditComment, MF_UNCHECKED);
\r
8086 if (commentDialog) {
\r
8087 ShowWindow(commentDialog, SW_HIDE);
\r
8089 commentUp = FALSE;
\r
8093 EditCommentPopUp(int index, char *title, char *str)
\r
8095 EitherCommentPopUp(index, title, str, TRUE);
\r
8102 MyPlaySound(&sounds[(int)SoundMove]);
\r
8105 VOID PlayIcsWinSound()
\r
8107 MyPlaySound(&sounds[(int)SoundIcsWin]);
\r
8110 VOID PlayIcsLossSound()
\r
8112 MyPlaySound(&sounds[(int)SoundIcsLoss]);
\r
8115 VOID PlayIcsDrawSound()
\r
8117 MyPlaySound(&sounds[(int)SoundIcsDraw]);
\r
8120 VOID PlayIcsUnfinishedSound()
\r
8122 MyPlaySound(&sounds[(int)SoundIcsUnfinished]);
\r
8128 MyPlaySound(&sounds[(int)SoundAlarm]);
\r
8136 consoleEcho = TRUE;
\r
8137 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
8138 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&consoleCF);
\r
8139 SendMessage(hInput, EM_SETBKGNDCOLOR, FALSE, consoleBackgroundColor);
\r
8148 consoleEcho = FALSE;
\r
8149 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
8150 /* This works OK: set text and background both to the same color */
\r
8152 cf.crTextColor = COLOR_ECHOOFF;
\r
8153 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&cf);
\r
8154 SendMessage(hInput, EM_SETBKGNDCOLOR, FALSE, cf.crTextColor);
\r
8157 /* No Raw()...? */
\r
8159 void Colorize(ColorClass cc, int continuation)
\r
8161 currentColorClass = cc;
\r
8162 consoleCF.dwMask = CFM_COLOR|CFM_BOLD|CFM_ITALIC|CFM_UNDERLINE|CFM_STRIKEOUT;
\r
8163 consoleCF.crTextColor = textAttribs[cc].color;
\r
8164 consoleCF.dwEffects = textAttribs[cc].effects;
\r
8165 if (!continuation) MyPlaySound(&textAttribs[cc].sound);
\r
8171 static char buf[MSG_SIZ];
\r
8172 DWORD bufsiz = MSG_SIZ;
\r
8174 if(appData.userName != NULL && appData.userName[0] != 0) {
\r
8175 return appData.userName; /* [HGM] username: prefer name selected by user over his system login */
\r
8177 if (!GetUserName(buf, &bufsiz)) {
\r
8178 /*DisplayError("Error getting user name", GetLastError());*/
\r
8179 strcpy(buf, "User");
\r
8187 static char buf[MSG_SIZ];
\r
8188 DWORD bufsiz = MSG_SIZ;
\r
8190 if (!GetComputerName(buf, &bufsiz)) {
\r
8191 /*DisplayError("Error getting host name", GetLastError());*/
\r
8192 strcpy(buf, "Unknown");
\r
8199 ClockTimerRunning()
\r
8201 return clockTimerEvent != 0;
\r
8207 if (clockTimerEvent == 0) return FALSE;
\r
8208 KillTimer(hwndMain, clockTimerEvent);
\r
8209 clockTimerEvent = 0;
\r
8214 StartClockTimer(long millisec)
\r
8216 clockTimerEvent = SetTimer(hwndMain, (UINT) CLOCK_TIMER_ID,
\r
8217 (UINT) millisec, NULL);
\r
8221 DisplayWhiteClock(long timeRemaining, int highlight)
\r
8224 char *flag = whiteFlag && gameMode == TwoMachinesPlay ? "(!)" : "";
\r
8226 if(appData.noGUI) return;
\r
8227 hdc = GetDC(hwndMain);
\r
8228 if (!IsIconic(hwndMain)) {
\r
8229 DisplayAClock(hdc, timeRemaining, highlight,
\r
8230 flipClock ? &blackRect : &whiteRect, "White", flag);
\r
8232 if (highlight && iconCurrent == iconBlack) {
\r
8233 iconCurrent = iconWhite;
\r
8234 PostMessage(hwndMain, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
8235 if (IsIconic(hwndMain)) {
\r
8236 DrawIcon(hdc, 2, 2, iconCurrent);
\r
8239 (void) ReleaseDC(hwndMain, hdc);
\r
8241 PostMessage(hwndConsole, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
8245 DisplayBlackClock(long timeRemaining, int highlight)
\r
8248 char *flag = blackFlag && gameMode == TwoMachinesPlay ? "(!)" : "";
\r
8250 if(appData.noGUI) return;
\r
8251 hdc = GetDC(hwndMain);
\r
8252 if (!IsIconic(hwndMain)) {
\r
8253 DisplayAClock(hdc, timeRemaining, highlight,
\r
8254 flipClock ? &whiteRect : &blackRect, "Black", flag);
\r
8256 if (highlight && iconCurrent == iconWhite) {
\r
8257 iconCurrent = iconBlack;
\r
8258 PostMessage(hwndMain, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
8259 if (IsIconic(hwndMain)) {
\r
8260 DrawIcon(hdc, 2, 2, iconCurrent);
\r
8263 (void) ReleaseDC(hwndMain, hdc);
\r
8265 PostMessage(hwndConsole, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
8270 LoadGameTimerRunning()
\r
8272 return loadGameTimerEvent != 0;
\r
8276 StopLoadGameTimer()
\r
8278 if (loadGameTimerEvent == 0) return FALSE;
\r
8279 KillTimer(hwndMain, loadGameTimerEvent);
\r
8280 loadGameTimerEvent = 0;
\r
8285 StartLoadGameTimer(long millisec)
\r
8287 loadGameTimerEvent = SetTimer(hwndMain, (UINT) LOAD_GAME_TIMER_ID,
\r
8288 (UINT) millisec, NULL);
\r
8296 char fileTitle[MSG_SIZ];
\r
8298 defName = DefaultFileName(appData.oldSaveStyle ? "gam" : "pgn");
\r
8299 f = OpenFileDialog(hwndMain, "a", defName,
\r
8300 appData.oldSaveStyle ? "gam" : "pgn",
\r
8302 "Save Game to File", NULL, fileTitle, NULL);
\r
8304 SaveGame(f, 0, "");
\r
8311 ScheduleDelayedEvent(DelayedEventCallback cb, long millisec)
\r
8313 if (delayedTimerEvent != 0) {
\r
8314 if (appData.debugMode && cb != delayedTimerCallback) { // [HGM] alive: not too much debug
\r
8315 fprintf(debugFP, "ScheduleDelayedEvent: event already scheduled\n");
\r
8317 KillTimer(hwndMain, delayedTimerEvent);
\r
8318 delayedTimerEvent = 0;
\r
8319 if(delayedTimerCallback != cb) // [HGM] alive: do not "flush" same event, just postpone it
\r
8320 delayedTimerCallback();
\r
8322 delayedTimerCallback = cb;
\r
8323 delayedTimerEvent = SetTimer(hwndMain, (UINT) DELAYED_TIMER_ID,
\r
8324 (UINT) millisec, NULL);
\r
8327 DelayedEventCallback
\r
8330 if (delayedTimerEvent) {
\r
8331 return delayedTimerCallback;
\r
8338 CancelDelayedEvent()
\r
8340 if (delayedTimerEvent) {
\r
8341 KillTimer(hwndMain, delayedTimerEvent);
\r
8342 delayedTimerEvent = 0;
\r
8346 DWORD GetWin32Priority(int nice)
\r
8347 { // [HGM] nice: translate Unix nice() value to indows priority class. (Code stolen from Polyglot 1.4w11)
\r
8349 REALTIME_PRIORITY_CLASS 0x00000100
\r
8350 HIGH_PRIORITY_CLASS 0x00000080
\r
8351 ABOVE_NORMAL_PRIORITY_CLASS 0x00008000
\r
8352 NORMAL_PRIORITY_CLASS 0x00000020
\r
8353 BELOW_NORMAL_PRIORITY_CLASS 0x00004000
\r
8354 IDLE_PRIORITY_CLASS 0x00000040
\r
8356 if (nice < -15) return 0x00000080;
\r
8357 if (nice < 0) return 0x00008000;
\r
8358 if (nice == 0) return 0x00000020;
\r
8359 if (nice < 15) return 0x00004000;
\r
8360 return 0x00000040;
\r
8363 /* Start a child process running the given program.
\r
8364 The process's standard output can be read from "from", and its
\r
8365 standard input can be written to "to".
\r
8366 Exit with fatal error if anything goes wrong.
\r
8367 Returns an opaque pointer that can be used to destroy the process
\r
8371 StartChildProcess(char *cmdLine, char *dir, ProcRef *pr)
\r
8373 #define BUFSIZE 4096
\r
8375 HANDLE hChildStdinRd, hChildStdinWr,
\r
8376 hChildStdoutRd, hChildStdoutWr;
\r
8377 HANDLE hChildStdinWrDup, hChildStdoutRdDup;
\r
8378 SECURITY_ATTRIBUTES saAttr;
\r
8380 PROCESS_INFORMATION piProcInfo;
\r
8381 STARTUPINFO siStartInfo;
\r
8383 char buf[MSG_SIZ];
\r
8386 if (appData.debugMode) {
\r
8387 fprintf(debugFP, "StartChildProcess (dir=\"%s\") %s\n", dir, cmdLine);
\r
8392 /* Set the bInheritHandle flag so pipe handles are inherited. */
\r
8393 saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
\r
8394 saAttr.bInheritHandle = TRUE;
\r
8395 saAttr.lpSecurityDescriptor = NULL;
\r
8398 * The steps for redirecting child's STDOUT:
\r
8399 * 1. Create anonymous pipe to be STDOUT for child.
\r
8400 * 2. Create a noninheritable duplicate of read handle,
\r
8401 * and close the inheritable read handle.
\r
8404 /* Create a pipe for the child's STDOUT. */
\r
8405 if (! CreatePipe(&hChildStdoutRd, &hChildStdoutWr, &saAttr, 0)) {
\r
8406 return GetLastError();
\r
8409 /* Duplicate the read handle to the pipe, so it is not inherited. */
\r
8410 fSuccess = DuplicateHandle(GetCurrentProcess(), hChildStdoutRd,
\r
8411 GetCurrentProcess(), &hChildStdoutRdDup, 0,
\r
8412 FALSE, /* not inherited */
\r
8413 DUPLICATE_SAME_ACCESS);
\r
8415 return GetLastError();
\r
8417 CloseHandle(hChildStdoutRd);
\r
8420 * The steps for redirecting child's STDIN:
\r
8421 * 1. Create anonymous pipe to be STDIN for child.
\r
8422 * 2. Create a noninheritable duplicate of write handle,
\r
8423 * and close the inheritable write handle.
\r
8426 /* Create a pipe for the child's STDIN. */
\r
8427 if (! CreatePipe(&hChildStdinRd, &hChildStdinWr, &saAttr, 0)) {
\r
8428 return GetLastError();
\r
8431 /* Duplicate the write handle to the pipe, so it is not inherited. */
\r
8432 fSuccess = DuplicateHandle(GetCurrentProcess(), hChildStdinWr,
\r
8433 GetCurrentProcess(), &hChildStdinWrDup, 0,
\r
8434 FALSE, /* not inherited */
\r
8435 DUPLICATE_SAME_ACCESS);
\r
8437 return GetLastError();
\r
8439 CloseHandle(hChildStdinWr);
\r
8441 /* Arrange to (1) look in dir for the child .exe file, and
\r
8442 * (2) have dir be the child's working directory. Interpret
\r
8443 * dir relative to the directory WinBoard loaded from. */
\r
8444 GetCurrentDirectory(MSG_SIZ, buf);
\r
8445 SetCurrentDirectory(installDir);
\r
8446 SetCurrentDirectory(dir);
\r
8448 /* Now create the child process. */
\r
8450 siStartInfo.cb = sizeof(STARTUPINFO);
\r
8451 siStartInfo.lpReserved = NULL;
\r
8452 siStartInfo.lpDesktop = NULL;
\r
8453 siStartInfo.lpTitle = NULL;
\r
8454 siStartInfo.dwFlags = STARTF_USESTDHANDLES;
\r
8455 siStartInfo.cbReserved2 = 0;
\r
8456 siStartInfo.lpReserved2 = NULL;
\r
8457 siStartInfo.hStdInput = hChildStdinRd;
\r
8458 siStartInfo.hStdOutput = hChildStdoutWr;
\r
8459 siStartInfo.hStdError = hChildStdoutWr;
\r
8461 fSuccess = CreateProcess(NULL,
\r
8462 cmdLine, /* command line */
\r
8463 NULL, /* process security attributes */
\r
8464 NULL, /* primary thread security attrs */
\r
8465 TRUE, /* handles are inherited */
\r
8466 DETACHED_PROCESS|CREATE_NEW_PROCESS_GROUP,
\r
8467 NULL, /* use parent's environment */
\r
8469 &siStartInfo, /* STARTUPINFO pointer */
\r
8470 &piProcInfo); /* receives PROCESS_INFORMATION */
\r
8472 err = GetLastError();
\r
8473 SetCurrentDirectory(buf); /* return to prev directory */
\r
8478 if (appData.niceEngines){ // [HGM] nice: adjust engine proc priority
\r
8479 if(appData.debugMode) fprintf(debugFP, "nice engine proc to %d\n", appData.niceEngines);
\r
8480 SetPriorityClass(piProcInfo.hProcess, GetWin32Priority(appData.niceEngines));
\r
8483 /* Close the handles we don't need in the parent */
\r
8484 CloseHandle(piProcInfo.hThread);
\r
8485 CloseHandle(hChildStdinRd);
\r
8486 CloseHandle(hChildStdoutWr);
\r
8488 /* Prepare return value */
\r
8489 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
8490 cp->kind = CPReal;
\r
8491 cp->hProcess = piProcInfo.hProcess;
\r
8492 cp->pid = piProcInfo.dwProcessId;
\r
8493 cp->hFrom = hChildStdoutRdDup;
\r
8494 cp->hTo = hChildStdinWrDup;
\r
8496 *pr = (void *) cp;
\r
8498 /* Klaus Friedel says that this Sleep solves a problem under Windows
\r
8499 2000 where engines sometimes don't see the initial command(s)
\r
8500 from WinBoard and hang. I don't understand how that can happen,
\r
8501 but the Sleep is harmless, so I've put it in. Others have also
\r
8502 reported what may be the same problem, so hopefully this will fix
\r
8503 it for them too. */
\r
8511 DestroyChildProcess(ProcRef pr, int/*boolean*/ signal)
\r
8513 ChildProc *cp; int result;
\r
8515 cp = (ChildProc *) pr;
\r
8516 if (cp == NULL) return;
\r
8518 switch (cp->kind) {
\r
8520 /* TerminateProcess is considered harmful, so... */
\r
8521 CloseHandle(cp->hTo); /* Closing this will give the child an EOF and hopefully kill it */
\r
8522 if (cp->hFrom) CloseHandle(cp->hFrom); /* if NULL, InputThread will close it */
\r
8523 /* The following doesn't work because the chess program
\r
8524 doesn't "have the same console" as WinBoard. Maybe
\r
8525 we could arrange for this even though neither WinBoard
\r
8526 nor the chess program uses a console for stdio? */
\r
8527 /*!!if (signal) GenerateConsoleCtrlEvent(CTRL_BREAK_EVENT, cp->pid);*/
\r
8529 /* [AS] Special termination modes for misbehaving programs... */
\r
8530 if( signal == 9 ) {
\r
8531 result = TerminateProcess( cp->hProcess, 0 );
\r
8533 if ( appData.debugMode) {
\r
8534 fprintf( debugFP, "Terminating process %lu, result=%d\n", cp->pid, result );
\r
8537 else if( signal == 10 ) {
\r
8538 DWORD dw = WaitForSingleObject( cp->hProcess, 3*1000 ); // Wait 3 seconds at most
\r
8540 if( dw != WAIT_OBJECT_0 ) {
\r
8541 result = TerminateProcess( cp->hProcess, 0 );
\r
8543 if ( appData.debugMode) {
\r
8544 fprintf( debugFP, "Process %lu still alive after timeout, killing... result=%d\n", cp->pid, result );
\r
8550 CloseHandle(cp->hProcess);
\r
8554 if (cp->hFrom) CloseHandle(cp->hFrom);
\r
8558 closesocket(cp->sock);
\r
8563 if (signal) send(cp->sock2, "\017", 1, 0); /* 017 = 15 = SIGTERM */
\r
8564 closesocket(cp->sock);
\r
8565 closesocket(cp->sock2);
\r
8573 InterruptChildProcess(ProcRef pr)
\r
8577 cp = (ChildProc *) pr;
\r
8578 if (cp == NULL) return;
\r
8579 switch (cp->kind) {
\r
8581 /* The following doesn't work because the chess program
\r
8582 doesn't "have the same console" as WinBoard. Maybe
\r
8583 we could arrange for this even though neither WinBoard
\r
8584 nor the chess program uses a console for stdio */
\r
8585 /*!!GenerateConsoleCtrlEvent(CTRL_C_EVENT, cp->pid);*/
\r
8590 /* Can't interrupt */
\r
8594 send(cp->sock2, "\002", 1, 0); /* 2 = SIGINT */
\r
8601 OpenTelnet(char *host, char *port, ProcRef *pr)
\r
8603 char cmdLine[MSG_SIZ];
\r
8605 if (port[0] == NULLCHAR) {
\r
8606 sprintf(cmdLine, "%s %s", appData.telnetProgram, host);
\r
8608 sprintf(cmdLine, "%s %s %s", appData.telnetProgram, host, port);
\r
8610 return StartChildProcess(cmdLine, "", pr);
\r
8614 /* Code to open TCP sockets */
\r
8617 OpenTCP(char *host, char *port, ProcRef *pr)
\r
8622 struct sockaddr_in sa, mysa;
\r
8623 struct hostent FAR *hp;
\r
8624 unsigned short uport;
\r
8625 WORD wVersionRequested;
\r
8628 /* Initialize socket DLL */
\r
8629 wVersionRequested = MAKEWORD(1, 1);
\r
8630 err = WSAStartup(wVersionRequested, &wsaData);
\r
8631 if (err != 0) return err;
\r
8634 if ((s = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
\r
8635 err = WSAGetLastError();
\r
8640 /* Bind local address using (mostly) don't-care values.
\r
8642 memset((char *) &mysa, 0, sizeof(struct sockaddr_in));
\r
8643 mysa.sin_family = AF_INET;
\r
8644 mysa.sin_addr.s_addr = INADDR_ANY;
\r
8645 uport = (unsigned short) 0;
\r
8646 mysa.sin_port = htons(uport);
\r
8647 if (bind(s, (struct sockaddr *) &mysa, sizeof(struct sockaddr_in))
\r
8648 == SOCKET_ERROR) {
\r
8649 err = WSAGetLastError();
\r
8654 /* Resolve remote host name */
\r
8655 memset((char *) &sa, 0, sizeof(struct sockaddr_in));
\r
8656 if (!(hp = gethostbyname(host))) {
\r
8657 unsigned int b0, b1, b2, b3;
\r
8659 err = WSAGetLastError();
\r
8661 if (sscanf(host, "%u.%u.%u.%u", &b0, &b1, &b2, &b3) == 4) {
\r
8662 hp = (struct hostent *) calloc(1, sizeof(struct hostent));
\r
8663 hp->h_addrtype = AF_INET;
\r
8665 hp->h_addr_list = (char **) calloc(2, sizeof(char *));
\r
8666 hp->h_addr_list[0] = (char *) malloc(4);
\r
8667 hp->h_addr_list[0][0] = (char) b0;
\r
8668 hp->h_addr_list[0][1] = (char) b1;
\r
8669 hp->h_addr_list[0][2] = (char) b2;
\r
8670 hp->h_addr_list[0][3] = (char) b3;
\r
8676 sa.sin_family = hp->h_addrtype;
\r
8677 uport = (unsigned short) atoi(port);
\r
8678 sa.sin_port = htons(uport);
\r
8679 memcpy((char *) &sa.sin_addr, hp->h_addr, hp->h_length);
\r
8681 /* Make connection */
\r
8682 if (connect(s, (struct sockaddr *) &sa,
\r
8683 sizeof(struct sockaddr_in)) == SOCKET_ERROR) {
\r
8684 err = WSAGetLastError();
\r
8689 /* Prepare return value */
\r
8690 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
8691 cp->kind = CPSock;
\r
8693 *pr = (ProcRef *) cp;
\r
8699 OpenCommPort(char *name, ProcRef *pr)
\r
8704 char fullname[MSG_SIZ];
\r
8706 if (*name != '\\')
\r
8707 sprintf(fullname, "\\\\.\\%s", name);
\r
8709 strcpy(fullname, name);
\r
8711 h = CreateFile(name, GENERIC_READ | GENERIC_WRITE,
\r
8712 0, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
\r
8713 if (h == (HANDLE) -1) {
\r
8714 return GetLastError();
\r
8718 if (!SetCommState(h, (LPDCB) &dcb)) return GetLastError();
\r
8720 /* Accumulate characters until a 100ms pause, then parse */
\r
8721 ct.ReadIntervalTimeout = 100;
\r
8722 ct.ReadTotalTimeoutMultiplier = 0;
\r
8723 ct.ReadTotalTimeoutConstant = 0;
\r
8724 ct.WriteTotalTimeoutMultiplier = 0;
\r
8725 ct.WriteTotalTimeoutConstant = 0;
\r
8726 if (!SetCommTimeouts(h, (LPCOMMTIMEOUTS) &ct)) return GetLastError();
\r
8728 /* Prepare return value */
\r
8729 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
8730 cp->kind = CPComm;
\r
8733 *pr = (ProcRef *) cp;
\r
8739 OpenLoopback(ProcRef *pr)
\r
8741 DisplayFatalError("Not implemented", 0, 1);
\r
8747 OpenRcmd(char* host, char* user, char* cmd, ProcRef* pr)
\r
8752 struct sockaddr_in sa, mysa;
\r
8753 struct hostent FAR *hp;
\r
8754 unsigned short uport;
\r
8755 WORD wVersionRequested;
\r
8758 char stderrPortStr[MSG_SIZ];
\r
8760 /* Initialize socket DLL */
\r
8761 wVersionRequested = MAKEWORD(1, 1);
\r
8762 err = WSAStartup(wVersionRequested, &wsaData);
\r
8763 if (err != 0) return err;
\r
8765 /* Resolve remote host name */
\r
8766 memset((char *) &sa, 0, sizeof(struct sockaddr_in));
\r
8767 if (!(hp = gethostbyname(host))) {
\r
8768 unsigned int b0, b1, b2, b3;
\r
8770 err = WSAGetLastError();
\r
8772 if (sscanf(host, "%u.%u.%u.%u", &b0, &b1, &b2, &b3) == 4) {
\r
8773 hp = (struct hostent *) calloc(1, sizeof(struct hostent));
\r
8774 hp->h_addrtype = AF_INET;
\r
8776 hp->h_addr_list = (char **) calloc(2, sizeof(char *));
\r
8777 hp->h_addr_list[0] = (char *) malloc(4);
\r
8778 hp->h_addr_list[0][0] = (char) b0;
\r
8779 hp->h_addr_list[0][1] = (char) b1;
\r
8780 hp->h_addr_list[0][2] = (char) b2;
\r
8781 hp->h_addr_list[0][3] = (char) b3;
\r
8787 sa.sin_family = hp->h_addrtype;
\r
8788 uport = (unsigned short) 514;
\r
8789 sa.sin_port = htons(uport);
\r
8790 memcpy((char *) &sa.sin_addr, hp->h_addr, hp->h_length);
\r
8792 /* Bind local socket to unused "privileged" port address
\r
8794 s = INVALID_SOCKET;
\r
8795 memset((char *) &mysa, 0, sizeof(struct sockaddr_in));
\r
8796 mysa.sin_family = AF_INET;
\r
8797 mysa.sin_addr.s_addr = INADDR_ANY;
\r
8798 for (fromPort = 1023;; fromPort--) {
\r
8799 if (fromPort < 0) {
\r
8801 return WSAEADDRINUSE;
\r
8803 if (s == INVALID_SOCKET) {
\r
8804 if ((s = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
\r
8805 err = WSAGetLastError();
\r
8810 uport = (unsigned short) fromPort;
\r
8811 mysa.sin_port = htons(uport);
\r
8812 if (bind(s, (struct sockaddr *) &mysa, sizeof(struct sockaddr_in))
\r
8813 == SOCKET_ERROR) {
\r
8814 err = WSAGetLastError();
\r
8815 if (err == WSAEADDRINUSE) continue;
\r
8819 if (connect(s, (struct sockaddr *) &sa,
\r
8820 sizeof(struct sockaddr_in)) == SOCKET_ERROR) {
\r
8821 err = WSAGetLastError();
\r
8822 if (err == WSAEADDRINUSE) {
\r
8833 /* Bind stderr local socket to unused "privileged" port address
\r
8835 s2 = INVALID_SOCKET;
\r
8836 memset((char *) &mysa, 0, sizeof(struct sockaddr_in));
\r
8837 mysa.sin_family = AF_INET;
\r
8838 mysa.sin_addr.s_addr = INADDR_ANY;
\r
8839 for (fromPort = 1023;; fromPort--) {
\r
8840 if (fromPort == prevStderrPort) continue; // don't reuse port
\r
8841 if (fromPort < 0) {
\r
8842 (void) closesocket(s);
\r
8844 return WSAEADDRINUSE;
\r
8846 if (s2 == INVALID_SOCKET) {
\r
8847 if ((s2 = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
\r
8848 err = WSAGetLastError();
\r
8854 uport = (unsigned short) fromPort;
\r
8855 mysa.sin_port = htons(uport);
\r
8856 if (bind(s2, (struct sockaddr *) &mysa, sizeof(struct sockaddr_in))
\r
8857 == SOCKET_ERROR) {
\r
8858 err = WSAGetLastError();
\r
8859 if (err == WSAEADDRINUSE) continue;
\r
8860 (void) closesocket(s);
\r
8864 if (listen(s2, 1) == SOCKET_ERROR) {
\r
8865 err = WSAGetLastError();
\r
8866 if (err == WSAEADDRINUSE) {
\r
8868 s2 = INVALID_SOCKET;
\r
8871 (void) closesocket(s);
\r
8872 (void) closesocket(s2);
\r
8878 prevStderrPort = fromPort; // remember port used
\r
8879 sprintf(stderrPortStr, "%d", fromPort);
\r
8881 if (send(s, stderrPortStr, strlen(stderrPortStr) + 1, 0) == SOCKET_ERROR) {
\r
8882 err = WSAGetLastError();
\r
8883 (void) closesocket(s);
\r
8884 (void) closesocket(s2);
\r
8889 if (send(s, UserName(), strlen(UserName()) + 1, 0) == SOCKET_ERROR) {
\r
8890 err = WSAGetLastError();
\r
8891 (void) closesocket(s);
\r
8892 (void) closesocket(s2);
\r
8896 if (*user == NULLCHAR) user = UserName();
\r
8897 if (send(s, user, strlen(user) + 1, 0) == SOCKET_ERROR) {
\r
8898 err = WSAGetLastError();
\r
8899 (void) closesocket(s);
\r
8900 (void) closesocket(s2);
\r
8904 if (send(s, cmd, strlen(cmd) + 1, 0) == SOCKET_ERROR) {
\r
8905 err = WSAGetLastError();
\r
8906 (void) closesocket(s);
\r
8907 (void) closesocket(s2);
\r
8912 if ((s3 = accept(s2, NULL, NULL)) == INVALID_SOCKET) {
\r
8913 err = WSAGetLastError();
\r
8914 (void) closesocket(s);
\r
8915 (void) closesocket(s2);
\r
8919 (void) closesocket(s2); /* Stop listening */
\r
8921 /* Prepare return value */
\r
8922 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
8923 cp->kind = CPRcmd;
\r
8926 *pr = (ProcRef *) cp;
\r
8933 AddInputSource(ProcRef pr, int lineByLine,
\r
8934 InputCallback func, VOIDSTAR closure)
\r
8936 InputSource *is, *is2 = NULL;
\r
8937 ChildProc *cp = (ChildProc *) pr;
\r
8939 is = (InputSource *) calloc(1, sizeof(InputSource));
\r
8940 is->lineByLine = lineByLine;
\r
8942 is->closure = closure;
\r
8943 is->second = NULL;
\r
8944 is->next = is->buf;
\r
8945 if (pr == NoProc) {
\r
8946 is->kind = CPReal;
\r
8947 consoleInputSource = is;
\r
8949 is->kind = cp->kind;
\r
8951 [AS] Try to avoid a race condition if the thread is given control too early:
\r
8952 we create all threads suspended so that the is->hThread variable can be
\r
8953 safely assigned, then let the threads start with ResumeThread.
\r
8955 switch (cp->kind) {
\r
8957 is->hFile = cp->hFrom;
\r
8958 cp->hFrom = NULL; /* now owned by InputThread */
\r
8960 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) NonOvlInputThread,
\r
8961 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
8965 is->hFile = cp->hFrom;
\r
8966 cp->hFrom = NULL; /* now owned by InputThread */
\r
8968 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) InputThread,
\r
8969 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
8973 is->sock = cp->sock;
\r
8975 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SocketInputThread,
\r
8976 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
8980 is2 = (InputSource *) calloc(1, sizeof(InputSource));
\r
8982 is->sock = cp->sock;
\r
8984 is2->sock = cp->sock2;
\r
8985 is2->second = is2;
\r
8987 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SocketInputThread,
\r
8988 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
8990 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SocketInputThread,
\r
8991 (LPVOID) is2, CREATE_SUSPENDED, &is2->id);
\r
8995 if( is->hThread != NULL ) {
\r
8996 ResumeThread( is->hThread );
\r
8999 if( is2 != NULL && is2->hThread != NULL ) {
\r
9000 ResumeThread( is2->hThread );
\r
9004 return (InputSourceRef) is;
\r
9008 RemoveInputSource(InputSourceRef isr)
\r
9012 is = (InputSource *) isr;
\r
9013 is->hThread = NULL; /* tell thread to stop */
\r
9014 CloseHandle(is->hThread);
\r
9015 if (is->second != NULL) {
\r
9016 is->second->hThread = NULL;
\r
9017 CloseHandle(is->second->hThread);
\r
9021 int no_wrap(char *message, int count)
\r
9023 ConsoleOutput(message, count, FALSE);
\r
9028 OutputToProcess(ProcRef pr, char *message, int count, int *outError)
\r
9031 int outCount = SOCKET_ERROR;
\r
9032 ChildProc *cp = (ChildProc *) pr;
\r
9033 static OVERLAPPED ovl;
\r
9034 static int line = 0;
\r
9038 if (appData.noJoin || !appData.useInternalWrap)
\r
9039 return no_wrap(message, count);
\r
9042 int width = get_term_width();
\r
9043 int len = wrap(NULL, message, count, width, &line);
\r
9044 char *msg = malloc(len);
\r
9048 return no_wrap(message, count);
\r
9051 dbgchk = wrap(msg, message, count, width, &line);
\r
9052 if (dbgchk != len && appData.debugMode)
\r
9053 fprintf(debugFP, "wrap(): dbgchk(%d) != len(%d)\n", dbgchk, len);
\r
9054 ConsoleOutput(msg, len, FALSE);
\r
9061 if (ovl.hEvent == NULL) {
\r
9062 ovl.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
\r
9064 ovl.Internal = ovl.InternalHigh = ovl.Offset = ovl.OffsetHigh = 0;
\r
9066 switch (cp->kind) {
\r
9069 outCount = send(cp->sock, message, count, 0);
\r
9070 if (outCount == SOCKET_ERROR) {
\r
9071 *outError = WSAGetLastError();
\r
9073 *outError = NO_ERROR;
\r
9078 if (WriteFile(((ChildProc *)pr)->hTo, message, count,
\r
9079 &dOutCount, NULL)) {
\r
9080 *outError = NO_ERROR;
\r
9081 outCount = (int) dOutCount;
\r
9083 *outError = GetLastError();
\r
9088 *outError = DoWriteFile(((ChildProc *)pr)->hTo, message, count,
\r
9089 &dOutCount, &ovl);
\r
9090 if (*outError == NO_ERROR) {
\r
9091 outCount = (int) dOutCount;
\r
9099 OutputToProcessDelayed(ProcRef pr, char *message, int count, int *outError,
\r
9102 /* Ignore delay, not implemented for WinBoard */
\r
9103 return OutputToProcess(pr, message, count, outError);
\r
9108 CmailSigHandlerCallBack(InputSourceRef isr, VOIDSTAR closure,
\r
9109 char *buf, int count, int error)
\r
9111 DisplayFatalError("Not implemented", 0, 1);
\r
9114 /* see wgamelist.c for Game List functions */
\r
9115 /* see wedittags.c for Edit Tags functions */
\r
9122 char buf[MSG_SIZ];
\r
9125 if (SearchPath(installDir, appData.icsLogon, NULL, MSG_SIZ, buf, &dummy)) {
\r
9126 f = fopen(buf, "r");
\r
9128 ProcessICSInitScript(f);
\r
9136 StartAnalysisClock()
\r
9138 if (analysisTimerEvent) return;
\r
9139 analysisTimerEvent = SetTimer(hwndMain, (UINT) ANALYSIS_TIMER_ID,
\r
9140 (UINT) 2000, NULL);
\r
9144 SetHighlights(int fromX, int fromY, int toX, int toY)
\r
9146 highlightInfo.sq[0].x = fromX;
\r
9147 highlightInfo.sq[0].y = fromY;
\r
9148 highlightInfo.sq[1].x = toX;
\r
9149 highlightInfo.sq[1].y = toY;
\r
9155 highlightInfo.sq[0].x = highlightInfo.sq[0].y =
\r
9156 highlightInfo.sq[1].x = highlightInfo.sq[1].y = -1;
\r
9160 SetPremoveHighlights(int fromX, int fromY, int toX, int toY)
\r
9162 premoveHighlightInfo.sq[0].x = fromX;
\r
9163 premoveHighlightInfo.sq[0].y = fromY;
\r
9164 premoveHighlightInfo.sq[1].x = toX;
\r
9165 premoveHighlightInfo.sq[1].y = toY;
\r
9169 ClearPremoveHighlights()
\r
9171 premoveHighlightInfo.sq[0].x = premoveHighlightInfo.sq[0].y =
\r
9172 premoveHighlightInfo.sq[1].x = premoveHighlightInfo.sq[1].y = -1;
\r
9176 ShutDownFrontEnd()
\r
9178 if (saveSettingsOnExit) SaveSettings(settingsFileName);
\r
9179 DeleteClipboardTempFiles();
\r
9185 if (IsIconic(hwndMain))
\r
9186 ShowWindow(hwndMain, SW_RESTORE);
\r
9188 SetActiveWindow(hwndMain);
\r
9192 * Prototypes for animation support routines
\r
9194 static void ScreenSquare(int column, int row, POINT * pt);
\r
9195 static void Tween( POINT * start, POINT * mid, POINT * finish, int factor,
\r
9196 POINT frames[], int * nFrames);
\r
9200 AnimateAtomicCapture(int fromX, int fromY, int toX, int toY, int nFrames)
\r
9201 { // [HGM] atomic: animate blast wave
\r
9203 if(appData.debugMode) fprintf(debugFP, "exploding (%d,%d)\n", toX, toY);
\r
9204 explodeInfo.fromX = fromX;
\r
9205 explodeInfo.fromY = fromY;
\r
9206 explodeInfo.toX = toX;
\r
9207 explodeInfo.toY = toY;
\r
9208 for(i=1; i<nFrames; i++) {
\r
9209 explodeInfo.radius = (i*180)/(nFrames-1);
\r
9210 DrawPosition(FALSE, NULL);
\r
9211 Sleep(appData.animSpeed);
\r
9213 explodeInfo.radius = 0;
\r
9214 DrawPosition(TRUE, NULL);
\r
9220 AnimateMove(board, fromX, fromY, toX, toY)
\r
9227 ChessSquare piece;
\r
9228 POINT start, finish, mid;
\r
9229 POINT frames[kFactor * 2 + 1];
\r
9232 if (!appData.animate) return;
\r
9233 if (doingSizing) return;
\r
9234 if (fromY < 0 || fromX < 0) return;
\r
9235 piece = board[fromY][fromX];
\r
9236 if (piece >= EmptySquare) return;
\r
9238 ScreenSquare(fromX, fromY, &start);
\r
9239 ScreenSquare(toX, toY, &finish);
\r
9241 /* All pieces except knights move in straight line */
\r
9242 if (piece != WhiteKnight && piece != BlackKnight) {
\r
9243 mid.x = start.x + (finish.x - start.x) / 2;
\r
9244 mid.y = start.y + (finish.y - start.y) / 2;
\r
9246 /* Knight: make diagonal movement then straight */
\r
9247 if (abs(toY - fromY) < abs(toX - fromX)) {
\r
9248 mid.x = start.x + (finish.x - start.x) / 2;
\r
9252 mid.y = start.y + (finish.y - start.y) / 2;
\r
9256 /* Don't use as many frames for very short moves */
\r
9257 if (abs(toY - fromY) + abs(toX - fromX) <= 2)
\r
9258 Tween(&start, &mid, &finish, kFactor - 1, frames, &nFrames);
\r
9260 Tween(&start, &mid, &finish, kFactor, frames, &nFrames);
\r
9262 animInfo.from.x = fromX;
\r
9263 animInfo.from.y = fromY;
\r
9264 animInfo.to.x = toX;
\r
9265 animInfo.to.y = toY;
\r
9266 animInfo.lastpos = start;
\r
9267 animInfo.piece = piece;
\r
9268 for (n = 0; n < nFrames; n++) {
\r
9269 animInfo.pos = frames[n];
\r
9270 DrawPosition(FALSE, NULL);
\r
9271 animInfo.lastpos = animInfo.pos;
\r
9272 Sleep(appData.animSpeed);
\r
9274 animInfo.pos = finish;
\r
9275 DrawPosition(FALSE, NULL);
\r
9276 animInfo.piece = EmptySquare;
\r
9277 if(gameInfo.variant == VariantAtomic &&
\r
9278 (board[toY][toX] != EmptySquare || fromX != toX && (piece == WhitePawn || piece == BlackPawn) ) )
\r
9279 AnimateAtomicCapture(fromX, fromY, toX, toY, 2*nFrames);
\r
9282 /* Convert board position to corner of screen rect and color */
\r
9285 ScreenSquare(column, row, pt)
\r
9286 int column; int row; POINT * pt;
\r
9289 pt->x = lineGap + ((BOARD_WIDTH-1)-column) * (squareSize + lineGap);
\r
9290 pt->y = lineGap + row * (squareSize + lineGap);
\r
9292 pt->x = lineGap + column * (squareSize + lineGap);
\r
9293 pt->y = lineGap + ((BOARD_HEIGHT-1)-row) * (squareSize + lineGap);
\r
9297 /* Generate a series of frame coords from start->mid->finish.
\r
9298 The movement rate doubles until the half way point is
\r
9299 reached, then halves back down to the final destination,
\r
9300 which gives a nice slow in/out effect. The algorithmn
\r
9301 may seem to generate too many intermediates for short
\r
9302 moves, but remember that the purpose is to attract the
\r
9303 viewers attention to the piece about to be moved and
\r
9304 then to where it ends up. Too few frames would be less
\r
9308 Tween(start, mid, finish, factor, frames, nFrames)
\r
9309 POINT * start; POINT * mid;
\r
9310 POINT * finish; int factor;
\r
9311 POINT frames[]; int * nFrames;
\r
9313 int n, fraction = 1, count = 0;
\r
9315 /* Slow in, stepping 1/16th, then 1/8th, ... */
\r
9316 for (n = 0; n < factor; n++)
\r
9318 for (n = 0; n < factor; n++) {
\r
9319 frames[count].x = start->x + (mid->x - start->x) / fraction;
\r
9320 frames[count].y = start->y + (mid->y - start->y) / fraction;
\r
9322 fraction = fraction / 2;
\r
9326 frames[count] = *mid;
\r
9329 /* Slow out, stepping 1/2, then 1/4, ... */
\r
9331 for (n = 0; n < factor; n++) {
\r
9332 frames[count].x = finish->x - (finish->x - mid->x) / fraction;
\r
9333 frames[count].y = finish->y - (finish->y - mid->y) / fraction;
\r
9335 fraction = fraction * 2;
\r
9341 HistorySet( char movelist[][2*MOVE_LEN], int first, int last, int current )
\r
9343 MoveHistorySet( movelist, first, last, current, pvInfoList );
\r
9345 EvalGraphSet( first, last, current, pvInfoList );
\r