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
889 // front-end part of option handling
\r
892 LFfromMFP(LOGFONT* lf, MyFontParams *mfp)
\r
894 HDC hdc = CreateDC("DISPLAY", NULL, NULL, NULL);
\r
895 lf->lfHeight = -(int)(mfp->pointSize * GetDeviceCaps(hdc, LOGPIXELSY) / 72.0 + 0.5);
\r
898 lf->lfEscapement = 0;
\r
899 lf->lfOrientation = 0;
\r
900 lf->lfWeight = mfp->bold ? FW_BOLD : FW_NORMAL;
\r
901 lf->lfItalic = mfp->italic;
\r
902 lf->lfUnderline = mfp->underline;
\r
903 lf->lfStrikeOut = mfp->strikeout;
\r
904 lf->lfCharSet = mfp->charset;
\r
905 lf->lfOutPrecision = OUT_DEFAULT_PRECIS;
\r
906 lf->lfClipPrecision = CLIP_DEFAULT_PRECIS;
\r
907 lf->lfQuality = DEFAULT_QUALITY;
\r
908 lf->lfPitchAndFamily = DEFAULT_PITCH|FF_DONTCARE;
\r
909 strcpy(lf->lfFaceName, mfp->faceName);
\r
913 CreateFontInMF(MyFont *mf)
\r
915 LFfromMFP(&mf->lf, &mf->mfp);
\r
916 if (mf->hf) DeleteObject(mf->hf);
\r
917 mf->hf = CreateFontIndirect(&mf->lf);
\r
920 // [HGM] This platform-dependent table provides the location for storing the color info
\r
922 colorVariable[] = {
\r
927 &highlightSquareColor,
\r
928 &premoveHighlightColor,
\r
930 &consoleBackgroundColor,
\r
931 &appData.fontForeColorWhite,
\r
932 &appData.fontBackColorWhite,
\r
933 &appData.fontForeColorBlack,
\r
934 &appData.fontBackColorBlack,
\r
935 &appData.evalHistColorWhite,
\r
936 &appData.evalHistColorBlack,
\r
937 &appData.highlightArrowColor,
\r
940 /* Command line font name parser. NULL name means do nothing.
\r
941 Syntax like "Courier New:10.0 bi" or "Arial:10" or "Arial:10b"
\r
942 For backward compatibility, syntax without the colon is also
\r
943 accepted, but font names with digits in them won't work in that case.
\r
946 ParseFontName(char *name, MyFontParams *mfp)
\r
949 if (name == NULL) return;
\r
951 q = strchr(p, ':');
\r
953 if (q - p >= sizeof(mfp->faceName))
\r
954 ExitArgError("Font name too long:", name);
\r
955 memcpy(mfp->faceName, p, q - p);
\r
956 mfp->faceName[q - p] = NULLCHAR;
\r
960 while (*p && !isdigit(*p)) {
\r
962 if (q - mfp->faceName >= sizeof(mfp->faceName))
\r
963 ExitArgError("Font name too long:", name);
\r
965 while (q > mfp->faceName && q[-1] == ' ') q--;
\r
968 if (!*p) ExitArgError("Font point size missing:", name);
\r
969 mfp->pointSize = (float) atof(p);
\r
970 mfp->bold = (strchr(p, 'b') != NULL);
\r
971 mfp->italic = (strchr(p, 'i') != NULL);
\r
972 mfp->underline = (strchr(p, 'u') != NULL);
\r
973 mfp->strikeout = (strchr(p, 's') != NULL);
\r
974 mfp->charset = DEFAULT_CHARSET;
\r
975 q = strchr(p, 'c');
\r
977 mfp->charset = (BYTE) atoi(q+1);
\r
981 ParseFont(char *name, int number)
\r
982 { // wrapper to shield back-end from 'font'
\r
983 ParseFontName(name, &font[boardSize][number]->mfp);
\r
988 { // in WB we have a 2D array of fonts; this initializes their description
\r
990 /* Point font array elements to structures and
\r
991 parse default font names */
\r
992 for (i=0; i<NUM_FONTS; i++) {
\r
993 for (j=0; j<NUM_SIZES; j++) {
\r
994 font[j][i] = &fontRec[j][i];
\r
995 ParseFontName(font[j][i]->def, &font[j][i]->mfp);
\r
1002 { // here we create the actual fonts from the selected descriptions
\r
1004 for (i=0; i<NUM_FONTS; i++) {
\r
1005 for (j=0; j<NUM_SIZES; j++) {
\r
1006 CreateFontInMF(font[j][i]);
\r
1010 /* Color name parser.
\r
1011 X version accepts X color names, but this one
\r
1012 handles only the #rrggbb form (hex) or rrr,ggg,bbb (decimal) */
\r
1014 ParseColorName(char *name)
\r
1016 int red, green, blue, count;
\r
1017 char buf[MSG_SIZ];
\r
1019 count = sscanf(name, "#%2x%2x%2x", &red, &green, &blue);
\r
1021 count = sscanf(name, "%3d%*[^0-9]%3d%*[^0-9]%3d",
\r
1022 &red, &green, &blue);
\r
1025 sprintf(buf, "Can't parse color name %s", name);
\r
1026 DisplayError(buf, 0);
\r
1027 return RGB(0, 0, 0);
\r
1029 return PALETTERGB(red, green, blue);
\r
1033 ParseColor(int n, char *name)
\r
1034 { // for WinBoard the color is an int, which needs to be derived from the string
\r
1035 if(colorVariable[n]) *(int*)colorVariable[n] = ParseColorName(name);
\r
1039 ParseAttribs(COLORREF *color, int *effects, char* argValue)
\r
1041 char *e = argValue;
\r
1045 if (*e == 'b') eff |= CFE_BOLD;
\r
1046 else if (*e == 'i') eff |= CFE_ITALIC;
\r
1047 else if (*e == 'u') eff |= CFE_UNDERLINE;
\r
1048 else if (*e == 's') eff |= CFE_STRIKEOUT;
\r
1049 else if (*e == '#' || isdigit(*e)) break;
\r
1053 *color = ParseColorName(e);
\r
1057 ParseTextAttribs(ColorClass cc, char *s)
\r
1058 { // [HGM] front-end wrapper that does the platform-dependent call
\r
1059 // for XBoard we would set (&appData.colorShout)[cc] = strdup(s);
\r
1060 ParseAttribs(&textAttribs[cc].color, &textAttribs[cc].effects, s);
\r
1064 ParseBoardSize(void *addr, char *name)
\r
1065 { // [HGM] rewritten with return-value ptr to shield back-end from BoardSize
\r
1066 BoardSize bs = SizeTiny;
\r
1067 while (sizeInfo[bs].name != NULL) {
\r
1068 if (StrCaseCmp(name, sizeInfo[bs].name) == 0) {
\r
1069 *(BoardSize *)addr = bs;
\r
1074 ExitArgError("Unrecognized board size value", name);
\r
1079 { // [HGM] import name from appData first
\r
1082 for (cc = (ColorClass)0; cc < ColorNormal; cc++) {
\r
1083 textAttribs[cc].sound.name = strdup((&appData.soundShout)[cc]);
\r
1084 textAttribs[cc].sound.data = NULL;
\r
1085 MyLoadSound(&textAttribs[cc].sound);
\r
1087 for (cc = ColorNormal; cc < NColorClasses; cc++) {
\r
1088 textAttribs[cc].sound.name = strdup("");
\r
1089 textAttribs[cc].sound.data = NULL;
\r
1091 for (sc = (SoundClass)0; sc < NSoundClasses; sc++) {
\r
1092 sounds[sc].name = strdup((&appData.soundMove)[sc]);
\r
1093 sounds[sc].data = NULL;
\r
1094 MyLoadSound(&sounds[sc]);
\r
1099 SetCommPortDefaults()
\r
1101 memset(&dcb, 0, sizeof(DCB)); // required by VS 2002 +
\r
1102 dcb.DCBlength = sizeof(DCB);
\r
1103 dcb.BaudRate = 9600;
\r
1104 dcb.fBinary = TRUE;
\r
1105 dcb.fParity = FALSE;
\r
1106 dcb.fOutxCtsFlow = FALSE;
\r
1107 dcb.fOutxDsrFlow = FALSE;
\r
1108 dcb.fDtrControl = DTR_CONTROL_ENABLE;
\r
1109 dcb.fDsrSensitivity = FALSE;
\r
1110 dcb.fTXContinueOnXoff = TRUE;
\r
1111 dcb.fOutX = FALSE;
\r
1113 dcb.fNull = FALSE;
\r
1114 dcb.fRtsControl = RTS_CONTROL_ENABLE;
\r
1115 dcb.fAbortOnError = FALSE;
\r
1117 dcb.Parity = SPACEPARITY;
\r
1118 dcb.StopBits = ONESTOPBIT;
\r
1121 // [HGM] args: these three cases taken out to stay in front-end
\r
1123 SaveFontArg(FILE *f, ArgDescriptor *ad)
\r
1124 { // in WinBoard every board size has its own font, and the "argLoc" identifies the table,
\r
1125 // while the curent board size determines the element. This system should be ported to XBoard.
\r
1126 // What the table contains pointers to, and how to print the font description, remains platform-dependent
\r
1128 for (bs=0; bs<NUM_SIZES; bs++) {
\r
1129 MyFontParams *mfp = &font[bs][(int) ad->argLoc]->mfp;
\r
1130 fprintf(f, "/size=%s ", sizeInfo[bs].name);
\r
1131 fprintf(f, "/%s=\"%s:%g%s%s%s%s%sc%d\"\n",
\r
1132 ad->argName, mfp->faceName, mfp->pointSize,
\r
1133 mfp->bold || mfp->italic || mfp->underline || mfp->strikeout ? " " : "",
\r
1134 mfp->bold ? "b" : "",
\r
1135 mfp->italic ? "i" : "",
\r
1136 mfp->underline ? "u" : "",
\r
1137 mfp->strikeout ? "s" : "",
\r
1138 (int)mfp->charset);
\r
1144 { // [HGM] copy the names from the internal WB variables to appData
\r
1147 for (cc = (ColorClass)0; cc < ColorNormal; cc++)
\r
1148 (&appData.soundShout)[cc] = textAttribs[cc].sound.name;
\r
1149 for (sc = (SoundClass)0; sc < NSoundClasses; sc++)
\r
1150 (&appData.soundMove)[sc] = sounds[sc].name;
\r
1154 SaveAttribsArg(FILE *f, ArgDescriptor *ad)
\r
1155 { // here the "argLoc" defines a table index. It could have contained the 'ta' pointer itself, though
\r
1156 MyTextAttribs* ta = &textAttribs[(ColorClass)ad->argLoc];
\r
1157 fprintf(f, "/%s=\"%s%s%s%s%s#%02lx%02lx%02lx\"\n", ad->argName,
\r
1158 (ta->effects & CFE_BOLD) ? "b" : "",
\r
1159 (ta->effects & CFE_ITALIC) ? "i" : "",
\r
1160 (ta->effects & CFE_UNDERLINE) ? "u" : "",
\r
1161 (ta->effects & CFE_STRIKEOUT) ? "s" : "",
\r
1162 (ta->effects) ? " " : "",
\r
1163 ta->color&0xff, (ta->color >> 8)&0xff, (ta->color >> 16)&0xff);
\r
1167 SaveColor(FILE *f, ArgDescriptor *ad)
\r
1168 { // in WinBoard the color is an int and has to be converted to text. In X it would be a string already?
\r
1169 COLORREF color = *(COLORREF *)colorVariable[(int)ad->argLoc];
\r
1170 fprintf(f, "/%s=#%02lx%02lx%02lx\n", ad->argName,
\r
1171 color&0xff, (color>>8)&0xff, (color>>16)&0xff);
\r
1175 SaveBoardSize(FILE *f, char *name, void *addr)
\r
1176 { // wrapper to shield back-end from BoardSize & sizeInfo
\r
1177 fprintf(f, "/%s=%s\n", name, sizeInfo[*(BoardSize *)addr].name);
\r
1181 ParseCommPortSettings(char *s)
\r
1182 { // wrapper to keep dcb from back-end
\r
1183 ParseCommSettings(s, &dcb);
\r
1188 { // wrapper to shield use of window handles from back-end (make addressible by number?)
\r
1189 GetActualPlacement(hwndMain, &wpMain);
\r
1190 GetActualPlacement(hwndConsole, &wpConsole);
\r
1191 GetActualPlacement(commentDialog, &wpComment);
\r
1192 GetActualPlacement(editTagsDialog, &wpTags);
\r
1193 GetActualPlacement(gameListDialog, &wpGameList);
\r
1194 GetActualPlacement(moveHistoryDialog, &wpMoveHistory);
\r
1195 GetActualPlacement(evalGraphDialog, &wpEvalGraph);
\r
1196 GetActualPlacement(engineOutputDialog, &wpEngineOutput);
\r
1200 PrintCommPortSettings(FILE *f, char *name)
\r
1201 { // wrapper to shield back-end from DCB
\r
1202 PrintCommSettings(f, name, &dcb);
\r
1206 MySearchPath(char *installDir, char *name, char *fullname)
\r
1209 return (int) SearchPath(installDir, name, NULL, MSG_SIZ, fullname, &dummy);
\r
1213 MyGetFullPathName(char *name, char *fullname)
\r
1216 return (int) GetFullPathName(name, MSG_SIZ, fullname, &dummy);
\r
1221 { // [HGM] args: allows testing if main window is realized from back-end
\r
1222 return hwndMain != NULL;
\r
1226 PopUpStartupDialog()
\r
1230 lpProc = MakeProcInstance((FARPROC)StartupDialog, hInst);
\r
1231 DialogBox(hInst, MAKEINTRESOURCE(DLG_Startup), NULL, (DLGPROC)lpProc);
\r
1232 FreeProcInstance(lpProc);
\r
1235 /*---------------------------------------------------------------------------*\
\r
1237 * GDI board drawing routines
\r
1239 \*---------------------------------------------------------------------------*/
\r
1241 /* [AS] Draw square using background texture */
\r
1242 static void DrawTile( int dx, int dy, int dw, int dh, HDC dst, HDC src, int mode, int sx, int sy )
\r
1247 return; /* Should never happen! */
\r
1250 SetGraphicsMode( dst, GM_ADVANCED );
\r
1257 /* X reflection */
\r
1262 x.eDx = (FLOAT) dw + dx - 1;
\r
1265 SetWorldTransform( dst, &x );
\r
1268 /* Y reflection */
\r
1274 x.eDy = (FLOAT) dh + dy - 1;
\r
1276 SetWorldTransform( dst, &x );
\r
1284 x.eDx = (FLOAT) dx;
\r
1285 x.eDy = (FLOAT) dy;
\r
1288 SetWorldTransform( dst, &x );
\r
1292 BitBlt( dst, dx, dy, dw, dh, src, sx, sy, SRCCOPY );
\r
1300 SetWorldTransform( dst, &x );
\r
1302 ModifyWorldTransform( dst, 0, MWT_IDENTITY );
\r
1305 /* [AS] [HGM] Make room for more piece types, so all pieces can be different */
\r
1307 PM_WP = (int) WhitePawn,
\r
1308 PM_WN = (int) WhiteKnight,
\r
1309 PM_WB = (int) WhiteBishop,
\r
1310 PM_WR = (int) WhiteRook,
\r
1311 PM_WQ = (int) WhiteQueen,
\r
1312 PM_WF = (int) WhiteFerz,
\r
1313 PM_WW = (int) WhiteWazir,
\r
1314 PM_WE = (int) WhiteAlfil,
\r
1315 PM_WM = (int) WhiteMan,
\r
1316 PM_WO = (int) WhiteCannon,
\r
1317 PM_WU = (int) WhiteUnicorn,
\r
1318 PM_WH = (int) WhiteNightrider,
\r
1319 PM_WA = (int) WhiteAngel,
\r
1320 PM_WC = (int) WhiteMarshall,
\r
1321 PM_WAB = (int) WhiteCardinal,
\r
1322 PM_WD = (int) WhiteDragon,
\r
1323 PM_WL = (int) WhiteLance,
\r
1324 PM_WS = (int) WhiteCobra,
\r
1325 PM_WV = (int) WhiteFalcon,
\r
1326 PM_WSG = (int) WhiteSilver,
\r
1327 PM_WG = (int) WhiteGrasshopper,
\r
1328 PM_WK = (int) WhiteKing,
\r
1329 PM_BP = (int) BlackPawn,
\r
1330 PM_BN = (int) BlackKnight,
\r
1331 PM_BB = (int) BlackBishop,
\r
1332 PM_BR = (int) BlackRook,
\r
1333 PM_BQ = (int) BlackQueen,
\r
1334 PM_BF = (int) BlackFerz,
\r
1335 PM_BW = (int) BlackWazir,
\r
1336 PM_BE = (int) BlackAlfil,
\r
1337 PM_BM = (int) BlackMan,
\r
1338 PM_BO = (int) BlackCannon,
\r
1339 PM_BU = (int) BlackUnicorn,
\r
1340 PM_BH = (int) BlackNightrider,
\r
1341 PM_BA = (int) BlackAngel,
\r
1342 PM_BC = (int) BlackMarshall,
\r
1343 PM_BG = (int) BlackGrasshopper,
\r
1344 PM_BAB = (int) BlackCardinal,
\r
1345 PM_BD = (int) BlackDragon,
\r
1346 PM_BL = (int) BlackLance,
\r
1347 PM_BS = (int) BlackCobra,
\r
1348 PM_BV = (int) BlackFalcon,
\r
1349 PM_BSG = (int) BlackSilver,
\r
1350 PM_BK = (int) BlackKing
\r
1353 static HFONT hPieceFont = NULL;
\r
1354 static HBITMAP hPieceMask[(int) EmptySquare];
\r
1355 static HBITMAP hPieceFace[(int) EmptySquare];
\r
1356 static int fontBitmapSquareSize = 0;
\r
1357 static char pieceToFontChar[(int) EmptySquare] =
\r
1358 { 'p', 'n', 'b', 'r', 'q',
\r
1359 'n', 'b', 'p', 'n', 'b', 'r', 'b', 'r', 'q', 'k',
\r
1360 'k', 'o', 'm', 'v', 't', 'w',
\r
1361 'v', 't', 'o', 'm', 'v', 't', 'v', 't', 'w', 'l',
\r
1364 extern BOOL SetCharTable( char *table, const char * map );
\r
1365 /* [HGM] moved to backend.c */
\r
1367 static void SetPieceBackground( HDC hdc, COLORREF color, int mode )
\r
1370 BYTE r1 = GetRValue( color );
\r
1371 BYTE g1 = GetGValue( color );
\r
1372 BYTE b1 = GetBValue( color );
\r
1378 /* Create a uniform background first */
\r
1379 hbrush = CreateSolidBrush( color );
\r
1380 SetRect( &rc, 0, 0, squareSize, squareSize );
\r
1381 FillRect( hdc, &rc, hbrush );
\r
1382 DeleteObject( hbrush );
\r
1385 /* Vertical gradient, good for pawn, knight and rook, less for queen and king */
\r
1386 int steps = squareSize / 2;
\r
1389 for( i=0; i<steps; i++ ) {
\r
1390 BYTE r = r1 - (r1-r2) * i / steps;
\r
1391 BYTE g = g1 - (g1-g2) * i / steps;
\r
1392 BYTE b = b1 - (b1-b2) * i / steps;
\r
1394 hbrush = CreateSolidBrush( RGB(r,g,b) );
\r
1395 SetRect( &rc, i + squareSize - steps, 0, i + squareSize - steps + 1, squareSize );
\r
1396 FillRect( hdc, &rc, hbrush );
\r
1397 DeleteObject(hbrush);
\r
1400 else if( mode == 2 ) {
\r
1401 /* Diagonal gradient, good more or less for every piece */
\r
1402 POINT triangle[3];
\r
1403 HPEN hpen = SelectObject( hdc, GetStockObject(NULL_PEN) );
\r
1404 HBRUSH hbrush_old;
\r
1405 int steps = squareSize;
\r
1408 triangle[0].x = squareSize - steps;
\r
1409 triangle[0].y = squareSize;
\r
1410 triangle[1].x = squareSize;
\r
1411 triangle[1].y = squareSize;
\r
1412 triangle[2].x = squareSize;
\r
1413 triangle[2].y = squareSize - steps;
\r
1415 for( i=0; i<steps; i++ ) {
\r
1416 BYTE r = r1 - (r1-r2) * i / steps;
\r
1417 BYTE g = g1 - (g1-g2) * i / steps;
\r
1418 BYTE b = b1 - (b1-b2) * i / steps;
\r
1420 hbrush = CreateSolidBrush( RGB(r,g,b) );
\r
1421 hbrush_old = SelectObject( hdc, hbrush );
\r
1422 Polygon( hdc, triangle, 3 );
\r
1423 SelectObject( hdc, hbrush_old );
\r
1424 DeleteObject(hbrush);
\r
1429 SelectObject( hdc, hpen );
\r
1434 [AS] The method I use to create the bitmaps it a bit tricky, but it
\r
1435 seems to work ok. The main problem here is to find the "inside" of a chess
\r
1436 piece: follow the steps as explained below.
\r
1438 static void CreatePieceMaskFromFont( HDC hdc_window, HDC hdc, int index )
\r
1442 COLORREF chroma = RGB(0xFF,0x00,0xFF);
\r
1446 int backColor = whitePieceColor;
\r
1447 int foreColor = blackPieceColor;
\r
1449 if( index < (int)BlackPawn && appData.fontBackColorWhite != appData.fontForeColorWhite ) {
\r
1450 backColor = appData.fontBackColorWhite;
\r
1451 foreColor = appData.fontForeColorWhite;
\r
1453 else if( index >= (int)BlackPawn && appData.fontBackColorBlack != appData.fontForeColorBlack ) {
\r
1454 backColor = appData.fontBackColorBlack;
\r
1455 foreColor = appData.fontForeColorBlack;
\r
1459 hbm = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
\r
1461 hbm_old = SelectObject( hdc, hbm );
\r
1465 rc.right = squareSize;
\r
1466 rc.bottom = squareSize;
\r
1468 /* Step 1: background is now black */
\r
1469 FillRect( hdc, &rc, GetStockObject(BLACK_BRUSH) );
\r
1471 GetTextExtentPoint32( hdc, &pieceToFontChar[index], 1, &sz );
\r
1473 pt.x = (squareSize - sz.cx) / 2;
\r
1474 pt.y = (squareSize - sz.cy) / 2;
\r
1476 SetBkMode( hdc, TRANSPARENT );
\r
1477 SetTextColor( hdc, chroma );
\r
1478 /* Step 2: the piece has been drawn in purple, there are now black and purple in this bitmap */
\r
1479 TextOut( hdc, pt.x, pt.y, &pieceToFontChar[appData.allWhite && index >= (int)BlackPawn ? index - (int)BlackPawn : index], 1 );
\r
1481 SelectObject( hdc, GetStockObject(WHITE_BRUSH) );
\r
1482 /* Step 3: the area outside the piece is filled with white */
\r
1483 // FloodFill( hdc, 0, 0, chroma );
\r
1484 ExtFloodFill( hdc, 0, 0, 0, FLOODFILLSURFACE );
\r
1485 ExtFloodFill( hdc, 0, squareSize-1, 0, FLOODFILLSURFACE ); // [HGM] fill from all 4 corners, for if piece too big
\r
1486 ExtFloodFill( hdc, squareSize-1, 0, 0, FLOODFILLSURFACE );
\r
1487 ExtFloodFill( hdc, squareSize-1, squareSize-1, 0, FLOODFILLSURFACE );
\r
1488 SelectObject( hdc, GetStockObject(BLACK_BRUSH) );
\r
1490 Step 4: this is the tricky part, the area inside the piece is filled with black,
\r
1491 but if the start point is not inside the piece we're lost!
\r
1492 There should be a better way to do this... if we could create a region or path
\r
1493 from the fill operation we would be fine for example.
\r
1495 // FloodFill( hdc, squareSize / 2, squareSize / 2, RGB(0xFF,0xFF,0xFF) );
\r
1496 ExtFloodFill( hdc, squareSize / 2, squareSize / 2, RGB(0xFF,0xFF,0xFF), FLOODFILLBORDER );
\r
1498 { /* [HGM] shave off edges of mask, in an attempt to correct for the fact that FloodFill does not work correctly under Win XP */
\r
1499 HDC dc2 = CreateCompatibleDC( hdc_window );
\r
1500 HBITMAP bm2 = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
\r
1502 SelectObject( dc2, bm2 );
\r
1503 BitBlt( dc2, 0, 0, squareSize, squareSize, hdc, 0, 0, SRCCOPY ); // make copy
\r
1504 BitBlt( hdc, 0, 1, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );
\r
1505 BitBlt( hdc, 2, 1, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );
\r
1506 BitBlt( hdc, 1, 0, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );
\r
1507 BitBlt( hdc, 1, 2, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );
\r
1510 DeleteObject( bm2 );
\r
1513 SetTextColor( hdc, 0 );
\r
1515 Step 5: some fonts have "disconnected" areas that are skipped by the fill:
\r
1516 draw the piece again in black for safety.
\r
1518 TextOut( hdc, pt.x, pt.y, &pieceToFontChar[appData.allWhite && index >= (int)BlackPawn ? index - (int)BlackPawn : index], 1 );
\r
1520 SelectObject( hdc, hbm_old );
\r
1522 if( hPieceMask[index] != NULL ) {
\r
1523 DeleteObject( hPieceMask[index] );
\r
1526 hPieceMask[index] = hbm;
\r
1529 hbm = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
\r
1531 SelectObject( hdc, hbm );
\r
1534 HDC dc1 = CreateCompatibleDC( hdc_window );
\r
1535 HDC dc2 = CreateCompatibleDC( hdc_window );
\r
1536 HBITMAP bm2 = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
\r
1538 SelectObject( dc1, hPieceMask[index] );
\r
1539 SelectObject( dc2, bm2 );
\r
1540 FillRect( dc2, &rc, GetStockObject(WHITE_BRUSH) );
\r
1541 BitBlt( dc2, 0, 0, squareSize, squareSize, dc1, 0, 0, SRCINVERT );
\r
1544 Now dc2 contains the inverse of the piece mask, i.e. a mask that preserves
\r
1545 the piece background and deletes (makes transparent) the rest.
\r
1546 Thanks to that mask, we are free to paint the background with the greates
\r
1547 freedom, as we'll be able to mask off the unwanted parts when finished.
\r
1548 We use this, to make gradients and give the pieces a "roundish" look.
\r
1550 SetPieceBackground( hdc, backColor, 2 );
\r
1551 BitBlt( hdc, 0, 0, squareSize, squareSize, dc2, 0, 0, SRCAND );
\r
1555 DeleteObject( bm2 );
\r
1558 SetTextColor( hdc, foreColor );
\r
1559 TextOut( hdc, pt.x, pt.y, &pieceToFontChar[appData.allWhite && index >= (int)BlackPawn ? index - (int)BlackPawn : index], 1 );
\r
1561 SelectObject( hdc, hbm_old );
\r
1563 if( hPieceFace[index] != NULL ) {
\r
1564 DeleteObject( hPieceFace[index] );
\r
1567 hPieceFace[index] = hbm;
\r
1570 static int TranslatePieceToFontPiece( int piece )
\r
1600 case BlackMarshall:
\r
1604 case BlackNightrider:
\r
1610 case BlackUnicorn:
\r
1614 case BlackGrasshopper:
\r
1626 case BlackCardinal:
\r
1633 case WhiteMarshall:
\r
1637 case WhiteNightrider:
\r
1643 case WhiteUnicorn:
\r
1647 case WhiteGrasshopper:
\r
1659 case WhiteCardinal:
\r
1668 void CreatePiecesFromFont()
\r
1671 HDC hdc_window = NULL;
\r
1677 if( fontBitmapSquareSize < 0 ) {
\r
1678 /* Something went seriously wrong in the past: do not try to recreate fonts! */
\r
1682 if( appData.renderPiecesWithFont == NULL || appData.renderPiecesWithFont[0] == NULLCHAR || appData.renderPiecesWithFont[0] == '*' ) {
\r
1683 fontBitmapSquareSize = -1;
\r
1687 if( fontBitmapSquareSize != squareSize ) {
\r
1688 hdc_window = GetDC( hwndMain );
\r
1689 hdc = CreateCompatibleDC( hdc_window );
\r
1691 if( hPieceFont != NULL ) {
\r
1692 DeleteObject( hPieceFont );
\r
1695 for( i=0; i<=(int)BlackKing; i++ ) {
\r
1696 hPieceMask[i] = NULL;
\r
1697 hPieceFace[i] = NULL;
\r
1703 if( appData.fontPieceSize >= 50 && appData.fontPieceSize <= 150 ) {
\r
1704 fontHeight = appData.fontPieceSize;
\r
1707 fontHeight = (fontHeight * squareSize) / 100;
\r
1709 lf.lfHeight = -MulDiv( fontHeight, GetDeviceCaps(hdc, LOGPIXELSY), 72 );
\r
1711 lf.lfEscapement = 0;
\r
1712 lf.lfOrientation = 0;
\r
1713 lf.lfWeight = FW_NORMAL;
\r
1715 lf.lfUnderline = 0;
\r
1716 lf.lfStrikeOut = 0;
\r
1717 lf.lfCharSet = DEFAULT_CHARSET;
\r
1718 lf.lfOutPrecision = OUT_DEFAULT_PRECIS;
\r
1719 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
\r
1720 lf.lfQuality = PROOF_QUALITY;
\r
1721 lf.lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;
\r
1722 strncpy( lf.lfFaceName, appData.renderPiecesWithFont, sizeof(lf.lfFaceName) );
\r
1723 lf.lfFaceName[ sizeof(lf.lfFaceName) - 1 ] = '\0';
\r
1725 hPieceFont = CreateFontIndirect( &lf );
\r
1727 if( hPieceFont == NULL ) {
\r
1728 fontBitmapSquareSize = -2;
\r
1731 /* Setup font-to-piece character table */
\r
1732 if( ! SetCharTable(pieceToFontChar, appData.fontToPieceTable) ) {
\r
1733 /* No (or wrong) global settings, try to detect the font */
\r
1734 if( strstr(lf.lfFaceName,"Alpha") != NULL ) {
\r
1736 SetCharTable(pieceToFontChar, "phbrqkojntwl");
\r
1738 else if( strstr(lf.lfFaceName,"DiagramTT") != NULL ) {
\r
1739 /* DiagramTT* family */
\r
1740 SetCharTable(pieceToFontChar, "PNLRQKpnlrqk");
\r
1742 else if( strstr(lf.lfFaceName,"WinboardF") != NULL ) {
\r
1743 /* Fairy symbols */
\r
1744 SetCharTable(pieceToFontChar, "PNBRQFEACWMOHIJGDVSLUKpnbrqfeacwmohijgdvsluk");
\r
1746 else if( strstr(lf.lfFaceName,"GC2004D") != NULL ) {
\r
1747 /* Good Companion (Some characters get warped as literal :-( */
\r
1748 char s[] = "1cmWG0??S??oYI23wgQU";
\r
1749 s[0]=0xB9; s[1]=0xA9; s[6]=0xB1; s[11]=0xBB; s[12]=0xAB; s[17]=0xB3;
\r
1750 SetCharTable(pieceToFontChar, s);
\r
1753 /* Cases, Condal, Leipzig, Lucena, Marroquin, Merida, Usual */
\r
1754 SetCharTable(pieceToFontChar, "pnbrqkomvtwl");
\r
1758 /* Create bitmaps */
\r
1759 hfont_old = SelectObject( hdc, hPieceFont );
\r
1760 for(i=(int)WhitePawn; i<(int)EmptySquare; i++) /* [HGM] made a loop for this */
\r
1761 if(PieceToChar((ChessSquare)i) != '.') /* skip unused pieces */
\r
1762 CreatePieceMaskFromFont( hdc_window, hdc, i );
\r
1764 SelectObject( hdc, hfont_old );
\r
1766 fontBitmapSquareSize = squareSize;
\r
1770 if( hdc != NULL ) {
\r
1774 if( hdc_window != NULL ) {
\r
1775 ReleaseDC( hwndMain, hdc_window );
\r
1780 DoLoadBitmap(HINSTANCE hinst, char *piece, int squareSize, char *suffix)
\r
1784 sprintf(name, "%s%d%s", piece, squareSize, suffix);
\r
1785 if (gameInfo.event &&
\r
1786 strcmp(gameInfo.event, "Easter Egg Hunt") == 0 &&
\r
1787 strcmp(name, "k80s") == 0) {
\r
1788 strcpy(name, "tim");
\r
1790 return LoadBitmap(hinst, name);
\r
1794 /* Insert a color into the program's logical palette
\r
1795 structure. This code assumes the given color is
\r
1796 the result of the RGB or PALETTERGB macro, and it
\r
1797 knows how those macros work (which is documented).
\r
1800 InsertInPalette(COLORREF color)
\r
1802 LPPALETTEENTRY pe = &(pLogPal->palPalEntry[pLogPal->palNumEntries]);
\r
1804 if (pLogPal->palNumEntries++ >= PALETTESIZE) {
\r
1805 DisplayFatalError("Too many colors", 0, 1);
\r
1806 pLogPal->palNumEntries--;
\r
1810 pe->peFlags = (char) 0;
\r
1811 pe->peRed = (char) (0xFF & color);
\r
1812 pe->peGreen = (char) (0xFF & (color >> 8));
\r
1813 pe->peBlue = (char) (0xFF & (color >> 16));
\r
1819 InitDrawingColors()
\r
1821 if (pLogPal == NULL) {
\r
1822 /* Allocate enough memory for a logical palette with
\r
1823 * PALETTESIZE entries and set the size and version fields
\r
1824 * of the logical palette structure.
\r
1826 pLogPal = (NPLOGPALETTE)
\r
1827 LocalAlloc(LMEM_FIXED, (sizeof(LOGPALETTE) +
\r
1828 (sizeof(PALETTEENTRY) * (PALETTESIZE))));
\r
1829 pLogPal->palVersion = 0x300;
\r
1831 pLogPal->palNumEntries = 0;
\r
1833 InsertInPalette(lightSquareColor);
\r
1834 InsertInPalette(darkSquareColor);
\r
1835 InsertInPalette(whitePieceColor);
\r
1836 InsertInPalette(blackPieceColor);
\r
1837 InsertInPalette(highlightSquareColor);
\r
1838 InsertInPalette(premoveHighlightColor);
\r
1840 /* create a logical color palette according the information
\r
1841 * in the LOGPALETTE structure.
\r
1843 hPal = CreatePalette((LPLOGPALETTE) pLogPal);
\r
1845 lightSquareBrush = CreateSolidBrush(lightSquareColor);
\r
1846 blackSquareBrush = CreateSolidBrush(blackPieceColor);
\r
1847 darkSquareBrush = CreateSolidBrush(darkSquareColor);
\r
1848 whitePieceBrush = CreateSolidBrush(whitePieceColor);
\r
1849 blackPieceBrush = CreateSolidBrush(blackPieceColor);
\r
1850 iconBkgndBrush = CreateSolidBrush(GetSysColor(COLOR_BACKGROUND));
\r
1851 explodeBrush = CreateSolidBrush(highlightSquareColor); // [HGM] atomic
\r
1852 /* [AS] Force rendering of the font-based pieces */
\r
1853 if( fontBitmapSquareSize > 0 ) {
\r
1854 fontBitmapSquareSize = 0;
\r
1860 BoardWidth(int boardSize, int n)
\r
1861 { /* [HGM] argument n added to allow different width and height */
\r
1862 int lineGap = sizeInfo[boardSize].lineGap;
\r
1864 if( appData.overrideLineGap >= 0 && appData.overrideLineGap <= 5 ) {
\r
1865 lineGap = appData.overrideLineGap;
\r
1868 return (n + 1) * lineGap +
\r
1869 n * sizeInfo[boardSize].squareSize;
\r
1872 /* Respond to board resize by dragging edge */
\r
1874 ResizeBoard(int newSizeX, int newSizeY, int flags)
\r
1876 BoardSize newSize = NUM_SIZES - 1;
\r
1877 static int recurse = 0;
\r
1878 if (IsIconic(hwndMain)) return;
\r
1879 if (recurse > 0) return;
\r
1881 while (newSize > 0) {
\r
1882 InitDrawingSizes(newSize+1000, 0); // [HGM] kludge to update sizeInfo without visible effects
\r
1883 if(newSizeX >= sizeInfo[newSize].cliWidth &&
\r
1884 newSizeY >= sizeInfo[newSize].cliHeight) break;
\r
1887 boardSize = newSize;
\r
1888 InitDrawingSizes(boardSize, flags);
\r
1895 InitDrawingSizes(BoardSize boardSize, int flags)
\r
1897 int i, boardWidth, boardHeight; /* [HGM] height treated separately */
\r
1898 ChessSquare piece;
\r
1899 static int oldBoardSize = -1, oldTinyLayout = 0;
\r
1901 SIZE clockSize, messageSize;
\r
1903 char buf[MSG_SIZ];
\r
1905 HMENU hmenu = GetMenu(hwndMain);
\r
1906 RECT crect, wrect, oldRect;
\r
1908 LOGBRUSH logbrush;
\r
1910 int suppressVisibleEffects = 0; // [HGM] kludge to request updating sizeInfo only
\r
1911 if((int)boardSize >= 1000 ) { boardSize -= 1000; suppressVisibleEffects = 1; }
\r
1913 /* [HGM] call with -2 uses old size (for if nr of files, ranks changes) */
\r
1914 if(boardSize == (BoardSize)(-2) ) boardSize = oldBoardSize;
\r
1916 oldRect.left = wpMain.x; //[HGM] placement: remember previous window params
\r
1917 oldRect.top = wpMain.y;
\r
1918 oldRect.right = wpMain.x + wpMain.width;
\r
1919 oldRect.bottom = wpMain.y + wpMain.height;
\r
1921 tinyLayout = sizeInfo[boardSize].tinyLayout;
\r
1922 smallLayout = sizeInfo[boardSize].smallLayout;
\r
1923 squareSize = sizeInfo[boardSize].squareSize;
\r
1924 lineGap = sizeInfo[boardSize].lineGap;
\r
1925 minorSize = 0; /* [HGM] Kludge to see if demagnified pieces need to be shifted */
\r
1927 if( appData.overrideLineGap >= 0 && appData.overrideLineGap <= 5 ) {
\r
1928 lineGap = appData.overrideLineGap;
\r
1931 if (tinyLayout != oldTinyLayout) {
\r
1932 long style = GetWindowLong(hwndMain, GWL_STYLE);
\r
1934 style &= ~WS_SYSMENU;
\r
1935 InsertMenu(hmenu, IDM_Exit, MF_BYCOMMAND, IDM_Minimize,
\r
1936 "&Minimize\tCtrl+F4");
\r
1938 style |= WS_SYSMENU;
\r
1939 RemoveMenu(hmenu, IDM_Minimize, MF_BYCOMMAND);
\r
1941 SetWindowLong(hwndMain, GWL_STYLE, style);
\r
1943 for (i=0; menuBarText[tinyLayout][i]; i++) {
\r
1944 ModifyMenu(hmenu, i, MF_STRING|MF_BYPOSITION|MF_POPUP,
\r
1945 (UINT)GetSubMenu(hmenu, i), menuBarText[tinyLayout][i]);
\r
1947 DrawMenuBar(hwndMain);
\r
1950 boardWidth = BoardWidth(boardSize, BOARD_WIDTH);
\r
1951 boardHeight = BoardWidth(boardSize, BOARD_HEIGHT);
\r
1953 /* Get text area sizes */
\r
1954 hdc = GetDC(hwndMain);
\r
1955 if (appData.clockMode) {
\r
1956 sprintf(buf, "White: %s", TimeString(23*60*60*1000L));
\r
1958 sprintf(buf, "White");
\r
1960 oldFont = SelectObject(hdc, font[boardSize][CLOCK_FONT]->hf);
\r
1961 GetTextExtentPoint(hdc, buf, strlen(buf), &clockSize);
\r
1962 SelectObject(hdc, font[boardSize][MESSAGE_FONT]->hf);
\r
1963 str = "We only care about the height here";
\r
1964 GetTextExtentPoint(hdc, str, strlen(str), &messageSize);
\r
1965 SelectObject(hdc, oldFont);
\r
1966 ReleaseDC(hwndMain, hdc);
\r
1968 /* Compute where everything goes */
\r
1969 if((first.programLogo || second.programLogo) && !tinyLayout) {
\r
1970 /* [HGM] logo: if either logo is on, reserve space for it */
\r
1971 logoHeight = 2*clockSize.cy;
\r
1972 leftLogoRect.left = OUTER_MARGIN;
\r
1973 leftLogoRect.right = leftLogoRect.left + 4*clockSize.cy;
\r
1974 leftLogoRect.top = OUTER_MARGIN;
\r
1975 leftLogoRect.bottom = OUTER_MARGIN + logoHeight;
\r
1977 rightLogoRect.right = OUTER_MARGIN + boardWidth;
\r
1978 rightLogoRect.left = rightLogoRect.right - 4*clockSize.cy;
\r
1979 rightLogoRect.top = OUTER_MARGIN;
\r
1980 rightLogoRect.bottom = OUTER_MARGIN + logoHeight;
\r
1983 whiteRect.left = leftLogoRect.right;
\r
1984 whiteRect.right = OUTER_MARGIN + boardWidth/2 - INNER_MARGIN/2;
\r
1985 whiteRect.top = OUTER_MARGIN;
\r
1986 whiteRect.bottom = whiteRect.top + logoHeight;
\r
1988 blackRect.right = rightLogoRect.left;
\r
1989 blackRect.left = whiteRect.right + INNER_MARGIN;
\r
1990 blackRect.top = whiteRect.top;
\r
1991 blackRect.bottom = whiteRect.bottom;
\r
1993 whiteRect.left = OUTER_MARGIN;
\r
1994 whiteRect.right = whiteRect.left + boardWidth/2 - INNER_MARGIN/2;
\r
1995 whiteRect.top = OUTER_MARGIN;
\r
1996 whiteRect.bottom = whiteRect.top + clockSize.cy;
\r
1998 blackRect.left = whiteRect.right + INNER_MARGIN;
\r
1999 blackRect.right = blackRect.left + boardWidth/2 - 1;
\r
2000 blackRect.top = whiteRect.top;
\r
2001 blackRect.bottom = whiteRect.bottom;
\r
2004 messageRect.left = OUTER_MARGIN + MESSAGE_LINE_LEFTMARGIN;
\r
2005 if (appData.showButtonBar) {
\r
2006 messageRect.right = OUTER_MARGIN + boardWidth // [HGM] logo: expressed independent of clock placement
\r
2007 - N_BUTTONS*BUTTON_WIDTH - MESSAGE_LINE_LEFTMARGIN;
\r
2009 messageRect.right = OUTER_MARGIN + boardWidth;
\r
2011 messageRect.top = whiteRect.bottom + INNER_MARGIN;
\r
2012 messageRect.bottom = messageRect.top + messageSize.cy;
\r
2014 boardRect.left = OUTER_MARGIN;
\r
2015 boardRect.right = boardRect.left + boardWidth;
\r
2016 boardRect.top = messageRect.bottom + INNER_MARGIN;
\r
2017 boardRect.bottom = boardRect.top + boardHeight;
\r
2019 sizeInfo[boardSize].cliWidth = boardRect.right + OUTER_MARGIN;
\r
2020 sizeInfo[boardSize].cliHeight = boardRect.bottom + OUTER_MARGIN;
\r
2021 oldBoardSize = boardSize;
\r
2022 oldTinyLayout = tinyLayout;
\r
2023 winW = 2 * GetSystemMetrics(SM_CXFRAME) + boardRect.right + OUTER_MARGIN;
\r
2024 winH = 2 * GetSystemMetrics(SM_CYFRAME) + GetSystemMetrics(SM_CYMENU) +
\r
2025 GetSystemMetrics(SM_CYCAPTION) + boardRect.bottom + OUTER_MARGIN;
\r
2026 if(suppressVisibleEffects) return; // [HGM] when called for filling sizeInfo only
\r
2027 wpMain.width = winW; // [HGM] placement: set through temporary which can used by initial sizing choice
\r
2028 wpMain.height = winH; // without disturbing window attachments
\r
2029 GetWindowRect(hwndMain, &wrect);
\r
2030 SetWindowPos(hwndMain, NULL, 0, 0, wpMain.width, wpMain.height,
\r
2031 SWP_NOCOPYBITS|SWP_NOZORDER|SWP_NOMOVE);
\r
2033 // [HGM] placement: let attached windows follow size change.
\r
2034 ReattachAfterSize( &oldRect, wpMain.width, wpMain.height, moveHistoryDialog, &wpMoveHistory );
\r
2035 ReattachAfterSize( &oldRect, wpMain.width, wpMain.height, evalGraphDialog, &wpEvalGraph );
\r
2036 ReattachAfterSize( &oldRect, wpMain.width, wpMain.height, engineOutputDialog, &wpEngineOutput );
\r
2037 ReattachAfterSize( &oldRect, wpMain.width, wpMain.height, gameListDialog, &wpGameList );
\r
2038 ReattachAfterSize( &oldRect, wpMain.width, wpMain.height, hwndConsole, &wpConsole );
\r
2040 /* compensate if menu bar wrapped */
\r
2041 GetClientRect(hwndMain, &crect);
\r
2042 offby = boardRect.bottom + OUTER_MARGIN - crect.bottom;
\r
2043 wpMain.height += offby;
\r
2045 case WMSZ_TOPLEFT:
\r
2046 SetWindowPos(hwndMain, NULL,
\r
2047 wrect.right - wpMain.width, wrect.bottom - wpMain.height,
\r
2048 wpMain.width, wpMain.height, SWP_NOCOPYBITS|SWP_NOZORDER);
\r
2051 case WMSZ_TOPRIGHT:
\r
2053 SetWindowPos(hwndMain, NULL,
\r
2054 wrect.left, wrect.bottom - wpMain.height,
\r
2055 wpMain.width, wpMain.height, SWP_NOCOPYBITS|SWP_NOZORDER);
\r
2058 case WMSZ_BOTTOMLEFT:
\r
2060 SetWindowPos(hwndMain, NULL,
\r
2061 wrect.right - wpMain.width, wrect.top,
\r
2062 wpMain.width, wpMain.height, SWP_NOCOPYBITS|SWP_NOZORDER);
\r
2065 case WMSZ_BOTTOMRIGHT:
\r
2069 SetWindowPos(hwndMain, NULL, 0, 0, wpMain.width, wpMain.height,
\r
2070 SWP_NOCOPYBITS|SWP_NOZORDER|SWP_NOMOVE);
\r
2075 for (i = 0; i < N_BUTTONS; i++) {
\r
2076 if (buttonDesc[i].hwnd != NULL) {
\r
2077 DestroyWindow(buttonDesc[i].hwnd);
\r
2078 buttonDesc[i].hwnd = NULL;
\r
2080 if (appData.showButtonBar) {
\r
2081 buttonDesc[i].hwnd =
\r
2082 CreateWindow("BUTTON", buttonDesc[i].label,
\r
2083 WS_VISIBLE | WS_CHILD | BS_PUSHBUTTON,
\r
2084 boardRect.right - BUTTON_WIDTH*(N_BUTTONS-i),
\r
2085 messageRect.top, BUTTON_WIDTH, messageSize.cy, hwndMain,
\r
2086 (HMENU) buttonDesc[i].id,
\r
2087 (HINSTANCE) GetWindowLong(hwndMain, GWL_HINSTANCE), NULL);
\r
2089 SendMessage(buttonDesc[i].hwnd, WM_SETFONT,
\r
2090 (WPARAM)font[boardSize][MESSAGE_FONT]->hf,
\r
2091 MAKELPARAM(FALSE, 0));
\r
2093 if (buttonDesc[i].id == IDM_Pause)
\r
2094 hwndPause = buttonDesc[i].hwnd;
\r
2095 buttonDesc[i].wndproc = (WNDPROC)
\r
2096 SetWindowLong(buttonDesc[i].hwnd, GWL_WNDPROC, (LONG) ButtonProc);
\r
2099 if (gridPen != NULL) DeleteObject(gridPen);
\r
2100 if (highlightPen != NULL) DeleteObject(highlightPen);
\r
2101 if (premovePen != NULL) DeleteObject(premovePen);
\r
2102 if (lineGap != 0) {
\r
2103 logbrush.lbStyle = BS_SOLID;
\r
2104 logbrush.lbColor = RGB(0, 0, 0); /* grid pen color = black */
\r
2106 ExtCreatePen(PS_GEOMETRIC|PS_SOLID|PS_ENDCAP_FLAT|PS_JOIN_MITER,
\r
2107 lineGap, &logbrush, 0, NULL);
\r
2108 logbrush.lbColor = highlightSquareColor;
\r
2110 ExtCreatePen(PS_GEOMETRIC|PS_SOLID|PS_ENDCAP_FLAT|PS_JOIN_MITER,
\r
2111 lineGap, &logbrush, 0, NULL);
\r
2113 logbrush.lbColor = premoveHighlightColor;
\r
2115 ExtCreatePen(PS_GEOMETRIC|PS_SOLID|PS_ENDCAP_FLAT|PS_JOIN_MITER,
\r
2116 lineGap, &logbrush, 0, NULL);
\r
2118 /* [HGM] Loop had to be split in part for vert. and hor. lines */
\r
2119 for (i = 0; i < BOARD_HEIGHT + 1; i++) {
\r
2120 gridEndpoints[i*2].x = boardRect.left + lineGap / 2;
\r
2121 gridEndpoints[i*2].y = gridEndpoints[i*2 + 1].y =
\r
2122 boardRect.top + lineGap / 2 + (i * (squareSize + lineGap));
\r
2123 gridEndpoints[i*2 + 1].x = boardRect.left + lineGap / 2 +
\r
2124 BOARD_WIDTH * (squareSize + lineGap);
\r
2125 gridVertexCounts[i*2] = gridVertexCounts[i*2 + 1] = 2;
\r
2127 for (i = 0; i < BOARD_WIDTH + 1; i++) {
\r
2128 gridEndpoints[i*2 + BOARD_HEIGHT*2 + 2].y = boardRect.top + lineGap / 2;
\r
2129 gridEndpoints[i*2 + BOARD_HEIGHT*2 + 2].x =
\r
2130 gridEndpoints[i*2 + 1 + BOARD_HEIGHT*2 + 2].x = boardRect.left +
\r
2131 lineGap / 2 + (i * (squareSize + lineGap));
\r
2132 gridEndpoints[i*2 + 1 + BOARD_HEIGHT*2 + 2].y =
\r
2133 boardRect.top + BOARD_HEIGHT * (squareSize + lineGap);
\r
2134 gridVertexCounts[i*2] = gridVertexCounts[i*2 + 1] = 2;
\r
2138 /* [HGM] Licensing requirement */
\r
2140 if(gameInfo.variant == VariantGothic) GothicPopUp( GOTHIC, VariantGothic); else
\r
2143 if(gameInfo.variant == VariantFalcon) GothicPopUp( FALCON, VariantFalcon); else
\r
2145 GothicPopUp( "", VariantNormal);
\r
2148 /* if (boardSize == oldBoardSize) return; [HGM] variant might have changed */
\r
2150 /* Load piece bitmaps for this board size */
\r
2151 for (i=0; i<=2; i++) {
\r
2152 for (piece = WhitePawn;
\r
2153 (int) piece < (int) BlackPawn;
\r
2154 piece = (ChessSquare) ((int) piece + 1)) {
\r
2155 if (pieceBitmap[i][piece] != NULL)
\r
2156 DeleteObject(pieceBitmap[i][piece]);
\r
2160 fontBitmapSquareSize = 0; /* [HGM] render: make sure pieces will be recreated, as we might need others now */
\r
2161 // Orthodox Chess pieces
\r
2162 pieceBitmap[0][WhitePawn] = DoLoadBitmap(hInst, "p", squareSize, "s");
\r
2163 pieceBitmap[0][WhiteKnight] = DoLoadBitmap(hInst, "n", squareSize, "s");
\r
2164 pieceBitmap[0][WhiteBishop] = DoLoadBitmap(hInst, "b", squareSize, "s");
\r
2165 pieceBitmap[0][WhiteRook] = DoLoadBitmap(hInst, "r", squareSize, "s");
\r
2166 pieceBitmap[0][WhiteKing] = DoLoadBitmap(hInst, "k", squareSize, "s");
\r
2167 pieceBitmap[1][WhitePawn] = DoLoadBitmap(hInst, "p", squareSize, "o");
\r
2168 pieceBitmap[1][WhiteKnight] = DoLoadBitmap(hInst, "n", squareSize, "o");
\r
2169 pieceBitmap[1][WhiteBishop] = DoLoadBitmap(hInst, "b", squareSize, "o");
\r
2170 pieceBitmap[1][WhiteRook] = DoLoadBitmap(hInst, "r", squareSize, "o");
\r
2171 pieceBitmap[1][WhiteKing] = DoLoadBitmap(hInst, "k", squareSize, "o");
\r
2172 pieceBitmap[2][WhitePawn] = DoLoadBitmap(hInst, "p", squareSize, "w");
\r
2173 pieceBitmap[2][WhiteKnight] = DoLoadBitmap(hInst, "n", squareSize, "w");
\r
2174 pieceBitmap[2][WhiteBishop] = DoLoadBitmap(hInst, "b", squareSize, "w");
\r
2175 pieceBitmap[2][WhiteRook] = DoLoadBitmap(hInst, "r", squareSize, "w");
\r
2176 pieceBitmap[2][WhiteKing] = DoLoadBitmap(hInst, "k", squareSize, "w");
\r
2177 if( !strcmp(appData.variant, "shogi") && (squareSize==72 || squareSize==49)) {
\r
2178 // in Shogi, Hijack the unused Queen for Lance
\r
2179 pieceBitmap[0][WhiteQueen] = DoLoadBitmap(hInst, "l", squareSize, "s");
\r
2180 pieceBitmap[1][WhiteQueen] = DoLoadBitmap(hInst, "l", squareSize, "o");
\r
2181 pieceBitmap[2][WhiteQueen] = DoLoadBitmap(hInst, "l", squareSize, "w");
\r
2183 pieceBitmap[0][WhiteQueen] = DoLoadBitmap(hInst, "q", squareSize, "s");
\r
2184 pieceBitmap[1][WhiteQueen] = DoLoadBitmap(hInst, "q", squareSize, "o");
\r
2185 pieceBitmap[2][WhiteQueen] = DoLoadBitmap(hInst, "q", squareSize, "w");
\r
2188 if(squareSize <= 72 && squareSize >= 33) {
\r
2189 /* A & C are available in most sizes now */
\r
2190 if(squareSize != 49 && squareSize != 72 && squareSize != 33) { // Vortex-like
\r
2191 pieceBitmap[0][WhiteAngel] = DoLoadBitmap(hInst, "a", squareSize, "s");
\r
2192 pieceBitmap[1][WhiteAngel] = DoLoadBitmap(hInst, "a", squareSize, "o");
\r
2193 pieceBitmap[2][WhiteAngel] = DoLoadBitmap(hInst, "a", squareSize, "w");
\r
2194 pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "s");
\r
2195 pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "o");
\r
2196 pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "w");
\r
2197 pieceBitmap[0][WhiteCobra] = DoLoadBitmap(hInst, "cv", squareSize, "s");
\r
2198 pieceBitmap[1][WhiteCobra] = DoLoadBitmap(hInst, "cv", squareSize, "o");
\r
2199 pieceBitmap[2][WhiteCobra] = DoLoadBitmap(hInst, "cv", squareSize, "w");
\r
2200 pieceBitmap[0][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "s");
\r
2201 pieceBitmap[1][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "o");
\r
2202 pieceBitmap[2][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "w");
\r
2203 } else { // Smirf-like
\r
2204 pieceBitmap[0][WhiteAngel] = DoLoadBitmap(hInst, "aa", squareSize, "s");
\r
2205 pieceBitmap[1][WhiteAngel] = DoLoadBitmap(hInst, "aa", squareSize, "o");
\r
2206 pieceBitmap[2][WhiteAngel] = DoLoadBitmap(hInst, "aa", squareSize, "w");
\r
2208 if(gameInfo.variant == VariantGothic) { // Vortex-like
\r
2209 pieceBitmap[0][WhiteMarshall] = DoLoadBitmap(hInst, "cv", squareSize, "s");
\r
2210 pieceBitmap[1][WhiteMarshall] = DoLoadBitmap(hInst, "cv", squareSize, "o");
\r
2211 pieceBitmap[2][WhiteMarshall] = DoLoadBitmap(hInst, "cv", squareSize, "w");
\r
2212 } else { // WinBoard standard
\r
2213 pieceBitmap[0][WhiteMarshall] = DoLoadBitmap(hInst, "c", squareSize, "s");
\r
2214 pieceBitmap[1][WhiteMarshall] = DoLoadBitmap(hInst, "c", squareSize, "o");
\r
2215 pieceBitmap[2][WhiteMarshall] = DoLoadBitmap(hInst, "c", squareSize, "w");
\r
2220 if(squareSize==72 || squareSize==49 || squareSize==33) { /* experiment with some home-made bitmaps */
\r
2221 pieceBitmap[0][WhiteFerz] = DoLoadBitmap(hInst, "f", squareSize, "s");
\r
2222 pieceBitmap[1][WhiteFerz] = DoLoadBitmap(hInst, "f", squareSize, "o");
\r
2223 pieceBitmap[2][WhiteFerz] = DoLoadBitmap(hInst, "f", squareSize, "w");
\r
2224 pieceBitmap[0][WhiteWazir] = DoLoadBitmap(hInst, "w", squareSize, "s");
\r
2225 pieceBitmap[1][WhiteWazir] = DoLoadBitmap(hInst, "w", squareSize, "o");
\r
2226 pieceBitmap[2][WhiteWazir] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
2227 pieceBitmap[0][WhiteAlfil] = DoLoadBitmap(hInst, "e", squareSize, "s");
\r
2228 pieceBitmap[1][WhiteAlfil] = DoLoadBitmap(hInst, "e", squareSize, "o");
\r
2229 pieceBitmap[2][WhiteAlfil] = DoLoadBitmap(hInst, "e", squareSize, "w");
\r
2230 pieceBitmap[0][WhiteMan] = DoLoadBitmap(hInst, "m", squareSize, "s");
\r
2231 pieceBitmap[1][WhiteMan] = DoLoadBitmap(hInst, "m", squareSize, "o");
\r
2232 pieceBitmap[2][WhiteMan] = DoLoadBitmap(hInst, "m", squareSize, "w");
\r
2233 pieceBitmap[0][WhiteCardinal] = DoLoadBitmap(hInst, "a", squareSize, "s");
\r
2234 pieceBitmap[1][WhiteCardinal] = DoLoadBitmap(hInst, "a", squareSize, "o");
\r
2235 pieceBitmap[2][WhiteCardinal] = DoLoadBitmap(hInst, "a", squareSize, "w");
\r
2236 pieceBitmap[0][WhiteDragon] = DoLoadBitmap(hInst, "dk", squareSize, "s");
\r
2237 pieceBitmap[1][WhiteDragon] = DoLoadBitmap(hInst, "dk", squareSize, "o");
\r
2238 pieceBitmap[2][WhiteDragon] = DoLoadBitmap(hInst, "dk", squareSize, "w");
\r
2239 pieceBitmap[0][WhiteFalcon] = DoLoadBitmap(hInst, "v", squareSize, "s");
\r
2240 pieceBitmap[1][WhiteFalcon] = DoLoadBitmap(hInst, "v", squareSize, "o");
\r
2241 pieceBitmap[2][WhiteFalcon] = DoLoadBitmap(hInst, "v", squareSize, "w");
\r
2242 pieceBitmap[0][WhiteCobra] = DoLoadBitmap(hInst, "s", squareSize, "s");
\r
2243 pieceBitmap[1][WhiteCobra] = DoLoadBitmap(hInst, "s", squareSize, "o");
\r
2244 pieceBitmap[2][WhiteCobra] = DoLoadBitmap(hInst, "s", squareSize, "w");
\r
2245 pieceBitmap[0][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "s");
\r
2246 pieceBitmap[1][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "o");
\r
2247 pieceBitmap[2][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "w");
\r
2248 pieceBitmap[0][WhiteUnicorn] = DoLoadBitmap(hInst, "u", squareSize, "s");
\r
2249 pieceBitmap[1][WhiteUnicorn] = DoLoadBitmap(hInst, "u", squareSize, "o");
\r
2250 pieceBitmap[2][WhiteUnicorn] = DoLoadBitmap(hInst, "u", squareSize, "w");
\r
2252 if(gameInfo.variant == VariantShogi) { /* promoted Gold represemtations */
\r
2253 pieceBitmap[0][WhiteCannon] = DoLoadBitmap(hInst, "wp", squareSize, "s");
\r
2254 pieceBitmap[1][WhiteCannon] = DoLoadBitmap(hInst, "wp", squareSize, "o");
\r
2255 pieceBitmap[2][WhiteCannon] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
2256 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "wn", squareSize, "s");
\r
2257 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "wn", squareSize, "o");
\r
2258 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
2259 pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "ws", squareSize, "s");
\r
2260 pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "ws", squareSize, "o");
\r
2261 pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
2262 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "wl", squareSize, "s");
\r
2263 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "wl", squareSize, "o");
\r
2264 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
2266 pieceBitmap[0][WhiteCannon] = DoLoadBitmap(hInst, "o", squareSize, "s");
\r
2267 pieceBitmap[1][WhiteCannon] = DoLoadBitmap(hInst, "o", squareSize, "o");
\r
2268 pieceBitmap[2][WhiteCannon] = DoLoadBitmap(hInst, "o", squareSize, "w");
\r
2269 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "h", squareSize, "s");
\r
2270 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "h", squareSize, "o");
\r
2271 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "h", squareSize, "w");
\r
2272 pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "s");
\r
2273 pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "o");
\r
2274 pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "w");
\r
2275 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "g", squareSize, "s");
\r
2276 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "g", squareSize, "o");
\r
2277 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "g", squareSize, "w");
\r
2280 } else { /* other size, no special bitmaps available. Use smaller symbols */
\r
2281 if((int)boardSize < 2) minorSize = sizeInfo[0].squareSize;
\r
2282 else minorSize = sizeInfo[(int)boardSize - 2].squareSize;
\r
2283 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "n", minorSize, "s");
\r
2284 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "n", minorSize, "o");
\r
2285 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "n", minorSize, "w");
\r
2286 pieceBitmap[0][WhiteCardinal] = DoLoadBitmap(hInst, "b", minorSize, "s");
\r
2287 pieceBitmap[1][WhiteCardinal] = DoLoadBitmap(hInst, "b", minorSize, "o");
\r
2288 pieceBitmap[2][WhiteCardinal] = DoLoadBitmap(hInst, "b", minorSize, "w");
\r
2289 pieceBitmap[0][WhiteDragon] = DoLoadBitmap(hInst, "r", minorSize, "s");
\r
2290 pieceBitmap[1][WhiteDragon] = DoLoadBitmap(hInst, "r", minorSize, "o");
\r
2291 pieceBitmap[2][WhiteDragon] = DoLoadBitmap(hInst, "r", minorSize, "w");
\r
2292 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "q", minorSize, "s");
\r
2293 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "q", minorSize, "o");
\r
2294 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "q", minorSize, "w");
\r
2298 if(gameInfo.variant == VariantShogi && squareSize == 58)
\r
2299 /* special Shogi support in this size */
\r
2300 { for (i=0; i<=2; i++) { /* replace all bitmaps */
\r
2301 for (piece = WhitePawn;
\r
2302 (int) piece < (int) BlackPawn;
\r
2303 piece = (ChessSquare) ((int) piece + 1)) {
\r
2304 if (pieceBitmap[i][piece] != NULL)
\r
2305 DeleteObject(pieceBitmap[i][piece]);
\r
2308 pieceBitmap[0][WhitePawn] = DoLoadBitmap(hInst, "sp", squareSize, "o");
\r
2309 pieceBitmap[0][WhiteKnight] = DoLoadBitmap(hInst, "sn", squareSize, "o");
\r
2310 pieceBitmap[0][WhiteBishop] = DoLoadBitmap(hInst, "sb", squareSize, "o");
\r
2311 pieceBitmap[0][WhiteRook] = DoLoadBitmap(hInst, "sr", squareSize, "o");
\r
2312 pieceBitmap[0][WhiteQueen] = DoLoadBitmap(hInst, "sl", squareSize, "o");
\r
2313 pieceBitmap[0][WhiteKing] = DoLoadBitmap(hInst, "sk", squareSize, "o");
\r
2314 pieceBitmap[0][WhiteFerz] = DoLoadBitmap(hInst, "sf", squareSize, "o");
\r
2315 pieceBitmap[0][WhiteWazir] = DoLoadBitmap(hInst, "sw", squareSize, "o");
\r
2316 pieceBitmap[0][WhiteCannon] = DoLoadBitmap(hInst, "su", squareSize, "o");
\r
2317 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "sh", squareSize, "o");
\r
2318 pieceBitmap[0][WhiteCardinal] = DoLoadBitmap(hInst, "sa", squareSize, "o");
\r
2319 pieceBitmap[0][WhiteDragon] = DoLoadBitmap(hInst, "sc", squareSize, "o");
\r
2320 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "sg", squareSize, "o");
\r
2321 pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "ss", squareSize, "o");
\r
2322 pieceBitmap[1][WhitePawn] = DoLoadBitmap(hInst, "sp", squareSize, "o");
\r
2323 pieceBitmap[1][WhiteKnight] = DoLoadBitmap(hInst, "sn", squareSize, "o");
\r
2324 pieceBitmap[1][WhiteBishop] = DoLoadBitmap(hInst, "sb", squareSize, "o");
\r
2325 pieceBitmap[1][WhiteRook] = DoLoadBitmap(hInst, "sr", squareSize, "o");
\r
2326 pieceBitmap[1][WhiteQueen] = DoLoadBitmap(hInst, "sl", squareSize, "o");
\r
2327 pieceBitmap[1][WhiteKing] = DoLoadBitmap(hInst, "sk", squareSize, "o");
\r
2328 pieceBitmap[1][WhiteFerz] = DoLoadBitmap(hInst, "sf", squareSize, "o");
\r
2329 pieceBitmap[1][WhiteWazir] = DoLoadBitmap(hInst, "sw", squareSize, "o");
\r
2330 pieceBitmap[1][WhiteCannon] = DoLoadBitmap(hInst, "su", squareSize, "o");
\r
2331 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "sh", squareSize, "o");
\r
2332 pieceBitmap[1][WhiteCardinal] = DoLoadBitmap(hInst, "sa", squareSize, "o");
\r
2333 pieceBitmap[1][WhiteDragon] = DoLoadBitmap(hInst, "sc", squareSize, "o");
\r
2334 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "sg", squareSize, "o");
\r
2335 pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "ss", squareSize, "o");
\r
2336 pieceBitmap[2][WhitePawn] = DoLoadBitmap(hInst, "sp", squareSize, "w");
\r
2337 pieceBitmap[2][WhiteKnight] = DoLoadBitmap(hInst, "sn", squareSize, "w");
\r
2338 pieceBitmap[2][WhiteBishop] = DoLoadBitmap(hInst, "sr", squareSize, "w");
\r
2339 pieceBitmap[2][WhiteRook] = DoLoadBitmap(hInst, "sr", squareSize, "w");
\r
2340 pieceBitmap[2][WhiteQueen] = DoLoadBitmap(hInst, "sl", squareSize, "w");
\r
2341 pieceBitmap[2][WhiteKing] = DoLoadBitmap(hInst, "sk", squareSize, "w");
\r
2342 pieceBitmap[2][WhiteFerz] = DoLoadBitmap(hInst, "sw", squareSize, "w");
\r
2343 pieceBitmap[2][WhiteWazir] = DoLoadBitmap(hInst, "sw", squareSize, "w");
\r
2344 pieceBitmap[2][WhiteCannon] = DoLoadBitmap(hInst, "sp", squareSize, "w");
\r
2345 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "sn", squareSize, "w");
\r
2346 pieceBitmap[2][WhiteCardinal] = DoLoadBitmap(hInst, "sr", squareSize, "w");
\r
2347 pieceBitmap[2][WhiteDragon] = DoLoadBitmap(hInst, "sr", squareSize, "w");
\r
2348 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "sl", squareSize, "w");
\r
2349 pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "sw", squareSize, "w");
\r
2355 PieceBitmap(ChessSquare p, int kind)
\r
2357 if ((int) p >= (int) BlackPawn)
\r
2358 p = (ChessSquare) ((int) p - (int) BlackPawn + (int) WhitePawn);
\r
2360 return pieceBitmap[kind][(int) p];
\r
2363 /***************************************************************/
\r
2365 #define MIN(a,b) (((a) < (b)) ? (a) : (b))
\r
2366 #define MAX(a,b) (((a) > (b)) ? (a) : (b))
\r
2368 #define MIN3(a,b,c) (((a) < (b) && (a) < (c)) ? (a) : (((b) < (a) && (b) < (c)) ? (b) : (c)))
\r
2369 #define MAX3(a,b,c) (((a) > (b) && (a) > (c)) ? (a) : (((b) > (a) && (b) > (c)) ? (b) : (c)))
\r
2373 SquareToPos(int row, int column, int * x, int * y)
\r
2376 *x = boardRect.left + lineGap + ((BOARD_WIDTH-1)-column) * (squareSize + lineGap);
\r
2377 *y = boardRect.top + lineGap + row * (squareSize + lineGap);
\r
2379 *x = boardRect.left + lineGap + column * (squareSize + lineGap);
\r
2380 *y = boardRect.top + lineGap + ((BOARD_HEIGHT-1)-row) * (squareSize + lineGap);
\r
2385 DrawCoordsOnDC(HDC hdc)
\r
2387 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
2388 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
2389 char str[2] = { NULLCHAR, NULLCHAR };
\r
2390 int oldMode, oldAlign, x, y, start, i;
\r
2394 if (!appData.showCoords)
\r
2397 start = flipView ? 1-(ONE!='1') : 23+(ONE!='1')-BOARD_HEIGHT;
\r
2399 oldBrush = SelectObject(hdc, GetStockObject(BLACK_BRUSH));
\r
2400 oldMode = SetBkMode(hdc, (appData.monoMode ? OPAQUE : TRANSPARENT));
\r
2401 oldAlign = GetTextAlign(hdc);
\r
2402 oldFont = SelectObject(hdc, font[boardSize][COORD_FONT]->hf);
\r
2404 y = boardRect.top + lineGap;
\r
2405 x = boardRect.left + lineGap + gameInfo.holdingsWidth*(squareSize + lineGap);
\r
2407 SetTextAlign(hdc, TA_LEFT|TA_TOP);
\r
2408 for (i = 0; i < BOARD_HEIGHT; i++) {
\r
2409 str[0] = files[start + i];
\r
2410 ExtTextOut(hdc, x + 2, y + 1, 0, NULL, str, 1, NULL);
\r
2411 y += squareSize + lineGap;
\r
2414 start = flipView ? 12-(BOARD_RGHT-BOARD_LEFT) : 12;
\r
2416 SetTextAlign(hdc, TA_RIGHT|TA_BOTTOM);
\r
2417 for (i = 0; i < BOARD_RGHT - BOARD_LEFT; i++) {
\r
2418 str[0] = ranks[start + i];
\r
2419 ExtTextOut(hdc, x + squareSize - 2, y - 1, 0, NULL, str, 1, NULL);
\r
2420 x += squareSize + lineGap;
\r
2423 SelectObject(hdc, oldBrush);
\r
2424 SetBkMode(hdc, oldMode);
\r
2425 SetTextAlign(hdc, oldAlign);
\r
2426 SelectObject(hdc, oldFont);
\r
2430 DrawGridOnDC(HDC hdc)
\r
2434 if (lineGap != 0) {
\r
2435 oldPen = SelectObject(hdc, gridPen);
\r
2436 PolyPolyline(hdc, gridEndpoints, gridVertexCounts, BOARD_WIDTH+BOARD_HEIGHT + 2);
\r
2437 SelectObject(hdc, oldPen);
\r
2441 #define HIGHLIGHT_PEN 0
\r
2442 #define PREMOVE_PEN 1
\r
2445 DrawHighlightOnDC(HDC hdc, BOOLEAN on, int x, int y, int pen)
\r
2448 HPEN oldPen, hPen;
\r
2449 if (lineGap == 0) return;
\r
2451 x1 = boardRect.left +
\r
2452 lineGap/2 + ((BOARD_WIDTH-1)-x) * (squareSize + lineGap);
\r
2453 y1 = boardRect.top +
\r
2454 lineGap/2 + y * (squareSize + lineGap);
\r
2456 x1 = boardRect.left +
\r
2457 lineGap/2 + x * (squareSize + lineGap);
\r
2458 y1 = boardRect.top +
\r
2459 lineGap/2 + ((BOARD_HEIGHT-1)-y) * (squareSize + lineGap);
\r
2461 hPen = pen ? premovePen : highlightPen;
\r
2462 oldPen = SelectObject(hdc, on ? hPen : gridPen);
\r
2463 MoveToEx(hdc, x1, y1, NULL);
\r
2464 LineTo(hdc, x1 + squareSize + lineGap, y1);
\r
2465 LineTo(hdc, x1 + squareSize + lineGap, y1 + squareSize + lineGap);
\r
2466 LineTo(hdc, x1, y1 + squareSize + lineGap);
\r
2467 LineTo(hdc, x1, y1);
\r
2468 SelectObject(hdc, oldPen);
\r
2472 DrawHighlightsOnDC(HDC hdc)
\r
2475 for (i=0; i<2; i++) {
\r
2476 if (highlightInfo.sq[i].x >= 0 && highlightInfo.sq[i].y >= 0)
\r
2477 DrawHighlightOnDC(hdc, TRUE,
\r
2478 highlightInfo.sq[i].x, highlightInfo.sq[i].y,
\r
2481 for (i=0; i<2; i++) {
\r
2482 if (premoveHighlightInfo.sq[i].x >= 0 &&
\r
2483 premoveHighlightInfo.sq[i].y >= 0) {
\r
2484 DrawHighlightOnDC(hdc, TRUE,
\r
2485 premoveHighlightInfo.sq[i].x,
\r
2486 premoveHighlightInfo.sq[i].y,
\r
2492 /* Note: sqcolor is used only in monoMode */
\r
2493 /* Note that this code is largely duplicated in woptions.c,
\r
2494 function DrawSampleSquare, so that needs to be updated too */
\r
2496 DrawPieceOnDC(HDC hdc, ChessSquare piece, int color, int sqcolor, int x, int y, HDC tmphdc)
\r
2498 HBITMAP oldBitmap;
\r
2502 if (appData.blindfold) return;
\r
2504 /* [AS] Use font-based pieces if needed */
\r
2505 if( fontBitmapSquareSize >= 0 && squareSize > 32 ) {
\r
2506 /* Create piece bitmaps, or do nothing if piece set is up to date */
\r
2507 CreatePiecesFromFont();
\r
2509 if( fontBitmapSquareSize == squareSize ) {
\r
2510 int index = TranslatePieceToFontPiece(piece);
\r
2512 SelectObject( tmphdc, hPieceMask[ index ] );
\r
2516 squareSize, squareSize,
\r
2521 SelectObject( tmphdc, hPieceFace[ index ] );
\r
2525 squareSize, squareSize,
\r
2534 if (appData.monoMode) {
\r
2535 SelectObject(tmphdc, PieceBitmap(piece,
\r
2536 color == sqcolor ? OUTLINE_PIECE : SOLID_PIECE));
\r
2537 BitBlt(hdc, x, y, squareSize, squareSize, tmphdc, 0, 0,
\r
2538 sqcolor ? SRCCOPY : NOTSRCCOPY);
\r
2540 tmpSize = squareSize;
\r
2542 ((piece >= (int)WhiteNightrider && piece <= WhiteGrasshopper) ||
\r
2543 (piece >= (int)BlackNightrider && piece <= BlackGrasshopper)) ) {
\r
2544 /* [HGM] no bitmap available for promoted pieces in Crazyhouse */
\r
2545 /* Bitmaps of smaller size are substituted, but we have to align them */
\r
2546 x += (squareSize - minorSize)>>1;
\r
2547 y += squareSize - minorSize - 2;
\r
2548 tmpSize = minorSize;
\r
2550 if (color || appData.allWhite ) {
\r
2551 oldBitmap = SelectObject(tmphdc, PieceBitmap(piece, WHITE_PIECE));
\r
2553 oldBrush = SelectObject(hdc, whitePieceBrush);
\r
2554 else oldBrush = SelectObject(hdc, blackPieceBrush);
\r
2555 if(appData.upsideDown && color==flipView)
\r
2556 StretchBlt(hdc, x+tmpSize, y+tmpSize, -tmpSize, -tmpSize, tmphdc, 0, 0, tmpSize, tmpSize, 0x00B8074A);
\r
2558 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, 0x00B8074A);
\r
2559 /* Use black for outline of white pieces */
\r
2560 SelectObject(tmphdc, PieceBitmap(piece, OUTLINE_PIECE));
\r
2561 if(appData.upsideDown && color==flipView)
\r
2562 StretchBlt(hdc, x+tmpSize, y+tmpSize, -tmpSize, -tmpSize, tmphdc, 0, 0, tmpSize, tmpSize, SRCAND);
\r
2564 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, SRCAND);
\r
2566 /* Use square color for details of black pieces */
\r
2567 oldBitmap = SelectObject(tmphdc, PieceBitmap(piece, SOLID_PIECE));
\r
2568 oldBrush = SelectObject(hdc, blackPieceBrush);
\r
2569 if(appData.upsideDown && !flipView)
\r
2570 StretchBlt(hdc, x+tmpSize, y+tmpSize, -tmpSize, -tmpSize, tmphdc, 0, 0, tmpSize, tmpSize, 0x00B8074A);
\r
2572 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, 0x00B8074A);
\r
2574 SelectObject(hdc, oldBrush);
\r
2575 SelectObject(tmphdc, oldBitmap);
\r
2579 /* [AS] Compute a drawing mode for a square, based on specified settings (see DrawTile) */
\r
2580 int GetBackTextureMode( int algo )
\r
2582 int result = BACK_TEXTURE_MODE_DISABLED;
\r
2586 case BACK_TEXTURE_MODE_PLAIN:
\r
2587 result = 1; /* Always use identity map */
\r
2589 case BACK_TEXTURE_MODE_FULL_RANDOM:
\r
2590 result = 1 + (myrandom() % 3); /* Pick a transformation at random */
\r
2598 [AS] Compute and save texture drawing info, otherwise we may not be able
\r
2599 to handle redraws cleanly (as random numbers would always be different).
\r
2601 VOID RebuildTextureSquareInfo()
\r
2611 ZeroMemory( &backTextureSquareInfo, sizeof(backTextureSquareInfo) );
\r
2613 if( liteBackTexture != NULL ) {
\r
2614 if( GetObject( liteBackTexture, sizeof(bi), &bi ) > 0 ) {
\r
2615 lite_w = bi.bmWidth;
\r
2616 lite_h = bi.bmHeight;
\r
2620 if( darkBackTexture != NULL ) {
\r
2621 if( GetObject( darkBackTexture, sizeof(bi), &bi ) > 0 ) {
\r
2622 dark_w = bi.bmWidth;
\r
2623 dark_h = bi.bmHeight;
\r
2627 for( row=0; row<BOARD_HEIGHT; row++ ) {
\r
2628 for( col=0; col<BOARD_WIDTH; col++ ) {
\r
2629 if( (col + row) & 1 ) {
\r
2631 if( lite_w >= squareSize && lite_h >= squareSize ) {
\r
2632 backTextureSquareInfo[row][col].x = col * (lite_w - squareSize) / (BOARD_WIDTH-1); /* [HGM] divide by size-1 in stead of size! */
\r
2633 backTextureSquareInfo[row][col].y = (BOARD_HEIGHT-1-row) * (lite_h - squareSize) / (BOARD_HEIGHT-1);
\r
2634 backTextureSquareInfo[row][col].mode = GetBackTextureMode(liteBackTextureMode);
\r
2639 if( dark_w >= squareSize && dark_h >= squareSize ) {
\r
2640 backTextureSquareInfo[row][col].x = col * (dark_w - squareSize) / (BOARD_WIDTH-1);
\r
2641 backTextureSquareInfo[row][col].y = (BOARD_HEIGHT-1-row) * (dark_h - squareSize) / (BOARD_HEIGHT-1);
\r
2642 backTextureSquareInfo[row][col].mode = GetBackTextureMode(darkBackTextureMode);
\r
2649 /* [AS] Arrow highlighting support */
\r
2651 static int A_WIDTH = 5; /* Width of arrow body */
\r
2653 #define A_HEIGHT_FACTOR 6 /* Length of arrow "point", relative to body width */
\r
2654 #define A_WIDTH_FACTOR 3 /* Width of arrow "point", relative to body width */
\r
2656 static double Sqr( double x )
\r
2661 static int Round( double x )
\r
2663 return (int) (x + 0.5);
\r
2666 /* Draw an arrow between two points using current settings */
\r
2667 VOID DrawArrowBetweenPoints( HDC hdc, int s_x, int s_y, int d_x, int d_y )
\r
2670 double dx, dy, j, k, x, y;
\r
2672 if( d_x == s_x ) {
\r
2673 int h = (d_y > s_y) ? +A_WIDTH*A_HEIGHT_FACTOR : -A_WIDTH*A_HEIGHT_FACTOR;
\r
2675 arrow[0].x = s_x + A_WIDTH;
\r
2678 arrow[1].x = s_x + A_WIDTH;
\r
2679 arrow[1].y = d_y - h;
\r
2681 arrow[2].x = s_x + A_WIDTH*A_WIDTH_FACTOR;
\r
2682 arrow[2].y = d_y - h;
\r
2687 arrow[4].x = s_x - A_WIDTH*A_WIDTH_FACTOR;
\r
2688 arrow[4].y = d_y - h;
\r
2690 arrow[5].x = s_x - A_WIDTH;
\r
2691 arrow[5].y = d_y - h;
\r
2693 arrow[6].x = s_x - A_WIDTH;
\r
2696 else if( d_y == s_y ) {
\r
2697 int w = (d_x > s_x) ? +A_WIDTH*A_HEIGHT_FACTOR : -A_WIDTH*A_HEIGHT_FACTOR;
\r
2700 arrow[0].y = s_y + A_WIDTH;
\r
2702 arrow[1].x = d_x - w;
\r
2703 arrow[1].y = s_y + A_WIDTH;
\r
2705 arrow[2].x = d_x - w;
\r
2706 arrow[2].y = s_y + A_WIDTH*A_WIDTH_FACTOR;
\r
2711 arrow[4].x = d_x - w;
\r
2712 arrow[4].y = s_y - A_WIDTH*A_WIDTH_FACTOR;
\r
2714 arrow[5].x = d_x - w;
\r
2715 arrow[5].y = s_y - A_WIDTH;
\r
2718 arrow[6].y = s_y - A_WIDTH;
\r
2721 /* [AS] Needed a lot of paper for this! :-) */
\r
2722 dy = (double) (d_y - s_y) / (double) (d_x - s_x);
\r
2723 dx = (double) (s_x - d_x) / (double) (s_y - d_y);
\r
2725 j = sqrt( Sqr(A_WIDTH) / (1.0 + Sqr(dx)) );
\r
2727 k = sqrt( Sqr(A_WIDTH*A_HEIGHT_FACTOR) / (1.0 + Sqr(dy)) );
\r
2732 arrow[0].x = Round(x - j);
\r
2733 arrow[0].y = Round(y + j*dx);
\r
2735 arrow[1].x = Round(x + j);
\r
2736 arrow[1].y = Round(y - j*dx);
\r
2739 x = (double) d_x - k;
\r
2740 y = (double) d_y - k*dy;
\r
2743 x = (double) d_x + k;
\r
2744 y = (double) d_y + k*dy;
\r
2747 arrow[2].x = Round(x + j);
\r
2748 arrow[2].y = Round(y - j*dx);
\r
2750 arrow[3].x = Round(x + j*A_WIDTH_FACTOR);
\r
2751 arrow[3].y = Round(y - j*A_WIDTH_FACTOR*dx);
\r
2756 arrow[5].x = Round(x - j*A_WIDTH_FACTOR);
\r
2757 arrow[5].y = Round(y + j*A_WIDTH_FACTOR*dx);
\r
2759 arrow[6].x = Round(x - j);
\r
2760 arrow[6].y = Round(y + j*dx);
\r
2763 Polygon( hdc, arrow, 7 );
\r
2766 /* [AS] Draw an arrow between two squares */
\r
2767 VOID DrawArrowBetweenSquares( HDC hdc, int s_col, int s_row, int d_col, int d_row )
\r
2769 int s_x, s_y, d_x, d_y;
\r
2776 if( s_col == d_col && s_row == d_row ) {
\r
2780 /* Get source and destination points */
\r
2781 SquareToPos( s_row, s_col, &s_x, &s_y);
\r
2782 SquareToPos( d_row, d_col, &d_x, &d_y);
\r
2785 d_y += squareSize / 4;
\r
2787 else if( d_y < s_y ) {
\r
2788 d_y += 3 * squareSize / 4;
\r
2791 d_y += squareSize / 2;
\r
2795 d_x += squareSize / 4;
\r
2797 else if( d_x < s_x ) {
\r
2798 d_x += 3 * squareSize / 4;
\r
2801 d_x += squareSize / 2;
\r
2804 s_x += squareSize / 2;
\r
2805 s_y += squareSize / 2;
\r
2807 /* Adjust width */
\r
2808 A_WIDTH = squareSize / 14;
\r
2811 stLB.lbStyle = BS_SOLID;
\r
2812 stLB.lbColor = appData.highlightArrowColor;
\r
2815 hpen = CreatePen( PS_SOLID, 2, RGB(0x00,0x00,0x00) );
\r
2816 holdpen = SelectObject( hdc, hpen );
\r
2817 hbrush = CreateBrushIndirect( &stLB );
\r
2818 holdbrush = SelectObject( hdc, hbrush );
\r
2820 DrawArrowBetweenPoints( hdc, s_x, s_y, d_x, d_y );
\r
2822 SelectObject( hdc, holdpen );
\r
2823 SelectObject( hdc, holdbrush );
\r
2824 DeleteObject( hpen );
\r
2825 DeleteObject( hbrush );
\r
2828 BOOL HasHighlightInfo()
\r
2830 BOOL result = FALSE;
\r
2832 if( highlightInfo.sq[0].x >= 0 && highlightInfo.sq[0].y >= 0 &&
\r
2833 highlightInfo.sq[1].x >= 0 && highlightInfo.sq[1].y >= 0 )
\r
2841 BOOL IsDrawArrowEnabled()
\r
2843 BOOL result = FALSE;
\r
2845 if( appData.highlightMoveWithArrow && squareSize >= 32 ) {
\r
2852 VOID DrawArrowHighlight( HDC hdc )
\r
2854 if( IsDrawArrowEnabled() && HasHighlightInfo() ) {
\r
2855 DrawArrowBetweenSquares( hdc,
\r
2856 highlightInfo.sq[0].x, highlightInfo.sq[0].y,
\r
2857 highlightInfo.sq[1].x, highlightInfo.sq[1].y );
\r
2861 HRGN GetArrowHighlightClipRegion( HDC hdc )
\r
2863 HRGN result = NULL;
\r
2865 if( HasHighlightInfo() ) {
\r
2866 int x1, y1, x2, y2;
\r
2867 int sx, sy, dx, dy;
\r
2869 SquareToPos(highlightInfo.sq[0].y, highlightInfo.sq[0].x, &x1, &y1 );
\r
2870 SquareToPos(highlightInfo.sq[1].y, highlightInfo.sq[1].x, &x2, &y2 );
\r
2872 sx = MIN( x1, x2 );
\r
2873 sy = MIN( y1, y2 );
\r
2874 dx = MAX( x1, x2 ) + squareSize;
\r
2875 dy = MAX( y1, y2 ) + squareSize;
\r
2877 result = CreateRectRgn( sx, sy, dx, dy );
\r
2884 Warning: this function modifies the behavior of several other functions.
\r
2886 Basically, Winboard is optimized to avoid drawing the whole board if not strictly
\r
2887 needed. Unfortunately, the decision whether or not to perform a full or partial
\r
2888 repaint is scattered all over the place, which is not good for features such as
\r
2889 "arrow highlighting" that require a full repaint of the board.
\r
2891 So, I've tried to patch the code where I thought it made sense (e.g. after or during
\r
2892 user interaction, when speed is not so important) but especially to avoid errors
\r
2893 in the displayed graphics.
\r
2895 In such patched places, I always try refer to this function so there is a single
\r
2896 place to maintain knowledge.
\r
2898 To restore the original behavior, just return FALSE unconditionally.
\r
2900 BOOL IsFullRepaintPreferrable()
\r
2902 BOOL result = FALSE;
\r
2904 if( (appData.highlightLastMove || appData.highlightDragging) && IsDrawArrowEnabled() ) {
\r
2905 /* Arrow may appear on the board */
\r
2913 This function is called by DrawPosition to know whether a full repaint must
\r
2916 Only DrawPosition may directly call this function, which makes use of
\r
2917 some state information. Other function should call DrawPosition specifying
\r
2918 the repaint flag, and can use IsFullRepaintPreferrable if needed.
\r
2920 BOOL DrawPositionNeedsFullRepaint()
\r
2922 BOOL result = FALSE;
\r
2925 Probably a slightly better policy would be to trigger a full repaint
\r
2926 when animInfo.piece changes state (i.e. empty -> non-empty and viceversa),
\r
2927 but animation is fast enough that it's difficult to notice.
\r
2929 if( animInfo.piece == EmptySquare ) {
\r
2930 if( (appData.highlightLastMove || appData.highlightDragging) && IsDrawArrowEnabled() /*&& HasHighlightInfo()*/ ) {
\r
2939 DrawBoardOnDC(HDC hdc, Board board, HDC tmphdc)
\r
2941 int row, column, x, y, square_color, piece_color;
\r
2942 ChessSquare piece;
\r
2944 HDC texture_hdc = NULL;
\r
2946 /* [AS] Initialize background textures if needed */
\r
2947 if( liteBackTexture != NULL || darkBackTexture != NULL ) {
\r
2948 static int backTextureBoardSize; /* [HGM] boardsize: also new texture if board format changed */
\r
2949 if( backTextureSquareSize != squareSize
\r
2950 || backTextureBoardSize != BOARD_WIDTH+BOARD_FILES*BOARD_HEIGHT) {
\r
2951 backTextureBoardSize = BOARD_WIDTH+BOARD_FILES*BOARD_HEIGHT;
\r
2952 backTextureSquareSize = squareSize;
\r
2953 RebuildTextureSquareInfo();
\r
2956 texture_hdc = CreateCompatibleDC( hdc );
\r
2959 for (row = 0; row < BOARD_HEIGHT; row++) {
\r
2960 for (column = 0; column < BOARD_WIDTH; column++) {
\r
2962 SquareToPos(row, column, &x, &y);
\r
2964 piece = board[row][column];
\r
2966 square_color = ((column + row) % 2) == 1;
\r
2967 if( gameInfo.variant == VariantXiangqi ) {
\r
2968 square_color = !InPalace(row, column);
\r
2969 if(BOARD_HEIGHT&1) { if(row==BOARD_HEIGHT/2) square_color ^= 1; }
\r
2970 else if(row < BOARD_HEIGHT/2) square_color ^= 1;
\r
2972 piece_color = (int) piece < (int) BlackPawn;
\r
2975 /* [HGM] holdings file: light square or black */
\r
2976 if(column == BOARD_LEFT-2) {
\r
2977 if( row > BOARD_HEIGHT - gameInfo.holdingsSize - 1 )
\r
2980 DisplayHoldingsCount(hdc, x, y, 0, 0); /* black out */
\r
2984 if(column == BOARD_RGHT + 1 ) {
\r
2985 if( row < gameInfo.holdingsSize )
\r
2988 DisplayHoldingsCount(hdc, x, y, 0, 0);
\r
2992 if(column == BOARD_LEFT-1 ) /* left align */
\r
2993 DisplayHoldingsCount(hdc, x, y, flipView, (int) board[row][column]);
\r
2994 else if( column == BOARD_RGHT) /* right align */
\r
2995 DisplayHoldingsCount(hdc, x, y, !flipView, (int) board[row][column]);
\r
2997 if (appData.monoMode) {
\r
2998 if (piece == EmptySquare) {
\r
2999 BitBlt(hdc, x, y, squareSize, squareSize, 0, 0, 0,
\r
3000 square_color ? WHITENESS : BLACKNESS);
\r
3002 DrawPieceOnDC(hdc, piece, piece_color, square_color, x, y, tmphdc);
\r
3005 else if( backTextureSquareInfo[row][column].mode > 0 ) {
\r
3006 /* [AS] Draw the square using a texture bitmap */
\r
3007 HBITMAP hbm = SelectObject( texture_hdc, square_color ? liteBackTexture : darkBackTexture );
\r
3008 int r = row, c = column; // [HGM] do not flip board in flipView
\r
3009 if(flipView) { r = BOARD_HEIGHT-1 - r; c = BOARD_WIDTH-1 - c; }
\r
3012 squareSize, squareSize,
\r
3015 backTextureSquareInfo[r][c].mode,
\r
3016 backTextureSquareInfo[r][c].x,
\r
3017 backTextureSquareInfo[r][c].y );
\r
3019 SelectObject( texture_hdc, hbm );
\r
3021 if (piece != EmptySquare) {
\r
3022 DrawPieceOnDC(hdc, piece, piece_color, -1, x, y, tmphdc);
\r
3026 HBRUSH brush = square_color ? lightSquareBrush : darkSquareBrush;
\r
3028 oldBrush = SelectObject(hdc, brush );
\r
3029 BitBlt(hdc, x, y, squareSize, squareSize, 0, 0, 0, PATCOPY);
\r
3030 SelectObject(hdc, oldBrush);
\r
3031 if (piece != EmptySquare)
\r
3032 DrawPieceOnDC(hdc, piece, piece_color, -1, x, y, tmphdc);
\r
3037 if( texture_hdc != NULL ) {
\r
3038 DeleteDC( texture_hdc );
\r
3042 int saveDiagFlag = 0; FILE *diagFile; // [HGM] diag
\r
3043 void fputDW(FILE *f, int x)
\r
3045 fputc(x & 255, f);
\r
3046 fputc(x>>8 & 255, f);
\r
3047 fputc(x>>16 & 255, f);
\r
3048 fputc(x>>24 & 255, f);
\r
3051 #define MAX_CLIPS 200 /* more than enough */
\r
3054 DrawLogoOnDC(HDC hdc, RECT logoRect, HBITMAP logo)
\r
3056 // HBITMAP bufferBitmap;
\r
3061 int w = 100, h = 50;
\r
3063 if(logo == NULL) return;
\r
3064 // GetClientRect(hwndMain, &Rect);
\r
3065 // bufferBitmap = CreateCompatibleBitmap(hdc, Rect.right-Rect.left+1,
\r
3066 // Rect.bottom-Rect.top+1);
\r
3067 tmphdc = CreateCompatibleDC(hdc);
\r
3068 hbm = SelectObject(tmphdc, logo);
\r
3069 if( GetObject( logo, sizeof(bi), &bi ) > 0 ) {
\r
3073 StretchBlt(hdc, logoRect.left, logoRect.top, logoRect.right - logoRect.left,
\r
3074 logoRect.bottom - logoRect.top, tmphdc, 0, 0, w, h, SRCCOPY);
\r
3075 SelectObject(tmphdc, hbm);
\r
3080 HDCDrawPosition(HDC hdc, BOOLEAN repaint, Board board)
\r
3082 static Board lastReq, lastDrawn;
\r
3083 static HighlightInfo lastDrawnHighlight, lastDrawnPremove;
\r
3084 static int lastDrawnFlipView = 0;
\r
3085 static int lastReqValid = 0, lastDrawnValid = 0;
\r
3086 int releaseDC, x, y, x2, y2, row, column, num_clips = 0, i;
\r
3089 HBITMAP bufferBitmap;
\r
3090 HBITMAP oldBitmap;
\r
3092 HRGN clips[MAX_CLIPS];
\r
3093 ChessSquare dragged_piece = EmptySquare;
\r
3095 /* I'm undecided on this - this function figures out whether a full
\r
3096 * repaint is necessary on its own, so there's no real reason to have the
\r
3097 * caller tell it that. I think this can safely be set to FALSE - but
\r
3098 * if we trust the callers not to request full repaints unnessesarily, then
\r
3099 * we could skip some clipping work. In other words, only request a full
\r
3100 * redraw when the majority of pieces have changed positions (ie. flip,
\r
3101 * gamestart and similar) --Hawk
\r
3103 Boolean fullrepaint = repaint;
\r
3105 if( DrawPositionNeedsFullRepaint() ) {
\r
3106 fullrepaint = TRUE;
\r
3109 if (board == NULL) {
\r
3110 if (!lastReqValid) {
\r
3115 CopyBoard(lastReq, board);
\r
3119 if (doingSizing) {
\r
3123 if (IsIconic(hwndMain)) {
\r
3127 if (hdc == NULL) {
\r
3128 hdc = GetDC(hwndMain);
\r
3129 if (!appData.monoMode) {
\r
3130 SelectPalette(hdc, hPal, FALSE);
\r
3131 RealizePalette(hdc);
\r
3135 releaseDC = FALSE;
\r
3138 /* Create some work-DCs */
\r
3139 hdcmem = CreateCompatibleDC(hdc);
\r
3140 tmphdc = CreateCompatibleDC(hdc);
\r
3142 /* If dragging is in progress, we temporarely remove the piece */
\r
3143 /* [HGM] or temporarily decrease count if stacked */
\r
3144 /* !! Moved to before board compare !! */
\r
3145 if (dragInfo.from.x >= 0 && dragInfo.pos.x >= 0) {
\r
3146 dragged_piece = board[dragInfo.from.y][dragInfo.from.x];
\r
3147 if(dragInfo.from.x == BOARD_LEFT-2 ) {
\r
3148 if(--board[dragInfo.from.y][dragInfo.from.x+1] == 0 )
\r
3149 board[dragInfo.from.y][dragInfo.from.x] = EmptySquare;
\r
3151 if(dragInfo.from.x == BOARD_RGHT+1) {
\r
3152 if(--board[dragInfo.from.y][dragInfo.from.x-1] == 0 )
\r
3153 board[dragInfo.from.y][dragInfo.from.x] = EmptySquare;
\r
3155 board[dragInfo.from.y][dragInfo.from.x] = EmptySquare;
\r
3158 /* Figure out which squares need updating by comparing the
\r
3159 * newest board with the last drawn board and checking if
\r
3160 * flipping has changed.
\r
3162 if (!fullrepaint && lastDrawnValid && lastDrawnFlipView == flipView) {
\r
3163 for (row = 0; row < BOARD_HEIGHT; row++) { /* [HGM] true size, not 8 */
\r
3164 for (column = 0; column < BOARD_WIDTH; column++) {
\r
3165 if (lastDrawn[row][column] != board[row][column]) {
\r
3166 SquareToPos(row, column, &x, &y);
\r
3167 clips[num_clips++] =
\r
3168 CreateRectRgn(x, y, x + squareSize, y + squareSize);
\r
3172 for (i=0; i<2; i++) {
\r
3173 if (lastDrawnHighlight.sq[i].x != highlightInfo.sq[i].x ||
\r
3174 lastDrawnHighlight.sq[i].y != highlightInfo.sq[i].y) {
\r
3175 if (lastDrawnHighlight.sq[i].x >= 0 &&
\r
3176 lastDrawnHighlight.sq[i].y >= 0) {
\r
3177 SquareToPos(lastDrawnHighlight.sq[i].y,
\r
3178 lastDrawnHighlight.sq[i].x, &x, &y);
\r
3179 clips[num_clips++] =
\r
3180 CreateRectRgn(x - lineGap, y - lineGap,
\r
3181 x + squareSize + lineGap, y + squareSize + lineGap);
\r
3183 if (highlightInfo.sq[i].x >= 0 && highlightInfo.sq[i].y >= 0) {
\r
3184 SquareToPos(highlightInfo.sq[i].y, highlightInfo.sq[i].x, &x, &y);
\r
3185 clips[num_clips++] =
\r
3186 CreateRectRgn(x - lineGap, y - lineGap,
\r
3187 x + squareSize + lineGap, y + squareSize + lineGap);
\r
3191 for (i=0; i<2; i++) {
\r
3192 if (lastDrawnPremove.sq[i].x != premoveHighlightInfo.sq[i].x ||
\r
3193 lastDrawnPremove.sq[i].y != premoveHighlightInfo.sq[i].y) {
\r
3194 if (lastDrawnPremove.sq[i].x >= 0 &&
\r
3195 lastDrawnPremove.sq[i].y >= 0) {
\r
3196 SquareToPos(lastDrawnPremove.sq[i].y,
\r
3197 lastDrawnPremove.sq[i].x, &x, &y);
\r
3198 clips[num_clips++] =
\r
3199 CreateRectRgn(x - lineGap, y - lineGap,
\r
3200 x + squareSize + lineGap, y + squareSize + lineGap);
\r
3202 if (premoveHighlightInfo.sq[i].x >= 0 &&
\r
3203 premoveHighlightInfo.sq[i].y >= 0) {
\r
3204 SquareToPos(premoveHighlightInfo.sq[i].y,
\r
3205 premoveHighlightInfo.sq[i].x, &x, &y);
\r
3206 clips[num_clips++] =
\r
3207 CreateRectRgn(x - lineGap, y - lineGap,
\r
3208 x + squareSize + lineGap, y + squareSize + lineGap);
\r
3213 fullrepaint = TRUE;
\r
3216 /* Create a buffer bitmap - this is the actual bitmap
\r
3217 * being written to. When all the work is done, we can
\r
3218 * copy it to the real DC (the screen). This avoids
\r
3219 * the problems with flickering.
\r
3221 GetClientRect(hwndMain, &Rect);
\r
3222 bufferBitmap = CreateCompatibleBitmap(hdc, Rect.right-Rect.left+1,
\r
3223 Rect.bottom-Rect.top+1);
\r
3224 oldBitmap = SelectObject(hdcmem, bufferBitmap);
\r
3225 if (!appData.monoMode) {
\r
3226 SelectPalette(hdcmem, hPal, FALSE);
\r
3229 /* Create clips for dragging */
\r
3230 if (!fullrepaint) {
\r
3231 if (dragInfo.from.x >= 0) {
\r
3232 SquareToPos(dragInfo.from.y, dragInfo.from.x, &x, &y);
\r
3233 clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);
\r
3235 if (dragInfo.start.x >= 0) {
\r
3236 SquareToPos(dragInfo.start.y, dragInfo.start.x, &x, &y);
\r
3237 clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);
\r
3239 if (dragInfo.pos.x >= 0) {
\r
3240 x = dragInfo.pos.x - squareSize / 2;
\r
3241 y = dragInfo.pos.y - squareSize / 2;
\r
3242 clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);
\r
3244 if (dragInfo.lastpos.x >= 0) {
\r
3245 x = dragInfo.lastpos.x - squareSize / 2;
\r
3246 y = dragInfo.lastpos.y - squareSize / 2;
\r
3247 clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);
\r
3251 /* Are we animating a move?
\r
3253 * - remove the piece from the board (temporarely)
\r
3254 * - calculate the clipping region
\r
3256 if (!fullrepaint) {
\r
3257 if (animInfo.piece != EmptySquare) {
\r
3258 board[animInfo.from.y][animInfo.from.x] = EmptySquare;
\r
3259 x = boardRect.left + animInfo.lastpos.x;
\r
3260 y = boardRect.top + animInfo.lastpos.y;
\r
3261 x2 = boardRect.left + animInfo.pos.x;
\r
3262 y2 = boardRect.top + animInfo.pos.y;
\r
3263 clips[num_clips++] = CreateRectRgn(MIN(x,x2), MIN(y,y2), MAX(x,x2)+squareSize, MAX(y,y2)+squareSize);
\r
3264 /* Slight kludge. The real problem is that after AnimateMove is
\r
3265 done, the position on the screen does not match lastDrawn.
\r
3266 This currently causes trouble only on e.p. captures in
\r
3267 atomic, where the piece moves to an empty square and then
\r
3268 explodes. The old and new positions both had an empty square
\r
3269 at the destination, but animation has drawn a piece there and
\r
3270 we have to remember to erase it. [HGM] moved until after setting lastDrawn */
\r
3271 lastDrawn[animInfo.to.y][animInfo.to.x] = animInfo.piece;
\r
3275 /* No clips? Make sure we have fullrepaint set to TRUE */
\r
3276 if (num_clips == 0)
\r
3277 fullrepaint = TRUE;
\r
3279 /* Set clipping on the memory DC */
\r
3280 if (!fullrepaint) {
\r
3281 SelectClipRgn(hdcmem, clips[0]);
\r
3282 for (x = 1; x < num_clips; x++) {
\r
3283 if (ExtSelectClipRgn(hdcmem, clips[x], RGN_OR) == ERROR)
\r
3284 abort(); // this should never ever happen!
\r
3288 /* Do all the drawing to the memory DC */
\r
3289 if(explodeInfo.radius) { // [HGM] atomic
\r
3291 int x, y, r=(explodeInfo.radius * squareSize)/100;
\r
3292 board[explodeInfo.fromY][explodeInfo.fromX] = EmptySquare; // suppress display of capturer
\r
3293 SquareToPos(explodeInfo.toY, explodeInfo.toX, &x, &y);
\r
3294 x += squareSize/2;
\r
3295 y += squareSize/2;
\r
3296 if(!fullrepaint) {
\r
3297 clips[num_clips] = CreateRectRgn(x-r, y-r, x+r, y+r);
\r
3298 ExtSelectClipRgn(hdcmem, clips[num_clips++], RGN_OR);
\r
3300 DrawGridOnDC(hdcmem);
\r
3301 DrawHighlightsOnDC(hdcmem);
\r
3302 DrawBoardOnDC(hdcmem, board, tmphdc);
\r
3303 oldBrush = SelectObject(hdcmem, explodeBrush);
\r
3304 Ellipse(hdcmem, x-r, y-r, x+r, y+r);
\r
3305 SelectObject(hdcmem, oldBrush);
\r
3307 DrawGridOnDC(hdcmem);
\r
3308 DrawHighlightsOnDC(hdcmem);
\r
3309 DrawBoardOnDC(hdcmem, board, tmphdc);
\r
3312 HBITMAP whiteLogo = (HBITMAP) first.programLogo, blackLogo = (HBITMAP) second.programLogo;
\r
3313 if(appData.autoLogo) {
\r
3315 switch(gameMode) { // pick logos based on game mode
\r
3316 case IcsObserving:
\r
3317 whiteLogo = second.programLogo; // ICS logo
\r
3318 blackLogo = second.programLogo;
\r
3321 case IcsPlayingWhite:
\r
3322 if(!appData.zippyPlay) whiteLogo = userLogo;
\r
3323 blackLogo = second.programLogo; // ICS logo
\r
3325 case IcsPlayingBlack:
\r
3326 whiteLogo = second.programLogo; // ICS logo
\r
3327 blackLogo = appData.zippyPlay ? first.programLogo : userLogo;
\r
3329 case TwoMachinesPlay:
\r
3330 if(first.twoMachinesColor[0] == 'b') {
\r
3331 whiteLogo = second.programLogo;
\r
3332 blackLogo = first.programLogo;
\r
3335 case MachinePlaysWhite:
\r
3336 blackLogo = userLogo;
\r
3338 case MachinePlaysBlack:
\r
3339 whiteLogo = userLogo;
\r
3340 blackLogo = first.programLogo;
\r
3343 DrawLogoOnDC(hdc, leftLogoRect, flipClock ? blackLogo : whiteLogo);
\r
3344 DrawLogoOnDC(hdc, rightLogoRect, flipClock ? whiteLogo : blackLogo);
\r
3347 if( appData.highlightMoveWithArrow ) {
\r
3348 DrawArrowHighlight(hdcmem);
\r
3351 DrawCoordsOnDC(hdcmem);
\r
3353 CopyBoard(lastDrawn, board); /* [HGM] Moved to here from end of routine, */
\r
3354 /* to make sure lastDrawn contains what is actually drawn */
\r
3356 /* Put the dragged piece back into place and draw it (out of place!) */
\r
3357 if (dragged_piece != EmptySquare) {
\r
3358 /* [HGM] or restack */
\r
3359 if(dragInfo.from.x == BOARD_LEFT-2 )
\r
3360 board[dragInfo.from.y][dragInfo.from.x+1]++;
\r
3362 if(dragInfo.from.x == BOARD_RGHT+1 )
\r
3363 board[dragInfo.from.y][dragInfo.from.x-1]++;
\r
3364 board[dragInfo.from.y][dragInfo.from.x] = dragged_piece;
\r
3365 x = dragInfo.pos.x - squareSize / 2;
\r
3366 y = dragInfo.pos.y - squareSize / 2;
\r
3367 DrawPieceOnDC(hdcmem, dragged_piece,
\r
3368 ((int) dragged_piece < (int) BlackPawn),
\r
3369 (dragInfo.from.y + dragInfo.from.x) % 2, x, y, tmphdc);
\r
3372 /* Put the animated piece back into place and draw it */
\r
3373 if (animInfo.piece != EmptySquare) {
\r
3374 board[animInfo.from.y][animInfo.from.x] = animInfo.piece;
\r
3375 x = boardRect.left + animInfo.pos.x;
\r
3376 y = boardRect.top + animInfo.pos.y;
\r
3377 DrawPieceOnDC(hdcmem, animInfo.piece,
\r
3378 ((int) animInfo.piece < (int) BlackPawn),
\r
3379 (animInfo.from.y + animInfo.from.x) % 2, x, y, tmphdc);
\r
3382 /* Release the bufferBitmap by selecting in the old bitmap
\r
3383 * and delete the memory DC
\r
3385 SelectObject(hdcmem, oldBitmap);
\r
3388 /* Set clipping on the target DC */
\r
3389 if (!fullrepaint) {
\r
3390 SelectClipRgn(hdc, clips[0]);
\r
3391 for (x = 1; x < num_clips; x++) {
\r
3392 if (ExtSelectClipRgn(hdc, clips[x], RGN_OR) == ERROR)
\r
3393 abort(); // this should never ever happen!
\r
3397 /* Copy the new bitmap onto the screen in one go.
\r
3398 * This way we avoid any flickering
\r
3400 oldBitmap = SelectObject(tmphdc, bufferBitmap);
\r
3401 BitBlt(hdc, boardRect.left, boardRect.top,
\r
3402 boardRect.right - boardRect.left,
\r
3403 boardRect.bottom - boardRect.top,
\r
3404 tmphdc, boardRect.left, boardRect.top, SRCCOPY);
\r
3405 if(saveDiagFlag) {
\r
3406 BITMAP b; int i, j=0, m, w, wb, fac=0; char pData[1000000];
\r
3407 BITMAPINFOHEADER bih; int color[16], nrColors=0;
\r
3409 GetObject(bufferBitmap, sizeof(b), &b);
\r
3410 if(b.bmWidthBytes*b.bmHeight <= 990000) {
\r
3411 bih.biSize = sizeof(BITMAPINFOHEADER);
\r
3412 bih.biWidth = b.bmWidth;
\r
3413 bih.biHeight = b.bmHeight;
\r
3415 bih.biBitCount = b.bmBitsPixel;
\r
3416 bih.biCompression = 0;
\r
3417 bih.biSizeImage = b.bmWidthBytes*b.bmHeight;
\r
3418 bih.biXPelsPerMeter = 0;
\r
3419 bih.biYPelsPerMeter = 0;
\r
3420 bih.biClrUsed = 0;
\r
3421 bih.biClrImportant = 0;
\r
3422 // fprintf(diagFile, "t=%d\nw=%d\nh=%d\nB=%d\nP=%d\nX=%d\n",
\r
3423 // b.bmType, b.bmWidth, b.bmHeight, b.bmWidthBytes, b.bmPlanes, b.bmBitsPixel);
\r
3424 GetDIBits(tmphdc,bufferBitmap,0,b.bmHeight,pData,(BITMAPINFO*)&bih,DIB_RGB_COLORS);
\r
3425 // fprintf(diagFile, "%8x\n", (int) pData);
\r
3427 wb = b.bmWidthBytes;
\r
3429 for(i=0; i<wb*(b.bmHeight - boardRect.top + OUTER_MARGIN)>>2; i++) {
\r
3430 int k = ((int*) pData)[i];
\r
3431 for(j=0; j<nrColors; j++) if(color[j] == k) break;
\r
3432 if(j >= 16) break;
\r
3434 if(j >= nrColors) nrColors = j+1;
\r
3436 if(j<16) { // 16 colors is enough. Compress to 4 bits per pixel
\r
3438 for(i=0; i<b.bmHeight - boardRect.top + OUTER_MARGIN; i++) {
\r
3439 for(w=0; w<(wb>>2); w+=2) {
\r
3440 int k = ((int*) pData)[(wb*i>>2) + w];
\r
3441 for(j=0; j<nrColors; j++) if(color[j] == k) break;
\r
3442 k = ((int*) pData)[(wb*i>>2) + w + 1];
\r
3443 for(m=0; m<nrColors; m++) if(color[m] == k) break;
\r
3444 pData[p++] = m | j<<4;
\r
3446 while(p&3) pData[p++] = 0;
\r
3449 wb = ((wb+31)>>5)<<2;
\r
3451 // write BITMAPFILEHEADER
\r
3452 fprintf(diagFile, "BM");
\r
3453 fputDW(diagFile, wb*(b.bmHeight - boardRect.top + OUTER_MARGIN)+0x36 + (fac?64:0));
\r
3454 fputDW(diagFile, 0);
\r
3455 fputDW(diagFile, 0x36 + (fac?64:0));
\r
3456 // write BITMAPINFOHEADER
\r
3457 fputDW(diagFile, 40);
\r
3458 fputDW(diagFile, b.bmWidth);
\r
3459 fputDW(diagFile, b.bmHeight - boardRect.top + OUTER_MARGIN);
\r
3460 if(fac) fputDW(diagFile, 0x040001); // planes and bits/pixel
\r
3461 else fputDW(diagFile, 0x200001); // planes and bits/pixel
\r
3462 fputDW(diagFile, 0);
\r
3463 fputDW(diagFile, 0);
\r
3464 fputDW(diagFile, 0);
\r
3465 fputDW(diagFile, 0);
\r
3466 fputDW(diagFile, 0);
\r
3467 fputDW(diagFile, 0);
\r
3468 // write color table
\r
3470 for(i=0; i<16; i++) fputDW(diagFile, color[i]);
\r
3471 // write bitmap data
\r
3472 for(i=0; i<wb*(b.bmHeight - boardRect.top + OUTER_MARGIN); i++)
\r
3473 fputc(pData[i], diagFile);
\r
3477 SelectObject(tmphdc, oldBitmap);
\r
3479 /* Massive cleanup */
\r
3480 for (x = 0; x < num_clips; x++)
\r
3481 DeleteObject(clips[x]);
\r
3484 DeleteObject(bufferBitmap);
\r
3487 ReleaseDC(hwndMain, hdc);
\r
3489 if (lastDrawnFlipView != flipView) {
\r
3491 CheckMenuItem(GetMenu(hwndMain),IDM_FlipView, MF_BYCOMMAND|MF_CHECKED);
\r
3493 CheckMenuItem(GetMenu(hwndMain),IDM_FlipView, MF_BYCOMMAND|MF_UNCHECKED);
\r
3496 /* CopyBoard(lastDrawn, board);*/
\r
3497 lastDrawnHighlight = highlightInfo;
\r
3498 lastDrawnPremove = premoveHighlightInfo;
\r
3499 lastDrawnFlipView = flipView;
\r
3500 lastDrawnValid = 1;
\r
3503 /* [HGM] diag: Save the current board display to the given open file and close the file */
\r
3508 saveDiagFlag = 1; diagFile = f;
\r
3509 HDCDrawPosition(NULL, TRUE, NULL);
\r
3513 // if(f != NULL) fprintf(f, "Sorry, but this feature is still in preparation\n");
\r
3520 /*---------------------------------------------------------------------------*\
\r
3521 | CLIENT PAINT PROCEDURE
\r
3522 | This is the main event-handler for the WM_PAINT message.
\r
3524 \*---------------------------------------------------------------------------*/
\r
3526 PaintProc(HWND hwnd)
\r
3532 if((hdc = BeginPaint(hwnd, &ps))) {
\r
3533 if (IsIconic(hwnd)) {
\r
3534 DrawIcon(hdc, 2, 2, iconCurrent);
\r
3536 if (!appData.monoMode) {
\r
3537 SelectPalette(hdc, hPal, FALSE);
\r
3538 RealizePalette(hdc);
\r
3540 HDCDrawPosition(hdc, 1, NULL);
\r
3542 SelectObject(hdc, font[boardSize][MESSAGE_FONT]->hf);
\r
3543 ExtTextOut(hdc, messageRect.left, messageRect.top,
\r
3544 ETO_CLIPPED|ETO_OPAQUE,
\r
3545 &messageRect, messageText, strlen(messageText), NULL);
\r
3546 SelectObject(hdc, oldFont);
\r
3547 DisplayBothClocks();
\r
3549 EndPaint(hwnd,&ps);
\r
3557 * If the user selects on a border boundary, return -1; if off the board,
\r
3558 * return -2. Otherwise map the event coordinate to the square.
\r
3559 * The offset boardRect.left or boardRect.top must already have been
\r
3560 * subtracted from x.
\r
3562 int EventToSquare(x, limit)
\r
3570 if ((x % (squareSize + lineGap)) >= squareSize)
\r
3572 x /= (squareSize + lineGap);
\r
3584 DropEnable dropEnables[] = {
\r
3585 { 'P', DP_Pawn, "Pawn" },
\r
3586 { 'N', DP_Knight, "Knight" },
\r
3587 { 'B', DP_Bishop, "Bishop" },
\r
3588 { 'R', DP_Rook, "Rook" },
\r
3589 { 'Q', DP_Queen, "Queen" },
\r
3593 SetupDropMenu(HMENU hmenu)
\r
3595 int i, count, enable;
\r
3597 extern char white_holding[], black_holding[];
\r
3598 char item[MSG_SIZ];
\r
3600 for (i=0; i<sizeof(dropEnables)/sizeof(DropEnable); i++) {
\r
3601 p = strchr(gameMode == IcsPlayingWhite ? white_holding : black_holding,
\r
3602 dropEnables[i].piece);
\r
3604 while (p && *p++ == dropEnables[i].piece) count++;
\r
3605 sprintf(item, "%s %d", dropEnables[i].name, count);
\r
3606 enable = count > 0 || !appData.testLegality
\r
3607 /*!!temp:*/ || (gameInfo.variant == VariantCrazyhouse
\r
3608 && !appData.icsActive);
\r
3609 ModifyMenu(hmenu, dropEnables[i].command,
\r
3610 MF_BYCOMMAND | (enable ? MF_ENABLED : MF_GRAYED) | MF_STRING,
\r
3611 dropEnables[i].command, item);
\r
3615 void DragPieceBegin(int x, int y)
\r
3617 dragInfo.lastpos.x = boardRect.left + x;
\r
3618 dragInfo.lastpos.y = boardRect.top + y;
\r
3619 dragInfo.from.x = fromX;
\r
3620 dragInfo.from.y = fromY;
\r
3621 dragInfo.start = dragInfo.from;
\r
3622 SetCapture(hwndMain);
\r
3625 void DragPieceEnd(int x, int y)
\r
3628 dragInfo.start.x = dragInfo.start.y = -1;
\r
3629 dragInfo.from = dragInfo.start;
\r
3630 dragInfo.pos = dragInfo.lastpos = dragInfo.start;
\r
3633 /* Event handler for mouse messages */
\r
3635 MouseEvent(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
3639 static int recursive = 0;
\r
3641 BOOLEAN forceFullRepaint = IsFullRepaintPreferrable(); /* [AS] */
\r
3644 if (message == WM_MBUTTONUP) {
\r
3645 /* Hideous kludge to fool TrackPopupMenu into paying attention
\r
3646 to the middle button: we simulate pressing the left button too!
\r
3648 PostMessage(hwnd, WM_LBUTTONDOWN, wParam, lParam);
\r
3649 PostMessage(hwnd, WM_LBUTTONUP, wParam, lParam);
\r
3655 pt.x = LOWORD(lParam);
\r
3656 pt.y = HIWORD(lParam);
\r
3657 x = EventToSquare(pt.x - boardRect.left, BOARD_WIDTH);
\r
3658 y = EventToSquare(pt.y - boardRect.top, BOARD_HEIGHT);
\r
3659 if (!flipView && y >= 0) {
\r
3660 y = BOARD_HEIGHT - 1 - y;
\r
3662 if (flipView && x >= 0) {
\r
3663 x = BOARD_WIDTH - 1 - x;
\r
3666 switch (message) {
\r
3667 case WM_LBUTTONDOWN:
\r
3668 if (PtInRect((LPRECT) &whiteRect, pt)) {
\r
3669 if (gameMode == EditPosition) {
\r
3670 SetWhiteToPlayEvent();
\r
3671 } else if (gameMode == IcsPlayingBlack ||
\r
3672 gameMode == MachinePlaysWhite) {
\r
3674 } else if (gameMode == EditGame) {
\r
3675 AdjustClock(flipClock, -1);
\r
3677 } else if (PtInRect((LPRECT) &blackRect, pt)) {
\r
3678 if (gameMode == EditPosition) {
\r
3679 SetBlackToPlayEvent();
\r
3680 } else if (gameMode == IcsPlayingWhite ||
\r
3681 gameMode == MachinePlaysBlack) {
\r
3683 } else if (gameMode == EditGame) {
\r
3684 AdjustClock(!flipClock, -1);
\r
3687 dragInfo.start.x = dragInfo.start.y = -1;
\r
3688 dragInfo.from = dragInfo.start;
\r
3689 if(fromX == -1 && frozen) { // not sure where this is for
\r
3690 fromX = fromY = -1;
\r
3691 DrawPosition(forceFullRepaint || FALSE, NULL); /* [AS] */
\r
3694 LeftClick(Press, pt.x - boardRect.left, pt.y - boardRect.top);
\r
3695 DrawPosition(TRUE, NULL);
\r
3698 case WM_LBUTTONUP:
\r
3699 LeftClick(Release, pt.x - boardRect.left, pt.y - boardRect.top);
\r
3700 DrawPosition(TRUE, NULL);
\r
3703 case WM_MOUSEMOVE:
\r
3704 if ((appData.animateDragging || appData.highlightDragging)
\r
3705 && (wParam & MK_LBUTTON)
\r
3706 && dragInfo.from.x >= 0)
\r
3708 BOOL full_repaint = FALSE;
\r
3710 if (appData.animateDragging) {
\r
3711 dragInfo.pos = pt;
\r
3713 if (appData.highlightDragging) {
\r
3714 SetHighlights(fromX, fromY, x, y);
\r
3715 if( IsDrawArrowEnabled() && (x < 0 || x >= BOARD_WIDTH || y < 0 || y >= BOARD_HEIGHT) ) {
\r
3716 full_repaint = TRUE;
\r
3720 DrawPosition( full_repaint, NULL);
\r
3722 dragInfo.lastpos = dragInfo.pos;
\r
3726 case WM_MOUSEWHEEL: // [DM]
\r
3727 { static int lastDir = 0; // [HGM] build in some hysteresis to avoid spurious events
\r
3728 /* Mouse Wheel is being rolled forward
\r
3729 * Play moves forward
\r
3731 if((short)HIWORD(wParam) > 0 && currentMove < forwardMostMove)
\r
3732 { if(lastDir == 1) ForwardEvent(); else lastDir = 1; } // [HGM] suppress first event in direction
\r
3733 /* Mouse Wheel is being rolled backward
\r
3734 * Play moves backward
\r
3736 if((short)HIWORD(wParam) < 0 && currentMove > backwardMostMove)
\r
3737 { if(lastDir == -1) BackwardEvent(); else lastDir = -1; }
\r
3741 case WM_MBUTTONDOWN:
\r
3742 case WM_RBUTTONDOWN:
\r
3745 fromX = fromY = -1;
\r
3746 dragInfo.pos.x = dragInfo.pos.y = -1;
\r
3747 dragInfo.start.x = dragInfo.start.y = -1;
\r
3748 dragInfo.from = dragInfo.start;
\r
3749 dragInfo.lastpos = dragInfo.pos;
\r
3750 if (appData.highlightDragging) {
\r
3751 ClearHighlights();
\r
3754 /* [HGM] right mouse button in clock area edit-game mode ups clock */
\r
3755 if (PtInRect((LPRECT) &whiteRect, pt)) {
\r
3756 if (gameMode == EditGame) AdjustClock(flipClock, 1);
\r
3757 } else if (PtInRect((LPRECT) &blackRect, pt)) {
\r
3758 if (gameMode == EditGame) AdjustClock(!flipClock, 1);
\r
3761 DrawPosition(TRUE, NULL);
\r
3763 switch (gameMode) {
\r
3764 case EditPosition:
\r
3765 case IcsExamining:
\r
3766 if (x < 0 || y < 0) break;
\r
3769 if (message == WM_MBUTTONDOWN) {
\r
3770 buttonCount = 3; /* even if system didn't think so */
\r
3771 if (wParam & MK_SHIFT)
\r
3772 MenuPopup(hwnd, pt, LoadMenu(hInst, "BlackPieceMenu"), -1);
\r
3774 MenuPopup(hwnd, pt, LoadMenu(hInst, "WhitePieceMenu"), -1);
\r
3775 } else { /* message == WM_RBUTTONDOWN */
\r
3776 /* Just have one menu, on the right button. Windows users don't
\r
3777 think to try the middle one, and sometimes other software steals
\r
3778 it, or it doesn't really exist. */
\r
3779 if(gameInfo.variant != VariantShogi)
\r
3780 MenuPopup(hwnd, pt, LoadMenu(hInst, "PieceMenu"), -1);
\r
3782 MenuPopup(hwnd, pt, LoadMenu(hInst, "ShogiPieceMenu"), -1);
\r
3785 case IcsPlayingWhite:
\r
3786 case IcsPlayingBlack:
\r
3788 case MachinePlaysWhite:
\r
3789 case MachinePlaysBlack:
\r
3790 if (appData.testLegality &&
\r
3791 gameInfo.variant != VariantBughouse &&
\r
3792 gameInfo.variant != VariantCrazyhouse) break;
\r
3793 if (x < 0 || y < 0) break;
\r
3796 hmenu = LoadMenu(hInst, "DropPieceMenu");
\r
3797 SetupDropMenu(hmenu);
\r
3798 MenuPopup(hwnd, pt, hmenu, -1);
\r
3809 /* Preprocess messages for buttons in main window */
\r
3811 ButtonProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
3813 int id = GetWindowLong(hwnd, GWL_ID);
\r
3816 for (i=0; i<N_BUTTONS; i++) {
\r
3817 if (buttonDesc[i].id == id) break;
\r
3819 if (i == N_BUTTONS) return 0;
\r
3820 switch (message) {
\r
3825 dir = (wParam == VK_LEFT) ? -1 : 1;
\r
3826 SetFocus(buttonDesc[(i + dir + N_BUTTONS) % N_BUTTONS].hwnd);
\r
3833 SendMessage(hwndMain, WM_COMMAND, MAKEWPARAM(buttonDesc[i].id, 0), 0);
\r
3836 if (appData.icsActive && (isalpha((char)wParam) || wParam == '0')) {
\r
3837 // [HGM] movenum: only letters or leading zero should go to ICS input
\r
3838 HWND h = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
3839 if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
3841 SendMessage(h, WM_CHAR, wParam, lParam);
\r
3843 } else if (isalpha((char)wParam) || isdigit((char)wParam)){
\r
3844 PopUpMoveDialog((char)wParam);
\r
3850 return CallWindowProc(buttonDesc[i].wndproc, hwnd, message, wParam, lParam);
\r
3853 /* Process messages for Promotion dialog box */
\r
3855 Promotion(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
3859 switch (message) {
\r
3860 case WM_INITDIALOG: /* message: initialize dialog box */
\r
3861 /* Center the dialog over the application window */
\r
3862 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
3863 ShowWindow(GetDlgItem(hDlg, PB_King),
\r
3864 (!appData.testLegality || gameInfo.variant == VariantSuicide ||
\r
3865 gameInfo.variant == VariantGiveaway || gameInfo.variant == VariantSuper ) ?
\r
3866 SW_SHOW : SW_HIDE);
\r
3867 /* [HGM] Only allow C & A promotions if these pieces are defined */
\r
3868 ShowWindow(GetDlgItem(hDlg, PB_Archbishop),
\r
3869 ((PieceToChar(WhiteAngel) >= 'A' &&
\r
3870 PieceToChar(WhiteAngel) != '~') ||
\r
3871 (PieceToChar(BlackAngel) >= 'A' &&
\r
3872 PieceToChar(BlackAngel) != '~') ) ?
\r
3873 SW_SHOW : SW_HIDE);
\r
3874 ShowWindow(GetDlgItem(hDlg, PB_Chancellor),
\r
3875 ((PieceToChar(WhiteMarshall) >= 'A' &&
\r
3876 PieceToChar(WhiteMarshall) != '~') ||
\r
3877 (PieceToChar(BlackMarshall) >= 'A' &&
\r
3878 PieceToChar(BlackMarshall) != '~') ) ?
\r
3879 SW_SHOW : SW_HIDE);
\r
3880 /* [HGM] Hide B & R button in Shogi, use Q as promote, N as defer */
\r
3881 ShowWindow(GetDlgItem(hDlg, PB_Rook),
\r
3882 gameInfo.variant != VariantShogi ?
\r
3883 SW_SHOW : SW_HIDE);
\r
3884 ShowWindow(GetDlgItem(hDlg, PB_Bishop),
\r
3885 gameInfo.variant != VariantShogi ?
\r
3886 SW_SHOW : SW_HIDE);
\r
3887 ShowWindow(GetDlgItem(hDlg, IDC_Yes),
\r
3888 gameInfo.variant == VariantShogi ?
\r
3889 SW_SHOW : SW_HIDE);
\r
3890 ShowWindow(GetDlgItem(hDlg, IDC_No),
\r
3891 gameInfo.variant == VariantShogi ?
\r
3892 SW_SHOW : SW_HIDE);
\r
3893 ShowWindow(GetDlgItem(hDlg, IDC_Centaur),
\r
3894 gameInfo.variant == VariantSuper ?
\r
3895 SW_SHOW : SW_HIDE);
\r
3898 case WM_COMMAND: /* message: received a command */
\r
3899 switch (LOWORD(wParam)) {
\r
3901 EndDialog(hDlg, TRUE); /* Exit the dialog */
\r
3902 ClearHighlights();
\r
3903 DrawPosition(FALSE, NULL);
\r
3906 promoChar = gameInfo.variant == VariantSuper ? PieceToChar(BlackSilver) : PieceToChar(BlackKing);
\r
3909 promoChar = gameInfo.variant == VariantShogi ? '+' : PieceToChar(BlackQueen);
\r
3912 promoChar = PieceToChar(BlackRook);
\r
3915 promoChar = PieceToChar(BlackBishop);
\r
3917 case PB_Chancellor:
\r
3918 promoChar = PieceToChar(BlackMarshall);
\r
3920 case PB_Archbishop:
\r
3921 promoChar = PieceToChar(BlackAngel);
\r
3924 promoChar = gameInfo.variant == VariantShogi ? '=' : PieceToChar(BlackKnight);
\r
3929 EndDialog(hDlg, TRUE); /* Exit the dialog */
\r
3930 /* [HGM] <popupFix> Call FinishMove rather than UserMoveEvent, as we
\r
3931 only show the popup when we are already sure the move is valid or
\r
3932 legal. We pass a faulty move type, but the kludge is that FinishMove
\r
3933 will figure out it is a promotion from the promoChar. */
\r
3934 UserMoveEvent(fromX, fromY, toX, toY, promoChar);
\r
3935 fromX = fromY = -1;
\r
3936 if (!appData.highlightLastMove) {
\r
3937 ClearHighlights();
\r
3938 DrawPosition(FALSE, NULL);
\r
3945 /* Pop up promotion dialog */
\r
3947 PromotionPopup(HWND hwnd)
\r
3951 lpProc = MakeProcInstance((FARPROC)Promotion, hInst);
\r
3952 DialogBox(hInst, MAKEINTRESOURCE(DLG_PromotionKing),
\r
3953 hwnd, (DLGPROC)lpProc);
\r
3954 FreeProcInstance(lpProc);
\r
3960 DrawPosition(TRUE, NULL);
\r
3961 PromotionPopup(hwndMain);
\r
3964 /* Toggle ShowThinking */
\r
3966 ToggleShowThinking()
\r
3968 appData.showThinking = !appData.showThinking;
\r
3969 ShowThinkingEvent();
\r
3973 LoadGameDialog(HWND hwnd, char* title)
\r
3977 char fileTitle[MSG_SIZ];
\r
3978 f = OpenFileDialog(hwnd, "rb", "",
\r
3979 appData.oldSaveStyle ? "gam" : "pgn",
\r
3981 title, &number, fileTitle, NULL);
\r
3983 cmailMsgLoaded = FALSE;
\r
3984 if (number == 0) {
\r
3985 int error = GameListBuild(f);
\r
3987 DisplayError("Cannot build game list", error);
\r
3988 } else if (!ListEmpty(&gameList) &&
\r
3989 ((ListGame *) gameList.tailPred)->number > 1) {
\r
3990 GameListPopUp(f, fileTitle);
\r
3993 GameListDestroy();
\r
3996 LoadGame(f, number, fileTitle, FALSE);
\r
4000 int get_term_width()
\r
4005 HFONT hfont, hold_font;
\r
4010 hText = GetDlgItem(hwndConsole, OPT_ConsoleText);
\r
4014 // get the text metrics
\r
4015 hdc = GetDC(hText);
\r
4016 lf = font[boardSize][CONSOLE_FONT]->lf;
\r
4017 if (consoleCF.dwEffects & CFE_BOLD)
\r
4018 lf.lfWeight = FW_BOLD;
\r
4019 if (consoleCF.dwEffects & CFE_ITALIC)
\r
4020 lf.lfItalic = TRUE;
\r
4021 if (consoleCF.dwEffects & CFE_STRIKEOUT)
\r
4022 lf.lfStrikeOut = TRUE;
\r
4023 if (consoleCF.dwEffects & CFE_UNDERLINE)
\r
4024 lf.lfUnderline = TRUE;
\r
4025 hfont = CreateFontIndirect(&lf);
\r
4026 hold_font = SelectObject(hdc, hfont);
\r
4027 GetTextMetrics(hdc, &tm);
\r
4028 SelectObject(hdc, hold_font);
\r
4029 DeleteObject(hfont);
\r
4030 ReleaseDC(hText, hdc);
\r
4032 // get the rectangle
\r
4033 SendMessage(hText, EM_GETRECT, 0, (LPARAM)&rc);
\r
4035 return (rc.right-rc.left) / tm.tmAveCharWidth;
\r
4038 void UpdateICSWidth(HWND hText)
\r
4040 LONG old_width, new_width;
\r
4042 new_width = get_term_width(hText, FALSE);
\r
4043 old_width = GetWindowLong(hText, GWL_USERDATA);
\r
4044 if (new_width != old_width)
\r
4046 ics_update_width(new_width);
\r
4047 SetWindowLong(hText, GWL_USERDATA, new_width);
\r
4052 ChangedConsoleFont()
\r
4055 CHARRANGE tmpsel, sel;
\r
4056 MyFont *f = font[boardSize][CONSOLE_FONT];
\r
4057 HWND hText = GetDlgItem(hwndConsole, OPT_ConsoleText);
\r
4058 HWND hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
4061 cfmt.cbSize = sizeof(CHARFORMAT);
\r
4062 cfmt.dwMask = CFM_FACE|CFM_SIZE|CFM_CHARSET;
\r
4063 strcpy(cfmt.szFaceName, font[boardSize][CONSOLE_FONT]->mfp.faceName);
\r
4064 /* yHeight is expressed in twips. A twip is 1/20 of a font's point
\r
4065 * size. This was undocumented in the version of MSVC++ that I had
\r
4066 * when I wrote the code, but is apparently documented now.
\r
4068 cfmt.yHeight = (int)(f->mfp.pointSize * 20.0 + 0.5);
\r
4069 cfmt.bCharSet = f->lf.lfCharSet;
\r
4070 cfmt.bPitchAndFamily = f->lf.lfPitchAndFamily;
\r
4071 SendMessage(hText, EM_SETCHARFORMAT, SCF_ALL, (LPARAM) &cfmt);
\r
4072 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM) &cfmt);
\r
4073 /* Why are the following seemingly needed too? */
\r
4074 SendMessage(hText, EM_SETCHARFORMAT, SCF_DEFAULT, (LPARAM) &cfmt);
\r
4075 SendMessage(hInput, EM_SETCHARFORMAT, SCF_DEFAULT, (LPARAM) &cfmt);
\r
4076 SendMessage(hText, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
4078 tmpsel.cpMax = -1; /*999999?*/
\r
4079 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&tmpsel);
\r
4080 SendMessage(hText, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM) &cfmt);
\r
4081 /* Trying putting this here too. It still seems to tickle a RichEdit
\r
4082 * bug: sometimes RichEdit indents the first line of a paragraph too.
\r
4084 paraf.cbSize = sizeof(paraf);
\r
4085 paraf.dwMask = PFM_OFFSET | PFM_STARTINDENT;
\r
4086 paraf.dxStartIndent = 0;
\r
4087 paraf.dxOffset = WRAP_INDENT;
\r
4088 SendMessage(hText, EM_SETPARAFORMAT, 0, (LPARAM) ¶f);
\r
4089 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
4090 UpdateICSWidth(hText);
\r
4093 /*---------------------------------------------------------------------------*\
\r
4095 * Window Proc for main window
\r
4097 \*---------------------------------------------------------------------------*/
\r
4099 /* Process messages for main window, etc. */
\r
4101 WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
4104 int wmId, wmEvent;
\r
4108 char fileTitle[MSG_SIZ];
\r
4109 char buf[MSG_SIZ];
\r
4110 static SnapData sd;
\r
4112 switch (message) {
\r
4114 case WM_PAINT: /* message: repaint portion of window */
\r
4118 case WM_ERASEBKGND:
\r
4119 if (IsIconic(hwnd)) {
\r
4120 /* Cheat; change the message */
\r
4121 return (DefWindowProc(hwnd, WM_ICONERASEBKGND, wParam, lParam));
\r
4123 return (DefWindowProc(hwnd, message, wParam, lParam));
\r
4127 case WM_LBUTTONDOWN:
\r
4128 case WM_MBUTTONDOWN:
\r
4129 case WM_RBUTTONDOWN:
\r
4130 case WM_LBUTTONUP:
\r
4131 case WM_MBUTTONUP:
\r
4132 case WM_RBUTTONUP:
\r
4133 case WM_MOUSEMOVE:
\r
4134 case WM_MOUSEWHEEL:
\r
4135 MouseEvent(hwnd, message, wParam, lParam);
\r
4138 JAWS_KB_NAVIGATION
\r
4142 JAWS_ALT_INTERCEPT
\r
4144 if (appData.icsActive && ((char)wParam == '\r' || (char)wParam > ' ' && !((char)wParam >= '1' && (char)wParam <= '9'))) {
\r
4145 // [HGM] movenum: for non-zero digits we always do type-in dialog
\r
4146 HWND h = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
4147 if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
4149 SendMessage(h, message, wParam, lParam);
\r
4150 } else if(lParam != KF_REPEAT) {
\r
4151 if (isalpha((char)wParam) || isdigit((char)wParam)) {
\r
4152 PopUpMoveDialog((char)wParam);
\r
4153 } else if((char)wParam == 003) CopyGameToClipboard();
\r
4154 else if((char)wParam == 026) PasteGameOrFENFromClipboard();
\r
4159 case WM_PALETTECHANGED:
\r
4160 if (hwnd != (HWND)wParam && !appData.monoMode) {
\r
4162 HDC hdc = GetDC(hwndMain);
\r
4163 SelectPalette(hdc, hPal, TRUE);
\r
4164 nnew = RealizePalette(hdc);
\r
4166 paletteChanged = TRUE;
\r
4167 InvalidateRect(hwnd, &boardRect, FALSE);
\r
4169 ReleaseDC(hwnd, hdc);
\r
4173 case WM_QUERYNEWPALETTE:
\r
4174 if (!appData.monoMode /*&& paletteChanged*/) {
\r
4176 HDC hdc = GetDC(hwndMain);
\r
4177 paletteChanged = FALSE;
\r
4178 SelectPalette(hdc, hPal, FALSE);
\r
4179 nnew = RealizePalette(hdc);
\r
4181 InvalidateRect(hwnd, &boardRect, FALSE);
\r
4183 ReleaseDC(hwnd, hdc);
\r
4188 case WM_COMMAND: /* message: command from application menu */
\r
4189 wmId = LOWORD(wParam);
\r
4190 wmEvent = HIWORD(wParam);
\r
4195 SAY("new game enter a move to play against the computer with white");
\r
4198 case IDM_NewGameFRC:
\r
4199 if( NewGameFRC() == 0 ) {
\r
4204 case IDM_NewVariant:
\r
4205 NewVariantPopup(hwnd);
\r
4208 case IDM_LoadGame:
\r
4209 LoadGameDialog(hwnd, "Load Game from File");
\r
4212 case IDM_LoadNextGame:
\r
4216 case IDM_LoadPrevGame:
\r
4220 case IDM_ReloadGame:
\r
4224 case IDM_LoadPosition:
\r
4225 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile) {
\r
4226 Reset(FALSE, TRUE);
\r
4229 f = OpenFileDialog(hwnd, "rb", "",
\r
4230 appData.oldSaveStyle ? "pos" : "fen",
\r
4232 "Load Position from File", &number, fileTitle, NULL);
\r
4234 LoadPosition(f, number, fileTitle);
\r
4238 case IDM_LoadNextPosition:
\r
4239 ReloadPosition(1);
\r
4242 case IDM_LoadPrevPosition:
\r
4243 ReloadPosition(-1);
\r
4246 case IDM_ReloadPosition:
\r
4247 ReloadPosition(0);
\r
4250 case IDM_SaveGame:
\r
4251 defName = DefaultFileName(appData.oldSaveStyle ? "gam" : "pgn");
\r
4252 f = OpenFileDialog(hwnd, "a", defName,
\r
4253 appData.oldSaveStyle ? "gam" : "pgn",
\r
4255 "Save Game to File", NULL, fileTitle, NULL);
\r
4257 SaveGame(f, 0, "");
\r
4261 case IDM_SavePosition:
\r
4262 defName = DefaultFileName(appData.oldSaveStyle ? "pos" : "fen");
\r
4263 f = OpenFileDialog(hwnd, "a", defName,
\r
4264 appData.oldSaveStyle ? "pos" : "fen",
\r
4266 "Save Position to File", NULL, fileTitle, NULL);
\r
4268 SavePosition(f, 0, "");
\r
4272 case IDM_SaveDiagram:
\r
4273 defName = "diagram";
\r
4274 f = OpenFileDialog(hwnd, "wb", defName,
\r
4277 "Save Diagram to File", NULL, fileTitle, NULL);
\r
4283 case IDM_CopyGame:
\r
4284 CopyGameToClipboard();
\r
4287 case IDM_PasteGame:
\r
4288 PasteGameFromClipboard();
\r
4291 case IDM_CopyGameListToClipboard:
\r
4292 CopyGameListToClipboard();
\r
4295 /* [AS] Autodetect FEN or PGN data */
\r
4296 case IDM_PasteAny:
\r
4297 PasteGameOrFENFromClipboard();
\r
4300 /* [AS] Move history */
\r
4301 case IDM_ShowMoveHistory:
\r
4302 if( MoveHistoryIsUp() ) {
\r
4303 MoveHistoryPopDown();
\r
4306 MoveHistoryPopUp();
\r
4310 /* [AS] Eval graph */
\r
4311 case IDM_ShowEvalGraph:
\r
4312 if( EvalGraphIsUp() ) {
\r
4313 EvalGraphPopDown();
\r
4317 SetFocus(hwndMain);
\r
4321 /* [AS] Engine output */
\r
4322 case IDM_ShowEngineOutput:
\r
4323 if( EngineOutputIsUp() ) {
\r
4324 EngineOutputPopDown();
\r
4327 EngineOutputPopUp();
\r
4331 /* [AS] User adjudication */
\r
4332 case IDM_UserAdjudication_White:
\r
4333 UserAdjudicationEvent( +1 );
\r
4336 case IDM_UserAdjudication_Black:
\r
4337 UserAdjudicationEvent( -1 );
\r
4340 case IDM_UserAdjudication_Draw:
\r
4341 UserAdjudicationEvent( 0 );
\r
4344 /* [AS] Game list options dialog */
\r
4345 case IDM_GameListOptions:
\r
4346 GameListOptions();
\r
4353 case IDM_CopyPosition:
\r
4354 CopyFENToClipboard();
\r
4357 case IDM_PastePosition:
\r
4358 PasteFENFromClipboard();
\r
4361 case IDM_MailMove:
\r
4365 case IDM_ReloadCMailMsg:
\r
4366 Reset(TRUE, TRUE);
\r
4367 ReloadCmailMsgEvent(FALSE);
\r
4370 case IDM_Minimize:
\r
4371 ShowWindow(hwnd, SW_MINIMIZE);
\r
4378 case IDM_MachineWhite:
\r
4379 MachineWhiteEvent();
\r
4381 * refresh the tags dialog only if it's visible
\r
4383 if (gameMode == MachinePlaysWhite && IsWindowVisible(editTagsDialog)) {
\r
4385 tags = PGNTags(&gameInfo);
\r
4386 TagsPopUp(tags, CmailMsg());
\r
4389 SAY("computer starts playing white");
\r
4392 case IDM_MachineBlack:
\r
4393 MachineBlackEvent();
\r
4395 * refresh the tags dialog only if it's visible
\r
4397 if (gameMode == MachinePlaysBlack && IsWindowVisible(editTagsDialog)) {
\r
4399 tags = PGNTags(&gameInfo);
\r
4400 TagsPopUp(tags, CmailMsg());
\r
4403 SAY("computer starts playing black");
\r
4406 case IDM_TwoMachines:
\r
4407 TwoMachinesEvent();
\r
4409 * refresh the tags dialog only if it's visible
\r
4411 if (gameMode == TwoMachinesPlay && IsWindowVisible(editTagsDialog)) {
\r
4413 tags = PGNTags(&gameInfo);
\r
4414 TagsPopUp(tags, CmailMsg());
\r
4417 SAY("programs start playing each other");
\r
4420 case IDM_AnalysisMode:
\r
4421 if (!first.analysisSupport) {
\r
4422 sprintf(buf, "%s does not support analysis", first.tidy);
\r
4423 DisplayError(buf, 0);
\r
4425 SAY("analyzing current position");
\r
4426 /* [DM] icsEngineAnlyze [HGM] Why is this front-end??? */
\r
4427 if (appData.icsActive) {
\r
4428 if (gameMode != IcsObserving) {
\r
4429 sprintf(buf, "You are not observing a game");
\r
4430 DisplayError(buf, 0);
\r
4431 /* secure check */
\r
4432 if (appData.icsEngineAnalyze) {
\r
4433 if (appData.debugMode)
\r
4434 fprintf(debugFP, "Found unexpected active ICS engine analyze \n");
\r
4435 ExitAnalyzeMode();
\r
4441 /* if enable, user want disable icsEngineAnalyze */
\r
4442 if (appData.icsEngineAnalyze) {
\r
4443 ExitAnalyzeMode();
\r
4447 appData.icsEngineAnalyze = TRUE;
\r
4448 if (appData.debugMode) fprintf(debugFP, "ICS engine analyze starting...\n");
\r
4451 if (!appData.showThinking) ToggleShowThinking();
\r
4452 AnalyzeModeEvent();
\r
4456 case IDM_AnalyzeFile:
\r
4457 if (!first.analysisSupport) {
\r
4458 char buf[MSG_SIZ];
\r
4459 sprintf(buf, "%s does not support analysis", first.tidy);
\r
4460 DisplayError(buf, 0);
\r
4462 if (!appData.showThinking) ToggleShowThinking();
\r
4463 AnalyzeFileEvent();
\r
4464 LoadGameDialog(hwnd, "Analyze Game from File");
\r
4465 AnalysisPeriodicEvent(1);
\r
4469 case IDM_IcsClient:
\r
4473 case IDM_EditGame:
\r
4478 case IDM_EditPosition:
\r
4479 EditPositionEvent();
\r
4480 SAY("to set up a position type a FEN");
\r
4483 case IDM_Training:
\r
4487 case IDM_ShowGameList:
\r
4488 ShowGameListProc();
\r
4491 case IDM_EditTags:
\r
4495 case IDM_EditComment:
\r
4496 if (commentUp && editComment) {
\r
4499 EditCommentEvent();
\r
4519 case IDM_CallFlag:
\r
4539 case IDM_StopObserving:
\r
4540 StopObservingEvent();
\r
4543 case IDM_StopExamining:
\r
4544 StopExaminingEvent();
\r
4547 case IDM_TypeInMove:
\r
4548 PopUpMoveDialog('\000');
\r
4551 case IDM_TypeInName:
\r
4552 PopUpNameDialog('\000');
\r
4555 case IDM_Backward:
\r
4557 SetFocus(hwndMain);
\r
4564 SetFocus(hwndMain);
\r
4569 SetFocus(hwndMain);
\r
4574 SetFocus(hwndMain);
\r
4581 case IDM_TruncateGame:
\r
4582 TruncateGameEvent();
\r
4589 case IDM_RetractMove:
\r
4590 RetractMoveEvent();
\r
4593 case IDM_FlipView:
\r
4594 flipView = !flipView;
\r
4595 DrawPosition(FALSE, NULL);
\r
4598 case IDM_FlipClock:
\r
4599 flipClock = !flipClock;
\r
4600 DisplayBothClocks();
\r
4601 DrawPosition(FALSE, NULL);
\r
4604 case IDM_MuteSounds:
\r
4605 mute = !mute; // [HGM] mute: keep track of global muting variable
\r
4606 CheckMenuItem(GetMenu(hwndMain),IDM_MuteSounds,
\r
4607 MF_BYCOMMAND|(mute?MF_CHECKED:MF_UNCHECKED));
\r
4610 case IDM_GeneralOptions:
\r
4611 GeneralOptionsPopup(hwnd);
\r
4612 DrawPosition(TRUE, NULL);
\r
4615 case IDM_BoardOptions:
\r
4616 BoardOptionsPopup(hwnd);
\r
4619 case IDM_EnginePlayOptions:
\r
4620 EnginePlayOptionsPopup(hwnd);
\r
4623 case IDM_Engine1Options:
\r
4624 EngineOptionsPopup(hwnd, &first);
\r
4627 case IDM_Engine2Options:
\r
4628 EngineOptionsPopup(hwnd, &second);
\r
4631 case IDM_OptionsUCI:
\r
4632 UciOptionsPopup(hwnd);
\r
4635 case IDM_IcsOptions:
\r
4636 IcsOptionsPopup(hwnd);
\r
4640 FontsOptionsPopup(hwnd);
\r
4644 SoundOptionsPopup(hwnd);
\r
4647 case IDM_CommPort:
\r
4648 CommPortOptionsPopup(hwnd);
\r
4651 case IDM_LoadOptions:
\r
4652 LoadOptionsPopup(hwnd);
\r
4655 case IDM_SaveOptions:
\r
4656 SaveOptionsPopup(hwnd);
\r
4659 case IDM_TimeControl:
\r
4660 TimeControlOptionsPopup(hwnd);
\r
4663 case IDM_SaveSettings:
\r
4664 SaveSettings(settingsFileName);
\r
4667 case IDM_SaveSettingsOnExit:
\r
4668 saveSettingsOnExit = !saveSettingsOnExit;
\r
4669 (void) CheckMenuItem(GetMenu(hwndMain), IDM_SaveSettingsOnExit,
\r
4670 MF_BYCOMMAND|(saveSettingsOnExit ?
\r
4671 MF_CHECKED : MF_UNCHECKED));
\r
4682 case IDM_AboutGame:
\r
4687 appData.debugMode = !appData.debugMode;
\r
4688 if (appData.debugMode) {
\r
4689 char dir[MSG_SIZ];
\r
4690 GetCurrentDirectory(MSG_SIZ, dir);
\r
4691 SetCurrentDirectory(installDir);
\r
4692 debugFP = fopen(appData.nameOfDebugFile, "w");
\r
4693 SetCurrentDirectory(dir);
\r
4694 setbuf(debugFP, NULL);
\r
4701 case IDM_HELPCONTENTS:
\r
4702 if (!MyHelp (hwnd, "winboard.hlp", HELP_KEY,(DWORD)(LPSTR)"CONTENTS") &&
\r
4703 !HtmlHelp(hwnd, "winboard.chm", 0, 0) ) {
\r
4704 MessageBox (GetFocus(),
\r
4705 "Unable to activate help",
\r
4706 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
4710 case IDM_HELPSEARCH:
\r
4711 if (!MyHelp (hwnd, "winboard.hlp", HELP_PARTIALKEY, (DWORD)(LPSTR)"") &&
\r
4712 !HtmlHelp(hwnd, "winboard.chm", 0, 0) ) {
\r
4713 MessageBox (GetFocus(),
\r
4714 "Unable to activate help",
\r
4715 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
4719 case IDM_HELPHELP:
\r
4720 if(!WinHelp(hwnd, (LPSTR)NULL, HELP_HELPONHELP, 0)) {
\r
4721 MessageBox (GetFocus(),
\r
4722 "Unable to activate help",
\r
4723 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
4728 lpProc = MakeProcInstance((FARPROC)About, hInst);
\r
4730 (gameInfo.event && strcmp(gameInfo.event, "Easter Egg Hunt") == 0) ?
\r
4731 "AboutBox2" : "AboutBox", hwnd, (DLGPROC)lpProc);
\r
4732 FreeProcInstance(lpProc);
\r
4735 case IDM_DirectCommand1:
\r
4736 AskQuestionEvent("Direct Command",
\r
4737 "Send to chess program:", "", "1");
\r
4739 case IDM_DirectCommand2:
\r
4740 AskQuestionEvent("Direct Command",
\r
4741 "Send to second chess program:", "", "2");
\r
4744 case EP_WhitePawn:
\r
4745 EditPositionMenuEvent(WhitePawn, fromX, fromY);
\r
4746 fromX = fromY = -1;
\r
4749 case EP_WhiteKnight:
\r
4750 EditPositionMenuEvent(WhiteKnight, fromX, fromY);
\r
4751 fromX = fromY = -1;
\r
4754 case EP_WhiteBishop:
\r
4755 EditPositionMenuEvent(WhiteBishop, fromX, fromY);
\r
4756 fromX = fromY = -1;
\r
4759 case EP_WhiteRook:
\r
4760 EditPositionMenuEvent(WhiteRook, fromX, fromY);
\r
4761 fromX = fromY = -1;
\r
4764 case EP_WhiteQueen:
\r
4765 EditPositionMenuEvent(WhiteQueen, fromX, fromY);
\r
4766 fromX = fromY = -1;
\r
4769 case EP_WhiteFerz:
\r
4770 EditPositionMenuEvent(WhiteFerz, fromX, fromY);
\r
4771 fromX = fromY = -1;
\r
4774 case EP_WhiteWazir:
\r
4775 EditPositionMenuEvent(WhiteWazir, fromX, fromY);
\r
4776 fromX = fromY = -1;
\r
4779 case EP_WhiteAlfil:
\r
4780 EditPositionMenuEvent(WhiteAlfil, fromX, fromY);
\r
4781 fromX = fromY = -1;
\r
4784 case EP_WhiteCannon:
\r
4785 EditPositionMenuEvent(WhiteCannon, fromX, fromY);
\r
4786 fromX = fromY = -1;
\r
4789 case EP_WhiteCardinal:
\r
4790 EditPositionMenuEvent(WhiteAngel, fromX, fromY);
\r
4791 fromX = fromY = -1;
\r
4794 case EP_WhiteMarshall:
\r
4795 EditPositionMenuEvent(WhiteMarshall, fromX, fromY);
\r
4796 fromX = fromY = -1;
\r
4799 case EP_WhiteKing:
\r
4800 EditPositionMenuEvent(WhiteKing, fromX, fromY);
\r
4801 fromX = fromY = -1;
\r
4804 case EP_BlackPawn:
\r
4805 EditPositionMenuEvent(BlackPawn, fromX, fromY);
\r
4806 fromX = fromY = -1;
\r
4809 case EP_BlackKnight:
\r
4810 EditPositionMenuEvent(BlackKnight, fromX, fromY);
\r
4811 fromX = fromY = -1;
\r
4814 case EP_BlackBishop:
\r
4815 EditPositionMenuEvent(BlackBishop, fromX, fromY);
\r
4816 fromX = fromY = -1;
\r
4819 case EP_BlackRook:
\r
4820 EditPositionMenuEvent(BlackRook, fromX, fromY);
\r
4821 fromX = fromY = -1;
\r
4824 case EP_BlackQueen:
\r
4825 EditPositionMenuEvent(BlackQueen, fromX, fromY);
\r
4826 fromX = fromY = -1;
\r
4829 case EP_BlackFerz:
\r
4830 EditPositionMenuEvent(BlackFerz, fromX, fromY);
\r
4831 fromX = fromY = -1;
\r
4834 case EP_BlackWazir:
\r
4835 EditPositionMenuEvent(BlackWazir, fromX, fromY);
\r
4836 fromX = fromY = -1;
\r
4839 case EP_BlackAlfil:
\r
4840 EditPositionMenuEvent(BlackAlfil, fromX, fromY);
\r
4841 fromX = fromY = -1;
\r
4844 case EP_BlackCannon:
\r
4845 EditPositionMenuEvent(BlackCannon, fromX, fromY);
\r
4846 fromX = fromY = -1;
\r
4849 case EP_BlackCardinal:
\r
4850 EditPositionMenuEvent(BlackAngel, fromX, fromY);
\r
4851 fromX = fromY = -1;
\r
4854 case EP_BlackMarshall:
\r
4855 EditPositionMenuEvent(BlackMarshall, fromX, fromY);
\r
4856 fromX = fromY = -1;
\r
4859 case EP_BlackKing:
\r
4860 EditPositionMenuEvent(BlackKing, fromX, fromY);
\r
4861 fromX = fromY = -1;
\r
4864 case EP_EmptySquare:
\r
4865 EditPositionMenuEvent(EmptySquare, fromX, fromY);
\r
4866 fromX = fromY = -1;
\r
4869 case EP_ClearBoard:
\r
4870 EditPositionMenuEvent(ClearBoard, fromX, fromY);
\r
4871 fromX = fromY = -1;
\r
4875 EditPositionMenuEvent(WhitePlay, fromX, fromY);
\r
4876 fromX = fromY = -1;
\r
4880 EditPositionMenuEvent(BlackPlay, fromX, fromY);
\r
4881 fromX = fromY = -1;
\r
4885 EditPositionMenuEvent(PromotePiece, fromX, fromY);
\r
4886 fromX = fromY = -1;
\r
4890 EditPositionMenuEvent(DemotePiece, fromX, fromY);
\r
4891 fromX = fromY = -1;
\r
4895 DropMenuEvent(WhitePawn, fromX, fromY);
\r
4896 fromX = fromY = -1;
\r
4900 DropMenuEvent(WhiteKnight, fromX, fromY);
\r
4901 fromX = fromY = -1;
\r
4905 DropMenuEvent(WhiteBishop, fromX, fromY);
\r
4906 fromX = fromY = -1;
\r
4910 DropMenuEvent(WhiteRook, fromX, fromY);
\r
4911 fromX = fromY = -1;
\r
4915 DropMenuEvent(WhiteQueen, fromX, fromY);
\r
4916 fromX = fromY = -1;
\r
4920 return (DefWindowProc(hwnd, message, wParam, lParam));
\r
4926 case CLOCK_TIMER_ID:
\r
4927 KillTimer(hwnd, clockTimerEvent); /* Simulate one-shot timer as in X */
\r
4928 clockTimerEvent = 0;
\r
4929 DecrementClocks(); /* call into back end */
\r
4931 case LOAD_GAME_TIMER_ID:
\r
4932 KillTimer(hwnd, loadGameTimerEvent); /* Simulate one-shot timer as in X*/
\r
4933 loadGameTimerEvent = 0;
\r
4934 AutoPlayGameLoop(); /* call into back end */
\r
4936 case ANALYSIS_TIMER_ID:
\r
4937 if ((gameMode == AnalyzeMode || gameMode == AnalyzeFile
\r
4938 || appData.icsEngineAnalyze) && appData.periodicUpdates) {
\r
4939 AnalysisPeriodicEvent(0);
\r
4941 KillTimer(hwnd, analysisTimerEvent);
\r
4942 analysisTimerEvent = 0;
\r
4945 case DELAYED_TIMER_ID:
\r
4946 KillTimer(hwnd, delayedTimerEvent);
\r
4947 delayedTimerEvent = 0;
\r
4948 delayedTimerCallback();
\r
4953 case WM_USER_Input:
\r
4954 InputEvent(hwnd, message, wParam, lParam);
\r
4957 /* [AS] Also move "attached" child windows */
\r
4958 case WM_WINDOWPOSCHANGING:
\r
4960 if( hwnd == hwndMain && appData.useStickyWindows ) {
\r
4961 LPWINDOWPOS lpwp = (LPWINDOWPOS) lParam;
\r
4963 if( ((lpwp->flags & SWP_NOMOVE) == 0) && ((lpwp->flags & SWP_NOSIZE) != 0) ) {
\r
4964 /* Window is moving */
\r
4967 // GetWindowRect( hwnd, &rcMain ); //[HGM] sticky: in XP this returned new position, not old
\r
4968 rcMain.left = wpMain.x; // replace by these 4 lines to reconstruct old rect
\r
4969 rcMain.right = wpMain.x + wpMain.width;
\r
4970 rcMain.top = wpMain.y;
\r
4971 rcMain.bottom = wpMain.y + wpMain.height;
\r
4973 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, moveHistoryDialog, &wpMoveHistory );
\r
4974 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, evalGraphDialog, &wpEvalGraph );
\r
4975 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, engineOutputDialog, &wpEngineOutput );
\r
4976 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, gameListDialog, &wpGameList );
\r
4977 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, hwndConsole, &wpConsole );
\r
4978 wpMain.x = lpwp->x;
\r
4979 wpMain.y = lpwp->y;
\r
4984 /* [AS] Snapping */
\r
4985 case WM_ENTERSIZEMOVE:
\r
4986 if(appData.debugMode) { fprintf(debugFP, "size-move\n"); }
\r
4987 if (hwnd == hwndMain) {
\r
4988 doingSizing = TRUE;
\r
4991 return OnEnterSizeMove( &sd, hwnd, wParam, lParam );
\r
4995 if(appData.debugMode) { fprintf(debugFP, "sizing\n"); }
\r
4996 if (hwnd == hwndMain) {
\r
4997 lastSizing = wParam;
\r
5002 if(appData.debugMode) { fprintf(debugFP, "moving\n"); }
\r
5003 return OnMoving( &sd, hwnd, wParam, lParam );
\r
5005 case WM_EXITSIZEMOVE:
\r
5006 if(appData.debugMode) { fprintf(debugFP, "exit size-move, size = %d\n", squareSize); }
\r
5007 if (hwnd == hwndMain) {
\r
5009 doingSizing = FALSE;
\r
5010 InvalidateRect(hwnd, &boardRect, FALSE);
\r
5011 GetClientRect(hwnd, &client);
\r
5012 ResizeBoard(client.right, client.bottom, lastSizing);
\r
5014 if(appData.debugMode) { fprintf(debugFP, "square size = %d\n", squareSize); }
\r
5016 return OnExitSizeMove( &sd, hwnd, wParam, lParam );
\r
5019 case WM_DESTROY: /* message: window being destroyed */
\r
5020 PostQuitMessage(0);
\r
5024 if (hwnd == hwndMain) {
\r
5029 default: /* Passes it on if unprocessed */
\r
5030 return (DefWindowProc(hwnd, message, wParam, lParam));
\r
5035 /*---------------------------------------------------------------------------*\
\r
5037 * Misc utility routines
\r
5039 \*---------------------------------------------------------------------------*/
\r
5042 * Decent random number generator, at least not as bad as Windows
\r
5043 * standard rand, which returns a value in the range 0 to 0x7fff.
\r
5045 unsigned int randstate;
\r
5050 randstate = randstate * 1664525 + 1013904223;
\r
5051 return (int) randstate & 0x7fffffff;
\r
5055 mysrandom(unsigned int seed)
\r
5062 * returns TRUE if user selects a different color, FALSE otherwise
\r
5066 ChangeColor(HWND hwnd, COLORREF *which)
\r
5068 static BOOL firstTime = TRUE;
\r
5069 static DWORD customColors[16];
\r
5071 COLORREF newcolor;
\r
5076 /* Make initial colors in use available as custom colors */
\r
5077 /* Should we put the compiled-in defaults here instead? */
\r
5079 customColors[i++] = lightSquareColor & 0xffffff;
\r
5080 customColors[i++] = darkSquareColor & 0xffffff;
\r
5081 customColors[i++] = whitePieceColor & 0xffffff;
\r
5082 customColors[i++] = blackPieceColor & 0xffffff;
\r
5083 customColors[i++] = highlightSquareColor & 0xffffff;
\r
5084 customColors[i++] = premoveHighlightColor & 0xffffff;
\r
5086 for (ccl = (ColorClass) 0; ccl < NColorClasses && i < 16; ccl++) {
\r
5087 customColors[i++] = textAttribs[ccl].color;
\r
5089 while (i < 16) customColors[i++] = RGB(255, 255, 255);
\r
5090 firstTime = FALSE;
\r
5093 cc.lStructSize = sizeof(cc);
\r
5094 cc.hwndOwner = hwnd;
\r
5095 cc.hInstance = NULL;
\r
5096 cc.rgbResult = (DWORD) (*which & 0xffffff);
\r
5097 cc.lpCustColors = (LPDWORD) customColors;
\r
5098 cc.Flags = CC_RGBINIT|CC_FULLOPEN;
\r
5100 if (!ChooseColor(&cc)) return FALSE;
\r
5102 newcolor = (COLORREF) (0x2000000 | cc.rgbResult);
\r
5103 if (newcolor == *which) return FALSE;
\r
5104 *which = newcolor;
\r
5108 InitDrawingColors();
\r
5109 InvalidateRect(hwnd, &boardRect, FALSE);
\r
5114 MyLoadSound(MySound *ms)
\r
5120 if (ms->data) free(ms->data);
\r
5123 switch (ms->name[0]) {
\r
5129 /* System sound from Control Panel. Don't preload here. */
\r
5133 if (ms->name[1] == NULLCHAR) {
\r
5134 /* "!" alone = silence */
\r
5137 /* Builtin wave resource. Error if not found. */
\r
5138 HANDLE h = FindResource(hInst, ms->name + 1, "WAVE");
\r
5139 if (h == NULL) break;
\r
5140 ms->data = (void *)LoadResource(hInst, h);
\r
5141 if (h == NULL) break;
\r
5146 /* .wav file. Error if not found. */
\r
5147 f = fopen(ms->name, "rb");
\r
5148 if (f == NULL) break;
\r
5149 if (fstat(fileno(f), &st) < 0) break;
\r
5150 ms->data = malloc(st.st_size);
\r
5151 if (fread(ms->data, st.st_size, 1, f) < 1) break;
\r
5157 char buf[MSG_SIZ];
\r
5158 sprintf(buf, "Error loading sound %s", ms->name);
\r
5159 DisplayError(buf, GetLastError());
\r
5165 MyPlaySound(MySound *ms)
\r
5167 BOOLEAN ok = FALSE;
\r
5169 if(mute) return TRUE; // [HGM] mute: suppress all sound play when muted
\r
5170 switch (ms->name[0]) {
\r
5172 if(appData.debugMode) fprintf(debugFP, "silence\n");
\r
5177 /* System sound from Control Panel (deprecated feature).
\r
5178 "$" alone or an unset sound name gets default beep (still in use). */
\r
5179 if (ms->name[1]) {
\r
5180 ok = PlaySound(ms->name + 1, NULL, SND_ALIAS|SND_ASYNC);
\r
5182 if (!ok) ok = MessageBeep(MB_OK);
\r
5185 /* Builtin wave resource, or "!" alone for silence */
\r
5186 if (ms->name[1]) {
\r
5187 if (ms->data == NULL) return FALSE;
\r
5188 ok = PlaySound(ms->data, NULL, SND_MEMORY|SND_ASYNC);
\r
5194 /* .wav file. Error if not found. */
\r
5195 if (ms->data == NULL) return FALSE;
\r
5196 ok = PlaySound(ms->data, NULL, SND_MEMORY|SND_ASYNC);
\r
5199 /* Don't print an error: this can happen innocently if the sound driver
\r
5200 is busy; for instance, if another instance of WinBoard is playing
\r
5201 a sound at about the same time. */
\r
5207 OldOpenFileHook(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
5210 OPENFILENAME *ofn;
\r
5211 static UINT *number; /* gross that this is static */
\r
5213 switch (message) {
\r
5214 case WM_INITDIALOG: /* message: initialize dialog box */
\r
5215 /* Center the dialog over the application window */
\r
5216 ofn = (OPENFILENAME *) lParam;
\r
5217 if (ofn->Flags & OFN_ENABLETEMPLATE) {
\r
5218 number = (UINT *) ofn->lCustData;
\r
5219 SendMessage(GetDlgItem(hDlg, edt2), WM_SETTEXT, 0, (LPARAM) "");
\r
5223 CenterWindow (hDlg, GetWindow (hDlg, GW_OWNER));
\r
5224 return FALSE; /* Allow for further processing */
\r
5227 if ((LOWORD(wParam) == IDOK) && (number != NULL)) {
\r
5228 *number = GetDlgItemInt(hDlg, OPT_IndexNumberOld, &ok, FALSE);
\r
5230 return FALSE; /* Allow for further processing */
\r
5236 OpenFileHook(HWND hdlg, UINT uiMsg, WPARAM wParam, LPARAM lParam)
\r
5238 static UINT *number;
\r
5239 OPENFILENAME *ofname;
\r
5242 case WM_INITDIALOG:
\r
5243 ofname = (OPENFILENAME *)lParam;
\r
5244 number = (UINT *)(ofname->lCustData);
\r
5247 ofnot = (OFNOTIFY *)lParam;
\r
5248 if (ofnot->hdr.code == CDN_FILEOK) {
\r
5249 *number = GetDlgItemInt(hdlg, OPT_IndexNumber, NULL, FALSE);
\r
5258 OpenFileDialog(HWND hwnd, char *write, char *defName, char *defExt, // [HGM] diag: type of 'write' now string
\r
5259 char *nameFilt, char *dlgTitle, UINT *number,
\r
5260 char fileTitle[MSG_SIZ], char fileName[MSG_SIZ])
\r
5262 OPENFILENAME openFileName;
\r
5263 char buf1[MSG_SIZ];
\r
5266 if (fileName == NULL) fileName = buf1;
\r
5267 if (defName == NULL) {
\r
5268 strcpy(fileName, "*.");
\r
5269 strcat(fileName, defExt);
\r
5271 strcpy(fileName, defName);
\r
5273 if (fileTitle) strcpy(fileTitle, "");
\r
5274 if (number) *number = 0;
\r
5276 openFileName.lStructSize = sizeof(OPENFILENAME);
\r
5277 openFileName.hwndOwner = hwnd;
\r
5278 openFileName.hInstance = (HANDLE) hInst;
\r
5279 openFileName.lpstrFilter = nameFilt;
\r
5280 openFileName.lpstrCustomFilter = (LPSTR) NULL;
\r
5281 openFileName.nMaxCustFilter = 0L;
\r
5282 openFileName.nFilterIndex = 1L;
\r
5283 openFileName.lpstrFile = fileName;
\r
5284 openFileName.nMaxFile = MSG_SIZ;
\r
5285 openFileName.lpstrFileTitle = fileTitle;
\r
5286 openFileName.nMaxFileTitle = fileTitle ? MSG_SIZ : 0;
\r
5287 openFileName.lpstrInitialDir = NULL;
\r
5288 openFileName.lpstrTitle = dlgTitle;
\r
5289 openFileName.Flags = OFN_PATHMUSTEXIST | OFN_HIDEREADONLY
\r
5290 | (write[0] != 'r' ? 0 : OFN_FILEMUSTEXIST)
\r
5291 | (number ? OFN_ENABLETEMPLATE | OFN_ENABLEHOOK: 0)
\r
5292 | (oldDialog ? 0 : OFN_EXPLORER);
\r
5293 openFileName.nFileOffset = 0;
\r
5294 openFileName.nFileExtension = 0;
\r
5295 openFileName.lpstrDefExt = defExt;
\r
5296 openFileName.lCustData = (LONG) number;
\r
5297 openFileName.lpfnHook = oldDialog ?
\r
5298 (LPOFNHOOKPROC) OldOpenFileHook : (LPOFNHOOKPROC) OpenFileHook;
\r
5299 openFileName.lpTemplateName = (LPSTR)(oldDialog ? 1536 : DLG_IndexNumber);
\r
5301 if (write[0] != 'r' ? GetSaveFileName(&openFileName) :
\r
5302 GetOpenFileName(&openFileName)) {
\r
5303 /* open the file */
\r
5304 f = fopen(openFileName.lpstrFile, write);
\r
5306 MessageBox(hwnd, "File open failed", NULL,
\r
5307 MB_OK|MB_ICONEXCLAMATION);
\r
5311 int err = CommDlgExtendedError();
\r
5312 if (err != 0) DisplayError("Internal error in file dialog box", err);
\r
5321 MenuPopup(HWND hwnd, POINT pt, HMENU hmenu, UINT def)
\r
5323 HMENU hmenuTrackPopup; /* floating pop-up menu */
\r
5326 * Get the first pop-up menu in the menu template. This is the
\r
5327 * menu that TrackPopupMenu displays.
\r
5329 hmenuTrackPopup = GetSubMenu(hmenu, 0);
\r
5331 SetMenuDefaultItem(hmenuTrackPopup, def, FALSE);
\r
5334 * TrackPopup uses screen coordinates, so convert the
\r
5335 * coordinates of the mouse click to screen coordinates.
\r
5337 ClientToScreen(hwnd, (LPPOINT) &pt);
\r
5339 /* Draw and track the floating pop-up menu. */
\r
5340 TrackPopupMenu(hmenuTrackPopup, TPM_CENTERALIGN | TPM_RIGHTBUTTON,
\r
5341 pt.x, pt.y, 0, hwnd, NULL);
\r
5343 /* Destroy the menu.*/
\r
5344 DestroyMenu(hmenu);
\r
5349 int sizeX, sizeY, newSizeX, newSizeY;
\r
5351 } ResizeEditPlusButtonsClosure;
\r
5354 ResizeEditPlusButtonsCallback(HWND hChild, LPARAM lparam)
\r
5356 ResizeEditPlusButtonsClosure *cl = (ResizeEditPlusButtonsClosure *)lparam;
\r
5360 if (hChild == cl->hText) return TRUE;
\r
5361 GetWindowRect(hChild, &rect); /* gives screen coords */
\r
5362 pt.x = rect.left + (cl->newSizeX - cl->sizeX)/2;
\r
5363 pt.y = rect.top + cl->newSizeY - cl->sizeY;
\r
5364 ScreenToClient(cl->hDlg, &pt);
\r
5365 cl->hdwp = DeferWindowPos(cl->hdwp, hChild, NULL,
\r
5366 pt.x, pt.y, rect.right - rect.left, rect.bottom - rect.top, SWP_NOZORDER);
\r
5370 /* Resize a dialog that has a (rich) edit field filling most of
\r
5371 the top, with a row of buttons below */
\r
5373 ResizeEditPlusButtons(HWND hDlg, HWND hText, int sizeX, int sizeY, int newSizeX, int newSizeY)
\r
5376 int newTextHeight, newTextWidth;
\r
5377 ResizeEditPlusButtonsClosure cl;
\r
5379 /*if (IsIconic(hDlg)) return;*/
\r
5380 if (newSizeX == sizeX && newSizeY == sizeY) return;
\r
5382 cl.hdwp = BeginDeferWindowPos(8);
\r
5384 GetWindowRect(hText, &rectText); /* gives screen coords */
\r
5385 newTextWidth = rectText.right - rectText.left + newSizeX - sizeX;
\r
5386 newTextHeight = rectText.bottom - rectText.top + newSizeY - sizeY;
\r
5387 if (newTextHeight < 0) {
\r
5388 newSizeY += -newTextHeight;
\r
5389 newTextHeight = 0;
\r
5391 cl.hdwp = DeferWindowPos(cl.hdwp, hText, NULL, 0, 0,
\r
5392 newTextWidth, newTextHeight, SWP_NOZORDER|SWP_NOMOVE);
\r
5398 cl.newSizeX = newSizeX;
\r
5399 cl.newSizeY = newSizeY;
\r
5400 EnumChildWindows(hDlg, ResizeEditPlusButtonsCallback, (LPARAM)&cl);
\r
5402 EndDeferWindowPos(cl.hdwp);
\r
5405 BOOL CenterWindowEx(HWND hwndChild, HWND hwndParent, int mode)
\r
5407 RECT rChild, rParent;
\r
5408 int wChild, hChild, wParent, hParent;
\r
5409 int wScreen, hScreen, xNew, yNew;
\r
5412 /* Get the Height and Width of the child window */
\r
5413 GetWindowRect (hwndChild, &rChild);
\r
5414 wChild = rChild.right - rChild.left;
\r
5415 hChild = rChild.bottom - rChild.top;
\r
5417 /* Get the Height and Width of the parent window */
\r
5418 GetWindowRect (hwndParent, &rParent);
\r
5419 wParent = rParent.right - rParent.left;
\r
5420 hParent = rParent.bottom - rParent.top;
\r
5422 /* Get the display limits */
\r
5423 hdc = GetDC (hwndChild);
\r
5424 wScreen = GetDeviceCaps (hdc, HORZRES);
\r
5425 hScreen = GetDeviceCaps (hdc, VERTRES);
\r
5426 ReleaseDC(hwndChild, hdc);
\r
5428 /* Calculate new X position, then adjust for screen */
\r
5429 xNew = rParent.left + ((wParent - wChild) /2);
\r
5432 } else if ((xNew+wChild) > wScreen) {
\r
5433 xNew = wScreen - wChild;
\r
5436 /* Calculate new Y position, then adjust for screen */
\r
5438 yNew = rParent.top + ((hParent - hChild) /2);
\r
5441 yNew = rParent.top + GetSystemMetrics( SM_CYCAPTION ) * 2 / 3;
\r
5446 } else if ((yNew+hChild) > hScreen) {
\r
5447 yNew = hScreen - hChild;
\r
5450 /* Set it, and return */
\r
5451 return SetWindowPos (hwndChild, NULL,
\r
5452 xNew, yNew, 0, 0, SWP_NOSIZE | SWP_NOZORDER);
\r
5455 /* Center one window over another */
\r
5456 BOOL CenterWindow (HWND hwndChild, HWND hwndParent)
\r
5458 return CenterWindowEx( hwndChild, hwndParent, 0 );
\r
5461 /*---------------------------------------------------------------------------*\
\r
5463 * Startup Dialog functions
\r
5465 \*---------------------------------------------------------------------------*/
\r
5467 InitComboStrings(HANDLE hwndCombo, char **cd)
\r
5469 SendMessage(hwndCombo, CB_RESETCONTENT, 0, 0);
\r
5471 while (*cd != NULL) {
\r
5472 SendMessage(hwndCombo, CB_ADDSTRING, 0, (LPARAM) *cd);
\r
5478 InitComboStringsFromOption(HANDLE hwndCombo, char *str)
\r
5480 char buf1[MAX_ARG_LEN];
\r
5483 if (str[0] == '@') {
\r
5484 FILE* f = fopen(str + 1, "r");
\r
5486 DisplayFatalError(str + 1, errno, 2);
\r
5489 len = fread(buf1, 1, sizeof(buf1)-1, f);
\r
5491 buf1[len] = NULLCHAR;
\r
5495 SendMessage(hwndCombo, CB_RESETCONTENT, 0, 0);
\r
5498 char buf[MSG_SIZ];
\r
5499 char *end = strchr(str, '\n');
\r
5500 if (end == NULL) return;
\r
5501 memcpy(buf, str, end - str);
\r
5502 buf[end - str] = NULLCHAR;
\r
5503 SendMessage(hwndCombo, CB_ADDSTRING, 0, (LPARAM) buf);
\r
5509 SetStartupDialogEnables(HWND hDlg)
\r
5511 EnableWindow(GetDlgItem(hDlg, OPT_ChessEngineName),
\r
5512 IsDlgButtonChecked(hDlg, OPT_ChessEngine) ||
\r
5513 (appData.zippyPlay && IsDlgButtonChecked(hDlg, OPT_ChessServer)));
\r
5514 EnableWindow(GetDlgItem(hDlg, OPT_SecondChessEngineName),
\r
5515 IsDlgButtonChecked(hDlg, OPT_ChessEngine));
\r
5516 EnableWindow(GetDlgItem(hDlg, OPT_ChessServerName),
\r
5517 IsDlgButtonChecked(hDlg, OPT_ChessServer));
\r
5518 EnableWindow(GetDlgItem(hDlg, OPT_AdditionalOptions),
\r
5519 IsDlgButtonChecked(hDlg, OPT_AnyAdditional));
\r
5520 EnableWindow(GetDlgItem(hDlg, IDOK),
\r
5521 IsDlgButtonChecked(hDlg, OPT_ChessEngine) ||
\r
5522 IsDlgButtonChecked(hDlg, OPT_ChessServer) ||
\r
5523 IsDlgButtonChecked(hDlg, OPT_View));
\r
5527 QuoteForFilename(char *filename)
\r
5529 int dquote, space;
\r
5530 dquote = strchr(filename, '"') != NULL;
\r
5531 space = strchr(filename, ' ') != NULL;
\r
5532 if (dquote || space) {
\r
5544 InitEngineBox(HWND hDlg, HWND hwndCombo, char* nthcp, char* nthd, char* nthdir, char *nthnames)
\r
5546 char buf[MSG_SIZ];
\r
5549 InitComboStringsFromOption(hwndCombo, nthnames);
\r
5550 q = QuoteForFilename(nthcp);
\r
5551 sprintf(buf, "%s%s%s", q, nthcp, q);
\r
5552 if (*nthdir != NULLCHAR) {
\r
5553 q = QuoteForFilename(nthdir);
\r
5554 sprintf(buf + strlen(buf), " /%s=%s%s%s", nthd, q, nthdir, q);
\r
5556 if (*nthcp == NULLCHAR) {
\r
5557 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) 0, (LPARAM) 0);
\r
5558 } else if (SendMessage(hwndCombo, CB_SELECTSTRING, (WPARAM) -1, (LPARAM) buf) == CB_ERR) {
\r
5559 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) -1, (LPARAM) 0);
\r
5560 SendMessage(hwndCombo, WM_SETTEXT, (WPARAM) 0, (LPARAM) buf);
\r
5565 StartupDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
5567 char buf[MSG_SIZ];
\r
5571 switch (message) {
\r
5572 case WM_INITDIALOG:
\r
5573 /* Center the dialog */
\r
5574 CenterWindow (hDlg, GetDesktopWindow());
\r
5575 /* Initialize the dialog items */
\r
5576 InitEngineBox(hDlg, GetDlgItem(hDlg, OPT_ChessEngineName),
\r
5577 appData.firstChessProgram, "fd", appData.firstDirectory,
\r
5578 firstChessProgramNames);
\r
5579 InitEngineBox(hDlg, GetDlgItem(hDlg, OPT_SecondChessEngineName),
\r
5580 appData.secondChessProgram, "sd", appData.secondDirectory,
\r
5581 secondChessProgramNames);
\r
5582 hwndCombo = GetDlgItem(hDlg, OPT_ChessServerName);
\r
5583 InitComboStringsFromOption(hwndCombo, icsNames);
\r
5584 sprintf(buf, "%s /icsport=%s", appData.icsHost, appData.icsPort);
\r
5585 if (*appData.icsHelper != NULLCHAR) {
\r
5586 char *q = QuoteForFilename(appData.icsHelper);
\r
5587 sprintf(buf + strlen(buf), " /icshelper=%s%s%s", q, appData.icsHelper, q);
\r
5589 if (*appData.icsHost == NULLCHAR) {
\r
5590 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) 0, (LPARAM) 0);
\r
5591 /*SendMessage(hwndCombo, CB_SHOWDROPDOWN, (WPARAM) TRUE, (LPARAM) 0); !!too soon */
\r
5592 } else if (SendMessage(hwndCombo, CB_SELECTSTRING, (WPARAM) -1, (LPARAM) buf) == CB_ERR) {
\r
5593 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) -1, (LPARAM) 0);
\r
5594 SendMessage(hwndCombo, WM_SETTEXT, (WPARAM) 0, (LPARAM) buf);
\r
5597 if (appData.icsActive) {
\r
5598 CheckDlgButton(hDlg, OPT_ChessServer, BST_CHECKED);
\r
5600 else if (appData.noChessProgram) {
\r
5601 CheckDlgButton(hDlg, OPT_View, BST_CHECKED);
\r
5604 CheckDlgButton(hDlg, OPT_ChessEngine, BST_CHECKED);
\r
5607 SetStartupDialogEnables(hDlg);
\r
5611 switch (LOWORD(wParam)) {
\r
5613 if (IsDlgButtonChecked(hDlg, OPT_ChessEngine)) {
\r
5614 strcpy(buf, "/fcp=");
\r
5615 GetDlgItemText(hDlg, OPT_ChessEngineName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
5617 ParseArgs(StringGet, &p);
\r
5618 strcpy(buf, "/scp=");
\r
5619 GetDlgItemText(hDlg, OPT_SecondChessEngineName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
5621 ParseArgs(StringGet, &p);
\r
5622 appData.noChessProgram = FALSE;
\r
5623 appData.icsActive = FALSE;
\r
5624 } else if (IsDlgButtonChecked(hDlg, OPT_ChessServer)) {
\r
5625 strcpy(buf, "/ics /icshost=");
\r
5626 GetDlgItemText(hDlg, OPT_ChessServerName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
5628 ParseArgs(StringGet, &p);
\r
5629 if (appData.zippyPlay) {
\r
5630 strcpy(buf, "/fcp=");
\r
5631 GetDlgItemText(hDlg, OPT_ChessEngineName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
5633 ParseArgs(StringGet, &p);
\r
5635 } else if (IsDlgButtonChecked(hDlg, OPT_View)) {
\r
5636 appData.noChessProgram = TRUE;
\r
5637 appData.icsActive = FALSE;
\r
5639 MessageBox(hDlg, "Choose an option, or cancel to exit",
\r
5640 "Option Error", MB_OK|MB_ICONEXCLAMATION);
\r
5643 if (IsDlgButtonChecked(hDlg, OPT_AnyAdditional)) {
\r
5644 GetDlgItemText(hDlg, OPT_AdditionalOptions, buf, sizeof(buf));
\r
5646 ParseArgs(StringGet, &p);
\r
5648 EndDialog(hDlg, TRUE);
\r
5655 case IDM_HELPCONTENTS:
\r
5656 if (!WinHelp (hDlg, "winboard.hlp", HELP_KEY,(DWORD)(LPSTR)"CONTENTS")) {
\r
5657 MessageBox (GetFocus(),
\r
5658 "Unable to activate help",
\r
5659 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
5664 SetStartupDialogEnables(hDlg);
\r
5672 /*---------------------------------------------------------------------------*\
\r
5674 * About box dialog functions
\r
5676 \*---------------------------------------------------------------------------*/
\r
5678 /* Process messages for "About" dialog box */
\r
5680 About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
5682 switch (message) {
\r
5683 case WM_INITDIALOG: /* message: initialize dialog box */
\r
5684 /* Center the dialog over the application window */
\r
5685 CenterWindow (hDlg, GetWindow (hDlg, GW_OWNER));
\r
5686 SetDlgItemText(hDlg, ABOUTBOX_Version, programVersion);
\r
5690 case WM_COMMAND: /* message: received a command */
\r
5691 if (LOWORD(wParam) == IDOK /* "OK" box selected? */
\r
5692 || LOWORD(wParam) == IDCANCEL) { /* System menu close command? */
\r
5693 EndDialog(hDlg, TRUE); /* Exit the dialog */
\r
5701 /*---------------------------------------------------------------------------*\
\r
5703 * Comment Dialog functions
\r
5705 \*---------------------------------------------------------------------------*/
\r
5708 CommentDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
5710 static HANDLE hwndText = NULL;
\r
5711 int len, newSizeX, newSizeY, flags;
\r
5712 static int sizeX, sizeY;
\r
5717 switch (message) {
\r
5718 case WM_INITDIALOG: /* message: initialize dialog box */
\r
5719 /* Initialize the dialog items */
\r
5720 hwndText = GetDlgItem(hDlg, OPT_CommentText);
\r
5721 SetDlgItemText(hDlg, OPT_CommentText, commentText);
\r
5722 EnableWindow(GetDlgItem(hDlg, OPT_CancelComment), editComment);
\r
5723 EnableWindow(GetDlgItem(hDlg, OPT_ClearComment), editComment);
\r
5724 EnableWindow(GetDlgItem(hDlg, OPT_EditComment), !editComment);
\r
5725 SendMessage(hwndText, EM_SETREADONLY, !editComment, 0);
\r
5726 SetWindowText(hDlg, commentTitle);
\r
5727 if (editComment) {
\r
5728 SetFocus(hwndText);
\r
5730 SetFocus(GetDlgItem(hDlg, IDOK));
\r
5732 SendMessage(GetDlgItem(hDlg, OPT_CommentText),
\r
5733 WM_SETFONT, (WPARAM)font[boardSize][COMMENT_FONT]->hf,
\r
5734 MAKELPARAM(FALSE, 0));
\r
5735 /* Size and position the dialog */
\r
5736 if (!commentDialog) {
\r
5737 commentDialog = hDlg;
\r
5738 flags = SWP_NOZORDER;
\r
5739 GetClientRect(hDlg, &rect);
\r
5740 sizeX = rect.right;
\r
5741 sizeY = rect.bottom;
\r
5742 if (wpComment.x != CW_USEDEFAULT && wpComment.y != CW_USEDEFAULT &&
\r
5743 wpComment.width != CW_USEDEFAULT && wpComment.height != CW_USEDEFAULT) {
\r
5744 WINDOWPLACEMENT wp;
\r
5745 EnsureOnScreen(&wpComment.x, &wpComment.y, 0, 0);
\r
5746 wp.length = sizeof(WINDOWPLACEMENT);
\r
5748 wp.showCmd = SW_SHOW;
\r
5749 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
5750 wp.rcNormalPosition.left = wpComment.x;
\r
5751 wp.rcNormalPosition.right = wpComment.x + wpComment.width;
\r
5752 wp.rcNormalPosition.top = wpComment.y;
\r
5753 wp.rcNormalPosition.bottom = wpComment.y + wpComment.height;
\r
5754 SetWindowPlacement(hDlg, &wp);
\r
5756 GetClientRect(hDlg, &rect);
\r
5757 newSizeX = rect.right;
\r
5758 newSizeY = rect.bottom;
\r
5759 ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY,
\r
5760 newSizeX, newSizeY);
\r
5767 case WM_COMMAND: /* message: received a command */
\r
5768 switch (LOWORD(wParam)) {
\r
5770 if (editComment) {
\r
5772 /* Read changed options from the dialog box */
\r
5773 hwndText = GetDlgItem(hDlg, OPT_CommentText);
\r
5774 len = GetWindowTextLength(hwndText);
\r
5775 str = (char *) malloc(len + 1);
\r
5776 GetWindowText(hwndText, str, len + 1);
\r
5785 ReplaceComment(commentIndex, str);
\r
5792 case OPT_CancelComment:
\r
5796 case OPT_ClearComment:
\r
5797 SetDlgItemText(hDlg, OPT_CommentText, "");
\r
5800 case OPT_EditComment:
\r
5801 EditCommentEvent();
\r
5810 newSizeX = LOWORD(lParam);
\r
5811 newSizeY = HIWORD(lParam);
\r
5812 ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY, newSizeX, newSizeY);
\r
5817 case WM_GETMINMAXINFO:
\r
5818 /* Prevent resizing window too small */
\r
5819 mmi = (MINMAXINFO *) lParam;
\r
5820 mmi->ptMinTrackSize.x = 100;
\r
5821 mmi->ptMinTrackSize.y = 100;
\r
5828 EitherCommentPopUp(int index, char *title, char *str, BOOLEAN edit)
\r
5833 CheckMenuItem(GetMenu(hwndMain), IDM_EditComment, edit ? MF_CHECKED : MF_UNCHECKED);
\r
5835 if (str == NULL) str = "";
\r
5836 p = (char *) malloc(2 * strlen(str) + 2);
\r
5839 if (*str == '\n') *q++ = '\r';
\r
5843 if (commentText != NULL) free(commentText);
\r
5845 commentIndex = index;
\r
5846 commentTitle = title;
\r
5848 editComment = edit;
\r
5850 if (commentDialog) {
\r
5851 SendMessage(commentDialog, WM_INITDIALOG, 0, 0);
\r
5852 if (!commentUp) ShowWindow(commentDialog, SW_SHOW);
\r
5854 lpProc = MakeProcInstance((FARPROC)CommentDialog, hInst);
\r
5855 CreateDialog(hInst, MAKEINTRESOURCE(DLG_EditComment),
\r
5856 hwndMain, (DLGPROC)lpProc);
\r
5857 FreeProcInstance(lpProc);
\r
5863 /*---------------------------------------------------------------------------*\
\r
5865 * Type-in move dialog functions
\r
5867 \*---------------------------------------------------------------------------*/
\r
5870 TypeInMoveDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
5872 char move[MSG_SIZ];
\r
5874 ChessMove moveType;
\r
5875 int fromX, fromY, toX, toY;
\r
5878 switch (message) {
\r
5879 case WM_INITDIALOG:
\r
5880 move[0] = (char) lParam;
\r
5881 move[1] = NULLCHAR;
\r
5882 CenterWindowEx(hDlg, GetWindow(hDlg, GW_OWNER), 1 );
\r
5883 hInput = GetDlgItem(hDlg, OPT_Move);
\r
5884 SetWindowText(hInput, move);
\r
5886 SendMessage(hInput, EM_SETSEL, (WPARAM)9999, (LPARAM)9999);
\r
5890 switch (LOWORD(wParam)) {
\r
5892 GetDlgItemText(hDlg, OPT_Move, move, sizeof(move));
\r
5893 { int n; Board board;
\r
5895 if(gameMode == EditPosition && ParseFEN(board, &n, move) ) {
\r
5896 EditPositionPasteFEN(move);
\r
5897 EndDialog(hDlg, TRUE);
\r
5900 // [HGM] movenum: allow move number to be typed in any mode
\r
5901 if(sscanf(move, "%d", &n) == 1 && n != 0 ) {
\r
5903 EndDialog(hDlg, TRUE);
\r
5907 if (gameMode != EditGame && currentMove != forwardMostMove &&
\r
5908 gameMode != Training) {
\r
5909 DisplayMoveError("Displayed move is not current");
\r
5911 // GetDlgItemText(hDlg, OPT_Move, move, sizeof(move)); // moved upstream
\r
5912 int ok = ParseOneMove(move, gameMode == EditPosition ? blackPlaysFirst : currentMove,
\r
5913 &moveType, &fromX, &fromY, &toX, &toY, &promoChar);
\r
5914 if(!ok && move[0] >= 'a') { move[0] += 'A' - 'a'; ok = 2; } // [HGM] try also capitalized
\r
5915 if (ok==1 || ok && ParseOneMove(move, gameMode == EditPosition ? blackPlaysFirst : currentMove,
\r
5916 &moveType, &fromX, &fromY, &toX, &toY, &promoChar)) {
\r
5917 if (gameMode != Training)
\r
5918 forwardMostMove = currentMove;
\r
5919 UserMoveEvent(fromX, fromY, toX, toY, promoChar);
\r
5921 DisplayMoveError("Could not parse move");
\r
5924 EndDialog(hDlg, TRUE);
\r
5927 EndDialog(hDlg, FALSE);
\r
5938 PopUpMoveDialog(char firstchar)
\r
5942 if ((gameMode == BeginningOfGame && !appData.icsActive) ||
\r
5943 gameMode == MachinePlaysWhite || gameMode == MachinePlaysBlack ||
\r
5944 gameMode == AnalyzeMode || gameMode == EditGame ||
\r
5945 gameMode == EditPosition || gameMode == IcsExamining ||
\r
5946 gameMode == IcsPlayingWhite || gameMode == IcsPlayingBlack ||
\r
5947 isdigit(firstchar) && // [HGM] movenum: allow typing in of move nr in 'passive' modes
\r
5948 ( gameMode == AnalyzeFile || gameMode == PlayFromGameFile ||
\r
5949 gameMode == IcsObserving || gameMode == TwoMachinesPlay ) ||
\r
5950 gameMode == Training) {
\r
5951 lpProc = MakeProcInstance((FARPROC)TypeInMoveDialog, hInst);
\r
5952 DialogBoxParam(hInst, MAKEINTRESOURCE(DLG_TypeInMove),
\r
5953 hwndMain, (DLGPROC)lpProc, (LPARAM)firstchar);
\r
5954 FreeProcInstance(lpProc);
\r
5958 /*---------------------------------------------------------------------------*\
\r
5960 * Type-in name dialog functions
\r
5962 \*---------------------------------------------------------------------------*/
\r
5965 TypeInNameDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
5967 char move[MSG_SIZ];
\r
5970 switch (message) {
\r
5971 case WM_INITDIALOG:
\r
5972 move[0] = (char) lParam;
\r
5973 move[1] = NULLCHAR;
\r
5974 CenterWindowEx(hDlg, GetWindow(hDlg, GW_OWNER), 1 );
\r
5975 hInput = GetDlgItem(hDlg, OPT_Name);
\r
5976 SetWindowText(hInput, move);
\r
5978 SendMessage(hInput, EM_SETSEL, (WPARAM)9999, (LPARAM)9999);
\r
5982 switch (LOWORD(wParam)) {
\r
5984 GetDlgItemText(hDlg, OPT_Name, move, sizeof(move));
\r
5985 appData.userName = strdup(move);
\r
5988 EndDialog(hDlg, TRUE);
\r
5991 EndDialog(hDlg, FALSE);
\r
6002 PopUpNameDialog(char firstchar)
\r
6006 lpProc = MakeProcInstance((FARPROC)TypeInNameDialog, hInst);
\r
6007 DialogBoxParam(hInst, MAKEINTRESOURCE(DLG_TypeInName),
\r
6008 hwndMain, (DLGPROC)lpProc, (LPARAM)firstchar);
\r
6009 FreeProcInstance(lpProc);
\r
6012 /*---------------------------------------------------------------------------*\
\r
6016 \*---------------------------------------------------------------------------*/
\r
6018 /* Nonmodal error box */
\r
6019 LRESULT CALLBACK ErrorDialog(HWND hDlg, UINT message,
\r
6020 WPARAM wParam, LPARAM lParam);
\r
6023 ErrorPopUp(char *title, char *content)
\r
6027 BOOLEAN modal = hwndMain == NULL;
\r
6045 strncpy(errorTitle, title, sizeof(errorTitle));
\r
6046 errorTitle[sizeof(errorTitle) - 1] = '\0';
\r
6049 MessageBox(NULL, errorMessage, errorTitle, MB_OK|MB_ICONEXCLAMATION);
\r
6051 lpProc = MakeProcInstance((FARPROC)ErrorDialog, hInst);
\r
6052 CreateDialog(hInst, MAKEINTRESOURCE(DLG_Error),
\r
6053 hwndMain, (DLGPROC)lpProc);
\r
6054 FreeProcInstance(lpProc);
\r
6061 if (!appData.popupMoveErrors && moveErrorMessageUp) DisplayMessage("", "");
\r
6062 if (errorDialog == NULL) return;
\r
6063 DestroyWindow(errorDialog);
\r
6064 errorDialog = NULL;
\r
6068 ErrorDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
6073 switch (message) {
\r
6074 case WM_INITDIALOG:
\r
6075 GetWindowRect(hDlg, &rChild);
\r
6078 SetWindowPos(hDlg, NULL, rChild.left,
\r
6079 rChild.top + boardRect.top - (rChild.bottom - rChild.top),
\r
6080 0, 0, SWP_NOZORDER|SWP_NOSIZE);
\r
6084 [AS] It seems that the above code wants to move the dialog up in the "caption
\r
6085 area" of the main window, but it uses the dialog height as an hard-coded constant,
\r
6086 and it doesn't work when you resize the dialog.
\r
6087 For now, just give it a default position.
\r
6089 SetWindowPos(hDlg, NULL, boardRect.left+8, boardRect.top+8, 0, 0, SWP_NOZORDER|SWP_NOSIZE);
\r
6091 errorDialog = hDlg;
\r
6092 SetWindowText(hDlg, errorTitle);
\r
6093 hwndText = GetDlgItem(hDlg, OPT_ErrorText);
\r
6094 SetDlgItemText(hDlg, OPT_ErrorText, errorMessage);
\r
6098 switch (LOWORD(wParam)) {
\r
6101 if (errorDialog == hDlg) errorDialog = NULL;
\r
6102 DestroyWindow(hDlg);
\r
6114 HWND gothicDialog = NULL;
\r
6117 GothicDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
6121 int height = GetSystemMetrics(SM_CYCAPTION)+GetSystemMetrics(SM_CYFRAME);
\r
6123 switch (message) {
\r
6124 case WM_INITDIALOG:
\r
6125 GetWindowRect(hDlg, &rChild);
\r
6127 SetWindowPos(hDlg, NULL, wpMain.x, wpMain.y-height, wpMain.width, height,
\r
6131 [AS] It seems that the above code wants to move the dialog up in the "caption
\r
6132 area" of the main window, but it uses the dialog height as an hard-coded constant,
\r
6133 and it doesn't work when you resize the dialog.
\r
6134 For now, just give it a default position.
\r
6136 gothicDialog = hDlg;
\r
6137 SetWindowText(hDlg, errorTitle);
\r
6138 hwndText = GetDlgItem(hDlg, OPT_ErrorText);
\r
6139 SetDlgItemText(hDlg, OPT_ErrorText, errorMessage);
\r
6143 switch (LOWORD(wParam)) {
\r
6146 if (errorDialog == hDlg) errorDialog = NULL;
\r
6147 DestroyWindow(hDlg);
\r
6159 GothicPopUp(char *title, VariantClass variant)
\r
6162 static char *lastTitle;
\r
6164 strncpy(errorTitle, title, sizeof(errorTitle));
\r
6165 errorTitle[sizeof(errorTitle) - 1] = '\0';
\r
6167 if(lastTitle != title && gothicDialog != NULL) {
\r
6168 DestroyWindow(gothicDialog);
\r
6169 gothicDialog = NULL;
\r
6171 if(variant != VariantNormal && gothicDialog == NULL) {
\r
6172 title = lastTitle;
\r
6173 lpProc = MakeProcInstance((FARPROC)GothicDialog, hInst);
\r
6174 CreateDialog(hInst, MAKEINTRESOURCE(DLG_Error),
\r
6175 hwndMain, (DLGPROC)lpProc);
\r
6176 FreeProcInstance(lpProc);
\r
6181 /*---------------------------------------------------------------------------*\
\r
6183 * Ics Interaction console functions
\r
6185 \*---------------------------------------------------------------------------*/
\r
6187 #define HISTORY_SIZE 64
\r
6188 static char *history[HISTORY_SIZE];
\r
6189 int histIn = 0, histP = 0;
\r
6192 SaveInHistory(char *cmd)
\r
6194 if (history[histIn] != NULL) {
\r
6195 free(history[histIn]);
\r
6196 history[histIn] = NULL;
\r
6198 if (*cmd == NULLCHAR) return;
\r
6199 history[histIn] = StrSave(cmd);
\r
6200 histIn = (histIn + 1) % HISTORY_SIZE;
\r
6201 if (history[histIn] != NULL) {
\r
6202 free(history[histIn]);
\r
6203 history[histIn] = NULL;
\r
6209 PrevInHistory(char *cmd)
\r
6212 if (histP == histIn) {
\r
6213 if (history[histIn] != NULL) free(history[histIn]);
\r
6214 history[histIn] = StrSave(cmd);
\r
6216 newhp = (histP - 1 + HISTORY_SIZE) % HISTORY_SIZE;
\r
6217 if (newhp == histIn || history[newhp] == NULL) return NULL;
\r
6219 return history[histP];
\r
6225 if (histP == histIn) return NULL;
\r
6226 histP = (histP + 1) % HISTORY_SIZE;
\r
6227 return history[histP];
\r
6231 LoadIcsTextMenu(IcsTextMenuEntry *e)
\r
6235 hmenu = LoadMenu(hInst, "TextMenu");
\r
6236 h = GetSubMenu(hmenu, 0);
\r
6238 if (strcmp(e->item, "-") == 0) {
\r
6239 AppendMenu(h, MF_SEPARATOR, 0, 0);
\r
6241 if (e->item[0] == '|') {
\r
6242 AppendMenu(h, MF_STRING|MF_MENUBARBREAK,
\r
6243 IDM_CommandX + i, &e->item[1]);
\r
6245 AppendMenu(h, MF_STRING, IDM_CommandX + i, e->item);
\r
6254 WNDPROC consoleTextWindowProc;
\r
6257 CommandX(HWND hwnd, char *command, BOOLEAN getname, BOOLEAN immediate)
\r
6259 char buf[MSG_SIZ], name[MSG_SIZ];
\r
6260 HWND hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
6264 SetWindowText(hInput, command);
\r
6266 SendMessage(hInput, WM_CHAR, '\r', 0);
\r
6268 sel.cpMin = 999999;
\r
6269 sel.cpMax = 999999;
\r
6270 SendMessage(hInput, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
6275 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
6276 if (sel.cpMin == sel.cpMax) {
\r
6277 /* Expand to surrounding word */
\r
6280 tr.chrg.cpMax = sel.cpMin;
\r
6281 tr.chrg.cpMin = --sel.cpMin;
\r
6282 if (sel.cpMin < 0) break;
\r
6283 tr.lpstrText = name;
\r
6284 SendMessage(hwnd, EM_GETTEXTRANGE, 0, (LPARAM) &tr);
\r
6285 } while (isalpha(name[0]) || isdigit(name[0]) || name[0] == '-');
\r
6289 tr.chrg.cpMin = sel.cpMax;
\r
6290 tr.chrg.cpMax = ++sel.cpMax;
\r
6291 tr.lpstrText = name;
\r
6292 if (SendMessage(hwnd, EM_GETTEXTRANGE, 0, (LPARAM) &tr) < 1) break;
\r
6293 } while (isalpha(name[0]) || isdigit(name[0]) || name[0] == '-');
\r
6296 if (sel.cpMax == sel.cpMin || sel.cpMax - sel.cpMin > MSG_SIZ/2) {
\r
6297 MessageBeep(MB_ICONEXCLAMATION);
\r
6301 tr.lpstrText = name;
\r
6302 SendMessage(hwnd, EM_GETTEXTRANGE, 0, (LPARAM) &tr);
\r
6304 if (sel.cpMax - sel.cpMin > MSG_SIZ/2) {
\r
6305 MessageBeep(MB_ICONEXCLAMATION);
\r
6308 SendMessage(hwnd, EM_GETSELTEXT, 0, (LPARAM) name);
\r
6311 sprintf(buf, "%s %s", command, name);
\r
6312 SetWindowText(hInput, buf);
\r
6313 SendMessage(hInput, WM_CHAR, '\r', 0);
\r
6315 sprintf(buf, "%s %s ", command, name); /* trailing space */
\r
6316 SetWindowText(hInput, buf);
\r
6317 sel.cpMin = 999999;
\r
6318 sel.cpMax = 999999;
\r
6319 SendMessage(hInput, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
6325 ConsoleTextSubclass(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
6330 switch (message) {
\r
6332 if (!(GetKeyState(VK_CONTROL) & ~1)) break;
\r
6335 SendMessage(hwnd, EM_LINESCROLL, 0, -999999);
\r
6338 sel.cpMin = 999999;
\r
6339 sel.cpMax = 999999;
\r
6340 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
6341 SendMessage(hwnd, EM_SCROLLCARET, 0, 0);
\r
6346 if(wParam != '\022') {
\r
6347 if (wParam == '\t') {
\r
6348 if (GetKeyState(VK_SHIFT) < 0) {
\r
6350 if (IsIconic(hwndMain)) ShowWindow(hwndMain, SW_RESTORE);
\r
6351 if (buttonDesc[0].hwnd) {
\r
6352 SetFocus(buttonDesc[0].hwnd);
\r
6354 SetFocus(hwndMain);
\r
6358 SetFocus(GetDlgItem(hwndConsole, OPT_ConsoleInput));
\r
6361 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
6362 JAWS_DELETE( SetFocus(hInput); )
\r
6363 SendMessage(hInput, message, wParam, lParam);
\r
6366 } // [HGM] navigate: for Ctrl+R, flow into nex case (moved up here) to summon up menu
\r
6367 case WM_RBUTTONUP:
\r
6368 if (GetKeyState(VK_SHIFT) & ~1) {
\r
6369 SendDlgItemMessage(hwndConsole, OPT_ConsoleText,
\r
6370 WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
6373 HMENU hmenu = LoadIcsTextMenu(icsTextMenuEntry);
\r
6374 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
6375 if (sel.cpMin == sel.cpMax) {
\r
6376 EnableMenuItem(hmenu, IDM_Copy, MF_BYCOMMAND|MF_GRAYED);
\r
6377 EnableMenuItem(hmenu, IDM_QuickPaste, MF_BYCOMMAND|MF_GRAYED);
\r
6379 if (!IsClipboardFormatAvailable(CF_TEXT)) {
\r
6380 EnableMenuItem(hmenu, IDM_Paste, MF_BYCOMMAND|MF_GRAYED);
\r
6382 pt.x = LOWORD(lParam);
\r
6383 pt.y = HIWORD(lParam);
\r
6384 MenuPopup(hwnd, pt, hmenu, -1);
\r
6388 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
6390 return SendMessage(hInput, message, wParam, lParam);
\r
6391 case WM_MBUTTONDOWN:
\r
6392 return SendMessage(hwnd, WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
6393 case WM_RBUTTONDOWN:
\r
6394 if (!(GetKeyState(VK_SHIFT) & ~1)) {
\r
6395 /* Move selection here if it was empty */
\r
6397 pt.x = LOWORD(lParam);
\r
6398 pt.y = HIWORD(lParam);
\r
6399 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
6400 if (sel.cpMin == sel.cpMax) {
\r
6401 sel.cpMin = SendMessage(hwnd, EM_CHARFROMPOS, 0, (LPARAM)&pt); /*doc is wrong*/
\r
6402 sel.cpMax = sel.cpMin;
\r
6403 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
6405 SendMessage(hwnd, EM_HIDESELECTION, FALSE, FALSE);
\r
6409 switch (LOWORD(wParam)) {
\r
6410 case IDM_QuickPaste:
\r
6412 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
6413 if (sel.cpMin == sel.cpMax) {
\r
6414 MessageBeep(MB_ICONEXCLAMATION);
\r
6417 SendMessage(hwnd, WM_COPY, 0, 0);
\r
6418 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
6419 SendMessage(hInput, WM_PASTE, 0, 0);
\r
6424 SendMessage(hwnd, WM_CUT, 0, 0);
\r
6427 SendMessage(hwnd, WM_PASTE, 0, 0);
\r
6430 SendMessage(hwnd, WM_COPY, 0, 0);
\r
6434 int i = LOWORD(wParam) - IDM_CommandX;
\r
6435 if (i >= 0 && i < ICS_TEXT_MENU_SIZE &&
\r
6436 icsTextMenuEntry[i].command != NULL) {
\r
6437 CommandX(hwnd, icsTextMenuEntry[i].command,
\r
6438 icsTextMenuEntry[i].getname,
\r
6439 icsTextMenuEntry[i].immediate);
\r
6447 return (*consoleTextWindowProc)(hwnd, message, wParam, lParam);
\r
6450 WNDPROC consoleInputWindowProc;
\r
6453 ConsoleInputSubclass(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
6455 char buf[MSG_SIZ];
\r
6457 static BOOL sendNextChar = FALSE;
\r
6458 static BOOL quoteNextChar = FALSE;
\r
6459 InputSource *is = consoleInputSource;
\r
6463 switch (message) {
\r
6465 if (!appData.localLineEditing || sendNextChar) {
\r
6466 is->buf[0] = (CHAR) wParam;
\r
6468 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
6469 sendNextChar = FALSE;
\r
6472 if (quoteNextChar) {
\r
6473 buf[0] = (char) wParam;
\r
6474 buf[1] = NULLCHAR;
\r
6475 SendMessage(hwnd, EM_REPLACESEL, TRUE, (LPARAM) buf);
\r
6476 quoteNextChar = FALSE;
\r
6480 case '\r': /* Enter key */
\r
6481 is->count = GetWindowText(hwnd, is->buf, INPUT_SOURCE_BUF_SIZE-1);
\r
6482 if (consoleEcho) SaveInHistory(is->buf);
\r
6483 is->buf[is->count++] = '\n';
\r
6484 is->buf[is->count] = NULLCHAR;
\r
6485 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
6486 if (consoleEcho) {
\r
6487 ConsoleOutput(is->buf, is->count, TRUE);
\r
6488 } else if (appData.localLineEditing) {
\r
6489 ConsoleOutput("\n", 1, TRUE);
\r
6492 case '\033': /* Escape key */
\r
6493 SetWindowText(hwnd, "");
\r
6494 cf.cbSize = sizeof(CHARFORMAT);
\r
6495 cf.dwMask = CFM_COLOR|CFM_BOLD|CFM_ITALIC|CFM_UNDERLINE|CFM_STRIKEOUT;
\r
6496 if (consoleEcho) {
\r
6497 cf.crTextColor = textAttribs[ColorNormal].color;
\r
6499 cf.crTextColor = COLOR_ECHOOFF;
\r
6501 cf.dwEffects = textAttribs[ColorNormal].effects;
\r
6502 SendMessage(hwnd, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&cf);
\r
6504 case '\t': /* Tab key */
\r
6505 if (GetKeyState(VK_SHIFT) < 0) {
\r
6507 SetFocus(GetDlgItem(hwndConsole, OPT_ConsoleText));
\r
6510 if (IsIconic(hwndMain)) ShowWindow(hwndMain, SW_RESTORE);
\r
6511 if (buttonDesc[0].hwnd) {
\r
6512 SetFocus(buttonDesc[0].hwnd);
\r
6514 SetFocus(hwndMain);
\r
6518 case '\023': /* Ctrl+S */
\r
6519 sendNextChar = TRUE;
\r
6521 case '\021': /* Ctrl+Q */
\r
6522 quoteNextChar = TRUE;
\r
6532 GetWindowText(hwnd, buf, MSG_SIZ);
\r
6533 p = PrevInHistory(buf);
\r
6535 SetWindowText(hwnd, p);
\r
6536 sel.cpMin = 999999;
\r
6537 sel.cpMax = 999999;
\r
6538 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
6543 p = NextInHistory();
\r
6545 SetWindowText(hwnd, p);
\r
6546 sel.cpMin = 999999;
\r
6547 sel.cpMax = 999999;
\r
6548 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
6554 if (!(GetKeyState(VK_CONTROL) & ~1)) break;
\r
6558 SendDlgItemMessage(hwndConsole, OPT_ConsoleText, message, wParam, lParam);
\r
6562 case WM_MBUTTONDOWN:
\r
6563 SendDlgItemMessage(hwndConsole, OPT_ConsoleText,
\r
6564 WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
6566 case WM_RBUTTONUP:
\r
6567 if (GetKeyState(VK_SHIFT) & ~1) {
\r
6568 SendDlgItemMessage(hwndConsole, OPT_ConsoleText,
\r
6569 WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
6573 hmenu = LoadMenu(hInst, "InputMenu");
\r
6574 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
6575 if (sel.cpMin == sel.cpMax) {
\r
6576 EnableMenuItem(hmenu, IDM_Copy, MF_BYCOMMAND|MF_GRAYED);
\r
6577 EnableMenuItem(hmenu, IDM_Cut, MF_BYCOMMAND|MF_GRAYED);
\r
6579 if (!IsClipboardFormatAvailable(CF_TEXT)) {
\r
6580 EnableMenuItem(hmenu, IDM_Paste, MF_BYCOMMAND|MF_GRAYED);
\r
6582 pt.x = LOWORD(lParam);
\r
6583 pt.y = HIWORD(lParam);
\r
6584 MenuPopup(hwnd, pt, hmenu, -1);
\r
6588 switch (LOWORD(wParam)) {
\r
6590 SendMessage(hwnd, EM_UNDO, 0, 0);
\r
6592 case IDM_SelectAll:
\r
6594 sel.cpMax = -1; /*999999?*/
\r
6595 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
6598 SendMessage(hwnd, WM_CUT, 0, 0);
\r
6601 SendMessage(hwnd, WM_PASTE, 0, 0);
\r
6604 SendMessage(hwnd, WM_COPY, 0, 0);
\r
6609 return (*consoleInputWindowProc)(hwnd, message, wParam, lParam);
\r
6612 #define CO_MAX 100000
\r
6613 #define CO_TRIM 1000
\r
6616 ConsoleWndProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
6618 static SnapData sd;
\r
6619 HWND hText, hInput;
\r
6621 static int sizeX, sizeY;
\r
6622 int newSizeX, newSizeY;
\r
6626 hText = GetDlgItem(hDlg, OPT_ConsoleText);
\r
6627 hInput = GetDlgItem(hDlg, OPT_ConsoleInput);
\r
6629 switch (message) {
\r
6631 if (((NMHDR*)lParam)->code == EN_LINK)
\r
6633 ENLINK *pLink = (ENLINK*)lParam;
\r
6634 if (pLink->msg == WM_LBUTTONUP)
\r
6638 tr.chrg = pLink->chrg;
\r
6639 tr.lpstrText = malloc(1+tr.chrg.cpMax-tr.chrg.cpMin);
\r
6640 SendMessage(hText, EM_GETTEXTRANGE, 0, (LPARAM)&tr);
\r
6641 ShellExecute(NULL, "open", tr.lpstrText, NULL, NULL, SW_SHOW);
\r
6642 free(tr.lpstrText);
\r
6646 case WM_INITDIALOG: /* message: initialize dialog box */
\r
6647 hwndConsole = hDlg;
\r
6649 consoleTextWindowProc = (WNDPROC)
\r
6650 SetWindowLong(hText, GWL_WNDPROC, (LONG) ConsoleTextSubclass);
\r
6651 SendMessage(hText, EM_SETBKGNDCOLOR, FALSE, consoleBackgroundColor);
\r
6652 consoleInputWindowProc = (WNDPROC)
\r
6653 SetWindowLong(hInput, GWL_WNDPROC, (LONG) ConsoleInputSubclass);
\r
6654 SendMessage(hInput, EM_SETBKGNDCOLOR, FALSE, consoleBackgroundColor);
\r
6655 Colorize(ColorNormal, TRUE);
\r
6656 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM) &consoleCF);
\r
6657 ChangedConsoleFont();
\r
6658 GetClientRect(hDlg, &rect);
\r
6659 sizeX = rect.right;
\r
6660 sizeY = rect.bottom;
\r
6661 if (wpConsole.x != CW_USEDEFAULT && wpConsole.y != CW_USEDEFAULT &&
\r
6662 wpConsole.width != CW_USEDEFAULT && wpConsole.height != CW_USEDEFAULT) {
\r
6663 WINDOWPLACEMENT wp;
\r
6664 EnsureOnScreen(&wpConsole.x, &wpConsole.y, 0, 0);
\r
6665 wp.length = sizeof(WINDOWPLACEMENT);
\r
6667 wp.showCmd = SW_SHOW;
\r
6668 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
6669 wp.rcNormalPosition.left = wpConsole.x;
\r
6670 wp.rcNormalPosition.right = wpConsole.x + wpConsole.width;
\r
6671 wp.rcNormalPosition.top = wpConsole.y;
\r
6672 wp.rcNormalPosition.bottom = wpConsole.y + wpConsole.height;
\r
6673 SetWindowPlacement(hDlg, &wp);
\r
6676 // [HGM] Chessknight's change 2004-07-13
\r
6677 else { /* Determine Defaults */
\r
6678 WINDOWPLACEMENT wp;
\r
6679 wpConsole.x = wpMain.width + 1;
\r
6680 wpConsole.y = wpMain.y;
\r
6681 wpConsole.width = screenWidth - wpMain.width;
\r
6682 wpConsole.height = wpMain.height;
\r
6683 EnsureOnScreen(&wpConsole.x, &wpConsole.y, 0, 0);
\r
6684 wp.length = sizeof(WINDOWPLACEMENT);
\r
6686 wp.showCmd = SW_SHOW;
\r
6687 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
6688 wp.rcNormalPosition.left = wpConsole.x;
\r
6689 wp.rcNormalPosition.right = wpConsole.x + wpConsole.width;
\r
6690 wp.rcNormalPosition.top = wpConsole.y;
\r
6691 wp.rcNormalPosition.bottom = wpConsole.y + wpConsole.height;
\r
6692 SetWindowPlacement(hDlg, &wp);
\r
6695 // Allow hText to highlight URLs and send notifications on them
\r
6696 wMask = (WORD) SendMessage(hText, EM_GETEVENTMASK, 0, 0L);
\r
6697 SendMessage(hText, EM_SETEVENTMASK, 0, wMask | ENM_LINK);
\r
6698 SendMessage(hText, EM_AUTOURLDETECT, TRUE, 0L);
\r
6699 SetWindowLong(hText, GWL_USERDATA, 79); // initialize the text window's width
\r
6713 if (IsIconic(hDlg)) break;
\r
6714 newSizeX = LOWORD(lParam);
\r
6715 newSizeY = HIWORD(lParam);
\r
6716 if (sizeX != newSizeX || sizeY != newSizeY) {
\r
6717 RECT rectText, rectInput;
\r
6719 int newTextHeight, newTextWidth;
\r
6720 GetWindowRect(hText, &rectText);
\r
6721 newTextWidth = rectText.right - rectText.left + newSizeX - sizeX;
\r
6722 newTextHeight = rectText.bottom - rectText.top + newSizeY - sizeY;
\r
6723 if (newTextHeight < 0) {
\r
6724 newSizeY += -newTextHeight;
\r
6725 newTextHeight = 0;
\r
6727 SetWindowPos(hText, NULL, 0, 0,
\r
6728 newTextWidth, newTextHeight, SWP_NOZORDER|SWP_NOMOVE);
\r
6729 GetWindowRect(hInput, &rectInput); /* gives screen coords */
\r
6730 pt.x = rectInput.left;
\r
6731 pt.y = rectInput.top + newSizeY - sizeY;
\r
6732 ScreenToClient(hDlg, &pt);
\r
6733 SetWindowPos(hInput, NULL,
\r
6734 pt.x, pt.y, /* needs client coords */
\r
6735 rectInput.right - rectInput.left + newSizeX - sizeX,
\r
6736 rectInput.bottom - rectInput.top, SWP_NOZORDER);
\r
6742 case WM_GETMINMAXINFO:
\r
6743 /* Prevent resizing window too small */
\r
6744 mmi = (MINMAXINFO *) lParam;
\r
6745 mmi->ptMinTrackSize.x = 100;
\r
6746 mmi->ptMinTrackSize.y = 100;
\r
6749 /* [AS] Snapping */
\r
6750 case WM_ENTERSIZEMOVE:
\r
6751 return OnEnterSizeMove( &sd, hDlg, wParam, lParam );
\r
6754 return OnSizing( &sd, hDlg, wParam, lParam );
\r
6757 return OnMoving( &sd, hDlg, wParam, lParam );
\r
6759 case WM_EXITSIZEMOVE:
\r
6760 UpdateICSWidth(hText);
\r
6761 return OnExitSizeMove( &sd, hDlg, wParam, lParam );
\r
6764 return DefWindowProc(hDlg, message, wParam, lParam);
\r
6772 if (hwndConsole) return;
\r
6773 hCons = CreateDialog(hInst, szConsoleName, 0, NULL);
\r
6774 SendMessage(hCons, WM_INITDIALOG, 0, 0);
\r
6779 ConsoleOutput(char* data, int length, int forceVisible)
\r
6784 char buf[CO_MAX+1];
\r
6787 static int delayLF = 0;
\r
6788 CHARRANGE savesel, sel;
\r
6790 if (hwndConsole == NULL || length > CO_MAX-100 || length == 0) return;
\r
6798 while (length--) {
\r
6806 } else if (*p == '\007') {
\r
6807 MyPlaySound(&sounds[(int)SoundBell]);
\r
6814 hText = GetDlgItem(hwndConsole, OPT_ConsoleText);
\r
6815 SendMessage(hText, EM_HIDESELECTION, TRUE, FALSE);
\r
6816 /* Save current selection */
\r
6817 SendMessage(hText, EM_EXGETSEL, 0, (LPARAM)&savesel);
\r
6818 exlen = GetWindowTextLength(hText);
\r
6819 /* Find out whether current end of text is visible */
\r
6820 SendMessage(hText, EM_GETRECT, 0, (LPARAM) &rect);
\r
6821 SendMessage(hText, EM_POSFROMCHAR, (WPARAM) &pEnd, exlen);
\r
6822 /* Trim existing text if it's too long */
\r
6823 if (exlen + (q - buf) > CO_MAX) {
\r
6824 trim = (CO_TRIM > (q - buf)) ? CO_TRIM : (q - buf);
\r
6827 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
6828 SendMessage(hText, EM_REPLACESEL, 0, (LPARAM)"");
\r
6830 savesel.cpMin -= trim;
\r
6831 savesel.cpMax -= trim;
\r
6832 if (exlen < 0) exlen = 0;
\r
6833 if (savesel.cpMin < 0) savesel.cpMin = 0;
\r
6834 if (savesel.cpMax < savesel.cpMin) savesel.cpMax = savesel.cpMin;
\r
6836 /* Append the new text */
\r
6837 sel.cpMin = exlen;
\r
6838 sel.cpMax = exlen;
\r
6839 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
6840 SendMessage(hText, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&consoleCF);
\r
6841 SendMessage(hText, EM_REPLACESEL, 0, (LPARAM) buf);
\r
6842 if (forceVisible || exlen == 0 ||
\r
6843 (rect.left <= pEnd.x && pEnd.x < rect.right &&
\r
6844 rect.top <= pEnd.y && pEnd.y < rect.bottom)) {
\r
6845 /* Scroll to make new end of text visible if old end of text
\r
6846 was visible or new text is an echo of user typein */
\r
6847 sel.cpMin = 9999999;
\r
6848 sel.cpMax = 9999999;
\r
6849 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
6850 SendMessage(hText, EM_HIDESELECTION, FALSE, FALSE);
\r
6851 SendMessage(hText, EM_SCROLLCARET, 0, 0);
\r
6852 SendMessage(hText, EM_HIDESELECTION, TRUE, FALSE);
\r
6854 if (savesel.cpMax == exlen || forceVisible) {
\r
6855 /* Move insert point to new end of text if it was at the old
\r
6856 end of text or if the new text is an echo of user typein */
\r
6857 sel.cpMin = 9999999;
\r
6858 sel.cpMax = 9999999;
\r
6859 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
6861 /* Restore previous selection */
\r
6862 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&savesel);
\r
6864 SendMessage(hText, EM_HIDESELECTION, FALSE, FALSE);
\r
6871 DisplayHoldingsCount(HDC hdc, int x, int y, int rightAlign, int copyNumber)
\r
6875 COLORREF oldFg, oldBg;
\r
6879 if(copyNumber > 1) sprintf(buf, "%d", copyNumber); else buf[0] = 0;
\r
6881 oldFg = SetTextColor(hdc, RGB(255, 255, 255)); /* white */
\r
6882 oldBg = SetBkColor(hdc, RGB(0, 0, 0)); /* black */
\r
6883 oldFont = SelectObject(hdc, font[boardSize][CLOCK_FONT]->hf);
\r
6886 rect.right = x + squareSize;
\r
6888 rect.bottom = y + squareSize;
\r
6891 ExtTextOut(hdc, x + MESSAGE_LINE_LEFTMARGIN
\r
6892 + (rightAlign ? (squareSize*2)/3 : 0),
\r
6893 y, ETO_CLIPPED|ETO_OPAQUE,
\r
6894 &rect, str, strlen(str), NULL);
\r
6896 (void) SetTextColor(hdc, oldFg);
\r
6897 (void) SetBkColor(hdc, oldBg);
\r
6898 (void) SelectObject(hdc, oldFont);
\r
6902 DisplayAClock(HDC hdc, int timeRemaining, int highlight,
\r
6903 RECT *rect, char *color, char *flagFell)
\r
6907 COLORREF oldFg, oldBg;
\r
6910 if (appData.clockMode) {
\r
6912 sprintf(buf, "%c %s %s", color[0], TimeString(timeRemaining), flagFell);
\r
6914 sprintf(buf, "%s:%c%s %s", color, (logoHeight>0 ? 0 : ' '), TimeString(timeRemaining), flagFell);
\r
6921 oldFg = SetTextColor(hdc, RGB(255, 255, 255)); /* white */
\r
6922 oldBg = SetBkColor(hdc, RGB(0, 0, 0)); /* black */
\r
6924 oldFg = SetTextColor(hdc, RGB(0, 0, 0)); /* black */
\r
6925 oldBg = SetBkColor(hdc, RGB(255, 255, 255)); /* white */
\r
6927 oldFont = SelectObject(hdc, font[boardSize][CLOCK_FONT]->hf);
\r
6931 ExtTextOut(hdc, rect->left + MESSAGE_LINE_LEFTMARGIN,
\r
6932 rect->top, ETO_CLIPPED|ETO_OPAQUE,
\r
6933 rect, str, strlen(str), NULL);
\r
6934 if(logoHeight > 0 && appData.clockMode) {
\r
6936 sprintf(buf, "%s %s", buf+7, flagFell);
\r
6937 r.top = rect->top + logoHeight/2;
\r
6938 r.left = rect->left;
\r
6939 r.right = rect->right;
\r
6940 r.bottom = rect->bottom;
\r
6941 ExtTextOut(hdc, rect->left + MESSAGE_LINE_LEFTMARGIN,
\r
6942 r.top, ETO_CLIPPED|ETO_OPAQUE,
\r
6943 &r, str, strlen(str), NULL);
\r
6945 (void) SetTextColor(hdc, oldFg);
\r
6946 (void) SetBkColor(hdc, oldBg);
\r
6947 (void) SelectObject(hdc, oldFont);
\r
6952 DoReadFile(HANDLE hFile, char *buf, int count, DWORD *outCount,
\r
6958 if( count <= 0 ) {
\r
6959 if (appData.debugMode) {
\r
6960 fprintf( debugFP, "DoReadFile: trying to read past end of buffer, overflow = %d\n", count );
\r
6963 return ERROR_INVALID_USER_BUFFER;
\r
6966 ResetEvent(ovl->hEvent);
\r
6967 ovl->Offset = ovl->OffsetHigh = 0;
\r
6968 ok = ReadFile(hFile, buf, count, outCount, ovl);
\r
6972 err = GetLastError();
\r
6973 if (err == ERROR_IO_PENDING) {
\r
6974 ok = GetOverlappedResult(hFile, ovl, outCount, TRUE);
\r
6978 err = GetLastError();
\r
6985 DoWriteFile(HANDLE hFile, char *buf, int count, DWORD *outCount,
\r
6990 ResetEvent(ovl->hEvent);
\r
6991 ovl->Offset = ovl->OffsetHigh = 0;
\r
6992 ok = WriteFile(hFile, buf, count, outCount, ovl);
\r
6996 err = GetLastError();
\r
6997 if (err == ERROR_IO_PENDING) {
\r
6998 ok = GetOverlappedResult(hFile, ovl, outCount, TRUE);
\r
7002 err = GetLastError();
\r
7008 /* [AS] If input is line by line and a line exceed the buffer size, force an error */
\r
7009 void CheckForInputBufferFull( InputSource * is )
\r
7011 if( is->lineByLine && (is->next - is->buf) >= INPUT_SOURCE_BUF_SIZE ) {
\r
7012 /* Look for end of line */
\r
7013 char * p = is->buf;
\r
7015 while( p < is->next && *p != '\n' ) {
\r
7019 if( p >= is->next ) {
\r
7020 if (appData.debugMode) {
\r
7021 fprintf( debugFP, "Input line exceeded buffer size (source id=%lu)\n", is->id );
\r
7024 is->error = ERROR_BROKEN_PIPE; /* [AS] Just any non-successful code! */
\r
7025 is->count = (DWORD) -1;
\r
7026 is->next = is->buf;
\r
7032 InputThread(LPVOID arg)
\r
7037 is = (InputSource *) arg;
\r
7038 ovl.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
\r
7039 ovl.Internal = ovl.InternalHigh = ovl.Offset = ovl.OffsetHigh = 0;
\r
7040 while (is->hThread != NULL) {
\r
7041 is->error = DoReadFile(is->hFile, is->next,
\r
7042 INPUT_SOURCE_BUF_SIZE - (is->next - is->buf),
\r
7043 &is->count, &ovl);
\r
7044 if (is->error == NO_ERROR) {
\r
7045 is->next += is->count;
\r
7047 if (is->error == ERROR_BROKEN_PIPE) {
\r
7048 /* Correct for MS brain damage. EOF reading a pipe is not an error. */
\r
7051 is->count = (DWORD) -1;
\r
7052 /* [AS] The (is->count <= 0) check below is not useful for unsigned values! */
\r
7057 CheckForInputBufferFull( is );
\r
7059 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
7061 if( is->count == ((DWORD) -1) ) break; /* [AS] */
\r
7063 if (is->count <= 0) break; /* Quit on EOF or error */
\r
7066 CloseHandle(ovl.hEvent);
\r
7067 CloseHandle(is->hFile);
\r
7069 if (appData.debugMode) {
\r
7070 fprintf( debugFP, "Input thread terminated (id=%lu, error=%d, count=%ld)\n", is->id, is->error, is->count );
\r
7077 /* Windows 95 beta 2 won't let you do overlapped i/o on a console or pipe */
\r
7079 NonOvlInputThread(LPVOID arg)
\r
7086 is = (InputSource *) arg;
\r
7087 while (is->hThread != NULL) {
\r
7088 is->error = ReadFile(is->hFile, is->next,
\r
7089 INPUT_SOURCE_BUF_SIZE - (is->next - is->buf),
\r
7090 &is->count, NULL) ? NO_ERROR : GetLastError();
\r
7091 if (is->error == NO_ERROR) {
\r
7092 /* Change CRLF to LF */
\r
7093 if (is->next > is->buf) {
\r
7095 i = is->count + 1;
\r
7103 if (prev == '\r' && *p == '\n') {
\r
7115 if (is->error == ERROR_BROKEN_PIPE) {
\r
7116 /* Correct for MS brain damage. EOF reading a pipe is not an error. */
\r
7119 is->count = (DWORD) -1;
\r
7123 CheckForInputBufferFull( is );
\r
7125 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
7127 if( is->count == ((DWORD) -1) ) break; /* [AS] */
\r
7129 if (is->count < 0) break; /* Quit on error */
\r
7131 CloseHandle(is->hFile);
\r
7136 SocketInputThread(LPVOID arg)
\r
7140 is = (InputSource *) arg;
\r
7141 while (is->hThread != NULL) {
\r
7142 is->count = recv(is->sock, is->buf, INPUT_SOURCE_BUF_SIZE, 0);
\r
7143 if ((int)is->count == SOCKET_ERROR) {
\r
7144 is->count = (DWORD) -1;
\r
7145 is->error = WSAGetLastError();
\r
7147 is->error = NO_ERROR;
\r
7148 is->next += is->count;
\r
7149 if (is->count == 0 && is->second == is) {
\r
7150 /* End of file on stderr; quit with no message */
\r
7154 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
7156 if( is->count == ((DWORD) -1) ) break; /* [AS] */
\r
7158 if (is->count <= 0) break; /* Quit on EOF or error */
\r
7164 InputEvent(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
7168 is = (InputSource *) lParam;
\r
7169 if (is->lineByLine) {
\r
7170 /* Feed in lines one by one */
\r
7171 char *p = is->buf;
\r
7173 while (q < is->next) {
\r
7174 if (*q++ == '\n') {
\r
7175 (is->func)(is, is->closure, p, q - p, NO_ERROR);
\r
7180 /* Move any partial line to the start of the buffer */
\r
7182 while (p < is->next) {
\r
7187 if (is->error != NO_ERROR || is->count == 0) {
\r
7188 /* Notify backend of the error. Note: If there was a partial
\r
7189 line at the end, it is not flushed through. */
\r
7190 (is->func)(is, is->closure, is->buf, is->count, is->error);
\r
7193 /* Feed in the whole chunk of input at once */
\r
7194 (is->func)(is, is->closure, is->buf, is->count, is->error);
\r
7195 is->next = is->buf;
\r
7199 /*---------------------------------------------------------------------------*\
\r
7201 * Menu enables. Used when setting various modes.
\r
7203 \*---------------------------------------------------------------------------*/
\r
7211 GreyRevert(Boolean grey)
\r
7212 { // [HGM] vari: for retracting variations in local mode
\r
7213 HMENU hmenu = GetMenu(hwndMain);
\r
7214 EnableMenuItem(hmenu, IDM_Revert, MF_BYCOMMAND|(grey ? MF_GRAYED : MF_ENABLED));
\r
7218 SetMenuEnables(HMENU hmenu, Enables *enab)
\r
7220 while (enab->item > 0) {
\r
7221 (void) EnableMenuItem(hmenu, enab->item, enab->flags);
\r
7226 Enables gnuEnables[] = {
\r
7227 { IDM_MailMove, MF_BYCOMMAND|MF_GRAYED },
\r
7228 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_GRAYED },
\r
7229 { IDM_IcsClient, MF_BYCOMMAND|MF_GRAYED },
\r
7230 { IDM_Accept, MF_BYCOMMAND|MF_GRAYED },
\r
7231 { IDM_Decline, MF_BYCOMMAND|MF_GRAYED },
\r
7232 { IDM_Rematch, MF_BYCOMMAND|MF_GRAYED },
\r
7233 { IDM_Adjourn, MF_BYCOMMAND|MF_GRAYED },
\r
7234 { IDM_StopExamining, MF_BYCOMMAND|MF_GRAYED },
\r
7235 { IDM_StopObserving, MF_BYCOMMAND|MF_GRAYED },
\r
7236 { IDM_Revert, MF_BYCOMMAND|MF_GRAYED },
\r
7237 { IDM_NewChat, MF_BYCOMMAND|MF_GRAYED },
\r
7241 Enables icsEnables[] = {
\r
7242 { IDM_MailMove, MF_BYCOMMAND|MF_GRAYED },
\r
7243 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_GRAYED },
\r
7244 { IDM_MachineWhite, MF_BYCOMMAND|MF_GRAYED },
\r
7245 { IDM_MachineBlack, MF_BYCOMMAND|MF_GRAYED },
\r
7246 { IDM_TwoMachines, MF_BYCOMMAND|MF_GRAYED },
\r
7247 { IDM_MachineBoth, MF_BYCOMMAND|MF_GRAYED },
\r
7248 { IDM_AnalysisMode, MF_BYCOMMAND|MF_ENABLED },
\r
7249 { IDM_AnalyzeFile, MF_BYCOMMAND|MF_GRAYED },
\r
7250 { IDM_TimeControl, MF_BYCOMMAND|MF_GRAYED },
\r
7251 { IDM_MoveNow, MF_BYCOMMAND|MF_GRAYED },
\r
7252 { IDM_Hint, MF_BYCOMMAND|MF_GRAYED },
\r
7253 { IDM_Book, MF_BYCOMMAND|MF_GRAYED },
\r
7254 { IDM_IcsOptions, MF_BYCOMMAND|MF_ENABLED },
\r
7255 { IDM_Engine1Options, MF_BYCOMMAND|MF_GRAYED },
\r
7256 { IDM_Engine2Options, MF_BYCOMMAND|MF_GRAYED },
\r
7261 Enables zippyEnables[] = {
\r
7262 { IDM_MoveNow, MF_BYCOMMAND|MF_ENABLED },
\r
7263 { IDM_Hint, MF_BYCOMMAND|MF_ENABLED },
\r
7264 { IDM_Book, MF_BYCOMMAND|MF_ENABLED },
\r
7265 { IDM_Engine1Options, MF_BYCOMMAND|MF_ENABLED },
\r
7270 Enables ncpEnables[] = {
\r
7271 { IDM_MailMove, MF_BYCOMMAND|MF_GRAYED },
\r
7272 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_GRAYED },
\r
7273 { IDM_MachineWhite, MF_BYCOMMAND|MF_GRAYED },
\r
7274 { IDM_MachineBlack, MF_BYCOMMAND|MF_GRAYED },
\r
7275 { IDM_TwoMachines, MF_BYCOMMAND|MF_GRAYED },
\r
7276 { IDM_AnalysisMode, MF_BYCOMMAND|MF_GRAYED },
\r
7277 { IDM_AnalyzeFile, MF_BYCOMMAND|MF_GRAYED },
\r
7278 { IDM_IcsClient, MF_BYCOMMAND|MF_GRAYED },
\r
7279 { ACTION_POS, MF_BYPOSITION|MF_GRAYED },
\r
7280 { IDM_Revert, MF_BYCOMMAND|MF_GRAYED },
\r
7281 { IDM_MoveNow, MF_BYCOMMAND|MF_GRAYED },
\r
7282 { IDM_RetractMove, MF_BYCOMMAND|MF_GRAYED },
\r
7283 { IDM_TimeControl, MF_BYCOMMAND|MF_GRAYED },
\r
7284 { IDM_Hint, MF_BYCOMMAND|MF_GRAYED },
\r
7285 { IDM_Book, MF_BYCOMMAND|MF_GRAYED },
\r
7286 { IDM_MachineBoth, MF_BYCOMMAND|MF_GRAYED },
\r
7287 { IDM_NewChat, MF_BYCOMMAND|MF_GRAYED },
\r
7288 { IDM_Engine1Options, MF_BYCOMMAND|MF_GRAYED },
\r
7289 { IDM_Engine2Options, MF_BYCOMMAND|MF_GRAYED },
\r
7293 Enables trainingOnEnables[] = {
\r
7294 { IDM_EditComment, MF_BYCOMMAND|MF_GRAYED },
\r
7295 { IDM_Pause, MF_BYCOMMAND|MF_GRAYED },
\r
7296 { IDM_Forward, MF_BYCOMMAND|MF_GRAYED },
\r
7297 { IDM_Backward, MF_BYCOMMAND|MF_GRAYED },
\r
7298 { IDM_ToEnd, MF_BYCOMMAND|MF_GRAYED },
\r
7299 { IDM_ToStart, MF_BYCOMMAND|MF_GRAYED },
\r
7300 { IDM_MoveNow, MF_BYCOMMAND|MF_GRAYED },
\r
7301 { IDM_TruncateGame, MF_BYCOMMAND|MF_GRAYED },
\r
7305 Enables trainingOffEnables[] = {
\r
7306 { IDM_EditComment, MF_BYCOMMAND|MF_ENABLED },
\r
7307 { IDM_Pause, MF_BYCOMMAND|MF_ENABLED },
\r
7308 { IDM_Forward, MF_BYCOMMAND|MF_ENABLED },
\r
7309 { IDM_Backward, MF_BYCOMMAND|MF_ENABLED },
\r
7310 { IDM_ToEnd, MF_BYCOMMAND|MF_ENABLED },
\r
7311 { IDM_ToStart, MF_BYCOMMAND|MF_ENABLED },
\r
7312 { IDM_MoveNow, MF_BYCOMMAND|MF_ENABLED },
\r
7313 { IDM_TruncateGame, MF_BYCOMMAND|MF_ENABLED },
\r
7317 /* These modify either ncpEnables or gnuEnables */
\r
7318 Enables cmailEnables[] = {
\r
7319 { IDM_MailMove, MF_BYCOMMAND|MF_ENABLED },
\r
7320 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_ENABLED },
\r
7321 { ACTION_POS, MF_BYPOSITION|MF_ENABLED },
\r
7322 { IDM_CallFlag, MF_BYCOMMAND|MF_GRAYED },
\r
7323 { IDM_Draw, MF_BYCOMMAND|MF_ENABLED },
\r
7324 { IDM_Adjourn, MF_BYCOMMAND|MF_GRAYED },
\r
7325 { IDM_Abort, MF_BYCOMMAND|MF_GRAYED },
\r
7329 Enables machineThinkingEnables[] = {
\r
7330 { IDM_LoadGame, MF_BYCOMMAND|MF_GRAYED },
\r
7331 { IDM_LoadNextGame, MF_BYCOMMAND|MF_GRAYED },
\r
7332 { IDM_LoadPrevGame, MF_BYCOMMAND|MF_GRAYED },
\r
7333 { IDM_ReloadGame, MF_BYCOMMAND|MF_GRAYED },
\r
7334 { IDM_PasteGame, MF_BYCOMMAND|MF_GRAYED },
\r
7335 { IDM_LoadPosition, MF_BYCOMMAND|MF_GRAYED },
\r
7336 { IDM_LoadNextPosition, MF_BYCOMMAND|MF_GRAYED },
\r
7337 { IDM_LoadPrevPosition, MF_BYCOMMAND|MF_GRAYED },
\r
7338 { IDM_ReloadPosition, MF_BYCOMMAND|MF_GRAYED },
\r
7339 { IDM_PastePosition, MF_BYCOMMAND|MF_GRAYED },
\r
7340 { IDM_MachineWhite, MF_BYCOMMAND|MF_GRAYED },
\r
7341 { IDM_MachineBlack, MF_BYCOMMAND|MF_GRAYED },
\r
7342 { IDM_TwoMachines, MF_BYCOMMAND|MF_GRAYED },
\r
7343 { IDM_TypeInMove, MF_BYCOMMAND|MF_GRAYED },
\r
7344 { IDM_RetractMove, MF_BYCOMMAND|MF_GRAYED },
\r
7348 Enables userThinkingEnables[] = {
\r
7349 { IDM_LoadGame, MF_BYCOMMAND|MF_ENABLED },
\r
7350 { IDM_LoadNextGame, MF_BYCOMMAND|MF_ENABLED },
\r
7351 { IDM_LoadPrevGame, MF_BYCOMMAND|MF_ENABLED },
\r
7352 { IDM_ReloadGame, MF_BYCOMMAND|MF_ENABLED },
\r
7353 { IDM_PasteGame, MF_BYCOMMAND|MF_ENABLED },
\r
7354 { IDM_LoadPosition, MF_BYCOMMAND|MF_ENABLED },
\r
7355 { IDM_LoadNextPosition, MF_BYCOMMAND|MF_ENABLED },
\r
7356 { IDM_LoadPrevPosition, MF_BYCOMMAND|MF_ENABLED },
\r
7357 { IDM_ReloadPosition, MF_BYCOMMAND|MF_ENABLED },
\r
7358 { IDM_PastePosition, MF_BYCOMMAND|MF_ENABLED },
\r
7359 { IDM_MachineWhite, MF_BYCOMMAND|MF_ENABLED },
\r
7360 { IDM_MachineBlack, MF_BYCOMMAND|MF_ENABLED },
\r
7361 { IDM_TwoMachines, MF_BYCOMMAND|MF_ENABLED },
\r
7362 { IDM_TypeInMove, MF_BYCOMMAND|MF_ENABLED },
\r
7363 { IDM_RetractMove, MF_BYCOMMAND|MF_ENABLED },
\r
7367 /*---------------------------------------------------------------------------*\
\r
7369 * Front-end interface functions exported by XBoard.
\r
7370 * Functions appear in same order as prototypes in frontend.h.
\r
7372 \*---------------------------------------------------------------------------*/
\r
7376 static UINT prevChecked = 0;
\r
7377 static int prevPausing = 0;
\r
7380 if (pausing != prevPausing) {
\r
7381 prevPausing = pausing;
\r
7382 (void) CheckMenuItem(GetMenu(hwndMain), IDM_Pause,
\r
7383 MF_BYCOMMAND|(pausing ? MF_CHECKED : MF_UNCHECKED));
\r
7384 if (hwndPause) SetWindowText(hwndPause, pausing ? "C" : "P");
\r
7387 switch (gameMode) {
\r
7388 case BeginningOfGame:
\r
7389 if (appData.icsActive)
\r
7390 nowChecked = IDM_IcsClient;
\r
7391 else if (appData.noChessProgram)
\r
7392 nowChecked = IDM_EditGame;
\r
7394 nowChecked = IDM_MachineBlack;
\r
7396 case MachinePlaysBlack:
\r
7397 nowChecked = IDM_MachineBlack;
\r
7399 case MachinePlaysWhite:
\r
7400 nowChecked = IDM_MachineWhite;
\r
7402 case TwoMachinesPlay:
\r
7403 nowChecked = IDM_TwoMachines;
\r
7406 nowChecked = IDM_AnalysisMode;
\r
7409 nowChecked = IDM_AnalyzeFile;
\r
7412 nowChecked = IDM_EditGame;
\r
7414 case PlayFromGameFile:
\r
7415 nowChecked = IDM_LoadGame;
\r
7417 case EditPosition:
\r
7418 nowChecked = IDM_EditPosition;
\r
7421 nowChecked = IDM_Training;
\r
7423 case IcsPlayingWhite:
\r
7424 case IcsPlayingBlack:
\r
7425 case IcsObserving:
\r
7427 nowChecked = IDM_IcsClient;
\r
7434 if (prevChecked != 0)
\r
7435 (void) CheckMenuItem(GetMenu(hwndMain),
\r
7436 prevChecked, MF_BYCOMMAND|MF_UNCHECKED);
\r
7437 if (nowChecked != 0)
\r
7438 (void) CheckMenuItem(GetMenu(hwndMain),
\r
7439 nowChecked, MF_BYCOMMAND|MF_CHECKED);
\r
7441 if (nowChecked == IDM_LoadGame || nowChecked == IDM_Training) {
\r
7442 (void) EnableMenuItem(GetMenu(hwndMain), IDM_Training,
\r
7443 MF_BYCOMMAND|MF_ENABLED);
\r
7445 (void) EnableMenuItem(GetMenu(hwndMain),
\r
7446 IDM_Training, MF_BYCOMMAND|MF_GRAYED);
\r
7449 prevChecked = nowChecked;
\r
7451 /* [DM] icsEngineAnalyze - Do a sceure check too */
\r
7452 if (appData.icsActive) {
\r
7453 if (appData.icsEngineAnalyze) {
\r
7454 (void) CheckMenuItem(GetMenu(hwndMain), IDM_AnalysisMode,
\r
7455 MF_BYCOMMAND|MF_CHECKED);
\r
7457 (void) CheckMenuItem(GetMenu(hwndMain), IDM_AnalysisMode,
\r
7458 MF_BYCOMMAND|MF_UNCHECKED);
\r
7466 HMENU hmenu = GetMenu(hwndMain);
\r
7467 SetMenuEnables(hmenu, icsEnables);
\r
7468 EnableMenuItem(GetSubMenu(hmenu, OPTIONS_POS), ICS_POS,
\r
7469 MF_BYPOSITION|MF_ENABLED);
\r
7471 if (appData.zippyPlay) {
\r
7472 SetMenuEnables(hmenu, zippyEnables);
\r
7473 if (!appData.noChessProgram) /* [DM] icsEngineAnalyze */
\r
7474 (void) EnableMenuItem(GetMenu(hwndMain), IDM_AnalysisMode,
\r
7475 MF_BYCOMMAND|MF_ENABLED);
\r
7483 SetMenuEnables(GetMenu(hwndMain), gnuEnables);
\r
7489 HMENU hmenu = GetMenu(hwndMain);
\r
7490 SetMenuEnables(hmenu, ncpEnables);
\r
7491 EnableMenuItem(GetSubMenu(hmenu, OPTIONS_POS), SOUNDS_POS,
\r
7492 MF_BYPOSITION|MF_GRAYED);
\r
7493 DrawMenuBar(hwndMain);
\r
7499 SetMenuEnables(GetMenu(hwndMain), cmailEnables);
\r
7503 SetTrainingModeOn()
\r
7506 SetMenuEnables(GetMenu(hwndMain), trainingOnEnables);
\r
7507 for (i = 0; i < N_BUTTONS; i++) {
\r
7508 if (buttonDesc[i].hwnd != NULL)
\r
7509 EnableWindow(buttonDesc[i].hwnd, FALSE);
\r
7514 VOID SetTrainingModeOff()
\r
7517 SetMenuEnables(GetMenu(hwndMain), trainingOffEnables);
\r
7518 for (i = 0; i < N_BUTTONS; i++) {
\r
7519 if (buttonDesc[i].hwnd != NULL)
\r
7520 EnableWindow(buttonDesc[i].hwnd, TRUE);
\r
7526 SetUserThinkingEnables()
\r
7528 SetMenuEnables(GetMenu(hwndMain), userThinkingEnables);
\r
7532 SetMachineThinkingEnables()
\r
7534 HMENU hMenu = GetMenu(hwndMain);
\r
7535 int flags = MF_BYCOMMAND|MF_ENABLED;
\r
7537 SetMenuEnables(hMenu, machineThinkingEnables);
\r
7539 if (gameMode == MachinePlaysBlack) {
\r
7540 (void)EnableMenuItem(hMenu, IDM_MachineBlack, flags);
\r
7541 } else if (gameMode == MachinePlaysWhite) {
\r
7542 (void)EnableMenuItem(hMenu, IDM_MachineWhite, flags);
\r
7543 } else if (gameMode == TwoMachinesPlay) {
\r
7544 (void)EnableMenuItem(hMenu, IDM_TwoMachines, flags);
\r
7550 DisplayTitle(char *str)
\r
7552 char title[MSG_SIZ], *host;
\r
7553 if (str[0] != NULLCHAR) {
\r
7554 strcpy(title, str);
\r
7555 } else if (appData.icsActive) {
\r
7556 if (appData.icsCommPort[0] != NULLCHAR)
\r
7559 host = appData.icsHost;
\r
7560 sprintf(title, "%s: %s", szTitle, host);
\r
7561 } else if (appData.noChessProgram) {
\r
7562 strcpy(title, szTitle);
\r
7564 strcpy(title, szTitle);
\r
7565 strcat(title, ": ");
\r
7566 strcat(title, first.tidy);
\r
7568 SetWindowText(hwndMain, title);
\r
7573 DisplayMessage(char *str1, char *str2)
\r
7577 int remain = MESSAGE_TEXT_MAX - 1;
\r
7580 moveErrorMessageUp = FALSE; /* turned on later by caller if needed */
\r
7581 messageText[0] = NULLCHAR;
\r
7583 len = strlen(str1);
\r
7584 if (len > remain) len = remain;
\r
7585 strncpy(messageText, str1, len);
\r
7586 messageText[len] = NULLCHAR;
\r
7589 if (*str2 && remain >= 2) {
\r
7591 strcat(messageText, " ");
\r
7594 len = strlen(str2);
\r
7595 if (len > remain) len = remain;
\r
7596 strncat(messageText, str2, len);
\r
7598 messageText[MESSAGE_TEXT_MAX - 1] = NULLCHAR;
\r
7600 if (hwndMain == NULL || IsIconic(hwndMain)) return;
\r
7604 hdc = GetDC(hwndMain);
\r
7605 oldFont = SelectObject(hdc, font[boardSize][MESSAGE_FONT]->hf);
\r
7606 ExtTextOut(hdc, messageRect.left, messageRect.top, ETO_CLIPPED|ETO_OPAQUE,
\r
7607 &messageRect, messageText, strlen(messageText), NULL);
\r
7608 (void) SelectObject(hdc, oldFont);
\r
7609 (void) ReleaseDC(hwndMain, hdc);
\r
7613 DisplayError(char *str, int error)
\r
7615 char buf[MSG_SIZ*2], buf2[MSG_SIZ];
\r
7621 len = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
\r
7622 NULL, error, LANG_NEUTRAL,
\r
7623 (LPSTR) buf2, MSG_SIZ, NULL);
\r
7625 sprintf(buf, "%s:\n%s", str, buf2);
\r
7627 ErrorMap *em = errmap;
\r
7628 while (em->err != 0 && em->err != error) em++;
\r
7629 if (em->err != 0) {
\r
7630 sprintf(buf, "%s:\n%s", str, em->msg);
\r
7632 sprintf(buf, "%s:\nError code %d", str, error);
\r
7637 ErrorPopUp("Error", buf);
\r
7642 DisplayMoveError(char *str)
\r
7644 fromX = fromY = -1;
\r
7645 ClearHighlights();
\r
7646 DrawPosition(FALSE, NULL);
\r
7647 if (appData.popupMoveErrors) {
\r
7648 ErrorPopUp("Error", str);
\r
7650 DisplayMessage(str, "");
\r
7651 moveErrorMessageUp = TRUE;
\r
7656 DisplayFatalError(char *str, int error, int exitStatus)
\r
7658 char buf[2*MSG_SIZ], buf2[MSG_SIZ];
\r
7660 char *label = exitStatus ? "Fatal Error" : "Exiting";
\r
7663 len = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
\r
7664 NULL, error, LANG_NEUTRAL,
\r
7665 (LPSTR) buf2, MSG_SIZ, NULL);
\r
7667 sprintf(buf, "%s:\n%s", str, buf2);
\r
7669 ErrorMap *em = errmap;
\r
7670 while (em->err != 0 && em->err != error) em++;
\r
7671 if (em->err != 0) {
\r
7672 sprintf(buf, "%s:\n%s", str, em->msg);
\r
7674 sprintf(buf, "%s:\nError code %d", str, error);
\r
7679 if (appData.debugMode) {
\r
7680 fprintf(debugFP, "%s: %s\n", label, str);
\r
7682 if (appData.popupExitMessage) {
\r
7683 (void) MessageBox(hwndMain, str, label, MB_OK|
\r
7684 (exitStatus ? MB_ICONSTOP : MB_ICONINFORMATION));
\r
7686 ExitEvent(exitStatus);
\r
7691 DisplayInformation(char *str)
\r
7693 (void) MessageBox(hwndMain, str, "Information", MB_OK|MB_ICONINFORMATION);
\r
7698 DisplayNote(char *str)
\r
7700 ErrorPopUp("Note", str);
\r
7705 char *title, *question, *replyPrefix;
\r
7710 QuestionDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7712 static QuestionParams *qp;
\r
7713 char reply[MSG_SIZ];
\r
7716 switch (message) {
\r
7717 case WM_INITDIALOG:
\r
7718 qp = (QuestionParams *) lParam;
\r
7719 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
7720 SetWindowText(hDlg, qp->title);
\r
7721 SetDlgItemText(hDlg, OPT_QuestionText, qp->question);
\r
7722 SetFocus(GetDlgItem(hDlg, OPT_QuestionInput));
\r
7726 switch (LOWORD(wParam)) {
\r
7728 strcpy(reply, qp->replyPrefix);
\r
7729 if (*reply) strcat(reply, " ");
\r
7730 len = strlen(reply);
\r
7731 GetDlgItemText(hDlg, OPT_QuestionInput, reply + len, sizeof(reply) - len);
\r
7732 strcat(reply, "\n");
\r
7733 OutputToProcess(qp->pr, reply, strlen(reply), &err);
\r
7734 EndDialog(hDlg, TRUE);
\r
7735 if (err) DisplayFatalError("Error writing to chess program", err, 1);
\r
7738 EndDialog(hDlg, FALSE);
\r
7749 AskQuestion(char* title, char *question, char *replyPrefix, ProcRef pr)
\r
7751 QuestionParams qp;
\r
7755 qp.question = question;
\r
7756 qp.replyPrefix = replyPrefix;
\r
7758 lpProc = MakeProcInstance((FARPROC)QuestionDialog, hInst);
\r
7759 DialogBoxParam(hInst, MAKEINTRESOURCE(DLG_Question),
\r
7760 hwndMain, (DLGPROC)lpProc, (LPARAM)&qp);
\r
7761 FreeProcInstance(lpProc);
\r
7764 /* [AS] Pick FRC position */
\r
7765 LRESULT CALLBACK NewGameFRC_Proc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7767 static int * lpIndexFRC;
\r
7773 case WM_INITDIALOG:
\r
7774 lpIndexFRC = (int *) lParam;
\r
7776 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
7778 SendDlgItemMessage( hDlg, IDC_NFG_Edit, EM_SETLIMITTEXT, sizeof(buf)-1, 0 );
\r
7779 SetDlgItemInt( hDlg, IDC_NFG_Edit, *lpIndexFRC, TRUE );
\r
7780 SendDlgItemMessage( hDlg, IDC_NFG_Edit, EM_SETSEL, 0, -1 );
\r
7781 SetFocus(GetDlgItem(hDlg, IDC_NFG_Edit));
\r
7786 switch( LOWORD(wParam) ) {
\r
7788 *lpIndexFRC = GetDlgItemInt(hDlg, IDC_NFG_Edit, &index_is_ok, TRUE );
\r
7789 EndDialog( hDlg, 0 );
\r
7790 shuffleOpenings = TRUE; /* [HGM] shuffle: switch shuffling on for as long as we stay in current variant */
\r
7793 EndDialog( hDlg, 1 );
\r
7795 case IDC_NFG_Edit:
\r
7796 if( HIWORD(wParam) == EN_CHANGE ) {
\r
7797 GetDlgItemInt(hDlg, IDC_NFG_Edit, &index_is_ok, TRUE );
\r
7799 EnableWindow( GetDlgItem(hDlg, IDOK), index_is_ok );
\r
7802 case IDC_NFG_Random:
\r
7803 sprintf( buf, "%d", myrandom() ); /* [HGM] shuffle: no longer limit to 960 */
\r
7804 SetDlgItemText(hDlg, IDC_NFG_Edit, buf );
\r
7817 int index = appData.defaultFrcPosition;
\r
7818 FARPROC lpProc = MakeProcInstance( (FARPROC) NewGameFRC_Proc, hInst );
\r
7820 result = DialogBoxParam( hInst, MAKEINTRESOURCE(DLG_NewGameFRC), hwndMain, (DLGPROC)lpProc, (LPARAM)&index );
\r
7822 if( result == 0 ) {
\r
7823 appData.defaultFrcPosition = index;
\r
7829 /* [AS] Game list options */
\r
7835 static GLT_Item GLT_ItemInfo[] = {
\r
7836 { GLT_EVENT, "Event" },
\r
7837 { GLT_SITE, "Site" },
\r
7838 { GLT_DATE, "Date" },
\r
7839 { GLT_ROUND, "Round" },
\r
7840 { GLT_PLAYERS, "Players" },
\r
7841 { GLT_RESULT, "Result" },
\r
7842 { GLT_WHITE_ELO, "White Rating" },
\r
7843 { GLT_BLACK_ELO, "Black Rating" },
\r
7844 { GLT_TIME_CONTROL,"Time Control" },
\r
7845 { GLT_VARIANT, "Variant" },
\r
7846 { GLT_OUT_OF_BOOK,PGN_OUT_OF_BOOK },
\r
7847 { GLT_RESULT_COMMENT, "Result Comment" }, // [HGM] rescom
\r
7851 const char * GLT_FindItem( char id )
\r
7853 const char * result = 0;
\r
7855 GLT_Item * list = GLT_ItemInfo;
\r
7857 while( list->id != 0 ) {
\r
7858 if( list->id == id ) {
\r
7859 result = list->name;
\r
7869 void GLT_AddToList( HWND hDlg, int iDlgItem, char id, int index )
\r
7871 const char * name = GLT_FindItem( id );
\r
7874 if( index >= 0 ) {
\r
7875 SendDlgItemMessage( hDlg, iDlgItem, LB_INSERTSTRING, index, (LPARAM) name );
\r
7878 SendDlgItemMessage( hDlg, iDlgItem, LB_ADDSTRING, 0, (LPARAM) name );
\r
7883 void GLT_TagsToList( HWND hDlg, char * tags )
\r
7887 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_RESETCONTENT, 0, 0 );
\r
7890 GLT_AddToList( hDlg, IDC_GameListTags, *pc, -1 );
\r
7894 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_ADDSTRING, 0, (LPARAM) "\t --- Hidden tags ---" );
\r
7896 pc = GLT_ALL_TAGS;
\r
7899 if( strchr( tags, *pc ) == 0 ) {
\r
7900 GLT_AddToList( hDlg, IDC_GameListTags, *pc, -1 );
\r
7905 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_SETCURSEL, 0, 0 );
\r
7908 char GLT_ListItemToTag( HWND hDlg, int index )
\r
7910 char result = '\0';
\r
7913 GLT_Item * list = GLT_ItemInfo;
\r
7915 if( SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETTEXT, index, (LPARAM) name ) != LB_ERR ) {
\r
7916 while( list->id != 0 ) {
\r
7917 if( strcmp( list->name, name ) == 0 ) {
\r
7918 result = list->id;
\r
7929 void GLT_MoveSelection( HWND hDlg, int delta )
\r
7931 int idx1 = (int) SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETCURSEL, 0, 0 );
\r
7932 int idx2 = idx1 + delta;
\r
7933 int count = (int) SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETCOUNT, 0, 0 );
\r
7935 if( idx1 >=0 && idx1 < count && idx2 >= 0 && idx2 < count ) {
\r
7938 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETTEXT, idx1, (LPARAM) buf );
\r
7939 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_DELETESTRING, idx1, 0 );
\r
7940 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_INSERTSTRING, idx2, (LPARAM) buf );
\r
7941 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_SETCURSEL, idx2, 0 );
\r
7945 LRESULT CALLBACK GameListOptions_Proc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7947 static char glt[64];
\r
7948 static char * lpUserGLT;
\r
7952 case WM_INITDIALOG:
\r
7953 lpUserGLT = (char *) lParam;
\r
7955 strcpy( glt, lpUserGLT );
\r
7957 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
7959 /* Initialize list */
\r
7960 GLT_TagsToList( hDlg, glt );
\r
7962 SetFocus( GetDlgItem(hDlg, IDC_GameListTags) );
\r
7967 switch( LOWORD(wParam) ) {
\r
7970 char * pc = lpUserGLT;
\r
7972 // int cnt = (int) SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETCOUNT, 0, 0 );
\r
7976 id = GLT_ListItemToTag( hDlg, idx );
\r
7980 } while( id != '\0' );
\r
7982 EndDialog( hDlg, 0 );
\r
7985 EndDialog( hDlg, 1 );
\r
7988 case IDC_GLT_Default:
\r
7989 strcpy( glt, GLT_DEFAULT_TAGS );
\r
7990 GLT_TagsToList( hDlg, glt );
\r
7993 case IDC_GLT_Restore:
\r
7994 strcpy( glt, lpUserGLT );
\r
7995 GLT_TagsToList( hDlg, glt );
\r
7999 GLT_MoveSelection( hDlg, -1 );
\r
8002 case IDC_GLT_Down:
\r
8003 GLT_MoveSelection( hDlg, +1 );
\r
8013 int GameListOptions()
\r
8017 FARPROC lpProc = MakeProcInstance( (FARPROC) GameListOptions_Proc, hInst );
\r
8019 strcpy( glt, appData.gameListTags );
\r
8021 result = DialogBoxParam( hInst, MAKEINTRESOURCE(DLG_GameListOptions), hwndMain, (DLGPROC)lpProc, (LPARAM)glt );
\r
8023 if( result == 0 ) {
\r
8024 /* [AS] Memory leak here! */
\r
8025 appData.gameListTags = strdup( glt );
\r
8033 DisplayIcsInteractionTitle(char *str)
\r
8035 char consoleTitle[MSG_SIZ];
\r
8037 sprintf(consoleTitle, "%s: %s", szConsoleTitle, str);
\r
8038 SetWindowText(hwndConsole, consoleTitle);
\r
8042 DrawPosition(int fullRedraw, Board board)
\r
8044 HDCDrawPosition(NULL, (BOOLEAN) fullRedraw, board);
\r
8047 void NotifyFrontendLogin()
\r
8050 UpdateICSWidth(GetDlgItem(hwndConsole, OPT_ConsoleText));
\r
8056 fromX = fromY = -1;
\r
8057 if (dragInfo.pos.x != -1 || dragInfo.pos.y != -1) {
\r
8058 dragInfo.pos.x = dragInfo.pos.y = -1;
\r
8059 dragInfo.pos.x = dragInfo.pos.y = -1;
\r
8060 dragInfo.lastpos = dragInfo.pos;
\r
8061 dragInfo.start.x = dragInfo.start.y = -1;
\r
8062 dragInfo.from = dragInfo.start;
\r
8064 DrawPosition(TRUE, NULL);
\r
8070 CommentPopUp(char *title, char *str)
\r
8072 HWND hwnd = GetActiveWindow();
\r
8073 EitherCommentPopUp(0, title, str, FALSE);
\r
8075 SetActiveWindow(hwnd);
\r
8079 CommentPopDown(void)
\r
8081 CheckMenuItem(GetMenu(hwndMain), IDM_EditComment, MF_UNCHECKED);
\r
8082 if (commentDialog) {
\r
8083 ShowWindow(commentDialog, SW_HIDE);
\r
8085 commentUp = FALSE;
\r
8089 EditCommentPopUp(int index, char *title, char *str)
\r
8091 EitherCommentPopUp(index, title, str, TRUE);
\r
8098 MyPlaySound(&sounds[(int)SoundMove]);
\r
8101 VOID PlayIcsWinSound()
\r
8103 MyPlaySound(&sounds[(int)SoundIcsWin]);
\r
8106 VOID PlayIcsLossSound()
\r
8108 MyPlaySound(&sounds[(int)SoundIcsLoss]);
\r
8111 VOID PlayIcsDrawSound()
\r
8113 MyPlaySound(&sounds[(int)SoundIcsDraw]);
\r
8116 VOID PlayIcsUnfinishedSound()
\r
8118 MyPlaySound(&sounds[(int)SoundIcsUnfinished]);
\r
8124 MyPlaySound(&sounds[(int)SoundAlarm]);
\r
8132 consoleEcho = TRUE;
\r
8133 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
8134 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&consoleCF);
\r
8135 SendMessage(hInput, EM_SETBKGNDCOLOR, FALSE, consoleBackgroundColor);
\r
8144 consoleEcho = FALSE;
\r
8145 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
8146 /* This works OK: set text and background both to the same color */
\r
8148 cf.crTextColor = COLOR_ECHOOFF;
\r
8149 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&cf);
\r
8150 SendMessage(hInput, EM_SETBKGNDCOLOR, FALSE, cf.crTextColor);
\r
8153 /* No Raw()...? */
\r
8155 void Colorize(ColorClass cc, int continuation)
\r
8157 currentColorClass = cc;
\r
8158 consoleCF.dwMask = CFM_COLOR|CFM_BOLD|CFM_ITALIC|CFM_UNDERLINE|CFM_STRIKEOUT;
\r
8159 consoleCF.crTextColor = textAttribs[cc].color;
\r
8160 consoleCF.dwEffects = textAttribs[cc].effects;
\r
8161 if (!continuation) MyPlaySound(&textAttribs[cc].sound);
\r
8167 static char buf[MSG_SIZ];
\r
8168 DWORD bufsiz = MSG_SIZ;
\r
8170 if(appData.userName != NULL && appData.userName[0] != 0) {
\r
8171 return appData.userName; /* [HGM] username: prefer name selected by user over his system login */
\r
8173 if (!GetUserName(buf, &bufsiz)) {
\r
8174 /*DisplayError("Error getting user name", GetLastError());*/
\r
8175 strcpy(buf, "User");
\r
8183 static char buf[MSG_SIZ];
\r
8184 DWORD bufsiz = MSG_SIZ;
\r
8186 if (!GetComputerName(buf, &bufsiz)) {
\r
8187 /*DisplayError("Error getting host name", GetLastError());*/
\r
8188 strcpy(buf, "Unknown");
\r
8195 ClockTimerRunning()
\r
8197 return clockTimerEvent != 0;
\r
8203 if (clockTimerEvent == 0) return FALSE;
\r
8204 KillTimer(hwndMain, clockTimerEvent);
\r
8205 clockTimerEvent = 0;
\r
8210 StartClockTimer(long millisec)
\r
8212 clockTimerEvent = SetTimer(hwndMain, (UINT) CLOCK_TIMER_ID,
\r
8213 (UINT) millisec, NULL);
\r
8217 DisplayWhiteClock(long timeRemaining, int highlight)
\r
8220 char *flag = whiteFlag && gameMode == TwoMachinesPlay ? "(!)" : "";
\r
8222 if(appData.noGUI) return;
\r
8223 hdc = GetDC(hwndMain);
\r
8224 if (!IsIconic(hwndMain)) {
\r
8225 DisplayAClock(hdc, timeRemaining, highlight,
\r
8226 flipClock ? &blackRect : &whiteRect, "White", flag);
\r
8228 if (highlight && iconCurrent == iconBlack) {
\r
8229 iconCurrent = iconWhite;
\r
8230 PostMessage(hwndMain, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
8231 if (IsIconic(hwndMain)) {
\r
8232 DrawIcon(hdc, 2, 2, iconCurrent);
\r
8235 (void) ReleaseDC(hwndMain, hdc);
\r
8237 PostMessage(hwndConsole, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
8241 DisplayBlackClock(long timeRemaining, int highlight)
\r
8244 char *flag = blackFlag && gameMode == TwoMachinesPlay ? "(!)" : "";
\r
8246 if(appData.noGUI) return;
\r
8247 hdc = GetDC(hwndMain);
\r
8248 if (!IsIconic(hwndMain)) {
\r
8249 DisplayAClock(hdc, timeRemaining, highlight,
\r
8250 flipClock ? &whiteRect : &blackRect, "Black", flag);
\r
8252 if (highlight && iconCurrent == iconWhite) {
\r
8253 iconCurrent = iconBlack;
\r
8254 PostMessage(hwndMain, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
8255 if (IsIconic(hwndMain)) {
\r
8256 DrawIcon(hdc, 2, 2, iconCurrent);
\r
8259 (void) ReleaseDC(hwndMain, hdc);
\r
8261 PostMessage(hwndConsole, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
8266 LoadGameTimerRunning()
\r
8268 return loadGameTimerEvent != 0;
\r
8272 StopLoadGameTimer()
\r
8274 if (loadGameTimerEvent == 0) return FALSE;
\r
8275 KillTimer(hwndMain, loadGameTimerEvent);
\r
8276 loadGameTimerEvent = 0;
\r
8281 StartLoadGameTimer(long millisec)
\r
8283 loadGameTimerEvent = SetTimer(hwndMain, (UINT) LOAD_GAME_TIMER_ID,
\r
8284 (UINT) millisec, NULL);
\r
8292 char fileTitle[MSG_SIZ];
\r
8294 defName = DefaultFileName(appData.oldSaveStyle ? "gam" : "pgn");
\r
8295 f = OpenFileDialog(hwndMain, "a", defName,
\r
8296 appData.oldSaveStyle ? "gam" : "pgn",
\r
8298 "Save Game to File", NULL, fileTitle, NULL);
\r
8300 SaveGame(f, 0, "");
\r
8307 ScheduleDelayedEvent(DelayedEventCallback cb, long millisec)
\r
8309 if (delayedTimerEvent != 0) {
\r
8310 if (appData.debugMode && cb != delayedTimerCallback) { // [HGM] alive: not too much debug
\r
8311 fprintf(debugFP, "ScheduleDelayedEvent: event already scheduled\n");
\r
8313 KillTimer(hwndMain, delayedTimerEvent);
\r
8314 delayedTimerEvent = 0;
\r
8315 if(delayedTimerCallback != cb) // [HGM] alive: do not "flush" same event, just postpone it
\r
8316 delayedTimerCallback();
\r
8318 delayedTimerCallback = cb;
\r
8319 delayedTimerEvent = SetTimer(hwndMain, (UINT) DELAYED_TIMER_ID,
\r
8320 (UINT) millisec, NULL);
\r
8323 DelayedEventCallback
\r
8326 if (delayedTimerEvent) {
\r
8327 return delayedTimerCallback;
\r
8334 CancelDelayedEvent()
\r
8336 if (delayedTimerEvent) {
\r
8337 KillTimer(hwndMain, delayedTimerEvent);
\r
8338 delayedTimerEvent = 0;
\r
8342 DWORD GetWin32Priority(int nice)
\r
8343 { // [HGM] nice: translate Unix nice() value to indows priority class. (Code stolen from Polyglot 1.4w11)
\r
8345 REALTIME_PRIORITY_CLASS 0x00000100
\r
8346 HIGH_PRIORITY_CLASS 0x00000080
\r
8347 ABOVE_NORMAL_PRIORITY_CLASS 0x00008000
\r
8348 NORMAL_PRIORITY_CLASS 0x00000020
\r
8349 BELOW_NORMAL_PRIORITY_CLASS 0x00004000
\r
8350 IDLE_PRIORITY_CLASS 0x00000040
\r
8352 if (nice < -15) return 0x00000080;
\r
8353 if (nice < 0) return 0x00008000;
\r
8354 if (nice == 0) return 0x00000020;
\r
8355 if (nice < 15) return 0x00004000;
\r
8356 return 0x00000040;
\r
8359 /* Start a child process running the given program.
\r
8360 The process's standard output can be read from "from", and its
\r
8361 standard input can be written to "to".
\r
8362 Exit with fatal error if anything goes wrong.
\r
8363 Returns an opaque pointer that can be used to destroy the process
\r
8367 StartChildProcess(char *cmdLine, char *dir, ProcRef *pr)
\r
8369 #define BUFSIZE 4096
\r
8371 HANDLE hChildStdinRd, hChildStdinWr,
\r
8372 hChildStdoutRd, hChildStdoutWr;
\r
8373 HANDLE hChildStdinWrDup, hChildStdoutRdDup;
\r
8374 SECURITY_ATTRIBUTES saAttr;
\r
8376 PROCESS_INFORMATION piProcInfo;
\r
8377 STARTUPINFO siStartInfo;
\r
8379 char buf[MSG_SIZ];
\r
8382 if (appData.debugMode) {
\r
8383 fprintf(debugFP, "StartChildProcess (dir=\"%s\") %s\n", dir, cmdLine);
\r
8388 /* Set the bInheritHandle flag so pipe handles are inherited. */
\r
8389 saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
\r
8390 saAttr.bInheritHandle = TRUE;
\r
8391 saAttr.lpSecurityDescriptor = NULL;
\r
8394 * The steps for redirecting child's STDOUT:
\r
8395 * 1. Create anonymous pipe to be STDOUT for child.
\r
8396 * 2. Create a noninheritable duplicate of read handle,
\r
8397 * and close the inheritable read handle.
\r
8400 /* Create a pipe for the child's STDOUT. */
\r
8401 if (! CreatePipe(&hChildStdoutRd, &hChildStdoutWr, &saAttr, 0)) {
\r
8402 return GetLastError();
\r
8405 /* Duplicate the read handle to the pipe, so it is not inherited. */
\r
8406 fSuccess = DuplicateHandle(GetCurrentProcess(), hChildStdoutRd,
\r
8407 GetCurrentProcess(), &hChildStdoutRdDup, 0,
\r
8408 FALSE, /* not inherited */
\r
8409 DUPLICATE_SAME_ACCESS);
\r
8411 return GetLastError();
\r
8413 CloseHandle(hChildStdoutRd);
\r
8416 * The steps for redirecting child's STDIN:
\r
8417 * 1. Create anonymous pipe to be STDIN for child.
\r
8418 * 2. Create a noninheritable duplicate of write handle,
\r
8419 * and close the inheritable write handle.
\r
8422 /* Create a pipe for the child's STDIN. */
\r
8423 if (! CreatePipe(&hChildStdinRd, &hChildStdinWr, &saAttr, 0)) {
\r
8424 return GetLastError();
\r
8427 /* Duplicate the write handle to the pipe, so it is not inherited. */
\r
8428 fSuccess = DuplicateHandle(GetCurrentProcess(), hChildStdinWr,
\r
8429 GetCurrentProcess(), &hChildStdinWrDup, 0,
\r
8430 FALSE, /* not inherited */
\r
8431 DUPLICATE_SAME_ACCESS);
\r
8433 return GetLastError();
\r
8435 CloseHandle(hChildStdinWr);
\r
8437 /* Arrange to (1) look in dir for the child .exe file, and
\r
8438 * (2) have dir be the child's working directory. Interpret
\r
8439 * dir relative to the directory WinBoard loaded from. */
\r
8440 GetCurrentDirectory(MSG_SIZ, buf);
\r
8441 SetCurrentDirectory(installDir);
\r
8442 SetCurrentDirectory(dir);
\r
8444 /* Now create the child process. */
\r
8446 siStartInfo.cb = sizeof(STARTUPINFO);
\r
8447 siStartInfo.lpReserved = NULL;
\r
8448 siStartInfo.lpDesktop = NULL;
\r
8449 siStartInfo.lpTitle = NULL;
\r
8450 siStartInfo.dwFlags = STARTF_USESTDHANDLES;
\r
8451 siStartInfo.cbReserved2 = 0;
\r
8452 siStartInfo.lpReserved2 = NULL;
\r
8453 siStartInfo.hStdInput = hChildStdinRd;
\r
8454 siStartInfo.hStdOutput = hChildStdoutWr;
\r
8455 siStartInfo.hStdError = hChildStdoutWr;
\r
8457 fSuccess = CreateProcess(NULL,
\r
8458 cmdLine, /* command line */
\r
8459 NULL, /* process security attributes */
\r
8460 NULL, /* primary thread security attrs */
\r
8461 TRUE, /* handles are inherited */
\r
8462 DETACHED_PROCESS|CREATE_NEW_PROCESS_GROUP,
\r
8463 NULL, /* use parent's environment */
\r
8465 &siStartInfo, /* STARTUPINFO pointer */
\r
8466 &piProcInfo); /* receives PROCESS_INFORMATION */
\r
8468 err = GetLastError();
\r
8469 SetCurrentDirectory(buf); /* return to prev directory */
\r
8474 if (appData.niceEngines){ // [HGM] nice: adjust engine proc priority
\r
8475 if(appData.debugMode) fprintf(debugFP, "nice engine proc to %d\n", appData.niceEngines);
\r
8476 SetPriorityClass(piProcInfo.hProcess, GetWin32Priority(appData.niceEngines));
\r
8479 /* Close the handles we don't need in the parent */
\r
8480 CloseHandle(piProcInfo.hThread);
\r
8481 CloseHandle(hChildStdinRd);
\r
8482 CloseHandle(hChildStdoutWr);
\r
8484 /* Prepare return value */
\r
8485 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
8486 cp->kind = CPReal;
\r
8487 cp->hProcess = piProcInfo.hProcess;
\r
8488 cp->pid = piProcInfo.dwProcessId;
\r
8489 cp->hFrom = hChildStdoutRdDup;
\r
8490 cp->hTo = hChildStdinWrDup;
\r
8492 *pr = (void *) cp;
\r
8494 /* Klaus Friedel says that this Sleep solves a problem under Windows
\r
8495 2000 where engines sometimes don't see the initial command(s)
\r
8496 from WinBoard and hang. I don't understand how that can happen,
\r
8497 but the Sleep is harmless, so I've put it in. Others have also
\r
8498 reported what may be the same problem, so hopefully this will fix
\r
8499 it for them too. */
\r
8507 DestroyChildProcess(ProcRef pr, int/*boolean*/ signal)
\r
8509 ChildProc *cp; int result;
\r
8511 cp = (ChildProc *) pr;
\r
8512 if (cp == NULL) return;
\r
8514 switch (cp->kind) {
\r
8516 /* TerminateProcess is considered harmful, so... */
\r
8517 CloseHandle(cp->hTo); /* Closing this will give the child an EOF and hopefully kill it */
\r
8518 if (cp->hFrom) CloseHandle(cp->hFrom); /* if NULL, InputThread will close it */
\r
8519 /* The following doesn't work because the chess program
\r
8520 doesn't "have the same console" as WinBoard. Maybe
\r
8521 we could arrange for this even though neither WinBoard
\r
8522 nor the chess program uses a console for stdio? */
\r
8523 /*!!if (signal) GenerateConsoleCtrlEvent(CTRL_BREAK_EVENT, cp->pid);*/
\r
8525 /* [AS] Special termination modes for misbehaving programs... */
\r
8526 if( signal == 9 ) {
\r
8527 result = TerminateProcess( cp->hProcess, 0 );
\r
8529 if ( appData.debugMode) {
\r
8530 fprintf( debugFP, "Terminating process %lu, result=%d\n", cp->pid, result );
\r
8533 else if( signal == 10 ) {
\r
8534 DWORD dw = WaitForSingleObject( cp->hProcess, 3*1000 ); // Wait 3 seconds at most
\r
8536 if( dw != WAIT_OBJECT_0 ) {
\r
8537 result = TerminateProcess( cp->hProcess, 0 );
\r
8539 if ( appData.debugMode) {
\r
8540 fprintf( debugFP, "Process %lu still alive after timeout, killing... result=%d\n", cp->pid, result );
\r
8546 CloseHandle(cp->hProcess);
\r
8550 if (cp->hFrom) CloseHandle(cp->hFrom);
\r
8554 closesocket(cp->sock);
\r
8559 if (signal) send(cp->sock2, "\017", 1, 0); /* 017 = 15 = SIGTERM */
\r
8560 closesocket(cp->sock);
\r
8561 closesocket(cp->sock2);
\r
8569 InterruptChildProcess(ProcRef pr)
\r
8573 cp = (ChildProc *) pr;
\r
8574 if (cp == NULL) return;
\r
8575 switch (cp->kind) {
\r
8577 /* The following doesn't work because the chess program
\r
8578 doesn't "have the same console" as WinBoard. Maybe
\r
8579 we could arrange for this even though neither WinBoard
\r
8580 nor the chess program uses a console for stdio */
\r
8581 /*!!GenerateConsoleCtrlEvent(CTRL_C_EVENT, cp->pid);*/
\r
8586 /* Can't interrupt */
\r
8590 send(cp->sock2, "\002", 1, 0); /* 2 = SIGINT */
\r
8597 OpenTelnet(char *host, char *port, ProcRef *pr)
\r
8599 char cmdLine[MSG_SIZ];
\r
8601 if (port[0] == NULLCHAR) {
\r
8602 sprintf(cmdLine, "%s %s", appData.telnetProgram, host);
\r
8604 sprintf(cmdLine, "%s %s %s", appData.telnetProgram, host, port);
\r
8606 return StartChildProcess(cmdLine, "", pr);
\r
8610 /* Code to open TCP sockets */
\r
8613 OpenTCP(char *host, char *port, ProcRef *pr)
\r
8618 struct sockaddr_in sa, mysa;
\r
8619 struct hostent FAR *hp;
\r
8620 unsigned short uport;
\r
8621 WORD wVersionRequested;
\r
8624 /* Initialize socket DLL */
\r
8625 wVersionRequested = MAKEWORD(1, 1);
\r
8626 err = WSAStartup(wVersionRequested, &wsaData);
\r
8627 if (err != 0) return err;
\r
8630 if ((s = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
\r
8631 err = WSAGetLastError();
\r
8636 /* Bind local address using (mostly) don't-care values.
\r
8638 memset((char *) &mysa, 0, sizeof(struct sockaddr_in));
\r
8639 mysa.sin_family = AF_INET;
\r
8640 mysa.sin_addr.s_addr = INADDR_ANY;
\r
8641 uport = (unsigned short) 0;
\r
8642 mysa.sin_port = htons(uport);
\r
8643 if (bind(s, (struct sockaddr *) &mysa, sizeof(struct sockaddr_in))
\r
8644 == SOCKET_ERROR) {
\r
8645 err = WSAGetLastError();
\r
8650 /* Resolve remote host name */
\r
8651 memset((char *) &sa, 0, sizeof(struct sockaddr_in));
\r
8652 if (!(hp = gethostbyname(host))) {
\r
8653 unsigned int b0, b1, b2, b3;
\r
8655 err = WSAGetLastError();
\r
8657 if (sscanf(host, "%u.%u.%u.%u", &b0, &b1, &b2, &b3) == 4) {
\r
8658 hp = (struct hostent *) calloc(1, sizeof(struct hostent));
\r
8659 hp->h_addrtype = AF_INET;
\r
8661 hp->h_addr_list = (char **) calloc(2, sizeof(char *));
\r
8662 hp->h_addr_list[0] = (char *) malloc(4);
\r
8663 hp->h_addr_list[0][0] = (char) b0;
\r
8664 hp->h_addr_list[0][1] = (char) b1;
\r
8665 hp->h_addr_list[0][2] = (char) b2;
\r
8666 hp->h_addr_list[0][3] = (char) b3;
\r
8672 sa.sin_family = hp->h_addrtype;
\r
8673 uport = (unsigned short) atoi(port);
\r
8674 sa.sin_port = htons(uport);
\r
8675 memcpy((char *) &sa.sin_addr, hp->h_addr, hp->h_length);
\r
8677 /* Make connection */
\r
8678 if (connect(s, (struct sockaddr *) &sa,
\r
8679 sizeof(struct sockaddr_in)) == SOCKET_ERROR) {
\r
8680 err = WSAGetLastError();
\r
8685 /* Prepare return value */
\r
8686 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
8687 cp->kind = CPSock;
\r
8689 *pr = (ProcRef *) cp;
\r
8695 OpenCommPort(char *name, ProcRef *pr)
\r
8700 char fullname[MSG_SIZ];
\r
8702 if (*name != '\\')
\r
8703 sprintf(fullname, "\\\\.\\%s", name);
\r
8705 strcpy(fullname, name);
\r
8707 h = CreateFile(name, GENERIC_READ | GENERIC_WRITE,
\r
8708 0, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
\r
8709 if (h == (HANDLE) -1) {
\r
8710 return GetLastError();
\r
8714 if (!SetCommState(h, (LPDCB) &dcb)) return GetLastError();
\r
8716 /* Accumulate characters until a 100ms pause, then parse */
\r
8717 ct.ReadIntervalTimeout = 100;
\r
8718 ct.ReadTotalTimeoutMultiplier = 0;
\r
8719 ct.ReadTotalTimeoutConstant = 0;
\r
8720 ct.WriteTotalTimeoutMultiplier = 0;
\r
8721 ct.WriteTotalTimeoutConstant = 0;
\r
8722 if (!SetCommTimeouts(h, (LPCOMMTIMEOUTS) &ct)) return GetLastError();
\r
8724 /* Prepare return value */
\r
8725 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
8726 cp->kind = CPComm;
\r
8729 *pr = (ProcRef *) cp;
\r
8735 OpenLoopback(ProcRef *pr)
\r
8737 DisplayFatalError("Not implemented", 0, 1);
\r
8743 OpenRcmd(char* host, char* user, char* cmd, ProcRef* pr)
\r
8748 struct sockaddr_in sa, mysa;
\r
8749 struct hostent FAR *hp;
\r
8750 unsigned short uport;
\r
8751 WORD wVersionRequested;
\r
8754 char stderrPortStr[MSG_SIZ];
\r
8756 /* Initialize socket DLL */
\r
8757 wVersionRequested = MAKEWORD(1, 1);
\r
8758 err = WSAStartup(wVersionRequested, &wsaData);
\r
8759 if (err != 0) return err;
\r
8761 /* Resolve remote host name */
\r
8762 memset((char *) &sa, 0, sizeof(struct sockaddr_in));
\r
8763 if (!(hp = gethostbyname(host))) {
\r
8764 unsigned int b0, b1, b2, b3;
\r
8766 err = WSAGetLastError();
\r
8768 if (sscanf(host, "%u.%u.%u.%u", &b0, &b1, &b2, &b3) == 4) {
\r
8769 hp = (struct hostent *) calloc(1, sizeof(struct hostent));
\r
8770 hp->h_addrtype = AF_INET;
\r
8772 hp->h_addr_list = (char **) calloc(2, sizeof(char *));
\r
8773 hp->h_addr_list[0] = (char *) malloc(4);
\r
8774 hp->h_addr_list[0][0] = (char) b0;
\r
8775 hp->h_addr_list[0][1] = (char) b1;
\r
8776 hp->h_addr_list[0][2] = (char) b2;
\r
8777 hp->h_addr_list[0][3] = (char) b3;
\r
8783 sa.sin_family = hp->h_addrtype;
\r
8784 uport = (unsigned short) 514;
\r
8785 sa.sin_port = htons(uport);
\r
8786 memcpy((char *) &sa.sin_addr, hp->h_addr, hp->h_length);
\r
8788 /* Bind local socket to unused "privileged" port address
\r
8790 s = INVALID_SOCKET;
\r
8791 memset((char *) &mysa, 0, sizeof(struct sockaddr_in));
\r
8792 mysa.sin_family = AF_INET;
\r
8793 mysa.sin_addr.s_addr = INADDR_ANY;
\r
8794 for (fromPort = 1023;; fromPort--) {
\r
8795 if (fromPort < 0) {
\r
8797 return WSAEADDRINUSE;
\r
8799 if (s == INVALID_SOCKET) {
\r
8800 if ((s = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
\r
8801 err = WSAGetLastError();
\r
8806 uport = (unsigned short) fromPort;
\r
8807 mysa.sin_port = htons(uport);
\r
8808 if (bind(s, (struct sockaddr *) &mysa, sizeof(struct sockaddr_in))
\r
8809 == SOCKET_ERROR) {
\r
8810 err = WSAGetLastError();
\r
8811 if (err == WSAEADDRINUSE) continue;
\r
8815 if (connect(s, (struct sockaddr *) &sa,
\r
8816 sizeof(struct sockaddr_in)) == SOCKET_ERROR) {
\r
8817 err = WSAGetLastError();
\r
8818 if (err == WSAEADDRINUSE) {
\r
8829 /* Bind stderr local socket to unused "privileged" port address
\r
8831 s2 = INVALID_SOCKET;
\r
8832 memset((char *) &mysa, 0, sizeof(struct sockaddr_in));
\r
8833 mysa.sin_family = AF_INET;
\r
8834 mysa.sin_addr.s_addr = INADDR_ANY;
\r
8835 for (fromPort = 1023;; fromPort--) {
\r
8836 if (fromPort == prevStderrPort) continue; // don't reuse port
\r
8837 if (fromPort < 0) {
\r
8838 (void) closesocket(s);
\r
8840 return WSAEADDRINUSE;
\r
8842 if (s2 == INVALID_SOCKET) {
\r
8843 if ((s2 = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
\r
8844 err = WSAGetLastError();
\r
8850 uport = (unsigned short) fromPort;
\r
8851 mysa.sin_port = htons(uport);
\r
8852 if (bind(s2, (struct sockaddr *) &mysa, sizeof(struct sockaddr_in))
\r
8853 == SOCKET_ERROR) {
\r
8854 err = WSAGetLastError();
\r
8855 if (err == WSAEADDRINUSE) continue;
\r
8856 (void) closesocket(s);
\r
8860 if (listen(s2, 1) == SOCKET_ERROR) {
\r
8861 err = WSAGetLastError();
\r
8862 if (err == WSAEADDRINUSE) {
\r
8864 s2 = INVALID_SOCKET;
\r
8867 (void) closesocket(s);
\r
8868 (void) closesocket(s2);
\r
8874 prevStderrPort = fromPort; // remember port used
\r
8875 sprintf(stderrPortStr, "%d", fromPort);
\r
8877 if (send(s, stderrPortStr, strlen(stderrPortStr) + 1, 0) == SOCKET_ERROR) {
\r
8878 err = WSAGetLastError();
\r
8879 (void) closesocket(s);
\r
8880 (void) closesocket(s2);
\r
8885 if (send(s, UserName(), strlen(UserName()) + 1, 0) == SOCKET_ERROR) {
\r
8886 err = WSAGetLastError();
\r
8887 (void) closesocket(s);
\r
8888 (void) closesocket(s2);
\r
8892 if (*user == NULLCHAR) user = UserName();
\r
8893 if (send(s, user, strlen(user) + 1, 0) == SOCKET_ERROR) {
\r
8894 err = WSAGetLastError();
\r
8895 (void) closesocket(s);
\r
8896 (void) closesocket(s2);
\r
8900 if (send(s, cmd, strlen(cmd) + 1, 0) == SOCKET_ERROR) {
\r
8901 err = WSAGetLastError();
\r
8902 (void) closesocket(s);
\r
8903 (void) closesocket(s2);
\r
8908 if ((s3 = accept(s2, NULL, NULL)) == INVALID_SOCKET) {
\r
8909 err = WSAGetLastError();
\r
8910 (void) closesocket(s);
\r
8911 (void) closesocket(s2);
\r
8915 (void) closesocket(s2); /* Stop listening */
\r
8917 /* Prepare return value */
\r
8918 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
8919 cp->kind = CPRcmd;
\r
8922 *pr = (ProcRef *) cp;
\r
8929 AddInputSource(ProcRef pr, int lineByLine,
\r
8930 InputCallback func, VOIDSTAR closure)
\r
8932 InputSource *is, *is2 = NULL;
\r
8933 ChildProc *cp = (ChildProc *) pr;
\r
8935 is = (InputSource *) calloc(1, sizeof(InputSource));
\r
8936 is->lineByLine = lineByLine;
\r
8938 is->closure = closure;
\r
8939 is->second = NULL;
\r
8940 is->next = is->buf;
\r
8941 if (pr == NoProc) {
\r
8942 is->kind = CPReal;
\r
8943 consoleInputSource = is;
\r
8945 is->kind = cp->kind;
\r
8947 [AS] Try to avoid a race condition if the thread is given control too early:
\r
8948 we create all threads suspended so that the is->hThread variable can be
\r
8949 safely assigned, then let the threads start with ResumeThread.
\r
8951 switch (cp->kind) {
\r
8953 is->hFile = cp->hFrom;
\r
8954 cp->hFrom = NULL; /* now owned by InputThread */
\r
8956 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) NonOvlInputThread,
\r
8957 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
8961 is->hFile = cp->hFrom;
\r
8962 cp->hFrom = NULL; /* now owned by InputThread */
\r
8964 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) InputThread,
\r
8965 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
8969 is->sock = cp->sock;
\r
8971 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SocketInputThread,
\r
8972 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
8976 is2 = (InputSource *) calloc(1, sizeof(InputSource));
\r
8978 is->sock = cp->sock;
\r
8980 is2->sock = cp->sock2;
\r
8981 is2->second = is2;
\r
8983 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SocketInputThread,
\r
8984 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
8986 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SocketInputThread,
\r
8987 (LPVOID) is2, CREATE_SUSPENDED, &is2->id);
\r
8991 if( is->hThread != NULL ) {
\r
8992 ResumeThread( is->hThread );
\r
8995 if( is2 != NULL && is2->hThread != NULL ) {
\r
8996 ResumeThread( is2->hThread );
\r
9000 return (InputSourceRef) is;
\r
9004 RemoveInputSource(InputSourceRef isr)
\r
9008 is = (InputSource *) isr;
\r
9009 is->hThread = NULL; /* tell thread to stop */
\r
9010 CloseHandle(is->hThread);
\r
9011 if (is->second != NULL) {
\r
9012 is->second->hThread = NULL;
\r
9013 CloseHandle(is->second->hThread);
\r
9017 int no_wrap(char *message, int count)
\r
9019 ConsoleOutput(message, count, FALSE);
\r
9024 OutputToProcess(ProcRef pr, char *message, int count, int *outError)
\r
9027 int outCount = SOCKET_ERROR;
\r
9028 ChildProc *cp = (ChildProc *) pr;
\r
9029 static OVERLAPPED ovl;
\r
9030 static int line = 0;
\r
9034 if (appData.noJoin || !appData.useInternalWrap)
\r
9035 return no_wrap(message, count);
\r
9038 int width = get_term_width();
\r
9039 int len = wrap(NULL, message, count, width, &line);
\r
9040 char *msg = malloc(len);
\r
9044 return no_wrap(message, count);
\r
9047 dbgchk = wrap(msg, message, count, width, &line);
\r
9048 if (dbgchk != len && appData.debugMode)
\r
9049 fprintf(debugFP, "wrap(): dbgchk(%d) != len(%d)\n", dbgchk, len);
\r
9050 ConsoleOutput(msg, len, FALSE);
\r
9057 if (ovl.hEvent == NULL) {
\r
9058 ovl.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
\r
9060 ovl.Internal = ovl.InternalHigh = ovl.Offset = ovl.OffsetHigh = 0;
\r
9062 switch (cp->kind) {
\r
9065 outCount = send(cp->sock, message, count, 0);
\r
9066 if (outCount == SOCKET_ERROR) {
\r
9067 *outError = WSAGetLastError();
\r
9069 *outError = NO_ERROR;
\r
9074 if (WriteFile(((ChildProc *)pr)->hTo, message, count,
\r
9075 &dOutCount, NULL)) {
\r
9076 *outError = NO_ERROR;
\r
9077 outCount = (int) dOutCount;
\r
9079 *outError = GetLastError();
\r
9084 *outError = DoWriteFile(((ChildProc *)pr)->hTo, message, count,
\r
9085 &dOutCount, &ovl);
\r
9086 if (*outError == NO_ERROR) {
\r
9087 outCount = (int) dOutCount;
\r
9095 OutputToProcessDelayed(ProcRef pr, char *message, int count, int *outError,
\r
9098 /* Ignore delay, not implemented for WinBoard */
\r
9099 return OutputToProcess(pr, message, count, outError);
\r
9104 CmailSigHandlerCallBack(InputSourceRef isr, VOIDSTAR closure,
\r
9105 char *buf, int count, int error)
\r
9107 DisplayFatalError("Not implemented", 0, 1);
\r
9110 /* see wgamelist.c for Game List functions */
\r
9111 /* see wedittags.c for Edit Tags functions */
\r
9118 char buf[MSG_SIZ];
\r
9121 if (SearchPath(installDir, appData.icsLogon, NULL, MSG_SIZ, buf, &dummy)) {
\r
9122 f = fopen(buf, "r");
\r
9124 ProcessICSInitScript(f);
\r
9132 StartAnalysisClock()
\r
9134 if (analysisTimerEvent) return;
\r
9135 analysisTimerEvent = SetTimer(hwndMain, (UINT) ANALYSIS_TIMER_ID,
\r
9136 (UINT) 2000, NULL);
\r
9140 SetHighlights(int fromX, int fromY, int toX, int toY)
\r
9142 highlightInfo.sq[0].x = fromX;
\r
9143 highlightInfo.sq[0].y = fromY;
\r
9144 highlightInfo.sq[1].x = toX;
\r
9145 highlightInfo.sq[1].y = toY;
\r
9151 highlightInfo.sq[0].x = highlightInfo.sq[0].y =
\r
9152 highlightInfo.sq[1].x = highlightInfo.sq[1].y = -1;
\r
9156 SetPremoveHighlights(int fromX, int fromY, int toX, int toY)
\r
9158 premoveHighlightInfo.sq[0].x = fromX;
\r
9159 premoveHighlightInfo.sq[0].y = fromY;
\r
9160 premoveHighlightInfo.sq[1].x = toX;
\r
9161 premoveHighlightInfo.sq[1].y = toY;
\r
9165 ClearPremoveHighlights()
\r
9167 premoveHighlightInfo.sq[0].x = premoveHighlightInfo.sq[0].y =
\r
9168 premoveHighlightInfo.sq[1].x = premoveHighlightInfo.sq[1].y = -1;
\r
9172 ShutDownFrontEnd()
\r
9174 if (saveSettingsOnExit) SaveSettings(settingsFileName);
\r
9175 DeleteClipboardTempFiles();
\r
9181 if (IsIconic(hwndMain))
\r
9182 ShowWindow(hwndMain, SW_RESTORE);
\r
9184 SetActiveWindow(hwndMain);
\r
9188 * Prototypes for animation support routines
\r
9190 static void ScreenSquare(int column, int row, POINT * pt);
\r
9191 static void Tween( POINT * start, POINT * mid, POINT * finish, int factor,
\r
9192 POINT frames[], int * nFrames);
\r
9196 AnimateAtomicCapture(int fromX, int fromY, int toX, int toY, int nFrames)
\r
9197 { // [HGM] atomic: animate blast wave
\r
9199 if(appData.debugMode) fprintf(debugFP, "exploding (%d,%d)\n", toX, toY);
\r
9200 explodeInfo.fromX = fromX;
\r
9201 explodeInfo.fromY = fromY;
\r
9202 explodeInfo.toX = toX;
\r
9203 explodeInfo.toY = toY;
\r
9204 for(i=1; i<nFrames; i++) {
\r
9205 explodeInfo.radius = (i*180)/(nFrames-1);
\r
9206 DrawPosition(FALSE, NULL);
\r
9207 Sleep(appData.animSpeed);
\r
9209 explodeInfo.radius = 0;
\r
9210 DrawPosition(TRUE, NULL);
\r
9216 AnimateMove(board, fromX, fromY, toX, toY)
\r
9223 ChessSquare piece;
\r
9224 POINT start, finish, mid;
\r
9225 POINT frames[kFactor * 2 + 1];
\r
9228 if (!appData.animate) return;
\r
9229 if (doingSizing) return;
\r
9230 if (fromY < 0 || fromX < 0) return;
\r
9231 piece = board[fromY][fromX];
\r
9232 if (piece >= EmptySquare) return;
\r
9234 ScreenSquare(fromX, fromY, &start);
\r
9235 ScreenSquare(toX, toY, &finish);
\r
9237 /* All pieces except knights move in straight line */
\r
9238 if (piece != WhiteKnight && piece != BlackKnight) {
\r
9239 mid.x = start.x + (finish.x - start.x) / 2;
\r
9240 mid.y = start.y + (finish.y - start.y) / 2;
\r
9242 /* Knight: make diagonal movement then straight */
\r
9243 if (abs(toY - fromY) < abs(toX - fromX)) {
\r
9244 mid.x = start.x + (finish.x - start.x) / 2;
\r
9248 mid.y = start.y + (finish.y - start.y) / 2;
\r
9252 /* Don't use as many frames for very short moves */
\r
9253 if (abs(toY - fromY) + abs(toX - fromX) <= 2)
\r
9254 Tween(&start, &mid, &finish, kFactor - 1, frames, &nFrames);
\r
9256 Tween(&start, &mid, &finish, kFactor, frames, &nFrames);
\r
9258 animInfo.from.x = fromX;
\r
9259 animInfo.from.y = fromY;
\r
9260 animInfo.to.x = toX;
\r
9261 animInfo.to.y = toY;
\r
9262 animInfo.lastpos = start;
\r
9263 animInfo.piece = piece;
\r
9264 for (n = 0; n < nFrames; n++) {
\r
9265 animInfo.pos = frames[n];
\r
9266 DrawPosition(FALSE, NULL);
\r
9267 animInfo.lastpos = animInfo.pos;
\r
9268 Sleep(appData.animSpeed);
\r
9270 animInfo.pos = finish;
\r
9271 DrawPosition(FALSE, NULL);
\r
9272 animInfo.piece = EmptySquare;
\r
9273 if(gameInfo.variant == VariantAtomic &&
\r
9274 (board[toY][toX] != EmptySquare || fromX != toX && (piece == WhitePawn || piece == BlackPawn) ) )
\r
9275 AnimateAtomicCapture(fromX, fromY, toX, toY, 2*nFrames);
\r
9278 /* Convert board position to corner of screen rect and color */
\r
9281 ScreenSquare(column, row, pt)
\r
9282 int column; int row; POINT * pt;
\r
9285 pt->x = lineGap + ((BOARD_WIDTH-1)-column) * (squareSize + lineGap);
\r
9286 pt->y = lineGap + row * (squareSize + lineGap);
\r
9288 pt->x = lineGap + column * (squareSize + lineGap);
\r
9289 pt->y = lineGap + ((BOARD_HEIGHT-1)-row) * (squareSize + lineGap);
\r
9293 /* Generate a series of frame coords from start->mid->finish.
\r
9294 The movement rate doubles until the half way point is
\r
9295 reached, then halves back down to the final destination,
\r
9296 which gives a nice slow in/out effect. The algorithmn
\r
9297 may seem to generate too many intermediates for short
\r
9298 moves, but remember that the purpose is to attract the
\r
9299 viewers attention to the piece about to be moved and
\r
9300 then to where it ends up. Too few frames would be less
\r
9304 Tween(start, mid, finish, factor, frames, nFrames)
\r
9305 POINT * start; POINT * mid;
\r
9306 POINT * finish; int factor;
\r
9307 POINT frames[]; int * nFrames;
\r
9309 int n, fraction = 1, count = 0;
\r
9311 /* Slow in, stepping 1/16th, then 1/8th, ... */
\r
9312 for (n = 0; n < factor; n++)
\r
9314 for (n = 0; n < factor; n++) {
\r
9315 frames[count].x = start->x + (mid->x - start->x) / fraction;
\r
9316 frames[count].y = start->y + (mid->y - start->y) / fraction;
\r
9318 fraction = fraction / 2;
\r
9322 frames[count] = *mid;
\r
9325 /* Slow out, stepping 1/2, then 1/4, ... */
\r
9327 for (n = 0; n < factor; n++) {
\r
9328 frames[count].x = finish->x - (finish->x - mid->x) / fraction;
\r
9329 frames[count].y = finish->y - (finish->y - mid->y) / fraction;
\r
9331 fraction = fraction * 2;
\r
9337 HistorySet( char movelist[][2*MOVE_LEN], int first, int last, int current )
\r
9339 MoveHistorySet( movelist, first, last, current, pvInfoList );
\r
9341 EvalGraphSet( first, last, current, pvInfoList );
\r