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
6071 ErrorDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
6076 switch (message) {
\r
6077 case WM_INITDIALOG:
\r
6078 GetWindowRect(hDlg, &rChild);
\r
6081 SetWindowPos(hDlg, NULL, rChild.left,
\r
6082 rChild.top + boardRect.top - (rChild.bottom - rChild.top),
\r
6083 0, 0, SWP_NOZORDER|SWP_NOSIZE);
\r
6087 [AS] It seems that the above code wants to move the dialog up in the "caption
\r
6088 area" of the main window, but it uses the dialog height as an hard-coded constant,
\r
6089 and it doesn't work when you resize the dialog.
\r
6090 For now, just give it a default position.
\r
6092 SetWindowPos(hDlg, NULL, boardRect.left+8, boardRect.top+8, 0, 0, SWP_NOZORDER|SWP_NOSIZE);
\r
6094 errorDialog = hDlg;
\r
6095 SetWindowText(hDlg, errorTitle);
\r
6096 hwndText = GetDlgItem(hDlg, OPT_ErrorText);
\r
6097 SetDlgItemText(hDlg, OPT_ErrorText, errorMessage);
\r
6101 switch (LOWORD(wParam)) {
\r
6104 if (errorDialog == hDlg) errorDialog = NULL;
\r
6105 DestroyWindow(hDlg);
\r
6117 HWND gothicDialog = NULL;
\r
6120 GothicDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
6124 int height = GetSystemMetrics(SM_CYCAPTION)+GetSystemMetrics(SM_CYFRAME);
\r
6126 switch (message) {
\r
6127 case WM_INITDIALOG:
\r
6128 GetWindowRect(hDlg, &rChild);
\r
6130 SetWindowPos(hDlg, NULL, wpMain.x, wpMain.y-height, wpMain.width, height,
\r
6134 [AS] It seems that the above code wants to move the dialog up in the "caption
\r
6135 area" of the main window, but it uses the dialog height as an hard-coded constant,
\r
6136 and it doesn't work when you resize the dialog.
\r
6137 For now, just give it a default position.
\r
6139 gothicDialog = hDlg;
\r
6140 SetWindowText(hDlg, errorTitle);
\r
6141 hwndText = GetDlgItem(hDlg, OPT_ErrorText);
\r
6142 SetDlgItemText(hDlg, OPT_ErrorText, errorMessage);
\r
6146 switch (LOWORD(wParam)) {
\r
6149 if (errorDialog == hDlg) errorDialog = NULL;
\r
6150 DestroyWindow(hDlg);
\r
6162 GothicPopUp(char *title, VariantClass variant)
\r
6165 static char *lastTitle;
\r
6167 strncpy(errorTitle, title, sizeof(errorTitle));
\r
6168 errorTitle[sizeof(errorTitle) - 1] = '\0';
\r
6170 if(lastTitle != title && gothicDialog != NULL) {
\r
6171 DestroyWindow(gothicDialog);
\r
6172 gothicDialog = NULL;
\r
6174 if(variant != VariantNormal && gothicDialog == NULL) {
\r
6175 title = lastTitle;
\r
6176 lpProc = MakeProcInstance((FARPROC)GothicDialog, hInst);
\r
6177 CreateDialog(hInst, MAKEINTRESOURCE(DLG_Error),
\r
6178 hwndMain, (DLGPROC)lpProc);
\r
6179 FreeProcInstance(lpProc);
\r
6184 /*---------------------------------------------------------------------------*\
\r
6186 * Ics Interaction console functions
\r
6188 \*---------------------------------------------------------------------------*/
\r
6190 #define HISTORY_SIZE 64
\r
6191 static char *history[HISTORY_SIZE];
\r
6192 int histIn = 0, histP = 0;
\r
6195 SaveInHistory(char *cmd)
\r
6197 if (history[histIn] != NULL) {
\r
6198 free(history[histIn]);
\r
6199 history[histIn] = NULL;
\r
6201 if (*cmd == NULLCHAR) return;
\r
6202 history[histIn] = StrSave(cmd);
\r
6203 histIn = (histIn + 1) % HISTORY_SIZE;
\r
6204 if (history[histIn] != NULL) {
\r
6205 free(history[histIn]);
\r
6206 history[histIn] = NULL;
\r
6212 PrevInHistory(char *cmd)
\r
6215 if (histP == histIn) {
\r
6216 if (history[histIn] != NULL) free(history[histIn]);
\r
6217 history[histIn] = StrSave(cmd);
\r
6219 newhp = (histP - 1 + HISTORY_SIZE) % HISTORY_SIZE;
\r
6220 if (newhp == histIn || history[newhp] == NULL) return NULL;
\r
6222 return history[histP];
\r
6228 if (histP == histIn) return NULL;
\r
6229 histP = (histP + 1) % HISTORY_SIZE;
\r
6230 return history[histP];
\r
6234 LoadIcsTextMenu(IcsTextMenuEntry *e)
\r
6238 hmenu = LoadMenu(hInst, "TextMenu");
\r
6239 h = GetSubMenu(hmenu, 0);
\r
6241 if (strcmp(e->item, "-") == 0) {
\r
6242 AppendMenu(h, MF_SEPARATOR, 0, 0);
\r
6244 if (e->item[0] == '|') {
\r
6245 AppendMenu(h, MF_STRING|MF_MENUBARBREAK,
\r
6246 IDM_CommandX + i, &e->item[1]);
\r
6248 AppendMenu(h, MF_STRING, IDM_CommandX + i, e->item);
\r
6257 WNDPROC consoleTextWindowProc;
\r
6260 CommandX(HWND hwnd, char *command, BOOLEAN getname, BOOLEAN immediate)
\r
6262 char buf[MSG_SIZ], name[MSG_SIZ];
\r
6263 HWND hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
6267 SetWindowText(hInput, command);
\r
6269 SendMessage(hInput, WM_CHAR, '\r', 0);
\r
6271 sel.cpMin = 999999;
\r
6272 sel.cpMax = 999999;
\r
6273 SendMessage(hInput, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
6278 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
6279 if (sel.cpMin == sel.cpMax) {
\r
6280 /* Expand to surrounding word */
\r
6283 tr.chrg.cpMax = sel.cpMin;
\r
6284 tr.chrg.cpMin = --sel.cpMin;
\r
6285 if (sel.cpMin < 0) break;
\r
6286 tr.lpstrText = name;
\r
6287 SendMessage(hwnd, EM_GETTEXTRANGE, 0, (LPARAM) &tr);
\r
6288 } while (isalpha(name[0]) || isdigit(name[0]) || name[0] == '-');
\r
6292 tr.chrg.cpMin = sel.cpMax;
\r
6293 tr.chrg.cpMax = ++sel.cpMax;
\r
6294 tr.lpstrText = name;
\r
6295 if (SendMessage(hwnd, EM_GETTEXTRANGE, 0, (LPARAM) &tr) < 1) break;
\r
6296 } while (isalpha(name[0]) || isdigit(name[0]) || name[0] == '-');
\r
6299 if (sel.cpMax == sel.cpMin || sel.cpMax - sel.cpMin > MSG_SIZ/2) {
\r
6300 MessageBeep(MB_ICONEXCLAMATION);
\r
6304 tr.lpstrText = name;
\r
6305 SendMessage(hwnd, EM_GETTEXTRANGE, 0, (LPARAM) &tr);
\r
6307 if (sel.cpMax - sel.cpMin > MSG_SIZ/2) {
\r
6308 MessageBeep(MB_ICONEXCLAMATION);
\r
6311 SendMessage(hwnd, EM_GETSELTEXT, 0, (LPARAM) name);
\r
6314 sprintf(buf, "%s %s", command, name);
\r
6315 SetWindowText(hInput, buf);
\r
6316 SendMessage(hInput, WM_CHAR, '\r', 0);
\r
6318 sprintf(buf, "%s %s ", command, name); /* trailing space */
\r
6319 SetWindowText(hInput, buf);
\r
6320 sel.cpMin = 999999;
\r
6321 sel.cpMax = 999999;
\r
6322 SendMessage(hInput, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
6328 ConsoleTextSubclass(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
6333 switch (message) {
\r
6335 if (!(GetKeyState(VK_CONTROL) & ~1)) break;
\r
6338 SendMessage(hwnd, EM_LINESCROLL, 0, -999999);
\r
6341 sel.cpMin = 999999;
\r
6342 sel.cpMax = 999999;
\r
6343 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
6344 SendMessage(hwnd, EM_SCROLLCARET, 0, 0);
\r
6349 if(wParam != '\022') {
\r
6350 if (wParam == '\t') {
\r
6351 if (GetKeyState(VK_SHIFT) < 0) {
\r
6353 if (IsIconic(hwndMain)) ShowWindow(hwndMain, SW_RESTORE);
\r
6354 if (buttonDesc[0].hwnd) {
\r
6355 SetFocus(buttonDesc[0].hwnd);
\r
6357 SetFocus(hwndMain);
\r
6361 SetFocus(GetDlgItem(hwndConsole, OPT_ConsoleInput));
\r
6364 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
6365 JAWS_DELETE( SetFocus(hInput); )
\r
6366 SendMessage(hInput, message, wParam, lParam);
\r
6369 } // [HGM] navigate: for Ctrl+R, flow into nex case (moved up here) to summon up menu
\r
6370 case WM_RBUTTONUP:
\r
6371 if (GetKeyState(VK_SHIFT) & ~1) {
\r
6372 SendDlgItemMessage(hwndConsole, OPT_ConsoleText,
\r
6373 WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
6376 HMENU hmenu = LoadIcsTextMenu(icsTextMenuEntry);
\r
6377 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
6378 if (sel.cpMin == sel.cpMax) {
\r
6379 EnableMenuItem(hmenu, IDM_Copy, MF_BYCOMMAND|MF_GRAYED);
\r
6380 EnableMenuItem(hmenu, IDM_QuickPaste, MF_BYCOMMAND|MF_GRAYED);
\r
6382 if (!IsClipboardFormatAvailable(CF_TEXT)) {
\r
6383 EnableMenuItem(hmenu, IDM_Paste, MF_BYCOMMAND|MF_GRAYED);
\r
6385 pt.x = LOWORD(lParam);
\r
6386 pt.y = HIWORD(lParam);
\r
6387 MenuPopup(hwnd, pt, hmenu, -1);
\r
6391 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
6393 return SendMessage(hInput, message, wParam, lParam);
\r
6394 case WM_MBUTTONDOWN:
\r
6395 return SendMessage(hwnd, WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
6396 case WM_RBUTTONDOWN:
\r
6397 if (!(GetKeyState(VK_SHIFT) & ~1)) {
\r
6398 /* Move selection here if it was empty */
\r
6400 pt.x = LOWORD(lParam);
\r
6401 pt.y = HIWORD(lParam);
\r
6402 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
6403 if (sel.cpMin == sel.cpMax) {
\r
6404 sel.cpMin = SendMessage(hwnd, EM_CHARFROMPOS, 0, (LPARAM)&pt); /*doc is wrong*/
\r
6405 sel.cpMax = sel.cpMin;
\r
6406 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
6408 SendMessage(hwnd, EM_HIDESELECTION, FALSE, FALSE);
\r
6412 switch (LOWORD(wParam)) {
\r
6413 case IDM_QuickPaste:
\r
6415 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
6416 if (sel.cpMin == sel.cpMax) {
\r
6417 MessageBeep(MB_ICONEXCLAMATION);
\r
6420 SendMessage(hwnd, WM_COPY, 0, 0);
\r
6421 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
6422 SendMessage(hInput, WM_PASTE, 0, 0);
\r
6427 SendMessage(hwnd, WM_CUT, 0, 0);
\r
6430 SendMessage(hwnd, WM_PASTE, 0, 0);
\r
6433 SendMessage(hwnd, WM_COPY, 0, 0);
\r
6437 int i = LOWORD(wParam) - IDM_CommandX;
\r
6438 if (i >= 0 && i < ICS_TEXT_MENU_SIZE &&
\r
6439 icsTextMenuEntry[i].command != NULL) {
\r
6440 CommandX(hwnd, icsTextMenuEntry[i].command,
\r
6441 icsTextMenuEntry[i].getname,
\r
6442 icsTextMenuEntry[i].immediate);
\r
6450 return (*consoleTextWindowProc)(hwnd, message, wParam, lParam);
\r
6453 WNDPROC consoleInputWindowProc;
\r
6456 ConsoleInputSubclass(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
6458 char buf[MSG_SIZ];
\r
6460 static BOOL sendNextChar = FALSE;
\r
6461 static BOOL quoteNextChar = FALSE;
\r
6462 InputSource *is = consoleInputSource;
\r
6466 switch (message) {
\r
6468 if (!appData.localLineEditing || sendNextChar) {
\r
6469 is->buf[0] = (CHAR) wParam;
\r
6471 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
6472 sendNextChar = FALSE;
\r
6475 if (quoteNextChar) {
\r
6476 buf[0] = (char) wParam;
\r
6477 buf[1] = NULLCHAR;
\r
6478 SendMessage(hwnd, EM_REPLACESEL, TRUE, (LPARAM) buf);
\r
6479 quoteNextChar = FALSE;
\r
6483 case '\r': /* Enter key */
\r
6484 is->count = GetWindowText(hwnd, is->buf, INPUT_SOURCE_BUF_SIZE-1);
\r
6485 if (consoleEcho) SaveInHistory(is->buf);
\r
6486 is->buf[is->count++] = '\n';
\r
6487 is->buf[is->count] = NULLCHAR;
\r
6488 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
6489 if (consoleEcho) {
\r
6490 ConsoleOutput(is->buf, is->count, TRUE);
\r
6491 } else if (appData.localLineEditing) {
\r
6492 ConsoleOutput("\n", 1, TRUE);
\r
6495 case '\033': /* Escape key */
\r
6496 SetWindowText(hwnd, "");
\r
6497 cf.cbSize = sizeof(CHARFORMAT);
\r
6498 cf.dwMask = CFM_COLOR|CFM_BOLD|CFM_ITALIC|CFM_UNDERLINE|CFM_STRIKEOUT;
\r
6499 if (consoleEcho) {
\r
6500 cf.crTextColor = textAttribs[ColorNormal].color;
\r
6502 cf.crTextColor = COLOR_ECHOOFF;
\r
6504 cf.dwEffects = textAttribs[ColorNormal].effects;
\r
6505 SendMessage(hwnd, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&cf);
\r
6507 case '\t': /* Tab key */
\r
6508 if (GetKeyState(VK_SHIFT) < 0) {
\r
6510 SetFocus(GetDlgItem(hwndConsole, OPT_ConsoleText));
\r
6513 if (IsIconic(hwndMain)) ShowWindow(hwndMain, SW_RESTORE);
\r
6514 if (buttonDesc[0].hwnd) {
\r
6515 SetFocus(buttonDesc[0].hwnd);
\r
6517 SetFocus(hwndMain);
\r
6521 case '\023': /* Ctrl+S */
\r
6522 sendNextChar = TRUE;
\r
6524 case '\021': /* Ctrl+Q */
\r
6525 quoteNextChar = TRUE;
\r
6535 GetWindowText(hwnd, buf, MSG_SIZ);
\r
6536 p = PrevInHistory(buf);
\r
6538 SetWindowText(hwnd, p);
\r
6539 sel.cpMin = 999999;
\r
6540 sel.cpMax = 999999;
\r
6541 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
6546 p = NextInHistory();
\r
6548 SetWindowText(hwnd, p);
\r
6549 sel.cpMin = 999999;
\r
6550 sel.cpMax = 999999;
\r
6551 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
6557 if (!(GetKeyState(VK_CONTROL) & ~1)) break;
\r
6561 SendDlgItemMessage(hwndConsole, OPT_ConsoleText, message, wParam, lParam);
\r
6565 case WM_MBUTTONDOWN:
\r
6566 SendDlgItemMessage(hwndConsole, OPT_ConsoleText,
\r
6567 WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
6569 case WM_RBUTTONUP:
\r
6570 if (GetKeyState(VK_SHIFT) & ~1) {
\r
6571 SendDlgItemMessage(hwndConsole, OPT_ConsoleText,
\r
6572 WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
6576 hmenu = LoadMenu(hInst, "InputMenu");
\r
6577 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
6578 if (sel.cpMin == sel.cpMax) {
\r
6579 EnableMenuItem(hmenu, IDM_Copy, MF_BYCOMMAND|MF_GRAYED);
\r
6580 EnableMenuItem(hmenu, IDM_Cut, MF_BYCOMMAND|MF_GRAYED);
\r
6582 if (!IsClipboardFormatAvailable(CF_TEXT)) {
\r
6583 EnableMenuItem(hmenu, IDM_Paste, MF_BYCOMMAND|MF_GRAYED);
\r
6585 pt.x = LOWORD(lParam);
\r
6586 pt.y = HIWORD(lParam);
\r
6587 MenuPopup(hwnd, pt, hmenu, -1);
\r
6591 switch (LOWORD(wParam)) {
\r
6593 SendMessage(hwnd, EM_UNDO, 0, 0);
\r
6595 case IDM_SelectAll:
\r
6597 sel.cpMax = -1; /*999999?*/
\r
6598 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
6601 SendMessage(hwnd, WM_CUT, 0, 0);
\r
6604 SendMessage(hwnd, WM_PASTE, 0, 0);
\r
6607 SendMessage(hwnd, WM_COPY, 0, 0);
\r
6612 return (*consoleInputWindowProc)(hwnd, message, wParam, lParam);
\r
6615 #define CO_MAX 100000
\r
6616 #define CO_TRIM 1000
\r
6619 ConsoleWndProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
6621 static SnapData sd;
\r
6622 HWND hText, hInput;
\r
6624 static int sizeX, sizeY;
\r
6625 int newSizeX, newSizeY;
\r
6629 hText = GetDlgItem(hDlg, OPT_ConsoleText);
\r
6630 hInput = GetDlgItem(hDlg, OPT_ConsoleInput);
\r
6632 switch (message) {
\r
6634 if (((NMHDR*)lParam)->code == EN_LINK)
\r
6636 ENLINK *pLink = (ENLINK*)lParam;
\r
6637 if (pLink->msg == WM_LBUTTONUP)
\r
6641 tr.chrg = pLink->chrg;
\r
6642 tr.lpstrText = malloc(1+tr.chrg.cpMax-tr.chrg.cpMin);
\r
6643 SendMessage(hText, EM_GETTEXTRANGE, 0, (LPARAM)&tr);
\r
6644 ShellExecute(NULL, "open", tr.lpstrText, NULL, NULL, SW_SHOW);
\r
6645 free(tr.lpstrText);
\r
6649 case WM_INITDIALOG: /* message: initialize dialog box */
\r
6650 hwndConsole = hDlg;
\r
6652 consoleTextWindowProc = (WNDPROC)
\r
6653 SetWindowLong(hText, GWL_WNDPROC, (LONG) ConsoleTextSubclass);
\r
6654 SendMessage(hText, EM_SETBKGNDCOLOR, FALSE, consoleBackgroundColor);
\r
6655 consoleInputWindowProc = (WNDPROC)
\r
6656 SetWindowLong(hInput, GWL_WNDPROC, (LONG) ConsoleInputSubclass);
\r
6657 SendMessage(hInput, EM_SETBKGNDCOLOR, FALSE, consoleBackgroundColor);
\r
6658 Colorize(ColorNormal, TRUE);
\r
6659 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM) &consoleCF);
\r
6660 ChangedConsoleFont();
\r
6661 GetClientRect(hDlg, &rect);
\r
6662 sizeX = rect.right;
\r
6663 sizeY = rect.bottom;
\r
6664 if (wpConsole.x != CW_USEDEFAULT && wpConsole.y != CW_USEDEFAULT &&
\r
6665 wpConsole.width != CW_USEDEFAULT && wpConsole.height != CW_USEDEFAULT) {
\r
6666 WINDOWPLACEMENT wp;
\r
6667 EnsureOnScreen(&wpConsole.x, &wpConsole.y, 0, 0);
\r
6668 wp.length = sizeof(WINDOWPLACEMENT);
\r
6670 wp.showCmd = SW_SHOW;
\r
6671 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
6672 wp.rcNormalPosition.left = wpConsole.x;
\r
6673 wp.rcNormalPosition.right = wpConsole.x + wpConsole.width;
\r
6674 wp.rcNormalPosition.top = wpConsole.y;
\r
6675 wp.rcNormalPosition.bottom = wpConsole.y + wpConsole.height;
\r
6676 SetWindowPlacement(hDlg, &wp);
\r
6679 // [HGM] Chessknight's change 2004-07-13
\r
6680 else { /* Determine Defaults */
\r
6681 WINDOWPLACEMENT wp;
\r
6682 wpConsole.x = wpMain.width + 1;
\r
6683 wpConsole.y = wpMain.y;
\r
6684 wpConsole.width = screenWidth - wpMain.width;
\r
6685 wpConsole.height = wpMain.height;
\r
6686 EnsureOnScreen(&wpConsole.x, &wpConsole.y, 0, 0);
\r
6687 wp.length = sizeof(WINDOWPLACEMENT);
\r
6689 wp.showCmd = SW_SHOW;
\r
6690 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
6691 wp.rcNormalPosition.left = wpConsole.x;
\r
6692 wp.rcNormalPosition.right = wpConsole.x + wpConsole.width;
\r
6693 wp.rcNormalPosition.top = wpConsole.y;
\r
6694 wp.rcNormalPosition.bottom = wpConsole.y + wpConsole.height;
\r
6695 SetWindowPlacement(hDlg, &wp);
\r
6698 // Allow hText to highlight URLs and send notifications on them
\r
6699 wMask = (WORD) SendMessage(hText, EM_GETEVENTMASK, 0, 0L);
\r
6700 SendMessage(hText, EM_SETEVENTMASK, 0, wMask | ENM_LINK);
\r
6701 SendMessage(hText, EM_AUTOURLDETECT, TRUE, 0L);
\r
6702 SetWindowLong(hText, GWL_USERDATA, 79); // initialize the text window's width
\r
6716 if (IsIconic(hDlg)) break;
\r
6717 newSizeX = LOWORD(lParam);
\r
6718 newSizeY = HIWORD(lParam);
\r
6719 if (sizeX != newSizeX || sizeY != newSizeY) {
\r
6720 RECT rectText, rectInput;
\r
6722 int newTextHeight, newTextWidth;
\r
6723 GetWindowRect(hText, &rectText);
\r
6724 newTextWidth = rectText.right - rectText.left + newSizeX - sizeX;
\r
6725 newTextHeight = rectText.bottom - rectText.top + newSizeY - sizeY;
\r
6726 if (newTextHeight < 0) {
\r
6727 newSizeY += -newTextHeight;
\r
6728 newTextHeight = 0;
\r
6730 SetWindowPos(hText, NULL, 0, 0,
\r
6731 newTextWidth, newTextHeight, SWP_NOZORDER|SWP_NOMOVE);
\r
6732 GetWindowRect(hInput, &rectInput); /* gives screen coords */
\r
6733 pt.x = rectInput.left;
\r
6734 pt.y = rectInput.top + newSizeY - sizeY;
\r
6735 ScreenToClient(hDlg, &pt);
\r
6736 SetWindowPos(hInput, NULL,
\r
6737 pt.x, pt.y, /* needs client coords */
\r
6738 rectInput.right - rectInput.left + newSizeX - sizeX,
\r
6739 rectInput.bottom - rectInput.top, SWP_NOZORDER);
\r
6745 case WM_GETMINMAXINFO:
\r
6746 /* Prevent resizing window too small */
\r
6747 mmi = (MINMAXINFO *) lParam;
\r
6748 mmi->ptMinTrackSize.x = 100;
\r
6749 mmi->ptMinTrackSize.y = 100;
\r
6752 /* [AS] Snapping */
\r
6753 case WM_ENTERSIZEMOVE:
\r
6754 return OnEnterSizeMove( &sd, hDlg, wParam, lParam );
\r
6757 return OnSizing( &sd, hDlg, wParam, lParam );
\r
6760 return OnMoving( &sd, hDlg, wParam, lParam );
\r
6762 case WM_EXITSIZEMOVE:
\r
6763 UpdateICSWidth(hText);
\r
6764 return OnExitSizeMove( &sd, hDlg, wParam, lParam );
\r
6767 return DefWindowProc(hDlg, message, wParam, lParam);
\r
6775 if (hwndConsole) return;
\r
6776 hCons = CreateDialog(hInst, szConsoleName, 0, NULL);
\r
6777 SendMessage(hCons, WM_INITDIALOG, 0, 0);
\r
6782 ConsoleOutput(char* data, int length, int forceVisible)
\r
6787 char buf[CO_MAX+1];
\r
6790 static int delayLF = 0;
\r
6791 CHARRANGE savesel, sel;
\r
6793 if (hwndConsole == NULL || length > CO_MAX-100 || length == 0) return;
\r
6801 while (length--) {
\r
6809 } else if (*p == '\007') {
\r
6810 MyPlaySound(&sounds[(int)SoundBell]);
\r
6817 hText = GetDlgItem(hwndConsole, OPT_ConsoleText);
\r
6818 SendMessage(hText, EM_HIDESELECTION, TRUE, FALSE);
\r
6819 /* Save current selection */
\r
6820 SendMessage(hText, EM_EXGETSEL, 0, (LPARAM)&savesel);
\r
6821 exlen = GetWindowTextLength(hText);
\r
6822 /* Find out whether current end of text is visible */
\r
6823 SendMessage(hText, EM_GETRECT, 0, (LPARAM) &rect);
\r
6824 SendMessage(hText, EM_POSFROMCHAR, (WPARAM) &pEnd, exlen);
\r
6825 /* Trim existing text if it's too long */
\r
6826 if (exlen + (q - buf) > CO_MAX) {
\r
6827 trim = (CO_TRIM > (q - buf)) ? CO_TRIM : (q - buf);
\r
6830 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
6831 SendMessage(hText, EM_REPLACESEL, 0, (LPARAM)"");
\r
6833 savesel.cpMin -= trim;
\r
6834 savesel.cpMax -= trim;
\r
6835 if (exlen < 0) exlen = 0;
\r
6836 if (savesel.cpMin < 0) savesel.cpMin = 0;
\r
6837 if (savesel.cpMax < savesel.cpMin) savesel.cpMax = savesel.cpMin;
\r
6839 /* Append the new text */
\r
6840 sel.cpMin = exlen;
\r
6841 sel.cpMax = exlen;
\r
6842 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
6843 SendMessage(hText, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&consoleCF);
\r
6844 SendMessage(hText, EM_REPLACESEL, 0, (LPARAM) buf);
\r
6845 if (forceVisible || exlen == 0 ||
\r
6846 (rect.left <= pEnd.x && pEnd.x < rect.right &&
\r
6847 rect.top <= pEnd.y && pEnd.y < rect.bottom)) {
\r
6848 /* Scroll to make new end of text visible if old end of text
\r
6849 was visible or new text is an echo of user typein */
\r
6850 sel.cpMin = 9999999;
\r
6851 sel.cpMax = 9999999;
\r
6852 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
6853 SendMessage(hText, EM_HIDESELECTION, FALSE, FALSE);
\r
6854 SendMessage(hText, EM_SCROLLCARET, 0, 0);
\r
6855 SendMessage(hText, EM_HIDESELECTION, TRUE, FALSE);
\r
6857 if (savesel.cpMax == exlen || forceVisible) {
\r
6858 /* Move insert point to new end of text if it was at the old
\r
6859 end of text or if the new text is an echo of user typein */
\r
6860 sel.cpMin = 9999999;
\r
6861 sel.cpMax = 9999999;
\r
6862 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
6864 /* Restore previous selection */
\r
6865 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&savesel);
\r
6867 SendMessage(hText, EM_HIDESELECTION, FALSE, FALSE);
\r
6874 DisplayHoldingsCount(HDC hdc, int x, int y, int rightAlign, int copyNumber)
\r
6878 COLORREF oldFg, oldBg;
\r
6882 if(copyNumber > 1) sprintf(buf, "%d", copyNumber); else buf[0] = 0;
\r
6884 oldFg = SetTextColor(hdc, RGB(255, 255, 255)); /* white */
\r
6885 oldBg = SetBkColor(hdc, RGB(0, 0, 0)); /* black */
\r
6886 oldFont = SelectObject(hdc, font[boardSize][CLOCK_FONT]->hf);
\r
6889 rect.right = x + squareSize;
\r
6891 rect.bottom = y + squareSize;
\r
6894 ExtTextOut(hdc, x + MESSAGE_LINE_LEFTMARGIN
\r
6895 + (rightAlign ? (squareSize*2)/3 : 0),
\r
6896 y, ETO_CLIPPED|ETO_OPAQUE,
\r
6897 &rect, str, strlen(str), NULL);
\r
6899 (void) SetTextColor(hdc, oldFg);
\r
6900 (void) SetBkColor(hdc, oldBg);
\r
6901 (void) SelectObject(hdc, oldFont);
\r
6905 DisplayAClock(HDC hdc, int timeRemaining, int highlight,
\r
6906 RECT *rect, char *color, char *flagFell)
\r
6910 COLORREF oldFg, oldBg;
\r
6913 if (appData.clockMode) {
\r
6915 sprintf(buf, "%c %s %s", color[0], TimeString(timeRemaining), flagFell);
\r
6917 sprintf(buf, "%s:%c%s %s", color, (logoHeight>0 ? 0 : ' '), TimeString(timeRemaining), flagFell);
\r
6924 oldFg = SetTextColor(hdc, RGB(255, 255, 255)); /* white */
\r
6925 oldBg = SetBkColor(hdc, RGB(0, 0, 0)); /* black */
\r
6927 oldFg = SetTextColor(hdc, RGB(0, 0, 0)); /* black */
\r
6928 oldBg = SetBkColor(hdc, RGB(255, 255, 255)); /* white */
\r
6930 oldFont = SelectObject(hdc, font[boardSize][CLOCK_FONT]->hf);
\r
6934 ExtTextOut(hdc, rect->left + MESSAGE_LINE_LEFTMARGIN,
\r
6935 rect->top, ETO_CLIPPED|ETO_OPAQUE,
\r
6936 rect, str, strlen(str), NULL);
\r
6937 if(logoHeight > 0 && appData.clockMode) {
\r
6939 sprintf(buf, "%s %s", buf+7, flagFell);
\r
6940 r.top = rect->top + logoHeight/2;
\r
6941 r.left = rect->left;
\r
6942 r.right = rect->right;
\r
6943 r.bottom = rect->bottom;
\r
6944 ExtTextOut(hdc, rect->left + MESSAGE_LINE_LEFTMARGIN,
\r
6945 r.top, ETO_CLIPPED|ETO_OPAQUE,
\r
6946 &r, str, strlen(str), NULL);
\r
6948 (void) SetTextColor(hdc, oldFg);
\r
6949 (void) SetBkColor(hdc, oldBg);
\r
6950 (void) SelectObject(hdc, oldFont);
\r
6955 DoReadFile(HANDLE hFile, char *buf, int count, DWORD *outCount,
\r
6961 if( count <= 0 ) {
\r
6962 if (appData.debugMode) {
\r
6963 fprintf( debugFP, "DoReadFile: trying to read past end of buffer, overflow = %d\n", count );
\r
6966 return ERROR_INVALID_USER_BUFFER;
\r
6969 ResetEvent(ovl->hEvent);
\r
6970 ovl->Offset = ovl->OffsetHigh = 0;
\r
6971 ok = ReadFile(hFile, buf, count, outCount, ovl);
\r
6975 err = GetLastError();
\r
6976 if (err == ERROR_IO_PENDING) {
\r
6977 ok = GetOverlappedResult(hFile, ovl, outCount, TRUE);
\r
6981 err = GetLastError();
\r
6988 DoWriteFile(HANDLE hFile, char *buf, int count, DWORD *outCount,
\r
6993 ResetEvent(ovl->hEvent);
\r
6994 ovl->Offset = ovl->OffsetHigh = 0;
\r
6995 ok = WriteFile(hFile, buf, count, outCount, ovl);
\r
6999 err = GetLastError();
\r
7000 if (err == ERROR_IO_PENDING) {
\r
7001 ok = GetOverlappedResult(hFile, ovl, outCount, TRUE);
\r
7005 err = GetLastError();
\r
7011 /* [AS] If input is line by line and a line exceed the buffer size, force an error */
\r
7012 void CheckForInputBufferFull( InputSource * is )
\r
7014 if( is->lineByLine && (is->next - is->buf) >= INPUT_SOURCE_BUF_SIZE ) {
\r
7015 /* Look for end of line */
\r
7016 char * p = is->buf;
\r
7018 while( p < is->next && *p != '\n' ) {
\r
7022 if( p >= is->next ) {
\r
7023 if (appData.debugMode) {
\r
7024 fprintf( debugFP, "Input line exceeded buffer size (source id=%lu)\n", is->id );
\r
7027 is->error = ERROR_BROKEN_PIPE; /* [AS] Just any non-successful code! */
\r
7028 is->count = (DWORD) -1;
\r
7029 is->next = is->buf;
\r
7035 InputThread(LPVOID arg)
\r
7040 is = (InputSource *) arg;
\r
7041 ovl.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
\r
7042 ovl.Internal = ovl.InternalHigh = ovl.Offset = ovl.OffsetHigh = 0;
\r
7043 while (is->hThread != NULL) {
\r
7044 is->error = DoReadFile(is->hFile, is->next,
\r
7045 INPUT_SOURCE_BUF_SIZE - (is->next - is->buf),
\r
7046 &is->count, &ovl);
\r
7047 if (is->error == NO_ERROR) {
\r
7048 is->next += is->count;
\r
7050 if (is->error == ERROR_BROKEN_PIPE) {
\r
7051 /* Correct for MS brain damage. EOF reading a pipe is not an error. */
\r
7054 is->count = (DWORD) -1;
\r
7055 /* [AS] The (is->count <= 0) check below is not useful for unsigned values! */
\r
7060 CheckForInputBufferFull( is );
\r
7062 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
7064 if( is->count == ((DWORD) -1) ) break; /* [AS] */
\r
7066 if (is->count <= 0) break; /* Quit on EOF or error */
\r
7069 CloseHandle(ovl.hEvent);
\r
7070 CloseHandle(is->hFile);
\r
7072 if (appData.debugMode) {
\r
7073 fprintf( debugFP, "Input thread terminated (id=%lu, error=%d, count=%ld)\n", is->id, is->error, is->count );
\r
7080 /* Windows 95 beta 2 won't let you do overlapped i/o on a console or pipe */
\r
7082 NonOvlInputThread(LPVOID arg)
\r
7089 is = (InputSource *) arg;
\r
7090 while (is->hThread != NULL) {
\r
7091 is->error = ReadFile(is->hFile, is->next,
\r
7092 INPUT_SOURCE_BUF_SIZE - (is->next - is->buf),
\r
7093 &is->count, NULL) ? NO_ERROR : GetLastError();
\r
7094 if (is->error == NO_ERROR) {
\r
7095 /* Change CRLF to LF */
\r
7096 if (is->next > is->buf) {
\r
7098 i = is->count + 1;
\r
7106 if (prev == '\r' && *p == '\n') {
\r
7118 if (is->error == ERROR_BROKEN_PIPE) {
\r
7119 /* Correct for MS brain damage. EOF reading a pipe is not an error. */
\r
7122 is->count = (DWORD) -1;
\r
7126 CheckForInputBufferFull( is );
\r
7128 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
7130 if( is->count == ((DWORD) -1) ) break; /* [AS] */
\r
7132 if (is->count < 0) break; /* Quit on error */
\r
7134 CloseHandle(is->hFile);
\r
7139 SocketInputThread(LPVOID arg)
\r
7143 is = (InputSource *) arg;
\r
7144 while (is->hThread != NULL) {
\r
7145 is->count = recv(is->sock, is->buf, INPUT_SOURCE_BUF_SIZE, 0);
\r
7146 if ((int)is->count == SOCKET_ERROR) {
\r
7147 is->count = (DWORD) -1;
\r
7148 is->error = WSAGetLastError();
\r
7150 is->error = NO_ERROR;
\r
7151 is->next += is->count;
\r
7152 if (is->count == 0 && is->second == is) {
\r
7153 /* End of file on stderr; quit with no message */
\r
7157 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
7159 if( is->count == ((DWORD) -1) ) break; /* [AS] */
\r
7161 if (is->count <= 0) break; /* Quit on EOF or error */
\r
7167 InputEvent(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
7171 is = (InputSource *) lParam;
\r
7172 if (is->lineByLine) {
\r
7173 /* Feed in lines one by one */
\r
7174 char *p = is->buf;
\r
7176 while (q < is->next) {
\r
7177 if (*q++ == '\n') {
\r
7178 (is->func)(is, is->closure, p, q - p, NO_ERROR);
\r
7183 /* Move any partial line to the start of the buffer */
\r
7185 while (p < is->next) {
\r
7190 if (is->error != NO_ERROR || is->count == 0) {
\r
7191 /* Notify backend of the error. Note: If there was a partial
\r
7192 line at the end, it is not flushed through. */
\r
7193 (is->func)(is, is->closure, is->buf, is->count, is->error);
\r
7196 /* Feed in the whole chunk of input at once */
\r
7197 (is->func)(is, is->closure, is->buf, is->count, is->error);
\r
7198 is->next = is->buf;
\r
7202 /*---------------------------------------------------------------------------*\
\r
7204 * Menu enables. Used when setting various modes.
\r
7206 \*---------------------------------------------------------------------------*/
\r
7214 GreyRevert(Boolean grey)
\r
7215 { // [HGM] vari: for retracting variations in local mode
\r
7216 HMENU hmenu = GetMenu(hwndMain);
\r
7217 EnableMenuItem(hmenu, IDM_Revert, MF_BYCOMMAND|(grey ? MF_GRAYED : MF_ENABLED));
\r
7221 SetMenuEnables(HMENU hmenu, Enables *enab)
\r
7223 while (enab->item > 0) {
\r
7224 (void) EnableMenuItem(hmenu, enab->item, enab->flags);
\r
7229 Enables gnuEnables[] = {
\r
7230 { IDM_MailMove, MF_BYCOMMAND|MF_GRAYED },
\r
7231 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_GRAYED },
\r
7232 { IDM_IcsClient, MF_BYCOMMAND|MF_GRAYED },
\r
7233 { IDM_Accept, MF_BYCOMMAND|MF_GRAYED },
\r
7234 { IDM_Decline, MF_BYCOMMAND|MF_GRAYED },
\r
7235 { IDM_Rematch, MF_BYCOMMAND|MF_GRAYED },
\r
7236 { IDM_Adjourn, MF_BYCOMMAND|MF_GRAYED },
\r
7237 { IDM_StopExamining, MF_BYCOMMAND|MF_GRAYED },
\r
7238 { IDM_StopObserving, MF_BYCOMMAND|MF_GRAYED },
\r
7239 { IDM_Revert, MF_BYCOMMAND|MF_GRAYED },
\r
7240 { IDM_NewChat, MF_BYCOMMAND|MF_GRAYED },
\r
7244 Enables icsEnables[] = {
\r
7245 { IDM_MailMove, MF_BYCOMMAND|MF_GRAYED },
\r
7246 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_GRAYED },
\r
7247 { IDM_MachineWhite, MF_BYCOMMAND|MF_GRAYED },
\r
7248 { IDM_MachineBlack, MF_BYCOMMAND|MF_GRAYED },
\r
7249 { IDM_TwoMachines, MF_BYCOMMAND|MF_GRAYED },
\r
7250 { IDM_MachineBoth, MF_BYCOMMAND|MF_GRAYED },
\r
7251 { IDM_AnalysisMode, MF_BYCOMMAND|MF_ENABLED },
\r
7252 { IDM_AnalyzeFile, MF_BYCOMMAND|MF_GRAYED },
\r
7253 { IDM_TimeControl, MF_BYCOMMAND|MF_GRAYED },
\r
7254 { IDM_MoveNow, MF_BYCOMMAND|MF_GRAYED },
\r
7255 { IDM_Hint, MF_BYCOMMAND|MF_GRAYED },
\r
7256 { IDM_Book, MF_BYCOMMAND|MF_GRAYED },
\r
7257 { IDM_IcsOptions, MF_BYCOMMAND|MF_ENABLED },
\r
7258 { IDM_Engine1Options, MF_BYCOMMAND|MF_GRAYED },
\r
7259 { IDM_Engine2Options, MF_BYCOMMAND|MF_GRAYED },
\r
7264 Enables zippyEnables[] = {
\r
7265 { IDM_MoveNow, MF_BYCOMMAND|MF_ENABLED },
\r
7266 { IDM_Hint, MF_BYCOMMAND|MF_ENABLED },
\r
7267 { IDM_Book, MF_BYCOMMAND|MF_ENABLED },
\r
7268 { IDM_Engine1Options, MF_BYCOMMAND|MF_ENABLED },
\r
7273 Enables ncpEnables[] = {
\r
7274 { IDM_MailMove, MF_BYCOMMAND|MF_GRAYED },
\r
7275 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_GRAYED },
\r
7276 { IDM_MachineWhite, MF_BYCOMMAND|MF_GRAYED },
\r
7277 { IDM_MachineBlack, MF_BYCOMMAND|MF_GRAYED },
\r
7278 { IDM_TwoMachines, MF_BYCOMMAND|MF_GRAYED },
\r
7279 { IDM_AnalysisMode, MF_BYCOMMAND|MF_GRAYED },
\r
7280 { IDM_AnalyzeFile, MF_BYCOMMAND|MF_GRAYED },
\r
7281 { IDM_IcsClient, MF_BYCOMMAND|MF_GRAYED },
\r
7282 { ACTION_POS, MF_BYPOSITION|MF_GRAYED },
\r
7283 { IDM_Revert, MF_BYCOMMAND|MF_GRAYED },
\r
7284 { IDM_MoveNow, MF_BYCOMMAND|MF_GRAYED },
\r
7285 { IDM_RetractMove, MF_BYCOMMAND|MF_GRAYED },
\r
7286 { IDM_TimeControl, MF_BYCOMMAND|MF_GRAYED },
\r
7287 { IDM_Hint, MF_BYCOMMAND|MF_GRAYED },
\r
7288 { IDM_Book, MF_BYCOMMAND|MF_GRAYED },
\r
7289 { IDM_MachineBoth, MF_BYCOMMAND|MF_GRAYED },
\r
7290 { IDM_NewChat, MF_BYCOMMAND|MF_GRAYED },
\r
7291 { IDM_Engine1Options, MF_BYCOMMAND|MF_GRAYED },
\r
7292 { IDM_Engine2Options, MF_BYCOMMAND|MF_GRAYED },
\r
7296 Enables trainingOnEnables[] = {
\r
7297 { IDM_EditComment, MF_BYCOMMAND|MF_GRAYED },
\r
7298 { IDM_Pause, MF_BYCOMMAND|MF_GRAYED },
\r
7299 { IDM_Forward, MF_BYCOMMAND|MF_GRAYED },
\r
7300 { IDM_Backward, MF_BYCOMMAND|MF_GRAYED },
\r
7301 { IDM_ToEnd, MF_BYCOMMAND|MF_GRAYED },
\r
7302 { IDM_ToStart, MF_BYCOMMAND|MF_GRAYED },
\r
7303 { IDM_MoveNow, MF_BYCOMMAND|MF_GRAYED },
\r
7304 { IDM_TruncateGame, MF_BYCOMMAND|MF_GRAYED },
\r
7308 Enables trainingOffEnables[] = {
\r
7309 { IDM_EditComment, MF_BYCOMMAND|MF_ENABLED },
\r
7310 { IDM_Pause, MF_BYCOMMAND|MF_ENABLED },
\r
7311 { IDM_Forward, MF_BYCOMMAND|MF_ENABLED },
\r
7312 { IDM_Backward, MF_BYCOMMAND|MF_ENABLED },
\r
7313 { IDM_ToEnd, MF_BYCOMMAND|MF_ENABLED },
\r
7314 { IDM_ToStart, MF_BYCOMMAND|MF_ENABLED },
\r
7315 { IDM_MoveNow, MF_BYCOMMAND|MF_ENABLED },
\r
7316 { IDM_TruncateGame, MF_BYCOMMAND|MF_ENABLED },
\r
7320 /* These modify either ncpEnables or gnuEnables */
\r
7321 Enables cmailEnables[] = {
\r
7322 { IDM_MailMove, MF_BYCOMMAND|MF_ENABLED },
\r
7323 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_ENABLED },
\r
7324 { ACTION_POS, MF_BYPOSITION|MF_ENABLED },
\r
7325 { IDM_CallFlag, MF_BYCOMMAND|MF_GRAYED },
\r
7326 { IDM_Draw, MF_BYCOMMAND|MF_ENABLED },
\r
7327 { IDM_Adjourn, MF_BYCOMMAND|MF_GRAYED },
\r
7328 { IDM_Abort, MF_BYCOMMAND|MF_GRAYED },
\r
7332 Enables machineThinkingEnables[] = {
\r
7333 { IDM_LoadGame, MF_BYCOMMAND|MF_GRAYED },
\r
7334 { IDM_LoadNextGame, MF_BYCOMMAND|MF_GRAYED },
\r
7335 { IDM_LoadPrevGame, MF_BYCOMMAND|MF_GRAYED },
\r
7336 { IDM_ReloadGame, MF_BYCOMMAND|MF_GRAYED },
\r
7337 { IDM_PasteGame, MF_BYCOMMAND|MF_GRAYED },
\r
7338 { IDM_LoadPosition, MF_BYCOMMAND|MF_GRAYED },
\r
7339 { IDM_LoadNextPosition, MF_BYCOMMAND|MF_GRAYED },
\r
7340 { IDM_LoadPrevPosition, MF_BYCOMMAND|MF_GRAYED },
\r
7341 { IDM_ReloadPosition, MF_BYCOMMAND|MF_GRAYED },
\r
7342 { IDM_PastePosition, MF_BYCOMMAND|MF_GRAYED },
\r
7343 { IDM_MachineWhite, MF_BYCOMMAND|MF_GRAYED },
\r
7344 { IDM_MachineBlack, MF_BYCOMMAND|MF_GRAYED },
\r
7345 { IDM_TwoMachines, MF_BYCOMMAND|MF_GRAYED },
\r
7346 { IDM_TypeInMove, MF_BYCOMMAND|MF_GRAYED },
\r
7347 { IDM_RetractMove, MF_BYCOMMAND|MF_GRAYED },
\r
7351 Enables userThinkingEnables[] = {
\r
7352 { IDM_LoadGame, MF_BYCOMMAND|MF_ENABLED },
\r
7353 { IDM_LoadNextGame, MF_BYCOMMAND|MF_ENABLED },
\r
7354 { IDM_LoadPrevGame, MF_BYCOMMAND|MF_ENABLED },
\r
7355 { IDM_ReloadGame, MF_BYCOMMAND|MF_ENABLED },
\r
7356 { IDM_PasteGame, MF_BYCOMMAND|MF_ENABLED },
\r
7357 { IDM_LoadPosition, MF_BYCOMMAND|MF_ENABLED },
\r
7358 { IDM_LoadNextPosition, MF_BYCOMMAND|MF_ENABLED },
\r
7359 { IDM_LoadPrevPosition, MF_BYCOMMAND|MF_ENABLED },
\r
7360 { IDM_ReloadPosition, MF_BYCOMMAND|MF_ENABLED },
\r
7361 { IDM_PastePosition, MF_BYCOMMAND|MF_ENABLED },
\r
7362 { IDM_MachineWhite, MF_BYCOMMAND|MF_ENABLED },
\r
7363 { IDM_MachineBlack, MF_BYCOMMAND|MF_ENABLED },
\r
7364 { IDM_TwoMachines, MF_BYCOMMAND|MF_ENABLED },
\r
7365 { IDM_TypeInMove, MF_BYCOMMAND|MF_ENABLED },
\r
7366 { IDM_RetractMove, MF_BYCOMMAND|MF_ENABLED },
\r
7370 /*---------------------------------------------------------------------------*\
\r
7372 * Front-end interface functions exported by XBoard.
\r
7373 * Functions appear in same order as prototypes in frontend.h.
\r
7375 \*---------------------------------------------------------------------------*/
\r
7379 static UINT prevChecked = 0;
\r
7380 static int prevPausing = 0;
\r
7383 if (pausing != prevPausing) {
\r
7384 prevPausing = pausing;
\r
7385 (void) CheckMenuItem(GetMenu(hwndMain), IDM_Pause,
\r
7386 MF_BYCOMMAND|(pausing ? MF_CHECKED : MF_UNCHECKED));
\r
7387 if (hwndPause) SetWindowText(hwndPause, pausing ? "C" : "P");
\r
7390 switch (gameMode) {
\r
7391 case BeginningOfGame:
\r
7392 if (appData.icsActive)
\r
7393 nowChecked = IDM_IcsClient;
\r
7394 else if (appData.noChessProgram)
\r
7395 nowChecked = IDM_EditGame;
\r
7397 nowChecked = IDM_MachineBlack;
\r
7399 case MachinePlaysBlack:
\r
7400 nowChecked = IDM_MachineBlack;
\r
7402 case MachinePlaysWhite:
\r
7403 nowChecked = IDM_MachineWhite;
\r
7405 case TwoMachinesPlay:
\r
7406 nowChecked = IDM_TwoMachines;
\r
7409 nowChecked = IDM_AnalysisMode;
\r
7412 nowChecked = IDM_AnalyzeFile;
\r
7415 nowChecked = IDM_EditGame;
\r
7417 case PlayFromGameFile:
\r
7418 nowChecked = IDM_LoadGame;
\r
7420 case EditPosition:
\r
7421 nowChecked = IDM_EditPosition;
\r
7424 nowChecked = IDM_Training;
\r
7426 case IcsPlayingWhite:
\r
7427 case IcsPlayingBlack:
\r
7428 case IcsObserving:
\r
7430 nowChecked = IDM_IcsClient;
\r
7437 if (prevChecked != 0)
\r
7438 (void) CheckMenuItem(GetMenu(hwndMain),
\r
7439 prevChecked, MF_BYCOMMAND|MF_UNCHECKED);
\r
7440 if (nowChecked != 0)
\r
7441 (void) CheckMenuItem(GetMenu(hwndMain),
\r
7442 nowChecked, MF_BYCOMMAND|MF_CHECKED);
\r
7444 if (nowChecked == IDM_LoadGame || nowChecked == IDM_Training) {
\r
7445 (void) EnableMenuItem(GetMenu(hwndMain), IDM_Training,
\r
7446 MF_BYCOMMAND|MF_ENABLED);
\r
7448 (void) EnableMenuItem(GetMenu(hwndMain),
\r
7449 IDM_Training, MF_BYCOMMAND|MF_GRAYED);
\r
7452 prevChecked = nowChecked;
\r
7454 /* [DM] icsEngineAnalyze - Do a sceure check too */
\r
7455 if (appData.icsActive) {
\r
7456 if (appData.icsEngineAnalyze) {
\r
7457 (void) CheckMenuItem(GetMenu(hwndMain), IDM_AnalysisMode,
\r
7458 MF_BYCOMMAND|MF_CHECKED);
\r
7460 (void) CheckMenuItem(GetMenu(hwndMain), IDM_AnalysisMode,
\r
7461 MF_BYCOMMAND|MF_UNCHECKED);
\r
7469 HMENU hmenu = GetMenu(hwndMain);
\r
7470 SetMenuEnables(hmenu, icsEnables);
\r
7471 EnableMenuItem(GetSubMenu(hmenu, OPTIONS_POS), ICS_POS,
\r
7472 MF_BYPOSITION|MF_ENABLED);
\r
7474 if (appData.zippyPlay) {
\r
7475 SetMenuEnables(hmenu, zippyEnables);
\r
7476 if (!appData.noChessProgram) /* [DM] icsEngineAnalyze */
\r
7477 (void) EnableMenuItem(GetMenu(hwndMain), IDM_AnalysisMode,
\r
7478 MF_BYCOMMAND|MF_ENABLED);
\r
7486 SetMenuEnables(GetMenu(hwndMain), gnuEnables);
\r
7492 HMENU hmenu = GetMenu(hwndMain);
\r
7493 SetMenuEnables(hmenu, ncpEnables);
\r
7494 EnableMenuItem(GetSubMenu(hmenu, OPTIONS_POS), SOUNDS_POS,
\r
7495 MF_BYPOSITION|MF_GRAYED);
\r
7496 DrawMenuBar(hwndMain);
\r
7502 SetMenuEnables(GetMenu(hwndMain), cmailEnables);
\r
7506 SetTrainingModeOn()
\r
7509 SetMenuEnables(GetMenu(hwndMain), trainingOnEnables);
\r
7510 for (i = 0; i < N_BUTTONS; i++) {
\r
7511 if (buttonDesc[i].hwnd != NULL)
\r
7512 EnableWindow(buttonDesc[i].hwnd, FALSE);
\r
7517 VOID SetTrainingModeOff()
\r
7520 SetMenuEnables(GetMenu(hwndMain), trainingOffEnables);
\r
7521 for (i = 0; i < N_BUTTONS; i++) {
\r
7522 if (buttonDesc[i].hwnd != NULL)
\r
7523 EnableWindow(buttonDesc[i].hwnd, TRUE);
\r
7529 SetUserThinkingEnables()
\r
7531 SetMenuEnables(GetMenu(hwndMain), userThinkingEnables);
\r
7535 SetMachineThinkingEnables()
\r
7537 HMENU hMenu = GetMenu(hwndMain);
\r
7538 int flags = MF_BYCOMMAND|MF_ENABLED;
\r
7540 SetMenuEnables(hMenu, machineThinkingEnables);
\r
7542 if (gameMode == MachinePlaysBlack) {
\r
7543 (void)EnableMenuItem(hMenu, IDM_MachineBlack, flags);
\r
7544 } else if (gameMode == MachinePlaysWhite) {
\r
7545 (void)EnableMenuItem(hMenu, IDM_MachineWhite, flags);
\r
7546 } else if (gameMode == TwoMachinesPlay) {
\r
7547 (void)EnableMenuItem(hMenu, IDM_TwoMachines, flags);
\r
7553 DisplayTitle(char *str)
\r
7555 char title[MSG_SIZ], *host;
\r
7556 if (str[0] != NULLCHAR) {
\r
7557 strcpy(title, str);
\r
7558 } else if (appData.icsActive) {
\r
7559 if (appData.icsCommPort[0] != NULLCHAR)
\r
7562 host = appData.icsHost;
\r
7563 sprintf(title, "%s: %s", szTitle, host);
\r
7564 } else if (appData.noChessProgram) {
\r
7565 strcpy(title, szTitle);
\r
7567 strcpy(title, szTitle);
\r
7568 strcat(title, ": ");
\r
7569 strcat(title, first.tidy);
\r
7571 SetWindowText(hwndMain, title);
\r
7576 DisplayMessage(char *str1, char *str2)
\r
7580 int remain = MESSAGE_TEXT_MAX - 1;
\r
7583 moveErrorMessageUp = FALSE; /* turned on later by caller if needed */
\r
7584 messageText[0] = NULLCHAR;
\r
7586 len = strlen(str1);
\r
7587 if (len > remain) len = remain;
\r
7588 strncpy(messageText, str1, len);
\r
7589 messageText[len] = NULLCHAR;
\r
7592 if (*str2 && remain >= 2) {
\r
7594 strcat(messageText, " ");
\r
7597 len = strlen(str2);
\r
7598 if (len > remain) len = remain;
\r
7599 strncat(messageText, str2, len);
\r
7601 messageText[MESSAGE_TEXT_MAX - 1] = NULLCHAR;
\r
7603 if (hwndMain == NULL || IsIconic(hwndMain)) return;
\r
7607 hdc = GetDC(hwndMain);
\r
7608 oldFont = SelectObject(hdc, font[boardSize][MESSAGE_FONT]->hf);
\r
7609 ExtTextOut(hdc, messageRect.left, messageRect.top, ETO_CLIPPED|ETO_OPAQUE,
\r
7610 &messageRect, messageText, strlen(messageText), NULL);
\r
7611 (void) SelectObject(hdc, oldFont);
\r
7612 (void) ReleaseDC(hwndMain, hdc);
\r
7616 DisplayError(char *str, int error)
\r
7618 char buf[MSG_SIZ*2], buf2[MSG_SIZ];
\r
7624 len = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
\r
7625 NULL, error, LANG_NEUTRAL,
\r
7626 (LPSTR) buf2, MSG_SIZ, NULL);
\r
7628 sprintf(buf, "%s:\n%s", str, buf2);
\r
7630 ErrorMap *em = errmap;
\r
7631 while (em->err != 0 && em->err != error) em++;
\r
7632 if (em->err != 0) {
\r
7633 sprintf(buf, "%s:\n%s", str, em->msg);
\r
7635 sprintf(buf, "%s:\nError code %d", str, error);
\r
7640 ErrorPopUp("Error", buf);
\r
7645 DisplayMoveError(char *str)
\r
7647 fromX = fromY = -1;
\r
7648 ClearHighlights();
\r
7649 DrawPosition(FALSE, NULL);
\r
7650 if (appData.popupMoveErrors) {
\r
7651 ErrorPopUp("Error", str);
\r
7653 DisplayMessage(str, "");
\r
7654 moveErrorMessageUp = TRUE;
\r
7659 DisplayFatalError(char *str, int error, int exitStatus)
\r
7661 char buf[2*MSG_SIZ], buf2[MSG_SIZ];
\r
7663 char *label = exitStatus ? "Fatal Error" : "Exiting";
\r
7666 len = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
\r
7667 NULL, error, LANG_NEUTRAL,
\r
7668 (LPSTR) buf2, MSG_SIZ, NULL);
\r
7670 sprintf(buf, "%s:\n%s", str, buf2);
\r
7672 ErrorMap *em = errmap;
\r
7673 while (em->err != 0 && em->err != error) em++;
\r
7674 if (em->err != 0) {
\r
7675 sprintf(buf, "%s:\n%s", str, em->msg);
\r
7677 sprintf(buf, "%s:\nError code %d", str, error);
\r
7682 if (appData.debugMode) {
\r
7683 fprintf(debugFP, "%s: %s\n", label, str);
\r
7685 if (appData.popupExitMessage) {
\r
7686 (void) MessageBox(hwndMain, str, label, MB_OK|
\r
7687 (exitStatus ? MB_ICONSTOP : MB_ICONINFORMATION));
\r
7689 ExitEvent(exitStatus);
\r
7694 DisplayInformation(char *str)
\r
7696 (void) MessageBox(hwndMain, str, "Information", MB_OK|MB_ICONINFORMATION);
\r
7701 DisplayNote(char *str)
\r
7703 ErrorPopUp("Note", str);
\r
7708 char *title, *question, *replyPrefix;
\r
7713 QuestionDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7715 static QuestionParams *qp;
\r
7716 char reply[MSG_SIZ];
\r
7719 switch (message) {
\r
7720 case WM_INITDIALOG:
\r
7721 qp = (QuestionParams *) lParam;
\r
7722 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
7723 SetWindowText(hDlg, qp->title);
\r
7724 SetDlgItemText(hDlg, OPT_QuestionText, qp->question);
\r
7725 SetFocus(GetDlgItem(hDlg, OPT_QuestionInput));
\r
7729 switch (LOWORD(wParam)) {
\r
7731 strcpy(reply, qp->replyPrefix);
\r
7732 if (*reply) strcat(reply, " ");
\r
7733 len = strlen(reply);
\r
7734 GetDlgItemText(hDlg, OPT_QuestionInput, reply + len, sizeof(reply) - len);
\r
7735 strcat(reply, "\n");
\r
7736 OutputToProcess(qp->pr, reply, strlen(reply), &err);
\r
7737 EndDialog(hDlg, TRUE);
\r
7738 if (err) DisplayFatalError("Error writing to chess program", err, 1);
\r
7741 EndDialog(hDlg, FALSE);
\r
7752 AskQuestion(char* title, char *question, char *replyPrefix, ProcRef pr)
\r
7754 QuestionParams qp;
\r
7758 qp.question = question;
\r
7759 qp.replyPrefix = replyPrefix;
\r
7761 lpProc = MakeProcInstance((FARPROC)QuestionDialog, hInst);
\r
7762 DialogBoxParam(hInst, MAKEINTRESOURCE(DLG_Question),
\r
7763 hwndMain, (DLGPROC)lpProc, (LPARAM)&qp);
\r
7764 FreeProcInstance(lpProc);
\r
7767 /* [AS] Pick FRC position */
\r
7768 LRESULT CALLBACK NewGameFRC_Proc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7770 static int * lpIndexFRC;
\r
7776 case WM_INITDIALOG:
\r
7777 lpIndexFRC = (int *) lParam;
\r
7779 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
7781 SendDlgItemMessage( hDlg, IDC_NFG_Edit, EM_SETLIMITTEXT, sizeof(buf)-1, 0 );
\r
7782 SetDlgItemInt( hDlg, IDC_NFG_Edit, *lpIndexFRC, TRUE );
\r
7783 SendDlgItemMessage( hDlg, IDC_NFG_Edit, EM_SETSEL, 0, -1 );
\r
7784 SetFocus(GetDlgItem(hDlg, IDC_NFG_Edit));
\r
7789 switch( LOWORD(wParam) ) {
\r
7791 *lpIndexFRC = GetDlgItemInt(hDlg, IDC_NFG_Edit, &index_is_ok, TRUE );
\r
7792 EndDialog( hDlg, 0 );
\r
7793 shuffleOpenings = TRUE; /* [HGM] shuffle: switch shuffling on for as long as we stay in current variant */
\r
7796 EndDialog( hDlg, 1 );
\r
7798 case IDC_NFG_Edit:
\r
7799 if( HIWORD(wParam) == EN_CHANGE ) {
\r
7800 GetDlgItemInt(hDlg, IDC_NFG_Edit, &index_is_ok, TRUE );
\r
7802 EnableWindow( GetDlgItem(hDlg, IDOK), index_is_ok );
\r
7805 case IDC_NFG_Random:
\r
7806 sprintf( buf, "%d", myrandom() ); /* [HGM] shuffle: no longer limit to 960 */
\r
7807 SetDlgItemText(hDlg, IDC_NFG_Edit, buf );
\r
7820 int index = appData.defaultFrcPosition;
\r
7821 FARPROC lpProc = MakeProcInstance( (FARPROC) NewGameFRC_Proc, hInst );
\r
7823 result = DialogBoxParam( hInst, MAKEINTRESOURCE(DLG_NewGameFRC), hwndMain, (DLGPROC)lpProc, (LPARAM)&index );
\r
7825 if( result == 0 ) {
\r
7826 appData.defaultFrcPosition = index;
\r
7832 /* [AS] Game list options */
\r
7838 static GLT_Item GLT_ItemInfo[] = {
\r
7839 { GLT_EVENT, "Event" },
\r
7840 { GLT_SITE, "Site" },
\r
7841 { GLT_DATE, "Date" },
\r
7842 { GLT_ROUND, "Round" },
\r
7843 { GLT_PLAYERS, "Players" },
\r
7844 { GLT_RESULT, "Result" },
\r
7845 { GLT_WHITE_ELO, "White Rating" },
\r
7846 { GLT_BLACK_ELO, "Black Rating" },
\r
7847 { GLT_TIME_CONTROL,"Time Control" },
\r
7848 { GLT_VARIANT, "Variant" },
\r
7849 { GLT_OUT_OF_BOOK,PGN_OUT_OF_BOOK },
\r
7850 { GLT_RESULT_COMMENT, "Result Comment" }, // [HGM] rescom
\r
7854 const char * GLT_FindItem( char id )
\r
7856 const char * result = 0;
\r
7858 GLT_Item * list = GLT_ItemInfo;
\r
7860 while( list->id != 0 ) {
\r
7861 if( list->id == id ) {
\r
7862 result = list->name;
\r
7872 void GLT_AddToList( HWND hDlg, int iDlgItem, char id, int index )
\r
7874 const char * name = GLT_FindItem( id );
\r
7877 if( index >= 0 ) {
\r
7878 SendDlgItemMessage( hDlg, iDlgItem, LB_INSERTSTRING, index, (LPARAM) name );
\r
7881 SendDlgItemMessage( hDlg, iDlgItem, LB_ADDSTRING, 0, (LPARAM) name );
\r
7886 void GLT_TagsToList( HWND hDlg, char * tags )
\r
7890 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_RESETCONTENT, 0, 0 );
\r
7893 GLT_AddToList( hDlg, IDC_GameListTags, *pc, -1 );
\r
7897 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_ADDSTRING, 0, (LPARAM) "\t --- Hidden tags ---" );
\r
7899 pc = GLT_ALL_TAGS;
\r
7902 if( strchr( tags, *pc ) == 0 ) {
\r
7903 GLT_AddToList( hDlg, IDC_GameListTags, *pc, -1 );
\r
7908 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_SETCURSEL, 0, 0 );
\r
7911 char GLT_ListItemToTag( HWND hDlg, int index )
\r
7913 char result = '\0';
\r
7916 GLT_Item * list = GLT_ItemInfo;
\r
7918 if( SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETTEXT, index, (LPARAM) name ) != LB_ERR ) {
\r
7919 while( list->id != 0 ) {
\r
7920 if( strcmp( list->name, name ) == 0 ) {
\r
7921 result = list->id;
\r
7932 void GLT_MoveSelection( HWND hDlg, int delta )
\r
7934 int idx1 = (int) SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETCURSEL, 0, 0 );
\r
7935 int idx2 = idx1 + delta;
\r
7936 int count = (int) SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETCOUNT, 0, 0 );
\r
7938 if( idx1 >=0 && idx1 < count && idx2 >= 0 && idx2 < count ) {
\r
7941 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETTEXT, idx1, (LPARAM) buf );
\r
7942 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_DELETESTRING, idx1, 0 );
\r
7943 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_INSERTSTRING, idx2, (LPARAM) buf );
\r
7944 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_SETCURSEL, idx2, 0 );
\r
7948 LRESULT CALLBACK GameListOptions_Proc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7950 static char glt[64];
\r
7951 static char * lpUserGLT;
\r
7955 case WM_INITDIALOG:
\r
7956 lpUserGLT = (char *) lParam;
\r
7958 strcpy( glt, lpUserGLT );
\r
7960 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
7962 /* Initialize list */
\r
7963 GLT_TagsToList( hDlg, glt );
\r
7965 SetFocus( GetDlgItem(hDlg, IDC_GameListTags) );
\r
7970 switch( LOWORD(wParam) ) {
\r
7973 char * pc = lpUserGLT;
\r
7975 // int cnt = (int) SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETCOUNT, 0, 0 );
\r
7979 id = GLT_ListItemToTag( hDlg, idx );
\r
7983 } while( id != '\0' );
\r
7985 EndDialog( hDlg, 0 );
\r
7988 EndDialog( hDlg, 1 );
\r
7991 case IDC_GLT_Default:
\r
7992 strcpy( glt, GLT_DEFAULT_TAGS );
\r
7993 GLT_TagsToList( hDlg, glt );
\r
7996 case IDC_GLT_Restore:
\r
7997 strcpy( glt, lpUserGLT );
\r
7998 GLT_TagsToList( hDlg, glt );
\r
8002 GLT_MoveSelection( hDlg, -1 );
\r
8005 case IDC_GLT_Down:
\r
8006 GLT_MoveSelection( hDlg, +1 );
\r
8016 int GameListOptions()
\r
8020 FARPROC lpProc = MakeProcInstance( (FARPROC) GameListOptions_Proc, hInst );
\r
8022 strcpy( glt, appData.gameListTags );
\r
8024 result = DialogBoxParam( hInst, MAKEINTRESOURCE(DLG_GameListOptions), hwndMain, (DLGPROC)lpProc, (LPARAM)glt );
\r
8026 if( result == 0 ) {
\r
8027 /* [AS] Memory leak here! */
\r
8028 appData.gameListTags = strdup( glt );
\r
8036 DisplayIcsInteractionTitle(char *str)
\r
8038 char consoleTitle[MSG_SIZ];
\r
8040 sprintf(consoleTitle, "%s: %s", szConsoleTitle, str);
\r
8041 SetWindowText(hwndConsole, consoleTitle);
\r
8045 DrawPosition(int fullRedraw, Board board)
\r
8047 HDCDrawPosition(NULL, (BOOLEAN) fullRedraw, board);
\r
8050 void NotifyFrontendLogin()
\r
8053 UpdateICSWidth(GetDlgItem(hwndConsole, OPT_ConsoleText));
\r
8059 fromX = fromY = -1;
\r
8060 if (dragInfo.pos.x != -1 || dragInfo.pos.y != -1) {
\r
8061 dragInfo.pos.x = dragInfo.pos.y = -1;
\r
8062 dragInfo.pos.x = dragInfo.pos.y = -1;
\r
8063 dragInfo.lastpos = dragInfo.pos;
\r
8064 dragInfo.start.x = dragInfo.start.y = -1;
\r
8065 dragInfo.from = dragInfo.start;
\r
8067 DrawPosition(TRUE, NULL);
\r
8073 CommentPopUp(char *title, char *str)
\r
8075 HWND hwnd = GetActiveWindow();
\r
8076 EitherCommentPopUp(0, title, str, FALSE);
\r
8078 SetActiveWindow(hwnd);
\r
8082 CommentPopDown(void)
\r
8084 CheckMenuItem(GetMenu(hwndMain), IDM_EditComment, MF_UNCHECKED);
\r
8085 if (commentDialog) {
\r
8086 ShowWindow(commentDialog, SW_HIDE);
\r
8088 commentUp = FALSE;
\r
8092 EditCommentPopUp(int index, char *title, char *str)
\r
8094 EitherCommentPopUp(index, title, str, TRUE);
\r
8101 MyPlaySound(&sounds[(int)SoundMove]);
\r
8104 VOID PlayIcsWinSound()
\r
8106 MyPlaySound(&sounds[(int)SoundIcsWin]);
\r
8109 VOID PlayIcsLossSound()
\r
8111 MyPlaySound(&sounds[(int)SoundIcsLoss]);
\r
8114 VOID PlayIcsDrawSound()
\r
8116 MyPlaySound(&sounds[(int)SoundIcsDraw]);
\r
8119 VOID PlayIcsUnfinishedSound()
\r
8121 MyPlaySound(&sounds[(int)SoundIcsUnfinished]);
\r
8127 MyPlaySound(&sounds[(int)SoundAlarm]);
\r
8135 consoleEcho = TRUE;
\r
8136 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
8137 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&consoleCF);
\r
8138 SendMessage(hInput, EM_SETBKGNDCOLOR, FALSE, consoleBackgroundColor);
\r
8147 consoleEcho = FALSE;
\r
8148 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
8149 /* This works OK: set text and background both to the same color */
\r
8151 cf.crTextColor = COLOR_ECHOOFF;
\r
8152 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&cf);
\r
8153 SendMessage(hInput, EM_SETBKGNDCOLOR, FALSE, cf.crTextColor);
\r
8156 /* No Raw()...? */
\r
8158 void Colorize(ColorClass cc, int continuation)
\r
8160 currentColorClass = cc;
\r
8161 consoleCF.dwMask = CFM_COLOR|CFM_BOLD|CFM_ITALIC|CFM_UNDERLINE|CFM_STRIKEOUT;
\r
8162 consoleCF.crTextColor = textAttribs[cc].color;
\r
8163 consoleCF.dwEffects = textAttribs[cc].effects;
\r
8164 if (!continuation) MyPlaySound(&textAttribs[cc].sound);
\r
8170 static char buf[MSG_SIZ];
\r
8171 DWORD bufsiz = MSG_SIZ;
\r
8173 if(appData.userName != NULL && appData.userName[0] != 0) {
\r
8174 return appData.userName; /* [HGM] username: prefer name selected by user over his system login */
\r
8176 if (!GetUserName(buf, &bufsiz)) {
\r
8177 /*DisplayError("Error getting user name", GetLastError());*/
\r
8178 strcpy(buf, "User");
\r
8186 static char buf[MSG_SIZ];
\r
8187 DWORD bufsiz = MSG_SIZ;
\r
8189 if (!GetComputerName(buf, &bufsiz)) {
\r
8190 /*DisplayError("Error getting host name", GetLastError());*/
\r
8191 strcpy(buf, "Unknown");
\r
8198 ClockTimerRunning()
\r
8200 return clockTimerEvent != 0;
\r
8206 if (clockTimerEvent == 0) return FALSE;
\r
8207 KillTimer(hwndMain, clockTimerEvent);
\r
8208 clockTimerEvent = 0;
\r
8213 StartClockTimer(long millisec)
\r
8215 clockTimerEvent = SetTimer(hwndMain, (UINT) CLOCK_TIMER_ID,
\r
8216 (UINT) millisec, NULL);
\r
8220 DisplayWhiteClock(long timeRemaining, int highlight)
\r
8223 char *flag = whiteFlag && gameMode == TwoMachinesPlay ? "(!)" : "";
\r
8225 if(appData.noGUI) return;
\r
8226 hdc = GetDC(hwndMain);
\r
8227 if (!IsIconic(hwndMain)) {
\r
8228 DisplayAClock(hdc, timeRemaining, highlight,
\r
8229 flipClock ? &blackRect : &whiteRect, "White", flag);
\r
8231 if (highlight && iconCurrent == iconBlack) {
\r
8232 iconCurrent = iconWhite;
\r
8233 PostMessage(hwndMain, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
8234 if (IsIconic(hwndMain)) {
\r
8235 DrawIcon(hdc, 2, 2, iconCurrent);
\r
8238 (void) ReleaseDC(hwndMain, hdc);
\r
8240 PostMessage(hwndConsole, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
8244 DisplayBlackClock(long timeRemaining, int highlight)
\r
8247 char *flag = blackFlag && gameMode == TwoMachinesPlay ? "(!)" : "";
\r
8249 if(appData.noGUI) return;
\r
8250 hdc = GetDC(hwndMain);
\r
8251 if (!IsIconic(hwndMain)) {
\r
8252 DisplayAClock(hdc, timeRemaining, highlight,
\r
8253 flipClock ? &whiteRect : &blackRect, "Black", flag);
\r
8255 if (highlight && iconCurrent == iconWhite) {
\r
8256 iconCurrent = iconBlack;
\r
8257 PostMessage(hwndMain, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
8258 if (IsIconic(hwndMain)) {
\r
8259 DrawIcon(hdc, 2, 2, iconCurrent);
\r
8262 (void) ReleaseDC(hwndMain, hdc);
\r
8264 PostMessage(hwndConsole, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
8269 LoadGameTimerRunning()
\r
8271 return loadGameTimerEvent != 0;
\r
8275 StopLoadGameTimer()
\r
8277 if (loadGameTimerEvent == 0) return FALSE;
\r
8278 KillTimer(hwndMain, loadGameTimerEvent);
\r
8279 loadGameTimerEvent = 0;
\r
8284 StartLoadGameTimer(long millisec)
\r
8286 loadGameTimerEvent = SetTimer(hwndMain, (UINT) LOAD_GAME_TIMER_ID,
\r
8287 (UINT) millisec, NULL);
\r
8295 char fileTitle[MSG_SIZ];
\r
8297 defName = DefaultFileName(appData.oldSaveStyle ? "gam" : "pgn");
\r
8298 f = OpenFileDialog(hwndMain, "a", defName,
\r
8299 appData.oldSaveStyle ? "gam" : "pgn",
\r
8301 "Save Game to File", NULL, fileTitle, NULL);
\r
8303 SaveGame(f, 0, "");
\r
8310 ScheduleDelayedEvent(DelayedEventCallback cb, long millisec)
\r
8312 if (delayedTimerEvent != 0) {
\r
8313 if (appData.debugMode && cb != delayedTimerCallback) { // [HGM] alive: not too much debug
\r
8314 fprintf(debugFP, "ScheduleDelayedEvent: event already scheduled\n");
\r
8316 KillTimer(hwndMain, delayedTimerEvent);
\r
8317 delayedTimerEvent = 0;
\r
8318 if(delayedTimerCallback != cb) // [HGM] alive: do not "flush" same event, just postpone it
\r
8319 delayedTimerCallback();
\r
8321 delayedTimerCallback = cb;
\r
8322 delayedTimerEvent = SetTimer(hwndMain, (UINT) DELAYED_TIMER_ID,
\r
8323 (UINT) millisec, NULL);
\r
8326 DelayedEventCallback
\r
8329 if (delayedTimerEvent) {
\r
8330 return delayedTimerCallback;
\r
8337 CancelDelayedEvent()
\r
8339 if (delayedTimerEvent) {
\r
8340 KillTimer(hwndMain, delayedTimerEvent);
\r
8341 delayedTimerEvent = 0;
\r
8345 DWORD GetWin32Priority(int nice)
\r
8346 { // [HGM] nice: translate Unix nice() value to indows priority class. (Code stolen from Polyglot 1.4w11)
\r
8348 REALTIME_PRIORITY_CLASS 0x00000100
\r
8349 HIGH_PRIORITY_CLASS 0x00000080
\r
8350 ABOVE_NORMAL_PRIORITY_CLASS 0x00008000
\r
8351 NORMAL_PRIORITY_CLASS 0x00000020
\r
8352 BELOW_NORMAL_PRIORITY_CLASS 0x00004000
\r
8353 IDLE_PRIORITY_CLASS 0x00000040
\r
8355 if (nice < -15) return 0x00000080;
\r
8356 if (nice < 0) return 0x00008000;
\r
8357 if (nice == 0) return 0x00000020;
\r
8358 if (nice < 15) return 0x00004000;
\r
8359 return 0x00000040;
\r
8362 /* Start a child process running the given program.
\r
8363 The process's standard output can be read from "from", and its
\r
8364 standard input can be written to "to".
\r
8365 Exit with fatal error if anything goes wrong.
\r
8366 Returns an opaque pointer that can be used to destroy the process
\r
8370 StartChildProcess(char *cmdLine, char *dir, ProcRef *pr)
\r
8372 #define BUFSIZE 4096
\r
8374 HANDLE hChildStdinRd, hChildStdinWr,
\r
8375 hChildStdoutRd, hChildStdoutWr;
\r
8376 HANDLE hChildStdinWrDup, hChildStdoutRdDup;
\r
8377 SECURITY_ATTRIBUTES saAttr;
\r
8379 PROCESS_INFORMATION piProcInfo;
\r
8380 STARTUPINFO siStartInfo;
\r
8382 char buf[MSG_SIZ];
\r
8385 if (appData.debugMode) {
\r
8386 fprintf(debugFP, "StartChildProcess (dir=\"%s\") %s\n", dir, cmdLine);
\r
8391 /* Set the bInheritHandle flag so pipe handles are inherited. */
\r
8392 saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
\r
8393 saAttr.bInheritHandle = TRUE;
\r
8394 saAttr.lpSecurityDescriptor = NULL;
\r
8397 * The steps for redirecting child's STDOUT:
\r
8398 * 1. Create anonymous pipe to be STDOUT for child.
\r
8399 * 2. Create a noninheritable duplicate of read handle,
\r
8400 * and close the inheritable read handle.
\r
8403 /* Create a pipe for the child's STDOUT. */
\r
8404 if (! CreatePipe(&hChildStdoutRd, &hChildStdoutWr, &saAttr, 0)) {
\r
8405 return GetLastError();
\r
8408 /* Duplicate the read handle to the pipe, so it is not inherited. */
\r
8409 fSuccess = DuplicateHandle(GetCurrentProcess(), hChildStdoutRd,
\r
8410 GetCurrentProcess(), &hChildStdoutRdDup, 0,
\r
8411 FALSE, /* not inherited */
\r
8412 DUPLICATE_SAME_ACCESS);
\r
8414 return GetLastError();
\r
8416 CloseHandle(hChildStdoutRd);
\r
8419 * The steps for redirecting child's STDIN:
\r
8420 * 1. Create anonymous pipe to be STDIN for child.
\r
8421 * 2. Create a noninheritable duplicate of write handle,
\r
8422 * and close the inheritable write handle.
\r
8425 /* Create a pipe for the child's STDIN. */
\r
8426 if (! CreatePipe(&hChildStdinRd, &hChildStdinWr, &saAttr, 0)) {
\r
8427 return GetLastError();
\r
8430 /* Duplicate the write handle to the pipe, so it is not inherited. */
\r
8431 fSuccess = DuplicateHandle(GetCurrentProcess(), hChildStdinWr,
\r
8432 GetCurrentProcess(), &hChildStdinWrDup, 0,
\r
8433 FALSE, /* not inherited */
\r
8434 DUPLICATE_SAME_ACCESS);
\r
8436 return GetLastError();
\r
8438 CloseHandle(hChildStdinWr);
\r
8440 /* Arrange to (1) look in dir for the child .exe file, and
\r
8441 * (2) have dir be the child's working directory. Interpret
\r
8442 * dir relative to the directory WinBoard loaded from. */
\r
8443 GetCurrentDirectory(MSG_SIZ, buf);
\r
8444 SetCurrentDirectory(installDir);
\r
8445 SetCurrentDirectory(dir);
\r
8447 /* Now create the child process. */
\r
8449 siStartInfo.cb = sizeof(STARTUPINFO);
\r
8450 siStartInfo.lpReserved = NULL;
\r
8451 siStartInfo.lpDesktop = NULL;
\r
8452 siStartInfo.lpTitle = NULL;
\r
8453 siStartInfo.dwFlags = STARTF_USESTDHANDLES;
\r
8454 siStartInfo.cbReserved2 = 0;
\r
8455 siStartInfo.lpReserved2 = NULL;
\r
8456 siStartInfo.hStdInput = hChildStdinRd;
\r
8457 siStartInfo.hStdOutput = hChildStdoutWr;
\r
8458 siStartInfo.hStdError = hChildStdoutWr;
\r
8460 fSuccess = CreateProcess(NULL,
\r
8461 cmdLine, /* command line */
\r
8462 NULL, /* process security attributes */
\r
8463 NULL, /* primary thread security attrs */
\r
8464 TRUE, /* handles are inherited */
\r
8465 DETACHED_PROCESS|CREATE_NEW_PROCESS_GROUP,
\r
8466 NULL, /* use parent's environment */
\r
8468 &siStartInfo, /* STARTUPINFO pointer */
\r
8469 &piProcInfo); /* receives PROCESS_INFORMATION */
\r
8471 err = GetLastError();
\r
8472 SetCurrentDirectory(buf); /* return to prev directory */
\r
8477 if (appData.niceEngines){ // [HGM] nice: adjust engine proc priority
\r
8478 if(appData.debugMode) fprintf(debugFP, "nice engine proc to %d\n", appData.niceEngines);
\r
8479 SetPriorityClass(piProcInfo.hProcess, GetWin32Priority(appData.niceEngines));
\r
8482 /* Close the handles we don't need in the parent */
\r
8483 CloseHandle(piProcInfo.hThread);
\r
8484 CloseHandle(hChildStdinRd);
\r
8485 CloseHandle(hChildStdoutWr);
\r
8487 /* Prepare return value */
\r
8488 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
8489 cp->kind = CPReal;
\r
8490 cp->hProcess = piProcInfo.hProcess;
\r
8491 cp->pid = piProcInfo.dwProcessId;
\r
8492 cp->hFrom = hChildStdoutRdDup;
\r
8493 cp->hTo = hChildStdinWrDup;
\r
8495 *pr = (void *) cp;
\r
8497 /* Klaus Friedel says that this Sleep solves a problem under Windows
\r
8498 2000 where engines sometimes don't see the initial command(s)
\r
8499 from WinBoard and hang. I don't understand how that can happen,
\r
8500 but the Sleep is harmless, so I've put it in. Others have also
\r
8501 reported what may be the same problem, so hopefully this will fix
\r
8502 it for them too. */
\r
8510 DestroyChildProcess(ProcRef pr, int/*boolean*/ signal)
\r
8512 ChildProc *cp; int result;
\r
8514 cp = (ChildProc *) pr;
\r
8515 if (cp == NULL) return;
\r
8517 switch (cp->kind) {
\r
8519 /* TerminateProcess is considered harmful, so... */
\r
8520 CloseHandle(cp->hTo); /* Closing this will give the child an EOF and hopefully kill it */
\r
8521 if (cp->hFrom) CloseHandle(cp->hFrom); /* if NULL, InputThread will close it */
\r
8522 /* The following doesn't work because the chess program
\r
8523 doesn't "have the same console" as WinBoard. Maybe
\r
8524 we could arrange for this even though neither WinBoard
\r
8525 nor the chess program uses a console for stdio? */
\r
8526 /*!!if (signal) GenerateConsoleCtrlEvent(CTRL_BREAK_EVENT, cp->pid);*/
\r
8528 /* [AS] Special termination modes for misbehaving programs... */
\r
8529 if( signal == 9 ) {
\r
8530 result = TerminateProcess( cp->hProcess, 0 );
\r
8532 if ( appData.debugMode) {
\r
8533 fprintf( debugFP, "Terminating process %lu, result=%d\n", cp->pid, result );
\r
8536 else if( signal == 10 ) {
\r
8537 DWORD dw = WaitForSingleObject( cp->hProcess, 3*1000 ); // Wait 3 seconds at most
\r
8539 if( dw != WAIT_OBJECT_0 ) {
\r
8540 result = TerminateProcess( cp->hProcess, 0 );
\r
8542 if ( appData.debugMode) {
\r
8543 fprintf( debugFP, "Process %lu still alive after timeout, killing... result=%d\n", cp->pid, result );
\r
8549 CloseHandle(cp->hProcess);
\r
8553 if (cp->hFrom) CloseHandle(cp->hFrom);
\r
8557 closesocket(cp->sock);
\r
8562 if (signal) send(cp->sock2, "\017", 1, 0); /* 017 = 15 = SIGTERM */
\r
8563 closesocket(cp->sock);
\r
8564 closesocket(cp->sock2);
\r
8572 InterruptChildProcess(ProcRef pr)
\r
8576 cp = (ChildProc *) pr;
\r
8577 if (cp == NULL) return;
\r
8578 switch (cp->kind) {
\r
8580 /* The following doesn't work because the chess program
\r
8581 doesn't "have the same console" as WinBoard. Maybe
\r
8582 we could arrange for this even though neither WinBoard
\r
8583 nor the chess program uses a console for stdio */
\r
8584 /*!!GenerateConsoleCtrlEvent(CTRL_C_EVENT, cp->pid);*/
\r
8589 /* Can't interrupt */
\r
8593 send(cp->sock2, "\002", 1, 0); /* 2 = SIGINT */
\r
8600 OpenTelnet(char *host, char *port, ProcRef *pr)
\r
8602 char cmdLine[MSG_SIZ];
\r
8604 if (port[0] == NULLCHAR) {
\r
8605 sprintf(cmdLine, "%s %s", appData.telnetProgram, host);
\r
8607 sprintf(cmdLine, "%s %s %s", appData.telnetProgram, host, port);
\r
8609 return StartChildProcess(cmdLine, "", pr);
\r
8613 /* Code to open TCP sockets */
\r
8616 OpenTCP(char *host, char *port, ProcRef *pr)
\r
8621 struct sockaddr_in sa, mysa;
\r
8622 struct hostent FAR *hp;
\r
8623 unsigned short uport;
\r
8624 WORD wVersionRequested;
\r
8627 /* Initialize socket DLL */
\r
8628 wVersionRequested = MAKEWORD(1, 1);
\r
8629 err = WSAStartup(wVersionRequested, &wsaData);
\r
8630 if (err != 0) return err;
\r
8633 if ((s = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
\r
8634 err = WSAGetLastError();
\r
8639 /* Bind local address using (mostly) don't-care values.
\r
8641 memset((char *) &mysa, 0, sizeof(struct sockaddr_in));
\r
8642 mysa.sin_family = AF_INET;
\r
8643 mysa.sin_addr.s_addr = INADDR_ANY;
\r
8644 uport = (unsigned short) 0;
\r
8645 mysa.sin_port = htons(uport);
\r
8646 if (bind(s, (struct sockaddr *) &mysa, sizeof(struct sockaddr_in))
\r
8647 == SOCKET_ERROR) {
\r
8648 err = WSAGetLastError();
\r
8653 /* Resolve remote host name */
\r
8654 memset((char *) &sa, 0, sizeof(struct sockaddr_in));
\r
8655 if (!(hp = gethostbyname(host))) {
\r
8656 unsigned int b0, b1, b2, b3;
\r
8658 err = WSAGetLastError();
\r
8660 if (sscanf(host, "%u.%u.%u.%u", &b0, &b1, &b2, &b3) == 4) {
\r
8661 hp = (struct hostent *) calloc(1, sizeof(struct hostent));
\r
8662 hp->h_addrtype = AF_INET;
\r
8664 hp->h_addr_list = (char **) calloc(2, sizeof(char *));
\r
8665 hp->h_addr_list[0] = (char *) malloc(4);
\r
8666 hp->h_addr_list[0][0] = (char) b0;
\r
8667 hp->h_addr_list[0][1] = (char) b1;
\r
8668 hp->h_addr_list[0][2] = (char) b2;
\r
8669 hp->h_addr_list[0][3] = (char) b3;
\r
8675 sa.sin_family = hp->h_addrtype;
\r
8676 uport = (unsigned short) atoi(port);
\r
8677 sa.sin_port = htons(uport);
\r
8678 memcpy((char *) &sa.sin_addr, hp->h_addr, hp->h_length);
\r
8680 /* Make connection */
\r
8681 if (connect(s, (struct sockaddr *) &sa,
\r
8682 sizeof(struct sockaddr_in)) == SOCKET_ERROR) {
\r
8683 err = WSAGetLastError();
\r
8688 /* Prepare return value */
\r
8689 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
8690 cp->kind = CPSock;
\r
8692 *pr = (ProcRef *) cp;
\r
8698 OpenCommPort(char *name, ProcRef *pr)
\r
8703 char fullname[MSG_SIZ];
\r
8705 if (*name != '\\')
\r
8706 sprintf(fullname, "\\\\.\\%s", name);
\r
8708 strcpy(fullname, name);
\r
8710 h = CreateFile(name, GENERIC_READ | GENERIC_WRITE,
\r
8711 0, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
\r
8712 if (h == (HANDLE) -1) {
\r
8713 return GetLastError();
\r
8717 if (!SetCommState(h, (LPDCB) &dcb)) return GetLastError();
\r
8719 /* Accumulate characters until a 100ms pause, then parse */
\r
8720 ct.ReadIntervalTimeout = 100;
\r
8721 ct.ReadTotalTimeoutMultiplier = 0;
\r
8722 ct.ReadTotalTimeoutConstant = 0;
\r
8723 ct.WriteTotalTimeoutMultiplier = 0;
\r
8724 ct.WriteTotalTimeoutConstant = 0;
\r
8725 if (!SetCommTimeouts(h, (LPCOMMTIMEOUTS) &ct)) return GetLastError();
\r
8727 /* Prepare return value */
\r
8728 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
8729 cp->kind = CPComm;
\r
8732 *pr = (ProcRef *) cp;
\r
8738 OpenLoopback(ProcRef *pr)
\r
8740 DisplayFatalError("Not implemented", 0, 1);
\r
8746 OpenRcmd(char* host, char* user, char* cmd, ProcRef* pr)
\r
8751 struct sockaddr_in sa, mysa;
\r
8752 struct hostent FAR *hp;
\r
8753 unsigned short uport;
\r
8754 WORD wVersionRequested;
\r
8757 char stderrPortStr[MSG_SIZ];
\r
8759 /* Initialize socket DLL */
\r
8760 wVersionRequested = MAKEWORD(1, 1);
\r
8761 err = WSAStartup(wVersionRequested, &wsaData);
\r
8762 if (err != 0) return err;
\r
8764 /* Resolve remote host name */
\r
8765 memset((char *) &sa, 0, sizeof(struct sockaddr_in));
\r
8766 if (!(hp = gethostbyname(host))) {
\r
8767 unsigned int b0, b1, b2, b3;
\r
8769 err = WSAGetLastError();
\r
8771 if (sscanf(host, "%u.%u.%u.%u", &b0, &b1, &b2, &b3) == 4) {
\r
8772 hp = (struct hostent *) calloc(1, sizeof(struct hostent));
\r
8773 hp->h_addrtype = AF_INET;
\r
8775 hp->h_addr_list = (char **) calloc(2, sizeof(char *));
\r
8776 hp->h_addr_list[0] = (char *) malloc(4);
\r
8777 hp->h_addr_list[0][0] = (char) b0;
\r
8778 hp->h_addr_list[0][1] = (char) b1;
\r
8779 hp->h_addr_list[0][2] = (char) b2;
\r
8780 hp->h_addr_list[0][3] = (char) b3;
\r
8786 sa.sin_family = hp->h_addrtype;
\r
8787 uport = (unsigned short) 514;
\r
8788 sa.sin_port = htons(uport);
\r
8789 memcpy((char *) &sa.sin_addr, hp->h_addr, hp->h_length);
\r
8791 /* Bind local socket to unused "privileged" port address
\r
8793 s = INVALID_SOCKET;
\r
8794 memset((char *) &mysa, 0, sizeof(struct sockaddr_in));
\r
8795 mysa.sin_family = AF_INET;
\r
8796 mysa.sin_addr.s_addr = INADDR_ANY;
\r
8797 for (fromPort = 1023;; fromPort--) {
\r
8798 if (fromPort < 0) {
\r
8800 return WSAEADDRINUSE;
\r
8802 if (s == INVALID_SOCKET) {
\r
8803 if ((s = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
\r
8804 err = WSAGetLastError();
\r
8809 uport = (unsigned short) fromPort;
\r
8810 mysa.sin_port = htons(uport);
\r
8811 if (bind(s, (struct sockaddr *) &mysa, sizeof(struct sockaddr_in))
\r
8812 == SOCKET_ERROR) {
\r
8813 err = WSAGetLastError();
\r
8814 if (err == WSAEADDRINUSE) continue;
\r
8818 if (connect(s, (struct sockaddr *) &sa,
\r
8819 sizeof(struct sockaddr_in)) == SOCKET_ERROR) {
\r
8820 err = WSAGetLastError();
\r
8821 if (err == WSAEADDRINUSE) {
\r
8832 /* Bind stderr local socket to unused "privileged" port address
\r
8834 s2 = INVALID_SOCKET;
\r
8835 memset((char *) &mysa, 0, sizeof(struct sockaddr_in));
\r
8836 mysa.sin_family = AF_INET;
\r
8837 mysa.sin_addr.s_addr = INADDR_ANY;
\r
8838 for (fromPort = 1023;; fromPort--) {
\r
8839 if (fromPort == prevStderrPort) continue; // don't reuse port
\r
8840 if (fromPort < 0) {
\r
8841 (void) closesocket(s);
\r
8843 return WSAEADDRINUSE;
\r
8845 if (s2 == INVALID_SOCKET) {
\r
8846 if ((s2 = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
\r
8847 err = WSAGetLastError();
\r
8853 uport = (unsigned short) fromPort;
\r
8854 mysa.sin_port = htons(uport);
\r
8855 if (bind(s2, (struct sockaddr *) &mysa, sizeof(struct sockaddr_in))
\r
8856 == SOCKET_ERROR) {
\r
8857 err = WSAGetLastError();
\r
8858 if (err == WSAEADDRINUSE) continue;
\r
8859 (void) closesocket(s);
\r
8863 if (listen(s2, 1) == SOCKET_ERROR) {
\r
8864 err = WSAGetLastError();
\r
8865 if (err == WSAEADDRINUSE) {
\r
8867 s2 = INVALID_SOCKET;
\r
8870 (void) closesocket(s);
\r
8871 (void) closesocket(s2);
\r
8877 prevStderrPort = fromPort; // remember port used
\r
8878 sprintf(stderrPortStr, "%d", fromPort);
\r
8880 if (send(s, stderrPortStr, strlen(stderrPortStr) + 1, 0) == SOCKET_ERROR) {
\r
8881 err = WSAGetLastError();
\r
8882 (void) closesocket(s);
\r
8883 (void) closesocket(s2);
\r
8888 if (send(s, UserName(), strlen(UserName()) + 1, 0) == SOCKET_ERROR) {
\r
8889 err = WSAGetLastError();
\r
8890 (void) closesocket(s);
\r
8891 (void) closesocket(s2);
\r
8895 if (*user == NULLCHAR) user = UserName();
\r
8896 if (send(s, user, strlen(user) + 1, 0) == SOCKET_ERROR) {
\r
8897 err = WSAGetLastError();
\r
8898 (void) closesocket(s);
\r
8899 (void) closesocket(s2);
\r
8903 if (send(s, cmd, strlen(cmd) + 1, 0) == SOCKET_ERROR) {
\r
8904 err = WSAGetLastError();
\r
8905 (void) closesocket(s);
\r
8906 (void) closesocket(s2);
\r
8911 if ((s3 = accept(s2, NULL, NULL)) == INVALID_SOCKET) {
\r
8912 err = WSAGetLastError();
\r
8913 (void) closesocket(s);
\r
8914 (void) closesocket(s2);
\r
8918 (void) closesocket(s2); /* Stop listening */
\r
8920 /* Prepare return value */
\r
8921 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
8922 cp->kind = CPRcmd;
\r
8925 *pr = (ProcRef *) cp;
\r
8932 AddInputSource(ProcRef pr, int lineByLine,
\r
8933 InputCallback func, VOIDSTAR closure)
\r
8935 InputSource *is, *is2 = NULL;
\r
8936 ChildProc *cp = (ChildProc *) pr;
\r
8938 is = (InputSource *) calloc(1, sizeof(InputSource));
\r
8939 is->lineByLine = lineByLine;
\r
8941 is->closure = closure;
\r
8942 is->second = NULL;
\r
8943 is->next = is->buf;
\r
8944 if (pr == NoProc) {
\r
8945 is->kind = CPReal;
\r
8946 consoleInputSource = is;
\r
8948 is->kind = cp->kind;
\r
8950 [AS] Try to avoid a race condition if the thread is given control too early:
\r
8951 we create all threads suspended so that the is->hThread variable can be
\r
8952 safely assigned, then let the threads start with ResumeThread.
\r
8954 switch (cp->kind) {
\r
8956 is->hFile = cp->hFrom;
\r
8957 cp->hFrom = NULL; /* now owned by InputThread */
\r
8959 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) NonOvlInputThread,
\r
8960 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
8964 is->hFile = cp->hFrom;
\r
8965 cp->hFrom = NULL; /* now owned by InputThread */
\r
8967 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) InputThread,
\r
8968 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
8972 is->sock = cp->sock;
\r
8974 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SocketInputThread,
\r
8975 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
8979 is2 = (InputSource *) calloc(1, sizeof(InputSource));
\r
8981 is->sock = cp->sock;
\r
8983 is2->sock = cp->sock2;
\r
8984 is2->second = is2;
\r
8986 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SocketInputThread,
\r
8987 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
8989 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SocketInputThread,
\r
8990 (LPVOID) is2, CREATE_SUSPENDED, &is2->id);
\r
8994 if( is->hThread != NULL ) {
\r
8995 ResumeThread( is->hThread );
\r
8998 if( is2 != NULL && is2->hThread != NULL ) {
\r
8999 ResumeThread( is2->hThread );
\r
9003 return (InputSourceRef) is;
\r
9007 RemoveInputSource(InputSourceRef isr)
\r
9011 is = (InputSource *) isr;
\r
9012 is->hThread = NULL; /* tell thread to stop */
\r
9013 CloseHandle(is->hThread);
\r
9014 if (is->second != NULL) {
\r
9015 is->second->hThread = NULL;
\r
9016 CloseHandle(is->second->hThread);
\r
9020 int no_wrap(char *message, int count)
\r
9022 ConsoleOutput(message, count, FALSE);
\r
9027 OutputToProcess(ProcRef pr, char *message, int count, int *outError)
\r
9030 int outCount = SOCKET_ERROR;
\r
9031 ChildProc *cp = (ChildProc *) pr;
\r
9032 static OVERLAPPED ovl;
\r
9033 static int line = 0;
\r
9037 if (appData.noJoin || !appData.useInternalWrap)
\r
9038 return no_wrap(message, count);
\r
9041 int width = get_term_width();
\r
9042 int len = wrap(NULL, message, count, width, &line);
\r
9043 char *msg = malloc(len);
\r
9047 return no_wrap(message, count);
\r
9050 dbgchk = wrap(msg, message, count, width, &line);
\r
9051 if (dbgchk != len && appData.debugMode)
\r
9052 fprintf(debugFP, "wrap(): dbgchk(%d) != len(%d)\n", dbgchk, len);
\r
9053 ConsoleOutput(msg, len, FALSE);
\r
9060 if (ovl.hEvent == NULL) {
\r
9061 ovl.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
\r
9063 ovl.Internal = ovl.InternalHigh = ovl.Offset = ovl.OffsetHigh = 0;
\r
9065 switch (cp->kind) {
\r
9068 outCount = send(cp->sock, message, count, 0);
\r
9069 if (outCount == SOCKET_ERROR) {
\r
9070 *outError = WSAGetLastError();
\r
9072 *outError = NO_ERROR;
\r
9077 if (WriteFile(((ChildProc *)pr)->hTo, message, count,
\r
9078 &dOutCount, NULL)) {
\r
9079 *outError = NO_ERROR;
\r
9080 outCount = (int) dOutCount;
\r
9082 *outError = GetLastError();
\r
9087 *outError = DoWriteFile(((ChildProc *)pr)->hTo, message, count,
\r
9088 &dOutCount, &ovl);
\r
9089 if (*outError == NO_ERROR) {
\r
9090 outCount = (int) dOutCount;
\r
9098 OutputToProcessDelayed(ProcRef pr, char *message, int count, int *outError,
\r
9101 /* Ignore delay, not implemented for WinBoard */
\r
9102 return OutputToProcess(pr, message, count, outError);
\r
9107 CmailSigHandlerCallBack(InputSourceRef isr, VOIDSTAR closure,
\r
9108 char *buf, int count, int error)
\r
9110 DisplayFatalError("Not implemented", 0, 1);
\r
9113 /* see wgamelist.c for Game List functions */
\r
9114 /* see wedittags.c for Edit Tags functions */
\r
9121 char buf[MSG_SIZ];
\r
9124 if (SearchPath(installDir, appData.icsLogon, NULL, MSG_SIZ, buf, &dummy)) {
\r
9125 f = fopen(buf, "r");
\r
9127 ProcessICSInitScript(f);
\r
9135 StartAnalysisClock()
\r
9137 if (analysisTimerEvent) return;
\r
9138 analysisTimerEvent = SetTimer(hwndMain, (UINT) ANALYSIS_TIMER_ID,
\r
9139 (UINT) 2000, NULL);
\r
9143 SetHighlights(int fromX, int fromY, int toX, int toY)
\r
9145 highlightInfo.sq[0].x = fromX;
\r
9146 highlightInfo.sq[0].y = fromY;
\r
9147 highlightInfo.sq[1].x = toX;
\r
9148 highlightInfo.sq[1].y = toY;
\r
9154 highlightInfo.sq[0].x = highlightInfo.sq[0].y =
\r
9155 highlightInfo.sq[1].x = highlightInfo.sq[1].y = -1;
\r
9159 SetPremoveHighlights(int fromX, int fromY, int toX, int toY)
\r
9161 premoveHighlightInfo.sq[0].x = fromX;
\r
9162 premoveHighlightInfo.sq[0].y = fromY;
\r
9163 premoveHighlightInfo.sq[1].x = toX;
\r
9164 premoveHighlightInfo.sq[1].y = toY;
\r
9168 ClearPremoveHighlights()
\r
9170 premoveHighlightInfo.sq[0].x = premoveHighlightInfo.sq[0].y =
\r
9171 premoveHighlightInfo.sq[1].x = premoveHighlightInfo.sq[1].y = -1;
\r
9175 ShutDownFrontEnd()
\r
9177 if (saveSettingsOnExit) SaveSettings(settingsFileName);
\r
9178 DeleteClipboardTempFiles();
\r
9184 if (IsIconic(hwndMain))
\r
9185 ShowWindow(hwndMain, SW_RESTORE);
\r
9187 SetActiveWindow(hwndMain);
\r
9191 * Prototypes for animation support routines
\r
9193 static void ScreenSquare(int column, int row, POINT * pt);
\r
9194 static void Tween( POINT * start, POINT * mid, POINT * finish, int factor,
\r
9195 POINT frames[], int * nFrames);
\r
9199 AnimateAtomicCapture(int fromX, int fromY, int toX, int toY, int nFrames)
\r
9200 { // [HGM] atomic: animate blast wave
\r
9202 if(appData.debugMode) fprintf(debugFP, "exploding (%d,%d)\n", toX, toY);
\r
9203 explodeInfo.fromX = fromX;
\r
9204 explodeInfo.fromY = fromY;
\r
9205 explodeInfo.toX = toX;
\r
9206 explodeInfo.toY = toY;
\r
9207 for(i=1; i<nFrames; i++) {
\r
9208 explodeInfo.radius = (i*180)/(nFrames-1);
\r
9209 DrawPosition(FALSE, NULL);
\r
9210 Sleep(appData.animSpeed);
\r
9212 explodeInfo.radius = 0;
\r
9213 DrawPosition(TRUE, NULL);
\r
9219 AnimateMove(board, fromX, fromY, toX, toY)
\r
9226 ChessSquare piece;
\r
9227 POINT start, finish, mid;
\r
9228 POINT frames[kFactor * 2 + 1];
\r
9231 if (!appData.animate) return;
\r
9232 if (doingSizing) return;
\r
9233 if (fromY < 0 || fromX < 0) return;
\r
9234 piece = board[fromY][fromX];
\r
9235 if (piece >= EmptySquare) return;
\r
9237 ScreenSquare(fromX, fromY, &start);
\r
9238 ScreenSquare(toX, toY, &finish);
\r
9240 /* All pieces except knights move in straight line */
\r
9241 if (piece != WhiteKnight && piece != BlackKnight) {
\r
9242 mid.x = start.x + (finish.x - start.x) / 2;
\r
9243 mid.y = start.y + (finish.y - start.y) / 2;
\r
9245 /* Knight: make diagonal movement then straight */
\r
9246 if (abs(toY - fromY) < abs(toX - fromX)) {
\r
9247 mid.x = start.x + (finish.x - start.x) / 2;
\r
9251 mid.y = start.y + (finish.y - start.y) / 2;
\r
9255 /* Don't use as many frames for very short moves */
\r
9256 if (abs(toY - fromY) + abs(toX - fromX) <= 2)
\r
9257 Tween(&start, &mid, &finish, kFactor - 1, frames, &nFrames);
\r
9259 Tween(&start, &mid, &finish, kFactor, frames, &nFrames);
\r
9261 animInfo.from.x = fromX;
\r
9262 animInfo.from.y = fromY;
\r
9263 animInfo.to.x = toX;
\r
9264 animInfo.to.y = toY;
\r
9265 animInfo.lastpos = start;
\r
9266 animInfo.piece = piece;
\r
9267 for (n = 0; n < nFrames; n++) {
\r
9268 animInfo.pos = frames[n];
\r
9269 DrawPosition(FALSE, NULL);
\r
9270 animInfo.lastpos = animInfo.pos;
\r
9271 Sleep(appData.animSpeed);
\r
9273 animInfo.pos = finish;
\r
9274 DrawPosition(FALSE, NULL);
\r
9275 animInfo.piece = EmptySquare;
\r
9276 if(gameInfo.variant == VariantAtomic &&
\r
9277 (board[toY][toX] != EmptySquare || fromX != toX && (piece == WhitePawn || piece == BlackPawn) ) )
\r
9278 AnimateAtomicCapture(fromX, fromY, toX, toY, 2*nFrames);
\r
9281 /* Convert board position to corner of screen rect and color */
\r
9284 ScreenSquare(column, row, pt)
\r
9285 int column; int row; POINT * pt;
\r
9288 pt->x = lineGap + ((BOARD_WIDTH-1)-column) * (squareSize + lineGap);
\r
9289 pt->y = lineGap + row * (squareSize + lineGap);
\r
9291 pt->x = lineGap + column * (squareSize + lineGap);
\r
9292 pt->y = lineGap + ((BOARD_HEIGHT-1)-row) * (squareSize + lineGap);
\r
9296 /* Generate a series of frame coords from start->mid->finish.
\r
9297 The movement rate doubles until the half way point is
\r
9298 reached, then halves back down to the final destination,
\r
9299 which gives a nice slow in/out effect. The algorithmn
\r
9300 may seem to generate too many intermediates for short
\r
9301 moves, but remember that the purpose is to attract the
\r
9302 viewers attention to the piece about to be moved and
\r
9303 then to where it ends up. Too few frames would be less
\r
9307 Tween(start, mid, finish, factor, frames, nFrames)
\r
9308 POINT * start; POINT * mid;
\r
9309 POINT * finish; int factor;
\r
9310 POINT frames[]; int * nFrames;
\r
9312 int n, fraction = 1, count = 0;
\r
9314 /* Slow in, stepping 1/16th, then 1/8th, ... */
\r
9315 for (n = 0; n < factor; n++)
\r
9317 for (n = 0; n < factor; n++) {
\r
9318 frames[count].x = start->x + (mid->x - start->x) / fraction;
\r
9319 frames[count].y = start->y + (mid->y - start->y) / fraction;
\r
9321 fraction = fraction / 2;
\r
9325 frames[count] = *mid;
\r
9328 /* Slow out, stepping 1/2, then 1/4, ... */
\r
9330 for (n = 0; n < factor; n++) {
\r
9331 frames[count].x = finish->x - (finish->x - mid->x) / fraction;
\r
9332 frames[count].y = finish->y - (finish->y - mid->y) / fraction;
\r
9334 fraction = fraction * 2;
\r
9340 HistorySet( char movelist[][2*MOVE_LEN], int first, int last, int current )
\r
9342 MoveHistorySet( movelist, first, last, current, pvInfoList );
\r
9344 EvalGraphSet( first, last, current, pvInfoList );
\r