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 markerBrush, /* [HGM] markers */
\r
195 whitePieceBrush, blackPieceBrush, iconBkgndBrush /*, outlineBrush*/;
\r
196 static POINT gridEndpoints[(BOARD_RANKS + BOARD_FILES + 2) * 2];
\r
197 static DWORD gridVertexCounts[BOARD_RANKS + BOARD_FILES + 2];
\r
198 static HPEN gridPen = NULL;
\r
199 static HPEN highlightPen = NULL;
\r
200 static HPEN premovePen = NULL;
\r
201 static NPLOGPALETTE pLogPal;
\r
202 static BOOL paletteChanged = FALSE;
\r
203 static HICON iconWhite, iconBlack, iconCurrent;
\r
204 static int doingSizing = FALSE;
\r
205 static int lastSizing = 0;
\r
206 static int prevStderrPort;
\r
207 static HBITMAP userLogo;
\r
209 static HBITMAP liteBackTexture = NULL;
\r
210 static HBITMAP darkBackTexture = NULL;
\r
211 static int liteBackTextureMode = BACK_TEXTURE_MODE_PLAIN;
\r
212 static int darkBackTextureMode = BACK_TEXTURE_MODE_PLAIN;
\r
213 static int backTextureSquareSize = 0;
\r
214 static struct { int x; int y; int mode; } backTextureSquareInfo[BOARD_RANKS][BOARD_FILES];
\r
216 #if __GNUC__ && !defined(_winmajor)
\r
217 #define oldDialog 0 /* cygwin doesn't define _winmajor; mingw does */
\r
219 #if defined(_winmajor)
\r
220 #define oldDialog (_winmajor < 4)
\r
222 #define oldDialog 0
\r
232 int cliWidth, cliHeight;
\r
235 SizeInfo sizeInfo[] =
\r
237 { "tiny", 21, 0, 1, 1, 0, 0 },
\r
238 { "teeny", 25, 1, 1, 1, 0, 0 },
\r
239 { "dinky", 29, 1, 1, 1, 0, 0 },
\r
240 { "petite", 33, 1, 1, 1, 0, 0 },
\r
241 { "slim", 37, 2, 1, 0, 0, 0 },
\r
242 { "small", 40, 2, 1, 0, 0, 0 },
\r
243 { "mediocre", 45, 2, 1, 0, 0, 0 },
\r
244 { "middling", 49, 2, 0, 0, 0, 0 },
\r
245 { "average", 54, 2, 0, 0, 0, 0 },
\r
246 { "moderate", 58, 3, 0, 0, 0, 0 },
\r
247 { "medium", 64, 3, 0, 0, 0, 0 },
\r
248 { "bulky", 72, 3, 0, 0, 0, 0 },
\r
249 { "large", 80, 3, 0, 0, 0, 0 },
\r
250 { "big", 87, 3, 0, 0, 0, 0 },
\r
251 { "huge", 95, 3, 0, 0, 0, 0 },
\r
252 { "giant", 108, 3, 0, 0, 0, 0 },
\r
253 { "colossal", 116, 4, 0, 0, 0, 0 },
\r
254 { "titanic", 129, 4, 0, 0, 0, 0 },
\r
255 { NULL, 0, 0, 0, 0, 0, 0 }
\r
258 #define MF(x) {x, {{0,}, 0. }, {0, }, 0}
\r
259 MyFont fontRec[NUM_SIZES][NUM_FONTS] =
\r
261 { 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
262 { 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
263 { 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
264 { 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
265 { 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
266 { 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
267 { 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
268 { 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
269 { 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
270 { 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
271 { 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
272 { 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
273 { 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
274 { 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
275 { 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
276 { 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
277 { 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
278 { 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
281 MyFont *font[NUM_SIZES][NUM_FONTS];
\r
290 #define BUTTON_WIDTH (tinyLayout ? 16 : 32)
\r
291 #define N_BUTTONS 5
\r
293 MyButtonDesc buttonDesc[N_BUTTONS] =
\r
295 {"<<", IDM_ToStart, NULL, NULL},
\r
296 {"<", IDM_Backward, NULL, NULL},
\r
297 {"P", IDM_Pause, NULL, NULL},
\r
298 {">", IDM_Forward, NULL, NULL},
\r
299 {">>", IDM_ToEnd, NULL, NULL},
\r
302 int tinyLayout = 0, smallLayout = 0;
\r
303 #define MENU_BAR_ITEMS 7
\r
304 char *menuBarText[2][MENU_BAR_ITEMS+1] = {
\r
305 { "&File", "&Mode", "&Action", "&Step", "&Options", "&Help", NULL },
\r
306 { "&F", "&M", "&A", "&S", "&O", "&H", NULL },
\r
310 MySound sounds[(int)NSoundClasses];
\r
311 MyTextAttribs textAttribs[(int)NColorClasses];
\r
313 MyColorizeAttribs colorizeAttribs[] = {
\r
314 { (COLORREF)0, 0, "Shout Text" },
\r
315 { (COLORREF)0, 0, "SShout/CShout" },
\r
316 { (COLORREF)0, 0, "Channel 1 Text" },
\r
317 { (COLORREF)0, 0, "Channel Text" },
\r
318 { (COLORREF)0, 0, "Kibitz Text" },
\r
319 { (COLORREF)0, 0, "Tell Text" },
\r
320 { (COLORREF)0, 0, "Challenge Text" },
\r
321 { (COLORREF)0, 0, "Request Text" },
\r
322 { (COLORREF)0, 0, "Seek Text" },
\r
323 { (COLORREF)0, 0, "Normal Text" },
\r
324 { (COLORREF)0, 0, "None" }
\r
329 static char *commentTitle;
\r
330 static char *commentText;
\r
331 static int commentIndex;
\r
332 static Boolean editComment = FALSE;
\r
335 char errorTitle[MSG_SIZ];
\r
336 char errorMessage[2*MSG_SIZ];
\r
337 HWND errorDialog = NULL;
\r
338 BOOLEAN moveErrorMessageUp = FALSE;
\r
339 BOOLEAN consoleEcho = TRUE;
\r
340 CHARFORMAT consoleCF;
\r
341 COLORREF consoleBackgroundColor;
\r
343 char *programVersion;
\r
349 typedef int CPKind;
\r
358 SOCKET sock2; /* stderr socket for OpenRcmd */
\r
361 #define INPUT_SOURCE_BUF_SIZE 4096
\r
363 typedef struct _InputSource {
\r
370 char buf[INPUT_SOURCE_BUF_SIZE];
\r
374 InputCallback func;
\r
375 struct _InputSource *second; /* for stderr thread on CPRcmd */
\r
379 InputSource *consoleInputSource;
\r
384 VOID ConsoleOutput(char* data, int length, int forceVisible);
\r
385 VOID ConsoleCreate();
\r
387 ConsoleWndProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);
\r
388 VOID ColorizeTextPopup(HWND hwnd, ColorClass cc);
\r
389 VOID PrintCommSettings(FILE *f, char *name, DCB *dcb);
\r
390 VOID ParseCommSettings(char *arg, DCB *dcb);
\r
392 StartupDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);
\r
393 VOID APIENTRY MenuPopup(HWND hwnd, POINT pt, HMENU hmenu, UINT def);
\r
394 void ParseIcsTextMenu(char *icsTextMenuString);
\r
395 VOID PopUpMoveDialog(char firstchar);
\r
396 VOID PopUpNameDialog(char firstchar);
\r
397 VOID UpdateSampleText(HWND hDlg, int id, MyColorizeAttribs *mca);
\r
401 int GameListOptions();
\r
403 int dummy; // [HGM] for obsolete args
\r
405 HWND hwndMain = NULL; /* root window*/
\r
406 HWND hwndConsole = NULL;
\r
407 HWND commentDialog = NULL;
\r
408 HWND moveHistoryDialog = NULL;
\r
409 HWND evalGraphDialog = NULL;
\r
410 HWND engineOutputDialog = NULL;
\r
411 HWND gameListDialog = NULL;
\r
412 HWND editTagsDialog = NULL;
\r
414 int commentUp = FALSE;
\r
416 WindowPlacement wpMain;
\r
417 WindowPlacement wpConsole;
\r
418 WindowPlacement wpComment;
\r
419 WindowPlacement wpMoveHistory;
\r
420 WindowPlacement wpEvalGraph;
\r
421 WindowPlacement wpEngineOutput;
\r
422 WindowPlacement wpGameList;
\r
423 WindowPlacement wpTags;
\r
425 VOID EngineOptionsPopup(); // [HGM] settings
\r
427 VOID GothicPopUp(char *title, VariantClass variant);
\r
429 * Setting "frozen" should disable all user input other than deleting
\r
430 * the window. We do this while engines are initializing themselves.
\r
432 static int frozen = 0;
\r
433 static int oldMenuItemState[MENU_BAR_ITEMS];
\r
439 if (frozen) return;
\r
441 hmenu = GetMenu(hwndMain);
\r
442 for (i=0; i<MENU_BAR_ITEMS; i++) {
\r
443 oldMenuItemState[i] = EnableMenuItem(hmenu, i, MF_BYPOSITION|MF_GRAYED);
\r
445 DrawMenuBar(hwndMain);
\r
448 /* Undo a FreezeUI */
\r
454 if (!frozen) return;
\r
456 hmenu = GetMenu(hwndMain);
\r
457 for (i=0; i<MENU_BAR_ITEMS; i++) {
\r
458 EnableMenuItem(hmenu, i, MF_BYPOSITION|oldMenuItemState[i]);
\r
460 DrawMenuBar(hwndMain);
\r
463 /*static*/ int fromX = -1, fromY = -1, toX, toY; // [HGM] moved upstream, so JAWS can use them
\r
465 /* JAWS preparation patch (WinBoard for the sight impaired). Define required insertions as empty */
\r
471 #define JAWS_ALT_INTERCEPT
\r
472 #define JAWS_KB_NAVIGATION
\r
473 #define JAWS_MENU_ITEMS
\r
474 #define JAWS_SILENCE
\r
475 #define JAWS_REPLAY
\r
477 #define JAWS_COPYRIGHT
\r
478 #define JAWS_DELETE(X) X
\r
479 #define SAYMACHINEMOVE()
\r
483 /*---------------------------------------------------------------------------*\
\r
487 \*---------------------------------------------------------------------------*/
\r
490 WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
\r
491 LPSTR lpCmdLine, int nCmdShow)
\r
494 HANDLE hAccelMain, hAccelNoAlt, hAccelNoICS;
\r
495 // INITCOMMONCONTROLSEX ex;
\r
499 LoadLibrary("RICHED32.DLL");
\r
500 consoleCF.cbSize = sizeof(CHARFORMAT);
\r
502 if (!InitApplication(hInstance)) {
\r
505 if (!InitInstance(hInstance, nCmdShow, lpCmdLine)) {
\r
511 // InitCommonControlsEx(&ex);
\r
512 InitCommonControls();
\r
514 hAccelMain = LoadAccelerators (hInstance, szAppName);
\r
515 hAccelNoAlt = LoadAccelerators (hInstance, "NO_ALT");
\r
516 hAccelNoICS = LoadAccelerators( hInstance, "NO_ICS"); /* [AS] No Ctrl-V on ICS!!! */
\r
518 /* Acquire and dispatch messages until a WM_QUIT message is received. */
\r
520 while (GetMessage(&msg, /* message structure */
\r
521 NULL, /* handle of window receiving the message */
\r
522 0, /* lowest message to examine */
\r
523 0)) /* highest message to examine */
\r
526 if(msg.message == WM_CHAR && msg.wParam == '\t') {
\r
527 // [HGM] navigate: switch between all windows with tab
\r
528 HWND e1 = NULL, e2 = NULL, mh = NULL, hInput = NULL, hText = NULL;
\r
529 int i, currentElement = 0;
\r
531 // first determine what element of the chain we come from (if any)
\r
532 if(appData.icsActive) {
\r
533 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
534 hText = GetDlgItem(hwndConsole, OPT_ConsoleText);
\r
536 if(engineOutputDialog && EngineOutputIsUp()) {
\r
537 e1 = GetDlgItem(engineOutputDialog, IDC_EngineMemo1);
\r
538 e2 = GetDlgItem(engineOutputDialog, IDC_EngineMemo2);
\r
540 if(moveHistoryDialog && MoveHistoryIsUp()) {
\r
541 mh = GetDlgItem(moveHistoryDialog, IDC_MoveHistory);
\r
543 if(msg.hwnd == hwndMain) currentElement = 7 ; else
\r
544 if(msg.hwnd == engineOutputDialog) currentElement = 2; else
\r
545 if(msg.hwnd == e1) currentElement = 2; else
\r
546 if(msg.hwnd == e2) currentElement = 3; else
\r
547 if(msg.hwnd == moveHistoryDialog) currentElement = 4; else
\r
548 if(msg.hwnd == mh) currentElement = 4; else
\r
549 if(msg.hwnd == evalGraphDialog) currentElement = 6; else
\r
550 if(msg.hwnd == hText) currentElement = 5; else
\r
551 if(msg.hwnd == hInput) currentElement = 6; else
\r
552 for (i = 0; i < N_BUTTONS; i++) {
\r
553 if (buttonDesc[i].hwnd == msg.hwnd) { currentElement = 1; break; }
\r
556 // determine where to go to
\r
557 if(currentElement) { HWND h = NULL; int direction = GetKeyState(VK_SHIFT) < 0 ? -1 : 1;
\r
559 currentElement = (currentElement + direction) % 7;
\r
560 switch(currentElement) {
\r
562 h = hwndMain; break; // passing this case always makes the loop exit
\r
564 h = buttonDesc[0].hwnd; break; // could be NULL
\r
566 if(!EngineOutputIsUp()) continue; // skip closed auxiliary windows
\r
569 if(!EngineOutputIsUp()) continue;
\r
572 if(!MoveHistoryIsUp()) continue;
\r
574 // case 6: // input to eval graph does not seem to get here!
\r
575 // if(!EvalGraphIsUp()) continue;
\r
576 // h = evalGraphDialog; break;
\r
578 if(!appData.icsActive) continue;
\r
582 if(!appData.icsActive) continue;
\r
588 if(currentElement > 4 && IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
589 if(currentElement < 5 && IsIconic(hwndMain)) ShowWindow(hwndMain, SW_RESTORE); // all open together
\r
592 continue; // this message now has been processed
\r
596 if (!(commentDialog && IsDialogMessage(commentDialog, &msg)) &&
\r
597 !(moveHistoryDialog && IsDialogMessage(moveHistoryDialog, &msg)) &&
\r
598 !(evalGraphDialog && IsDialogMessage(evalGraphDialog, &msg)) &&
\r
599 !(engineOutputDialog && IsDialogMessage(engineOutputDialog, &msg)) &&
\r
600 !(editTagsDialog && IsDialogMessage(editTagsDialog, &msg)) &&
\r
601 !(gameListDialog && IsDialogMessage(gameListDialog, &msg)) &&
\r
602 !(errorDialog && IsDialogMessage(errorDialog, &msg)) &&
\r
603 !(!frozen && TranslateAccelerator(hwndMain, hAccelMain, &msg)) && JAWS_ACCEL
\r
604 !(!hwndConsole && TranslateAccelerator(hwndMain, hAccelNoICS, &msg)) &&
\r
605 !(!hwndConsole && TranslateAccelerator(hwndMain, hAccelNoAlt, &msg))) {
\r
606 int done = 0, i; // [HGM] chat: dispatch cat-box messages
\r
607 for(i=0; i<MAX_CHAT; i++)
\r
608 if(chatHandle[i] && IsDialogMessage(chatHandle[i], &msg)) {
\r
611 if(done) continue; // [HGM] chat: end patch
\r
612 TranslateMessage(&msg); /* Translates virtual key codes */
\r
613 DispatchMessage(&msg); /* Dispatches message to window */
\r
618 return (msg.wParam); /* Returns the value from PostQuitMessage */
\r
621 /*---------------------------------------------------------------------------*\
\r
623 * Initialization functions
\r
625 \*---------------------------------------------------------------------------*/
\r
629 { // update user logo if necessary
\r
630 static char oldUserName[MSG_SIZ], *curName;
\r
632 if(appData.autoLogo) {
\r
633 curName = UserName();
\r
634 if(strcmp(curName, oldUserName)) {
\r
635 sprintf(oldUserName, "logos\\%s.bmp", curName);
\r
636 userLogo = LoadImage( 0, oldUserName, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
637 strcpy(oldUserName, curName);
\r
643 InitApplication(HINSTANCE hInstance)
\r
647 /* Fill in window class structure with parameters that describe the */
\r
650 wc.style = CS_HREDRAW | CS_VREDRAW; /* Class style(s). */
\r
651 wc.lpfnWndProc = (WNDPROC)WndProc; /* Window Procedure */
\r
652 wc.cbClsExtra = 0; /* No per-class extra data. */
\r
653 wc.cbWndExtra = 0; /* No per-window extra data. */
\r
654 wc.hInstance = hInstance; /* Owner of this class */
\r
655 wc.hIcon = LoadIcon(hInstance, "icon_white");
\r
656 wc.hCursor = LoadCursor(NULL, IDC_ARROW); /* Cursor */
\r
657 wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1); /* Default color */
\r
658 wc.lpszMenuName = szAppName; /* Menu name from .RC */
\r
659 wc.lpszClassName = szAppName; /* Name to register as */
\r
661 /* Register the window class and return success/failure code. */
\r
662 if (!RegisterClass(&wc)) return FALSE;
\r
664 wc.style = CS_HREDRAW | CS_VREDRAW;
\r
665 wc.lpfnWndProc = (WNDPROC)ConsoleWndProc;
\r
667 wc.cbWndExtra = DLGWINDOWEXTRA;
\r
668 wc.hInstance = hInstance;
\r
669 wc.hIcon = LoadIcon(hInstance, "icon_white");
\r
670 wc.hCursor = LoadCursor(NULL, IDC_ARROW);
\r
671 wc.hbrBackground = (HBRUSH)(COLOR_MENU+1);
\r
672 wc.lpszMenuName = NULL;
\r
673 wc.lpszClassName = szConsoleName;
\r
675 if (!RegisterClass(&wc)) return FALSE;
\r
680 /* Set by InitInstance, used by EnsureOnScreen */
\r
681 int screenHeight, screenWidth;
\r
684 EnsureOnScreen(int *x, int *y, int minX, int minY)
\r
686 // int gap = GetSystemMetrics(SM_CYFRAME) + GetSystemMetrics(SM_CYCAPTION);
\r
687 /* Be sure window at (x,y) is not off screen (or even mostly off screen) */
\r
688 if (*x > screenWidth - 32) *x = 0;
\r
689 if (*y > screenHeight - 32) *y = 0;
\r
690 if (*x < minX) *x = minX;
\r
691 if (*y < minY) *y = minY;
\r
695 InitInstance(HINSTANCE hInstance, int nCmdShow, LPSTR lpCmdLine)
\r
697 HWND hwnd; /* Main window handle. */
\r
699 WINDOWPLACEMENT wp;
\r
702 hInst = hInstance; /* Store instance handle in our global variable */
\r
703 programName = szAppName;
\r
705 if (SearchPath(NULL, "WinBoard.exe", NULL, MSG_SIZ, installDir, &filepart)) {
\r
706 *filepart = NULLCHAR;
\r
708 GetCurrentDirectory(MSG_SIZ, installDir);
\r
710 gameInfo.boardWidth = gameInfo.boardHeight = 8; // [HGM] won't have open window otherwise
\r
711 screenWidth = screenHeight = 1000; // [HGM] placement: kludge to allow calling EnsureOnScreen from InitAppData
\r
712 InitAppData(lpCmdLine); /* Get run-time parameters */
\r
713 /* xboard, and older WinBoards, controlled the move sound with the
\r
714 appData.ringBellAfterMoves option. In the current WinBoard, we
\r
715 always turn the option on (so that the backend will call us),
\r
716 then let the user turn the sound off by setting it to silence if
\r
717 desired. To accommodate old winboard.ini files saved by old
\r
718 versions of WinBoard, we also turn off the sound if the option
\r
719 was initially set to false. [HGM] taken out of InitAppData */
\r
720 if (!appData.ringBellAfterMoves) {
\r
721 sounds[(int)SoundMove].name = strdup("");
\r
722 appData.ringBellAfterMoves = TRUE;
\r
724 if (appData.debugMode) {
\r
725 debugFP = fopen(appData.nameOfDebugFile, "w");
\r
726 setbuf(debugFP, NULL);
\r
731 // InitEngineUCI( installDir, &first ); // [HGM] incorporated in InitBackEnd1()
\r
732 // InitEngineUCI( installDir, &second );
\r
734 /* Create a main window for this application instance. */
\r
735 hwnd = CreateWindow(szAppName, szTitle,
\r
736 (WS_OVERLAPPEDWINDOW & ~WS_MAXIMIZEBOX),
\r
737 CW_USEDEFAULT, 0, CW_USEDEFAULT, 0,
\r
738 NULL, NULL, hInstance, NULL);
\r
741 /* If window could not be created, return "failure" */
\r
746 /* [HGM] logo: Load logos if specified (must be done before InitDrawingSizes) */
\r
747 if( appData.firstLogo && appData.firstLogo[0] != NULLCHAR) {
\r
748 first.programLogo = LoadImage( 0, appData.firstLogo, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
750 if (first.programLogo == NULL && appData.debugMode) {
\r
751 fprintf( debugFP, "Unable to load logo bitmap '%s'\n", appData.firstLogo );
\r
753 } else if(appData.autoLogo) {
\r
754 if(appData.firstDirectory && appData.firstDirectory[0]) {
\r
756 sprintf(buf, "%s/logo.bmp", appData.firstDirectory);
\r
757 first.programLogo = LoadImage( 0, buf, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
761 if( appData.secondLogo && appData.secondLogo[0] != NULLCHAR) {
\r
762 second.programLogo = LoadImage( 0, appData.secondLogo, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
764 if (second.programLogo == NULL && appData.debugMode) {
\r
765 fprintf( debugFP, "Unable to load logo bitmap '%s'\n", appData.secondLogo );
\r
767 } else if(appData.autoLogo) {
\r
769 if(appData.icsActive) { // [HGM] logo: in ICS mode second can be used for ICS
\r
770 sprintf(buf, "logos\\%s.bmp", appData.icsHost);
\r
771 second.programLogo = LoadImage( 0, buf, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
773 if(appData.secondDirectory && appData.secondDirectory[0]) {
\r
774 sprintf(buf, "%s\\logo.bmp", appData.secondDirectory);
\r
775 second.programLogo = LoadImage( 0, buf, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
781 iconWhite = LoadIcon(hInstance, "icon_white");
\r
782 iconBlack = LoadIcon(hInstance, "icon_black");
\r
783 iconCurrent = iconWhite;
\r
784 InitDrawingColors();
\r
785 screenHeight = GetSystemMetrics(SM_CYSCREEN);
\r
786 screenWidth = GetSystemMetrics(SM_CXSCREEN);
\r
787 for (ibs = (int) NUM_SIZES - 1; ibs >= 0; ibs--) {
\r
788 /* Compute window size for each board size, and use the largest
\r
789 size that fits on this screen as the default. */
\r
790 InitDrawingSizes((BoardSize)(ibs+1000), 0);
\r
791 if (boardSize == (BoardSize)-1 &&
\r
792 winH <= screenHeight
\r
793 - GetSystemMetrics(SM_CYFRAME) - GetSystemMetrics(SM_CYCAPTION) - 10
\r
794 && winW <= screenWidth) {
\r
795 boardSize = (BoardSize)ibs;
\r
799 InitDrawingSizes(boardSize, 0);
\r
801 buttonCount = GetSystemMetrics(SM_CMOUSEBUTTONS);
\r
803 /* [AS] Load textures if specified */
\r
804 ZeroMemory( &backTextureSquareInfo, sizeof(backTextureSquareInfo) );
\r
806 if( appData.liteBackTextureFile && appData.liteBackTextureFile[0] != NULLCHAR && appData.liteBackTextureFile[0] != '*' ) {
\r
807 liteBackTexture = LoadImage( 0, appData.liteBackTextureFile, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
808 liteBackTextureMode = appData.liteBackTextureMode;
\r
810 if (liteBackTexture == NULL && appData.debugMode) {
\r
811 fprintf( debugFP, "Unable to load lite texture bitmap '%s'\n", appData.liteBackTextureFile );
\r
815 if( appData.darkBackTextureFile && appData.darkBackTextureFile[0] != NULLCHAR && appData.darkBackTextureFile[0] != '*' ) {
\r
816 darkBackTexture = LoadImage( 0, appData.darkBackTextureFile, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
817 darkBackTextureMode = appData.darkBackTextureMode;
\r
819 if (darkBackTexture == NULL && appData.debugMode) {
\r
820 fprintf( debugFP, "Unable to load dark texture bitmap '%s'\n", appData.darkBackTextureFile );
\r
824 mysrandom( (unsigned) time(NULL) );
\r
826 /* [AS] Restore layout */
\r
827 if( wpMoveHistory.visible ) {
\r
828 MoveHistoryPopUp();
\r
831 if( wpEvalGraph.visible ) {
\r
835 if( wpEngineOutput.visible ) {
\r
836 EngineOutputPopUp();
\r
841 /* Make the window visible; update its client area; and return "success" */
\r
842 EnsureOnScreen(&wpMain.x, &wpMain.y, minX, minY);
\r
843 wp.length = sizeof(WINDOWPLACEMENT);
\r
845 wp.showCmd = nCmdShow;
\r
846 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
847 wp.rcNormalPosition.left = wpMain.x;
\r
848 wp.rcNormalPosition.right = wpMain.x + wpMain.width;
\r
849 wp.rcNormalPosition.top = wpMain.y;
\r
850 wp.rcNormalPosition.bottom = wpMain.y + wpMain.height;
\r
851 SetWindowPlacement(hwndMain, &wp);
\r
853 if(!appData.noGUI) SetWindowPos(hwndMain, alwaysOnTop ? HWND_TOPMOST : HWND_NOTOPMOST,
\r
854 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE);
\r
858 SetWindowPos(hwndConsole, alwaysOnTop ? HWND_TOPMOST : HWND_NOTOPMOST,
\r
859 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE);
\r
861 ShowWindow(hwndConsole, nCmdShow);
\r
863 if(!appData.noGUI) UpdateWindow(hwnd); else ShowWindow(hwnd, SW_MINIMIZE);
\r
864 if(gameListDialog) SetFocus(gameListDialog); // [HGM] jaws: for if we clicked multi-game game file
\r
873 HMENU hmenu = GetMenu(hwndMain);
\r
875 (void) EnableMenuItem(hmenu, IDM_CommPort,
\r
876 MF_BYCOMMAND|((appData.icsActive &&
\r
877 *appData.icsCommPort != NULLCHAR) ?
\r
878 MF_ENABLED : MF_GRAYED));
\r
879 (void) CheckMenuItem(hmenu, IDM_SaveSettingsOnExit,
\r
880 MF_BYCOMMAND|(saveSettingsOnExit ?
\r
881 MF_CHECKED : MF_UNCHECKED));
\r
884 //---------------------------------------------------------------------------------------------------------
\r
886 #define ICS_TEXT_MENU_SIZE (IDM_CommandXLast - IDM_CommandX + 1)
\r
887 #define XBOARD FALSE
\r
889 #define OPTCHAR "/"
\r
890 #define SEPCHAR "="
\r
894 // front-end part of option handling
\r
897 LFfromMFP(LOGFONT* lf, MyFontParams *mfp)
\r
899 HDC hdc = CreateDC("DISPLAY", NULL, NULL, NULL);
\r
900 lf->lfHeight = -(int)(mfp->pointSize * GetDeviceCaps(hdc, LOGPIXELSY) / 72.0 + 0.5);
\r
903 lf->lfEscapement = 0;
\r
904 lf->lfOrientation = 0;
\r
905 lf->lfWeight = mfp->bold ? FW_BOLD : FW_NORMAL;
\r
906 lf->lfItalic = mfp->italic;
\r
907 lf->lfUnderline = mfp->underline;
\r
908 lf->lfStrikeOut = mfp->strikeout;
\r
909 lf->lfCharSet = mfp->charset;
\r
910 lf->lfOutPrecision = OUT_DEFAULT_PRECIS;
\r
911 lf->lfClipPrecision = CLIP_DEFAULT_PRECIS;
\r
912 lf->lfQuality = DEFAULT_QUALITY;
\r
913 lf->lfPitchAndFamily = DEFAULT_PITCH|FF_DONTCARE;
\r
914 strcpy(lf->lfFaceName, mfp->faceName);
\r
918 CreateFontInMF(MyFont *mf)
\r
920 LFfromMFP(&mf->lf, &mf->mfp);
\r
921 if (mf->hf) DeleteObject(mf->hf);
\r
922 mf->hf = CreateFontIndirect(&mf->lf);
\r
925 // [HGM] This platform-dependent table provides the location for storing the color info
\r
927 colorVariable[] = {
\r
932 &highlightSquareColor,
\r
933 &premoveHighlightColor,
\r
935 &consoleBackgroundColor,
\r
936 &appData.fontForeColorWhite,
\r
937 &appData.fontBackColorWhite,
\r
938 &appData.fontForeColorBlack,
\r
939 &appData.fontBackColorBlack,
\r
940 &appData.evalHistColorWhite,
\r
941 &appData.evalHistColorBlack,
\r
942 &appData.highlightArrowColor,
\r
945 /* Command line font name parser. NULL name means do nothing.
\r
946 Syntax like "Courier New:10.0 bi" or "Arial:10" or "Arial:10b"
\r
947 For backward compatibility, syntax without the colon is also
\r
948 accepted, but font names with digits in them won't work in that case.
\r
951 ParseFontName(char *name, MyFontParams *mfp)
\r
954 if (name == NULL) return;
\r
956 q = strchr(p, ':');
\r
958 if (q - p >= sizeof(mfp->faceName))
\r
959 ExitArgError("Font name too long:", name);
\r
960 memcpy(mfp->faceName, p, q - p);
\r
961 mfp->faceName[q - p] = NULLCHAR;
\r
965 while (*p && !isdigit(*p)) {
\r
967 if (q - mfp->faceName >= sizeof(mfp->faceName))
\r
968 ExitArgError("Font name too long:", name);
\r
970 while (q > mfp->faceName && q[-1] == ' ') q--;
\r
973 if (!*p) ExitArgError("Font point size missing:", name);
\r
974 mfp->pointSize = (float) atof(p);
\r
975 mfp->bold = (strchr(p, 'b') != NULL);
\r
976 mfp->italic = (strchr(p, 'i') != NULL);
\r
977 mfp->underline = (strchr(p, 'u') != NULL);
\r
978 mfp->strikeout = (strchr(p, 's') != NULL);
\r
979 mfp->charset = DEFAULT_CHARSET;
\r
980 q = strchr(p, 'c');
\r
982 mfp->charset = (BYTE) atoi(q+1);
\r
986 ParseFont(char *name, int number)
\r
987 { // wrapper to shield back-end from 'font'
\r
988 ParseFontName(name, &font[boardSize][number]->mfp);
\r
993 { // in WB we have a 2D array of fonts; this initializes their description
\r
995 /* Point font array elements to structures and
\r
996 parse default font names */
\r
997 for (i=0; i<NUM_FONTS; i++) {
\r
998 for (j=0; j<NUM_SIZES; j++) {
\r
999 font[j][i] = &fontRec[j][i];
\r
1000 ParseFontName(font[j][i]->def, &font[j][i]->mfp);
\r
1007 { // here we create the actual fonts from the selected descriptions
\r
1009 for (i=0; i<NUM_FONTS; i++) {
\r
1010 for (j=0; j<NUM_SIZES; j++) {
\r
1011 CreateFontInMF(font[j][i]);
\r
1015 /* Color name parser.
\r
1016 X version accepts X color names, but this one
\r
1017 handles only the #rrggbb form (hex) or rrr,ggg,bbb (decimal) */
\r
1019 ParseColorName(char *name)
\r
1021 int red, green, blue, count;
\r
1022 char buf[MSG_SIZ];
\r
1024 count = sscanf(name, "#%2x%2x%2x", &red, &green, &blue);
\r
1026 count = sscanf(name, "%3d%*[^0-9]%3d%*[^0-9]%3d",
\r
1027 &red, &green, &blue);
\r
1030 sprintf(buf, "Can't parse color name %s", name);
\r
1031 DisplayError(buf, 0);
\r
1032 return RGB(0, 0, 0);
\r
1034 return PALETTERGB(red, green, blue);
\r
1038 ParseColor(int n, char *name)
\r
1039 { // for WinBoard the color is an int, which needs to be derived from the string
\r
1040 if(colorVariable[n]) *(int*)colorVariable[n] = ParseColorName(name);
\r
1044 ParseAttribs(COLORREF *color, int *effects, char* argValue)
\r
1046 char *e = argValue;
\r
1050 if (*e == 'b') eff |= CFE_BOLD;
\r
1051 else if (*e == 'i') eff |= CFE_ITALIC;
\r
1052 else if (*e == 'u') eff |= CFE_UNDERLINE;
\r
1053 else if (*e == 's') eff |= CFE_STRIKEOUT;
\r
1054 else if (*e == '#' || isdigit(*e)) break;
\r
1058 *color = ParseColorName(e);
\r
1062 ParseTextAttribs(ColorClass cc, char *s)
\r
1063 { // [HGM] front-end wrapper that does the platform-dependent call
\r
1064 // for XBoard we would set (&appData.colorShout)[cc] = strdup(s);
\r
1065 ParseAttribs(&textAttribs[cc].color, &textAttribs[cc].effects, s);
\r
1069 ParseBoardSize(void *addr, char *name)
\r
1070 { // [HGM] rewritten with return-value ptr to shield back-end from BoardSize
\r
1071 BoardSize bs = SizeTiny;
\r
1072 while (sizeInfo[bs].name != NULL) {
\r
1073 if (StrCaseCmp(name, sizeInfo[bs].name) == 0) {
\r
1074 *(BoardSize *)addr = bs;
\r
1079 ExitArgError("Unrecognized board size value", name);
\r
1084 { // [HGM] import name from appData first
\r
1087 for (cc = (ColorClass)0; cc < ColorNormal; cc++) {
\r
1088 textAttribs[cc].sound.name = strdup((&appData.soundShout)[cc]);
\r
1089 textAttribs[cc].sound.data = NULL;
\r
1090 MyLoadSound(&textAttribs[cc].sound);
\r
1092 for (cc = ColorNormal; cc < NColorClasses; cc++) {
\r
1093 textAttribs[cc].sound.name = strdup("");
\r
1094 textAttribs[cc].sound.data = NULL;
\r
1096 for (sc = (SoundClass)0; sc < NSoundClasses; sc++) {
\r
1097 sounds[sc].name = strdup((&appData.soundMove)[sc]);
\r
1098 sounds[sc].data = NULL;
\r
1099 MyLoadSound(&sounds[sc]);
\r
1104 SetCommPortDefaults()
\r
1106 memset(&dcb, 0, sizeof(DCB)); // required by VS 2002 +
\r
1107 dcb.DCBlength = sizeof(DCB);
\r
1108 dcb.BaudRate = 9600;
\r
1109 dcb.fBinary = TRUE;
\r
1110 dcb.fParity = FALSE;
\r
1111 dcb.fOutxCtsFlow = FALSE;
\r
1112 dcb.fOutxDsrFlow = FALSE;
\r
1113 dcb.fDtrControl = DTR_CONTROL_ENABLE;
\r
1114 dcb.fDsrSensitivity = FALSE;
\r
1115 dcb.fTXContinueOnXoff = TRUE;
\r
1116 dcb.fOutX = FALSE;
\r
1118 dcb.fNull = FALSE;
\r
1119 dcb.fRtsControl = RTS_CONTROL_ENABLE;
\r
1120 dcb.fAbortOnError = FALSE;
\r
1122 dcb.Parity = SPACEPARITY;
\r
1123 dcb.StopBits = ONESTOPBIT;
\r
1126 // [HGM] args: these three cases taken out to stay in front-end
\r
1128 SaveFontArg(FILE *f, ArgDescriptor *ad)
\r
1129 { // in WinBoard every board size has its own font, and the "argLoc" identifies the table,
\r
1130 // while the curent board size determines the element. This system should be ported to XBoard.
\r
1131 // What the table contains pointers to, and how to print the font description, remains platform-dependent
\r
1133 for (bs=0; bs<NUM_SIZES; bs++) {
\r
1134 MyFontParams *mfp = &font[bs][(int) ad->argLoc]->mfp;
\r
1135 fprintf(f, "/size=%s ", sizeInfo[bs].name);
\r
1136 fprintf(f, "/%s=\"%s:%g%s%s%s%s%sc%d\"\n",
\r
1137 ad->argName, mfp->faceName, mfp->pointSize,
\r
1138 mfp->bold || mfp->italic || mfp->underline || mfp->strikeout ? " " : "",
\r
1139 mfp->bold ? "b" : "",
\r
1140 mfp->italic ? "i" : "",
\r
1141 mfp->underline ? "u" : "",
\r
1142 mfp->strikeout ? "s" : "",
\r
1143 (int)mfp->charset);
\r
1149 { // [HGM] copy the names from the internal WB variables to appData
\r
1152 for (cc = (ColorClass)0; cc < ColorNormal; cc++)
\r
1153 (&appData.soundShout)[cc] = textAttribs[cc].sound.name;
\r
1154 for (sc = (SoundClass)0; sc < NSoundClasses; sc++)
\r
1155 (&appData.soundMove)[sc] = sounds[sc].name;
\r
1159 SaveAttribsArg(FILE *f, ArgDescriptor *ad)
\r
1160 { // here the "argLoc" defines a table index. It could have contained the 'ta' pointer itself, though
\r
1161 MyTextAttribs* ta = &textAttribs[(ColorClass)ad->argLoc];
\r
1162 fprintf(f, "/%s=\"%s%s%s%s%s#%02lx%02lx%02lx\"\n", ad->argName,
\r
1163 (ta->effects & CFE_BOLD) ? "b" : "",
\r
1164 (ta->effects & CFE_ITALIC) ? "i" : "",
\r
1165 (ta->effects & CFE_UNDERLINE) ? "u" : "",
\r
1166 (ta->effects & CFE_STRIKEOUT) ? "s" : "",
\r
1167 (ta->effects) ? " " : "",
\r
1168 ta->color&0xff, (ta->color >> 8)&0xff, (ta->color >> 16)&0xff);
\r
1172 SaveColor(FILE *f, ArgDescriptor *ad)
\r
1173 { // in WinBoard the color is an int and has to be converted to text. In X it would be a string already?
\r
1174 COLORREF color = *(COLORREF *)colorVariable[(int)ad->argLoc];
\r
1175 fprintf(f, "/%s=#%02lx%02lx%02lx\n", ad->argName,
\r
1176 color&0xff, (color>>8)&0xff, (color>>16)&0xff);
\r
1180 SaveBoardSize(FILE *f, char *name, void *addr)
\r
1181 { // wrapper to shield back-end from BoardSize & sizeInfo
\r
1182 fprintf(f, "/%s=%s\n", name, sizeInfo[*(BoardSize *)addr].name);
\r
1186 ParseCommPortSettings(char *s)
\r
1187 { // wrapper to keep dcb from back-end
\r
1188 ParseCommSettings(s, &dcb);
\r
1193 { // wrapper to shield use of window handles from back-end (make addressible by number?)
\r
1194 GetActualPlacement(hwndMain, &wpMain);
\r
1195 GetActualPlacement(hwndConsole, &wpConsole);
\r
1196 GetActualPlacement(commentDialog, &wpComment);
\r
1197 GetActualPlacement(editTagsDialog, &wpTags);
\r
1198 GetActualPlacement(gameListDialog, &wpGameList);
\r
1199 GetActualPlacement(moveHistoryDialog, &wpMoveHistory);
\r
1200 GetActualPlacement(evalGraphDialog, &wpEvalGraph);
\r
1201 GetActualPlacement(engineOutputDialog, &wpEngineOutput);
\r
1205 PrintCommPortSettings(FILE *f, char *name)
\r
1206 { // wrapper to shield back-end from DCB
\r
1207 PrintCommSettings(f, name, &dcb);
\r
1211 MySearchPath(char *installDir, char *name, char *fullname)
\r
1214 return (int) SearchPath(installDir, name, NULL, MSG_SIZ, fullname, &dummy);
\r
1218 MyGetFullPathName(char *name, char *fullname)
\r
1221 return (int) GetFullPathName(name, MSG_SIZ, fullname, &dummy);
\r
1226 { // [HGM] args: allows testing if main window is realized from back-end
\r
1227 return hwndMain != NULL;
\r
1231 PopUpStartupDialog()
\r
1235 lpProc = MakeProcInstance((FARPROC)StartupDialog, hInst);
\r
1236 DialogBox(hInst, MAKEINTRESOURCE(DLG_Startup), NULL, (DLGPROC)lpProc);
\r
1237 FreeProcInstance(lpProc);
\r
1240 /*---------------------------------------------------------------------------*\
\r
1242 * GDI board drawing routines
\r
1244 \*---------------------------------------------------------------------------*/
\r
1246 /* [AS] Draw square using background texture */
\r
1247 static void DrawTile( int dx, int dy, int dw, int dh, HDC dst, HDC src, int mode, int sx, int sy )
\r
1252 return; /* Should never happen! */
\r
1255 SetGraphicsMode( dst, GM_ADVANCED );
\r
1262 /* X reflection */
\r
1267 x.eDx = (FLOAT) dw + dx - 1;
\r
1270 SetWorldTransform( dst, &x );
\r
1273 /* Y reflection */
\r
1279 x.eDy = (FLOAT) dh + dy - 1;
\r
1281 SetWorldTransform( dst, &x );
\r
1289 x.eDx = (FLOAT) dx;
\r
1290 x.eDy = (FLOAT) dy;
\r
1293 SetWorldTransform( dst, &x );
\r
1297 BitBlt( dst, dx, dy, dw, dh, src, sx, sy, SRCCOPY );
\r
1305 SetWorldTransform( dst, &x );
\r
1307 ModifyWorldTransform( dst, 0, MWT_IDENTITY );
\r
1310 /* [AS] [HGM] Make room for more piece types, so all pieces can be different */
\r
1312 PM_WP = (int) WhitePawn,
\r
1313 PM_WN = (int) WhiteKnight,
\r
1314 PM_WB = (int) WhiteBishop,
\r
1315 PM_WR = (int) WhiteRook,
\r
1316 PM_WQ = (int) WhiteQueen,
\r
1317 PM_WF = (int) WhiteFerz,
\r
1318 PM_WW = (int) WhiteWazir,
\r
1319 PM_WE = (int) WhiteAlfil,
\r
1320 PM_WM = (int) WhiteMan,
\r
1321 PM_WO = (int) WhiteCannon,
\r
1322 PM_WU = (int) WhiteUnicorn,
\r
1323 PM_WH = (int) WhiteNightrider,
\r
1324 PM_WA = (int) WhiteAngel,
\r
1325 PM_WC = (int) WhiteMarshall,
\r
1326 PM_WAB = (int) WhiteCardinal,
\r
1327 PM_WD = (int) WhiteDragon,
\r
1328 PM_WL = (int) WhiteLance,
\r
1329 PM_WS = (int) WhiteCobra,
\r
1330 PM_WV = (int) WhiteFalcon,
\r
1331 PM_WSG = (int) WhiteSilver,
\r
1332 PM_WG = (int) WhiteGrasshopper,
\r
1333 PM_WK = (int) WhiteKing,
\r
1334 PM_BP = (int) BlackPawn,
\r
1335 PM_BN = (int) BlackKnight,
\r
1336 PM_BB = (int) BlackBishop,
\r
1337 PM_BR = (int) BlackRook,
\r
1338 PM_BQ = (int) BlackQueen,
\r
1339 PM_BF = (int) BlackFerz,
\r
1340 PM_BW = (int) BlackWazir,
\r
1341 PM_BE = (int) BlackAlfil,
\r
1342 PM_BM = (int) BlackMan,
\r
1343 PM_BO = (int) BlackCannon,
\r
1344 PM_BU = (int) BlackUnicorn,
\r
1345 PM_BH = (int) BlackNightrider,
\r
1346 PM_BA = (int) BlackAngel,
\r
1347 PM_BC = (int) BlackMarshall,
\r
1348 PM_BG = (int) BlackGrasshopper,
\r
1349 PM_BAB = (int) BlackCardinal,
\r
1350 PM_BD = (int) BlackDragon,
\r
1351 PM_BL = (int) BlackLance,
\r
1352 PM_BS = (int) BlackCobra,
\r
1353 PM_BV = (int) BlackFalcon,
\r
1354 PM_BSG = (int) BlackSilver,
\r
1355 PM_BK = (int) BlackKing
\r
1358 static HFONT hPieceFont = NULL;
\r
1359 static HBITMAP hPieceMask[(int) EmptySquare];
\r
1360 static HBITMAP hPieceFace[(int) EmptySquare];
\r
1361 static int fontBitmapSquareSize = 0;
\r
1362 static char pieceToFontChar[(int) EmptySquare] =
\r
1363 { 'p', 'n', 'b', 'r', 'q',
\r
1364 'n', 'b', 'p', 'n', 'b', 'r', 'b', 'r', 'q', 'k',
\r
1365 'k', 'o', 'm', 'v', 't', 'w',
\r
1366 'v', 't', 'o', 'm', 'v', 't', 'v', 't', 'w', 'l',
\r
1369 extern BOOL SetCharTable( char *table, const char * map );
\r
1370 /* [HGM] moved to backend.c */
\r
1372 static void SetPieceBackground( HDC hdc, COLORREF color, int mode )
\r
1375 BYTE r1 = GetRValue( color );
\r
1376 BYTE g1 = GetGValue( color );
\r
1377 BYTE b1 = GetBValue( color );
\r
1383 /* Create a uniform background first */
\r
1384 hbrush = CreateSolidBrush( color );
\r
1385 SetRect( &rc, 0, 0, squareSize, squareSize );
\r
1386 FillRect( hdc, &rc, hbrush );
\r
1387 DeleteObject( hbrush );
\r
1390 /* Vertical gradient, good for pawn, knight and rook, less for queen and king */
\r
1391 int steps = squareSize / 2;
\r
1394 for( i=0; i<steps; i++ ) {
\r
1395 BYTE r = r1 - (r1-r2) * i / steps;
\r
1396 BYTE g = g1 - (g1-g2) * i / steps;
\r
1397 BYTE b = b1 - (b1-b2) * i / steps;
\r
1399 hbrush = CreateSolidBrush( RGB(r,g,b) );
\r
1400 SetRect( &rc, i + squareSize - steps, 0, i + squareSize - steps + 1, squareSize );
\r
1401 FillRect( hdc, &rc, hbrush );
\r
1402 DeleteObject(hbrush);
\r
1405 else if( mode == 2 ) {
\r
1406 /* Diagonal gradient, good more or less for every piece */
\r
1407 POINT triangle[3];
\r
1408 HPEN hpen = SelectObject( hdc, GetStockObject(NULL_PEN) );
\r
1409 HBRUSH hbrush_old;
\r
1410 int steps = squareSize;
\r
1413 triangle[0].x = squareSize - steps;
\r
1414 triangle[0].y = squareSize;
\r
1415 triangle[1].x = squareSize;
\r
1416 triangle[1].y = squareSize;
\r
1417 triangle[2].x = squareSize;
\r
1418 triangle[2].y = squareSize - steps;
\r
1420 for( i=0; i<steps; i++ ) {
\r
1421 BYTE r = r1 - (r1-r2) * i / steps;
\r
1422 BYTE g = g1 - (g1-g2) * i / steps;
\r
1423 BYTE b = b1 - (b1-b2) * i / steps;
\r
1425 hbrush = CreateSolidBrush( RGB(r,g,b) );
\r
1426 hbrush_old = SelectObject( hdc, hbrush );
\r
1427 Polygon( hdc, triangle, 3 );
\r
1428 SelectObject( hdc, hbrush_old );
\r
1429 DeleteObject(hbrush);
\r
1434 SelectObject( hdc, hpen );
\r
1439 [AS] The method I use to create the bitmaps it a bit tricky, but it
\r
1440 seems to work ok. The main problem here is to find the "inside" of a chess
\r
1441 piece: follow the steps as explained below.
\r
1443 static void CreatePieceMaskFromFont( HDC hdc_window, HDC hdc, int index )
\r
1447 COLORREF chroma = RGB(0xFF,0x00,0xFF);
\r
1451 int backColor = whitePieceColor;
\r
1452 int foreColor = blackPieceColor;
\r
1454 if( index < (int)BlackPawn && appData.fontBackColorWhite != appData.fontForeColorWhite ) {
\r
1455 backColor = appData.fontBackColorWhite;
\r
1456 foreColor = appData.fontForeColorWhite;
\r
1458 else if( index >= (int)BlackPawn && appData.fontBackColorBlack != appData.fontForeColorBlack ) {
\r
1459 backColor = appData.fontBackColorBlack;
\r
1460 foreColor = appData.fontForeColorBlack;
\r
1464 hbm = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
\r
1466 hbm_old = SelectObject( hdc, hbm );
\r
1470 rc.right = squareSize;
\r
1471 rc.bottom = squareSize;
\r
1473 /* Step 1: background is now black */
\r
1474 FillRect( hdc, &rc, GetStockObject(BLACK_BRUSH) );
\r
1476 GetTextExtentPoint32( hdc, &pieceToFontChar[index], 1, &sz );
\r
1478 pt.x = (squareSize - sz.cx) / 2;
\r
1479 pt.y = (squareSize - sz.cy) / 2;
\r
1481 SetBkMode( hdc, TRANSPARENT );
\r
1482 SetTextColor( hdc, chroma );
\r
1483 /* Step 2: the piece has been drawn in purple, there are now black and purple in this bitmap */
\r
1484 TextOut( hdc, pt.x, pt.y, &pieceToFontChar[appData.allWhite && index >= (int)BlackPawn ? index - (int)BlackPawn : index], 1 );
\r
1486 SelectObject( hdc, GetStockObject(WHITE_BRUSH) );
\r
1487 /* Step 3: the area outside the piece is filled with white */
\r
1488 // FloodFill( hdc, 0, 0, chroma );
\r
1489 ExtFloodFill( hdc, 0, 0, 0, FLOODFILLSURFACE );
\r
1490 ExtFloodFill( hdc, 0, squareSize-1, 0, FLOODFILLSURFACE ); // [HGM] fill from all 4 corners, for if piece too big
\r
1491 ExtFloodFill( hdc, squareSize-1, 0, 0, FLOODFILLSURFACE );
\r
1492 ExtFloodFill( hdc, squareSize-1, squareSize-1, 0, FLOODFILLSURFACE );
\r
1493 SelectObject( hdc, GetStockObject(BLACK_BRUSH) );
\r
1495 Step 4: this is the tricky part, the area inside the piece is filled with black,
\r
1496 but if the start point is not inside the piece we're lost!
\r
1497 There should be a better way to do this... if we could create a region or path
\r
1498 from the fill operation we would be fine for example.
\r
1500 // FloodFill( hdc, squareSize / 2, squareSize / 2, RGB(0xFF,0xFF,0xFF) );
\r
1501 ExtFloodFill( hdc, squareSize / 2, squareSize / 2, RGB(0xFF,0xFF,0xFF), FLOODFILLBORDER );
\r
1503 { /* [HGM] shave off edges of mask, in an attempt to correct for the fact that FloodFill does not work correctly under Win XP */
\r
1504 HDC dc2 = CreateCompatibleDC( hdc_window );
\r
1505 HBITMAP bm2 = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
\r
1507 SelectObject( dc2, bm2 );
\r
1508 BitBlt( dc2, 0, 0, squareSize, squareSize, hdc, 0, 0, SRCCOPY ); // make copy
\r
1509 BitBlt( hdc, 0, 1, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );
\r
1510 BitBlt( hdc, 2, 1, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );
\r
1511 BitBlt( hdc, 1, 0, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );
\r
1512 BitBlt( hdc, 1, 2, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );
\r
1515 DeleteObject( bm2 );
\r
1518 SetTextColor( hdc, 0 );
\r
1520 Step 5: some fonts have "disconnected" areas that are skipped by the fill:
\r
1521 draw the piece again in black for safety.
\r
1523 TextOut( hdc, pt.x, pt.y, &pieceToFontChar[appData.allWhite && index >= (int)BlackPawn ? index - (int)BlackPawn : index], 1 );
\r
1525 SelectObject( hdc, hbm_old );
\r
1527 if( hPieceMask[index] != NULL ) {
\r
1528 DeleteObject( hPieceMask[index] );
\r
1531 hPieceMask[index] = hbm;
\r
1534 hbm = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
\r
1536 SelectObject( hdc, hbm );
\r
1539 HDC dc1 = CreateCompatibleDC( hdc_window );
\r
1540 HDC dc2 = CreateCompatibleDC( hdc_window );
\r
1541 HBITMAP bm2 = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
\r
1543 SelectObject( dc1, hPieceMask[index] );
\r
1544 SelectObject( dc2, bm2 );
\r
1545 FillRect( dc2, &rc, GetStockObject(WHITE_BRUSH) );
\r
1546 BitBlt( dc2, 0, 0, squareSize, squareSize, dc1, 0, 0, SRCINVERT );
\r
1549 Now dc2 contains the inverse of the piece mask, i.e. a mask that preserves
\r
1550 the piece background and deletes (makes transparent) the rest.
\r
1551 Thanks to that mask, we are free to paint the background with the greates
\r
1552 freedom, as we'll be able to mask off the unwanted parts when finished.
\r
1553 We use this, to make gradients and give the pieces a "roundish" look.
\r
1555 SetPieceBackground( hdc, backColor, 2 );
\r
1556 BitBlt( hdc, 0, 0, squareSize, squareSize, dc2, 0, 0, SRCAND );
\r
1560 DeleteObject( bm2 );
\r
1563 SetTextColor( hdc, foreColor );
\r
1564 TextOut( hdc, pt.x, pt.y, &pieceToFontChar[appData.allWhite && index >= (int)BlackPawn ? index - (int)BlackPawn : index], 1 );
\r
1566 SelectObject( hdc, hbm_old );
\r
1568 if( hPieceFace[index] != NULL ) {
\r
1569 DeleteObject( hPieceFace[index] );
\r
1572 hPieceFace[index] = hbm;
\r
1575 static int TranslatePieceToFontPiece( int piece )
\r
1605 case BlackMarshall:
\r
1609 case BlackNightrider:
\r
1615 case BlackUnicorn:
\r
1619 case BlackGrasshopper:
\r
1631 case BlackCardinal:
\r
1638 case WhiteMarshall:
\r
1642 case WhiteNightrider:
\r
1648 case WhiteUnicorn:
\r
1652 case WhiteGrasshopper:
\r
1664 case WhiteCardinal:
\r
1673 void CreatePiecesFromFont()
\r
1676 HDC hdc_window = NULL;
\r
1682 if( fontBitmapSquareSize < 0 ) {
\r
1683 /* Something went seriously wrong in the past: do not try to recreate fonts! */
\r
1687 if( appData.renderPiecesWithFont == NULL || appData.renderPiecesWithFont[0] == NULLCHAR || appData.renderPiecesWithFont[0] == '*' ) {
\r
1688 fontBitmapSquareSize = -1;
\r
1692 if( fontBitmapSquareSize != squareSize ) {
\r
1693 hdc_window = GetDC( hwndMain );
\r
1694 hdc = CreateCompatibleDC( hdc_window );
\r
1696 if( hPieceFont != NULL ) {
\r
1697 DeleteObject( hPieceFont );
\r
1700 for( i=0; i<=(int)BlackKing; i++ ) {
\r
1701 hPieceMask[i] = NULL;
\r
1702 hPieceFace[i] = NULL;
\r
1708 if( appData.fontPieceSize >= 50 && appData.fontPieceSize <= 150 ) {
\r
1709 fontHeight = appData.fontPieceSize;
\r
1712 fontHeight = (fontHeight * squareSize) / 100;
\r
1714 lf.lfHeight = -MulDiv( fontHeight, GetDeviceCaps(hdc, LOGPIXELSY), 72 );
\r
1716 lf.lfEscapement = 0;
\r
1717 lf.lfOrientation = 0;
\r
1718 lf.lfWeight = FW_NORMAL;
\r
1720 lf.lfUnderline = 0;
\r
1721 lf.lfStrikeOut = 0;
\r
1722 lf.lfCharSet = DEFAULT_CHARSET;
\r
1723 lf.lfOutPrecision = OUT_DEFAULT_PRECIS;
\r
1724 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
\r
1725 lf.lfQuality = PROOF_QUALITY;
\r
1726 lf.lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;
\r
1727 strncpy( lf.lfFaceName, appData.renderPiecesWithFont, sizeof(lf.lfFaceName) );
\r
1728 lf.lfFaceName[ sizeof(lf.lfFaceName) - 1 ] = '\0';
\r
1730 hPieceFont = CreateFontIndirect( &lf );
\r
1732 if( hPieceFont == NULL ) {
\r
1733 fontBitmapSquareSize = -2;
\r
1736 /* Setup font-to-piece character table */
\r
1737 if( ! SetCharTable(pieceToFontChar, appData.fontToPieceTable) ) {
\r
1738 /* No (or wrong) global settings, try to detect the font */
\r
1739 if( strstr(lf.lfFaceName,"Alpha") != NULL ) {
\r
1741 SetCharTable(pieceToFontChar, "phbrqkojntwl");
\r
1743 else if( strstr(lf.lfFaceName,"DiagramTT") != NULL ) {
\r
1744 /* DiagramTT* family */
\r
1745 SetCharTable(pieceToFontChar, "PNLRQKpnlrqk");
\r
1747 else if( strstr(lf.lfFaceName,"WinboardF") != NULL ) {
\r
1748 /* Fairy symbols */
\r
1749 SetCharTable(pieceToFontChar, "PNBRQFEACWMOHIJGDVSLUKpnbrqfeacwmohijgdvsluk");
\r
1751 else if( strstr(lf.lfFaceName,"GC2004D") != NULL ) {
\r
1752 /* Good Companion (Some characters get warped as literal :-( */
\r
1753 char s[] = "1cmWG0??S??oYI23wgQU";
\r
1754 s[0]=0xB9; s[1]=0xA9; s[6]=0xB1; s[11]=0xBB; s[12]=0xAB; s[17]=0xB3;
\r
1755 SetCharTable(pieceToFontChar, s);
\r
1758 /* Cases, Condal, Leipzig, Lucena, Marroquin, Merida, Usual */
\r
1759 SetCharTable(pieceToFontChar, "pnbrqkomvtwl");
\r
1763 /* Create bitmaps */
\r
1764 hfont_old = SelectObject( hdc, hPieceFont );
\r
1765 for(i=(int)WhitePawn; i<(int)EmptySquare; i++) /* [HGM] made a loop for this */
\r
1766 if(PieceToChar((ChessSquare)i) != '.') /* skip unused pieces */
\r
1767 CreatePieceMaskFromFont( hdc_window, hdc, i );
\r
1769 SelectObject( hdc, hfont_old );
\r
1771 fontBitmapSquareSize = squareSize;
\r
1775 if( hdc != NULL ) {
\r
1779 if( hdc_window != NULL ) {
\r
1780 ReleaseDC( hwndMain, hdc_window );
\r
1785 DoLoadBitmap(HINSTANCE hinst, char *piece, int squareSize, char *suffix)
\r
1789 sprintf(name, "%s%d%s", piece, squareSize, suffix);
\r
1790 if (gameInfo.event &&
\r
1791 strcmp(gameInfo.event, "Easter Egg Hunt") == 0 &&
\r
1792 strcmp(name, "k80s") == 0) {
\r
1793 strcpy(name, "tim");
\r
1795 return LoadBitmap(hinst, name);
\r
1799 /* Insert a color into the program's logical palette
\r
1800 structure. This code assumes the given color is
\r
1801 the result of the RGB or PALETTERGB macro, and it
\r
1802 knows how those macros work (which is documented).
\r
1805 InsertInPalette(COLORREF color)
\r
1807 LPPALETTEENTRY pe = &(pLogPal->palPalEntry[pLogPal->palNumEntries]);
\r
1809 if (pLogPal->palNumEntries++ >= PALETTESIZE) {
\r
1810 DisplayFatalError("Too many colors", 0, 1);
\r
1811 pLogPal->palNumEntries--;
\r
1815 pe->peFlags = (char) 0;
\r
1816 pe->peRed = (char) (0xFF & color);
\r
1817 pe->peGreen = (char) (0xFF & (color >> 8));
\r
1818 pe->peBlue = (char) (0xFF & (color >> 16));
\r
1824 InitDrawingColors()
\r
1826 if (pLogPal == NULL) {
\r
1827 /* Allocate enough memory for a logical palette with
\r
1828 * PALETTESIZE entries and set the size and version fields
\r
1829 * of the logical palette structure.
\r
1831 pLogPal = (NPLOGPALETTE)
\r
1832 LocalAlloc(LMEM_FIXED, (sizeof(LOGPALETTE) +
\r
1833 (sizeof(PALETTEENTRY) * (PALETTESIZE))));
\r
1834 pLogPal->palVersion = 0x300;
\r
1836 pLogPal->palNumEntries = 0;
\r
1838 InsertInPalette(lightSquareColor);
\r
1839 InsertInPalette(darkSquareColor);
\r
1840 InsertInPalette(whitePieceColor);
\r
1841 InsertInPalette(blackPieceColor);
\r
1842 InsertInPalette(highlightSquareColor);
\r
1843 InsertInPalette(premoveHighlightColor);
\r
1845 /* create a logical color palette according the information
\r
1846 * in the LOGPALETTE structure.
\r
1848 hPal = CreatePalette((LPLOGPALETTE) pLogPal);
\r
1850 lightSquareBrush = CreateSolidBrush(lightSquareColor);
\r
1851 blackSquareBrush = CreateSolidBrush(blackPieceColor);
\r
1852 darkSquareBrush = CreateSolidBrush(darkSquareColor);
\r
1853 whitePieceBrush = CreateSolidBrush(whitePieceColor);
\r
1854 blackPieceBrush = CreateSolidBrush(blackPieceColor);
\r
1855 iconBkgndBrush = CreateSolidBrush(GetSysColor(COLOR_BACKGROUND));
\r
1856 explodeBrush = CreateSolidBrush(highlightSquareColor); // [HGM] atomic
\r
1857 markerBrush = CreateSolidBrush(premoveHighlightColor); // [HGM] markers
\r
1858 /* [AS] Force rendering of the font-based pieces */
\r
1859 if( fontBitmapSquareSize > 0 ) {
\r
1860 fontBitmapSquareSize = 0;
\r
1866 BoardWidth(int boardSize, int n)
\r
1867 { /* [HGM] argument n added to allow different width and height */
\r
1868 int lineGap = sizeInfo[boardSize].lineGap;
\r
1870 if( appData.overrideLineGap >= 0 && appData.overrideLineGap <= 5 ) {
\r
1871 lineGap = appData.overrideLineGap;
\r
1874 return (n + 1) * lineGap +
\r
1875 n * sizeInfo[boardSize].squareSize;
\r
1878 /* Respond to board resize by dragging edge */
\r
1880 ResizeBoard(int newSizeX, int newSizeY, int flags)
\r
1882 BoardSize newSize = NUM_SIZES - 1;
\r
1883 static int recurse = 0;
\r
1884 if (IsIconic(hwndMain)) return;
\r
1885 if (recurse > 0) return;
\r
1887 while (newSize > 0) {
\r
1888 InitDrawingSizes(newSize+1000, 0); // [HGM] kludge to update sizeInfo without visible effects
\r
1889 if(newSizeX >= sizeInfo[newSize].cliWidth &&
\r
1890 newSizeY >= sizeInfo[newSize].cliHeight) break;
\r
1893 boardSize = newSize;
\r
1894 InitDrawingSizes(boardSize, flags);
\r
1901 InitDrawingSizes(BoardSize boardSize, int flags)
\r
1903 int i, boardWidth, boardHeight; /* [HGM] height treated separately */
\r
1904 ChessSquare piece;
\r
1905 static int oldBoardSize = -1, oldTinyLayout = 0;
\r
1907 SIZE clockSize, messageSize;
\r
1909 char buf[MSG_SIZ];
\r
1911 HMENU hmenu = GetMenu(hwndMain);
\r
1912 RECT crect, wrect, oldRect;
\r
1914 LOGBRUSH logbrush;
\r
1916 int suppressVisibleEffects = 0; // [HGM] kludge to request updating sizeInfo only
\r
1917 if((int)boardSize >= 1000 ) { boardSize -= 1000; suppressVisibleEffects = 1; }
\r
1919 /* [HGM] call with -2 uses old size (for if nr of files, ranks changes) */
\r
1920 if(boardSize == (BoardSize)(-2) ) boardSize = oldBoardSize;
\r
1922 oldRect.left = wpMain.x; //[HGM] placement: remember previous window params
\r
1923 oldRect.top = wpMain.y;
\r
1924 oldRect.right = wpMain.x + wpMain.width;
\r
1925 oldRect.bottom = wpMain.y + wpMain.height;
\r
1927 tinyLayout = sizeInfo[boardSize].tinyLayout;
\r
1928 smallLayout = sizeInfo[boardSize].smallLayout;
\r
1929 squareSize = sizeInfo[boardSize].squareSize;
\r
1930 lineGap = sizeInfo[boardSize].lineGap;
\r
1931 minorSize = 0; /* [HGM] Kludge to see if demagnified pieces need to be shifted */
\r
1933 if( appData.overrideLineGap >= 0 && appData.overrideLineGap <= 5 ) {
\r
1934 lineGap = appData.overrideLineGap;
\r
1937 if (tinyLayout != oldTinyLayout) {
\r
1938 long style = GetWindowLong(hwndMain, GWL_STYLE);
\r
1940 style &= ~WS_SYSMENU;
\r
1941 InsertMenu(hmenu, IDM_Exit, MF_BYCOMMAND, IDM_Minimize,
\r
1942 "&Minimize\tCtrl+F4");
\r
1944 style |= WS_SYSMENU;
\r
1945 RemoveMenu(hmenu, IDM_Minimize, MF_BYCOMMAND);
\r
1947 SetWindowLong(hwndMain, GWL_STYLE, style);
\r
1949 for (i=0; menuBarText[tinyLayout][i]; i++) {
\r
1950 ModifyMenu(hmenu, i, MF_STRING|MF_BYPOSITION|MF_POPUP,
\r
1951 (UINT)GetSubMenu(hmenu, i), menuBarText[tinyLayout][i]);
\r
1953 DrawMenuBar(hwndMain);
\r
1956 boardWidth = BoardWidth(boardSize, BOARD_WIDTH);
\r
1957 boardHeight = BoardWidth(boardSize, BOARD_HEIGHT);
\r
1959 /* Get text area sizes */
\r
1960 hdc = GetDC(hwndMain);
\r
1961 if (appData.clockMode) {
\r
1962 sprintf(buf, "White: %s", TimeString(23*60*60*1000L));
\r
1964 sprintf(buf, "White");
\r
1966 oldFont = SelectObject(hdc, font[boardSize][CLOCK_FONT]->hf);
\r
1967 GetTextExtentPoint(hdc, buf, strlen(buf), &clockSize);
\r
1968 SelectObject(hdc, font[boardSize][MESSAGE_FONT]->hf);
\r
1969 str = "We only care about the height here";
\r
1970 GetTextExtentPoint(hdc, str, strlen(str), &messageSize);
\r
1971 SelectObject(hdc, oldFont);
\r
1972 ReleaseDC(hwndMain, hdc);
\r
1974 /* Compute where everything goes */
\r
1975 if((first.programLogo || second.programLogo) && !tinyLayout) {
\r
1976 /* [HGM] logo: if either logo is on, reserve space for it */
\r
1977 logoHeight = 2*clockSize.cy;
\r
1978 leftLogoRect.left = OUTER_MARGIN;
\r
1979 leftLogoRect.right = leftLogoRect.left + 4*clockSize.cy;
\r
1980 leftLogoRect.top = OUTER_MARGIN;
\r
1981 leftLogoRect.bottom = OUTER_MARGIN + logoHeight;
\r
1983 rightLogoRect.right = OUTER_MARGIN + boardWidth;
\r
1984 rightLogoRect.left = rightLogoRect.right - 4*clockSize.cy;
\r
1985 rightLogoRect.top = OUTER_MARGIN;
\r
1986 rightLogoRect.bottom = OUTER_MARGIN + logoHeight;
\r
1989 whiteRect.left = leftLogoRect.right;
\r
1990 whiteRect.right = OUTER_MARGIN + boardWidth/2 - INNER_MARGIN/2;
\r
1991 whiteRect.top = OUTER_MARGIN;
\r
1992 whiteRect.bottom = whiteRect.top + logoHeight;
\r
1994 blackRect.right = rightLogoRect.left;
\r
1995 blackRect.left = whiteRect.right + INNER_MARGIN;
\r
1996 blackRect.top = whiteRect.top;
\r
1997 blackRect.bottom = whiteRect.bottom;
\r
1999 whiteRect.left = OUTER_MARGIN;
\r
2000 whiteRect.right = whiteRect.left + boardWidth/2 - INNER_MARGIN/2;
\r
2001 whiteRect.top = OUTER_MARGIN;
\r
2002 whiteRect.bottom = whiteRect.top + clockSize.cy;
\r
2004 blackRect.left = whiteRect.right + INNER_MARGIN;
\r
2005 blackRect.right = blackRect.left + boardWidth/2 - 1;
\r
2006 blackRect.top = whiteRect.top;
\r
2007 blackRect.bottom = whiteRect.bottom;
\r
2010 messageRect.left = OUTER_MARGIN + MESSAGE_LINE_LEFTMARGIN;
\r
2011 if (appData.showButtonBar) {
\r
2012 messageRect.right = OUTER_MARGIN + boardWidth // [HGM] logo: expressed independent of clock placement
\r
2013 - N_BUTTONS*BUTTON_WIDTH - MESSAGE_LINE_LEFTMARGIN;
\r
2015 messageRect.right = OUTER_MARGIN + boardWidth;
\r
2017 messageRect.top = whiteRect.bottom + INNER_MARGIN;
\r
2018 messageRect.bottom = messageRect.top + messageSize.cy;
\r
2020 boardRect.left = OUTER_MARGIN;
\r
2021 boardRect.right = boardRect.left + boardWidth;
\r
2022 boardRect.top = messageRect.bottom + INNER_MARGIN;
\r
2023 boardRect.bottom = boardRect.top + boardHeight;
\r
2025 sizeInfo[boardSize].cliWidth = boardRect.right + OUTER_MARGIN;
\r
2026 sizeInfo[boardSize].cliHeight = boardRect.bottom + OUTER_MARGIN;
\r
2027 oldBoardSize = boardSize;
\r
2028 oldTinyLayout = tinyLayout;
\r
2029 winW = 2 * GetSystemMetrics(SM_CXFRAME) + boardRect.right + OUTER_MARGIN;
\r
2030 winH = 2 * GetSystemMetrics(SM_CYFRAME) + GetSystemMetrics(SM_CYMENU) +
\r
2031 GetSystemMetrics(SM_CYCAPTION) + boardRect.bottom + OUTER_MARGIN;
\r
2032 if(suppressVisibleEffects) return; // [HGM] when called for filling sizeInfo only
\r
2033 wpMain.width = winW; // [HGM] placement: set through temporary which can used by initial sizing choice
\r
2034 wpMain.height = winH; // without disturbing window attachments
\r
2035 GetWindowRect(hwndMain, &wrect);
\r
2036 SetWindowPos(hwndMain, NULL, 0, 0, wpMain.width, wpMain.height,
\r
2037 SWP_NOCOPYBITS|SWP_NOZORDER|SWP_NOMOVE);
\r
2039 // [HGM] placement: let attached windows follow size change.
\r
2040 ReattachAfterSize( &oldRect, wpMain.width, wpMain.height, moveHistoryDialog, &wpMoveHistory );
\r
2041 ReattachAfterSize( &oldRect, wpMain.width, wpMain.height, evalGraphDialog, &wpEvalGraph );
\r
2042 ReattachAfterSize( &oldRect, wpMain.width, wpMain.height, engineOutputDialog, &wpEngineOutput );
\r
2043 ReattachAfterSize( &oldRect, wpMain.width, wpMain.height, gameListDialog, &wpGameList );
\r
2044 ReattachAfterSize( &oldRect, wpMain.width, wpMain.height, hwndConsole, &wpConsole );
\r
2046 /* compensate if menu bar wrapped */
\r
2047 GetClientRect(hwndMain, &crect);
\r
2048 offby = boardRect.bottom + OUTER_MARGIN - crect.bottom;
\r
2049 wpMain.height += offby;
\r
2051 case WMSZ_TOPLEFT:
\r
2052 SetWindowPos(hwndMain, NULL,
\r
2053 wrect.right - wpMain.width, wrect.bottom - wpMain.height,
\r
2054 wpMain.width, wpMain.height, SWP_NOCOPYBITS|SWP_NOZORDER);
\r
2057 case WMSZ_TOPRIGHT:
\r
2059 SetWindowPos(hwndMain, NULL,
\r
2060 wrect.left, wrect.bottom - wpMain.height,
\r
2061 wpMain.width, wpMain.height, SWP_NOCOPYBITS|SWP_NOZORDER);
\r
2064 case WMSZ_BOTTOMLEFT:
\r
2066 SetWindowPos(hwndMain, NULL,
\r
2067 wrect.right - wpMain.width, wrect.top,
\r
2068 wpMain.width, wpMain.height, SWP_NOCOPYBITS|SWP_NOZORDER);
\r
2071 case WMSZ_BOTTOMRIGHT:
\r
2075 SetWindowPos(hwndMain, NULL, 0, 0, wpMain.width, wpMain.height,
\r
2076 SWP_NOCOPYBITS|SWP_NOZORDER|SWP_NOMOVE);
\r
2081 for (i = 0; i < N_BUTTONS; i++) {
\r
2082 if (buttonDesc[i].hwnd != NULL) {
\r
2083 DestroyWindow(buttonDesc[i].hwnd);
\r
2084 buttonDesc[i].hwnd = NULL;
\r
2086 if (appData.showButtonBar) {
\r
2087 buttonDesc[i].hwnd =
\r
2088 CreateWindow("BUTTON", buttonDesc[i].label,
\r
2089 WS_VISIBLE | WS_CHILD | BS_PUSHBUTTON,
\r
2090 boardRect.right - BUTTON_WIDTH*(N_BUTTONS-i),
\r
2091 messageRect.top, BUTTON_WIDTH, messageSize.cy, hwndMain,
\r
2092 (HMENU) buttonDesc[i].id,
\r
2093 (HINSTANCE) GetWindowLong(hwndMain, GWL_HINSTANCE), NULL);
\r
2095 SendMessage(buttonDesc[i].hwnd, WM_SETFONT,
\r
2096 (WPARAM)font[boardSize][MESSAGE_FONT]->hf,
\r
2097 MAKELPARAM(FALSE, 0));
\r
2099 if (buttonDesc[i].id == IDM_Pause)
\r
2100 hwndPause = buttonDesc[i].hwnd;
\r
2101 buttonDesc[i].wndproc = (WNDPROC)
\r
2102 SetWindowLong(buttonDesc[i].hwnd, GWL_WNDPROC, (LONG) ButtonProc);
\r
2105 if (gridPen != NULL) DeleteObject(gridPen);
\r
2106 if (highlightPen != NULL) DeleteObject(highlightPen);
\r
2107 if (premovePen != NULL) DeleteObject(premovePen);
\r
2108 if (lineGap != 0) {
\r
2109 logbrush.lbStyle = BS_SOLID;
\r
2110 logbrush.lbColor = RGB(0, 0, 0); /* grid pen color = black */
\r
2112 ExtCreatePen(PS_GEOMETRIC|PS_SOLID|PS_ENDCAP_FLAT|PS_JOIN_MITER,
\r
2113 lineGap, &logbrush, 0, NULL);
\r
2114 logbrush.lbColor = highlightSquareColor;
\r
2116 ExtCreatePen(PS_GEOMETRIC|PS_SOLID|PS_ENDCAP_FLAT|PS_JOIN_MITER,
\r
2117 lineGap, &logbrush, 0, NULL);
\r
2119 logbrush.lbColor = premoveHighlightColor;
\r
2121 ExtCreatePen(PS_GEOMETRIC|PS_SOLID|PS_ENDCAP_FLAT|PS_JOIN_MITER,
\r
2122 lineGap, &logbrush, 0, NULL);
\r
2124 /* [HGM] Loop had to be split in part for vert. and hor. lines */
\r
2125 for (i = 0; i < BOARD_HEIGHT + 1; i++) {
\r
2126 gridEndpoints[i*2].x = boardRect.left + lineGap / 2;
\r
2127 gridEndpoints[i*2].y = gridEndpoints[i*2 + 1].y =
\r
2128 boardRect.top + lineGap / 2 + (i * (squareSize + lineGap));
\r
2129 gridEndpoints[i*2 + 1].x = boardRect.left + lineGap / 2 +
\r
2130 BOARD_WIDTH * (squareSize + lineGap);
\r
2131 gridVertexCounts[i*2] = gridVertexCounts[i*2 + 1] = 2;
\r
2133 for (i = 0; i < BOARD_WIDTH + 1; i++) {
\r
2134 gridEndpoints[i*2 + BOARD_HEIGHT*2 + 2].y = boardRect.top + lineGap / 2;
\r
2135 gridEndpoints[i*2 + BOARD_HEIGHT*2 + 2].x =
\r
2136 gridEndpoints[i*2 + 1 + BOARD_HEIGHT*2 + 2].x = boardRect.left +
\r
2137 lineGap / 2 + (i * (squareSize + lineGap));
\r
2138 gridEndpoints[i*2 + 1 + BOARD_HEIGHT*2 + 2].y =
\r
2139 boardRect.top + BOARD_HEIGHT * (squareSize + lineGap);
\r
2140 gridVertexCounts[i*2] = gridVertexCounts[i*2 + 1] = 2;
\r
2144 /* [HGM] Licensing requirement */
\r
2146 if(gameInfo.variant == VariantGothic) GothicPopUp( GOTHIC, VariantGothic); else
\r
2149 if(gameInfo.variant == VariantFalcon) GothicPopUp( FALCON, VariantFalcon); else
\r
2151 GothicPopUp( "", VariantNormal);
\r
2154 /* if (boardSize == oldBoardSize) return; [HGM] variant might have changed */
\r
2156 /* Load piece bitmaps for this board size */
\r
2157 for (i=0; i<=2; i++) {
\r
2158 for (piece = WhitePawn;
\r
2159 (int) piece < (int) BlackPawn;
\r
2160 piece = (ChessSquare) ((int) piece + 1)) {
\r
2161 if (pieceBitmap[i][piece] != NULL)
\r
2162 DeleteObject(pieceBitmap[i][piece]);
\r
2166 fontBitmapSquareSize = 0; /* [HGM] render: make sure pieces will be recreated, as we might need others now */
\r
2167 // Orthodox Chess pieces
\r
2168 pieceBitmap[0][WhitePawn] = DoLoadBitmap(hInst, "p", squareSize, "s");
\r
2169 pieceBitmap[0][WhiteKnight] = DoLoadBitmap(hInst, "n", squareSize, "s");
\r
2170 pieceBitmap[0][WhiteBishop] = DoLoadBitmap(hInst, "b", squareSize, "s");
\r
2171 pieceBitmap[0][WhiteRook] = DoLoadBitmap(hInst, "r", squareSize, "s");
\r
2172 pieceBitmap[0][WhiteKing] = DoLoadBitmap(hInst, "k", squareSize, "s");
\r
2173 pieceBitmap[1][WhitePawn] = DoLoadBitmap(hInst, "p", squareSize, "o");
\r
2174 pieceBitmap[1][WhiteKnight] = DoLoadBitmap(hInst, "n", squareSize, "o");
\r
2175 pieceBitmap[1][WhiteBishop] = DoLoadBitmap(hInst, "b", squareSize, "o");
\r
2176 pieceBitmap[1][WhiteRook] = DoLoadBitmap(hInst, "r", squareSize, "o");
\r
2177 pieceBitmap[1][WhiteKing] = DoLoadBitmap(hInst, "k", squareSize, "o");
\r
2178 pieceBitmap[2][WhitePawn] = DoLoadBitmap(hInst, "p", squareSize, "w");
\r
2179 pieceBitmap[2][WhiteKnight] = DoLoadBitmap(hInst, "n", squareSize, "w");
\r
2180 pieceBitmap[2][WhiteBishop] = DoLoadBitmap(hInst, "b", squareSize, "w");
\r
2181 pieceBitmap[2][WhiteRook] = DoLoadBitmap(hInst, "r", squareSize, "w");
\r
2182 pieceBitmap[2][WhiteKing] = DoLoadBitmap(hInst, "k", squareSize, "w");
\r
2183 if( !strcmp(appData.variant, "shogi") && (squareSize==72 || squareSize==49)) {
\r
2184 // in Shogi, Hijack the unused Queen for Lance
\r
2185 pieceBitmap[0][WhiteQueen] = DoLoadBitmap(hInst, "l", squareSize, "s");
\r
2186 pieceBitmap[1][WhiteQueen] = DoLoadBitmap(hInst, "l", squareSize, "o");
\r
2187 pieceBitmap[2][WhiteQueen] = DoLoadBitmap(hInst, "l", squareSize, "w");
\r
2189 pieceBitmap[0][WhiteQueen] = DoLoadBitmap(hInst, "q", squareSize, "s");
\r
2190 pieceBitmap[1][WhiteQueen] = DoLoadBitmap(hInst, "q", squareSize, "o");
\r
2191 pieceBitmap[2][WhiteQueen] = DoLoadBitmap(hInst, "q", squareSize, "w");
\r
2194 if(squareSize <= 72 && squareSize >= 33) {
\r
2195 /* A & C are available in most sizes now */
\r
2196 if(squareSize != 49 && squareSize != 72 && squareSize != 33) { // Vortex-like
\r
2197 pieceBitmap[0][WhiteAngel] = DoLoadBitmap(hInst, "a", squareSize, "s");
\r
2198 pieceBitmap[1][WhiteAngel] = DoLoadBitmap(hInst, "a", squareSize, "o");
\r
2199 pieceBitmap[2][WhiteAngel] = DoLoadBitmap(hInst, "a", squareSize, "w");
\r
2200 pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "s");
\r
2201 pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "o");
\r
2202 pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "w");
\r
2203 pieceBitmap[0][WhiteCobra] = DoLoadBitmap(hInst, "cv", squareSize, "s");
\r
2204 pieceBitmap[1][WhiteCobra] = DoLoadBitmap(hInst, "cv", squareSize, "o");
\r
2205 pieceBitmap[2][WhiteCobra] = DoLoadBitmap(hInst, "cv", squareSize, "w");
\r
2206 pieceBitmap[0][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "s");
\r
2207 pieceBitmap[1][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "o");
\r
2208 pieceBitmap[2][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "w");
\r
2209 } else { // Smirf-like
\r
2210 pieceBitmap[0][WhiteAngel] = DoLoadBitmap(hInst, "aa", squareSize, "s");
\r
2211 pieceBitmap[1][WhiteAngel] = DoLoadBitmap(hInst, "aa", squareSize, "o");
\r
2212 pieceBitmap[2][WhiteAngel] = DoLoadBitmap(hInst, "aa", squareSize, "w");
\r
2214 if(gameInfo.variant == VariantGothic) { // Vortex-like
\r
2215 pieceBitmap[0][WhiteMarshall] = DoLoadBitmap(hInst, "cv", squareSize, "s");
\r
2216 pieceBitmap[1][WhiteMarshall] = DoLoadBitmap(hInst, "cv", squareSize, "o");
\r
2217 pieceBitmap[2][WhiteMarshall] = DoLoadBitmap(hInst, "cv", squareSize, "w");
\r
2218 } else { // WinBoard standard
\r
2219 pieceBitmap[0][WhiteMarshall] = DoLoadBitmap(hInst, "c", squareSize, "s");
\r
2220 pieceBitmap[1][WhiteMarshall] = DoLoadBitmap(hInst, "c", squareSize, "o");
\r
2221 pieceBitmap[2][WhiteMarshall] = DoLoadBitmap(hInst, "c", squareSize, "w");
\r
2226 if(squareSize==72 || squareSize==49 || squareSize==33) { /* experiment with some home-made bitmaps */
\r
2227 pieceBitmap[0][WhiteFerz] = DoLoadBitmap(hInst, "f", squareSize, "s");
\r
2228 pieceBitmap[1][WhiteFerz] = DoLoadBitmap(hInst, "f", squareSize, "o");
\r
2229 pieceBitmap[2][WhiteFerz] = DoLoadBitmap(hInst, "f", squareSize, "w");
\r
2230 pieceBitmap[0][WhiteWazir] = DoLoadBitmap(hInst, "w", squareSize, "s");
\r
2231 pieceBitmap[1][WhiteWazir] = DoLoadBitmap(hInst, "w", squareSize, "o");
\r
2232 pieceBitmap[2][WhiteWazir] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
2233 pieceBitmap[0][WhiteAlfil] = DoLoadBitmap(hInst, "e", squareSize, "s");
\r
2234 pieceBitmap[1][WhiteAlfil] = DoLoadBitmap(hInst, "e", squareSize, "o");
\r
2235 pieceBitmap[2][WhiteAlfil] = DoLoadBitmap(hInst, "e", squareSize, "w");
\r
2236 pieceBitmap[0][WhiteMan] = DoLoadBitmap(hInst, "m", squareSize, "s");
\r
2237 pieceBitmap[1][WhiteMan] = DoLoadBitmap(hInst, "m", squareSize, "o");
\r
2238 pieceBitmap[2][WhiteMan] = DoLoadBitmap(hInst, "m", squareSize, "w");
\r
2239 pieceBitmap[0][WhiteCardinal] = DoLoadBitmap(hInst, "a", squareSize, "s");
\r
2240 pieceBitmap[1][WhiteCardinal] = DoLoadBitmap(hInst, "a", squareSize, "o");
\r
2241 pieceBitmap[2][WhiteCardinal] = DoLoadBitmap(hInst, "a", squareSize, "w");
\r
2242 pieceBitmap[0][WhiteDragon] = DoLoadBitmap(hInst, "dk", squareSize, "s");
\r
2243 pieceBitmap[1][WhiteDragon] = DoLoadBitmap(hInst, "dk", squareSize, "o");
\r
2244 pieceBitmap[2][WhiteDragon] = DoLoadBitmap(hInst, "dk", squareSize, "w");
\r
2245 pieceBitmap[0][WhiteFalcon] = DoLoadBitmap(hInst, "v", squareSize, "s");
\r
2246 pieceBitmap[1][WhiteFalcon] = DoLoadBitmap(hInst, "v", squareSize, "o");
\r
2247 pieceBitmap[2][WhiteFalcon] = DoLoadBitmap(hInst, "v", squareSize, "w");
\r
2248 pieceBitmap[0][WhiteCobra] = DoLoadBitmap(hInst, "s", squareSize, "s");
\r
2249 pieceBitmap[1][WhiteCobra] = DoLoadBitmap(hInst, "s", squareSize, "o");
\r
2250 pieceBitmap[2][WhiteCobra] = DoLoadBitmap(hInst, "s", squareSize, "w");
\r
2251 pieceBitmap[0][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "s");
\r
2252 pieceBitmap[1][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "o");
\r
2253 pieceBitmap[2][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "w");
\r
2254 pieceBitmap[0][WhiteUnicorn] = DoLoadBitmap(hInst, "u", squareSize, "s");
\r
2255 pieceBitmap[1][WhiteUnicorn] = DoLoadBitmap(hInst, "u", squareSize, "o");
\r
2256 pieceBitmap[2][WhiteUnicorn] = DoLoadBitmap(hInst, "u", squareSize, "w");
\r
2258 if(gameInfo.variant == VariantShogi) { /* promoted Gold represemtations */
\r
2259 pieceBitmap[0][WhiteCannon] = DoLoadBitmap(hInst, "wp", squareSize, "s");
\r
2260 pieceBitmap[1][WhiteCannon] = DoLoadBitmap(hInst, "wp", squareSize, "o");
\r
2261 pieceBitmap[2][WhiteCannon] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
2262 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "wn", squareSize, "s");
\r
2263 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "wn", squareSize, "o");
\r
2264 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
2265 pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "ws", squareSize, "s");
\r
2266 pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "ws", squareSize, "o");
\r
2267 pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
2268 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "wl", squareSize, "s");
\r
2269 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "wl", squareSize, "o");
\r
2270 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
2272 pieceBitmap[0][WhiteCannon] = DoLoadBitmap(hInst, "o", squareSize, "s");
\r
2273 pieceBitmap[1][WhiteCannon] = DoLoadBitmap(hInst, "o", squareSize, "o");
\r
2274 pieceBitmap[2][WhiteCannon] = DoLoadBitmap(hInst, "o", squareSize, "w");
\r
2275 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "h", squareSize, "s");
\r
2276 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "h", squareSize, "o");
\r
2277 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "h", squareSize, "w");
\r
2278 pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "s");
\r
2279 pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "o");
\r
2280 pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "w");
\r
2281 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "g", squareSize, "s");
\r
2282 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "g", squareSize, "o");
\r
2283 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "g", squareSize, "w");
\r
2286 } else { /* other size, no special bitmaps available. Use smaller symbols */
\r
2287 if((int)boardSize < 2) minorSize = sizeInfo[0].squareSize;
\r
2288 else minorSize = sizeInfo[(int)boardSize - 2].squareSize;
\r
2289 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "n", minorSize, "s");
\r
2290 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "n", minorSize, "o");
\r
2291 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "n", minorSize, "w");
\r
2292 pieceBitmap[0][WhiteCardinal] = DoLoadBitmap(hInst, "b", minorSize, "s");
\r
2293 pieceBitmap[1][WhiteCardinal] = DoLoadBitmap(hInst, "b", minorSize, "o");
\r
2294 pieceBitmap[2][WhiteCardinal] = DoLoadBitmap(hInst, "b", minorSize, "w");
\r
2295 pieceBitmap[0][WhiteDragon] = DoLoadBitmap(hInst, "r", minorSize, "s");
\r
2296 pieceBitmap[1][WhiteDragon] = DoLoadBitmap(hInst, "r", minorSize, "o");
\r
2297 pieceBitmap[2][WhiteDragon] = DoLoadBitmap(hInst, "r", minorSize, "w");
\r
2298 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "q", minorSize, "s");
\r
2299 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "q", minorSize, "o");
\r
2300 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "q", minorSize, "w");
\r
2304 if(gameInfo.variant == VariantShogi && squareSize == 58)
\r
2305 /* special Shogi support in this size */
\r
2306 { for (i=0; i<=2; i++) { /* replace all bitmaps */
\r
2307 for (piece = WhitePawn;
\r
2308 (int) piece < (int) BlackPawn;
\r
2309 piece = (ChessSquare) ((int) piece + 1)) {
\r
2310 if (pieceBitmap[i][piece] != NULL)
\r
2311 DeleteObject(pieceBitmap[i][piece]);
\r
2314 pieceBitmap[0][WhitePawn] = DoLoadBitmap(hInst, "sp", squareSize, "o");
\r
2315 pieceBitmap[0][WhiteKnight] = DoLoadBitmap(hInst, "sn", squareSize, "o");
\r
2316 pieceBitmap[0][WhiteBishop] = DoLoadBitmap(hInst, "sb", squareSize, "o");
\r
2317 pieceBitmap[0][WhiteRook] = DoLoadBitmap(hInst, "sr", squareSize, "o");
\r
2318 pieceBitmap[0][WhiteQueen] = DoLoadBitmap(hInst, "sl", squareSize, "o");
\r
2319 pieceBitmap[0][WhiteKing] = DoLoadBitmap(hInst, "sk", squareSize, "o");
\r
2320 pieceBitmap[0][WhiteFerz] = DoLoadBitmap(hInst, "sf", squareSize, "o");
\r
2321 pieceBitmap[0][WhiteWazir] = DoLoadBitmap(hInst, "sw", squareSize, "o");
\r
2322 pieceBitmap[0][WhiteCannon] = DoLoadBitmap(hInst, "su", squareSize, "o");
\r
2323 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "sh", squareSize, "o");
\r
2324 pieceBitmap[0][WhiteCardinal] = DoLoadBitmap(hInst, "sa", squareSize, "o");
\r
2325 pieceBitmap[0][WhiteDragon] = DoLoadBitmap(hInst, "sc", squareSize, "o");
\r
2326 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "sg", squareSize, "o");
\r
2327 pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "ss", squareSize, "o");
\r
2328 pieceBitmap[1][WhitePawn] = DoLoadBitmap(hInst, "sp", squareSize, "o");
\r
2329 pieceBitmap[1][WhiteKnight] = DoLoadBitmap(hInst, "sn", squareSize, "o");
\r
2330 pieceBitmap[1][WhiteBishop] = DoLoadBitmap(hInst, "sb", squareSize, "o");
\r
2331 pieceBitmap[1][WhiteRook] = DoLoadBitmap(hInst, "sr", squareSize, "o");
\r
2332 pieceBitmap[1][WhiteQueen] = DoLoadBitmap(hInst, "sl", squareSize, "o");
\r
2333 pieceBitmap[1][WhiteKing] = DoLoadBitmap(hInst, "sk", squareSize, "o");
\r
2334 pieceBitmap[1][WhiteFerz] = DoLoadBitmap(hInst, "sf", squareSize, "o");
\r
2335 pieceBitmap[1][WhiteWazir] = DoLoadBitmap(hInst, "sw", squareSize, "o");
\r
2336 pieceBitmap[1][WhiteCannon] = DoLoadBitmap(hInst, "su", squareSize, "o");
\r
2337 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "sh", squareSize, "o");
\r
2338 pieceBitmap[1][WhiteCardinal] = DoLoadBitmap(hInst, "sa", squareSize, "o");
\r
2339 pieceBitmap[1][WhiteDragon] = DoLoadBitmap(hInst, "sc", squareSize, "o");
\r
2340 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "sg", squareSize, "o");
\r
2341 pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "ss", squareSize, "o");
\r
2342 pieceBitmap[2][WhitePawn] = DoLoadBitmap(hInst, "sp", squareSize, "w");
\r
2343 pieceBitmap[2][WhiteKnight] = DoLoadBitmap(hInst, "sn", squareSize, "w");
\r
2344 pieceBitmap[2][WhiteBishop] = DoLoadBitmap(hInst, "sr", squareSize, "w");
\r
2345 pieceBitmap[2][WhiteRook] = DoLoadBitmap(hInst, "sr", squareSize, "w");
\r
2346 pieceBitmap[2][WhiteQueen] = DoLoadBitmap(hInst, "sl", squareSize, "w");
\r
2347 pieceBitmap[2][WhiteKing] = DoLoadBitmap(hInst, "sk", squareSize, "w");
\r
2348 pieceBitmap[2][WhiteFerz] = DoLoadBitmap(hInst, "sw", squareSize, "w");
\r
2349 pieceBitmap[2][WhiteWazir] = DoLoadBitmap(hInst, "sw", squareSize, "w");
\r
2350 pieceBitmap[2][WhiteCannon] = DoLoadBitmap(hInst, "sp", squareSize, "w");
\r
2351 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "sn", squareSize, "w");
\r
2352 pieceBitmap[2][WhiteCardinal] = DoLoadBitmap(hInst, "sr", squareSize, "w");
\r
2353 pieceBitmap[2][WhiteDragon] = DoLoadBitmap(hInst, "sr", squareSize, "w");
\r
2354 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "sl", squareSize, "w");
\r
2355 pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "sw", squareSize, "w");
\r
2361 PieceBitmap(ChessSquare p, int kind)
\r
2363 if ((int) p >= (int) BlackPawn)
\r
2364 p = (ChessSquare) ((int) p - (int) BlackPawn + (int) WhitePawn);
\r
2366 return pieceBitmap[kind][(int) p];
\r
2369 /***************************************************************/
\r
2371 #define MIN(a,b) (((a) < (b)) ? (a) : (b))
\r
2372 #define MAX(a,b) (((a) > (b)) ? (a) : (b))
\r
2374 #define MIN3(a,b,c) (((a) < (b) && (a) < (c)) ? (a) : (((b) < (a) && (b) < (c)) ? (b) : (c)))
\r
2375 #define MAX3(a,b,c) (((a) > (b) && (a) > (c)) ? (a) : (((b) > (a) && (b) > (c)) ? (b) : (c)))
\r
2379 SquareToPos(int row, int column, int * x, int * y)
\r
2382 *x = boardRect.left + lineGap + ((BOARD_WIDTH-1)-column) * (squareSize + lineGap);
\r
2383 *y = boardRect.top + lineGap + row * (squareSize + lineGap);
\r
2385 *x = boardRect.left + lineGap + column * (squareSize + lineGap);
\r
2386 *y = boardRect.top + lineGap + ((BOARD_HEIGHT-1)-row) * (squareSize + lineGap);
\r
2391 DrawCoordsOnDC(HDC hdc)
\r
2393 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
2394 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
2395 char str[2] = { NULLCHAR, NULLCHAR };
\r
2396 int oldMode, oldAlign, x, y, start, i;
\r
2400 if (!appData.showCoords)
\r
2403 start = flipView ? 1-(ONE!='1') : 23+(ONE!='1')-BOARD_HEIGHT;
\r
2405 oldBrush = SelectObject(hdc, GetStockObject(BLACK_BRUSH));
\r
2406 oldMode = SetBkMode(hdc, (appData.monoMode ? OPAQUE : TRANSPARENT));
\r
2407 oldAlign = GetTextAlign(hdc);
\r
2408 oldFont = SelectObject(hdc, font[boardSize][COORD_FONT]->hf);
\r
2410 y = boardRect.top + lineGap;
\r
2411 x = boardRect.left + lineGap + gameInfo.holdingsWidth*(squareSize + lineGap);
\r
2413 SetTextAlign(hdc, TA_LEFT|TA_TOP);
\r
2414 for (i = 0; i < BOARD_HEIGHT; i++) {
\r
2415 str[0] = files[start + i];
\r
2416 ExtTextOut(hdc, x + 2, y + 1, 0, NULL, str, 1, NULL);
\r
2417 y += squareSize + lineGap;
\r
2420 start = flipView ? 12-(BOARD_RGHT-BOARD_LEFT) : 12;
\r
2422 SetTextAlign(hdc, TA_RIGHT|TA_BOTTOM);
\r
2423 for (i = 0; i < BOARD_RGHT - BOARD_LEFT; i++) {
\r
2424 str[0] = ranks[start + i];
\r
2425 ExtTextOut(hdc, x + squareSize - 2, y - 1, 0, NULL, str, 1, NULL);
\r
2426 x += squareSize + lineGap;
\r
2429 SelectObject(hdc, oldBrush);
\r
2430 SetBkMode(hdc, oldMode);
\r
2431 SetTextAlign(hdc, oldAlign);
\r
2432 SelectObject(hdc, oldFont);
\r
2436 DrawGridOnDC(HDC hdc)
\r
2440 if (lineGap != 0) {
\r
2441 oldPen = SelectObject(hdc, gridPen);
\r
2442 PolyPolyline(hdc, gridEndpoints, gridVertexCounts, BOARD_WIDTH+BOARD_HEIGHT + 2);
\r
2443 SelectObject(hdc, oldPen);
\r
2447 #define HIGHLIGHT_PEN 0
\r
2448 #define PREMOVE_PEN 1
\r
2451 DrawHighlightOnDC(HDC hdc, BOOLEAN on, int x, int y, int pen)
\r
2454 HPEN oldPen, hPen;
\r
2455 if (lineGap == 0) return;
\r
2457 x1 = boardRect.left +
\r
2458 lineGap/2 + ((BOARD_WIDTH-1)-x) * (squareSize + lineGap);
\r
2459 y1 = boardRect.top +
\r
2460 lineGap/2 + y * (squareSize + lineGap);
\r
2462 x1 = boardRect.left +
\r
2463 lineGap/2 + x * (squareSize + lineGap);
\r
2464 y1 = boardRect.top +
\r
2465 lineGap/2 + ((BOARD_HEIGHT-1)-y) * (squareSize + lineGap);
\r
2467 hPen = pen ? premovePen : highlightPen;
\r
2468 oldPen = SelectObject(hdc, on ? hPen : gridPen);
\r
2469 MoveToEx(hdc, x1, y1, NULL);
\r
2470 LineTo(hdc, x1 + squareSize + lineGap, y1);
\r
2471 LineTo(hdc, x1 + squareSize + lineGap, y1 + squareSize + lineGap);
\r
2472 LineTo(hdc, x1, y1 + squareSize + lineGap);
\r
2473 LineTo(hdc, x1, y1);
\r
2474 SelectObject(hdc, oldPen);
\r
2478 DrawHighlightsOnDC(HDC hdc)
\r
2481 for (i=0; i<2; i++) {
\r
2482 if (highlightInfo.sq[i].x >= 0 && highlightInfo.sq[i].y >= 0)
\r
2483 DrawHighlightOnDC(hdc, TRUE,
\r
2484 highlightInfo.sq[i].x, highlightInfo.sq[i].y,
\r
2487 for (i=0; i<2; i++) {
\r
2488 if (premoveHighlightInfo.sq[i].x >= 0 &&
\r
2489 premoveHighlightInfo.sq[i].y >= 0) {
\r
2490 DrawHighlightOnDC(hdc, TRUE,
\r
2491 premoveHighlightInfo.sq[i].x,
\r
2492 premoveHighlightInfo.sq[i].y,
\r
2498 /* Note: sqcolor is used only in monoMode */
\r
2499 /* Note that this code is largely duplicated in woptions.c,
\r
2500 function DrawSampleSquare, so that needs to be updated too */
\r
2502 DrawPieceOnDC(HDC hdc, ChessSquare piece, int color, int sqcolor, int x, int y, HDC tmphdc)
\r
2504 HBITMAP oldBitmap;
\r
2508 if (appData.blindfold) return;
\r
2510 /* [AS] Use font-based pieces if needed */
\r
2511 if( fontBitmapSquareSize >= 0 && squareSize > 32 ) {
\r
2512 /* Create piece bitmaps, or do nothing if piece set is up to date */
\r
2513 CreatePiecesFromFont();
\r
2515 if( fontBitmapSquareSize == squareSize ) {
\r
2516 int index = TranslatePieceToFontPiece(piece);
\r
2518 SelectObject( tmphdc, hPieceMask[ index ] );
\r
2522 squareSize, squareSize,
\r
2527 SelectObject( tmphdc, hPieceFace[ index ] );
\r
2531 squareSize, squareSize,
\r
2540 if (appData.monoMode) {
\r
2541 SelectObject(tmphdc, PieceBitmap(piece,
\r
2542 color == sqcolor ? OUTLINE_PIECE : SOLID_PIECE));
\r
2543 BitBlt(hdc, x, y, squareSize, squareSize, tmphdc, 0, 0,
\r
2544 sqcolor ? SRCCOPY : NOTSRCCOPY);
\r
2546 tmpSize = squareSize;
\r
2548 ((piece >= (int)WhiteNightrider && piece <= WhiteGrasshopper) ||
\r
2549 (piece >= (int)BlackNightrider && piece <= BlackGrasshopper)) ) {
\r
2550 /* [HGM] no bitmap available for promoted pieces in Crazyhouse */
\r
2551 /* Bitmaps of smaller size are substituted, but we have to align them */
\r
2552 x += (squareSize - minorSize)>>1;
\r
2553 y += squareSize - minorSize - 2;
\r
2554 tmpSize = minorSize;
\r
2556 if (color || appData.allWhite ) {
\r
2557 oldBitmap = SelectObject(tmphdc, PieceBitmap(piece, WHITE_PIECE));
\r
2559 oldBrush = SelectObject(hdc, whitePieceBrush);
\r
2560 else oldBrush = SelectObject(hdc, blackPieceBrush);
\r
2561 if(appData.upsideDown && color==flipView)
\r
2562 StretchBlt(hdc, x+tmpSize, y+tmpSize, -tmpSize, -tmpSize, tmphdc, 0, 0, tmpSize, tmpSize, 0x00B8074A);
\r
2564 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, 0x00B8074A);
\r
2565 /* Use black for outline of white pieces */
\r
2566 SelectObject(tmphdc, PieceBitmap(piece, OUTLINE_PIECE));
\r
2567 if(appData.upsideDown && color==flipView)
\r
2568 StretchBlt(hdc, x+tmpSize, y+tmpSize, -tmpSize, -tmpSize, tmphdc, 0, 0, tmpSize, tmpSize, SRCAND);
\r
2570 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, SRCAND);
\r
2572 /* Use square color for details of black pieces */
\r
2573 oldBitmap = SelectObject(tmphdc, PieceBitmap(piece, SOLID_PIECE));
\r
2574 oldBrush = SelectObject(hdc, blackPieceBrush);
\r
2575 if(appData.upsideDown && !flipView)
\r
2576 StretchBlt(hdc, x+tmpSize, y+tmpSize, -tmpSize, -tmpSize, tmphdc, 0, 0, tmpSize, tmpSize, 0x00B8074A);
\r
2578 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, 0x00B8074A);
\r
2580 SelectObject(hdc, oldBrush);
\r
2581 SelectObject(tmphdc, oldBitmap);
\r
2585 /* [AS] Compute a drawing mode for a square, based on specified settings (see DrawTile) */
\r
2586 int GetBackTextureMode( int algo )
\r
2588 int result = BACK_TEXTURE_MODE_DISABLED;
\r
2592 case BACK_TEXTURE_MODE_PLAIN:
\r
2593 result = 1; /* Always use identity map */
\r
2595 case BACK_TEXTURE_MODE_FULL_RANDOM:
\r
2596 result = 1 + (myrandom() % 3); /* Pick a transformation at random */
\r
2604 [AS] Compute and save texture drawing info, otherwise we may not be able
\r
2605 to handle redraws cleanly (as random numbers would always be different).
\r
2607 VOID RebuildTextureSquareInfo()
\r
2617 ZeroMemory( &backTextureSquareInfo, sizeof(backTextureSquareInfo) );
\r
2619 if( liteBackTexture != NULL ) {
\r
2620 if( GetObject( liteBackTexture, sizeof(bi), &bi ) > 0 ) {
\r
2621 lite_w = bi.bmWidth;
\r
2622 lite_h = bi.bmHeight;
\r
2626 if( darkBackTexture != NULL ) {
\r
2627 if( GetObject( darkBackTexture, sizeof(bi), &bi ) > 0 ) {
\r
2628 dark_w = bi.bmWidth;
\r
2629 dark_h = bi.bmHeight;
\r
2633 for( row=0; row<BOARD_HEIGHT; row++ ) {
\r
2634 for( col=0; col<BOARD_WIDTH; col++ ) {
\r
2635 if( (col + row) & 1 ) {
\r
2637 if( lite_w >= squareSize && lite_h >= squareSize ) {
\r
2638 backTextureSquareInfo[row][col].x = col * (lite_w - squareSize) / (BOARD_WIDTH-1); /* [HGM] divide by size-1 in stead of size! */
\r
2639 backTextureSquareInfo[row][col].y = (BOARD_HEIGHT-1-row) * (lite_h - squareSize) / (BOARD_HEIGHT-1);
\r
2640 backTextureSquareInfo[row][col].mode = GetBackTextureMode(liteBackTextureMode);
\r
2645 if( dark_w >= squareSize && dark_h >= squareSize ) {
\r
2646 backTextureSquareInfo[row][col].x = col * (dark_w - squareSize) / (BOARD_WIDTH-1);
\r
2647 backTextureSquareInfo[row][col].y = (BOARD_HEIGHT-1-row) * (dark_h - squareSize) / (BOARD_HEIGHT-1);
\r
2648 backTextureSquareInfo[row][col].mode = GetBackTextureMode(darkBackTextureMode);
\r
2655 /* [AS] Arrow highlighting support */
\r
2657 static int A_WIDTH = 5; /* Width of arrow body */
\r
2659 #define A_HEIGHT_FACTOR 6 /* Length of arrow "point", relative to body width */
\r
2660 #define A_WIDTH_FACTOR 3 /* Width of arrow "point", relative to body width */
\r
2662 static double Sqr( double x )
\r
2667 static int Round( double x )
\r
2669 return (int) (x + 0.5);
\r
2672 /* Draw an arrow between two points using current settings */
\r
2673 VOID DrawArrowBetweenPoints( HDC hdc, int s_x, int s_y, int d_x, int d_y )
\r
2676 double dx, dy, j, k, x, y;
\r
2678 if( d_x == s_x ) {
\r
2679 int h = (d_y > s_y) ? +A_WIDTH*A_HEIGHT_FACTOR : -A_WIDTH*A_HEIGHT_FACTOR;
\r
2681 arrow[0].x = s_x + A_WIDTH;
\r
2684 arrow[1].x = s_x + A_WIDTH;
\r
2685 arrow[1].y = d_y - h;
\r
2687 arrow[2].x = s_x + A_WIDTH*A_WIDTH_FACTOR;
\r
2688 arrow[2].y = d_y - h;
\r
2693 arrow[4].x = s_x - A_WIDTH*A_WIDTH_FACTOR;
\r
2694 arrow[4].y = d_y - h;
\r
2696 arrow[5].x = s_x - A_WIDTH;
\r
2697 arrow[5].y = d_y - h;
\r
2699 arrow[6].x = s_x - A_WIDTH;
\r
2702 else if( d_y == s_y ) {
\r
2703 int w = (d_x > s_x) ? +A_WIDTH*A_HEIGHT_FACTOR : -A_WIDTH*A_HEIGHT_FACTOR;
\r
2706 arrow[0].y = s_y + A_WIDTH;
\r
2708 arrow[1].x = d_x - w;
\r
2709 arrow[1].y = s_y + A_WIDTH;
\r
2711 arrow[2].x = d_x - w;
\r
2712 arrow[2].y = s_y + A_WIDTH*A_WIDTH_FACTOR;
\r
2717 arrow[4].x = d_x - w;
\r
2718 arrow[4].y = s_y - A_WIDTH*A_WIDTH_FACTOR;
\r
2720 arrow[5].x = d_x - w;
\r
2721 arrow[5].y = s_y - A_WIDTH;
\r
2724 arrow[6].y = s_y - A_WIDTH;
\r
2727 /* [AS] Needed a lot of paper for this! :-) */
\r
2728 dy = (double) (d_y - s_y) / (double) (d_x - s_x);
\r
2729 dx = (double) (s_x - d_x) / (double) (s_y - d_y);
\r
2731 j = sqrt( Sqr(A_WIDTH) / (1.0 + Sqr(dx)) );
\r
2733 k = sqrt( Sqr(A_WIDTH*A_HEIGHT_FACTOR) / (1.0 + Sqr(dy)) );
\r
2738 arrow[0].x = Round(x - j);
\r
2739 arrow[0].y = Round(y + j*dx);
\r
2741 arrow[1].x = Round(x + j);
\r
2742 arrow[1].y = Round(y - j*dx);
\r
2745 x = (double) d_x - k;
\r
2746 y = (double) d_y - k*dy;
\r
2749 x = (double) d_x + k;
\r
2750 y = (double) d_y + k*dy;
\r
2753 arrow[2].x = Round(x + j);
\r
2754 arrow[2].y = Round(y - j*dx);
\r
2756 arrow[3].x = Round(x + j*A_WIDTH_FACTOR);
\r
2757 arrow[3].y = Round(y - j*A_WIDTH_FACTOR*dx);
\r
2762 arrow[5].x = Round(x - j*A_WIDTH_FACTOR);
\r
2763 arrow[5].y = Round(y + j*A_WIDTH_FACTOR*dx);
\r
2765 arrow[6].x = Round(x - j);
\r
2766 arrow[6].y = Round(y + j*dx);
\r
2769 Polygon( hdc, arrow, 7 );
\r
2772 /* [AS] Draw an arrow between two squares */
\r
2773 VOID DrawArrowBetweenSquares( HDC hdc, int s_col, int s_row, int d_col, int d_row )
\r
2775 int s_x, s_y, d_x, d_y;
\r
2782 if( s_col == d_col && s_row == d_row ) {
\r
2786 /* Get source and destination points */
\r
2787 SquareToPos( s_row, s_col, &s_x, &s_y);
\r
2788 SquareToPos( d_row, d_col, &d_x, &d_y);
\r
2791 d_y += squareSize / 4;
\r
2793 else if( d_y < s_y ) {
\r
2794 d_y += 3 * squareSize / 4;
\r
2797 d_y += squareSize / 2;
\r
2801 d_x += squareSize / 4;
\r
2803 else if( d_x < s_x ) {
\r
2804 d_x += 3 * squareSize / 4;
\r
2807 d_x += squareSize / 2;
\r
2810 s_x += squareSize / 2;
\r
2811 s_y += squareSize / 2;
\r
2813 /* Adjust width */
\r
2814 A_WIDTH = squareSize / 14;
\r
2817 stLB.lbStyle = BS_SOLID;
\r
2818 stLB.lbColor = appData.highlightArrowColor;
\r
2821 hpen = CreatePen( PS_SOLID, 2, RGB(0x00,0x00,0x00) );
\r
2822 holdpen = SelectObject( hdc, hpen );
\r
2823 hbrush = CreateBrushIndirect( &stLB );
\r
2824 holdbrush = SelectObject( hdc, hbrush );
\r
2826 DrawArrowBetweenPoints( hdc, s_x, s_y, d_x, d_y );
\r
2828 SelectObject( hdc, holdpen );
\r
2829 SelectObject( hdc, holdbrush );
\r
2830 DeleteObject( hpen );
\r
2831 DeleteObject( hbrush );
\r
2834 BOOL HasHighlightInfo()
\r
2836 BOOL result = FALSE;
\r
2838 if( highlightInfo.sq[0].x >= 0 && highlightInfo.sq[0].y >= 0 &&
\r
2839 highlightInfo.sq[1].x >= 0 && highlightInfo.sq[1].y >= 0 )
\r
2847 BOOL IsDrawArrowEnabled()
\r
2849 BOOL result = FALSE;
\r
2851 if( appData.highlightMoveWithArrow && squareSize >= 32 ) {
\r
2858 VOID DrawArrowHighlight( HDC hdc )
\r
2860 if( IsDrawArrowEnabled() && HasHighlightInfo() ) {
\r
2861 DrawArrowBetweenSquares( hdc,
\r
2862 highlightInfo.sq[0].x, highlightInfo.sq[0].y,
\r
2863 highlightInfo.sq[1].x, highlightInfo.sq[1].y );
\r
2867 HRGN GetArrowHighlightClipRegion( HDC hdc )
\r
2869 HRGN result = NULL;
\r
2871 if( HasHighlightInfo() ) {
\r
2872 int x1, y1, x2, y2;
\r
2873 int sx, sy, dx, dy;
\r
2875 SquareToPos(highlightInfo.sq[0].y, highlightInfo.sq[0].x, &x1, &y1 );
\r
2876 SquareToPos(highlightInfo.sq[1].y, highlightInfo.sq[1].x, &x2, &y2 );
\r
2878 sx = MIN( x1, x2 );
\r
2879 sy = MIN( y1, y2 );
\r
2880 dx = MAX( x1, x2 ) + squareSize;
\r
2881 dy = MAX( y1, y2 ) + squareSize;
\r
2883 result = CreateRectRgn( sx, sy, dx, dy );
\r
2890 Warning: this function modifies the behavior of several other functions.
\r
2892 Basically, Winboard is optimized to avoid drawing the whole board if not strictly
\r
2893 needed. Unfortunately, the decision whether or not to perform a full or partial
\r
2894 repaint is scattered all over the place, which is not good for features such as
\r
2895 "arrow highlighting" that require a full repaint of the board.
\r
2897 So, I've tried to patch the code where I thought it made sense (e.g. after or during
\r
2898 user interaction, when speed is not so important) but especially to avoid errors
\r
2899 in the displayed graphics.
\r
2901 In such patched places, I always try refer to this function so there is a single
\r
2902 place to maintain knowledge.
\r
2904 To restore the original behavior, just return FALSE unconditionally.
\r
2906 BOOL IsFullRepaintPreferrable()
\r
2908 BOOL result = FALSE;
\r
2910 if( (appData.highlightLastMove || appData.highlightDragging) && IsDrawArrowEnabled() ) {
\r
2911 /* Arrow may appear on the board */
\r
2919 This function is called by DrawPosition to know whether a full repaint must
\r
2922 Only DrawPosition may directly call this function, which makes use of
\r
2923 some state information. Other function should call DrawPosition specifying
\r
2924 the repaint flag, and can use IsFullRepaintPreferrable if needed.
\r
2926 BOOL DrawPositionNeedsFullRepaint()
\r
2928 BOOL result = FALSE;
\r
2931 Probably a slightly better policy would be to trigger a full repaint
\r
2932 when animInfo.piece changes state (i.e. empty -> non-empty and viceversa),
\r
2933 but animation is fast enough that it's difficult to notice.
\r
2935 if( animInfo.piece == EmptySquare ) {
\r
2936 if( (appData.highlightLastMove || appData.highlightDragging) && IsDrawArrowEnabled() /*&& HasHighlightInfo()*/ ) {
\r
2945 DrawBoardOnDC(HDC hdc, Board board, HDC tmphdc)
\r
2947 int row, column, x, y, square_color, piece_color;
\r
2948 ChessSquare piece;
\r
2950 HDC texture_hdc = NULL;
\r
2952 /* [AS] Initialize background textures if needed */
\r
2953 if( liteBackTexture != NULL || darkBackTexture != NULL ) {
\r
2954 static int backTextureBoardSize; /* [HGM] boardsize: also new texture if board format changed */
\r
2955 if( backTextureSquareSize != squareSize
\r
2956 || backTextureBoardSize != BOARD_WIDTH+BOARD_FILES*BOARD_HEIGHT) {
\r
2957 backTextureBoardSize = BOARD_WIDTH+BOARD_FILES*BOARD_HEIGHT;
\r
2958 backTextureSquareSize = squareSize;
\r
2959 RebuildTextureSquareInfo();
\r
2962 texture_hdc = CreateCompatibleDC( hdc );
\r
2965 for (row = 0; row < BOARD_HEIGHT; row++) {
\r
2966 for (column = 0; column < BOARD_WIDTH; column++) {
\r
2968 SquareToPos(row, column, &x, &y);
\r
2970 piece = board[row][column];
\r
2972 square_color = ((column + row) % 2) == 1;
\r
2973 if( gameInfo.variant == VariantXiangqi ) {
\r
2974 square_color = !InPalace(row, column);
\r
2975 if(BOARD_HEIGHT&1) { if(row==BOARD_HEIGHT/2) square_color ^= 1; }
\r
2976 else if(row < BOARD_HEIGHT/2) square_color ^= 1;
\r
2978 piece_color = (int) piece < (int) BlackPawn;
\r
2981 /* [HGM] holdings file: light square or black */
\r
2982 if(column == BOARD_LEFT-2) {
\r
2983 if( row > BOARD_HEIGHT - gameInfo.holdingsSize - 1 )
\r
2986 DisplayHoldingsCount(hdc, x, y, 0, 0); /* black out */
\r
2990 if(column == BOARD_RGHT + 1 ) {
\r
2991 if( row < gameInfo.holdingsSize )
\r
2994 DisplayHoldingsCount(hdc, x, y, 0, 0);
\r
2998 if(column == BOARD_LEFT-1 ) /* left align */
\r
2999 DisplayHoldingsCount(hdc, x, y, flipView, (int) board[row][column]);
\r
3000 else if( column == BOARD_RGHT) /* right align */
\r
3001 DisplayHoldingsCount(hdc, x, y, !flipView, (int) board[row][column]);
\r
3003 if (appData.monoMode) {
\r
3004 if (piece == EmptySquare) {
\r
3005 BitBlt(hdc, x, y, squareSize, squareSize, 0, 0, 0,
\r
3006 square_color ? WHITENESS : BLACKNESS);
\r
3008 DrawPieceOnDC(hdc, piece, piece_color, square_color, x, y, tmphdc);
\r
3011 else if( backTextureSquareInfo[row][column].mode > 0 ) {
\r
3012 /* [AS] Draw the square using a texture bitmap */
\r
3013 HBITMAP hbm = SelectObject( texture_hdc, square_color ? liteBackTexture : darkBackTexture );
\r
3014 int r = row, c = column; // [HGM] do not flip board in flipView
\r
3015 if(flipView) { r = BOARD_HEIGHT-1 - r; c = BOARD_WIDTH-1 - c; }
\r
3018 squareSize, squareSize,
\r
3021 backTextureSquareInfo[r][c].mode,
\r
3022 backTextureSquareInfo[r][c].x,
\r
3023 backTextureSquareInfo[r][c].y );
\r
3025 SelectObject( texture_hdc, hbm );
\r
3027 if (piece != EmptySquare) {
\r
3028 DrawPieceOnDC(hdc, piece, piece_color, -1, x, y, tmphdc);
\r
3032 HBRUSH brush = square_color ? lightSquareBrush : darkSquareBrush;
\r
3034 oldBrush = SelectObject(hdc, brush );
\r
3035 BitBlt(hdc, x, y, squareSize, squareSize, 0, 0, 0, PATCOPY);
\r
3036 SelectObject(hdc, oldBrush);
\r
3037 if (piece != EmptySquare)
\r
3038 DrawPieceOnDC(hdc, piece, piece_color, -1, x, y, tmphdc);
\r
3043 if( texture_hdc != NULL ) {
\r
3044 DeleteDC( texture_hdc );
\r
3048 int saveDiagFlag = 0; FILE *diagFile; // [HGM] diag
\r
3049 void fputDW(FILE *f, int x)
\r
3051 fputc(x & 255, f);
\r
3052 fputc(x>>8 & 255, f);
\r
3053 fputc(x>>16 & 255, f);
\r
3054 fputc(x>>24 & 255, f);
\r
3057 #define MAX_CLIPS 200 /* more than enough */
\r
3060 DrawLogoOnDC(HDC hdc, RECT logoRect, HBITMAP logo)
\r
3062 // HBITMAP bufferBitmap;
\r
3067 int w = 100, h = 50;
\r
3069 if(logo == NULL) return;
\r
3070 // GetClientRect(hwndMain, &Rect);
\r
3071 // bufferBitmap = CreateCompatibleBitmap(hdc, Rect.right-Rect.left+1,
\r
3072 // Rect.bottom-Rect.top+1);
\r
3073 tmphdc = CreateCompatibleDC(hdc);
\r
3074 hbm = SelectObject(tmphdc, logo);
\r
3075 if( GetObject( logo, sizeof(bi), &bi ) > 0 ) {
\r
3079 StretchBlt(hdc, logoRect.left, logoRect.top, logoRect.right - logoRect.left,
\r
3080 logoRect.bottom - logoRect.top, tmphdc, 0, 0, w, h, SRCCOPY);
\r
3081 SelectObject(tmphdc, hbm);
\r
3086 HDCDrawPosition(HDC hdc, BOOLEAN repaint, Board board)
\r
3088 static Board lastReq, lastDrawn;
\r
3089 static HighlightInfo lastDrawnHighlight, lastDrawnPremove;
\r
3090 static int lastDrawnFlipView = 0;
\r
3091 static int lastReqValid = 0, lastDrawnValid = 0;
\r
3092 int releaseDC, x, y, x2, y2, row, column, num_clips = 0, i;
\r
3095 HBITMAP bufferBitmap;
\r
3096 HBITMAP oldBitmap;
\r
3098 HRGN clips[MAX_CLIPS];
\r
3099 ChessSquare dragged_piece = EmptySquare;
\r
3101 /* I'm undecided on this - this function figures out whether a full
\r
3102 * repaint is necessary on its own, so there's no real reason to have the
\r
3103 * caller tell it that. I think this can safely be set to FALSE - but
\r
3104 * if we trust the callers not to request full repaints unnessesarily, then
\r
3105 * we could skip some clipping work. In other words, only request a full
\r
3106 * redraw when the majority of pieces have changed positions (ie. flip,
\r
3107 * gamestart and similar) --Hawk
\r
3109 Boolean fullrepaint = repaint;
\r
3111 if( DrawPositionNeedsFullRepaint() ) {
\r
3112 fullrepaint = TRUE;
\r
3115 if (board == NULL) {
\r
3116 if (!lastReqValid) {
\r
3121 CopyBoard(lastReq, board);
\r
3125 if (doingSizing) {
\r
3129 if (IsIconic(hwndMain)) {
\r
3133 if (hdc == NULL) {
\r
3134 hdc = GetDC(hwndMain);
\r
3135 if (!appData.monoMode) {
\r
3136 SelectPalette(hdc, hPal, FALSE);
\r
3137 RealizePalette(hdc);
\r
3141 releaseDC = FALSE;
\r
3144 /* Create some work-DCs */
\r
3145 hdcmem = CreateCompatibleDC(hdc);
\r
3146 tmphdc = CreateCompatibleDC(hdc);
\r
3148 /* If dragging is in progress, we temporarely remove the piece */
\r
3149 /* [HGM] or temporarily decrease count if stacked */
\r
3150 /* !! Moved to before board compare !! */
\r
3151 if (dragInfo.from.x >= 0 && dragInfo.pos.x >= 0) {
\r
3152 dragged_piece = board[dragInfo.from.y][dragInfo.from.x];
\r
3153 if(dragInfo.from.x == BOARD_LEFT-2 ) {
\r
3154 if(--board[dragInfo.from.y][dragInfo.from.x+1] == 0 )
\r
3155 board[dragInfo.from.y][dragInfo.from.x] = EmptySquare;
\r
3157 if(dragInfo.from.x == BOARD_RGHT+1) {
\r
3158 if(--board[dragInfo.from.y][dragInfo.from.x-1] == 0 )
\r
3159 board[dragInfo.from.y][dragInfo.from.x] = EmptySquare;
\r
3161 board[dragInfo.from.y][dragInfo.from.x] = EmptySquare;
\r
3164 /* Figure out which squares need updating by comparing the
\r
3165 * newest board with the last drawn board and checking if
\r
3166 * flipping has changed.
\r
3168 if (!fullrepaint && lastDrawnValid && lastDrawnFlipView == flipView) {
\r
3169 for (row = 0; row < BOARD_HEIGHT; row++) { /* [HGM] true size, not 8 */
\r
3170 for (column = 0; column < BOARD_WIDTH; column++) {
\r
3171 if (lastDrawn[row][column] != board[row][column]) {
\r
3172 SquareToPos(row, column, &x, &y);
\r
3173 clips[num_clips++] =
\r
3174 CreateRectRgn(x, y, x + squareSize, y + squareSize);
\r
3178 for (i=0; i<2; i++) {
\r
3179 if (lastDrawnHighlight.sq[i].x != highlightInfo.sq[i].x ||
\r
3180 lastDrawnHighlight.sq[i].y != highlightInfo.sq[i].y) {
\r
3181 if (lastDrawnHighlight.sq[i].x >= 0 &&
\r
3182 lastDrawnHighlight.sq[i].y >= 0) {
\r
3183 SquareToPos(lastDrawnHighlight.sq[i].y,
\r
3184 lastDrawnHighlight.sq[i].x, &x, &y);
\r
3185 clips[num_clips++] =
\r
3186 CreateRectRgn(x - lineGap, y - lineGap,
\r
3187 x + squareSize + lineGap, y + squareSize + lineGap);
\r
3189 if (highlightInfo.sq[i].x >= 0 && highlightInfo.sq[i].y >= 0) {
\r
3190 SquareToPos(highlightInfo.sq[i].y, highlightInfo.sq[i].x, &x, &y);
\r
3191 clips[num_clips++] =
\r
3192 CreateRectRgn(x - lineGap, y - lineGap,
\r
3193 x + squareSize + lineGap, y + squareSize + lineGap);
\r
3197 for (i=0; i<2; i++) {
\r
3198 if (lastDrawnPremove.sq[i].x != premoveHighlightInfo.sq[i].x ||
\r
3199 lastDrawnPremove.sq[i].y != premoveHighlightInfo.sq[i].y) {
\r
3200 if (lastDrawnPremove.sq[i].x >= 0 &&
\r
3201 lastDrawnPremove.sq[i].y >= 0) {
\r
3202 SquareToPos(lastDrawnPremove.sq[i].y,
\r
3203 lastDrawnPremove.sq[i].x, &x, &y);
\r
3204 clips[num_clips++] =
\r
3205 CreateRectRgn(x - lineGap, y - lineGap,
\r
3206 x + squareSize + lineGap, y + squareSize + lineGap);
\r
3208 if (premoveHighlightInfo.sq[i].x >= 0 &&
\r
3209 premoveHighlightInfo.sq[i].y >= 0) {
\r
3210 SquareToPos(premoveHighlightInfo.sq[i].y,
\r
3211 premoveHighlightInfo.sq[i].x, &x, &y);
\r
3212 clips[num_clips++] =
\r
3213 CreateRectRgn(x - lineGap, y - lineGap,
\r
3214 x + squareSize + lineGap, y + squareSize + lineGap);
\r