2 * WinBoard.c -- Windows NT front end to XBoard
\r
4 * Copyright 1991 by Digital Equipment Corporation, Maynard,
\r
7 * Enhancements Copyright 1992-2001, 2002, 2003, 2004, 2005, 2006,
\r
8 * 2007, 2008, 2009 Free Software Foundation, Inc.
\r
10 * Enhancements Copyright 2005 Alessandro Scotti
\r
12 * XBoard borrows its colors and the bitmaps.xchess bitmap set from XChess,
\r
13 * which was written and is copyrighted by Wayne Christopher.
\r
15 * The following terms apply to Digital Equipment Corporation's copyright
\r
16 * interest in XBoard:
\r
17 * ------------------------------------------------------------------------
\r
18 * All Rights Reserved
\r
20 * Permission to use, copy, modify, and distribute this software and its
\r
21 * documentation for any purpose and without fee is hereby granted,
\r
22 * provided that the above copyright notice appear in all copies and that
\r
23 * both that copyright notice and this permission notice appear in
\r
24 * supporting documentation, and that the name of Digital not be
\r
25 * used in advertising or publicity pertaining to distribution of the
\r
26 * software without specific, written prior permission.
\r
28 * DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
\r
29 * ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
\r
30 * DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
\r
31 * ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
\r
32 * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
\r
33 * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
\r
35 * ------------------------------------------------------------------------
\r
37 * The following terms apply to the enhanced version of XBoard
\r
38 * distributed by the Free Software Foundation:
\r
39 * ------------------------------------------------------------------------
\r
41 * GNU XBoard is free software: you can redistribute it and/or modify
\r
42 * it under the terms of the GNU General Public License as published by
\r
43 * the Free Software Foundation, either version 3 of the License, or (at
\r
44 * your option) any later version.
\r
46 * GNU XBoard is distributed in the hope that it will be useful, but
\r
47 * WITHOUT ANY WARRANTY; without even the implied warranty of
\r
48 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
\r
49 * General Public License for more details.
\r
51 * You should have received a copy of the GNU General Public License
\r
52 * along with this program. If not, see http://www.gnu.org/licenses/. *
\r
54 *------------------------------------------------------------------------
\r
55 ** See the file ChangeLog for a revision history. */
\r
59 #include <windows.h>
\r
60 #include <winuser.h>
\r
61 #include <winsock.h>
\r
62 #include <commctrl.h>
\r
68 #include <sys/stat.h>
\r
71 #include <commdlg.h>
\r
73 #include <richedit.h>
\r
74 #include <mmsystem.h>
\r
83 #include "frontend.h"
\r
84 #include "backend.h"
\r
85 #include "winboard.h"
\r
87 #include "wclipbrd.h"
\r
88 #include "woptions.h"
\r
89 #include "wsockerr.h"
\r
90 #include "defaults.h"
\r
94 //void InitEngineUCI( const char * iniDir, ChessProgramState * cps );
\r
97 void mysrandom(unsigned int seed);
\r
99 extern int whiteFlag, blackFlag;
\r
100 Boolean flipClock = FALSE;
\r
101 extern HANDLE chatHandle[];
\r
102 extern int ics_type;
\r
104 void DisplayHoldingsCount(HDC hdc, int x, int y, int align, int copyNumber);
\r
105 VOID NewVariantPopup(HWND hwnd);
\r
106 int FinishMove P((ChessMove moveType, int fromX, int fromY, int toX, int toY,
\r
107 /*char*/int promoChar));
\r
108 void AnimateAtomicCapture(int fromX, int fromY, int toX, int toY, int nFrames);
\r
109 void DisplayMove P((int moveNumber));
\r
110 Boolean ParseFEN P((Board board, int *blackPlaysFirst, char *fen));
\r
111 void ChatPopUp P(());
\r
113 ChessSquare piece;
\r
114 POINT pos; /* window coordinates of current pos */
\r
115 POINT lastpos; /* window coordinates of last pos - used for clipping */
\r
116 POINT from; /* board coordinates of the piece's orig pos */
\r
117 POINT to; /* board coordinates of the piece's new pos */
\r
120 static AnimInfo animInfo = { EmptySquare, {-1,-1}, {-1,-1}, {-1,-1} };
\r
123 POINT start; /* window coordinates of start pos */
\r
124 POINT pos; /* window coordinates of current pos */
\r
125 POINT lastpos; /* window coordinates of last pos - used for clipping */
\r
126 POINT from; /* board coordinates of the piece's orig pos */
\r
129 static DragInfo dragInfo = { {-1,-1}, {-1,-1}, {-1,-1}, {-1,-1} };
\r
132 POINT sq[2]; /* board coordinates of from, to squares */
\r
135 static HighlightInfo highlightInfo = { {{-1, -1}, {-1, -1}} };
\r
136 static HighlightInfo premoveHighlightInfo = { {{-1, -1}, {-1, -1}} };
\r
138 typedef struct { // [HGM] atomic
\r
139 int fromX, fromY, toX, toY, radius;
\r
142 static ExplodeInfo explodeInfo;
\r
144 /* Window class names */
\r
145 char szAppName[] = "WinBoard";
\r
146 char szConsoleName[] = "WBConsole";
\r
148 /* Title bar text */
\r
149 char szTitle[] = "WinBoard";
\r
150 char szConsoleTitle[] = "I C S Interaction";
\r
153 char *settingsFileName;
\r
154 Boolean saveSettingsOnExit;
\r
155 char installDir[MSG_SIZ];
\r
156 int errorExitStatus;
\r
158 BoardSize boardSize;
\r
159 Boolean chessProgram;
\r
160 //static int boardX, boardY;
\r
161 int minX, minY; // [HGM] placement: volatile limits on upper-left corner
\r
162 static int squareSize, lineGap, minorSize;
\r
163 static int winW, winH;
\r
164 static RECT messageRect, whiteRect, blackRect, leftLogoRect, rightLogoRect; // [HGM] logo
\r
165 static int logoHeight = 0;
\r
166 static char messageText[MESSAGE_TEXT_MAX];
\r
167 static int clockTimerEvent = 0;
\r
168 static int loadGameTimerEvent = 0;
\r
169 static int analysisTimerEvent = 0;
\r
170 static DelayedEventCallback delayedTimerCallback;
\r
171 static int delayedTimerEvent = 0;
\r
172 static int buttonCount = 2;
\r
173 char *icsTextMenuString;
\r
175 char *firstChessProgramNames;
\r
176 char *secondChessProgramNames;
\r
178 #define PALETTESIZE 256
\r
180 HINSTANCE hInst; /* current instance */
\r
181 Boolean alwaysOnTop = FALSE;
\r
183 COLORREF lightSquareColor, darkSquareColor, whitePieceColor,
\r
184 blackPieceColor, highlightSquareColor, premoveHighlightColor;
\r
186 ColorClass currentColorClass;
\r
188 HWND hCommPort = NULL; /* currently open comm port */
\r
189 static HWND hwndPause; /* pause button */
\r
190 static HBITMAP pieceBitmap[3][(int) BlackPawn]; /* [HGM] nr of bitmaps referred to bP in stead of wK */
\r
191 static HBRUSH lightSquareBrush, darkSquareBrush,
\r
192 blackSquareBrush, /* [HGM] for band between board and holdings */
\r
193 explodeBrush, /* [HGM] atomic */
\r
194 whitePieceBrush, blackPieceBrush, iconBkgndBrush /*, outlineBrush*/;
\r
195 static POINT gridEndpoints[(BOARD_RANKS + BOARD_FILES + 2) * 2];
\r
196 static DWORD gridVertexCounts[BOARD_RANKS + BOARD_FILES + 2];
\r
197 static HPEN gridPen = NULL;
\r
198 static HPEN highlightPen = NULL;
\r
199 static HPEN premovePen = NULL;
\r
200 static NPLOGPALETTE pLogPal;
\r
201 static BOOL paletteChanged = FALSE;
\r
202 static HICON iconWhite, iconBlack, iconCurrent;
\r
203 static int doingSizing = FALSE;
\r
204 static int lastSizing = 0;
\r
205 static int prevStderrPort;
\r
206 static HBITMAP userLogo;
\r
208 static HBITMAP liteBackTexture = NULL;
\r
209 static HBITMAP darkBackTexture = NULL;
\r
210 static int liteBackTextureMode = BACK_TEXTURE_MODE_PLAIN;
\r
211 static int darkBackTextureMode = BACK_TEXTURE_MODE_PLAIN;
\r
212 static int backTextureSquareSize = 0;
\r
213 static struct { int x; int y; int mode; } backTextureSquareInfo[BOARD_RANKS][BOARD_FILES];
\r
215 #if __GNUC__ && !defined(_winmajor)
\r
216 #define oldDialog 0 /* cygwin doesn't define _winmajor; mingw does */
\r
218 #if defined(_winmajor)
\r
219 #define oldDialog (_winmajor < 4)
\r
221 #define oldDialog 0
\r
231 int cliWidth, cliHeight;
\r
234 SizeInfo sizeInfo[] =
\r
236 { "tiny", 21, 0, 1, 1, 0, 0 },
\r
237 { "teeny", 25, 1, 1, 1, 0, 0 },
\r
238 { "dinky", 29, 1, 1, 1, 0, 0 },
\r
239 { "petite", 33, 1, 1, 1, 0, 0 },
\r
240 { "slim", 37, 2, 1, 0, 0, 0 },
\r
241 { "small", 40, 2, 1, 0, 0, 0 },
\r
242 { "mediocre", 45, 2, 1, 0, 0, 0 },
\r
243 { "middling", 49, 2, 0, 0, 0, 0 },
\r
244 { "average", 54, 2, 0, 0, 0, 0 },
\r
245 { "moderate", 58, 3, 0, 0, 0, 0 },
\r
246 { "medium", 64, 3, 0, 0, 0, 0 },
\r
247 { "bulky", 72, 3, 0, 0, 0, 0 },
\r
248 { "large", 80, 3, 0, 0, 0, 0 },
\r
249 { "big", 87, 3, 0, 0, 0, 0 },
\r
250 { "huge", 95, 3, 0, 0, 0, 0 },
\r
251 { "giant", 108, 3, 0, 0, 0, 0 },
\r
252 { "colossal", 116, 4, 0, 0, 0, 0 },
\r
253 { "titanic", 129, 4, 0, 0, 0, 0 },
\r
254 { NULL, 0, 0, 0, 0, 0, 0 }
\r
257 #define MF(x) {x, {{0,}, 0. }, {0, }, 0}
\r
258 MyFont fontRec[NUM_SIZES][NUM_FONTS] =
\r
260 { MF(CLOCK_FONT_TINY), MF(MESSAGE_FONT_TINY), MF(COORD_FONT_TINY), MF(CONSOLE_FONT_TINY), MF(COMMENT_FONT_TINY), MF(EDITTAGS_FONT_TINY), MF(MOVEHISTORY_FONT_ALL) },
\r
261 { MF(CLOCK_FONT_TEENY), MF(MESSAGE_FONT_TEENY), MF(COORD_FONT_TEENY), MF(CONSOLE_FONT_TEENY), MF(COMMENT_FONT_TEENY), MF(EDITTAGS_FONT_TEENY), MF(MOVEHISTORY_FONT_ALL) },
\r
262 { MF(CLOCK_FONT_DINKY), MF(MESSAGE_FONT_DINKY), MF(COORD_FONT_DINKY), MF(CONSOLE_FONT_DINKY), MF(COMMENT_FONT_DINKY), MF(EDITTAGS_FONT_DINKY), MF(MOVEHISTORY_FONT_ALL) },
\r
263 { MF(CLOCK_FONT_PETITE), MF(MESSAGE_FONT_PETITE), MF(COORD_FONT_PETITE), MF(CONSOLE_FONT_PETITE), MF(COMMENT_FONT_PETITE), MF(EDITTAGS_FONT_PETITE), MF(MOVEHISTORY_FONT_ALL) },
\r
264 { MF(CLOCK_FONT_SLIM), MF(MESSAGE_FONT_SLIM), MF(COORD_FONT_SLIM), MF(CONSOLE_FONT_SLIM), MF(COMMENT_FONT_SLIM), MF(EDITTAGS_FONT_SLIM), MF(MOVEHISTORY_FONT_ALL) },
\r
265 { MF(CLOCK_FONT_SMALL), MF(MESSAGE_FONT_SMALL), MF(COORD_FONT_SMALL), MF(CONSOLE_FONT_SMALL), MF(COMMENT_FONT_SMALL), MF(EDITTAGS_FONT_SMALL), MF(MOVEHISTORY_FONT_ALL) },
\r
266 { MF(CLOCK_FONT_MEDIOCRE), MF(MESSAGE_FONT_MEDIOCRE), MF(COORD_FONT_MEDIOCRE), MF(CONSOLE_FONT_MEDIOCRE), MF(COMMENT_FONT_MEDIOCRE), MF(EDITTAGS_FONT_MEDIOCRE), MF(MOVEHISTORY_FONT_ALL) },
\r
267 { MF(CLOCK_FONT_MIDDLING), MF(MESSAGE_FONT_MIDDLING), MF(COORD_FONT_MIDDLING), MF(CONSOLE_FONT_MIDDLING), MF(COMMENT_FONT_MIDDLING), MF(EDITTAGS_FONT_MIDDLING), MF(MOVEHISTORY_FONT_ALL) },
\r
268 { MF(CLOCK_FONT_AVERAGE), MF(MESSAGE_FONT_AVERAGE), MF(COORD_FONT_AVERAGE), MF(CONSOLE_FONT_AVERAGE), MF(COMMENT_FONT_AVERAGE), MF(EDITTAGS_FONT_AVERAGE), MF(MOVEHISTORY_FONT_ALL) },
\r
269 { MF(CLOCK_FONT_MODERATE), MF(MESSAGE_FONT_MODERATE), MF(COORD_FONT_MODERATE), MF(CONSOLE_FONT_MODERATE), MF(COMMENT_FONT_MODERATE), MF(EDITTAGS_FONT_MODERATE), MF(MOVEHISTORY_FONT_ALL) },
\r
270 { MF(CLOCK_FONT_MEDIUM), MF(MESSAGE_FONT_MEDIUM), MF(COORD_FONT_MEDIUM), MF(CONSOLE_FONT_MEDIUM), MF(COMMENT_FONT_MEDIUM), MF(EDITTAGS_FONT_MEDIUM), MF(MOVEHISTORY_FONT_ALL) },
\r
271 { MF(CLOCK_FONT_BULKY), MF(MESSAGE_FONT_BULKY), MF(COORD_FONT_BULKY), MF(CONSOLE_FONT_BULKY), MF(COMMENT_FONT_BULKY), MF(EDITTAGS_FONT_BULKY), MF(MOVEHISTORY_FONT_ALL) },
\r
272 { MF(CLOCK_FONT_LARGE), MF(MESSAGE_FONT_LARGE), MF(COORD_FONT_LARGE), MF(CONSOLE_FONT_LARGE), MF(COMMENT_FONT_LARGE), MF(EDITTAGS_FONT_LARGE), MF(MOVEHISTORY_FONT_ALL) },
\r
273 { MF(CLOCK_FONT_BIG), MF(MESSAGE_FONT_BIG), MF(COORD_FONT_BIG), MF(CONSOLE_FONT_BIG), MF(COMMENT_FONT_BIG), MF(EDITTAGS_FONT_BIG), MF(MOVEHISTORY_FONT_ALL) },
\r
274 { MF(CLOCK_FONT_HUGE), MF(MESSAGE_FONT_HUGE), MF(COORD_FONT_HUGE), MF(CONSOLE_FONT_HUGE), MF(COMMENT_FONT_HUGE), MF(EDITTAGS_FONT_HUGE), MF(MOVEHISTORY_FONT_ALL) },
\r
275 { MF(CLOCK_FONT_GIANT), MF(MESSAGE_FONT_GIANT), MF(COORD_FONT_GIANT), MF(CONSOLE_FONT_GIANT), MF(COMMENT_FONT_GIANT), MF(EDITTAGS_FONT_GIANT), MF(MOVEHISTORY_FONT_ALL) },
\r
276 { MF(CLOCK_FONT_COLOSSAL), MF(MESSAGE_FONT_COLOSSAL), MF(COORD_FONT_COLOSSAL), MF(CONSOLE_FONT_COLOSSAL), MF(COMMENT_FONT_COLOSSAL), MF(EDITTAGS_FONT_COLOSSAL), MF(MOVEHISTORY_FONT_ALL) },
\r
277 { MF(CLOCK_FONT_TITANIC), MF(MESSAGE_FONT_TITANIC), MF(COORD_FONT_TITANIC), MF(CONSOLE_FONT_TITANIC), MF(COMMENT_FONT_TITANIC), MF(EDITTAGS_FONT_TITANIC), MF(MOVEHISTORY_FONT_ALL) },
\r
280 MyFont *font[NUM_SIZES][NUM_FONTS];
\r
289 #define BUTTON_WIDTH (tinyLayout ? 16 : 32)
\r
290 #define N_BUTTONS 5
\r
292 MyButtonDesc buttonDesc[N_BUTTONS] =
\r
294 {"<<", IDM_ToStart, NULL, NULL},
\r
295 {"<", IDM_Backward, NULL, NULL},
\r
296 {"P", IDM_Pause, NULL, NULL},
\r
297 {">", IDM_Forward, NULL, NULL},
\r
298 {">>", IDM_ToEnd, NULL, NULL},
\r
301 int tinyLayout = 0, smallLayout = 0;
\r
302 #define MENU_BAR_ITEMS 7
\r
303 char *menuBarText[2][MENU_BAR_ITEMS+1] = {
\r
304 { "&File", "&Mode", "&Action", "&Step", "&Options", "&Help", NULL },
\r
305 { "&F", "&M", "&A", "&S", "&O", "&H", NULL },
\r
309 MySound sounds[(int)NSoundClasses];
\r
310 MyTextAttribs textAttribs[(int)NColorClasses];
\r
312 MyColorizeAttribs colorizeAttribs[] = {
\r
313 { (COLORREF)0, 0, "Shout Text" },
\r
314 { (COLORREF)0, 0, "SShout/CShout" },
\r
315 { (COLORREF)0, 0, "Channel 1 Text" },
\r
316 { (COLORREF)0, 0, "Channel Text" },
\r
317 { (COLORREF)0, 0, "Kibitz Text" },
\r
318 { (COLORREF)0, 0, "Tell Text" },
\r
319 { (COLORREF)0, 0, "Challenge Text" },
\r
320 { (COLORREF)0, 0, "Request Text" },
\r
321 { (COLORREF)0, 0, "Seek Text" },
\r
322 { (COLORREF)0, 0, "Normal Text" },
\r
323 { (COLORREF)0, 0, "None" }
\r
328 static char *commentTitle;
\r
329 static char *commentText;
\r
330 static int commentIndex;
\r
331 static Boolean editComment = FALSE;
\r
334 char errorTitle[MSG_SIZ];
\r
335 char errorMessage[2*MSG_SIZ];
\r
336 HWND errorDialog = NULL;
\r
337 BOOLEAN moveErrorMessageUp = FALSE;
\r
338 BOOLEAN consoleEcho = TRUE;
\r
339 CHARFORMAT consoleCF;
\r
340 COLORREF consoleBackgroundColor;
\r
342 char *programVersion;
\r
348 typedef int CPKind;
\r
357 SOCKET sock2; /* stderr socket for OpenRcmd */
\r
360 #define INPUT_SOURCE_BUF_SIZE 4096
\r
362 typedef struct _InputSource {
\r
369 char buf[INPUT_SOURCE_BUF_SIZE];
\r
373 InputCallback func;
\r
374 struct _InputSource *second; /* for stderr thread on CPRcmd */
\r
378 InputSource *consoleInputSource;
\r
383 VOID ConsoleOutput(char* data, int length, int forceVisible);
\r
384 VOID ConsoleCreate();
\r
386 ConsoleWndProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);
\r
387 VOID ColorizeTextPopup(HWND hwnd, ColorClass cc);
\r
388 VOID PrintCommSettings(FILE *f, char *name, DCB *dcb);
\r
389 VOID ParseCommSettings(char *arg, DCB *dcb);
\r
391 StartupDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);
\r
392 VOID APIENTRY MenuPopup(HWND hwnd, POINT pt, HMENU hmenu, UINT def);
\r
393 void ParseIcsTextMenu(char *icsTextMenuString);
\r
394 VOID PopUpMoveDialog(char firstchar);
\r
395 VOID PopUpNameDialog(char firstchar);
\r
396 VOID UpdateSampleText(HWND hDlg, int id, MyColorizeAttribs *mca);
\r
400 int GameListOptions();
\r
402 int dummy; // [HGM] for obsolete args
\r
404 HWND hwndMain = NULL; /* root window*/
\r
405 HWND hwndConsole = NULL;
\r
406 HWND commentDialog = NULL;
\r
407 HWND moveHistoryDialog = NULL;
\r
408 HWND evalGraphDialog = NULL;
\r
409 HWND engineOutputDialog = NULL;
\r
410 HWND gameListDialog = NULL;
\r
411 HWND editTagsDialog = NULL;
\r
413 int commentUp = FALSE;
\r
415 WindowPlacement wpMain;
\r
416 WindowPlacement wpConsole;
\r
417 WindowPlacement wpComment;
\r
418 WindowPlacement wpMoveHistory;
\r
419 WindowPlacement wpEvalGraph;
\r
420 WindowPlacement wpEngineOutput;
\r
421 WindowPlacement wpGameList;
\r
422 WindowPlacement wpTags;
\r
424 VOID EngineOptionsPopup(); // [HGM] settings
\r
426 VOID GothicPopUp(char *title, VariantClass variant);
\r
428 * Setting "frozen" should disable all user input other than deleting
\r
429 * the window. We do this while engines are initializing themselves.
\r
431 static int frozen = 0;
\r
432 static int oldMenuItemState[MENU_BAR_ITEMS];
\r
438 if (frozen) return;
\r
440 hmenu = GetMenu(hwndMain);
\r
441 for (i=0; i<MENU_BAR_ITEMS; i++) {
\r
442 oldMenuItemState[i] = EnableMenuItem(hmenu, i, MF_BYPOSITION|MF_GRAYED);
\r
444 DrawMenuBar(hwndMain);
\r
447 /* Undo a FreezeUI */
\r
453 if (!frozen) return;
\r
455 hmenu = GetMenu(hwndMain);
\r
456 for (i=0; i<MENU_BAR_ITEMS; i++) {
\r
457 EnableMenuItem(hmenu, i, MF_BYPOSITION|oldMenuItemState[i]);
\r
459 DrawMenuBar(hwndMain);
\r
462 /*static*/ int fromX = -1, fromY = -1, toX, toY; // [HGM] moved upstream, so JAWS can use them
\r
464 /* JAWS preparation patch (WinBoard for the sight impaired). Define required insertions as empty */
\r
470 #define JAWS_ALT_INTERCEPT
\r
471 #define JAWS_KB_NAVIGATION
\r
472 #define JAWS_MENU_ITEMS
\r
473 #define JAWS_SILENCE
\r
474 #define JAWS_REPLAY
\r
476 #define JAWS_COPYRIGHT
\r
477 #define JAWS_DELETE(X) X
\r
478 #define SAYMACHINEMOVE()
\r
482 /*---------------------------------------------------------------------------*\
\r
486 \*---------------------------------------------------------------------------*/
\r
489 WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
\r
490 LPSTR lpCmdLine, int nCmdShow)
\r
493 HANDLE hAccelMain, hAccelNoAlt, hAccelNoICS;
\r
494 // INITCOMMONCONTROLSEX ex;
\r
498 LoadLibrary("RICHED32.DLL");
\r
499 consoleCF.cbSize = sizeof(CHARFORMAT);
\r
501 if (!InitApplication(hInstance)) {
\r
504 if (!InitInstance(hInstance, nCmdShow, lpCmdLine)) {
\r
510 // InitCommonControlsEx(&ex);
\r
511 InitCommonControls();
\r
513 hAccelMain = LoadAccelerators (hInstance, szAppName);
\r
514 hAccelNoAlt = LoadAccelerators (hInstance, "NO_ALT");
\r
515 hAccelNoICS = LoadAccelerators( hInstance, "NO_ICS"); /* [AS] No Ctrl-V on ICS!!! */
\r
517 /* Acquire and dispatch messages until a WM_QUIT message is received. */
\r
519 while (GetMessage(&msg, /* message structure */
\r
520 NULL, /* handle of window receiving the message */
\r
521 0, /* lowest message to examine */
\r
522 0)) /* highest message to examine */
\r
525 if(msg.message == WM_CHAR && msg.wParam == '\t') {
\r
526 // [HGM] navigate: switch between all windows with tab
\r
527 HWND e1 = NULL, e2 = NULL, mh = NULL, hInput = NULL, hText = NULL;
\r
528 int i, currentElement = 0;
\r
530 // first determine what element of the chain we come from (if any)
\r
531 if(appData.icsActive) {
\r
532 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
533 hText = GetDlgItem(hwndConsole, OPT_ConsoleText);
\r
535 if(engineOutputDialog && EngineOutputIsUp()) {
\r
536 e1 = GetDlgItem(engineOutputDialog, IDC_EngineMemo1);
\r
537 e2 = GetDlgItem(engineOutputDialog, IDC_EngineMemo2);
\r
539 if(moveHistoryDialog && MoveHistoryIsUp()) {
\r
540 mh = GetDlgItem(moveHistoryDialog, IDC_MoveHistory);
\r
542 if(msg.hwnd == hwndMain) currentElement = 7 ; else
\r
543 if(msg.hwnd == engineOutputDialog) currentElement = 2; else
\r
544 if(msg.hwnd == e1) currentElement = 2; else
\r
545 if(msg.hwnd == e2) currentElement = 3; else
\r
546 if(msg.hwnd == moveHistoryDialog) currentElement = 4; else
\r
547 if(msg.hwnd == mh) currentElement = 4; else
\r
548 if(msg.hwnd == evalGraphDialog) currentElement = 6; else
\r
549 if(msg.hwnd == hText) currentElement = 5; else
\r
550 if(msg.hwnd == hInput) currentElement = 6; else
\r
551 for (i = 0; i < N_BUTTONS; i++) {
\r
552 if (buttonDesc[i].hwnd == msg.hwnd) { currentElement = 1; break; }
\r
555 // determine where to go to
\r
556 if(currentElement) { HWND h = NULL; int direction = GetKeyState(VK_SHIFT) < 0 ? -1 : 1;
\r
558 currentElement = (currentElement + direction) % 7;
\r
559 switch(currentElement) {
\r
561 h = hwndMain; break; // passing this case always makes the loop exit
\r
563 h = buttonDesc[0].hwnd; break; // could be NULL
\r
565 if(!EngineOutputIsUp()) continue; // skip closed auxiliary windows
\r
568 if(!EngineOutputIsUp()) continue;
\r
571 if(!MoveHistoryIsUp()) continue;
\r
573 // case 6: // input to eval graph does not seem to get here!
\r
574 // if(!EvalGraphIsUp()) continue;
\r
575 // h = evalGraphDialog; break;
\r
577 if(!appData.icsActive) continue;
\r
581 if(!appData.icsActive) continue;
\r
587 if(currentElement > 4 && IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
588 if(currentElement < 5 && IsIconic(hwndMain)) ShowWindow(hwndMain, SW_RESTORE); // all open together
\r
591 continue; // this message now has been processed
\r
595 if (!(commentDialog && IsDialogMessage(commentDialog, &msg)) &&
\r
596 !(moveHistoryDialog && IsDialogMessage(moveHistoryDialog, &msg)) &&
\r
597 !(evalGraphDialog && IsDialogMessage(evalGraphDialog, &msg)) &&
\r
598 !(engineOutputDialog && IsDialogMessage(engineOutputDialog, &msg)) &&
\r
599 !(editTagsDialog && IsDialogMessage(editTagsDialog, &msg)) &&
\r
600 !(gameListDialog && IsDialogMessage(gameListDialog, &msg)) &&
\r
601 !(errorDialog && IsDialogMessage(errorDialog, &msg)) &&
\r
602 !(!frozen && TranslateAccelerator(hwndMain, hAccelMain, &msg)) && JAWS_ACCEL
\r
603 !(!hwndConsole && TranslateAccelerator(hwndMain, hAccelNoICS, &msg)) &&
\r
604 !(!hwndConsole && TranslateAccelerator(hwndMain, hAccelNoAlt, &msg))) {
\r
605 int done = 0, i; // [HGM] chat: dispatch cat-box messages
\r
606 for(i=0; i<MAX_CHAT; i++)
\r
607 if(chatHandle[i] && IsDialogMessage(chatHandle[i], &msg)) {
\r
610 if(done) continue; // [HGM] chat: end patch
\r
611 TranslateMessage(&msg); /* Translates virtual key codes */
\r
612 DispatchMessage(&msg); /* Dispatches message to window */
\r
617 return (msg.wParam); /* Returns the value from PostQuitMessage */
\r
620 /*---------------------------------------------------------------------------*\
\r
622 * Initialization functions
\r
624 \*---------------------------------------------------------------------------*/
\r
628 { // update user logo if necessary
\r
629 static char oldUserName[MSG_SIZ], *curName;
\r
631 if(appData.autoLogo) {
\r
632 curName = UserName();
\r
633 if(strcmp(curName, oldUserName)) {
\r
634 sprintf(oldUserName, "logos\\%s.bmp", curName);
\r
635 userLogo = LoadImage( 0, oldUserName, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
636 strcpy(oldUserName, curName);
\r
642 InitApplication(HINSTANCE hInstance)
\r
646 /* Fill in window class structure with parameters that describe the */
\r
649 wc.style = CS_HREDRAW | CS_VREDRAW; /* Class style(s). */
\r
650 wc.lpfnWndProc = (WNDPROC)WndProc; /* Window Procedure */
\r
651 wc.cbClsExtra = 0; /* No per-class extra data. */
\r
652 wc.cbWndExtra = 0; /* No per-window extra data. */
\r
653 wc.hInstance = hInstance; /* Owner of this class */
\r
654 wc.hIcon = LoadIcon(hInstance, "icon_white");
\r
655 wc.hCursor = LoadCursor(NULL, IDC_ARROW); /* Cursor */
\r
656 wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1); /* Default color */
\r
657 wc.lpszMenuName = szAppName; /* Menu name from .RC */
\r
658 wc.lpszClassName = szAppName; /* Name to register as */
\r
660 /* Register the window class and return success/failure code. */
\r
661 if (!RegisterClass(&wc)) return FALSE;
\r
663 wc.style = CS_HREDRAW | CS_VREDRAW;
\r
664 wc.lpfnWndProc = (WNDPROC)ConsoleWndProc;
\r
666 wc.cbWndExtra = DLGWINDOWEXTRA;
\r
667 wc.hInstance = hInstance;
\r
668 wc.hIcon = LoadIcon(hInstance, "icon_white");
\r
669 wc.hCursor = LoadCursor(NULL, IDC_ARROW);
\r
670 wc.hbrBackground = (HBRUSH)(COLOR_MENU+1);
\r
671 wc.lpszMenuName = NULL;
\r
672 wc.lpszClassName = szConsoleName;
\r
674 if (!RegisterClass(&wc)) return FALSE;
\r
679 /* Set by InitInstance, used by EnsureOnScreen */
\r
680 int screenHeight, screenWidth;
\r
683 EnsureOnScreen(int *x, int *y, int minX, int minY)
\r
685 // int gap = GetSystemMetrics(SM_CYFRAME) + GetSystemMetrics(SM_CYCAPTION);
\r
686 /* Be sure window at (x,y) is not off screen (or even mostly off screen) */
\r
687 if (*x > screenWidth - 32) *x = 0;
\r
688 if (*y > screenHeight - 32) *y = 0;
\r
689 if (*x < minX) *x = minX;
\r
690 if (*y < minY) *y = minY;
\r
694 InitInstance(HINSTANCE hInstance, int nCmdShow, LPSTR lpCmdLine)
\r
696 HWND hwnd; /* Main window handle. */
\r
698 WINDOWPLACEMENT wp;
\r
701 hInst = hInstance; /* Store instance handle in our global variable */
\r
702 programName = szAppName;
\r
704 if (SearchPath(NULL, "WinBoard.exe", NULL, MSG_SIZ, installDir, &filepart)) {
\r
705 *filepart = NULLCHAR;
\r
707 GetCurrentDirectory(MSG_SIZ, installDir);
\r
709 gameInfo.boardWidth = gameInfo.boardHeight = 8; // [HGM] won't have open window otherwise
\r
710 screenWidth = screenHeight = 1000; // [HGM] placement: kludge to allow calling EnsureOnScreen from InitAppData
\r
711 InitAppData(lpCmdLine); /* Get run-time parameters */
\r
712 /* xboard, and older WinBoards, controlled the move sound with the
\r
713 appData.ringBellAfterMoves option. In the current WinBoard, we
\r
714 always turn the option on (so that the backend will call us),
\r
715 then let the user turn the sound off by setting it to silence if
\r
716 desired. To accommodate old winboard.ini files saved by old
\r
717 versions of WinBoard, we also turn off the sound if the option
\r
718 was initially set to false. [HGM] taken out of InitAppData */
\r
719 if (!appData.ringBellAfterMoves) {
\r
720 sounds[(int)SoundMove].name = strdup("");
\r
721 appData.ringBellAfterMoves = TRUE;
\r
723 if (appData.debugMode) {
\r
724 debugFP = fopen(appData.nameOfDebugFile, "w");
\r
725 setbuf(debugFP, NULL);
\r
730 // InitEngineUCI( installDir, &first ); // [HGM] incorporated in InitBackEnd1()
\r
731 // InitEngineUCI( installDir, &second );
\r
733 /* Create a main window for this application instance. */
\r
734 hwnd = CreateWindow(szAppName, szTitle,
\r
735 (WS_OVERLAPPEDWINDOW & ~WS_MAXIMIZEBOX),
\r
736 CW_USEDEFAULT, 0, CW_USEDEFAULT, 0,
\r
737 NULL, NULL, hInstance, NULL);
\r
740 /* If window could not be created, return "failure" */
\r
745 /* [HGM] logo: Load logos if specified (must be done before InitDrawingSizes) */
\r
746 if( appData.firstLogo && appData.firstLogo[0] != NULLCHAR) {
\r
747 first.programLogo = LoadImage( 0, appData.firstLogo, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
749 if (first.programLogo == NULL && appData.debugMode) {
\r
750 fprintf( debugFP, "Unable to load logo bitmap '%s'\n", appData.firstLogo );
\r
752 } else if(appData.autoLogo) {
\r
753 if(appData.firstDirectory && appData.firstDirectory[0]) {
\r
755 sprintf(buf, "%s/logo.bmp", appData.firstDirectory);
\r
756 first.programLogo = LoadImage( 0, buf, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
760 if( appData.secondLogo && appData.secondLogo[0] != NULLCHAR) {
\r
761 second.programLogo = LoadImage( 0, appData.secondLogo, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
763 if (second.programLogo == NULL && appData.debugMode) {
\r
764 fprintf( debugFP, "Unable to load logo bitmap '%s'\n", appData.secondLogo );
\r
766 } else if(appData.autoLogo) {
\r
768 if(appData.icsActive) { // [HGM] logo: in ICS mode second can be used for ICS
\r
769 sprintf(buf, "logos\\%s.bmp", appData.icsHost);
\r
770 second.programLogo = LoadImage( 0, buf, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
772 if(appData.secondDirectory && appData.secondDirectory[0]) {
\r
773 sprintf(buf, "%s\\logo.bmp", appData.secondDirectory);
\r
774 second.programLogo = LoadImage( 0, buf, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
780 iconWhite = LoadIcon(hInstance, "icon_white");
\r
781 iconBlack = LoadIcon(hInstance, "icon_black");
\r
782 iconCurrent = iconWhite;
\r
783 InitDrawingColors();
\r
784 screenHeight = GetSystemMetrics(SM_CYSCREEN);
\r
785 screenWidth = GetSystemMetrics(SM_CXSCREEN);
\r
786 for (ibs = (int) NUM_SIZES - 1; ibs >= 0; ibs--) {
\r
787 /* Compute window size for each board size, and use the largest
\r
788 size that fits on this screen as the default. */
\r
789 InitDrawingSizes((BoardSize)(ibs+1000), 0);
\r
790 if (boardSize == (BoardSize)-1 &&
\r
791 winH <= screenHeight
\r
792 - GetSystemMetrics(SM_CYFRAME) - GetSystemMetrics(SM_CYCAPTION) - 10
\r
793 && winW <= screenWidth) {
\r
794 boardSize = (BoardSize)ibs;
\r
798 InitDrawingSizes(boardSize, 0);
\r
800 buttonCount = GetSystemMetrics(SM_CMOUSEBUTTONS);
\r
802 /* [AS] Load textures if specified */
\r
803 ZeroMemory( &backTextureSquareInfo, sizeof(backTextureSquareInfo) );
\r
805 if( appData.liteBackTextureFile && appData.liteBackTextureFile[0] != NULLCHAR && appData.liteBackTextureFile[0] != '*' ) {
\r
806 liteBackTexture = LoadImage( 0, appData.liteBackTextureFile, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
807 liteBackTextureMode = appData.liteBackTextureMode;
\r
809 if (liteBackTexture == NULL && appData.debugMode) {
\r
810 fprintf( debugFP, "Unable to load lite texture bitmap '%s'\n", appData.liteBackTextureFile );
\r
814 if( appData.darkBackTextureFile && appData.darkBackTextureFile[0] != NULLCHAR && appData.darkBackTextureFile[0] != '*' ) {
\r
815 darkBackTexture = LoadImage( 0, appData.darkBackTextureFile, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
816 darkBackTextureMode = appData.darkBackTextureMode;
\r
818 if (darkBackTexture == NULL && appData.debugMode) {
\r
819 fprintf( debugFP, "Unable to load dark texture bitmap '%s'\n", appData.darkBackTextureFile );
\r
823 mysrandom( (unsigned) time(NULL) );
\r
825 /* [AS] Restore layout */
\r
826 if( wpMoveHistory.visible ) {
\r
827 MoveHistoryPopUp();
\r
830 if( wpEvalGraph.visible ) {
\r
834 if( wpEngineOutput.visible ) {
\r
835 EngineOutputPopUp();
\r
840 /* Make the window visible; update its client area; and return "success" */
\r
841 EnsureOnScreen(&wpMain.x, &wpMain.y, minX, minY);
\r
842 wp.length = sizeof(WINDOWPLACEMENT);
\r
844 wp.showCmd = nCmdShow;
\r
845 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
846 wp.rcNormalPosition.left = wpMain.x;
\r
847 wp.rcNormalPosition.right = wpMain.x + wpMain.width;
\r
848 wp.rcNormalPosition.top = wpMain.y;
\r
849 wp.rcNormalPosition.bottom = wpMain.y + wpMain.height;
\r
850 SetWindowPlacement(hwndMain, &wp);
\r
852 if(!appData.noGUI) SetWindowPos(hwndMain, alwaysOnTop ? HWND_TOPMOST : HWND_NOTOPMOST,
\r
853 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE);
\r
857 SetWindowPos(hwndConsole, alwaysOnTop ? HWND_TOPMOST : HWND_NOTOPMOST,
\r
858 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE);
\r
860 ShowWindow(hwndConsole, nCmdShow);
\r
862 if(!appData.noGUI) UpdateWindow(hwnd); else ShowWindow(hwnd, SW_MINIMIZE);
\r
863 if(gameListDialog) SetFocus(gameListDialog); // [HGM] jaws: for if we clicked multi-game game file
\r
872 HMENU hmenu = GetMenu(hwndMain);
\r
874 (void) EnableMenuItem(hmenu, IDM_CommPort,
\r
875 MF_BYCOMMAND|((appData.icsActive &&
\r
876 *appData.icsCommPort != NULLCHAR) ?
\r
877 MF_ENABLED : MF_GRAYED));
\r
878 (void) CheckMenuItem(hmenu, IDM_SaveSettingsOnExit,
\r
879 MF_BYCOMMAND|(saveSettingsOnExit ?
\r
880 MF_CHECKED : MF_UNCHECKED));
\r
883 //---------------------------------------------------------------------------------------------------------
\r
885 #define ICS_TEXT_MENU_SIZE (IDM_CommandXLast - IDM_CommandX + 1)
\r
886 #define XBOARD FALSE
\r
888 #define OPTCHAR "/"
\r
889 #define SEPCHAR "="
\r
893 // front-end part of option handling
\r
896 LFfromMFP(LOGFONT* lf, MyFontParams *mfp)
\r
898 HDC hdc = CreateDC("DISPLAY", NULL, NULL, NULL);
\r
899 lf->lfHeight = -(int)(mfp->pointSize * GetDeviceCaps(hdc, LOGPIXELSY) / 72.0 + 0.5);
\r
902 lf->lfEscapement = 0;
\r
903 lf->lfOrientation = 0;
\r
904 lf->lfWeight = mfp->bold ? FW_BOLD : FW_NORMAL;
\r
905 lf->lfItalic = mfp->italic;
\r
906 lf->lfUnderline = mfp->underline;
\r
907 lf->lfStrikeOut = mfp->strikeout;
\r
908 lf->lfCharSet = mfp->charset;
\r
909 lf->lfOutPrecision = OUT_DEFAULT_PRECIS;
\r
910 lf->lfClipPrecision = CLIP_DEFAULT_PRECIS;
\r
911 lf->lfQuality = DEFAULT_QUALITY;
\r
912 lf->lfPitchAndFamily = DEFAULT_PITCH|FF_DONTCARE;
\r
913 strcpy(lf->lfFaceName, mfp->faceName);
\r
917 CreateFontInMF(MyFont *mf)
\r
919 LFfromMFP(&mf->lf, &mf->mfp);
\r
920 if (mf->hf) DeleteObject(mf->hf);
\r
921 mf->hf = CreateFontIndirect(&mf->lf);
\r
924 // [HGM] This platform-dependent table provides the location for storing the color info
\r
926 colorVariable[] = {
\r
931 &highlightSquareColor,
\r
932 &premoveHighlightColor,
\r
934 &consoleBackgroundColor,
\r
935 &appData.fontForeColorWhite,
\r
936 &appData.fontBackColorWhite,
\r
937 &appData.fontForeColorBlack,
\r
938 &appData.fontBackColorBlack,
\r
939 &appData.evalHistColorWhite,
\r
940 &appData.evalHistColorBlack,
\r
941 &appData.highlightArrowColor,
\r
944 /* Command line font name parser. NULL name means do nothing.
\r
945 Syntax like "Courier New:10.0 bi" or "Arial:10" or "Arial:10b"
\r
946 For backward compatibility, syntax without the colon is also
\r
947 accepted, but font names with digits in them won't work in that case.
\r
950 ParseFontName(char *name, MyFontParams *mfp)
\r
953 if (name == NULL) return;
\r
955 q = strchr(p, ':');
\r
957 if (q - p >= sizeof(mfp->faceName))
\r
958 ExitArgError("Font name too long:", name);
\r
959 memcpy(mfp->faceName, p, q - p);
\r
960 mfp->faceName[q - p] = NULLCHAR;
\r
964 while (*p && !isdigit(*p)) {
\r
966 if (q - mfp->faceName >= sizeof(mfp->faceName))
\r
967 ExitArgError("Font name too long:", name);
\r
969 while (q > mfp->faceName && q[-1] == ' ') q--;
\r
972 if (!*p) ExitArgError("Font point size missing:", name);
\r
973 mfp->pointSize = (float) atof(p);
\r
974 mfp->bold = (strchr(p, 'b') != NULL);
\r
975 mfp->italic = (strchr(p, 'i') != NULL);
\r
976 mfp->underline = (strchr(p, 'u') != NULL);
\r
977 mfp->strikeout = (strchr(p, 's') != NULL);
\r
978 mfp->charset = DEFAULT_CHARSET;
\r
979 q = strchr(p, 'c');
\r
981 mfp->charset = (BYTE) atoi(q+1);
\r
985 ParseFont(char *name, int number)
\r
986 { // wrapper to shield back-end from 'font'
\r
987 ParseFontName(name, &font[boardSize][number]->mfp);
\r
992 { // in WB we have a 2D array of fonts; this initializes their description
\r
994 /* Point font array elements to structures and
\r
995 parse default font names */
\r
996 for (i=0; i<NUM_FONTS; i++) {
\r
997 for (j=0; j<NUM_SIZES; j++) {
\r
998 font[j][i] = &fontRec[j][i];
\r
999 ParseFontName(font[j][i]->def, &font[j][i]->mfp);
\r
1006 { // here we create the actual fonts from the selected descriptions
\r
1008 for (i=0; i<NUM_FONTS; i++) {
\r
1009 for (j=0; j<NUM_SIZES; j++) {
\r
1010 CreateFontInMF(font[j][i]);
\r
1014 /* Color name parser.
\r
1015 X version accepts X color names, but this one
\r
1016 handles only the #rrggbb form (hex) or rrr,ggg,bbb (decimal) */
\r
1018 ParseColorName(char *name)
\r
1020 int red, green, blue, count;
\r
1021 char buf[MSG_SIZ];
\r
1023 count = sscanf(name, "#%2x%2x%2x", &red, &green, &blue);
\r
1025 count = sscanf(name, "%3d%*[^0-9]%3d%*[^0-9]%3d",
\r
1026 &red, &green, &blue);
\r
1029 sprintf(buf, "Can't parse color name %s", name);
\r
1030 DisplayError(buf, 0);
\r
1031 return RGB(0, 0, 0);
\r
1033 return PALETTERGB(red, green, blue);
\r
1037 ParseColor(int n, char *name)
\r
1038 { // for WinBoard the color is an int, which needs to be derived from the string
\r
1039 if(colorVariable[n]) *(int*)colorVariable[n] = ParseColorName(name);
\r
1043 ParseAttribs(COLORREF *color, int *effects, char* argValue)
\r
1045 char *e = argValue;
\r
1049 if (*e == 'b') eff |= CFE_BOLD;
\r
1050 else if (*e == 'i') eff |= CFE_ITALIC;
\r
1051 else if (*e == 'u') eff |= CFE_UNDERLINE;
\r
1052 else if (*e == 's') eff |= CFE_STRIKEOUT;
\r
1053 else if (*e == '#' || isdigit(*e)) break;
\r
1057 *color = ParseColorName(e);
\r
1061 ParseTextAttribs(ColorClass cc, char *s)
\r
1062 { // [HGM] front-end wrapper that does the platform-dependent call
\r
1063 // for XBoard we would set (&appData.colorShout)[cc] = strdup(s);
\r
1064 ParseAttribs(&textAttribs[cc].color, &textAttribs[cc].effects, s);
\r
1068 ParseBoardSize(void *addr, char *name)
\r
1069 { // [HGM] rewritten with return-value ptr to shield back-end from BoardSize
\r
1070 BoardSize bs = SizeTiny;
\r
1071 while (sizeInfo[bs].name != NULL) {
\r
1072 if (StrCaseCmp(name, sizeInfo[bs].name) == 0) {
\r
1073 *(BoardSize *)addr = bs;
\r
1078 ExitArgError("Unrecognized board size value", name);
\r
1083 { // [HGM] import name from appData first
\r
1086 for (cc = (ColorClass)0; cc < ColorNormal; cc++) {
\r
1087 textAttribs[cc].sound.name = strdup((&appData.soundShout)[cc]);
\r
1088 textAttribs[cc].sound.data = NULL;
\r
1089 MyLoadSound(&textAttribs[cc].sound);
\r
1091 for (cc = ColorNormal; cc < NColorClasses; cc++) {
\r
1092 textAttribs[cc].sound.name = strdup("");
\r
1093 textAttribs[cc].sound.data = NULL;
\r
1095 for (sc = (SoundClass)0; sc < NSoundClasses; sc++) {
\r
1096 sounds[sc].name = strdup((&appData.soundMove)[sc]);
\r
1097 sounds[sc].data = NULL;
\r
1098 MyLoadSound(&sounds[sc]);
\r
1103 SetCommPortDefaults()
\r
1105 memset(&dcb, 0, sizeof(DCB)); // required by VS 2002 +
\r
1106 dcb.DCBlength = sizeof(DCB);
\r
1107 dcb.BaudRate = 9600;
\r
1108 dcb.fBinary = TRUE;
\r
1109 dcb.fParity = FALSE;
\r
1110 dcb.fOutxCtsFlow = FALSE;
\r
1111 dcb.fOutxDsrFlow = FALSE;
\r
1112 dcb.fDtrControl = DTR_CONTROL_ENABLE;
\r
1113 dcb.fDsrSensitivity = FALSE;
\r
1114 dcb.fTXContinueOnXoff = TRUE;
\r
1115 dcb.fOutX = FALSE;
\r
1117 dcb.fNull = FALSE;
\r
1118 dcb.fRtsControl = RTS_CONTROL_ENABLE;
\r
1119 dcb.fAbortOnError = FALSE;
\r
1121 dcb.Parity = SPACEPARITY;
\r
1122 dcb.StopBits = ONESTOPBIT;
\r
1125 // [HGM] args: these three cases taken out to stay in front-end
\r
1127 SaveFontArg(FILE *f, ArgDescriptor *ad)
\r
1128 { // in WinBoard every board size has its own font, and the "argLoc" identifies the table,
\r
1129 // while the curent board size determines the element. This system should be ported to XBoard.
\r
1130 // What the table contains pointers to, and how to print the font description, remains platform-dependent
\r
1132 for (bs=0; bs<NUM_SIZES; bs++) {
\r
1133 MyFontParams *mfp = &font[bs][(int) ad->argLoc]->mfp;
\r
1134 fprintf(f, "/size=%s ", sizeInfo[bs].name);
\r
1135 fprintf(f, "/%s=\"%s:%g%s%s%s%s%sc%d\"\n",
\r
1136 ad->argName, mfp->faceName, mfp->pointSize,
\r
1137 mfp->bold || mfp->italic || mfp->underline || mfp->strikeout ? " " : "",
\r
1138 mfp->bold ? "b" : "",
\r
1139 mfp->italic ? "i" : "",
\r
1140 mfp->underline ? "u" : "",
\r
1141 mfp->strikeout ? "s" : "",
\r
1142 (int)mfp->charset);
\r
1148 { // [HGM] copy the names from the internal WB variables to appData
\r
1151 for (cc = (ColorClass)0; cc < ColorNormal; cc++)
\r
1152 (&appData.soundShout)[cc] = textAttribs[cc].sound.name;
\r
1153 for (sc = (SoundClass)0; sc < NSoundClasses; sc++)
\r
1154 (&appData.soundMove)[sc] = sounds[sc].name;
\r
1158 SaveAttribsArg(FILE *f, ArgDescriptor *ad)
\r
1159 { // here the "argLoc" defines a table index. It could have contained the 'ta' pointer itself, though
\r
1160 MyTextAttribs* ta = &textAttribs[(ColorClass)ad->argLoc];
\r
1161 fprintf(f, "/%s=\"%s%s%s%s%s#%02lx%02lx%02lx\"\n", ad->argName,
\r
1162 (ta->effects & CFE_BOLD) ? "b" : "",
\r
1163 (ta->effects & CFE_ITALIC) ? "i" : "",
\r
1164 (ta->effects & CFE_UNDERLINE) ? "u" : "",
\r
1165 (ta->effects & CFE_STRIKEOUT) ? "s" : "",
\r
1166 (ta->effects) ? " " : "",
\r
1167 ta->color&0xff, (ta->color >> 8)&0xff, (ta->color >> 16)&0xff);
\r
1171 SaveColor(FILE *f, ArgDescriptor *ad)
\r
1172 { // in WinBoard the color is an int and has to be converted to text. In X it would be a string already?
\r
1173 COLORREF color = *(COLORREF *)colorVariable[(int)ad->argLoc];
\r
1174 fprintf(f, "/%s=#%02lx%02lx%02lx\n", ad->argName,
\r
1175 color&0xff, (color>>8)&0xff, (color>>16)&0xff);
\r
1179 SaveBoardSize(FILE *f, char *name, void *addr)
\r
1180 { // wrapper to shield back-end from BoardSize & sizeInfo
\r
1181 fprintf(f, "/%s=%s\n", name, sizeInfo[*(BoardSize *)addr].name);
\r
1185 ParseCommPortSettings(char *s)
\r
1186 { // wrapper to keep dcb from back-end
\r
1187 ParseCommSettings(s, &dcb);
\r
1192 { // wrapper to shield use of window handles from back-end (make addressible by number?)
\r
1193 GetActualPlacement(hwndMain, &wpMain);
\r
1194 GetActualPlacement(hwndConsole, &wpConsole);
\r
1195 GetActualPlacement(commentDialog, &wpComment);
\r
1196 GetActualPlacement(editTagsDialog, &wpTags);
\r
1197 GetActualPlacement(gameListDialog, &wpGameList);
\r
1198 GetActualPlacement(moveHistoryDialog, &wpMoveHistory);
\r
1199 GetActualPlacement(evalGraphDialog, &wpEvalGraph);
\r
1200 GetActualPlacement(engineOutputDialog, &wpEngineOutput);
\r
1204 PrintCommPortSettings(FILE *f, char *name)
\r
1205 { // wrapper to shield back-end from DCB
\r
1206 PrintCommSettings(f, name, &dcb);
\r
1210 MySearchPath(char *installDir, char *name, char *fullname)
\r
1213 return (int) SearchPath(installDir, name, NULL, MSG_SIZ, fullname, &dummy);
\r
1217 MyGetFullPathName(char *name, char *fullname)
\r
1220 return (int) GetFullPathName(name, MSG_SIZ, fullname, &dummy);
\r
1225 { // [HGM] args: allows testing if main window is realized from back-end
\r
1226 return hwndMain != NULL;
\r
1230 PopUpStartupDialog()
\r
1234 lpProc = MakeProcInstance((FARPROC)StartupDialog, hInst);
\r
1235 DialogBox(hInst, MAKEINTRESOURCE(DLG_Startup), NULL, (DLGPROC)lpProc);
\r
1236 FreeProcInstance(lpProc);
\r
1239 /*---------------------------------------------------------------------------*\
\r
1241 * GDI board drawing routines
\r
1243 \*---------------------------------------------------------------------------*/
\r
1245 /* [AS] Draw square using background texture */
\r
1246 static void DrawTile( int dx, int dy, int dw, int dh, HDC dst, HDC src, int mode, int sx, int sy )
\r
1251 return; /* Should never happen! */
\r
1254 SetGraphicsMode( dst, GM_ADVANCED );
\r
1261 /* X reflection */
\r
1266 x.eDx = (FLOAT) dw + dx - 1;
\r
1269 SetWorldTransform( dst, &x );
\r
1272 /* Y reflection */
\r
1278 x.eDy = (FLOAT) dh + dy - 1;
\r
1280 SetWorldTransform( dst, &x );
\r
1288 x.eDx = (FLOAT) dx;
\r
1289 x.eDy = (FLOAT) dy;
\r
1292 SetWorldTransform( dst, &x );
\r
1296 BitBlt( dst, dx, dy, dw, dh, src, sx, sy, SRCCOPY );
\r
1304 SetWorldTransform( dst, &x );
\r
1306 ModifyWorldTransform( dst, 0, MWT_IDENTITY );
\r
1309 /* [AS] [HGM] Make room for more piece types, so all pieces can be different */
\r
1311 PM_WP = (int) WhitePawn,
\r
1312 PM_WN = (int) WhiteKnight,
\r
1313 PM_WB = (int) WhiteBishop,
\r
1314 PM_WR = (int) WhiteRook,
\r
1315 PM_WQ = (int) WhiteQueen,
\r
1316 PM_WF = (int) WhiteFerz,
\r
1317 PM_WW = (int) WhiteWazir,
\r
1318 PM_WE = (int) WhiteAlfil,
\r
1319 PM_WM = (int) WhiteMan,
\r
1320 PM_WO = (int) WhiteCannon,
\r
1321 PM_WU = (int) WhiteUnicorn,
\r
1322 PM_WH = (int) WhiteNightrider,
\r
1323 PM_WA = (int) WhiteAngel,
\r
1324 PM_WC = (int) WhiteMarshall,
\r
1325 PM_WAB = (int) WhiteCardinal,
\r
1326 PM_WD = (int) WhiteDragon,
\r
1327 PM_WL = (int) WhiteLance,
\r
1328 PM_WS = (int) WhiteCobra,
\r
1329 PM_WV = (int) WhiteFalcon,
\r
1330 PM_WSG = (int) WhiteSilver,
\r
1331 PM_WG = (int) WhiteGrasshopper,
\r
1332 PM_WK = (int) WhiteKing,
\r
1333 PM_BP = (int) BlackPawn,
\r
1334 PM_BN = (int) BlackKnight,
\r
1335 PM_BB = (int) BlackBishop,
\r
1336 PM_BR = (int) BlackRook,
\r
1337 PM_BQ = (int) BlackQueen,
\r
1338 PM_BF = (int) BlackFerz,
\r
1339 PM_BW = (int) BlackWazir,
\r
1340 PM_BE = (int) BlackAlfil,
\r
1341 PM_BM = (int) BlackMan,
\r
1342 PM_BO = (int) BlackCannon,
\r
1343 PM_BU = (int) BlackUnicorn,
\r
1344 PM_BH = (int) BlackNightrider,
\r
1345 PM_BA = (int) BlackAngel,
\r
1346 PM_BC = (int) BlackMarshall,
\r
1347 PM_BG = (int) BlackGrasshopper,
\r
1348 PM_BAB = (int) BlackCardinal,
\r
1349 PM_BD = (int) BlackDragon,
\r
1350 PM_BL = (int) BlackLance,
\r
1351 PM_BS = (int) BlackCobra,
\r
1352 PM_BV = (int) BlackFalcon,
\r
1353 PM_BSG = (int) BlackSilver,
\r
1354 PM_BK = (int) BlackKing
\r
1357 static HFONT hPieceFont = NULL;
\r
1358 static HBITMAP hPieceMask[(int) EmptySquare];
\r
1359 static HBITMAP hPieceFace[(int) EmptySquare];
\r
1360 static int fontBitmapSquareSize = 0;
\r
1361 static char pieceToFontChar[(int) EmptySquare] =
\r
1362 { 'p', 'n', 'b', 'r', 'q',
\r
1363 'n', 'b', 'p', 'n', 'b', 'r', 'b', 'r', 'q', 'k',
\r
1364 'k', 'o', 'm', 'v', 't', 'w',
\r
1365 'v', 't', 'o', 'm', 'v', 't', 'v', 't', 'w', 'l',
\r
1368 extern BOOL SetCharTable( char *table, const char * map );
\r
1369 /* [HGM] moved to backend.c */
\r
1371 static void SetPieceBackground( HDC hdc, COLORREF color, int mode )
\r
1374 BYTE r1 = GetRValue( color );
\r
1375 BYTE g1 = GetGValue( color );
\r
1376 BYTE b1 = GetBValue( color );
\r
1382 /* Create a uniform background first */
\r
1383 hbrush = CreateSolidBrush( color );
\r
1384 SetRect( &rc, 0, 0, squareSize, squareSize );
\r
1385 FillRect( hdc, &rc, hbrush );
\r
1386 DeleteObject( hbrush );
\r
1389 /* Vertical gradient, good for pawn, knight and rook, less for queen and king */
\r
1390 int steps = squareSize / 2;
\r
1393 for( i=0; i<steps; i++ ) {
\r
1394 BYTE r = r1 - (r1-r2) * i / steps;
\r
1395 BYTE g = g1 - (g1-g2) * i / steps;
\r
1396 BYTE b = b1 - (b1-b2) * i / steps;
\r
1398 hbrush = CreateSolidBrush( RGB(r,g,b) );
\r
1399 SetRect( &rc, i + squareSize - steps, 0, i + squareSize - steps + 1, squareSize );
\r
1400 FillRect( hdc, &rc, hbrush );
\r
1401 DeleteObject(hbrush);
\r
1404 else if( mode == 2 ) {
\r
1405 /* Diagonal gradient, good more or less for every piece */
\r
1406 POINT triangle[3];
\r
1407 HPEN hpen = SelectObject( hdc, GetStockObject(NULL_PEN) );
\r
1408 HBRUSH hbrush_old;
\r
1409 int steps = squareSize;
\r
1412 triangle[0].x = squareSize - steps;
\r
1413 triangle[0].y = squareSize;
\r
1414 triangle[1].x = squareSize;
\r
1415 triangle[1].y = squareSize;
\r
1416 triangle[2].x = squareSize;
\r
1417 triangle[2].y = squareSize - steps;
\r
1419 for( i=0; i<steps; i++ ) {
\r
1420 BYTE r = r1 - (r1-r2) * i / steps;
\r
1421 BYTE g = g1 - (g1-g2) * i / steps;
\r
1422 BYTE b = b1 - (b1-b2) * i / steps;
\r
1424 hbrush = CreateSolidBrush( RGB(r,g,b) );
\r
1425 hbrush_old = SelectObject( hdc, hbrush );
\r
1426 Polygon( hdc, triangle, 3 );
\r
1427 SelectObject( hdc, hbrush_old );
\r
1428 DeleteObject(hbrush);
\r
1433 SelectObject( hdc, hpen );
\r
1438 [AS] The method I use to create the bitmaps it a bit tricky, but it
\r
1439 seems to work ok. The main problem here is to find the "inside" of a chess
\r
1440 piece: follow the steps as explained below.
\r
1442 static void CreatePieceMaskFromFont( HDC hdc_window, HDC hdc, int index )
\r
1446 COLORREF chroma = RGB(0xFF,0x00,0xFF);
\r
1450 int backColor = whitePieceColor;
\r
1451 int foreColor = blackPieceColor;
\r
1453 if( index < (int)BlackPawn && appData.fontBackColorWhite != appData.fontForeColorWhite ) {
\r
1454 backColor = appData.fontBackColorWhite;
\r
1455 foreColor = appData.fontForeColorWhite;
\r
1457 else if( index >= (int)BlackPawn && appData.fontBackColorBlack != appData.fontForeColorBlack ) {
\r
1458 backColor = appData.fontBackColorBlack;
\r
1459 foreColor = appData.fontForeColorBlack;
\r
1463 hbm = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
\r
1465 hbm_old = SelectObject( hdc, hbm );
\r
1469 rc.right = squareSize;
\r
1470 rc.bottom = squareSize;
\r
1472 /* Step 1: background is now black */
\r
1473 FillRect( hdc, &rc, GetStockObject(BLACK_BRUSH) );
\r
1475 GetTextExtentPoint32( hdc, &pieceToFontChar[index], 1, &sz );
\r
1477 pt.x = (squareSize - sz.cx) / 2;
\r
1478 pt.y = (squareSize - sz.cy) / 2;
\r
1480 SetBkMode( hdc, TRANSPARENT );
\r
1481 SetTextColor( hdc, chroma );
\r
1482 /* Step 2: the piece has been drawn in purple, there are now black and purple in this bitmap */
\r
1483 TextOut( hdc, pt.x, pt.y, &pieceToFontChar[appData.allWhite && index >= (int)BlackPawn ? index - (int)BlackPawn : index], 1 );
\r
1485 SelectObject( hdc, GetStockObject(WHITE_BRUSH) );
\r
1486 /* Step 3: the area outside the piece is filled with white */
\r
1487 // FloodFill( hdc, 0, 0, chroma );
\r
1488 ExtFloodFill( hdc, 0, 0, 0, FLOODFILLSURFACE );
\r
1489 ExtFloodFill( hdc, 0, squareSize-1, 0, FLOODFILLSURFACE ); // [HGM] fill from all 4 corners, for if piece too big
\r
1490 ExtFloodFill( hdc, squareSize-1, 0, 0, FLOODFILLSURFACE );
\r
1491 ExtFloodFill( hdc, squareSize-1, squareSize-1, 0, FLOODFILLSURFACE );
\r
1492 SelectObject( hdc, GetStockObject(BLACK_BRUSH) );
\r
1494 Step 4: this is the tricky part, the area inside the piece is filled with black,
\r
1495 but if the start point is not inside the piece we're lost!
\r
1496 There should be a better way to do this... if we could create a region or path
\r
1497 from the fill operation we would be fine for example.
\r
1499 // FloodFill( hdc, squareSize / 2, squareSize / 2, RGB(0xFF,0xFF,0xFF) );
\r
1500 ExtFloodFill( hdc, squareSize / 2, squareSize / 2, RGB(0xFF,0xFF,0xFF), FLOODFILLBORDER );
\r
1502 { /* [HGM] shave off edges of mask, in an attempt to correct for the fact that FloodFill does not work correctly under Win XP */
\r
1503 HDC dc2 = CreateCompatibleDC( hdc_window );
\r
1504 HBITMAP bm2 = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
\r
1506 SelectObject( dc2, bm2 );
\r
1507 BitBlt( dc2, 0, 0, squareSize, squareSize, hdc, 0, 0, SRCCOPY ); // make copy
\r
1508 BitBlt( hdc, 0, 1, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );
\r
1509 BitBlt( hdc, 2, 1, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );
\r
1510 BitBlt( hdc, 1, 0, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );
\r
1511 BitBlt( hdc, 1, 2, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );
\r
1514 DeleteObject( bm2 );
\r
1517 SetTextColor( hdc, 0 );
\r
1519 Step 5: some fonts have "disconnected" areas that are skipped by the fill:
\r
1520 draw the piece again in black for safety.
\r
1522 TextOut( hdc, pt.x, pt.y, &pieceToFontChar[appData.allWhite && index >= (int)BlackPawn ? index - (int)BlackPawn : index], 1 );
\r
1524 SelectObject( hdc, hbm_old );
\r
1526 if( hPieceMask[index] != NULL ) {
\r
1527 DeleteObject( hPieceMask[index] );
\r
1530 hPieceMask[index] = hbm;
\r
1533 hbm = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
\r
1535 SelectObject( hdc, hbm );
\r
1538 HDC dc1 = CreateCompatibleDC( hdc_window );
\r
1539 HDC dc2 = CreateCompatibleDC( hdc_window );
\r
1540 HBITMAP bm2 = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
\r
1542 SelectObject( dc1, hPieceMask[index] );
\r
1543 SelectObject( dc2, bm2 );
\r
1544 FillRect( dc2, &rc, GetStockObject(WHITE_BRUSH) );
\r
1545 BitBlt( dc2, 0, 0, squareSize, squareSize, dc1, 0, 0, SRCINVERT );
\r
1548 Now dc2 contains the inverse of the piece mask, i.e. a mask that preserves
\r
1549 the piece background and deletes (makes transparent) the rest.
\r
1550 Thanks to that mask, we are free to paint the background with the greates
\r
1551 freedom, as we'll be able to mask off the unwanted parts when finished.
\r
1552 We use this, to make gradients and give the pieces a "roundish" look.
\r
1554 SetPieceBackground( hdc, backColor, 2 );
\r
1555 BitBlt( hdc, 0, 0, squareSize, squareSize, dc2, 0, 0, SRCAND );
\r
1559 DeleteObject( bm2 );
\r
1562 SetTextColor( hdc, foreColor );
\r
1563 TextOut( hdc, pt.x, pt.y, &pieceToFontChar[appData.allWhite && index >= (int)BlackPawn ? index - (int)BlackPawn : index], 1 );
\r
1565 SelectObject( hdc, hbm_old );
\r
1567 if( hPieceFace[index] != NULL ) {
\r
1568 DeleteObject( hPieceFace[index] );
\r
1571 hPieceFace[index] = hbm;
\r
1574 static int TranslatePieceToFontPiece( int piece )
\r
1604 case BlackMarshall:
\r
1608 case BlackNightrider:
\r
1614 case BlackUnicorn:
\r
1618 case BlackGrasshopper:
\r
1630 case BlackCardinal:
\r
1637 case WhiteMarshall:
\r
1641 case WhiteNightrider:
\r
1647 case WhiteUnicorn:
\r
1651 case WhiteGrasshopper:
\r
1663 case WhiteCardinal:
\r
1672 void CreatePiecesFromFont()
\r
1675 HDC hdc_window = NULL;
\r
1681 if( fontBitmapSquareSize < 0 ) {
\r
1682 /* Something went seriously wrong in the past: do not try to recreate fonts! */
\r
1686 if( appData.renderPiecesWithFont == NULL || appData.renderPiecesWithFont[0] == NULLCHAR || appData.renderPiecesWithFont[0] == '*' ) {
\r
1687 fontBitmapSquareSize = -1;
\r
1691 if( fontBitmapSquareSize != squareSize ) {
\r
1692 hdc_window = GetDC( hwndMain );
\r
1693 hdc = CreateCompatibleDC( hdc_window );
\r
1695 if( hPieceFont != NULL ) {
\r
1696 DeleteObject( hPieceFont );
\r
1699 for( i=0; i<=(int)BlackKing; i++ ) {
\r
1700 hPieceMask[i] = NULL;
\r
1701 hPieceFace[i] = NULL;
\r
1707 if( appData.fontPieceSize >= 50 && appData.fontPieceSize <= 150 ) {
\r
1708 fontHeight = appData.fontPieceSize;
\r
1711 fontHeight = (fontHeight * squareSize) / 100;
\r
1713 lf.lfHeight = -MulDiv( fontHeight, GetDeviceCaps(hdc, LOGPIXELSY), 72 );
\r
1715 lf.lfEscapement = 0;
\r
1716 lf.lfOrientation = 0;
\r
1717 lf.lfWeight = FW_NORMAL;
\r
1719 lf.lfUnderline = 0;
\r
1720 lf.lfStrikeOut = 0;
\r
1721 lf.lfCharSet = DEFAULT_CHARSET;
\r
1722 lf.lfOutPrecision = OUT_DEFAULT_PRECIS;
\r
1723 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
\r
1724 lf.lfQuality = PROOF_QUALITY;
\r
1725 lf.lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;
\r
1726 strncpy( lf.lfFaceName, appData.renderPiecesWithFont, sizeof(lf.lfFaceName) );
\r
1727 lf.lfFaceName[ sizeof(lf.lfFaceName) - 1 ] = '\0';
\r
1729 hPieceFont = CreateFontIndirect( &lf );
\r
1731 if( hPieceFont == NULL ) {
\r
1732 fontBitmapSquareSize = -2;
\r
1735 /* Setup font-to-piece character table */
\r
1736 if( ! SetCharTable(pieceToFontChar, appData.fontToPieceTable) ) {
\r
1737 /* No (or wrong) global settings, try to detect the font */
\r
1738 if( strstr(lf.lfFaceName,"Alpha") != NULL ) {
\r
1740 SetCharTable(pieceToFontChar, "phbrqkojntwl");
\r
1742 else if( strstr(lf.lfFaceName,"DiagramTT") != NULL ) {
\r
1743 /* DiagramTT* family */
\r
1744 SetCharTable(pieceToFontChar, "PNLRQKpnlrqk");
\r
1746 else if( strstr(lf.lfFaceName,"WinboardF") != NULL ) {
\r
1747 /* Fairy symbols */
\r
1748 SetCharTable(pieceToFontChar, "PNBRQFEACWMOHIJGDVSLUKpnbrqfeacwmohijgdvsluk");
\r
1750 else if( strstr(lf.lfFaceName,"GC2004D") != NULL ) {
\r
1751 /* Good Companion (Some characters get warped as literal :-( */
\r
1752 char s[] = "1cmWG0??S??oYI23wgQU";
\r
1753 s[0]=0xB9; s[1]=0xA9; s[6]=0xB1; s[11]=0xBB; s[12]=0xAB; s[17]=0xB3;
\r
1754 SetCharTable(pieceToFontChar, s);
\r
1757 /* Cases, Condal, Leipzig, Lucena, Marroquin, Merida, Usual */
\r
1758 SetCharTable(pieceToFontChar, "pnbrqkomvtwl");
\r
1762 /* Create bitmaps */
\r
1763 hfont_old = SelectObject( hdc, hPieceFont );
\r
1764 for(i=(int)WhitePawn; i<(int)EmptySquare; i++) /* [HGM] made a loop for this */
\r
1765 if(PieceToChar((ChessSquare)i) != '.') /* skip unused pieces */
\r
1766 CreatePieceMaskFromFont( hdc_window, hdc, i );
\r
1768 SelectObject( hdc, hfont_old );
\r
1770 fontBitmapSquareSize = squareSize;
\r
1774 if( hdc != NULL ) {
\r
1778 if( hdc_window != NULL ) {
\r
1779 ReleaseDC( hwndMain, hdc_window );
\r
1784 DoLoadBitmap(HINSTANCE hinst, char *piece, int squareSize, char *suffix)
\r
1788 sprintf(name, "%s%d%s", piece, squareSize, suffix);
\r
1789 if (gameInfo.event &&
\r
1790 strcmp(gameInfo.event, "Easter Egg Hunt") == 0 &&
\r
1791 strcmp(name, "k80s") == 0) {
\r
1792 strcpy(name, "tim");
\r
1794 return LoadBitmap(hinst, name);
\r
1798 /* Insert a color into the program's logical palette
\r
1799 structure. This code assumes the given color is
\r
1800 the result of the RGB or PALETTERGB macro, and it
\r
1801 knows how those macros work (which is documented).
\r
1804 InsertInPalette(COLORREF color)
\r
1806 LPPALETTEENTRY pe = &(pLogPal->palPalEntry[pLogPal->palNumEntries]);
\r
1808 if (pLogPal->palNumEntries++ >= PALETTESIZE) {
\r
1809 DisplayFatalError("Too many colors", 0, 1);
\r
1810 pLogPal->palNumEntries--;
\r
1814 pe->peFlags = (char) 0;
\r
1815 pe->peRed = (char) (0xFF & color);
\r
1816 pe->peGreen = (char) (0xFF & (color >> 8));
\r
1817 pe->peBlue = (char) (0xFF & (color >> 16));
\r
1823 InitDrawingColors()
\r
1825 if (pLogPal == NULL) {
\r
1826 /* Allocate enough memory for a logical palette with
\r
1827 * PALETTESIZE entries and set the size and version fields
\r
1828 * of the logical palette structure.
\r
1830 pLogPal = (NPLOGPALETTE)
\r
1831 LocalAlloc(LMEM_FIXED, (sizeof(LOGPALETTE) +
\r
1832 (sizeof(PALETTEENTRY) * (PALETTESIZE))));
\r
1833 pLogPal->palVersion = 0x300;
\r
1835 pLogPal->palNumEntries = 0;
\r
1837 InsertInPalette(lightSquareColor);
\r
1838 InsertInPalette(darkSquareColor);
\r
1839 InsertInPalette(whitePieceColor);
\r
1840 InsertInPalette(blackPieceColor);
\r
1841 InsertInPalette(highlightSquareColor);
\r
1842 InsertInPalette(premoveHighlightColor);
\r
1844 /* create a logical color palette according the information
\r
1845 * in the LOGPALETTE structure.
\r
1847 hPal = CreatePalette((LPLOGPALETTE) pLogPal);
\r
1849 lightSquareBrush = CreateSolidBrush(lightSquareColor);
\r
1850 blackSquareBrush = CreateSolidBrush(blackPieceColor);
\r
1851 darkSquareBrush = CreateSolidBrush(darkSquareColor);
\r
1852 whitePieceBrush = CreateSolidBrush(whitePieceColor);
\r
1853 blackPieceBrush = CreateSolidBrush(blackPieceColor);
\r
1854 iconBkgndBrush = CreateSolidBrush(GetSysColor(COLOR_BACKGROUND));
\r
1855 explodeBrush = CreateSolidBrush(highlightSquareColor); // [HGM] atomic
\r
1856 /* [AS] Force rendering of the font-based pieces */
\r
1857 if( fontBitmapSquareSize > 0 ) {
\r
1858 fontBitmapSquareSize = 0;
\r
1864 BoardWidth(int boardSize, int n)
\r
1865 { /* [HGM] argument n added to allow different width and height */
\r
1866 int lineGap = sizeInfo[boardSize].lineGap;
\r
1868 if( appData.overrideLineGap >= 0 && appData.overrideLineGap <= 5 ) {
\r
1869 lineGap = appData.overrideLineGap;
\r
1872 return (n + 1) * lineGap +
\r
1873 n * sizeInfo[boardSize].squareSize;
\r
1876 /* Respond to board resize by dragging edge */
\r
1878 ResizeBoard(int newSizeX, int newSizeY, int flags)
\r
1880 BoardSize newSize = NUM_SIZES - 1;
\r
1881 static int recurse = 0;
\r
1882 if (IsIconic(hwndMain)) return;
\r
1883 if (recurse > 0) return;
\r
1885 while (newSize > 0) {
\r
1886 InitDrawingSizes(newSize+1000, 0); // [HGM] kludge to update sizeInfo without visible effects
\r
1887 if(newSizeX >= sizeInfo[newSize].cliWidth &&
\r
1888 newSizeY >= sizeInfo[newSize].cliHeight) break;
\r
1891 boardSize = newSize;
\r
1892 InitDrawingSizes(boardSize, flags);
\r
1899 InitDrawingSizes(BoardSize boardSize, int flags)
\r
1901 int i, boardWidth, boardHeight; /* [HGM] height treated separately */
\r
1902 ChessSquare piece;
\r
1903 static int oldBoardSize = -1, oldTinyLayout = 0;
\r
1905 SIZE clockSize, messageSize;
\r
1907 char buf[MSG_SIZ];
\r
1909 HMENU hmenu = GetMenu(hwndMain);
\r
1910 RECT crect, wrect, oldRect;
\r
1912 LOGBRUSH logbrush;
\r
1914 int suppressVisibleEffects = 0; // [HGM] kludge to request updating sizeInfo only
\r
1915 if((int)boardSize >= 1000 ) { boardSize -= 1000; suppressVisibleEffects = 1; }
\r
1917 /* [HGM] call with -2 uses old size (for if nr of files, ranks changes) */
\r
1918 if(boardSize == (BoardSize)(-2) ) boardSize = oldBoardSize;
\r
1920 oldRect.left = wpMain.x; //[HGM] placement: remember previous window params
\r
1921 oldRect.top = wpMain.y;
\r
1922 oldRect.right = wpMain.x + wpMain.width;
\r
1923 oldRect.bottom = wpMain.y + wpMain.height;
\r
1925 tinyLayout = sizeInfo[boardSize].tinyLayout;
\r
1926 smallLayout = sizeInfo[boardSize].smallLayout;
\r
1927 squareSize = sizeInfo[boardSize].squareSize;
\r
1928 lineGap = sizeInfo[boardSize].lineGap;
\r
1929 minorSize = 0; /* [HGM] Kludge to see if demagnified pieces need to be shifted */
\r
1931 if( appData.overrideLineGap >= 0 && appData.overrideLineGap <= 5 ) {
\r
1932 lineGap = appData.overrideLineGap;
\r
1935 if (tinyLayout != oldTinyLayout) {
\r
1936 long style = GetWindowLong(hwndMain, GWL_STYLE);
\r
1938 style &= ~WS_SYSMENU;
\r
1939 InsertMenu(hmenu, IDM_Exit, MF_BYCOMMAND, IDM_Minimize,
\r
1940 "&Minimize\tCtrl+F4");
\r
1942 style |= WS_SYSMENU;
\r
1943 RemoveMenu(hmenu, IDM_Minimize, MF_BYCOMMAND);
\r
1945 SetWindowLong(hwndMain, GWL_STYLE, style);
\r
1947 for (i=0; menuBarText[tinyLayout][i]; i++) {
\r
1948 ModifyMenu(hmenu, i, MF_STRING|MF_BYPOSITION|MF_POPUP,
\r
1949 (UINT)GetSubMenu(hmenu, i), menuBarText[tinyLayout][i]);
\r
1951 DrawMenuBar(hwndMain);
\r
1954 boardWidth = BoardWidth(boardSize, BOARD_WIDTH);
\r
1955 boardHeight = BoardWidth(boardSize, BOARD_HEIGHT);
\r
1957 /* Get text area sizes */
\r
1958 hdc = GetDC(hwndMain);
\r
1959 if (appData.clockMode) {
\r
1960 sprintf(buf, "White: %s", TimeString(23*60*60*1000L));
\r
1962 sprintf(buf, "White");
\r
1964 oldFont = SelectObject(hdc, font[boardSize][CLOCK_FONT]->hf);
\r
1965 GetTextExtentPoint(hdc, buf, strlen(buf), &clockSize);
\r
1966 SelectObject(hdc, font[boardSize][MESSAGE_FONT]->hf);
\r
1967 str = "We only care about the height here";
\r
1968 GetTextExtentPoint(hdc, str, strlen(str), &messageSize);
\r
1969 SelectObject(hdc, oldFont);
\r
1970 ReleaseDC(hwndMain, hdc);
\r
1972 /* Compute where everything goes */
\r
1973 if((first.programLogo || second.programLogo) && !tinyLayout) {
\r
1974 /* [HGM] logo: if either logo is on, reserve space for it */
\r
1975 logoHeight = 2*clockSize.cy;
\r
1976 leftLogoRect.left = OUTER_MARGIN;
\r
1977 leftLogoRect.right = leftLogoRect.left + 4*clockSize.cy;
\r
1978 leftLogoRect.top = OUTER_MARGIN;
\r
1979 leftLogoRect.bottom = OUTER_MARGIN + logoHeight;
\r
1981 rightLogoRect.right = OUTER_MARGIN + boardWidth;
\r
1982 rightLogoRect.left = rightLogoRect.right - 4*clockSize.cy;
\r
1983 rightLogoRect.top = OUTER_MARGIN;
\r
1984 rightLogoRect.bottom = OUTER_MARGIN + logoHeight;
\r
1987 whiteRect.left = leftLogoRect.right;
\r
1988 whiteRect.right = OUTER_MARGIN + boardWidth/2 - INNER_MARGIN/2;
\r
1989 whiteRect.top = OUTER_MARGIN;
\r
1990 whiteRect.bottom = whiteRect.top + logoHeight;
\r
1992 blackRect.right = rightLogoRect.left;
\r
1993 blackRect.left = whiteRect.right + INNER_MARGIN;
\r
1994 blackRect.top = whiteRect.top;
\r
1995 blackRect.bottom = whiteRect.bottom;
\r
1997 whiteRect.left = OUTER_MARGIN;
\r
1998 whiteRect.right = whiteRect.left + boardWidth/2 - INNER_MARGIN/2;
\r
1999 whiteRect.top = OUTER_MARGIN;
\r
2000 whiteRect.bottom = whiteRect.top + clockSize.cy;
\r
2002 blackRect.left = whiteRect.right + INNER_MARGIN;
\r
2003 blackRect.right = blackRect.left + boardWidth/2 - 1;
\r
2004 blackRect.top = whiteRect.top;
\r
2005 blackRect.bottom = whiteRect.bottom;
\r
2008 messageRect.left = OUTER_MARGIN + MESSAGE_LINE_LEFTMARGIN;
\r
2009 if (appData.showButtonBar) {
\r
2010 messageRect.right = OUTER_MARGIN + boardWidth // [HGM] logo: expressed independent of clock placement
\r
2011 - N_BUTTONS*BUTTON_WIDTH - MESSAGE_LINE_LEFTMARGIN;
\r
2013 messageRect.right = OUTER_MARGIN + boardWidth;
\r
2015 messageRect.top = whiteRect.bottom + INNER_MARGIN;
\r
2016 messageRect.bottom = messageRect.top + messageSize.cy;
\r
2018 boardRect.left = OUTER_MARGIN;
\r
2019 boardRect.right = boardRect.left + boardWidth;
\r
2020 boardRect.top = messageRect.bottom + INNER_MARGIN;
\r
2021 boardRect.bottom = boardRect.top + boardHeight;
\r
2023 sizeInfo[boardSize].cliWidth = boardRect.right + OUTER_MARGIN;
\r
2024 sizeInfo[boardSize].cliHeight = boardRect.bottom + OUTER_MARGIN;
\r
2025 oldBoardSize = boardSize;
\r
2026 oldTinyLayout = tinyLayout;
\r
2027 winW = 2 * GetSystemMetrics(SM_CXFRAME) + boardRect.right + OUTER_MARGIN;
\r
2028 winH = 2 * GetSystemMetrics(SM_CYFRAME) + GetSystemMetrics(SM_CYMENU) +
\r
2029 GetSystemMetrics(SM_CYCAPTION) + boardRect.bottom + OUTER_MARGIN;
\r
2030 if(suppressVisibleEffects) return; // [HGM] when called for filling sizeInfo only
\r
2031 wpMain.width = winW; // [HGM] placement: set through temporary which can used by initial sizing choice
\r
2032 wpMain.height = winH; // without disturbing window attachments
\r
2033 GetWindowRect(hwndMain, &wrect);
\r
2034 SetWindowPos(hwndMain, NULL, 0, 0, wpMain.width, wpMain.height,
\r
2035 SWP_NOCOPYBITS|SWP_NOZORDER|SWP_NOMOVE);
\r
2037 // [HGM] placement: let attached windows follow size change.
\r
2038 ReattachAfterSize( &oldRect, wpMain.width, wpMain.height, moveHistoryDialog, &wpMoveHistory );
\r
2039 ReattachAfterSize( &oldRect, wpMain.width, wpMain.height, evalGraphDialog, &wpEvalGraph );
\r
2040 ReattachAfterSize( &oldRect, wpMain.width, wpMain.height, engineOutputDialog, &wpEngineOutput );
\r
2041 ReattachAfterSize( &oldRect, wpMain.width, wpMain.height, gameListDialog, &wpGameList );
\r
2042 ReattachAfterSize( &oldRect, wpMain.width, wpMain.height, hwndConsole, &wpConsole );
\r
2044 /* compensate if menu bar wrapped */
\r
2045 GetClientRect(hwndMain, &crect);
\r
2046 offby = boardRect.bottom + OUTER_MARGIN - crect.bottom;
\r
2047 wpMain.height += offby;
\r
2049 case WMSZ_TOPLEFT:
\r
2050 SetWindowPos(hwndMain, NULL,
\r
2051 wrect.right - wpMain.width, wrect.bottom - wpMain.height,
\r
2052 wpMain.width, wpMain.height, SWP_NOCOPYBITS|SWP_NOZORDER);
\r
2055 case WMSZ_TOPRIGHT:
\r
2057 SetWindowPos(hwndMain, NULL,
\r
2058 wrect.left, wrect.bottom - wpMain.height,
\r
2059 wpMain.width, wpMain.height, SWP_NOCOPYBITS|SWP_NOZORDER);
\r
2062 case WMSZ_BOTTOMLEFT:
\r
2064 SetWindowPos(hwndMain, NULL,
\r
2065 wrect.right - wpMain.width, wrect.top,
\r
2066 wpMain.width, wpMain.height, SWP_NOCOPYBITS|SWP_NOZORDER);
\r
2069 case WMSZ_BOTTOMRIGHT:
\r
2073 SetWindowPos(hwndMain, NULL, 0, 0, wpMain.width, wpMain.height,
\r
2074 SWP_NOCOPYBITS|SWP_NOZORDER|SWP_NOMOVE);
\r
2079 for (i = 0; i < N_BUTTONS; i++) {
\r
2080 if (buttonDesc[i].hwnd != NULL) {
\r
2081 DestroyWindow(buttonDesc[i].hwnd);
\r
2082 buttonDesc[i].hwnd = NULL;
\r
2084 if (appData.showButtonBar) {
\r
2085 buttonDesc[i].hwnd =
\r
2086 CreateWindow("BUTTON", buttonDesc[i].label,
\r
2087 WS_VISIBLE | WS_CHILD | BS_PUSHBUTTON,
\r
2088 boardRect.right - BUTTON_WIDTH*(N_BUTTONS-i),
\r
2089 messageRect.top, BUTTON_WIDTH, messageSize.cy, hwndMain,
\r
2090 (HMENU) buttonDesc[i].id,
\r
2091 (HINSTANCE) GetWindowLong(hwndMain, GWL_HINSTANCE), NULL);
\r
2093 SendMessage(buttonDesc[i].hwnd, WM_SETFONT,
\r
2094 (WPARAM)font[boardSize][MESSAGE_FONT]->hf,
\r
2095 MAKELPARAM(FALSE, 0));
\r
2097 if (buttonDesc[i].id == IDM_Pause)
\r
2098 hwndPause = buttonDesc[i].hwnd;
\r
2099 buttonDesc[i].wndproc = (WNDPROC)
\r
2100 SetWindowLong(buttonDesc[i].hwnd, GWL_WNDPROC, (LONG) ButtonProc);
\r
2103 if (gridPen != NULL) DeleteObject(gridPen);
\r
2104 if (highlightPen != NULL) DeleteObject(highlightPen);
\r
2105 if (premovePen != NULL) DeleteObject(premovePen);
\r
2106 if (lineGap != 0) {
\r
2107 logbrush.lbStyle = BS_SOLID;
\r
2108 logbrush.lbColor = RGB(0, 0, 0); /* grid pen color = black */
\r
2110 ExtCreatePen(PS_GEOMETRIC|PS_SOLID|PS_ENDCAP_FLAT|PS_JOIN_MITER,
\r
2111 lineGap, &logbrush, 0, NULL);
\r
2112 logbrush.lbColor = highlightSquareColor;
\r
2114 ExtCreatePen(PS_GEOMETRIC|PS_SOLID|PS_ENDCAP_FLAT|PS_JOIN_MITER,
\r
2115 lineGap, &logbrush, 0, NULL);
\r
2117 logbrush.lbColor = premoveHighlightColor;
\r
2119 ExtCreatePen(PS_GEOMETRIC|PS_SOLID|PS_ENDCAP_FLAT|PS_JOIN_MITER,
\r
2120 lineGap, &logbrush, 0, NULL);
\r
2122 /* [HGM] Loop had to be split in part for vert. and hor. lines */
\r
2123 for (i = 0; i < BOARD_HEIGHT + 1; i++) {
\r
2124 gridEndpoints[i*2].x = boardRect.left + lineGap / 2;
\r
2125 gridEndpoints[i*2].y = gridEndpoints[i*2 + 1].y =
\r
2126 boardRect.top + lineGap / 2 + (i * (squareSize + lineGap));
\r
2127 gridEndpoints[i*2 + 1].x = boardRect.left + lineGap / 2 +
\r
2128 BOARD_WIDTH * (squareSize + lineGap);
\r
2129 gridVertexCounts[i*2] = gridVertexCounts[i*2 + 1] = 2;
\r
2131 for (i = 0; i < BOARD_WIDTH + 1; i++) {
\r
2132 gridEndpoints[i*2 + BOARD_HEIGHT*2 + 2].y = boardRect.top + lineGap / 2;
\r
2133 gridEndpoints[i*2 + BOARD_HEIGHT*2 + 2].x =
\r
2134 gridEndpoints[i*2 + 1 + BOARD_HEIGHT*2 + 2].x = boardRect.left +
\r
2135 lineGap / 2 + (i * (squareSize + lineGap));
\r
2136 gridEndpoints[i*2 + 1 + BOARD_HEIGHT*2 + 2].y =
\r
2137 boardRect.top + BOARD_HEIGHT * (squareSize + lineGap);
\r
2138 gridVertexCounts[i*2] = gridVertexCounts[i*2 + 1] = 2;
\r
2142 /* [HGM] Licensing requirement */
\r
2144 if(gameInfo.variant == VariantGothic) GothicPopUp( GOTHIC, VariantGothic); else
\r
2147 if(gameInfo.variant == VariantFalcon) GothicPopUp( FALCON, VariantFalcon); else
\r
2149 GothicPopUp( "", VariantNormal);
\r
2152 /* if (boardSize == oldBoardSize) return; [HGM] variant might have changed */
\r
2154 /* Load piece bitmaps for this board size */
\r
2155 for (i=0; i<=2; i++) {
\r
2156 for (piece = WhitePawn;
\r
2157 (int) piece < (int) BlackPawn;
\r
2158 piece = (ChessSquare) ((int) piece + 1)) {
\r
2159 if (pieceBitmap[i][piece] != NULL)
\r
2160 DeleteObject(pieceBitmap[i][piece]);
\r
2164 fontBitmapSquareSize = 0; /* [HGM] render: make sure pieces will be recreated, as we might need others now */
\r
2165 // Orthodox Chess pieces
\r
2166 pieceBitmap[0][WhitePawn] = DoLoadBitmap(hInst, "p", squareSize, "s");
\r
2167 pieceBitmap[0][WhiteKnight] = DoLoadBitmap(hInst, "n", squareSize, "s");
\r
2168 pieceBitmap[0][WhiteBishop] = DoLoadBitmap(hInst, "b", squareSize, "s");
\r
2169 pieceBitmap[0][WhiteRook] = DoLoadBitmap(hInst, "r", squareSize, "s");
\r
2170 pieceBitmap[0][WhiteKing] = DoLoadBitmap(hInst, "k", squareSize, "s");
\r
2171 pieceBitmap[1][WhitePawn] = DoLoadBitmap(hInst, "p", squareSize, "o");
\r
2172 pieceBitmap[1][WhiteKnight] = DoLoadBitmap(hInst, "n", squareSize, "o");
\r
2173 pieceBitmap[1][WhiteBishop] = DoLoadBitmap(hInst, "b", squareSize, "o");
\r
2174 pieceBitmap[1][WhiteRook] = DoLoadBitmap(hInst, "r", squareSize, "o");
\r
2175 pieceBitmap[1][WhiteKing] = DoLoadBitmap(hInst, "k", squareSize, "o");
\r
2176 pieceBitmap[2][WhitePawn] = DoLoadBitmap(hInst, "p", squareSize, "w");
\r
2177 pieceBitmap[2][WhiteKnight] = DoLoadBitmap(hInst, "n", squareSize, "w");
\r
2178 pieceBitmap[2][WhiteBishop] = DoLoadBitmap(hInst, "b", squareSize, "w");
\r
2179 pieceBitmap[2][WhiteRook] = DoLoadBitmap(hInst, "r", squareSize, "w");
\r
2180 pieceBitmap[2][WhiteKing] = DoLoadBitmap(hInst, "k", squareSize, "w");
\r
2181 if( !strcmp(appData.variant, "shogi") && (squareSize==72 || squareSize==49)) {
\r
2182 // in Shogi, Hijack the unused Queen for Lance
\r
2183 pieceBitmap[0][WhiteQueen] = DoLoadBitmap(hInst, "l", squareSize, "s");
\r
2184 pieceBitmap[1][WhiteQueen] = DoLoadBitmap(hInst, "l", squareSize, "o");
\r
2185 pieceBitmap[2][WhiteQueen] = DoLoadBitmap(hInst, "l", squareSize, "w");
\r
2187 pieceBitmap[0][WhiteQueen] = DoLoadBitmap(hInst, "q", squareSize, "s");
\r
2188 pieceBitmap[1][WhiteQueen] = DoLoadBitmap(hInst, "q", squareSize, "o");
\r
2189 pieceBitmap[2][WhiteQueen] = DoLoadBitmap(hInst, "q", squareSize, "w");
\r
2192 if(squareSize <= 72 && squareSize >= 33) {
\r
2193 /* A & C are available in most sizes now */
\r
2194 if(squareSize != 49 && squareSize != 72 && squareSize != 33) { // Vortex-like
\r
2195 pieceBitmap[0][WhiteAngel] = DoLoadBitmap(hInst, "a", squareSize, "s");
\r
2196 pieceBitmap[1][WhiteAngel] = DoLoadBitmap(hInst, "a", squareSize, "o");
\r
2197 pieceBitmap[2][WhiteAngel] = DoLoadBitmap(hInst, "a", squareSize, "w");
\r
2198 pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "s");
\r
2199 pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "o");
\r
2200 pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "w");
\r
2201 pieceBitmap[0][WhiteCobra] = DoLoadBitmap(hInst, "cv", squareSize, "s");
\r
2202 pieceBitmap[1][WhiteCobra] = DoLoadBitmap(hInst, "cv", squareSize, "o");
\r
2203 pieceBitmap[2][WhiteCobra] = DoLoadBitmap(hInst, "cv", squareSize, "w");
\r
2204 pieceBitmap[0][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "s");
\r
2205 pieceBitmap[1][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "o");
\r
2206 pieceBitmap[2][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "w");
\r
2207 } else { // Smirf-like
\r
2208 pieceBitmap[0][WhiteAngel] = DoLoadBitmap(hInst, "aa", squareSize, "s");
\r
2209 pieceBitmap[1][WhiteAngel] = DoLoadBitmap(hInst, "aa", squareSize, "o");
\r
2210 pieceBitmap[2][WhiteAngel] = DoLoadBitmap(hInst, "aa", squareSize, "w");
\r
2212 if(gameInfo.variant == VariantGothic) { // Vortex-like
\r
2213 pieceBitmap[0][WhiteMarshall] = DoLoadBitmap(hInst, "cv", squareSize, "s");
\r
2214 pieceBitmap[1][WhiteMarshall] = DoLoadBitmap(hInst, "cv", squareSize, "o");
\r
2215 pieceBitmap[2][WhiteMarshall] = DoLoadBitmap(hInst, "cv", squareSize, "w");
\r
2216 } else { // WinBoard standard
\r
2217 pieceBitmap[0][WhiteMarshall] = DoLoadBitmap(hInst, "c", squareSize, "s");
\r
2218 pieceBitmap[1][WhiteMarshall] = DoLoadBitmap(hInst, "c", squareSize, "o");
\r
2219 pieceBitmap[2][WhiteMarshall] = DoLoadBitmap(hInst, "c", squareSize, "w");
\r
2224 if(squareSize==72 || squareSize==49 || squareSize==33) { /* experiment with some home-made bitmaps */
\r
2225 pieceBitmap[0][WhiteFerz] = DoLoadBitmap(hInst, "f", squareSize, "s");
\r
2226 pieceBitmap[1][WhiteFerz] = DoLoadBitmap(hInst, "f", squareSize, "o");
\r
2227 pieceBitmap[2][WhiteFerz] = DoLoadBitmap(hInst, "f", squareSize, "w");
\r
2228 pieceBitmap[0][WhiteWazir] = DoLoadBitmap(hInst, "w", squareSize, "s");
\r
2229 pieceBitmap[1][WhiteWazir] = DoLoadBitmap(hInst, "w", squareSize, "o");
\r
2230 pieceBitmap[2][WhiteWazir] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
2231 pieceBitmap[0][WhiteAlfil] = DoLoadBitmap(hInst, "e", squareSize, "s");
\r
2232 pieceBitmap[1][WhiteAlfil] = DoLoadBitmap(hInst, "e", squareSize, "o");
\r
2233 pieceBitmap[2][WhiteAlfil] = DoLoadBitmap(hInst, "e", squareSize, "w");
\r
2234 pieceBitmap[0][WhiteMan] = DoLoadBitmap(hInst, "m", squareSize, "s");
\r
2235 pieceBitmap[1][WhiteMan] = DoLoadBitmap(hInst, "m", squareSize, "o");
\r
2236 pieceBitmap[2][WhiteMan] = DoLoadBitmap(hInst, "m", squareSize, "w");
\r
2237 pieceBitmap[0][WhiteCardinal] = DoLoadBitmap(hInst, "a", squareSize, "s");
\r
2238 pieceBitmap[1][WhiteCardinal] = DoLoadBitmap(hInst, "a", squareSize, "o");
\r
2239 pieceBitmap[2][WhiteCardinal] = DoLoadBitmap(hInst, "a", squareSize, "w");
\r
2240 pieceBitmap[0][WhiteDragon] = DoLoadBitmap(hInst, "dk", squareSize, "s");
\r
2241 pieceBitmap[1][WhiteDragon] = DoLoadBitmap(hInst, "dk", squareSize, "o");
\r
2242 pieceBitmap[2][WhiteDragon] = DoLoadBitmap(hInst, "dk", squareSize, "w");
\r
2243 pieceBitmap[0][WhiteFalcon] = DoLoadBitmap(hInst, "v", squareSize, "s");
\r
2244 pieceBitmap[1][WhiteFalcon] = DoLoadBitmap(hInst, "v", squareSize, "o");
\r
2245 pieceBitmap[2][WhiteFalcon] = DoLoadBitmap(hInst, "v", squareSize, "w");
\r
2246 pieceBitmap[0][WhiteCobra] = DoLoadBitmap(hInst, "s", squareSize, "s");
\r
2247 pieceBitmap[1][WhiteCobra] = DoLoadBitmap(hInst, "s", squareSize, "o");
\r
2248 pieceBitmap[2][WhiteCobra] = DoLoadBitmap(hInst, "s", squareSize, "w");
\r
2249 pieceBitmap[0][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "s");
\r
2250 pieceBitmap[1][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "o");
\r
2251 pieceBitmap[2][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "w");
\r
2252 pieceBitmap[0][WhiteUnicorn] = DoLoadBitmap(hInst, "u", squareSize, "s");
\r
2253 pieceBitmap[1][WhiteUnicorn] = DoLoadBitmap(hInst, "u", squareSize, "o");
\r
2254 pieceBitmap[2][WhiteUnicorn] = DoLoadBitmap(hInst, "u", squareSize, "w");
\r
2256 if(gameInfo.variant == VariantShogi) { /* promoted Gold represemtations */
\r
2257 pieceBitmap[0][WhiteCannon] = DoLoadBitmap(hInst, "wp", squareSize, "s");
\r
2258 pieceBitmap[1][WhiteCannon] = DoLoadBitmap(hInst, "wp", squareSize, "o");
\r
2259 pieceBitmap[2][WhiteCannon] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
2260 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "wn", squareSize, "s");
\r
2261 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "wn", squareSize, "o");
\r
2262 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
2263 pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "ws", squareSize, "s");
\r
2264 pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "ws", squareSize, "o");
\r
2265 pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
2266 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "wl", squareSize, "s");
\r
2267 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "wl", squareSize, "o");
\r
2268 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
2270 pieceBitmap[0][WhiteCannon] = DoLoadBitmap(hInst, "o", squareSize, "s");
\r
2271 pieceBitmap[1][WhiteCannon] = DoLoadBitmap(hInst, "o", squareSize, "o");
\r
2272 pieceBitmap[2][WhiteCannon] = DoLoadBitmap(hInst, "o", squareSize, "w");
\r
2273 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "h", squareSize, "s");
\r
2274 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "h", squareSize, "o");
\r
2275 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "h", squareSize, "w");
\r
2276 pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "s");
\r
2277 pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "o");
\r
2278 pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "w");
\r
2279 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "g", squareSize, "s");
\r
2280 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "g", squareSize, "o");
\r
2281 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "g", squareSize, "w");
\r
2284 } else { /* other size, no special bitmaps available. Use smaller symbols */
\r
2285 if((int)boardSize < 2) minorSize = sizeInfo[0].squareSize;
\r
2286 else minorSize = sizeInfo[(int)boardSize - 2].squareSize;
\r
2287 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "n", minorSize, "s");
\r
2288 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "n", minorSize, "o");
\r
2289 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "n", minorSize, "w");
\r
2290 pieceBitmap[0][WhiteCardinal] = DoLoadBitmap(hInst, "b", minorSize, "s");
\r
2291 pieceBitmap[1][WhiteCardinal] = DoLoadBitmap(hInst, "b", minorSize, "o");
\r
2292 pieceBitmap[2][WhiteCardinal] = DoLoadBitmap(hInst, "b", minorSize, "w");
\r
2293 pieceBitmap[0][WhiteDragon] = DoLoadBitmap(hInst, "r", minorSize, "s");
\r
2294 pieceBitmap[1][WhiteDragon] = DoLoadBitmap(hInst, "r", minorSize, "o");
\r
2295 pieceBitmap[2][WhiteDragon] = DoLoadBitmap(hInst, "r", minorSize, "w");
\r
2296 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "q", minorSize, "s");
\r
2297 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "q", minorSize, "o");
\r
2298 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "q", minorSize, "w");
\r
2302 if(gameInfo.variant == VariantShogi && squareSize == 58)
\r
2303 /* special Shogi support in this size */
\r
2304 { for (i=0; i<=2; i++) { /* replace all bitmaps */
\r
2305 for (piece = WhitePawn;
\r
2306 (int) piece < (int) BlackPawn;
\r
2307 piece = (ChessSquare) ((int) piece + 1)) {
\r
2308 if (pieceBitmap[i][piece] != NULL)
\r
2309 DeleteObject(pieceBitmap[i][piece]);
\r
2312 pieceBitmap[0][WhitePawn] = DoLoadBitmap(hInst, "sp", squareSize, "o");
\r
2313 pieceBitmap[0][WhiteKnight] = DoLoadBitmap(hInst, "sn", squareSize, "o");
\r
2314 pieceBitmap[0][WhiteBishop] = DoLoadBitmap(hInst, "sb", squareSize, "o");
\r
2315 pieceBitmap[0][WhiteRook] = DoLoadBitmap(hInst, "sr", squareSize, "o");
\r
2316 pieceBitmap[0][WhiteQueen] = DoLoadBitmap(hInst, "sl", squareSize, "o");
\r
2317 pieceBitmap[0][WhiteKing] = DoLoadBitmap(hInst, "sk", squareSize, "o");
\r
2318 pieceBitmap[0][WhiteFerz] = DoLoadBitmap(hInst, "sf", squareSize, "o");
\r
2319 pieceBitmap[0][WhiteWazir] = DoLoadBitmap(hInst, "sw", squareSize, "o");
\r
2320 pieceBitmap[0][WhiteCannon] = DoLoadBitmap(hInst, "su", squareSize, "o");
\r
2321 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "sh", squareSize, "o");
\r
2322 pieceBitmap[0][WhiteCardinal] = DoLoadBitmap(hInst, "sa", squareSize, "o");
\r
2323 pieceBitmap[0][WhiteDragon] = DoLoadBitmap(hInst, "sc", squareSize, "o");
\r
2324 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "sg", squareSize, "o");
\r
2325 pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "ss", squareSize, "o");
\r
2326 pieceBitmap[1][WhitePawn] = DoLoadBitmap(hInst, "sp", squareSize, "o");
\r
2327 pieceBitmap[1][WhiteKnight] = DoLoadBitmap(hInst, "sn", squareSize, "o");
\r
2328 pieceBitmap[1][WhiteBishop] = DoLoadBitmap(hInst, "sb", squareSize, "o");
\r
2329 pieceBitmap[1][WhiteRook] = DoLoadBitmap(hInst, "sr", squareSize, "o");
\r
2330 pieceBitmap[1][WhiteQueen] = DoLoadBitmap(hInst, "sl", squareSize, "o");
\r
2331 pieceBitmap[1][WhiteKing] = DoLoadBitmap(hInst, "sk", squareSize, "o");
\r
2332 pieceBitmap[1][WhiteFerz] = DoLoadBitmap(hInst, "sf", squareSize, "o");
\r
2333 pieceBitmap[1][WhiteWazir] = DoLoadBitmap(hInst, "sw", squareSize, "o");
\r
2334 pieceBitmap[1][WhiteCannon] = DoLoadBitmap(hInst, "su", squareSize, "o");
\r
2335 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "sh", squareSize, "o");
\r
2336 pieceBitmap[1][WhiteCardinal] = DoLoadBitmap(hInst, "sa", squareSize, "o");
\r
2337 pieceBitmap[1][WhiteDragon] = DoLoadBitmap(hInst, "sc", squareSize, "o");
\r
2338 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "sg", squareSize, "o");
\r
2339 pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "ss", squareSize, "o");
\r
2340 pieceBitmap[2][WhitePawn] = DoLoadBitmap(hInst, "sp", squareSize, "w");
\r
2341 pieceBitmap[2][WhiteKnight] = DoLoadBitmap(hInst, "sn", squareSize, "w");
\r
2342 pieceBitmap[2][WhiteBishop] = DoLoadBitmap(hInst, "sr", squareSize, "w");
\r
2343 pieceBitmap[2][WhiteRook] = DoLoadBitmap(hInst, "sr", squareSize, "w");
\r
2344 pieceBitmap[2][WhiteQueen] = DoLoadBitmap(hInst, "sl", squareSize, "w");
\r
2345 pieceBitmap[2][WhiteKing] = DoLoadBitmap(hInst, "sk", squareSize, "w");
\r
2346 pieceBitmap[2][WhiteFerz] = DoLoadBitmap(hInst, "sw", squareSize, "w");
\r
2347 pieceBitmap[2][WhiteWazir] = DoLoadBitmap(hInst, "sw", squareSize, "w");
\r
2348 pieceBitmap[2][WhiteCannon] = DoLoadBitmap(hInst, "sp", squareSize, "w");
\r
2349 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "sn", squareSize, "w");
\r
2350 pieceBitmap[2][WhiteCardinal] = DoLoadBitmap(hInst, "sr", squareSize, "w");
\r
2351 pieceBitmap[2][WhiteDragon] = DoLoadBitmap(hInst, "sr", squareSize, "w");
\r
2352 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "sl", squareSize, "w");
\r
2353 pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "sw", squareSize, "w");
\r
2359 PieceBitmap(ChessSquare p, int kind)
\r
2361 if ((int) p >= (int) BlackPawn)
\r
2362 p = (ChessSquare) ((int) p - (int) BlackPawn + (int) WhitePawn);
\r
2364 return pieceBitmap[kind][(int) p];
\r
2367 /***************************************************************/
\r
2369 #define MIN(a,b) (((a) < (b)) ? (a) : (b))
\r
2370 #define MAX(a,b) (((a) > (b)) ? (a) : (b))
\r
2372 #define MIN3(a,b,c) (((a) < (b) && (a) < (c)) ? (a) : (((b) < (a) && (b) < (c)) ? (b) : (c)))
\r
2373 #define MAX3(a,b,c) (((a) > (b) && (a) > (c)) ? (a) : (((b) > (a) && (b) > (c)) ? (b) : (c)))
\r
2377 SquareToPos(int row, int column, int * x, int * y)
\r
2380 *x = boardRect.left + lineGap + ((BOARD_WIDTH-1)-column) * (squareSize + lineGap);
\r
2381 *y = boardRect.top + lineGap + row * (squareSize + lineGap);
\r
2383 *x = boardRect.left + lineGap + column * (squareSize + lineGap);
\r
2384 *y = boardRect.top + lineGap + ((BOARD_HEIGHT-1)-row) * (squareSize + lineGap);
\r
2389 DrawCoordsOnDC(HDC hdc)
\r
2391 static char files[24] = {'0', '1','2','3','4','5','6','7','8','9','0','1','1','0','9','8','7','6','5','4','3','2','1','0'};
\r
2392 static char ranks[24] = {'l', 'k','j','i','h','g','f','e','d','c','b','a','a','b','c','d','e','f','g','h','i','j','k','l'};
\r
2393 char str[2] = { NULLCHAR, NULLCHAR };
\r
2394 int oldMode, oldAlign, x, y, start, i;
\r
2398 if (!appData.showCoords)
\r
2401 start = flipView ? 1-(ONE!='1') : 23+(ONE!='1')-BOARD_HEIGHT;
\r
2403 oldBrush = SelectObject(hdc, GetStockObject(BLACK_BRUSH));
\r
2404 oldMode = SetBkMode(hdc, (appData.monoMode ? OPAQUE : TRANSPARENT));
\r
2405 oldAlign = GetTextAlign(hdc);
\r
2406 oldFont = SelectObject(hdc, font[boardSize][COORD_FONT]->hf);
\r
2408 y = boardRect.top + lineGap;
\r
2409 x = boardRect.left + lineGap + gameInfo.holdingsWidth*(squareSize + lineGap);
\r
2411 SetTextAlign(hdc, TA_LEFT|TA_TOP);
\r
2412 for (i = 0; i < BOARD_HEIGHT; i++) {
\r
2413 str[0] = files[start + i];
\r
2414 ExtTextOut(hdc, x + 2, y + 1, 0, NULL, str, 1, NULL);
\r
2415 y += squareSize + lineGap;
\r
2418 start = flipView ? 12-(BOARD_RGHT-BOARD_LEFT) : 12;
\r
2420 SetTextAlign(hdc, TA_RIGHT|TA_BOTTOM);
\r
2421 for (i = 0; i < BOARD_RGHT - BOARD_LEFT; i++) {
\r
2422 str[0] = ranks[start + i];
\r
2423 ExtTextOut(hdc, x + squareSize - 2, y - 1, 0, NULL, str, 1, NULL);
\r
2424 x += squareSize + lineGap;
\r
2427 SelectObject(hdc, oldBrush);
\r
2428 SetBkMode(hdc, oldMode);
\r
2429 SetTextAlign(hdc, oldAlign);
\r
2430 SelectObject(hdc, oldFont);
\r
2434 DrawGridOnDC(HDC hdc)
\r
2438 if (lineGap != 0) {
\r
2439 oldPen = SelectObject(hdc, gridPen);
\r
2440 PolyPolyline(hdc, gridEndpoints, gridVertexCounts, BOARD_WIDTH+BOARD_HEIGHT + 2);
\r
2441 SelectObject(hdc, oldPen);
\r
2445 #define HIGHLIGHT_PEN 0
\r
2446 #define PREMOVE_PEN 1
\r
2449 DrawHighlightOnDC(HDC hdc, BOOLEAN on, int x, int y, int pen)
\r
2452 HPEN oldPen, hPen;
\r
2453 if (lineGap == 0) return;
\r
2455 x1 = boardRect.left +
\r
2456 lineGap/2 + ((BOARD_WIDTH-1)-x) * (squareSize + lineGap);
\r
2457 y1 = boardRect.top +
\r
2458 lineGap/2 + y * (squareSize + lineGap);
\r
2460 x1 = boardRect.left +
\r
2461 lineGap/2 + x * (squareSize + lineGap);
\r
2462 y1 = boardRect.top +
\r
2463 lineGap/2 + ((BOARD_HEIGHT-1)-y) * (squareSize + lineGap);
\r
2465 hPen = pen ? premovePen : highlightPen;
\r
2466 oldPen = SelectObject(hdc, on ? hPen : gridPen);
\r
2467 MoveToEx(hdc, x1, y1, NULL);
\r
2468 LineTo(hdc, x1 + squareSize + lineGap, y1);
\r
2469 LineTo(hdc, x1 + squareSize + lineGap, y1 + squareSize + lineGap);
\r
2470 LineTo(hdc, x1, y1 + squareSize + lineGap);
\r
2471 LineTo(hdc, x1, y1);
\r
2472 SelectObject(hdc, oldPen);
\r
2476 DrawHighlightsOnDC(HDC hdc)
\r
2479 for (i=0; i<2; i++) {
\r
2480 if (highlightInfo.sq[i].x >= 0 && highlightInfo.sq[i].y >= 0)
\r
2481 DrawHighlightOnDC(hdc, TRUE,
\r
2482 highlightInfo.sq[i].x, highlightInfo.sq[i].y,
\r
2485 for (i=0; i<2; i++) {
\r
2486 if (premoveHighlightInfo.sq[i].x >= 0 &&
\r
2487 premoveHighlightInfo.sq[i].y >= 0) {
\r
2488 DrawHighlightOnDC(hdc, TRUE,
\r
2489 premoveHighlightInfo.sq[i].x,
\r
2490 premoveHighlightInfo.sq[i].y,
\r
2496 /* Note: sqcolor is used only in monoMode */
\r
2497 /* Note that this code is largely duplicated in woptions.c,
\r
2498 function DrawSampleSquare, so that needs to be updated too */
\r
2500 DrawPieceOnDC(HDC hdc, ChessSquare piece, int color, int sqcolor, int x, int y, HDC tmphdc)
\r
2502 HBITMAP oldBitmap;
\r
2506 if (appData.blindfold) return;
\r
2508 /* [AS] Use font-based pieces if needed */
\r
2509 if( fontBitmapSquareSize >= 0 && squareSize > 32 ) {
\r
2510 /* Create piece bitmaps, or do nothing if piece set is up to date */
\r
2511 CreatePiecesFromFont();
\r
2513 if( fontBitmapSquareSize == squareSize ) {
\r
2514 int index = TranslatePieceToFontPiece(piece);
\r
2516 SelectObject( tmphdc, hPieceMask[ index ] );
\r
2520 squareSize, squareSize,
\r
2525 SelectObject( tmphdc, hPieceFace[ index ] );
\r
2529 squareSize, squareSize,
\r
2538 if (appData.monoMode) {
\r
2539 SelectObject(tmphdc, PieceBitmap(piece,
\r
2540 color == sqcolor ? OUTLINE_PIECE : SOLID_PIECE));
\r
2541 BitBlt(hdc, x, y, squareSize, squareSize, tmphdc, 0, 0,
\r
2542 sqcolor ? SRCCOPY : NOTSRCCOPY);
\r
2544 tmpSize = squareSize;
\r
2546 ((piece >= (int)WhiteNightrider && piece <= WhiteGrasshopper) ||
\r
2547 (piece >= (int)BlackNightrider && piece <= BlackGrasshopper)) ) {
\r
2548 /* [HGM] no bitmap available for promoted pieces in Crazyhouse */
\r
2549 /* Bitmaps of smaller size are substituted, but we have to align them */
\r
2550 x += (squareSize - minorSize)>>1;
\r
2551 y += squareSize - minorSize - 2;
\r
2552 tmpSize = minorSize;
\r
2554 if (color || appData.allWhite ) {
\r
2555 oldBitmap = SelectObject(tmphdc, PieceBitmap(piece, WHITE_PIECE));
\r
2557 oldBrush = SelectObject(hdc, whitePieceBrush);
\r
2558 else oldBrush = SelectObject(hdc, blackPieceBrush);
\r
2559 if(appData.upsideDown && color==flipView)
\r
2560 StretchBlt(hdc, x+tmpSize, y+tmpSize, -tmpSize, -tmpSize, tmphdc, 0, 0, tmpSize, tmpSize, 0x00B8074A);
\r
2562 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, 0x00B8074A);
\r
2563 /* Use black for outline of white pieces */
\r
2564 SelectObject(tmphdc, PieceBitmap(piece, OUTLINE_PIECE));
\r
2565 if(appData.upsideDown && color==flipView)
\r
2566 StretchBlt(hdc, x+tmpSize, y+tmpSize, -tmpSize, -tmpSize, tmphdc, 0, 0, tmpSize, tmpSize, SRCAND);
\r
2568 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, SRCAND);
\r
2570 /* Use square color for details of black pieces */
\r
2571 oldBitmap = SelectObject(tmphdc, PieceBitmap(piece, SOLID_PIECE));
\r
2572 oldBrush = SelectObject(hdc, blackPieceBrush);
\r
2573 if(appData.upsideDown && !flipView)
\r
2574 StretchBlt(hdc, x+tmpSize, y+tmpSize, -tmpSize, -tmpSize, tmphdc, 0, 0, tmpSize, tmpSize, 0x00B8074A);
\r
2576 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, 0x00B8074A);
\r
2578 SelectObject(hdc, oldBrush);
\r
2579 SelectObject(tmphdc, oldBitmap);
\r
2583 /* [AS] Compute a drawing mode for a square, based on specified settings (see DrawTile) */
\r
2584 int GetBackTextureMode( int algo )
\r
2586 int result = BACK_TEXTURE_MODE_DISABLED;
\r
2590 case BACK_TEXTURE_MODE_PLAIN:
\r
2591 result = 1; /* Always use identity map */
\r
2593 case BACK_TEXTURE_MODE_FULL_RANDOM:
\r
2594 result = 1 + (myrandom() % 3); /* Pick a transformation at random */
\r
2602 [AS] Compute and save texture drawing info, otherwise we may not be able
\r
2603 to handle redraws cleanly (as random numbers would always be different).
\r
2605 VOID RebuildTextureSquareInfo()
\r
2615 ZeroMemory( &backTextureSquareInfo, sizeof(backTextureSquareInfo) );
\r
2617 if( liteBackTexture != NULL ) {
\r
2618 if( GetObject( liteBackTexture, sizeof(bi), &bi ) > 0 ) {
\r
2619 lite_w = bi.bmWidth;
\r
2620 lite_h = bi.bmHeight;
\r
2624 if( darkBackTexture != NULL ) {
\r
2625 if( GetObject( darkBackTexture, sizeof(bi), &bi ) > 0 ) {
\r
2626 dark_w = bi.bmWidth;
\r
2627 dark_h = bi.bmHeight;
\r
2631 for( row=0; row<BOARD_HEIGHT; row++ ) {
\r
2632 for( col=0; col<BOARD_WIDTH; col++ ) {
\r
2633 if( (col + row) & 1 ) {
\r
2635 if( lite_w >= squareSize && lite_h >= squareSize ) {
\r
2636 backTextureSquareInfo[row][col].x = col * (lite_w - squareSize) / (BOARD_WIDTH-1); /* [HGM] divide by size-1 in stead of size! */
\r
2637 backTextureSquareInfo[row][col].y = (BOARD_HEIGHT-1-row) * (lite_h - squareSize) / (BOARD_HEIGHT-1);
\r
2638 backTextureSquareInfo[row][col].mode = GetBackTextureMode(liteBackTextureMode);
\r
2643 if( dark_w >= squareSize && dark_h >= squareSize ) {
\r
2644 backTextureSquareInfo[row][col].x = col * (dark_w - squareSize) / (BOARD_WIDTH-1);
\r
2645 backTextureSquareInfo[row][col].y = (BOARD_HEIGHT-1-row) * (dark_h - squareSize) / (BOARD_HEIGHT-1);
\r
2646 backTextureSquareInfo[row][col].mode = GetBackTextureMode(darkBackTextureMode);
\r
2653 /* [AS] Arrow highlighting support */
\r
2655 static int A_WIDTH = 5; /* Width of arrow body */
\r
2657 #define A_HEIGHT_FACTOR 6 /* Length of arrow "point", relative to body width */
\r
2658 #define A_WIDTH_FACTOR 3 /* Width of arrow "point", relative to body width */
\r
2660 static double Sqr( double x )
\r
2665 static int Round( double x )
\r
2667 return (int) (x + 0.5);
\r
2670 /* Draw an arrow between two points using current settings */
\r
2671 VOID DrawArrowBetweenPoints( HDC hdc, int s_x, int s_y, int d_x, int d_y )
\r
2674 double dx, dy, j, k, x, y;
\r
2676 if( d_x == s_x ) {
\r
2677 int h = (d_y > s_y) ? +A_WIDTH*A_HEIGHT_FACTOR : -A_WIDTH*A_HEIGHT_FACTOR;
\r
2679 arrow[0].x = s_x + A_WIDTH;
\r
2682 arrow[1].x = s_x + A_WIDTH;
\r
2683 arrow[1].y = d_y - h;
\r
2685 arrow[2].x = s_x + A_WIDTH*A_WIDTH_FACTOR;
\r
2686 arrow[2].y = d_y - h;
\r
2691 arrow[4].x = s_x - A_WIDTH*A_WIDTH_FACTOR;
\r
2692 arrow[4].y = d_y - h;
\r
2694 arrow[5].x = s_x - A_WIDTH;
\r
2695 arrow[5].y = d_y - h;
\r
2697 arrow[6].x = s_x - A_WIDTH;
\r
2700 else if( d_y == s_y ) {
\r
2701 int w = (d_x > s_x) ? +A_WIDTH*A_HEIGHT_FACTOR : -A_WIDTH*A_HEIGHT_FACTOR;
\r
2704 arrow[0].y = s_y + A_WIDTH;
\r
2706 arrow[1].x = d_x - w;
\r
2707 arrow[1].y = s_y + A_WIDTH;
\r
2709 arrow[2].x = d_x - w;
\r
2710 arrow[2].y = s_y + A_WIDTH*A_WIDTH_FACTOR;
\r
2715 arrow[4].x = d_x - w;
\r
2716 arrow[4].y = s_y - A_WIDTH*A_WIDTH_FACTOR;
\r
2718 arrow[5].x = d_x - w;
\r
2719 arrow[5].y = s_y - A_WIDTH;
\r
2722 arrow[6].y = s_y - A_WIDTH;
\r
2725 /* [AS] Needed a lot of paper for this! :-) */
\r
2726 dy = (double) (d_y - s_y) / (double) (d_x - s_x);
\r
2727 dx = (double) (s_x - d_x) / (double) (s_y - d_y);
\r
2729 j = sqrt( Sqr(A_WIDTH) / (1.0 + Sqr(dx)) );
\r
2731 k = sqrt( Sqr(A_WIDTH*A_HEIGHT_FACTOR) / (1.0 + Sqr(dy)) );
\r
2736 arrow[0].x = Round(x - j);
\r
2737 arrow[0].y = Round(y + j*dx);
\r
2739 arrow[1].x = Round(x + j);
\r
2740 arrow[1].y = Round(y - j*dx);
\r
2743 x = (double) d_x - k;
\r
2744 y = (double) d_y - k*dy;
\r
2747 x = (double) d_x + k;
\r
2748 y = (double) d_y + k*dy;
\r
2751 arrow[2].x = Round(x + j);
\r
2752 arrow[2].y = Round(y - j*dx);
\r
2754 arrow[3].x = Round(x + j*A_WIDTH_FACTOR);
\r
2755 arrow[3].y = Round(y - j*A_WIDTH_FACTOR*dx);
\r
2760 arrow[5].x = Round(x - j*A_WIDTH_FACTOR);
\r
2761 arrow[5].y = Round(y + j*A_WIDTH_FACTOR*dx);
\r
2763 arrow[6].x = Round(x - j);
\r
2764 arrow[6].y = Round(y + j*dx);
\r
2767 Polygon( hdc, arrow, 7 );
\r
2770 /* [AS] Draw an arrow between two squares */
\r
2771 VOID DrawArrowBetweenSquares( HDC hdc, int s_col, int s_row, int d_col, int d_row )
\r
2773 int s_x, s_y, d_x, d_y;
\r
2780 if( s_col == d_col && s_row == d_row ) {
\r
2784 /* Get source and destination points */
\r
2785 SquareToPos( s_row, s_col, &s_x, &s_y);
\r
2786 SquareToPos( d_row, d_col, &d_x, &d_y);
\r
2789 d_y += squareSize / 4;
\r
2791 else if( d_y < s_y ) {
\r
2792 d_y += 3 * squareSize / 4;
\r
2795 d_y += squareSize / 2;
\r
2799 d_x += squareSize / 4;
\r
2801 else if( d_x < s_x ) {
\r
2802 d_x += 3 * squareSize / 4;
\r
2805 d_x += squareSize / 2;
\r
2808 s_x += squareSize / 2;
\r
2809 s_y += squareSize / 2;
\r
2811 /* Adjust width */
\r
2812 A_WIDTH = squareSize / 14;
\r
2815 stLB.lbStyle = BS_SOLID;
\r
2816 stLB.lbColor = appData.highlightArrowColor;
\r
2819 hpen = CreatePen( PS_SOLID, 2, RGB(0x00,0x00,0x00) );
\r
2820 holdpen = SelectObject( hdc, hpen );
\r
2821 hbrush = CreateBrushIndirect( &stLB );
\r
2822 holdbrush = SelectObject( hdc, hbrush );
\r
2824 DrawArrowBetweenPoints( hdc, s_x, s_y, d_x, d_y );
\r
2826 SelectObject( hdc, holdpen );
\r
2827 SelectObject( hdc, holdbrush );
\r
2828 DeleteObject( hpen );
\r
2829 DeleteObject( hbrush );
\r
2832 BOOL HasHighlightInfo()
\r
2834 BOOL result = FALSE;
\r
2836 if( highlightInfo.sq[0].x >= 0 && highlightInfo.sq[0].y >= 0 &&
\r
2837 highlightInfo.sq[1].x >= 0 && highlightInfo.sq[1].y >= 0 )
\r
2845 BOOL IsDrawArrowEnabled()
\r
2847 BOOL result = FALSE;
\r
2849 if( appData.highlightMoveWithArrow && squareSize >= 32 ) {
\r
2856 VOID DrawArrowHighlight( HDC hdc )
\r
2858 if( IsDrawArrowEnabled() && HasHighlightInfo() ) {
\r
2859 DrawArrowBetweenSquares( hdc,
\r
2860 highlightInfo.sq[0].x, highlightInfo.sq[0].y,
\r
2861 highlightInfo.sq[1].x, highlightInfo.sq[1].y );
\r
2865 HRGN GetArrowHighlightClipRegion( HDC hdc )
\r
2867 HRGN result = NULL;
\r
2869 if( HasHighlightInfo() ) {
\r
2870 int x1, y1, x2, y2;
\r
2871 int sx, sy, dx, dy;
\r
2873 SquareToPos(highlightInfo.sq[0].y, highlightInfo.sq[0].x, &x1, &y1 );
\r
2874 SquareToPos(highlightInfo.sq[1].y, highlightInfo.sq[1].x, &x2, &y2 );
\r
2876 sx = MIN( x1, x2 );
\r
2877 sy = MIN( y1, y2 );
\r
2878 dx = MAX( x1, x2 ) + squareSize;
\r
2879 dy = MAX( y1, y2 ) + squareSize;
\r
2881 result = CreateRectRgn( sx, sy, dx, dy );
\r
2888 Warning: this function modifies the behavior of several other functions.
\r
2890 Basically, Winboard is optimized to avoid drawing the whole board if not strictly
\r
2891 needed. Unfortunately, the decision whether or not to perform a full or partial
\r
2892 repaint is scattered all over the place, which is not good for features such as
\r
2893 "arrow highlighting" that require a full repaint of the board.
\r
2895 So, I've tried to patch the code where I thought it made sense (e.g. after or during
\r
2896 user interaction, when speed is not so important) but especially to avoid errors
\r
2897 in the displayed graphics.
\r
2899 In such patched places, I always try refer to this function so there is a single
\r
2900 place to maintain knowledge.
\r
2902 To restore the original behavior, just return FALSE unconditionally.
\r
2904 BOOL IsFullRepaintPreferrable()
\r
2906 BOOL result = FALSE;
\r
2908 if( (appData.highlightLastMove || appData.highlightDragging) && IsDrawArrowEnabled() ) {
\r
2909 /* Arrow may appear on the board */
\r
2917 This function is called by DrawPosition to know whether a full repaint must
\r
2920 Only DrawPosition may directly call this function, which makes use of
\r
2921 some state information. Other function should call DrawPosition specifying
\r
2922 the repaint flag, and can use IsFullRepaintPreferrable if needed.
\r
2924 BOOL DrawPositionNeedsFullRepaint()
\r
2926 BOOL result = FALSE;
\r
2929 Probably a slightly better policy would be to trigger a full repaint
\r
2930 when animInfo.piece changes state (i.e. empty -> non-empty and viceversa),
\r
2931 but animation is fast enough that it's difficult to notice.
\r
2933 if( animInfo.piece == EmptySquare ) {
\r
2934 if( (appData.highlightLastMove || appData.highlightDragging) && IsDrawArrowEnabled() /*&& HasHighlightInfo()*/ ) {
\r
2943 DrawBoardOnDC(HDC hdc, Board board, HDC tmphdc)
\r
2945 int row, column, x, y, square_color, piece_color;
\r
2946 ChessSquare piece;
\r
2948 HDC texture_hdc = NULL;
\r
2950 /* [AS] Initialize background textures if needed */
\r
2951 if( liteBackTexture != NULL || darkBackTexture != NULL ) {
\r
2952 static int backTextureBoardSize; /* [HGM] boardsize: also new texture if board format changed */
\r
2953 if( backTextureSquareSize != squareSize
\r
2954 || backTextureBoardSize != BOARD_WIDTH+BOARD_FILES*BOARD_HEIGHT) {
\r
2955 backTextureBoardSize = BOARD_WIDTH+BOARD_FILES*BOARD_HEIGHT;
\r
2956 backTextureSquareSize = squareSize;
\r
2957 RebuildTextureSquareInfo();
\r
2960 texture_hdc = CreateCompatibleDC( hdc );
\r
2963 for (row = 0; row < BOARD_HEIGHT; row++) {
\r
2964 for (column = 0; column < BOARD_WIDTH; column++) {
\r
2966 SquareToPos(row, column, &x, &y);
\r
2968 piece = board[row][column];
\r
2970 square_color = ((column + row) % 2) == 1;
\r
2971 if( gameInfo.variant == VariantXiangqi ) {
\r
2972 square_color = !InPalace(row, column);
\r
2973 if(BOARD_HEIGHT&1) { if(row==BOARD_HEIGHT/2) square_color ^= 1; }
\r
2974 else if(row < BOARD_HEIGHT/2) square_color ^= 1;
\r
2976 piece_color = (int) piece < (int) BlackPawn;
\r
2979 /* [HGM] holdings file: light square or black */
\r
2980 if(column == BOARD_LEFT-2) {
\r
2981 if( row > BOARD_HEIGHT - gameInfo.holdingsSize - 1 )
\r
2984 DisplayHoldingsCount(hdc, x, y, 0, 0); /* black out */
\r
2988 if(column == BOARD_RGHT + 1 ) {
\r
2989 if( row < gameInfo.holdingsSize )
\r
2992 DisplayHoldingsCount(hdc, x, y, 0, 0);
\r
2996 if(column == BOARD_LEFT-1 ) /* left align */
\r
2997 DisplayHoldingsCount(hdc, x, y, flipView, (int) board[row][column]);
\r
2998 else if( column == BOARD_RGHT) /* right align */
\r
2999 DisplayHoldingsCount(hdc, x, y, !flipView, (int) board[row][column]);
\r
3001 if (appData.monoMode) {
\r
3002 if (piece == EmptySquare) {
\r
3003 BitBlt(hdc, x, y, squareSize, squareSize, 0, 0, 0,
\r
3004 square_color ? WHITENESS : BLACKNESS);
\r
3006 DrawPieceOnDC(hdc, piece, piece_color, square_color, x, y, tmphdc);
\r
3009 else if( backTextureSquareInfo[row][column].mode > 0 ) {
\r
3010 /* [AS] Draw the square using a texture bitmap */
\r
3011 HBITMAP hbm = SelectObject( texture_hdc, square_color ? liteBackTexture : darkBackTexture );
\r
3012 int r = row, c = column; // [HGM] do not flip board in flipView
\r
3013 if(flipView) { r = BOARD_HEIGHT-1 - r; c = BOARD_WIDTH-1 - c; }
\r
3016 squareSize, squareSize,
\r
3019 backTextureSquareInfo[r][c].mode,
\r
3020 backTextureSquareInfo[r][c].x,
\r
3021 backTextureSquareInfo[r][c].y );
\r
3023 SelectObject( texture_hdc, hbm );
\r
3025 if (piece != EmptySquare) {
\r
3026 DrawPieceOnDC(hdc, piece, piece_color, -1, x, y, tmphdc);
\r
3030 HBRUSH brush = square_color ? lightSquareBrush : darkSquareBrush;
\r
3032 oldBrush = SelectObject(hdc, brush );
\r
3033 BitBlt(hdc, x, y, squareSize, squareSize, 0, 0, 0, PATCOPY);
\r
3034 SelectObject(hdc, oldBrush);
\r
3035 if (piece != EmptySquare)
\r
3036 DrawPieceOnDC(hdc, piece, piece_color, -1, x, y, tmphdc);
\r
3041 if( texture_hdc != NULL ) {
\r
3042 DeleteDC( texture_hdc );
\r
3046 int saveDiagFlag = 0; FILE *diagFile; // [HGM] diag
\r
3047 void fputDW(FILE *f, int x)
\r
3049 fputc(x & 255, f);
\r
3050 fputc(x>>8 & 255, f);
\r
3051 fputc(x>>16 & 255, f);
\r
3052 fputc(x>>24 & 255, f);
\r
3055 #define MAX_CLIPS 200 /* more than enough */
\r
3058 DrawLogoOnDC(HDC hdc, RECT logoRect, HBITMAP logo)
\r
3060 // HBITMAP bufferBitmap;
\r
3065 int w = 100, h = 50;
\r
3067 if(logo == NULL) return;
\r
3068 // GetClientRect(hwndMain, &Rect);
\r
3069 // bufferBitmap = CreateCompatibleBitmap(hdc, Rect.right-Rect.left+1,
\r
3070 // Rect.bottom-Rect.top+1);
\r
3071 tmphdc = CreateCompatibleDC(hdc);
\r
3072 hbm = SelectObject(tmphdc, logo);
\r
3073 if( GetObject( logo, sizeof(bi), &bi ) > 0 ) {
\r
3077 StretchBlt(hdc, logoRect.left, logoRect.top, logoRect.right - logoRect.left,
\r
3078 logoRect.bottom - logoRect.top, tmphdc, 0, 0, w, h, SRCCOPY);
\r
3079 SelectObject(tmphdc, hbm);
\r
3084 HDCDrawPosition(HDC hdc, BOOLEAN repaint, Board board)
\r
3086 static Board lastReq, lastDrawn;
\r
3087 static HighlightInfo lastDrawnHighlight, lastDrawnPremove;
\r
3088 static int lastDrawnFlipView = 0;
\r
3089 static int lastReqValid = 0, lastDrawnValid = 0;
\r
3090 int releaseDC, x, y, x2, y2, row, column, num_clips = 0, i;
\r
3093 HBITMAP bufferBitmap;
\r
3094 HBITMAP oldBitmap;
\r
3096 HRGN clips[MAX_CLIPS];
\r
3097 ChessSquare dragged_piece = EmptySquare;
\r
3099 /* I'm undecided on this - this function figures out whether a full
\r
3100 * repaint is necessary on its own, so there's no real reason to have the
\r
3101 * caller tell it that. I think this can safely be set to FALSE - but
\r
3102 * if we trust the callers not to request full repaints unnessesarily, then
\r
3103 * we could skip some clipping work. In other words, only request a full
\r
3104 * redraw when the majority of pieces have changed positions (ie. flip,
\r
3105 * gamestart and similar) --Hawk
\r
3107 Boolean fullrepaint = repaint;
\r
3109 if( DrawPositionNeedsFullRepaint() ) {
\r
3110 fullrepaint = TRUE;
\r
3113 if (board == NULL) {
\r
3114 if (!lastReqValid) {
\r
3119 CopyBoard(lastReq, board);
\r
3123 if (doingSizing) {
\r
3127 if (IsIconic(hwndMain)) {
\r
3131 if (hdc == NULL) {
\r
3132 hdc = GetDC(hwndMain);
\r
3133 if (!appData.monoMode) {
\r
3134 SelectPalette(hdc, hPal, FALSE);
\r
3135 RealizePalette(hdc);
\r
3139 releaseDC = FALSE;
\r
3142 /* Create some work-DCs */
\r
3143 hdcmem = CreateCompatibleDC(hdc);
\r
3144 tmphdc = CreateCompatibleDC(hdc);
\r
3146 /* If dragging is in progress, we temporarely remove the piece */
\r
3147 /* [HGM] or temporarily decrease count if stacked */
\r
3148 /* !! Moved to before board compare !! */
\r
3149 if (dragInfo.from.x >= 0 && dragInfo.pos.x >= 0) {
\r
3150 dragged_piece = board[dragInfo.from.y][dragInfo.from.x];
\r
3151 if(dragInfo.from.x == BOARD_LEFT-2 ) {
\r
3152 if(--board[dragInfo.from.y][dragInfo.from.x+1] == 0 )
\r
3153 board[dragInfo.from.y][dragInfo.from.x] = EmptySquare;
\r
3155 if(dragInfo.from.x == BOARD_RGHT+1) {
\r
3156 if(--board[dragInfo.from.y][dragInfo.from.x-1] == 0 )
\r
3157 board[dragInfo.from.y][dragInfo.from.x] = EmptySquare;
\r
3159 board[dragInfo.from.y][dragInfo.from.x] = EmptySquare;
\r
3162 /* Figure out which squares need updating by comparing the
\r
3163 * newest board with the last drawn board and checking if
\r
3164 * flipping has changed.
\r
3166 if (!fullrepaint && lastDrawnValid && lastDrawnFlipView == flipView) {
\r
3167 for (row = 0; row < BOARD_HEIGHT; row++) { /* [HGM] true size, not 8 */
\r
3168 for (column = 0; column < BOARD_WIDTH; column++) {
\r
3169 if (lastDrawn[row][column] != board[row][column]) {
\r
3170 SquareToPos(row, column, &x, &y);
\r
3171 clips[num_clips++] =
\r
3172 CreateRectRgn(x, y, x + squareSize, y + squareSize);
\r
3176 for (i=0; i<2; i++) {
\r
3177 if (lastDrawnHighlight.sq[i].x != highlightInfo.sq[i].x ||
\r
3178 lastDrawnHighlight.sq[i].y != highlightInfo.sq[i].y) {
\r
3179 if (lastDrawnHighlight.sq[i].x >= 0 &&
\r
3180 lastDrawnHighlight.sq[i].y >= 0) {
\r
3181 SquareToPos(lastDrawnHighlight.sq[i].y,
\r
3182 lastDrawnHighlight.sq[i].x, &x, &y);
\r
3183 clips[num_clips++] =
\r
3184 CreateRectRgn(x - lineGap, y - lineGap,
\r
3185 x + squareSize + lineGap, y + squareSize + lineGap);
\r
3187 if (highlightInfo.sq[i].x >= 0 && highlightInfo.sq[i].y >= 0) {
\r
3188 SquareToPos(highlightInfo.sq[i].y, highlightInfo.sq[i].x, &x, &y);
\r
3189 clips[num_clips++] =
\r
3190 CreateRectRgn(x - lineGap, y - lineGap,
\r
3191 x + squareSize + lineGap, y + squareSize + lineGap);
\r
3195 for (i=0; i<2; i++) {
\r
3196 if (lastDrawnPremove.sq[i].x != premoveHighlightInfo.sq[i].x ||
\r
3197 lastDrawnPremove.sq[i].y != premoveHighlightInfo.sq[i].y) {
\r
3198 if (lastDrawnPremove.sq[i].x >= 0 &&
\r
3199 lastDrawnPremove.sq[i].y >= 0) {
\r
3200 SquareToPos(lastDrawnPremove.sq[i].y,
\r
3201 lastDrawnPremove.sq[i].x, &x, &y);
\r
3202 clips[num_clips++] =
\r
3203 CreateRectRgn(x - lineGap, y - lineGap,
\r
3204 x + squareSize + lineGap, y + squareSize + lineGap);
\r
3206 if (premoveHighlightInfo.sq[i].x >= 0 &&
\r
3207 premoveHighlightInfo.sq[i].y >= 0) {
\r
3208 SquareToPos(premoveHighlightInfo.sq[i].y,
\r
3209 premoveHighlightInfo.sq[i].x, &x, &y);
\r
3210 clips[num_clips++] =
\r
3211 CreateRectRgn(x - lineGap, y - lineGap,
\r
3212 x + squareSize + lineGap, y + squareSize + lineGap);
\r
3217 fullrepaint = TRUE;
\r