2 * WinBoard.c -- Windows NT front end to XBoard
\r
3 * $Id: winboard.c,v 2.3 2003/11/25 05:25:20 mann Exp $
5 * Copyright 1991 by Digital Equipment Corporation, Maynard, Massachusetts.
\r
6 * Enhancements Copyright 1992-2001 Free Software Foundation, Inc.
\r
8 * XBoard borrows its colors and the bitmaps.xchess bitmap set from XChess,
\r
9 * which was written and is copyrighted by Wayne Christopher.
\r
11 * The following terms apply to Digital Equipment Corporation's copyright
\r
12 * interest in XBoard:
\r
13 * ------------------------------------------------------------------------
\r
14 * All Rights Reserved
\r
16 * Permission to use, copy, modify, and distribute this software and its
\r
17 * documentation for any purpose and without fee is hereby granted,
\r
18 * provided that the above copyright notice appear in all copies and that
\r
19 * both that copyright notice and this permission notice appear in
\r
20 * supporting documentation, and that the name of Digital not be
\r
21 * used in advertising or publicity pertaining to distribution of the
\r
22 * software without specific, written prior permission.
\r
24 * DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
\r
25 * ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
\r
26 * DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
\r
27 * ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
\r
28 * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
\r
29 * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
\r
31 * ------------------------------------------------------------------------
\r
33 * The following terms apply to the enhanced version of XBoard distributed
\r
34 * by the Free Software Foundation:
\r
35 * ------------------------------------------------------------------------
\r
36 * This program is free software; you can redistribute it and/or modify
\r
37 * it under the terms of the GNU General Public License as published by
\r
38 * the Free Software Foundation; either version 2 of the License, or
\r
39 * (at your option) any later version.
\r
41 * This program is distributed in the hope that it will be useful,
\r
42 * but WITHOUT ANY WARRANTY; without even the implied warranty of
\r
43 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
\r
44 * GNU General Public License for more details.
\r
46 * You should have received a copy of the GNU General Public License
\r
47 * along with this program; if not, write to the Free Software
\r
48 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
\r
49 * ------------------------------------------------------------------------
\r
54 #include <windows.h>
\r
55 #include <winuser.h>
\r
56 #include <winsock.h>
\r
62 #include <sys/stat.h>
\r
65 #include <commdlg.h>
\r
67 #include <richedit.h>
\r
68 #include <mmsystem.h>
\r
76 #include "winboard.h"
\r
77 #include "frontend.h"
\r
78 #include "backend.h"
\r
80 #include "wclipbrd.h"
\r
81 #include "wgamelist.h"
\r
82 #include "wedittags.h"
\r
83 #include "woptions.h"
\r
84 #include "wsockerr.h"
\r
85 #include "defaults.h"
\r
88 void mysrandom(unsigned int seed);
92 POINT pos; /* window coordinates of current pos */
\r
93 POINT lastpos; /* window coordinates of last pos - used for clipping */
\r
94 POINT from; /* board coordinates of the piece's orig pos */
\r
95 POINT to; /* board coordinates of the piece's new pos */
\r
98 static AnimInfo animInfo = { EmptySquare, {-1,-1}, {-1,-1}, {-1,-1} };
\r
101 POINT start; /* window coordinates of start pos */
\r
102 POINT pos; /* window coordinates of current pos */
\r
103 POINT lastpos; /* window coordinates of last pos - used for clipping */
\r
104 POINT from; /* board coordinates of the piece's orig pos */
\r
107 static DragInfo dragInfo = { {-1,-1}, {-1,-1}, {-1,-1}, {-1,-1} };
\r
110 POINT sq[2]; /* board coordinates of from, to squares */
\r
113 static HighlightInfo highlightInfo = { {{-1, -1}, {-1, -1}} };
\r
114 static HighlightInfo premoveHighlightInfo = { {{-1, -1}, {-1, -1}} };
\r
116 /* Window class names */
\r
117 char szAppName[] = "WinBoard";
\r
118 char szConsoleName[] = "WBConsole";
\r
120 /* Title bar text */
\r
121 char szTitle[] = "WinBoard";
\r
122 char szConsoleTitle[] = "ICS Interaction";
\r
125 char *settingsFileName;
\r
126 BOOLEAN saveSettingsOnExit;
\r
127 char installDir[MSG_SIZ];
\r
129 BoardSize boardSize;
\r
130 BOOLEAN chessProgram;
\r
131 static int boardX, boardY, consoleX, consoleY, consoleW, consoleH;
\r
132 static int squareSize, lineGap;
\r
133 static int winWidth, winHeight;
\r
134 static RECT messageRect, whiteRect, blackRect;
\r
135 static char messageText[MESSAGE_TEXT_MAX];
\r
136 static int clockTimerEvent = 0;
\r
137 static int loadGameTimerEvent = 0;
\r
138 static int analysisTimerEvent = 0;
\r
139 static DelayedEventCallback delayedTimerCallback;
\r
140 static int delayedTimerEvent = 0;
\r
141 static int buttonCount = 2;
\r
142 char *icsTextMenuString;
\r
144 char *firstChessProgramNames;
\r
145 char *secondChessProgramNames;
\r
147 #define ARG_MAX 64*1024 /* [AS] For Roger Brown's very long list! */
149 #define PALETTESIZE 256
\r
151 HINSTANCE hInst; /* current instance */
\r
152 HWND hwndMain = NULL; /* root window*/
\r
153 HWND hwndConsole = NULL;
\r
154 BOOLEAN alwaysOnTop = FALSE;
\r
156 COLORREF lightSquareColor, darkSquareColor, whitePieceColor,
\r
157 blackPieceColor, highlightSquareColor, premoveHighlightColor;
\r
159 ColorClass currentColorClass;
\r
161 HWND hCommPort = NULL; /* currently open comm port */
\r
162 static HWND hwndPause; /* pause button */
\r
163 static HBITMAP pieceBitmap[3][(int) WhiteKing + 1];
\r
164 static HBRUSH lightSquareBrush, darkSquareBrush,
\r
165 whitePieceBrush, blackPieceBrush, iconBkgndBrush, outlineBrush;
\r
166 static POINT gridEndpoints[(BOARD_SIZE + 1) * 4];
\r
167 static DWORD gridVertexCounts[(BOARD_SIZE + 1) * 2];
\r
168 static HPEN gridPen = NULL;
\r
169 static HPEN highlightPen = NULL;
\r
170 static HPEN premovePen = NULL;
\r
171 static NPLOGPALETTE pLogPal;
\r
172 static BOOL paletteChanged = FALSE;
\r
173 static HICON iconWhite, iconBlack, iconCurrent;
\r
174 static int doingSizing = FALSE;
\r
175 static int lastSizing = 0;
\r
176 static int prevStderrPort;
\r
178 /* [AS] Support for background textures */
179 #define BACK_TEXTURE_MODE_DISABLED 0
180 #define BACK_TEXTURE_MODE_PLAIN 1
181 #define BACK_TEXTURE_MODE_FULL_RANDOM 2
183 static HBITMAP liteBackTexture = NULL;
184 static HBITMAP darkBackTexture = NULL;
185 static int liteBackTextureMode = BACK_TEXTURE_MODE_PLAIN;
186 static int darkBackTextureMode = BACK_TEXTURE_MODE_PLAIN;
187 static int backTextureSquareSize = 0;
188 static struct { int x; int y; int mode; } backTextureSquareInfo[BOARD_SIZE][BOARD_SIZE];
190 #if __GNUC__ && !defined(_winmajor)
\r
191 #define oldDialog 0 /* cygwin doesn't define _winmajor; mingw does */
\r
193 #define oldDialog (_winmajor < 4)
\r
196 char *defaultTextAttribs[] =
\r
198 COLOR_SHOUT, COLOR_SSHOUT, COLOR_CHANNEL1, COLOR_CHANNEL, COLOR_KIBITZ,
\r
199 COLOR_TELL, COLOR_CHALLENGE, COLOR_REQUEST, COLOR_SEEK, COLOR_NORMAL,
\r
209 int cliWidth, cliHeight;
\r
212 SizeInfo sizeInfo[] =
\r
214 { "tiny", 21, 0, 1, 1, 0, 0 },
\r
215 { "teeny", 25, 1, 1, 1, 0, 0 },
\r
216 { "dinky", 29, 1, 1, 1, 0, 0 },
\r
217 { "petite", 33, 1, 1, 1, 0, 0 },
\r
218 { "slim", 37, 2, 1, 0, 0, 0 },
\r
219 { "small", 40, 2, 1, 0, 0, 0 },
\r
220 { "mediocre", 45, 2, 1, 0, 0, 0 },
\r
221 { "middling", 49, 2, 0, 0, 0, 0 },
\r
222 { "average", 54, 2, 0, 0, 0, 0 },
\r
223 { "moderate", 58, 3, 0, 0, 0, 0 },
\r
224 { "medium", 64, 3, 0, 0, 0, 0 },
\r
225 { "bulky", 72, 3, 0, 0, 0, 0 },
\r
226 { "large", 80, 3, 0, 0, 0, 0 },
\r
227 { "big", 87, 3, 0, 0, 0, 0 },
\r
228 { "huge", 95, 3, 0, 0, 0, 0 },
\r
229 { "giant", 108, 3, 0, 0, 0, 0 },
\r
230 { "colossal", 116, 4, 0, 0, 0, 0 },
\r
231 { "titanic", 129, 4, 0, 0, 0, 0 },
\r
232 { NULL, 0, 0, 0, 0, 0, 0 }
\r
235 #define MF(x) {x, {0, }, {0, }, 0}
\r
236 MyFont fontRec[NUM_SIZES][NUM_FONTS] =
\r
238 { MF(CLOCK_FONT_TINY), MF(MESSAGE_FONT_TINY),
\r
239 MF(COORD_FONT_TINY), MF(CONSOLE_FONT_TINY),
\r
240 MF(COMMENT_FONT_TINY), MF(EDITTAGS_FONT_TINY) },
\r
241 { MF(CLOCK_FONT_TEENY), MF(MESSAGE_FONT_TEENY),
\r
242 MF(COORD_FONT_TEENY), MF(CONSOLE_FONT_TEENY),
\r
243 MF(COMMENT_FONT_TEENY), MF(EDITTAGS_FONT_TEENY) },
\r
244 { MF(CLOCK_FONT_DINKY), MF(MESSAGE_FONT_DINKY),
\r
245 MF(COORD_FONT_DINKY), MF(CONSOLE_FONT_DINKY),
\r
246 MF(COMMENT_FONT_DINKY), MF(EDITTAGS_FONT_DINKY) },
\r
247 { MF(CLOCK_FONT_PETITE), MF(MESSAGE_FONT_PETITE),
\r
248 MF(COORD_FONT_PETITE), MF(CONSOLE_FONT_PETITE),
\r
249 MF(COMMENT_FONT_PETITE), MF(EDITTAGS_FONT_PETITE) },
\r
250 { MF(CLOCK_FONT_SLIM), MF(MESSAGE_FONT_SLIM),
\r
251 MF(COORD_FONT_SLIM), MF(CONSOLE_FONT_SLIM),
\r
252 MF(COMMENT_FONT_SLIM), MF(EDITTAGS_FONT_SLIM) },
\r
253 { MF(CLOCK_FONT_SMALL), MF(MESSAGE_FONT_SMALL),
\r
254 MF(COORD_FONT_SMALL), MF(CONSOLE_FONT_SMALL),
\r
255 MF(COMMENT_FONT_SMALL), MF(EDITTAGS_FONT_SMALL) },
\r
256 { MF(CLOCK_FONT_MEDIOCRE), MF(MESSAGE_FONT_MEDIOCRE),
\r
257 MF(COORD_FONT_MEDIOCRE), MF(CONSOLE_FONT_MEDIOCRE),
\r
258 MF(COMMENT_FONT_MEDIOCRE), MF(EDITTAGS_FONT_MEDIOCRE) },
\r
259 { MF(CLOCK_FONT_MIDDLING), MF(MESSAGE_FONT_MIDDLING),
\r
260 MF(COORD_FONT_MIDDLING), MF(CONSOLE_FONT_MIDDLING),
\r
261 MF(COMMENT_FONT_MIDDLING), MF(EDITTAGS_FONT_MIDDLING) },
\r
262 { MF(CLOCK_FONT_AVERAGE), MF(MESSAGE_FONT_AVERAGE),
\r
263 MF(COORD_FONT_AVERAGE), MF(CONSOLE_FONT_AVERAGE),
\r
264 MF(COMMENT_FONT_AVERAGE), MF(EDITTAGS_FONT_AVERAGE) },
\r
265 { MF(CLOCK_FONT_MODERATE), MF(MESSAGE_FONT_MODERATE),
\r
266 MF(COORD_FONT_MODERATE), MF(CONSOLE_FONT_MODERATE),
\r
267 MF(COMMENT_FONT_MODERATE), MF(EDITTAGS_FONT_MODERATE) },
\r
268 { MF(CLOCK_FONT_MEDIUM), MF(MESSAGE_FONT_MEDIUM),
\r
269 MF(COORD_FONT_MEDIUM), MF(CONSOLE_FONT_MEDIUM),
\r
270 MF(COMMENT_FONT_MEDIUM), MF(EDITTAGS_FONT_MEDIUM) },
\r
271 { MF(CLOCK_FONT_BULKY), MF(MESSAGE_FONT_BULKY),
\r
272 MF(COORD_FONT_BULKY), MF(CONSOLE_FONT_BULKY),
\r
273 MF(COMMENT_FONT_BULKY), MF(EDITTAGS_FONT_BULKY) },
\r
274 { MF(CLOCK_FONT_LARGE), MF(MESSAGE_FONT_LARGE),
\r
275 MF(COORD_FONT_LARGE), MF(CONSOLE_FONT_LARGE),
\r
276 MF(COMMENT_FONT_LARGE), MF(EDITTAGS_FONT_LARGE) },
\r
277 { MF(CLOCK_FONT_BIG), MF(MESSAGE_FONT_BIG),
\r
278 MF(COORD_FONT_BIG), MF(CONSOLE_FONT_BIG),
\r
279 MF(COMMENT_FONT_BIG), MF(EDITTAGS_FONT_BIG) },
\r
280 { MF(CLOCK_FONT_HUGE), MF(MESSAGE_FONT_HUGE),
\r
281 MF(COORD_FONT_HUGE), MF(CONSOLE_FONT_HUGE),
\r
282 MF(COMMENT_FONT_HUGE), MF(EDITTAGS_FONT_HUGE) },
\r
283 { MF(CLOCK_FONT_GIANT), MF(MESSAGE_FONT_GIANT),
\r
284 MF(COORD_FONT_GIANT), MF(CONSOLE_FONT_GIANT),
\r
285 MF(COMMENT_FONT_GIANT), MF(EDITTAGS_FONT_GIANT) },
\r
286 { MF(CLOCK_FONT_COLOSSAL), MF(MESSAGE_FONT_COLOSSAL),
\r
287 MF(COORD_FONT_COLOSSAL), MF(CONSOLE_FONT_COLOSSAL),
\r
288 MF(COMMENT_FONT_COLOSSAL), MF(EDITTAGS_FONT_COLOSSAL) },
\r
289 { MF(CLOCK_FONT_TITANIC), MF(MESSAGE_FONT_TITANIC),
\r
290 MF(COORD_FONT_TITANIC), MF(CONSOLE_FONT_TITANIC),
\r
291 MF(COMMENT_FONT_TITANIC), MF(EDITTAGS_FONT_TITANIC) },
\r
294 MyFont *font[NUM_SIZES][NUM_FONTS];
\r
303 #define BUTTON_WIDTH (tinyLayout ? 16 : 32)
\r
304 #define N_BUTTONS 5
\r
306 MyButtonDesc buttonDesc[N_BUTTONS] =
\r
308 {"<<", IDM_ToStart, NULL, NULL},
\r
309 {"<", IDM_Backward, NULL, NULL},
\r
310 {"P", IDM_Pause, NULL, NULL},
\r
311 {">", IDM_Forward, NULL, NULL},
\r
312 {">>", IDM_ToEnd, NULL, NULL},
\r
315 int tinyLayout = 0, smallLayout = 0;
\r
316 #define MENU_BAR_ITEMS 6
\r
317 char *menuBarText[2][MENU_BAR_ITEMS+1] = {
\r
318 { "&File", "&Mode", "&Action", "&Step", "&Options", "&Help", NULL },
\r
319 { "&F", "&M", "&A", "&S", "&O", "&H", NULL },
\r
323 MySound sounds[(int)NSoundClasses];
\r
324 MyTextAttribs textAttribs[(int)NColorClasses];
\r
326 MyColorizeAttribs colorizeAttribs[] = {
\r
327 { (COLORREF)0, 0, "Shout Text" },
\r
328 { (COLORREF)0, 0, "SShout/CShout" },
\r
329 { (COLORREF)0, 0, "Channel 1 Text" },
\r
330 { (COLORREF)0, 0, "Channel Text" },
\r
331 { (COLORREF)0, 0, "Kibitz Text" },
\r
332 { (COLORREF)0, 0, "Tell Text" },
\r
333 { (COLORREF)0, 0, "Challenge Text" },
\r
334 { (COLORREF)0, 0, "Request Text" },
\r
335 { (COLORREF)0, 0, "Seek Text" },
\r
336 { (COLORREF)0, 0, "Normal Text" },
\r
337 { (COLORREF)0, 0, "None" }
\r
342 static char *commentTitle;
\r
343 static char *commentText;
\r
344 static int commentIndex;
\r
345 static Boolean editComment = FALSE;
\r
346 HWND commentDialog = NULL;
\r
347 BOOLEAN commentDialogUp = FALSE;
\r
348 static int commentX, commentY, commentH, commentW;
\r
350 static char *analysisTitle;
\r
351 static char *analysisText;
\r
352 HWND analysisDialog = NULL;
\r
353 BOOLEAN analysisDialogUp = FALSE;
\r
354 static int analysisX, analysisY, analysisH, analysisW;
\r
356 char errorTitle[MSG_SIZ];
\r
357 char errorMessage[2*MSG_SIZ];
\r
358 HWND errorDialog = NULL;
\r
359 BOOLEAN moveErrorMessageUp = FALSE;
\r
360 BOOLEAN consoleEcho = TRUE;
\r
361 CHARFORMAT consoleCF;
\r
362 COLORREF consoleBackgroundColor;
\r
364 char *programVersion;
\r
370 typedef int CPKind;
\r
379 SOCKET sock2; /* stderr socket for OpenRcmd */
\r
382 #define INPUT_SOURCE_BUF_SIZE 4096
\r
384 typedef struct _InputSource {
\r
391 char buf[INPUT_SOURCE_BUF_SIZE];
\r
395 InputCallback func;
\r
396 struct _InputSource *second; /* for stderr thread on CPRcmd */
\r
400 InputSource *consoleInputSource;
\r
405 VOID ConsoleOutput(char* data, int length, int forceVisible);
\r
406 VOID ConsoleCreate();
\r
408 ConsoleWndProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);
\r
409 VOID ColorizeTextPopup(HWND hwnd, ColorClass cc);
\r
410 VOID PrintCommSettings(FILE *f, char *name, DCB *dcb);
\r
411 VOID ParseCommSettings(char *arg, DCB *dcb);
\r
413 StartupDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);
\r
414 VOID APIENTRY MenuPopup(HWND hwnd, POINT pt, HMENU hmenu, UINT def);
\r
415 void ParseIcsTextMenu(char *icsTextMenuString);
\r
416 VOID PopUpMoveDialog(char firstchar);
\r
417 VOID UpdateSampleText(HWND hDlg, int id, MyColorizeAttribs *mca);
\r
421 * Setting "frozen" should disable all user input other than deleting
\r
422 * the window. We do this while engines are initializing themselves.
\r
424 static int frozen = 0;
\r
425 static int oldMenuItemState[MENU_BAR_ITEMS];
\r
431 if (frozen) return;
\r
433 hmenu = GetMenu(hwndMain);
\r
434 for (i=0; i<MENU_BAR_ITEMS; i++) {
\r
435 oldMenuItemState[i] = EnableMenuItem(hmenu, i, MF_BYPOSITION|MF_GRAYED);
\r
437 DrawMenuBar(hwndMain);
\r
440 /* Undo a FreezeUI */
\r
446 if (!frozen) return;
\r
448 hmenu = GetMenu(hwndMain);
\r
449 for (i=0; i<MENU_BAR_ITEMS; i++) {
\r
450 EnableMenuItem(hmenu, i, MF_BYPOSITION|oldMenuItemState[i]);
\r
452 DrawMenuBar(hwndMain);
\r
455 /*---------------------------------------------------------------------------*\
\r
459 \*---------------------------------------------------------------------------*/
\r
462 WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
\r
463 LPSTR lpCmdLine, int nCmdShow)
\r
466 HANDLE hAccelMain, hAccelNoAlt;
\r
470 LoadLibrary("RICHED32.DLL");
\r
471 consoleCF.cbSize = sizeof(CHARFORMAT);
\r
473 if (!InitApplication(hInstance)) {
\r
476 if (!InitInstance(hInstance, nCmdShow, lpCmdLine)) {
\r
480 hAccelMain = LoadAccelerators (hInstance, szAppName);
\r
481 hAccelNoAlt = LoadAccelerators (hInstance, "NO_ALT");
\r
483 /* Acquire and dispatch messages until a WM_QUIT message is received. */
\r
485 while (GetMessage(&msg, /* message structure */
\r
486 NULL, /* handle of window receiving the message */
\r
487 0, /* lowest message to examine */
\r
488 0)) /* highest message to examine */
\r
490 if (!(commentDialog && IsDialogMessage(commentDialog, &msg)) &&
\r
491 !(editTagsDialog && IsDialogMessage(editTagsDialog, &msg)) &&
\r
492 !(gameListDialog && IsDialogMessage(gameListDialog, &msg)) &&
\r
493 !(errorDialog && IsDialogMessage(errorDialog, &msg)) &&
\r
494 !(!frozen && TranslateAccelerator(hwndMain, hAccelMain, &msg)) &&
\r
495 !(!hwndConsole && TranslateAccelerator(hwndMain, hAccelNoAlt, &msg))) {
\r
496 TranslateMessage(&msg); /* Translates virtual key codes */
\r
497 DispatchMessage(&msg); /* Dispatches message to window */
\r
502 return (msg.wParam); /* Returns the value from PostQuitMessage */
\r
505 /*---------------------------------------------------------------------------*\
\r
507 * Initialization functions
\r
509 \*---------------------------------------------------------------------------*/
\r
512 InitApplication(HINSTANCE hInstance)
\r
516 /* Fill in window class structure with parameters that describe the */
\r
519 wc.style = CS_HREDRAW | CS_VREDRAW; /* Class style(s). */
\r
520 wc.lpfnWndProc = (WNDPROC)WndProc; /* Window Procedure */
\r
521 wc.cbClsExtra = 0; /* No per-class extra data. */
\r
522 wc.cbWndExtra = 0; /* No per-window extra data. */
\r
523 wc.hInstance = hInstance; /* Owner of this class */
\r
524 wc.hIcon = LoadIcon(hInstance, "icon_white");
\r
525 wc.hCursor = LoadCursor(NULL, IDC_ARROW); /* Cursor */
\r
526 wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1); /* Default color */
\r
527 wc.lpszMenuName = szAppName; /* Menu name from .RC */
\r
528 wc.lpszClassName = szAppName; /* Name to register as */
\r
530 /* Register the window class and return success/failure code. */
\r
531 if (!RegisterClass(&wc)) return FALSE;
\r
533 wc.style = CS_HREDRAW | CS_VREDRAW;
\r
534 wc.lpfnWndProc = (WNDPROC)ConsoleWndProc;
\r
536 wc.cbWndExtra = DLGWINDOWEXTRA;
\r
537 wc.hInstance = hInstance;
\r
538 wc.hIcon = LoadIcon(hInstance, "icon_white");
\r
539 wc.hCursor = LoadCursor(NULL, IDC_ARROW);
\r
540 wc.hbrBackground = (HBRUSH)(COLOR_MENU+1);
\r
541 wc.lpszMenuName = NULL;
\r
542 wc.lpszClassName = szConsoleName;
\r
544 if (!RegisterClass(&wc)) return FALSE;
\r
549 /* Set by InitInstance, used by EnsureOnScreen */
\r
550 int screenHeight, screenWidth;
\r
553 EnsureOnScreen(int *x, int *y)
\r
555 /* Be sure window at (x,y) is not off screen (or even mostly off screen) */
\r
556 if (*x > screenWidth - 32) *x = 0;
\r
557 if (*y > screenHeight - 32) *y = 0;
\r
561 InitInstance(HINSTANCE hInstance, int nCmdShow, LPSTR lpCmdLine)
\r
563 HWND hwnd; /* Main window handle. */
\r
565 WINDOWPLACEMENT wp;
\r
568 hInst = hInstance; /* Store instance handle in our global variable */
\r
570 if (SearchPath(NULL, "WinBoard.exe", NULL, MSG_SIZ, installDir, &filepart)) {
\r
571 *filepart = NULLCHAR;
\r
573 GetCurrentDirectory(MSG_SIZ, installDir);
\r
575 InitAppData(lpCmdLine); /* Get run-time parameters */
\r
576 if (appData.debugMode) {
\r
577 debugFP = fopen(appData.nameOfDebugFile, "w");
578 setbuf(debugFP, NULL);
\r
583 /* Create a main window for this application instance. */
\r
584 hwnd = CreateWindow(szAppName, szTitle,
\r
585 (WS_OVERLAPPEDWINDOW & ~WS_MAXIMIZEBOX),
\r
586 CW_USEDEFAULT, 0, CW_USEDEFAULT, 0,
\r
587 NULL, NULL, hInstance, NULL);
\r
590 /* If window could not be created, return "failure" */
\r
595 iconWhite = LoadIcon(hInstance, "icon_white");
\r
596 iconBlack = LoadIcon(hInstance, "icon_black");
\r
597 iconCurrent = iconWhite;
\r
598 InitDrawingColors();
\r
599 screenHeight = GetSystemMetrics(SM_CYSCREEN);
\r
600 screenWidth = GetSystemMetrics(SM_CXSCREEN);
\r
601 for (ibs = (int) NUM_SIZES - 1; ibs >= 0; ibs--) {
\r
602 /* Compute window size for each board size, and use the largest
\r
603 size that fits on this screen as the default. */
\r
604 InitDrawingSizes((BoardSize)ibs, 0);
\r
605 if (boardSize == (BoardSize)-1 &&
\r
606 winHeight <= screenHeight && winWidth <= screenWidth) {
\r
607 boardSize = (BoardSize)ibs;
\r
610 InitDrawingSizes(boardSize, 0);
\r
612 buttonCount = GetSystemMetrics(SM_CMOUSEBUTTONS);
\r
614 /* [AS] Load textures if specified */
615 ZeroMemory( &backTextureSquareInfo, sizeof(backTextureSquareInfo) );
617 if( appData.liteBackTextureFile && appData.liteBackTextureFile[0] != NULLCHAR && appData.liteBackTextureFile[0] != '*' ) {
618 liteBackTexture = LoadImage( 0, appData.liteBackTextureFile, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
619 liteBackTextureMode = appData.liteBackTextureMode;
621 if (liteBackTexture == NULL && appData.debugMode) {
622 fprintf( debugFP, "Unable to load lite texture bitmap '%s'\n", appData.liteBackTextureFile );
626 if( appData.darkBackTextureFile && appData.darkBackTextureFile[0] != NULLCHAR && appData.darkBackTextureFile[0] != '*' ) {
627 darkBackTexture = LoadImage( 0, appData.darkBackTextureFile, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
628 darkBackTextureMode = appData.darkBackTextureMode;
630 if (darkBackTexture == NULL && appData.debugMode) {
631 fprintf( debugFP, "Unable to load dark texture bitmap '%s'\n", appData.darkBackTextureFile );
635 mysrandom( (unsigned) time(NULL) );
637 /* Make a console window if needed */
\r
638 if (appData.icsActive) {
\r
644 /* Make the window visible; update its client area; and return "success" */
\r
645 EnsureOnScreen(&boardX, &boardY);
\r
646 wp.length = sizeof(WINDOWPLACEMENT);
\r
648 wp.showCmd = nCmdShow;
\r
649 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
650 wp.rcNormalPosition.left = boardX;
\r
651 wp.rcNormalPosition.right = boardX + winWidth;
\r
652 wp.rcNormalPosition.top = boardY;
\r
653 wp.rcNormalPosition.bottom = boardY + winHeight;
\r
654 SetWindowPlacement(hwndMain, &wp);
\r
656 SetWindowPos(hwndMain, alwaysOnTop ? HWND_TOPMOST : HWND_NOTOPMOST,
\r
657 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE);
\r
659 /* [AS] Disable the FRC stuff if not playing the proper variant */
660 if( gameInfo.variant != VariantFischeRandom ) {
661 EnableMenuItem( GetMenu(hwndMain), IDM_NewGameFRC, MF_GRAYED );
666 SetWindowPos(hwndConsole, alwaysOnTop ? HWND_TOPMOST : HWND_NOTOPMOST,
\r
667 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE);
\r
669 ShowWindow(hwndConsole, nCmdShow);
\r
671 UpdateWindow(hwnd);
\r
679 ArgString, ArgInt, ArgFloat, ArgBoolean, ArgTrue, ArgFalse, ArgNone,
\r
680 ArgColor, ArgAttribs, ArgFilename, ArgBoardSize, ArgFont, ArgCommSettings,
\r
681 ArgSettingsFilename
\r
689 String *pString; // ArgString
\r
690 int *pInt; // ArgInt
\r
691 float *pFloat; // ArgFloat
\r
692 Boolean *pBoolean; // ArgBoolean
\r
693 COLORREF *pColor; // ArgColor
\r
694 ColorClass cc; // ArgAttribs
\r
695 String *pFilename; // ArgFilename
\r
696 BoardSize *pBoardSize; // ArgBoardSize
\r
697 int whichFont; // ArgFont
\r
698 DCB *pDCB; // ArgCommSettings
\r
699 String *pFilename; // ArgSettingsFilename
\r
707 ArgDescriptor argDescriptors[] = {
\r
708 /* positional arguments */
\r
709 { "loadGameFile", ArgFilename, (LPVOID) &appData.loadGameFile, FALSE },
\r
710 { "", ArgNone, NULL },
\r
711 /* keyword arguments */
\r
712 { "whitePieceColor", ArgColor, (LPVOID) &whitePieceColor, TRUE },
\r
713 { "wpc", ArgColor, (LPVOID) &whitePieceColor, FALSE },
\r
714 { "blackPieceColor", ArgColor, (LPVOID) &blackPieceColor, TRUE },
\r
715 { "bpc", ArgColor, (LPVOID) &blackPieceColor, FALSE },
\r
716 { "lightSquareColor", ArgColor, (LPVOID) &lightSquareColor, TRUE },
\r
717 { "lsc", ArgColor, (LPVOID) &lightSquareColor, FALSE },
\r
718 { "darkSquareColor", ArgColor, (LPVOID) &darkSquareColor, TRUE },
\r
719 { "dsc", ArgColor, (LPVOID) &darkSquareColor, FALSE },
\r
720 { "highlightSquareColor", ArgColor, (LPVOID) &highlightSquareColor, TRUE },
\r
721 { "hsc", ArgColor, (LPVOID) &highlightSquareColor, FALSE },
\r
722 { "premoveHighlightColor", ArgColor, (LPVOID) &premoveHighlightColor, TRUE },
\r
723 { "phc", ArgColor, (LPVOID) &premoveHighlightColor, FALSE },
\r
724 { "movesPerSession", ArgInt, (LPVOID) &appData.movesPerSession, TRUE },
\r
725 { "mps", ArgInt, (LPVOID) &appData.movesPerSession, FALSE },
\r
726 { "initString", ArgString, (LPVOID) &appData.initString, FALSE },
\r
727 { "firstInitString", ArgString, (LPVOID) &appData.initString, FALSE },
\r
728 { "secondInitString", ArgString, (LPVOID) &appData.secondInitString, FALSE },
\r
729 { "firstComputerString", ArgString, (LPVOID) &appData.firstComputerString,
\r
731 { "secondComputerString", ArgString, (LPVOID) &appData.secondComputerString,
\r
733 { "firstChessProgram", ArgFilename, (LPVOID) &appData.firstChessProgram,
\r
735 { "fcp", ArgFilename, (LPVOID) &appData.firstChessProgram, FALSE },
\r
736 { "secondChessProgram", ArgFilename, (LPVOID) &appData.secondChessProgram,
\r
738 { "scp", ArgFilename, (LPVOID) &appData.secondChessProgram, FALSE },
\r
739 { "firstPlaysBlack", ArgBoolean, (LPVOID) &appData.firstPlaysBlack, FALSE },
\r
740 { "fb", ArgTrue, (LPVOID) &appData.firstPlaysBlack, FALSE },
\r
741 { "xfb", ArgFalse, (LPVOID) &appData.firstPlaysBlack, FALSE },
\r
742 { "-fb", ArgFalse, (LPVOID) &appData.firstPlaysBlack, FALSE },
\r
743 { "noChessProgram", ArgBoolean, (LPVOID) &appData.noChessProgram, FALSE },
\r
744 { "ncp", ArgTrue, (LPVOID) &appData.noChessProgram, FALSE },
\r
745 { "xncp", ArgFalse, (LPVOID) &appData.noChessProgram, FALSE },
\r
746 { "-ncp", ArgFalse, (LPVOID) &appData.noChessProgram, FALSE },
\r
747 { "firstHost", ArgString, (LPVOID) &appData.firstHost, FALSE },
\r
748 { "fh", ArgString, (LPVOID) &appData.firstHost, FALSE },
\r
749 { "secondHost", ArgString, (LPVOID) &appData.secondHost, FALSE },
\r
750 { "sh", ArgString, (LPVOID) &appData.secondHost, FALSE },
\r
751 { "firstDirectory", ArgFilename, (LPVOID) &appData.firstDirectory, FALSE },
\r
752 { "fd", ArgFilename, (LPVOID) &appData.firstDirectory, FALSE },
\r
753 { "secondDirectory", ArgFilename, (LPVOID) &appData.secondDirectory, FALSE },
\r
754 { "sd", ArgFilename, (LPVOID) &appData.secondDirectory, FALSE },
\r
755 /*!!bitmapDirectory?*/
\r
756 { "remoteShell", ArgFilename, (LPVOID) &appData.remoteShell, FALSE },
\r
757 { "rsh", ArgFilename, (LPVOID) &appData.remoteShell, FALSE },
\r
758 { "remoteUser", ArgString, (LPVOID) &appData.remoteUser, FALSE },
\r
759 { "ruser", ArgString, (LPVOID) &appData.remoteUser, FALSE },
\r
760 { "timeDelay", ArgFloat, (LPVOID) &appData.timeDelay, TRUE },
\r
761 { "td", ArgFloat, (LPVOID) &appData.timeDelay, FALSE },
\r
762 { "timeControl", ArgString, (LPVOID) &appData.timeControl, TRUE },
\r
763 { "tc", ArgString, (LPVOID) &appData.timeControl, FALSE },
\r
764 { "timeIncrement", ArgInt, (LPVOID) &appData.timeIncrement, TRUE },
\r
765 { "inc", ArgInt, (LPVOID) &appData.timeIncrement, FALSE },
\r
766 { "internetChessServerMode", ArgBoolean, (LPVOID) &appData.icsActive, FALSE },
\r
767 { "ics", ArgTrue, (LPVOID) &appData.icsActive, FALSE },
\r
768 { "xics", ArgFalse, (LPVOID) &appData.icsActive, FALSE },
\r
769 { "-ics", ArgFalse, (LPVOID) &appData.icsActive, FALSE },
\r
770 { "internetChessServerHost", ArgString, (LPVOID) &appData.icsHost, FALSE },
\r
771 { "icshost", ArgString, (LPVOID) &appData.icsHost, FALSE },
\r
772 { "internetChessServerPort", ArgString, (LPVOID) &appData.icsPort, FALSE },
\r
773 { "icsport", ArgString, (LPVOID) &appData.icsPort, FALSE },
\r
774 { "internetChessServerCommPort", ArgString, (LPVOID) &appData.icsCommPort, FALSE },
\r
775 { "icscomm", ArgString, (LPVOID) &appData.icsCommPort, FALSE },
\r
776 { "internetChessServerComPort", ArgString, (LPVOID) &appData.icsCommPort, FALSE },
\r
777 { "icscom", ArgString, (LPVOID) &appData.icsCommPort, FALSE },
\r
778 { "internetChessServerLogonScript", ArgFilename, (LPVOID) &appData.icsLogon, FALSE },
\r
779 { "icslogon", ArgFilename, (LPVOID) &appData.icsLogon, FALSE },
\r
780 { "useTelnet", ArgBoolean, (LPVOID) &appData.useTelnet, FALSE },
\r
781 { "telnet", ArgTrue, (LPVOID) &appData.useTelnet, FALSE },
\r
782 { "xtelnet", ArgFalse, (LPVOID) &appData.useTelnet, FALSE },
\r
783 { "-telnet", ArgFalse, (LPVOID) &appData.useTelnet, FALSE },
\r
784 { "telnetProgram", ArgFilename, (LPVOID) &appData.telnetProgram, FALSE },
\r
785 { "icshelper", ArgFilename, (LPVOID) &appData.icsHelper, FALSE },
\r
786 { "gateway", ArgString, (LPVOID) &appData.gateway, FALSE },
\r
787 { "loadGameFile", ArgFilename, (LPVOID) &appData.loadGameFile, FALSE },
\r
788 { "lgf", ArgFilename, (LPVOID) &appData.loadGameFile, FALSE },
\r
789 { "loadGameIndex", ArgInt, (LPVOID) &appData.loadGameIndex, FALSE },
\r
790 { "lgi", ArgInt, (LPVOID) &appData.loadGameIndex, FALSE },
\r
791 { "saveGameFile", ArgFilename, (LPVOID) &appData.saveGameFile, TRUE },
\r
792 { "sgf", ArgFilename, (LPVOID) &appData.saveGameFile, FALSE },
\r
793 { "autoSaveGames", ArgBoolean, (LPVOID) &appData.autoSaveGames, TRUE },
\r
794 { "autosave", ArgTrue, (LPVOID) &appData.autoSaveGames, FALSE },
\r
795 { "xautosave", ArgFalse, (LPVOID) &appData.autoSaveGames, FALSE },
\r
796 { "-autosave", ArgFalse, (LPVOID) &appData.autoSaveGames, FALSE },
\r
797 { "loadPositionFile", ArgFilename, (LPVOID) &appData.loadPositionFile, FALSE },
\r
798 { "lpf", ArgFilename, (LPVOID) &appData.loadPositionFile, FALSE },
\r
799 { "loadPositionIndex", ArgInt, (LPVOID) &appData.loadPositionIndex, FALSE },
\r
800 { "lpi", ArgInt, (LPVOID) &appData.loadPositionIndex, FALSE },
\r
801 { "savePositionFile", ArgFilename, (LPVOID) &appData.savePositionFile, FALSE },
\r
802 { "spf", ArgFilename, (LPVOID) &appData.savePositionFile, FALSE },
\r
803 { "matchMode", ArgBoolean, (LPVOID) &appData.matchMode, FALSE },
\r
804 { "mm", ArgTrue, (LPVOID) &appData.matchMode, FALSE },
\r
805 { "xmm", ArgFalse, (LPVOID) &appData.matchMode, FALSE },
\r
806 { "-mm", ArgFalse, (LPVOID) &appData.matchMode, FALSE },
\r
807 { "matchGames", ArgInt, (LPVOID) &appData.matchGames, FALSE },
\r
808 { "mg", ArgInt, (LPVOID) &appData.matchGames, FALSE },
\r
809 { "monoMode", ArgBoolean, (LPVOID) &appData.monoMode, TRUE },
\r
810 { "mono", ArgTrue, (LPVOID) &appData.monoMode, FALSE },
\r
811 { "xmono", ArgFalse, (LPVOID) &appData.monoMode, FALSE },
\r
812 { "-mono", ArgFalse, (LPVOID) &appData.monoMode, FALSE },
\r
813 { "debugMode", ArgBoolean, (LPVOID) &appData.debugMode, FALSE },
\r
814 { "debug", ArgTrue, (LPVOID) &appData.debugMode, FALSE },
\r
815 { "xdebug", ArgFalse, (LPVOID) &appData.debugMode, FALSE },
\r
816 { "-debug", ArgFalse, (LPVOID) &appData.debugMode, FALSE },
\r
817 { "clockMode", ArgBoolean, (LPVOID) &appData.clockMode, FALSE },
\r
818 { "clock", ArgTrue, (LPVOID) &appData.clockMode, FALSE },
\r
819 { "xclock", ArgFalse, (LPVOID) &appData.clockMode, FALSE },
\r
820 { "-clock", ArgFalse, (LPVOID) &appData.clockMode, FALSE },
\r
821 { "searchTime", ArgString, (LPVOID) &appData.searchTime, FALSE },
\r
822 { "st", ArgString, (LPVOID) &appData.searchTime, FALSE },
\r
823 { "searchDepth", ArgInt, (LPVOID) &appData.searchDepth, FALSE },
\r
824 { "depth", ArgInt, (LPVOID) &appData.searchDepth, FALSE },
\r
825 { "showCoords", ArgBoolean, (LPVOID) &appData.showCoords, TRUE },
\r
826 { "coords", ArgTrue, (LPVOID) &appData.showCoords, FALSE },
\r
827 { "xcoords", ArgFalse, (LPVOID) &appData.showCoords, FALSE },
\r
828 { "-coords", ArgFalse, (LPVOID) &appData.showCoords, FALSE },
\r
829 { "showThinking", ArgBoolean, (LPVOID) &appData.showThinking, TRUE },
\r
830 { "thinking", ArgTrue, (LPVOID) &appData.showThinking, FALSE },
\r
831 { "xthinking", ArgFalse, (LPVOID) &appData.showThinking, FALSE },
\r
832 { "-thinking", ArgFalse, (LPVOID) &appData.showThinking, FALSE },
\r
833 { "ponderNextMove", ArgBoolean, (LPVOID) &appData.ponderNextMove, TRUE },
\r
834 { "ponder", ArgTrue, (LPVOID) &appData.ponderNextMove, FALSE },
\r
835 { "xponder", ArgFalse, (LPVOID) &appData.ponderNextMove, FALSE },
\r
836 { "-ponder", ArgFalse, (LPVOID) &appData.ponderNextMove, FALSE },
\r
837 { "periodicUpdates", ArgBoolean, (LPVOID) &appData.periodicUpdates, TRUE },
\r
838 { "periodic", ArgTrue, (LPVOID) &appData.periodicUpdates, FALSE },
\r
839 { "xperiodic", ArgFalse, (LPVOID) &appData.periodicUpdates, FALSE },
\r
840 { "-periodic", ArgFalse, (LPVOID) &appData.periodicUpdates, FALSE },
\r
841 { "popupExitMessage", ArgBoolean, (LPVOID) &appData.popupExitMessage, TRUE },
\r
842 { "exit", ArgTrue, (LPVOID) &appData.popupExitMessage, FALSE },
\r
843 { "xexit", ArgFalse, (LPVOID) &appData.popupExitMessage, FALSE },
\r
844 { "-exit", ArgFalse, (LPVOID) &appData.popupExitMessage, FALSE },
\r
845 { "popupMoveErrors", ArgBoolean, (LPVOID) &appData.popupMoveErrors, TRUE },
\r
846 { "popup", ArgTrue, (LPVOID) &appData.popupMoveErrors, FALSE },
\r
847 { "xpopup", ArgFalse, (LPVOID) &appData.popupMoveErrors, FALSE },
\r
848 { "-popup", ArgFalse, (LPVOID) &appData.popupMoveErrors, FALSE },
\r
849 { "popUpErrors", ArgBoolean, (LPVOID) &appData.popupMoveErrors,
\r
850 FALSE }, /* only so that old WinBoard.ini files from betas can be read */
\r
851 { "clockFont", ArgFont, (LPVOID) CLOCK_FONT, TRUE },
\r
852 { "messageFont", ArgFont, (LPVOID) MESSAGE_FONT, TRUE },
\r
853 { "coordFont", ArgFont, (LPVOID) COORD_FONT, TRUE },
\r
854 { "tagsFont", ArgFont, (LPVOID) EDITTAGS_FONT, TRUE },
\r
855 { "commentFont", ArgFont, (LPVOID) COMMENT_FONT, TRUE },
\r
856 { "icsFont", ArgFont, (LPVOID) CONSOLE_FONT, TRUE },
\r
857 { "boardSize", ArgBoardSize, (LPVOID) &boardSize,
\r
858 TRUE }, /* must come after all fonts */
\r
859 { "size", ArgBoardSize, (LPVOID) &boardSize, FALSE },
\r
860 { "ringBellAfterMoves", ArgBoolean, (LPVOID) &appData.ringBellAfterMoves,
\r
861 FALSE }, /* historical; kept only so old winboard.ini files will parse */
\r
862 { "alwaysOnTop", ArgBoolean, (LPVOID) &alwaysOnTop, TRUE },
\r
863 { "top", ArgTrue, (LPVOID) &alwaysOnTop, FALSE },
\r
864 { "xtop", ArgFalse, (LPVOID) &alwaysOnTop, FALSE },
\r
865 { "-top", ArgFalse, (LPVOID) &alwaysOnTop, FALSE },
\r
866 { "autoCallFlag", ArgBoolean, (LPVOID) &appData.autoCallFlag, TRUE },
\r
867 { "autoflag", ArgTrue, (LPVOID) &appData.autoCallFlag, FALSE },
\r
868 { "xautoflag", ArgFalse, (LPVOID) &appData.autoCallFlag, FALSE },
\r
869 { "-autoflag", ArgFalse, (LPVOID) &appData.autoCallFlag, FALSE },
\r
870 { "autoComment", ArgBoolean, (LPVOID) &appData.autoComment, TRUE },
\r
871 { "autocomm", ArgTrue, (LPVOID) &appData.autoComment, FALSE },
\r
872 { "xautocomm", ArgFalse, (LPVOID) &appData.autoComment, FALSE },
\r
873 { "-autocomm", ArgFalse, (LPVOID) &appData.autoComment, FALSE },
\r
874 { "autoObserve", ArgBoolean, (LPVOID) &appData.autoObserve, TRUE },
\r
875 { "autobs", ArgTrue, (LPVOID) &appData.autoObserve, FALSE },
\r
876 { "xautobs", ArgFalse, (LPVOID) &appData.autoObserve, FALSE },
\r
877 { "-autobs", ArgFalse, (LPVOID) &appData.autoObserve, FALSE },
\r
878 { "flipView", ArgBoolean, (LPVOID) &appData.flipView, FALSE },
\r
879 { "flip", ArgTrue, (LPVOID) &appData.flipView, FALSE },
\r
880 { "xflip", ArgFalse, (LPVOID) &appData.flipView, FALSE },
\r
881 { "-flip", ArgFalse, (LPVOID) &appData.flipView, FALSE },
\r
882 { "autoFlipView", ArgBoolean, (LPVOID) &appData.autoFlipView, TRUE },
\r
883 { "autoflip", ArgTrue, (LPVOID) &appData.autoFlipView, FALSE },
\r
884 { "xautoflip", ArgFalse, (LPVOID) &appData.autoFlipView, FALSE },
\r
885 { "-autoflip", ArgFalse, (LPVOID) &appData.autoFlipView, FALSE },
\r
886 { "autoRaiseBoard", ArgBoolean, (LPVOID) &appData.autoRaiseBoard, TRUE },
\r
887 { "autoraise", ArgTrue, (LPVOID) &appData.autoRaiseBoard, FALSE },
\r
888 { "xautoraise", ArgFalse, (LPVOID) &appData.autoRaiseBoard, FALSE },
\r
889 { "-autoraise", ArgFalse, (LPVOID) &appData.autoRaiseBoard, FALSE },
\r
891 { "cmailGameName", ArgString, (LPVOID) &appData.cmailGameName, FALSE },
\r
892 { "cmail", ArgString, (LPVOID) &appData.cmailGameName, FALSE },
\r
894 { "alwaysPromoteToQueen", ArgBoolean, (LPVOID) &appData.alwaysPromoteToQueen, TRUE },
\r
895 { "queen", ArgTrue, (LPVOID) &appData.alwaysPromoteToQueen, FALSE },
\r
896 { "xqueen", ArgFalse, (LPVOID) &appData.alwaysPromoteToQueen, FALSE },
\r
897 { "-queen", ArgFalse, (LPVOID) &appData.alwaysPromoteToQueen, FALSE },
\r
898 { "oldSaveStyle", ArgBoolean, (LPVOID) &appData.oldSaveStyle, TRUE },
\r
899 { "oldsave", ArgTrue, (LPVOID) &appData.oldSaveStyle, FALSE },
\r
900 { "xoldsave", ArgFalse, (LPVOID) &appData.oldSaveStyle, FALSE },
\r
901 { "-oldsave", ArgFalse, (LPVOID) &appData.oldSaveStyle, FALSE },
\r
902 { "quietPlay", ArgBoolean, (LPVOID) &appData.quietPlay, TRUE },
\r
903 { "quiet", ArgTrue, (LPVOID) &appData.quietPlay, FALSE },
\r
904 { "xquiet", ArgFalse, (LPVOID) &appData.quietPlay, FALSE },
\r
905 { "-quiet", ArgFalse, (LPVOID) &appData.quietPlay, FALSE },
\r
906 { "getMoveList", ArgBoolean, (LPVOID) &appData.getMoveList, TRUE },
\r
907 { "moves", ArgTrue, (LPVOID) &appData.getMoveList, FALSE },
\r
908 { "xmoves", ArgFalse, (LPVOID) &appData.getMoveList, FALSE },
\r
909 { "-moves", ArgFalse, (LPVOID) &appData.getMoveList, FALSE },
\r
910 { "testLegality", ArgBoolean, (LPVOID) &appData.testLegality, TRUE },
\r
911 { "legal", ArgTrue, (LPVOID) &appData.testLegality, FALSE },
\r
912 { "xlegal", ArgFalse, (LPVOID) &appData.testLegality, FALSE },
\r
913 { "-legal", ArgFalse, (LPVOID) &appData.testLegality, FALSE },
\r
914 { "premove", ArgBoolean, (LPVOID) &appData.premove, TRUE },
\r
915 { "pre", ArgTrue, (LPVOID) &appData.premove, FALSE },
\r
916 { "xpre", ArgFalse, (LPVOID) &appData.premove, FALSE },
\r
917 { "-pre", ArgFalse, (LPVOID) &appData.premove, FALSE },
\r
918 { "premoveWhite", ArgBoolean, (LPVOID) &appData.premoveWhite, TRUE },
\r
919 { "prewhite", ArgTrue, (LPVOID) &appData.premoveWhite, FALSE },
\r
920 { "xprewhite", ArgFalse, (LPVOID) &appData.premoveWhite, FALSE },
\r
921 { "-prewhite", ArgFalse, (LPVOID) &appData.premoveWhite, FALSE },
\r
922 { "premoveWhiteText", ArgString, (LPVOID) &appData.premoveWhiteText, TRUE },
\r
923 { "premoveBlack", ArgBoolean, (LPVOID) &appData.premoveBlack, TRUE },
\r
924 { "preblack", ArgTrue, (LPVOID) &appData.premoveBlack, FALSE },
\r
925 { "xpreblack", ArgFalse, (LPVOID) &appData.premoveBlack, FALSE },
\r
926 { "-preblack", ArgFalse, (LPVOID) &appData.premoveBlack, FALSE },
\r
927 { "premoveBlackText", ArgString, (LPVOID) &appData.premoveBlackText, TRUE },
\r
928 { "icsAlarm", ArgBoolean, (LPVOID) &appData.icsAlarm, TRUE},
\r
929 { "alarm", ArgTrue, (LPVOID) &appData.icsAlarm, FALSE},
\r
930 { "xalarm", ArgFalse, (LPVOID) &appData.icsAlarm, FALSE},
\r
931 { "-alarm", ArgFalse, (LPVOID) &appData.icsAlarm, FALSE},
\r
932 { "icsAlarmTime", ArgInt, (LPVOID) &appData.icsAlarmTime, TRUE},
\r
933 { "localLineEditing", ArgBoolean, (LPVOID) &appData.localLineEditing, FALSE},
\r
934 { "localLineEditing", ArgBoolean, (LPVOID) &appData.localLineEditing, FALSE},
\r
935 { "edit", ArgTrue, (LPVOID) &appData.localLineEditing, FALSE },
\r
936 { "xedit", ArgFalse, (LPVOID) &appData.localLineEditing, FALSE },
\r
937 { "-edit", ArgFalse, (LPVOID) &appData.localLineEditing, FALSE },
\r
938 { "animateMoving", ArgBoolean, (LPVOID) &appData.animate, TRUE },
\r
939 { "animate", ArgTrue, (LPVOID) &appData.animate, FALSE },
\r
940 { "xanimate", ArgFalse, (LPVOID) &appData.animate, FALSE },
\r
941 { "-animate", ArgFalse, (LPVOID) &appData.animate, FALSE },
\r
942 { "animateSpeed", ArgInt, (LPVOID) &appData.animSpeed, TRUE },
\r
943 { "animateDragging", ArgBoolean, (LPVOID) &appData.animateDragging, TRUE },
\r
944 { "drag", ArgTrue, (LPVOID) &appData.animateDragging, FALSE },
\r
945 { "xdrag", ArgFalse, (LPVOID) &appData.animateDragging, FALSE },
\r
946 { "-drag", ArgFalse, (LPVOID) &appData.animateDragging, FALSE },
\r
947 { "blindfold", ArgBoolean, (LPVOID) &appData.blindfold, TRUE },
\r
948 { "blind", ArgTrue, (LPVOID) &appData.blindfold, FALSE },
\r
949 { "xblind", ArgFalse, (LPVOID) &appData.blindfold, FALSE },
\r
950 { "-blind", ArgFalse, (LPVOID) &appData.blindfold, FALSE },
\r
951 { "highlightLastMove", ArgBoolean,
\r
952 (LPVOID) &appData.highlightLastMove, TRUE },
\r
953 { "highlight", ArgTrue, (LPVOID) &appData.highlightLastMove, FALSE },
\r
954 { "xhighlight", ArgFalse, (LPVOID) &appData.highlightLastMove, FALSE },
\r
955 { "-highlight", ArgFalse, (LPVOID) &appData.highlightLastMove, FALSE },
\r
956 { "highlightDragging", ArgBoolean,
\r
957 (LPVOID) &appData.highlightDragging, TRUE },
\r
958 { "highdrag", ArgTrue, (LPVOID) &appData.highlightDragging, FALSE },
\r
959 { "xhighdrag", ArgFalse, (LPVOID) &appData.highlightDragging, FALSE },
\r
960 { "-highdrag", ArgFalse, (LPVOID) &appData.highlightDragging, FALSE },
\r
961 { "colorizeMessages", ArgBoolean, (LPVOID) &appData.colorize, TRUE },
\r
962 { "colorize", ArgTrue, (LPVOID) &appData.colorize, FALSE },
\r
963 { "xcolorize", ArgFalse, (LPVOID) &appData.colorize, FALSE },
\r
964 { "-colorize", ArgFalse, (LPVOID) &appData.colorize, FALSE },
\r
965 { "colorShout", ArgAttribs, (LPVOID) ColorShout, TRUE },
\r
966 { "colorSShout", ArgAttribs, (LPVOID) ColorSShout, TRUE },
\r
967 { "colorChannel1", ArgAttribs, (LPVOID) ColorChannel1, TRUE },
\r
968 { "colorChannel", ArgAttribs, (LPVOID) ColorChannel, TRUE },
\r
969 { "colorKibitz", ArgAttribs, (LPVOID) ColorKibitz, TRUE },
\r
970 { "colorTell", ArgAttribs, (LPVOID) ColorTell, TRUE },
\r
971 { "colorChallenge", ArgAttribs, (LPVOID) ColorChallenge, TRUE },
\r
972 { "colorRequest", ArgAttribs, (LPVOID) ColorRequest, TRUE },
\r
973 { "colorSeek", ArgAttribs, (LPVOID) ColorSeek, TRUE },
\r
974 { "colorNormal", ArgAttribs, (LPVOID) ColorNormal, TRUE },
\r
975 { "colorBackground", ArgColor, (LPVOID) &consoleBackgroundColor, TRUE },
\r
976 { "soundShout", ArgFilename,
\r
977 (LPVOID) &textAttribs[ColorShout].sound.name, TRUE },
\r
978 { "soundSShout", ArgFilename,
\r
979 (LPVOID) &textAttribs[ColorSShout].sound.name, TRUE },
\r
980 { "soundChannel1", ArgFilename,
\r
981 (LPVOID) &textAttribs[ColorChannel1].sound.name, TRUE },
\r
982 { "soundChannel", ArgFilename,
\r
983 (LPVOID) &textAttribs[ColorChannel].sound.name, TRUE },
\r
984 { "soundKibitz", ArgFilename,
\r
985 (LPVOID) &textAttribs[ColorKibitz].sound.name, TRUE },
\r
986 { "soundTell", ArgFilename,
\r
987 (LPVOID) &textAttribs[ColorTell].sound.name, TRUE },
\r
988 { "soundChallenge", ArgFilename,
\r
989 (LPVOID) &textAttribs[ColorChallenge].sound.name, TRUE },
\r
990 { "soundRequest", ArgFilename,
\r
991 (LPVOID) &textAttribs[ColorRequest].sound.name, TRUE },
\r
992 { "soundSeek", ArgFilename,
\r
993 (LPVOID) &textAttribs[ColorSeek].sound.name, TRUE },
\r
994 { "soundMove", ArgFilename, (LPVOID) &sounds[(int)SoundMove].name, TRUE },
\r
995 { "soundBell", ArgFilename, (LPVOID) &sounds[(int)SoundBell].name, TRUE },
\r
996 { "soundIcsWin", ArgFilename, (LPVOID) &sounds[(int)SoundIcsWin].name,TRUE },
\r
997 { "soundIcsLoss", ArgFilename,
\r
998 (LPVOID) &sounds[(int)SoundIcsLoss].name, TRUE },
\r
999 { "soundIcsDraw", ArgFilename,
\r
1000 (LPVOID) &sounds[(int)SoundIcsDraw].name, TRUE },
\r
1001 { "soundIcsUnfinished", ArgFilename,
\r
1002 (LPVOID) &sounds[(int)SoundIcsUnfinished].name, TRUE},
\r
1003 { "soundIcsAlarm", ArgFilename,
\r
1004 (LPVOID) &sounds[(int)SoundAlarm].name, TRUE },
\r
1005 { "reuseFirst", ArgBoolean, (LPVOID) &appData.reuseFirst, FALSE },
\r
1006 { "reuse", ArgTrue, (LPVOID) &appData.reuseFirst, FALSE },
\r
1007 { "xreuse", ArgFalse, (LPVOID) &appData.reuseFirst, FALSE },
\r
1008 { "-reuse", ArgFalse, (LPVOID) &appData.reuseFirst, FALSE },
\r
1009 { "reuseChessPrograms", ArgBoolean,
\r
1010 (LPVOID) &appData.reuseFirst, FALSE }, /* backward compat only */
\r
1011 { "reuseSecond", ArgBoolean, (LPVOID) &appData.reuseSecond, FALSE },
\r
1012 { "reuse2", ArgTrue, (LPVOID) &appData.reuseSecond, FALSE },
\r
1013 { "xreuse2", ArgFalse, (LPVOID) &appData.reuseSecond, FALSE },
\r
1014 { "-reuse2", ArgFalse, (LPVOID) &appData.reuseSecond, FALSE },
\r
1015 { "comPortSettings", ArgCommSettings, (LPVOID) &dcb, TRUE },
\r
1016 { "x", ArgInt, (LPVOID) &boardX, TRUE },
\r
1017 { "y", ArgInt, (LPVOID) &boardY, TRUE },
\r
1018 { "icsX", ArgInt, (LPVOID) &consoleX, TRUE },
\r
1019 { "icsY", ArgInt, (LPVOID) &consoleY, TRUE },
\r
1020 { "icsW", ArgInt, (LPVOID) &consoleW, TRUE },
\r
1021 { "icsH", ArgInt, (LPVOID) &consoleH, TRUE },
\r
1022 { "analysisX", ArgInt, (LPVOID) &analysisX, TRUE },
\r
1023 { "analysisY", ArgInt, (LPVOID) &analysisY, TRUE },
\r
1024 { "analysisW", ArgInt, (LPVOID) &analysisW, TRUE },
\r
1025 { "analysisH", ArgInt, (LPVOID) &analysisH, TRUE },
\r
1026 { "commentX", ArgInt, (LPVOID) &commentX, TRUE },
\r
1027 { "commentY", ArgInt, (LPVOID) &commentY, TRUE },
\r
1028 { "commentW", ArgInt, (LPVOID) &commentW, TRUE },
\r
1029 { "commentH", ArgInt, (LPVOID) &commentH, TRUE },
\r
1030 { "tagsX", ArgInt, (LPVOID) &editTagsX, TRUE },
\r
1031 { "tagsY", ArgInt, (LPVOID) &editTagsY, TRUE },
\r
1032 { "tagsW", ArgInt, (LPVOID) &editTagsW, TRUE },
\r
1033 { "tagsH", ArgInt, (LPVOID) &editTagsH, TRUE },
\r
1034 { "gameListX", ArgInt, (LPVOID) &gameListX, TRUE },
\r
1035 { "gameListY", ArgInt, (LPVOID) &gameListY, TRUE },
\r
1036 { "gameListW", ArgInt, (LPVOID) &gameListW, TRUE },
\r
1037 { "gameListH", ArgInt, (LPVOID) &gameListH, TRUE },
\r
1038 { "settingsFile", ArgSettingsFilename, (LPVOID) &settingsFileName, FALSE },
\r
1039 { "ini", ArgSettingsFilename, (LPVOID) &settingsFileName, FALSE },
\r
1040 { "saveSettingsOnExit", ArgBoolean, (LPVOID) &saveSettingsOnExit, TRUE },
\r
1041 { "chessProgram", ArgBoolean, (LPVOID) &chessProgram, FALSE },
\r
1042 { "cp", ArgTrue, (LPVOID) &chessProgram, FALSE },
\r
1043 { "xcp", ArgFalse, (LPVOID) &chessProgram, FALSE },
\r
1044 { "-cp", ArgFalse, (LPVOID) &chessProgram, FALSE },
\r
1045 { "icsMenu", ArgString, (LPVOID) &icsTextMenuString, TRUE },
\r
1046 { "icsNames", ArgString, (LPVOID) &icsNames, TRUE },
\r
1047 { "firstChessProgramNames", ArgString, (LPVOID) &firstChessProgramNames,
\r
1049 { "secondChessProgramNames", ArgString, (LPVOID) &secondChessProgramNames,
\r
1051 { "initialMode", ArgString, (LPVOID) &appData.initialMode, FALSE },
\r
1052 { "mode", ArgString, (LPVOID) &appData.initialMode, FALSE },
\r
1053 { "variant", ArgString, (LPVOID) &appData.variant, FALSE },
\r
1054 { "firstProtocolVersion", ArgInt, (LPVOID) &appData.firstProtocolVersion, FALSE },
1055 { "secondProtocolVersion", ArgInt, (LPVOID) &appData.secondProtocolVersion,FALSE },
1056 { "showButtonBar", ArgBoolean, (LPVOID) &appData.showButtonBar, TRUE },
\r
1057 { "buttons", ArgTrue, (LPVOID) &appData.showButtonBar, FALSE },
\r
1058 { "xbuttons", ArgFalse, (LPVOID) &appData.showButtonBar, FALSE },
\r
1059 { "-buttons", ArgFalse, (LPVOID) &appData.showButtonBar, FALSE },
\r
1060 /* [AS] New features */
1061 { "firstScoreAbs", ArgBoolean, (LPVOID) &appData.firstScoreIsAbsolute, TRUE },
1062 { "secondScoreAbs", ArgBoolean, (LPVOID) &appData.secondScoreIsAbsolute, TRUE },
1063 { "pgnExtendedInfo", ArgBoolean, (LPVOID) &appData.saveExtendedInfoInPGN, TRUE },
1064 { "hideThinkingFromHuman", ArgBoolean, (LPVOID) &appData.hideThinkingFromHuman, TRUE },
1065 { "liteBackTextureFile", ArgString, (LPVOID) &appData.liteBackTextureFile, TRUE },
1066 { "darkBackTextureFile", ArgString, (LPVOID) &appData.darkBackTextureFile, TRUE },
1067 { "liteBackTextureMode", ArgInt, (LPVOID) &appData.liteBackTextureMode, TRUE },
1068 { "darkBackTextureMode", ArgInt, (LPVOID) &appData.darkBackTextureMode, TRUE },
1069 { "renderPiecesWithFont", ArgString, (LPVOID) &appData.renderPiecesWithFont, TRUE },
1070 { "fontPieceToCharTable", ArgString, (LPVOID) &appData.fontToPieceTable, TRUE },
1071 { "fontPieceBackColorWhite", ArgColor, (LPVOID) &appData.fontBackColorWhite, TRUE },
1072 { "fontPieceForeColorWhite", ArgColor, (LPVOID) &appData.fontForeColorWhite, TRUE },
1073 { "fontPieceBackColorBlack", ArgColor, (LPVOID) &appData.fontBackColorBlack, TRUE },
1074 { "fontPieceForeColorBlack", ArgColor, (LPVOID) &appData.fontForeColorBlack, TRUE },
1075 { "fontPieceSize", ArgInt, (LPVOID) &appData.fontPieceSize, TRUE },
1076 { "overrideLineGap", ArgInt, (LPVOID) &appData.overrideLineGap, TRUE },
1077 { "adjudicateLossThreshold", ArgInt, (LPVOID) &appData.adjudicateLossThreshold, TRUE },
1078 { "delayBeforeQuit", ArgInt, (LPVOID) &appData.delayBeforeQuit, TRUE },
1079 { "delayAfterQuit", ArgInt, (LPVOID) &appData.delayAfterQuit, TRUE },
1080 { "nameOfDebugFile", ArgFilename, (LPVOID) &appData.nameOfDebugFile, FALSE },
1081 { "debugfile", ArgFilename, (LPVOID) &appData.nameOfDebugFile, FALSE },
1082 { "pgnEventHeader", ArgString, (LPVOID) &appData.pgnEventHeader, TRUE },
1083 { "defaultFrcPosition", ArgInt, (LPVOID) &appData.defaultFrcPosition, TRUE },
1085 { "zippyTalk", ArgBoolean, (LPVOID) &appData.zippyTalk, FALSE },
\r
1086 { "zt", ArgTrue, (LPVOID) &appData.zippyTalk, FALSE },
\r
1087 { "xzt", ArgFalse, (LPVOID) &appData.zippyTalk, FALSE },
\r
1088 { "-zt", ArgFalse, (LPVOID) &appData.zippyTalk, FALSE },
\r
1089 { "zippyPlay", ArgBoolean, (LPVOID) &appData.zippyPlay, FALSE },
\r
1090 { "zp", ArgTrue, (LPVOID) &appData.zippyPlay, FALSE },
\r
1091 { "xzp", ArgFalse, (LPVOID) &appData.zippyPlay, FALSE },
\r
1092 { "-zp", ArgFalse, (LPVOID) &appData.zippyPlay, FALSE },
\r
1093 { "zippyLines", ArgFilename, (LPVOID) &appData.zippyLines, FALSE },
\r
1094 { "zippyPinhead", ArgString, (LPVOID) &appData.zippyPinhead, FALSE },
\r
1095 { "zippyPassword", ArgString, (LPVOID) &appData.zippyPassword, FALSE },
\r
1096 { "zippyPassword2", ArgString, (LPVOID) &appData.zippyPassword2, FALSE },
\r
1097 { "zippyWrongPassword", ArgString, (LPVOID) &appData.zippyWrongPassword,
\r
1099 { "zippyAcceptOnly", ArgString, (LPVOID) &appData.zippyAcceptOnly, FALSE },
\r
1100 { "zippyUseI", ArgBoolean, (LPVOID) &appData.zippyUseI, FALSE },
\r
1101 { "zui", ArgTrue, (LPVOID) &appData.zippyUseI, FALSE },
\r
1102 { "xzui", ArgFalse, (LPVOID) &appData.zippyUseI, FALSE },
\r
1103 { "-zui", ArgFalse, (LPVOID) &appData.zippyUseI, FALSE },
\r
1104 { "zippyBughouse", ArgInt, (LPVOID) &appData.zippyBughouse, FALSE },
\r
1105 { "zippyNoplayCrafty", ArgBoolean, (LPVOID) &appData.zippyNoplayCrafty,
\r
1107 { "znc", ArgTrue, (LPVOID) &appData.zippyNoplayCrafty, FALSE },
\r
1108 { "xznc", ArgFalse, (LPVOID) &appData.zippyNoplayCrafty, FALSE },
\r
1109 { "-znc", ArgFalse, (LPVOID) &appData.zippyNoplayCrafty, FALSE },
\r
1110 { "zippyGameEnd", ArgString, (LPVOID) &appData.zippyGameEnd, FALSE },
\r
1111 { "zippyGameStart", ArgString, (LPVOID) &appData.zippyGameStart, FALSE },
\r
1112 { "zippyAdjourn", ArgBoolean, (LPVOID) &appData.zippyAdjourn, FALSE },
\r
1113 { "zadj", ArgTrue, (LPVOID) &appData.zippyAdjourn, FALSE },
\r
1114 { "xzadj", ArgFalse, (LPVOID) &appData.zippyAdjourn, FALSE },
\r
1115 { "-zadj", ArgFalse, (LPVOID) &appData.zippyAdjourn, FALSE },
\r
1116 { "zippyAbort", ArgBoolean, (LPVOID) &appData.zippyAbort, FALSE },
\r
1117 { "zab", ArgTrue, (LPVOID) &appData.zippyAbort, FALSE },
\r
1118 { "xzab", ArgFalse, (LPVOID) &appData.zippyAbort, FALSE },
\r
1119 { "-zab", ArgFalse, (LPVOID) &appData.zippyAbort, FALSE },
\r
1120 { "zippyVariants", ArgString, (LPVOID) &appData.zippyVariants, FALSE },
\r
1121 { "zippyMaxGames", ArgInt, (LPVOID)&appData.zippyMaxGames, FALSE },
\r
1122 { "zippyReplayTimeout", ArgInt, (LPVOID)&appData.zippyReplayTimeout, FALSE },
\r
1123 /* Kludge to allow winboard.ini files from buggy 4.0.4 to be read: */
\r
1124 { "zippyReplyTimeout", ArgInt, (LPVOID)&junk, FALSE },
\r
1126 { NULL, ArgNone, NULL, FALSE }
\r
1130 /* Kludge for indirection files on command line */
\r
1131 char* lastIndirectionFilename;
\r
1132 ArgDescriptor argDescriptorIndirection =
\r
1133 { "", ArgSettingsFilename, (LPVOID) NULL, FALSE };
\r
1137 ExitArgError(char *msg, char *badArg)
\r
1139 char buf[MSG_SIZ];
\r
1141 sprintf(buf, "%s %s", msg, badArg);
\r
1142 DisplayFatalError(buf, 0, 2);
\r
1146 /* Command line font name parser. NULL name means do nothing.
\r
1147 Syntax like "Courier New:10.0 bi" or "Arial:10" or "Arial:10b"
\r
1148 For backward compatibility, syntax without the colon is also
\r
1149 accepted, but font names with digits in them won't work in that case.
\r
1152 ParseFontName(char *name, MyFontParams *mfp)
\r
1155 if (name == NULL) return;
\r
1157 q = strchr(p, ':');
\r
1159 if (q - p >= sizeof(mfp->faceName))
\r
1160 ExitArgError("Font name too long:", name);
\r
1161 memcpy(mfp->faceName, p, q - p);
\r
1162 mfp->faceName[q - p] = NULLCHAR;
\r
1165 q = mfp->faceName;
\r
1166 while (*p && !isdigit(*p)) {
\r
1168 if (q - mfp->faceName >= sizeof(mfp->faceName))
\r
1169 ExitArgError("Font name too long:", name);
\r
1171 while (q > mfp->faceName && q[-1] == ' ') q--;
\r
1174 if (!*p) ExitArgError("Font point size missing:", name);
\r
1175 mfp->pointSize = (float) atof(p);
\r
1176 mfp->bold = (strchr(p, 'b') != NULL);
\r
1177 mfp->italic = (strchr(p, 'i') != NULL);
\r
1178 mfp->underline = (strchr(p, 'u') != NULL);
\r
1179 mfp->strikeout = (strchr(p, 's') != NULL);
\r
1182 /* Color name parser.
\r
1183 X version accepts X color names, but this one
\r
1184 handles only the #rrggbb form (hex) or rrr,ggg,bbb (decimal) */
\r
1186 ParseColorName(char *name)
\r
1188 int red, green, blue, count;
\r
1189 char buf[MSG_SIZ];
\r
1191 count = sscanf(name, "#%2x%2x%2x", &red, &green, &blue);
\r
1193 count = sscanf(name, "%3d%*[^0-9]%3d%*[^0-9]%3d",
\r
1194 &red, &green, &blue);
\r
1197 sprintf(buf, "Can't parse color name %s", name);
\r
1198 DisplayError(buf, 0);
\r
1199 return RGB(0, 0, 0);
\r
1201 return PALETTERGB(red, green, blue);
\r
1205 void ParseAttribs(COLORREF *color, int *effects, char* argValue)
\r
1207 char *e = argValue;
\r
1211 if (*e == 'b') eff |= CFE_BOLD;
\r
1212 else if (*e == 'i') eff |= CFE_ITALIC;
\r
1213 else if (*e == 'u') eff |= CFE_UNDERLINE;
\r
1214 else if (*e == 's') eff |= CFE_STRIKEOUT;
\r
1215 else if (*e == '#' || isdigit(*e)) break;
\r
1219 *color = ParseColorName(e);
\r
1224 ParseBoardSize(char *name)
\r
1226 BoardSize bs = SizeTiny;
\r
1227 while (sizeInfo[bs].name != NULL) {
\r
1228 if (StrCaseCmp(name, sizeInfo[bs].name) == 0) return bs;
\r
1231 ExitArgError("Unrecognized board size value", name);
\r
1232 return bs; /* not reached */
\r
1237 StringGet(void *getClosure)
\r
1239 char **p = (char **) getClosure;
\r
1244 FileGet(void *getClosure)
\r
1247 FILE* f = (FILE*) getClosure;
\r
1256 /* Parse settings file named "name". If file found, return the
\r
1257 full name in fullname and return TRUE; else return FALSE */
\r
1259 ParseSettingsFile(char *name, char fullname[MSG_SIZ])
\r
1264 if (SearchPath(installDir, name, NULL, MSG_SIZ, fullname, &dummy)) {
\r
1265 f = fopen(fullname, "r");
\r
1267 ParseArgs(FileGet, f);
\r
1276 ParseArgs(GetFunc get, void *cl)
\r
1278 char argName[ARG_MAX];
\r
1279 char argValue[ARG_MAX];
\r
1280 ArgDescriptor *ad;
\r
1289 while (ch == ' ' || ch == '\n' || ch == '\t') ch = get(cl);
\r
1290 if (ch == NULLCHAR) break;
\r
1292 /* Comment to end of line */
\r
1294 while (ch != '\n' && ch != NULLCHAR) ch = get(cl);
\r
1296 } else if (ch == '/' || ch == '-') {
\r
1299 while (ch != ' ' && ch != '=' && ch != ':' && ch != NULLCHAR &&
\r
1300 ch != '\n' && ch != '\t') {
\r
1306 for (ad = argDescriptors; ad->argName != NULL; ad++)
\r
1307 if (strcmp(ad->argName, argName + 1) == 0) break;
\r
1309 if (ad->argName == NULL)
\r
1310 ExitArgError("Unrecognized argument", argName);
\r
1312 } else if (ch == '@') {
\r
1313 /* Indirection file */
\r
1314 ad = &argDescriptorIndirection;
\r
1317 /* Positional argument */
\r
1318 ad = &argDescriptors[posarg++];
\r
1319 strcpy(argName, ad->argName);
\r
1322 if (ad->argType == ArgTrue) {
\r
1323 *(Boolean *) ad->argLoc = TRUE;
\r
1326 if (ad->argType == ArgFalse) {
\r
1327 *(Boolean *) ad->argLoc = FALSE;
\r
1331 while (ch == ' ' || ch == '=' || ch == ':' || ch == '\t') ch = get(cl);
\r
1332 if (ch == NULLCHAR || ch == '\n') {
\r
1333 ExitArgError("No value provided for argument", argName);
\r
1337 // Quoting with { }. No characters have to (or can) be escaped.
\r
1338 // Thus the string cannot contain a '}' character.
\r
1358 } else if (ch == '\'' || ch == '"') {
\r
1359 // Quoting with ' ' or " ", with \ as escape character.
\r
1360 // Inconvenient for long strings that may contain Windows filenames.
\r
1377 if (ch == start) {
\r
1386 if (ad->argType == ArgFilename
\r
1387 || ad->argType == ArgSettingsFilename) {
\r
1393 ExitArgError("Incomplete \\ escape in value for", argName);
\r
1417 for (i = 0; i < 3; i++) {
\r
1418 if (ch >= '0' && ch <= '7') {
\r
1419 octval = octval*8 + (ch - '0');
\r
1426 *q++ = (char) octval;
\r
1437 while (ch != ' ' && ch != NULLCHAR && ch != '\t' && ch != '\n') {
\r
1444 switch (ad->argType) {
\r
1446 *(int *) ad->argLoc = atoi(argValue);
\r
1450 *(float *) ad->argLoc = (float) atof(argValue);
\r
1455 *(char **) ad->argLoc = strdup(argValue);
\r
1458 case ArgSettingsFilename:
\r
1460 char fullname[MSG_SIZ];
\r
1461 if (ParseSettingsFile(argValue, fullname)) {
\r
1462 if (ad->argLoc != NULL) {
\r
1463 *(char **) ad->argLoc = strdup(fullname);
\r
1466 if (ad->argLoc != NULL) {
\r
1468 ExitArgError("Failed to open indirection file", argValue);
\r
1475 switch (argValue[0]) {
\r
1478 *(Boolean *) ad->argLoc = TRUE;
\r
1482 *(Boolean *) ad->argLoc = FALSE;
\r
1485 ExitArgError("Unrecognized boolean argument value", argValue);
\r
1491 *(COLORREF *)ad->argLoc = ParseColorName(argValue);
\r
1494 case ArgAttribs: {
\r
1495 ColorClass cc = (ColorClass)ad->argLoc;
\r
1496 ParseAttribs(&textAttribs[cc].color, &textAttribs[cc].effects, argValue);
\r
1500 case ArgBoardSize:
\r
1501 *(BoardSize *)ad->argLoc = ParseBoardSize(argValue);
\r
1505 ParseFontName(argValue, &font[boardSize][(int)ad->argLoc]->mfp);
\r
1508 case ArgCommSettings:
\r
1509 ParseCommSettings(argValue, &dcb);
\r
1513 ExitArgError("Unrecognized argument", argValue);
\r
1520 LFfromMFP(LOGFONT* lf, MyFontParams *mfp)
\r
1522 HDC hdc = CreateDC("DISPLAY", NULL, NULL, NULL);
\r
1523 lf->lfHeight = -(int)(mfp->pointSize * GetDeviceCaps(hdc, LOGPIXELSY) / 72.0 + 0.5);
\r
1526 lf->lfEscapement = 0;
\r
1527 lf->lfOrientation = 0;
\r
1528 lf->lfWeight = mfp->bold ? FW_BOLD : FW_NORMAL;
\r
1529 lf->lfItalic = mfp->italic;
\r
1530 lf->lfUnderline = mfp->underline;
\r
1531 lf->lfStrikeOut = mfp->strikeout;
\r
1532 lf->lfCharSet = DEFAULT_CHARSET;
\r
1533 lf->lfOutPrecision = OUT_DEFAULT_PRECIS;
\r
1534 lf->lfClipPrecision = CLIP_DEFAULT_PRECIS;
\r
1535 lf->lfQuality = DEFAULT_QUALITY;
\r
1536 lf->lfPitchAndFamily = DEFAULT_PITCH|FF_DONTCARE;
\r
1537 strcpy(lf->lfFaceName, mfp->faceName);
\r
1541 CreateFontInMF(MyFont *mf)
\r
1543 LFfromMFP(&mf->lf, &mf->mfp);
\r
1544 if (mf->hf) DeleteObject(mf->hf);
\r
1545 mf->hf = CreateFontIndirect(&mf->lf);
\r
1549 SetDefaultTextAttribs()
\r
1552 for (cc = (ColorClass)0; cc < NColorClasses; cc++) {
\r
1553 ParseAttribs(&textAttribs[cc].color,
\r
1554 &textAttribs[cc].effects,
\r
1555 defaultTextAttribs[cc]);
\r
1560 SetDefaultSounds()
\r
1564 for (cc = (ColorClass)0; cc < NColorClasses; cc++) {
\r
1565 textAttribs[cc].sound.name = strdup("");
\r
1566 textAttribs[cc].sound.data = NULL;
\r
1568 for (sc = (SoundClass)0; sc < NSoundClasses; sc++) {
\r
1569 sounds[sc].name = strdup("");
\r
1570 sounds[sc].data = NULL;
\r
1572 sounds[(int)SoundBell].name = strdup(SOUND_BELL);
\r
1580 for (cc = (ColorClass)0; cc < NColorClasses; cc++) {
\r
1581 MyLoadSound(&textAttribs[cc].sound);
\r
1583 for (sc = (SoundClass)0; sc < NSoundClasses; sc++) {
\r
1584 MyLoadSound(&sounds[sc]);
\r
1589 InitAppData(LPSTR lpCmdLine)
\r
1592 char buf[ARG_MAX], currDir[MSG_SIZ];
\r
1595 programName = szAppName;
\r
1597 /* Initialize to defaults */
\r
1598 lightSquareColor = ParseColorName(LIGHT_SQUARE_COLOR);
\r
1599 darkSquareColor = ParseColorName(DARK_SQUARE_COLOR);
\r
1600 whitePieceColor = ParseColorName(WHITE_PIECE_COLOR);
\r
1601 blackPieceColor = ParseColorName(BLACK_PIECE_COLOR);
\r
1602 highlightSquareColor = ParseColorName(HIGHLIGHT_SQUARE_COLOR);
\r
1603 premoveHighlightColor = ParseColorName(PREMOVE_HIGHLIGHT_COLOR);
\r
1604 consoleBackgroundColor = ParseColorName(COLOR_BKGD);
\r
1605 SetDefaultTextAttribs();
\r
1606 SetDefaultSounds();
\r
1607 appData.movesPerSession = MOVES_PER_SESSION;
\r
1608 appData.initString = INIT_STRING;
\r
1609 appData.secondInitString = INIT_STRING;
\r
1610 appData.firstComputerString = COMPUTER_STRING;
\r
1611 appData.secondComputerString = COMPUTER_STRING;
\r
1612 appData.firstChessProgram = FIRST_CHESS_PROGRAM;
\r
1613 appData.secondChessProgram = SECOND_CHESS_PROGRAM;
\r
1614 appData.firstPlaysBlack = FALSE;
\r
1615 appData.noChessProgram = FALSE;
\r
1616 chessProgram = FALSE;
\r
1617 appData.firstHost = FIRST_HOST;
\r
1618 appData.secondHost = SECOND_HOST;
\r
1619 appData.firstDirectory = FIRST_DIRECTORY;
\r
1620 appData.secondDirectory = SECOND_DIRECTORY;
\r
1621 appData.bitmapDirectory = "";
\r
1622 appData.remoteShell = REMOTE_SHELL;
\r
1623 appData.remoteUser = "";
\r
1624 appData.timeDelay = TIME_DELAY;
\r
1625 appData.timeControl = TIME_CONTROL;
\r
1626 appData.timeIncrement = TIME_INCREMENT;
\r
1627 appData.icsActive = FALSE;
\r
1628 appData.icsHost = "";
\r
1629 appData.icsPort = ICS_PORT;
\r
1630 appData.icsCommPort = ICS_COMM_PORT;
\r
1631 appData.icsLogon = ICS_LOGON;
\r
1632 appData.icsHelper = "";
\r
1633 appData.useTelnet = FALSE;
\r
1634 appData.telnetProgram = TELNET_PROGRAM;
\r
1635 appData.gateway = "";
\r
1636 appData.loadGameFile = "";
\r
1637 appData.loadGameIndex = 0;
\r
1638 appData.saveGameFile = "";
\r
1639 appData.autoSaveGames = FALSE;
\r
1640 appData.loadPositionFile = "";
\r
1641 appData.loadPositionIndex = 1;
\r
1642 appData.savePositionFile = "";
\r
1643 appData.matchMode = FALSE;
\r
1644 appData.matchGames = 0;
\r
1645 appData.monoMode = FALSE;
\r
1646 appData.debugMode = FALSE;
\r
1647 appData.clockMode = TRUE;
\r
1648 boardSize = (BoardSize) -1; /* determine by screen size */
\r
1649 appData.Iconic = FALSE; /*unused*/
\r
1650 appData.searchTime = "";
\r
1651 appData.searchDepth = 0;
\r
1652 appData.showCoords = FALSE;
\r
1653 appData.ringBellAfterMoves = TRUE; /*obsolete in WinBoard*/
\r
1654 appData.autoCallFlag = FALSE;
\r
1655 appData.flipView = FALSE;
\r
1656 appData.autoFlipView = TRUE;
\r
1657 appData.cmailGameName = "";
\r
1658 appData.alwaysPromoteToQueen = FALSE;
\r
1659 appData.oldSaveStyle = FALSE;
\r
1660 appData.quietPlay = FALSE;
\r
1661 appData.showThinking = FALSE;
\r
1662 appData.ponderNextMove = TRUE;
\r
1663 appData.periodicUpdates = TRUE;
\r
1664 appData.popupExitMessage = TRUE;
\r
1665 appData.popupMoveErrors = FALSE;
\r
1666 appData.autoObserve = FALSE;
\r
1667 appData.autoComment = FALSE;
\r
1668 appData.animate = TRUE;
\r
1669 appData.animSpeed = 10;
\r
1670 appData.animateDragging = TRUE;
\r
1671 appData.highlightLastMove = TRUE;
\r
1672 appData.getMoveList = TRUE;
\r
1673 appData.testLegality = TRUE;
\r
1674 appData.premove = TRUE;
\r
1675 appData.premoveWhite = FALSE;
\r
1676 appData.premoveWhiteText = "";
\r
1677 appData.premoveBlack = FALSE;
\r
1678 appData.premoveBlackText = "";
\r
1679 appData.icsAlarm = TRUE;
\r
1680 appData.icsAlarmTime = 5000;
\r
1681 appData.autoRaiseBoard = TRUE;
\r
1682 appData.localLineEditing = TRUE;
\r
1683 appData.colorize = TRUE;
\r
1684 appData.reuseFirst = TRUE;
\r
1685 appData.reuseSecond = TRUE;
\r
1686 appData.blindfold = FALSE;
\r
1687 dcb.DCBlength = sizeof(DCB);
\r
1688 dcb.BaudRate = 9600;
\r
1689 dcb.fBinary = TRUE;
\r
1690 dcb.fParity = FALSE;
\r
1691 dcb.fOutxCtsFlow = FALSE;
\r
1692 dcb.fOutxDsrFlow = FALSE;
\r
1693 dcb.fDtrControl = DTR_CONTROL_ENABLE;
\r
1694 dcb.fDsrSensitivity = FALSE;
\r
1695 dcb.fTXContinueOnXoff = TRUE;
\r
1696 dcb.fOutX = FALSE;
\r
1698 dcb.fNull = FALSE;
\r
1699 dcb.fRtsControl = RTS_CONTROL_ENABLE;
\r
1700 dcb.fAbortOnError = FALSE;
\r
1701 dcb.wReserved = 0;
\r
1703 dcb.Parity = SPACEPARITY;
\r
1704 dcb.StopBits = ONESTOPBIT;
\r
1705 settingsFileName = SETTINGS_FILE;
\r
1706 saveSettingsOnExit = TRUE;
\r
1707 boardX = CW_USEDEFAULT;
\r
1708 boardY = CW_USEDEFAULT;
\r
1709 consoleX = CW_USEDEFAULT;
\r
1710 consoleY = CW_USEDEFAULT;
\r
1711 consoleW = CW_USEDEFAULT;
\r
1712 consoleH = CW_USEDEFAULT;
\r
1713 analysisX = CW_USEDEFAULT;
\r
1714 analysisY = CW_USEDEFAULT;
\r
1715 analysisW = CW_USEDEFAULT;
\r
1716 analysisH = CW_USEDEFAULT;
\r
1717 commentX = CW_USEDEFAULT;
\r
1718 commentY = CW_USEDEFAULT;
\r
1719 commentW = CW_USEDEFAULT;
\r
1720 commentH = CW_USEDEFAULT;
\r
1721 editTagsX = CW_USEDEFAULT;
\r
1722 editTagsY = CW_USEDEFAULT;
\r
1723 editTagsW = CW_USEDEFAULT;
\r
1724 editTagsH = CW_USEDEFAULT;
\r
1725 gameListX = CW_USEDEFAULT;
\r
1726 gameListY = CW_USEDEFAULT;
\r
1727 gameListW = CW_USEDEFAULT;
\r
1728 gameListH = CW_USEDEFAULT;
\r
1729 icsTextMenuString = ICS_TEXT_MENU_DEFAULT;
\r
1730 icsNames = ICS_NAMES;
\r
1731 firstChessProgramNames = FCP_NAMES;
\r
1732 secondChessProgramNames = SCP_NAMES;
\r
1733 appData.initialMode = "";
\r
1734 appData.variant = "normal";
\r
1735 appData.firstProtocolVersion = PROTOVER;
\r
1736 appData.secondProtocolVersion = PROTOVER;
\r
1737 appData.showButtonBar = TRUE;
\r
1739 /* [AS] New properties (see comments in header file) */
1740 appData.firstScoreIsAbsolute = FALSE;
1741 appData.secondScoreIsAbsolute = FALSE;
1742 appData.saveExtendedInfoInPGN = FALSE;
1743 appData.hideThinkingFromHuman = FALSE;
1744 appData.liteBackTextureFile = "";
1745 appData.liteBackTextureMode = BACK_TEXTURE_MODE_PLAIN;
1746 appData.darkBackTextureFile = "";
1747 appData.darkBackTextureMode = BACK_TEXTURE_MODE_PLAIN;
1748 appData.renderPiecesWithFont = "";
1749 appData.fontToPieceTable = "";
1750 appData.fontBackColorWhite = 0;
1751 appData.fontForeColorWhite = 0;
1752 appData.fontBackColorBlack = 0;
1753 appData.fontForeColorBlack = 0;
1754 appData.fontPieceSize = 80;
1755 appData.overrideLineGap = 1;
1756 appData.adjudicateLossThreshold = 0;
1757 appData.delayBeforeQuit = 0;
1758 appData.delayAfterQuit = 0;
1759 appData.nameOfDebugFile = "winboard.debug";
1760 appData.pgnEventHeader = "Computer Chess Game";
1761 appData.defaultFrcPosition = -1;
1764 appData.zippyTalk = ZIPPY_TALK;
\r
1765 appData.zippyPlay = ZIPPY_PLAY;
\r
1766 appData.zippyLines = ZIPPY_LINES;
\r
1767 appData.zippyPinhead = ZIPPY_PINHEAD;
\r
1768 appData.zippyPassword = ZIPPY_PASSWORD;
\r
1769 appData.zippyPassword2 = ZIPPY_PASSWORD2;
\r
1770 appData.zippyWrongPassword = ZIPPY_WRONG_PASSWORD;
\r
1771 appData.zippyAcceptOnly = ZIPPY_ACCEPT_ONLY;
\r
1772 appData.zippyUseI = ZIPPY_USE_I;
\r
1773 appData.zippyBughouse = ZIPPY_BUGHOUSE;
\r
1774 appData.zippyNoplayCrafty = ZIPPY_NOPLAY_CRAFTY;
\r
1775 appData.zippyGameEnd = ZIPPY_GAME_END;
\r
1776 appData.zippyGameStart = ZIPPY_GAME_START;
\r
1777 appData.zippyAdjourn = ZIPPY_ADJOURN;
\r
1778 appData.zippyAbort = ZIPPY_ABORT;
\r
1779 appData.zippyVariants = ZIPPY_VARIANTS;
\r
1780 appData.zippyMaxGames = ZIPPY_MAX_GAMES;
\r
1781 appData.zippyReplayTimeout = ZIPPY_REPLAY_TIMEOUT;
\r
1784 /* Point font array elements to structures and
\r
1785 parse default font names */
\r
1786 for (i=0; i<NUM_FONTS; i++) {
\r
1787 for (j=0; j<NUM_SIZES; j++) {
\r
1788 font[j][i] = &fontRec[j][i];
\r
1789 ParseFontName(font[j][i]->def, &font[j][i]->mfp);
\r
1793 /* Parse default settings file if any */
\r
1794 if (ParseSettingsFile(settingsFileName, buf)) {
\r
1795 settingsFileName = strdup(buf);
\r
1798 /* Parse command line */
\r
1799 ParseArgs(StringGet, &lpCmdLine);
\r
1801 /* Propagate options that affect others */
\r
1802 if (appData.matchMode || appData.matchGames) chessProgram = TRUE;
\r
1803 if (appData.icsActive || appData.noChessProgram) {
\r
1804 chessProgram = FALSE; /* not local chess program mode */
\r
1807 /* Open startup dialog if needed */
\r
1808 if ((!appData.noChessProgram && !chessProgram && !appData.icsActive) ||
\r
1809 (appData.icsActive && *appData.icsHost == NULLCHAR) ||
\r
1810 (chessProgram && (*appData.firstChessProgram == NULLCHAR ||
\r
1811 *appData.secondChessProgram == NULLCHAR))) {
\r
1814 lpProc = MakeProcInstance((FARPROC)StartupDialog, hInst);
\r
1815 DialogBox(hInst, MAKEINTRESOURCE(DLG_Startup), NULL, (DLGPROC)lpProc);
\r
1816 FreeProcInstance(lpProc);
\r
1819 /* Make sure save files land in the right (?) directory */
\r
1820 if (GetFullPathName(appData.saveGameFile, MSG_SIZ, buf, &dummy)) {
\r
1821 appData.saveGameFile = strdup(buf);
\r
1823 if (GetFullPathName(appData.savePositionFile, MSG_SIZ, buf, &dummy)) {
\r
1824 appData.savePositionFile = strdup(buf);
\r
1827 /* Finish initialization for fonts and sounds */
\r
1828 for (i=0; i<NUM_FONTS; i++) {
\r
1829 for (j=0; j<NUM_SIZES; j++) {
\r
1830 CreateFontInMF(font[j][i]);
\r
1833 /* xboard, and older WinBoards, controlled the move sound with the
\r
1834 appData.ringBellAfterMoves option. In the current WinBoard, we
\r
1835 always turn the option on (so that the backend will call us),
\r
1836 then let the user turn the sound off by setting it to silence if
\r
1837 desired. To accommodate old winboard.ini files saved by old
\r
1838 versions of WinBoard, we also turn off the sound if the option
\r
1839 was initially set to false. */
\r
1840 if (!appData.ringBellAfterMoves) {
\r
1841 sounds[(int)SoundMove].name = strdup("");
\r
1842 appData.ringBellAfterMoves = TRUE;
\r
1844 GetCurrentDirectory(MSG_SIZ, currDir);
\r
1845 SetCurrentDirectory(installDir);
\r
1847 SetCurrentDirectory(currDir);
\r
1849 p = icsTextMenuString;
\r
1850 if (p[0] == '@') {
\r
1851 FILE* f = fopen(p + 1, "r");
\r
1853 DisplayFatalError(p + 1, errno, 2);
\r
1856 i = fread(buf, 1, sizeof(buf)-1, f);
\r
1858 buf[i] = NULLCHAR;
\r
1861 ParseIcsTextMenu(strdup(p));
\r
1868 HMENU hmenu = GetMenu(hwndMain);
\r
1870 (void) EnableMenuItem(hmenu, IDM_CommPort,
\r
1871 MF_BYCOMMAND|((appData.icsActive &&
\r
1872 *appData.icsCommPort != NULLCHAR) ?
\r
1873 MF_ENABLED : MF_GRAYED));
\r
1874 (void) CheckMenuItem(hmenu, IDM_SaveSettingsOnExit,
\r
1875 MF_BYCOMMAND|(saveSettingsOnExit ?
\r
1876 MF_CHECKED : MF_UNCHECKED));
\r
1881 SaveSettings(char* name)
\r
1884 ArgDescriptor *ad;
\r
1885 WINDOWPLACEMENT wp;
\r
1886 char dir[MSG_SIZ];
\r
1888 if (!hwndMain) return;
\r
1890 GetCurrentDirectory(MSG_SIZ, dir);
\r
1891 SetCurrentDirectory(installDir);
\r
1892 f = fopen(name, "w");
\r
1893 SetCurrentDirectory(dir);
\r
1895 DisplayError(name, errno);
\r
1898 fprintf(f, ";\n");
\r
1899 fprintf(f, "; %s %s.%s Save Settings file\n", PRODUCT, VERSION, PATCHLEVEL);
\r
1900 fprintf(f, ";\n");
\r
1901 fprintf(f, "; You can edit the values of options that are already set in this file,\n");
\r
1902 fprintf(f, "; but if you add other options, the next Save Settings will not save them.\n");
\r
1903 fprintf(f, "; Use a shortcut, an @indirection file, or a .bat file instead.\n");
\r
1904 fprintf(f, ";\n");
\r
1906 wp.length = sizeof(WINDOWPLACEMENT);
\r
1907 GetWindowPlacement(hwndMain, &wp);
\r
1908 boardX = wp.rcNormalPosition.left;
\r
1909 boardY = wp.rcNormalPosition.top;
\r
1911 if (hwndConsole) {
\r
1912 GetWindowPlacement(hwndConsole, &wp);
\r
1913 consoleX = wp.rcNormalPosition.left;
\r
1914 consoleY = wp.rcNormalPosition.top;
\r
1915 consoleW = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
1916 consoleH = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
1919 if (analysisDialog) {
\r
1920 GetWindowPlacement(analysisDialog, &wp);
\r
1921 analysisX = wp.rcNormalPosition.left;
\r
1922 analysisY = wp.rcNormalPosition.top;
\r
1923 analysisW = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
1924 analysisH = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
1927 if (commentDialog) {
\r
1928 GetWindowPlacement(commentDialog, &wp);
\r
1929 commentX = wp.rcNormalPosition.left;
\r
1930 commentY = wp.rcNormalPosition.top;
\r
1931 commentW = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
1932 commentH = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
1935 if (editTagsDialog) {
\r
1936 GetWindowPlacement(editTagsDialog, &wp);
\r
1937 editTagsX = wp.rcNormalPosition.left;
\r
1938 editTagsY = wp.rcNormalPosition.top;
\r
1939 editTagsW = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
1940 editTagsH = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
1943 if (gameListDialog) {
\r
1944 GetWindowPlacement(gameListDialog, &wp);
\r
1945 gameListX = wp.rcNormalPosition.left;
\r
1946 gameListY = wp.rcNormalPosition.top;
\r
1947 gameListW = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
1948 gameListH = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
1951 for (ad = argDescriptors; ad->argName != NULL; ad++) {
\r
1952 if (!ad->save) continue;
\r
1953 switch (ad->argType) {
\r
1956 char *p = *(char **)ad->argLoc;
\r
1957 if ((strchr(p, '\\') || strchr(p, '\n')) && !strchr(p, '}')) {
\r
1958 /* Quote multiline values or \-containing values
\r
1959 with { } if possible */
\r
1960 fprintf(f, "/%s={%s}\n", ad->argName, p);
\r
1962 /* Else quote with " " */
\r
1963 fprintf(f, "/%s=\"", ad->argName);
\r
1965 if (*p == '\n') fprintf(f, "\n");
\r
1966 else if (*p == '\r') fprintf(f, "\\r");
\r
1967 else if (*p == '\t') fprintf(f, "\\t");
\r
1968 else if (*p == '\b') fprintf(f, "\\b");
\r
1969 else if (*p == '\f') fprintf(f, "\\f");
\r
1970 else if (*p < ' ') fprintf(f, "\\%03o", *p);
\r
1971 else if (*p == '\"') fprintf(f, "\\\"");
\r
1972 else if (*p == '\\') fprintf(f, "\\\\");
\r
1976 fprintf(f, "\"\n");
\r
1981 fprintf(f, "/%s=%d\n", ad->argName, *(int *)ad->argLoc);
\r
1984 fprintf(f, "/%s=%g\n", ad->argName, *(float *)ad->argLoc);
\r
1987 fprintf(f, "/%s=%s\n", ad->argName,
\r
1988 (*(Boolean *)ad->argLoc) ? "true" : "false");
\r
1991 if (*(Boolean *)ad->argLoc) fprintf(f, "/%s\n", ad->argName);
\r
1994 if (!*(Boolean *)ad->argLoc) fprintf(f, "/%s\n", ad->argName);
\r
1998 COLORREF color = *(COLORREF *)ad->argLoc;
\r
1999 fprintf(f, "/%s=#%02x%02x%02x\n", ad->argName,
\r
2000 color&0xff, (color>>8)&0xff, (color>>16)&0xff);
\r
2005 MyTextAttribs* ta = &textAttribs[(ColorClass)ad->argLoc];
\r
2006 fprintf(f, "/%s=\"%s%s%s%s%s#%02x%02x%02x\"\n", ad->argName,
\r
2007 (ta->effects & CFE_BOLD) ? "b" : "",
\r
2008 (ta->effects & CFE_ITALIC) ? "i" : "",
\r
2009 (ta->effects & CFE_UNDERLINE) ? "u" : "",
\r
2010 (ta->effects & CFE_STRIKEOUT) ? "s" : "",
\r
2011 (ta->effects) ? " " : "",
\r
2012 ta->color&0xff, (ta->color >> 8)&0xff, (ta->color >> 16)&0xff);
\r
2016 if (strchr(*(char **)ad->argLoc, '\"')) {
\r
2017 fprintf(f, "/%s='%s'\n", ad->argName, *(char **)ad->argLoc);
\r
2019 fprintf(f, "/%s=\"%s\"\n", ad->argName, *(char **)ad->argLoc);
\r
2022 case ArgBoardSize:
\r
2023 fprintf(f, "/%s=%s\n", ad->argName,
\r
2024 sizeInfo[*(BoardSize *)ad->argLoc].name);
\r
2029 for (bs=0; bs<NUM_SIZES; bs++) {
\r
2030 MyFontParams *mfp = &font[bs][(int) ad->argLoc]->mfp;
\r
2031 fprintf(f, "/size=%s ", sizeInfo[bs].name);
\r
2032 fprintf(f, "/%s=\"%s:%g%s%s%s%s%s\"\n",
\r
2033 ad->argName, mfp->faceName, mfp->pointSize,
\r
2034 mfp->bold || mfp->italic || mfp->underline || mfp->strikeout ? " " : "",
\r
2035 mfp->bold ? "b" : "",
\r
2036 mfp->italic ? "i" : "",
\r
2037 mfp->underline ? "u" : "",
\r
2038 mfp->strikeout ? "s" : "");
\r
2042 case ArgCommSettings:
\r
2043 PrintCommSettings(f, ad->argName, (DCB *)ad->argLoc);
\r
2051 /*---------------------------------------------------------------------------*\
\r
2053 * GDI board drawing routines
\r
2055 \*---------------------------------------------------------------------------*/
\r
2057 /* [AS] Draw square using background texture */
2058 static void DrawTile( int dx, int dy, int dw, int dh, HDC dst, HDC src, int mode, int sx, int sy )
2063 return; /* Should never happen! */
2066 SetGraphicsMode( dst, GM_ADVANCED );
2078 x.eDx = (FLOAT) dw + dx - 1;
2081 SetWorldTransform( dst, &x );
2090 x.eDy = (FLOAT) dh + dy - 1;
2092 SetWorldTransform( dst, &x );
2104 SetWorldTransform( dst, &x );
2108 BitBlt( dst, dx, dy, dw, dh, src, sx, sy, SRCCOPY );
2116 SetWorldTransform( dst, &x );
2118 ModifyWorldTransform( dst, 0, MWT_IDENTITY );
2137 static HFONT hPieceFont = NULL;
2138 static HBITMAP hPieceMask[12];
2139 static HBITMAP hPieceFace[12];
2140 static int fontBitmapSquareSize = 0;
2141 static char pieceToFontChar[12] = { 'p', 'n', 'b', 'r', 'q', 'k', 'o', 'm', 'v', 't', 'w', 'l' };
2143 static BOOL SetPieceToFontCharTable( const char * map )
2145 BOOL result = FALSE;
2147 if( map != NULL && strlen(map) == 12 ) {
2150 for( i=0; i<12; i++ ) {
2151 pieceToFontChar[i] = map[i];
2160 static void SetPieceBackground( HDC hdc, COLORREF color, int mode )
2163 BYTE r1 = GetRValue( color );
2164 BYTE g1 = GetGValue( color );
2165 BYTE b1 = GetBValue( color );
2171 /* Create a uniform background first */
2172 hbrush = CreateSolidBrush( color );
2173 SetRect( &rc, 0, 0, squareSize, squareSize );
2174 FillRect( hdc, &rc, hbrush );
2175 DeleteObject( hbrush );
2178 /* Vertical gradient, good for pawn, knight and rook, less for queen and king */
2179 int steps = squareSize / 2;
2182 for( i=0; i<steps; i++ ) {
2183 BYTE r = r1 - (r1-r2) * i / steps;
2184 BYTE g = g1 - (g1-g2) * i / steps;
2185 BYTE b = b1 - (b1-b2) * i / steps;
2187 hbrush = CreateSolidBrush( RGB(r,g,b) );
2188 SetRect( &rc, i + squareSize - steps, 0, i + squareSize - steps + 1, squareSize );
2189 FillRect( hdc, &rc, hbrush );
2190 DeleteObject(hbrush);
2193 else if( mode == 2 ) {
2194 /* Diagonal gradient, good more or less for every piece */
2196 HPEN hpen = SelectObject( hdc, GetStockObject(NULL_PEN) );
2198 int steps = squareSize;
2201 triangle[0].x = squareSize - steps;
2202 triangle[0].y = squareSize;
2203 triangle[1].x = squareSize;
2204 triangle[1].y = squareSize;
2205 triangle[2].x = squareSize;
2206 triangle[2].y = squareSize - steps;
2208 for( i=0; i<steps; i++ ) {
2209 BYTE r = r1 - (r1-r2) * i / steps;
2210 BYTE g = g1 - (g1-g2) * i / steps;
2211 BYTE b = b1 - (b1-b2) * i / steps;
2213 hbrush = CreateSolidBrush( RGB(r,g,b) );
2214 hbrush_old = SelectObject( hdc, hbrush );
2215 Polygon( hdc, triangle, 3 );
2216 SelectObject( hdc, hbrush_old );
2217 DeleteObject(hbrush);
2222 SelectObject( hdc, hpen );
2227 [AS] The method I use to create the bitmaps it a bit tricky, but it
2228 seems to work ok. The main problem here is to find the "inside" of a chess
2229 piece: follow the steps as explained below.
2231 static void CreatePieceMaskFromFont( HDC hdc_window, HDC hdc, int index )
2235 COLORREF chroma = RGB(0xFF,0x00,0xFF);
2239 int backColor = whitePieceColor;
2240 int foreColor = blackPieceColor;
2241 int shapeIndex = index < 6 ? index+6 : index;
2243 if( index < 6 && appData.fontBackColorWhite != appData.fontForeColorWhite ) {
2244 backColor = appData.fontBackColorWhite;
2245 foreColor = appData.fontForeColorWhite;
2247 else if( index >= 6 && appData.fontBackColorBlack != appData.fontForeColorBlack ) {
2248 backColor = appData.fontBackColorBlack;
2249 foreColor = appData.fontForeColorBlack;
2253 hbm = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
2255 hbm_old = SelectObject( hdc, hbm );
2259 rc.right = squareSize;
2260 rc.bottom = squareSize;
2262 /* Step 1: background is now black */
2263 FillRect( hdc, &rc, GetStockObject(BLACK_BRUSH) );
2265 GetTextExtentPoint32( hdc, &pieceToFontChar[index], 1, &sz );
2267 pt.x = (squareSize - sz.cx) / 2;
2268 pt.y = (squareSize - sz.cy) / 2;
2270 SetBkMode( hdc, TRANSPARENT );
2271 SetTextColor( hdc, chroma );
2272 /* Step 2: the piece has been drawn in purple, there are now black and purple in this bitmap */
2273 TextOut( hdc, pt.x, pt.y, &pieceToFontChar[index], 1 );
2275 SelectObject( hdc, GetStockObject(WHITE_BRUSH) );
2276 /* Step 3: the area outside the piece is filled with white */
2277 FloodFill( hdc, 0, 0, chroma );
2278 SelectObject( hdc, GetStockObject(BLACK_BRUSH) );
2280 Step 4: this is the tricky part, the area inside the piece is filled with black,
2281 but if the start point is not inside the piece we're lost!
2282 There should be a better way to do this... if we could create a region or path
2283 from the fill operation we would be fine for example.
2285 FloodFill( hdc, squareSize / 2, squareSize / 2, RGB(0xFF,0xFF,0xFF) );
2287 SetTextColor( hdc, 0 );
2289 Step 5: some fonts have "disconnected" areas that are skipped by the fill:
2290 draw the piece again in black for safety.
2292 TextOut( hdc, pt.x, pt.y, &pieceToFontChar[index], 1 );
2294 SelectObject( hdc, hbm_old );
2296 if( hPieceMask[index] != NULL ) {
2297 DeleteObject( hPieceMask[index] );
2300 hPieceMask[index] = hbm;
2303 hbm = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
2305 SelectObject( hdc, hbm );
2308 HDC dc1 = CreateCompatibleDC( hdc_window );
2309 HDC dc2 = CreateCompatibleDC( hdc_window );
2310 HBITMAP bm2 = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
2312 SelectObject( dc1, hPieceMask[index] );
2313 SelectObject( dc2, bm2 );
2314 FillRect( dc2, &rc, GetStockObject(WHITE_BRUSH) );
2315 BitBlt( dc2, 0, 0, squareSize, squareSize, dc1, 0, 0, SRCINVERT );
2318 Now dc2 contains the inverse of the piece mask, i.e. a mask that preserves
2319 the piece background and deletes (makes transparent) the rest.
2320 Thanks to that mask, we are free to paint the background with the greates
2321 freedom, as we'll be able to mask off the unwanted parts when finished.
2322 We use this, to make gradients and give the pieces a "roundish" look.
2324 SetPieceBackground( hdc, backColor, 2 );
2325 BitBlt( hdc, 0, 0, squareSize, squareSize, dc2, 0, 0, SRCAND );
2329 DeleteObject( bm2 );
2332 SetTextColor( hdc, foreColor );
2333 TextOut( hdc, pt.x, pt.y, &pieceToFontChar[index], 1 );
2335 SelectObject( hdc, hbm_old );
2337 hPieceFace[index] = hbm;
2340 static int TranslatePieceToFontPiece( int piece )
2372 void CreatePiecesFromFont()
2375 HDC hdc_window = NULL;
2381 if( fontBitmapSquareSize < 0 ) {
2382 /* Something went seriously wrong in the past: do not try to recreate fonts! */
2386 if( appData.renderPiecesWithFont == NULL || appData.renderPiecesWithFont[0] == NULLCHAR || appData.renderPiecesWithFont[0] == '*' ) {
2387 fontBitmapSquareSize = -1;
2391 if( fontBitmapSquareSize != squareSize ) {
2392 hdc_window = GetDC( hwndMain );
2393 hdc = CreateCompatibleDC( hdc_window );
2395 if( hPieceFont != NULL ) {
2396 DeleteObject( hPieceFont );
2399 for( i=0; i<12; i++ ) {
2400 hPieceMask[i] = NULL;
2406 if( appData.fontPieceSize >= 50 && appData.fontPieceSize <= 150 ) {
2407 fontHeight = appData.fontPieceSize;
2410 fontHeight = (fontHeight * squareSize) / 100;
2412 lf.lfHeight = -MulDiv( fontHeight, GetDeviceCaps(hdc, LOGPIXELSY), 72 );
2414 lf.lfEscapement = 0;
2415 lf.lfOrientation = 0;
2416 lf.lfWeight = FW_NORMAL;
2420 lf.lfCharSet = DEFAULT_CHARSET;
2421 lf.lfOutPrecision = OUT_DEFAULT_PRECIS;
2422 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
2423 lf.lfQuality = PROOF_QUALITY;
2424 lf.lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;
2425 strncpy( lf.lfFaceName, appData.renderPiecesWithFont, sizeof(lf.lfFaceName) );
2426 lf.lfFaceName[ sizeof(lf.lfFaceName) - 1 ] = '\0';
2428 hPieceFont = CreateFontIndirect( &lf );
2430 if( hPieceFont == NULL ) {
2431 fontBitmapSquareSize = -2;
2434 /* Setup font-to-piece character table */
2435 if( ! SetPieceToFontCharTable(appData.fontToPieceTable) ) {
2436 /* No (or wrong) global settings, try to detect the font */
2437 if( strstr(lf.lfFaceName,"Alpha") != NULL ) {
2439 SetPieceToFontCharTable("phbrqkojntwl");
2441 else if( strstr(lf.lfFaceName,"DiagramTT") != NULL ) {
2442 /* DiagramTT* family */
2443 SetPieceToFontCharTable("PNLRQKpnlrqk");
2446 /* Cases, Condal, Leipzig, Lucena, Marroquin, Merida, Usual */
2447 SetPieceToFontCharTable("pnbrqkomvtwl");
2451 /* Create bitmaps */
2452 hfont_old = SelectObject( hdc, hPieceFont );
2454 CreatePieceMaskFromFont( hdc_window, hdc, PM_WP );
2455 CreatePieceMaskFromFont( hdc_window, hdc, PM_WN );
2456 CreatePieceMaskFromFont( hdc_window, hdc, PM_WB );
2457 CreatePieceMaskFromFont( hdc_window, hdc, PM_WR );
2458 CreatePieceMaskFromFont( hdc_window, hdc, PM_WQ );
2459 CreatePieceMaskFromFont( hdc_window, hdc, PM_WK );
2460 CreatePieceMaskFromFont( hdc_window, hdc, PM_BP );
2461 CreatePieceMaskFromFont( hdc_window, hdc, PM_BN );
2462 CreatePieceMaskFromFont( hdc_window, hdc, PM_BB );
2463 CreatePieceMaskFromFont( hdc_window, hdc, PM_BR );
2464 CreatePieceMaskFromFont( hdc_window, hdc, PM_BQ );
2465 CreatePieceMaskFromFont( hdc_window, hdc, PM_BK );
2467 SelectObject( hdc, hfont_old );
2469 fontBitmapSquareSize = squareSize;
2477 if( hdc_window != NULL ) {
2478 ReleaseDC( hwndMain, hdc_window );
2483 DoLoadBitmap(HINSTANCE hinst, char *piece, int squareSize, char *suffix)
\r
2487 sprintf(name, "%s%d%s", piece, squareSize, suffix);
\r
2488 if (gameInfo.event &&
\r
2489 strcmp(gameInfo.event, "Easter Egg Hunt") == 0 &&
\r
2490 strcmp(name, "k80s") == 0) {
\r
2491 strcpy(name, "tim");
\r
2493 return LoadBitmap(hinst, name);
\r
2497 /* Insert a color into the program's logical palette
\r
2498 structure. This code assumes the given color is
\r
2499 the result of the RGB or PALETTERGB macro, and it
\r
2500 knows how those macros work (which is documented).
\r
2503 InsertInPalette(COLORREF color)
\r
2505 LPPALETTEENTRY pe = &(pLogPal->palPalEntry[pLogPal->palNumEntries]);
\r
2507 if (pLogPal->palNumEntries++ >= PALETTESIZE) {
\r
2508 DisplayFatalError("Too many colors", 0, 1);
\r
2509 pLogPal->palNumEntries--;
\r
2513 pe->peFlags = (char) 0;
\r
2514 pe->peRed = (char) (0xFF & color);
\r
2515 pe->peGreen = (char) (0xFF & (color >> 8));
\r
2516 pe->peBlue = (char) (0xFF & (color >> 16));
\r
2522 InitDrawingColors()
\r
2524 if (pLogPal == NULL) {
\r
2525 /* Allocate enough memory for a logical palette with
\r
2526 * PALETTESIZE entries and set the size and version fields
\r
2527 * of the logical palette structure.
\r
2529 pLogPal = (NPLOGPALETTE)
\r
2530 LocalAlloc(LMEM_FIXED, (sizeof(LOGPALETTE) +
\r
2531 (sizeof(PALETTEENTRY) * (PALETTESIZE))));
\r
2532 pLogPal->palVersion = 0x300;
\r
2534 pLogPal->palNumEntries = 0;
\r
2536 InsertInPalette(lightSquareColor);
\r
2537 InsertInPalette(darkSquareColor);
\r
2538 InsertInPalette(whitePieceColor);
\r
2539 InsertInPalette(blackPieceColor);
\r
2540 InsertInPalette(highlightSquareColor);
\r
2541 InsertInPalette(premoveHighlightColor);
\r
2543 /* create a logical color palette according the information
\r
2544 * in the LOGPALETTE structure.
\r
2546 hPal = CreatePalette((LPLOGPALETTE) pLogPal);
\r
2548 lightSquareBrush = CreateSolidBrush(lightSquareColor);
\r
2549 darkSquareBrush = CreateSolidBrush(darkSquareColor);
\r
2550 whitePieceBrush = CreateSolidBrush(whitePieceColor);
\r
2551 blackPieceBrush = CreateSolidBrush(blackPieceColor);
\r
2552 iconBkgndBrush = CreateSolidBrush(GetSysColor(COLOR_BACKGROUND));
\r
2554 /* [AS] Force rendering of the font-based pieces */
2555 if( fontBitmapSquareSize > 0 ) {
2556 fontBitmapSquareSize = 0;
2562 BoardWidth(int boardSize)
\r
2564 int lineGap = sizeInfo[boardSize].lineGap;
2566 if( appData.overrideLineGap >= 0 && appData.overrideLineGap <= 5 ) {
2567 lineGap = appData.overrideLineGap;
2570 return (BOARD_SIZE + 1) * lineGap +
2571 BOARD_SIZE * sizeInfo[boardSize].squareSize;
\r
2574 /* Respond to board resize by dragging edge */
\r
2576 ResizeBoard(int newSizeX, int newSizeY, int flags)
\r
2578 BoardSize newSize = NUM_SIZES - 1;
\r
2579 static int recurse = 0;
\r
2580 if (IsIconic(hwndMain)) return;
\r
2581 if (recurse > 0) return;
\r
2583 while (newSize > 0 &&
\r
2584 (newSizeX < sizeInfo[newSize].cliWidth ||
\r
2585 newSizeY < sizeInfo[newSize].cliHeight)) {
\r
2588 boardSize = newSize;
\r
2589 InitDrawingSizes(boardSize, flags);
\r
2596 InitDrawingSizes(BoardSize boardSize, int flags)
\r
2598 int i, boardWidth;
\r
2599 ChessSquare piece;
\r
2600 static int oldBoardSize = -1, oldTinyLayout = 0;
\r
2602 SIZE clockSize, messageSize;
\r
2604 char buf[MSG_SIZ];
\r
2606 HMENU hmenu = GetMenu(hwndMain);
\r
2607 RECT crect, wrect;
\r
2609 LOGBRUSH logbrush;
\r
2611 tinyLayout = sizeInfo[boardSize].tinyLayout;
\r
2612 smallLayout = sizeInfo[boardSize].smallLayout;
\r
2613 squareSize = sizeInfo[boardSize].squareSize;
\r
2614 lineGap = sizeInfo[boardSize].lineGap;
\r
2616 if( appData.overrideLineGap >= 0 && appData.overrideLineGap <= 5 ) {
2617 lineGap = appData.overrideLineGap;
2620 if (tinyLayout != oldTinyLayout) {
\r
2621 long style = GetWindowLong(hwndMain, GWL_STYLE);
\r
2623 style &= ~WS_SYSMENU;
\r
2624 InsertMenu(hmenu, IDM_Exit, MF_BYCOMMAND, IDM_Minimize,
\r
2625 "&Minimize\tCtrl+F4");
\r
2627 style |= WS_SYSMENU;
\r
2628 RemoveMenu(hmenu, IDM_Minimize, MF_BYCOMMAND);
\r
2630 SetWindowLong(hwndMain, GWL_STYLE, style);
\r
2632 for (i=0; menuBarText[tinyLayout][i]; i++) {
\r
2633 ModifyMenu(hmenu, i, MF_STRING|MF_BYPOSITION|MF_POPUP,
\r
2634 (UINT)GetSubMenu(hmenu, i), menuBarText[tinyLayout][i]);
\r
2636 DrawMenuBar(hwndMain);
\r
2639 boardWidth = BoardWidth(boardSize);
\r
2641 /* Get text area sizes */
\r
2642 hdc = GetDC(hwndMain);
\r
2643 if (appData.clockMode) {
\r
2644 sprintf(buf, "White: %s", TimeString(23*60*60*1000L));
\r
2646 sprintf(buf, "White");
\r
2648 oldFont = SelectObject(hdc, font[boardSize][CLOCK_FONT]->hf);
\r
2649 GetTextExtentPoint(hdc, buf, strlen(buf), &clockSize);
\r
2650 SelectObject(hdc, font[boardSize][MESSAGE_FONT]->hf);
\r
2651 str = "We only care about the height here";
\r
2652 GetTextExtentPoint(hdc, str, strlen(str), &messageSize);
\r
2653 SelectObject(hdc, oldFont);
\r
2654 ReleaseDC(hwndMain, hdc);
\r
2656 /* Compute where everything goes */
\r
2657 whiteRect.left = OUTER_MARGIN;
\r
2658 whiteRect.right = whiteRect.left + boardWidth/2 - INNER_MARGIN/2;
\r
2659 whiteRect.top = OUTER_MARGIN;
\r
2660 whiteRect.bottom = whiteRect.top + clockSize.cy;
\r
2662 blackRect.left = whiteRect.right + INNER_MARGIN;
\r
2663 blackRect.right = blackRect.left + boardWidth/2 - 1;
\r
2664 blackRect.top = whiteRect.top;
\r
2665 blackRect.bottom = whiteRect.bottom;
\r
2667 messageRect.left = whiteRect.left + MESSAGE_LINE_LEFTMARGIN;
\r
2668 if (appData.showButtonBar) {
\r
2669 messageRect.right = blackRect.right
\r
2670 - N_BUTTONS*BUTTON_WIDTH - MESSAGE_LINE_LEFTMARGIN;
\r
2672 messageRect.right = blackRect.right;
\r
2674 messageRect.top = whiteRect.bottom + INNER_MARGIN;
\r
2675 messageRect.bottom = messageRect.top + messageSize.cy;
\r
2677 boardRect.left = whiteRect.left;
\r
2678 boardRect.right = boardRect.left + boardWidth;
\r
2679 boardRect.top = messageRect.bottom + INNER_MARGIN;
\r
2680 boardRect.bottom = boardRect.top + boardWidth;
\r
2682 sizeInfo[boardSize].cliWidth = boardRect.right + OUTER_MARGIN;
\r
2683 sizeInfo[boardSize].cliHeight = boardRect.bottom + OUTER_MARGIN;
\r
2684 winWidth = 2 * GetSystemMetrics(SM_CXFRAME) + boardRect.right + OUTER_MARGIN;
\r
2685 winHeight = 2 * GetSystemMetrics(SM_CYFRAME) + GetSystemMetrics(SM_CYMENU) +
\r
2686 GetSystemMetrics(SM_CYCAPTION) + boardRect.bottom + OUTER_MARGIN;
\r
2687 GetWindowRect(hwndMain, &wrect);
\r
2688 SetWindowPos(hwndMain, NULL, 0, 0, winWidth, winHeight,
\r
2689 SWP_NOCOPYBITS|SWP_NOZORDER|SWP_NOMOVE);
\r
2690 /* compensate if menu bar wrapped */
\r
2691 GetClientRect(hwndMain, &crect);
\r
2692 offby = boardRect.bottom + OUTER_MARGIN - crect.bottom;
\r
2693 winHeight += offby;
\r
2695 case WMSZ_TOPLEFT:
\r
2696 SetWindowPos(hwndMain, NULL,
\r
2697 wrect.right - winWidth, wrect.bottom - winHeight,
\r
2698 winWidth, winHeight, SWP_NOCOPYBITS|SWP_NOZORDER);
\r
2701 case WMSZ_TOPRIGHT:
\r
2703 SetWindowPos(hwndMain, NULL,
\r
2704 wrect.left, wrect.bottom - winHeight,
\r
2705 winWidth, winHeight, SWP_NOCOPYBITS|SWP_NOZORDER);
\r
2708 case WMSZ_BOTTOMLEFT:
\r
2710 SetWindowPos(hwndMain, NULL,
\r
2711 wrect.right - winWidth, wrect.top,
\r
2712 winWidth, winHeight, SWP_NOCOPYBITS|SWP_NOZORDER);
\r
2715 case WMSZ_BOTTOMRIGHT:
\r
2719 SetWindowPos(hwndMain, NULL, 0, 0, winWidth, winHeight,
\r
2720 SWP_NOCOPYBITS|SWP_NOZORDER|SWP_NOMOVE);
\r
2725 for (i = 0; i < N_BUTTONS; i++) {
\r
2726 if (buttonDesc[i].hwnd != NULL) {
\r
2727 DestroyWindow(buttonDesc[i].hwnd);
\r
2728 buttonDesc[i].hwnd = NULL;
\r
2730 if (appData.showButtonBar) {
\r
2731 buttonDesc[i].hwnd =
\r
2732 CreateWindow("BUTTON", buttonDesc[i].label,
\r
2733 WS_VISIBLE | WS_CHILD | BS_PUSHBUTTON,
\r
2734 boardRect.right - BUTTON_WIDTH*(N_BUTTONS-i),
\r
2735 messageRect.top, BUTTON_WIDTH, messageSize.cy, hwndMain,
\r
2736 (HMENU) buttonDesc[i].id,
\r
2737 (HINSTANCE) GetWindowLong(hwndMain, GWL_HINSTANCE), NULL);
\r
2739 SendMessage(buttonDesc[i].hwnd, WM_SETFONT,
\r
2740 (WPARAM)font[boardSize][MESSAGE_FONT]->hf,
\r
2741 MAKELPARAM(FALSE, 0));
\r
2743 if (buttonDesc[i].id == IDM_Pause)
\r
2744 hwndPause = buttonDesc[i].hwnd;
\r
2745 buttonDesc[i].wndproc = (WNDPROC)
\r
2746 SetWindowLong(buttonDesc[i].hwnd, GWL_WNDPROC, (LONG) ButtonProc);
\r
2749 if (gridPen != NULL) DeleteObject(gridPen);
\r
2750 if (highlightPen != NULL) DeleteObject(highlightPen);
\r
2751 if (premovePen != NULL) DeleteObject(premovePen);
\r
2752 if (lineGap != 0) {
\r
2753 logbrush.lbStyle = BS_SOLID;
\r
2754 logbrush.lbColor = RGB(0, 0, 0); /* grid pen color = black */
\r
2756 ExtCreatePen(PS_GEOMETRIC|PS_SOLID|PS_ENDCAP_FLAT|PS_JOIN_MITER,
\r
2757 lineGap, &logbrush, 0, NULL);
\r
2758 logbrush.lbColor = highlightSquareColor;
\r
2760 ExtCreatePen(PS_GEOMETRIC|PS_SOLID|PS_ENDCAP_FLAT|PS_JOIN_MITER,
\r
2761 lineGap, &logbrush, 0, NULL);
\r
2763 logbrush.lbColor = premoveHighlightColor;
\r
2765 ExtCreatePen(PS_GEOMETRIC|PS_SOLID|PS_ENDCAP_FLAT|PS_JOIN_MITER,
\r
2766 lineGap, &logbrush, 0, NULL);
\r
2768 for (i = 0; i < BOARD_SIZE + 1; i++) {
\r
2769 gridEndpoints[i*2].x = boardRect.left + lineGap / 2;
\r
2770 gridEndpoints[i*2 + BOARD_SIZE*2 + 2].y = boardRect.top + lineGap / 2;
\r
2771 gridEndpoints[i*2].y = gridEndpoints[i*2 + 1].y =
\r
2772 boardRect.top + lineGap / 2 + (i * (squareSize + lineGap));
\r
2773 gridEndpoints[i*2 + 1].x = boardRect.left + lineGap / 2 +
\r
2774 BOARD_SIZE * (squareSize + lineGap);
\r
2775 gridEndpoints[i*2 + BOARD_SIZE*2 + 2].x =
\r
2776 gridEndpoints[i*2 + 1 + BOARD_SIZE*2 + 2].x = boardRect.left +
\r
2777 lineGap / 2 + (i * (squareSize + lineGap));
\r
2778 gridEndpoints[i*2 + 1 + BOARD_SIZE*2 + 2].y =
\r
2779 boardRect.top + BOARD_SIZE * (squareSize + lineGap);
\r
2780 gridVertexCounts[i*2] = gridVertexCounts[i*2 + 1] = 2;
\r
2784 if (boardSize == oldBoardSize) return;
\r
2785 oldBoardSize = boardSize;
\r
2786 oldTinyLayout = tinyLayout;
\r
2788 /* Load piece bitmaps for this board size */
\r
2789 for (i=0; i<=2; i++) {
\r
2790 for (piece = WhitePawn;
\r
2791 (int) piece <= (int) WhiteKing;
\r
2792 piece = (ChessSquare) ((int) piece + 1)) {
\r
2793 if (pieceBitmap[i][piece] != NULL)
\r
2794 DeleteObject(pieceBitmap[i][piece]);
\r
2798 pieceBitmap[0][WhitePawn] = DoLoadBitmap(hInst, "p", squareSize, "s");
\r
2799 pieceBitmap[0][WhiteKnight] = DoLoadBitmap(hInst, "n", squareSize, "s");
\r
2800 pieceBitmap[0][WhiteBishop] = DoLoadBitmap(hInst, "b", squareSize, "s");
\r
2801 pieceBitmap[0][WhiteRook] = DoLoadBitmap(hInst, "r", squareSize, "s");
\r
2802 pieceBitmap[0][WhiteQueen] = DoLoadBitmap(hInst, "q", squareSize, "s");
\r
2803 pieceBitmap[0][WhiteKing] = DoLoadBitmap(hInst, "k", squareSize, "s");
\r
2804 pieceBitmap[1][WhitePawn] = DoLoadBitmap(hInst, "p", squareSize, "o");
\r
2805 pieceBitmap[1][WhiteKnight] = DoLoadBitmap(hInst, "n", squareSize, "o");
\r
2806 pieceBitmap[1][WhiteBishop] = DoLoadBitmap(hInst, "b", squareSize, "o");
\r
2807 pieceBitmap[1][WhiteRook] = DoLoadBitmap(hInst, "r", squareSize, "o");
\r
2808 pieceBitmap[1][WhiteQueen] = DoLoadBitmap(hInst, "q", squareSize, "o");
\r
2809 pieceBitmap[1][WhiteKing] = DoLoadBitmap(hInst, "k", squareSize, "o");
\r
2810 pieceBitmap[2][WhitePawn] = DoLoadBitmap(hInst, "p", squareSize, "w");
\r
2811 pieceBitmap[2][WhiteKnight] = DoLoadBitmap(hInst, "n", squareSize, "w");
\r
2812 pieceBitmap[2][WhiteBishop] = DoLoadBitmap(hInst, "b", squareSize, "w");
\r
2813 pieceBitmap[2][WhiteRook] = DoLoadBitmap(hInst, "r", squareSize, "w");
\r
2814 pieceBitmap[2][WhiteQueen] = DoLoadBitmap(hInst, "q", squareSize, "w");
\r
2815 pieceBitmap[2][WhiteKing] = DoLoadBitmap(hInst, "k", squareSize, "w");
\r
2820 PieceBitmap(ChessSquare p, int kind)
\r
2822 if ((int) p >= (int) BlackPawn)
\r
2823 p = (ChessSquare) ((int) p - (int) BlackPawn + (int) WhitePawn);
\r
2825 return pieceBitmap[kind][(int) p];
\r
2828 /***************************************************************/
\r
2830 #define MIN(a,b) (((a) < (b)) ? (a) : (b))
\r
2831 #define MAX(a,b) (((a) > (b)) ? (a) : (b))
\r
2833 #define MIN3(a,b,c) (((a) < (b) && (a) < (c)) ? (a) : (((b) < (a) && (b) < (c)) ? (b) : (c)))
\r
2834 #define MAX3(a,b,c) (((a) > (b) && (a) > (c)) ? (a) : (((b) > (a) && (b) > (c)) ? (b) : (c)))
\r
2838 SquareToPos(int row, int column, int * x, int * y)
\r
2841 *x = boardRect.left + lineGap + ((BOARD_SIZE-1)-column) * (squareSize + lineGap);
\r
2842 *y = boardRect.top + lineGap + row * (squareSize + lineGap);
\r
2844 *x = boardRect.left + lineGap + column * (squareSize + lineGap);
\r
2845 *y = boardRect.top + lineGap + ((BOARD_SIZE-1)-row) * (squareSize + lineGap);
\r
2850 DrawCoordsOnDC(HDC hdc)
\r
2852 static char files[16] = {'1','2','3','4','5','6','7','8','8','7','6','5','4','3','2','1'};
\r
2853 static char ranks[16] = {'h','g','f','e','d','c','b','a','a','b','c','d','e','f','g','h'};
\r
2854 char str[2] = { NULLCHAR, NULLCHAR };
\r
2855 int oldMode, oldAlign, x, y, start, i;
\r
2859 if (!appData.showCoords)
\r
2862 start = flipView ? 0 : 8;
\r
2864 oldBrush = SelectObject(hdc, GetStockObject(BLACK_BRUSH));
\r
2865 oldMode = SetBkMode(hdc, (appData.monoMode ? OPAQUE : TRANSPARENT));
\r
2866 oldAlign = GetTextAlign(hdc);
\r
2867 oldFont = SelectObject(hdc, font[boardSize][COORD_FONT]->hf);
\r
2869 y = boardRect.top + lineGap;
\r
2870 x = boardRect.left + lineGap;
\r
2872 SetTextAlign(hdc, TA_LEFT|TA_TOP);
\r
2873 for (i = 0; i < 8; i++) {
\r
2874 str[0] = files[start + i];
\r
2875 ExtTextOut(hdc, x + 2, y + 1, 0, NULL, str, 1, NULL);
\r
2876 y += squareSize + lineGap;
\r
2879 SetTextAlign(hdc, TA_RIGHT|TA_BOTTOM);
\r
2880 for (i = 0; i < 8; i++) {
\r
2881 str[0] = ranks[start + i];
\r
2882 ExtTextOut(hdc, x + squareSize - 2, y - 1, 0, NULL, str, 1, NULL);
\r
2883 x += squareSize + lineGap;
\r
2886 SelectObject(hdc, oldBrush);
\r
2887 SetBkMode(hdc, oldMode);
\r
2888 SetTextAlign(hdc, oldAlign);
\r
2889 SelectObject(hdc, oldFont);
\r
2893 DrawGridOnDC(HDC hdc)
\r
2897 if (lineGap != 0) {
\r
2898 oldPen = SelectObject(hdc, gridPen);
\r
2899 PolyPolyline(hdc, gridEndpoints, gridVertexCounts, BOARD_SIZE*2 + 2);
\r
2900 SelectObject(hdc, oldPen);
\r
2904 #define HIGHLIGHT_PEN 0
\r
2905 #define PREMOVE_PEN 1
\r
2908 DrawHighlightOnDC(HDC hdc, BOOLEAN on, int x, int y, int pen)
\r
2911 HPEN oldPen, hPen;
\r
2912 if (lineGap == 0) return;
\r
2914 x1 = boardRect.left +
\r
2915 lineGap/2 + ((BOARD_SIZE-1)-x) * (squareSize + lineGap);
\r
2916 y1 = boardRect.top +
\r
2917 lineGap/2 + y * (squareSize + lineGap);
\r
2919 x1 = boardRect.left +
\r
2920 lineGap/2 + x * (squareSize + lineGap);
\r
2921 y1 = boardRect.top +
\r
2922 lineGap/2 + ((BOARD_SIZE-1)-y) * (squareSize + lineGap);
\r
2924 hPen = pen ? premovePen : highlightPen;
\r
2925 oldPen = SelectObject(hdc, on ? hPen : gridPen);
\r
2926 MoveToEx(hdc, x1, y1, NULL);
\r
2927 LineTo(hdc, x1 + squareSize + lineGap, y1);
\r
2928 LineTo(hdc, x1 + squareSize + lineGap, y1 + squareSize + lineGap);
\r
2929 LineTo(hdc, x1, y1 + squareSize + lineGap);
\r
2930 LineTo(hdc, x1, y1);
\r
2931 SelectObject(hdc, oldPen);
\r
2935 DrawHighlightsOnDC(HDC hdc)
\r
2938 for (i=0; i<2; i++) {
\r
2939 if (highlightInfo.sq[i].x >= 0 && highlightInfo.sq[i].y >= 0)
\r
2940 DrawHighlightOnDC(hdc, TRUE,
\r
2941 highlightInfo.sq[i].x, highlightInfo.sq[i].y,
\r
2944 for (i=0; i<2; i++) {
\r
2945 if (premoveHighlightInfo.sq[i].x >= 0 &&
\r
2946 premoveHighlightInfo.sq[i].y >= 0) {
\r
2947 DrawHighlightOnDC(hdc, TRUE,
\r
2948 premoveHighlightInfo.sq[i].x,
\r
2949 premoveHighlightInfo.sq[i].y,
\r
2955 /* Note: sqcolor is used only in monoMode */
\r
2956 /* Note that this code is largely duplicated in woptions.c,
\r
2957 function DrawSampleSquare, so that needs to be updated too */
\r
2959 DrawPieceOnDC(HDC hdc, ChessSquare piece, int color, int sqcolor, int x, int y, HDC tmphdc)
\r
2961 HBITMAP oldBitmap;
\r
2964 if (appData.blindfold) return;
\r
2966 /* [AS] Use font-based pieces if needed */
2967 if( fontBitmapSquareSize >= 0 && squareSize > 32 ) {
2968 /* Create piece bitmaps, or do nothing if piece set is up to data */
2969 CreatePiecesFromFont();
2971 if( fontBitmapSquareSize == squareSize ) {
2972 int index = TranslatePieceToFontPiece( piece );
2974 SelectObject( tmphdc, hPieceMask[ index ] );
2978 squareSize, squareSize,
2983 SelectObject( tmphdc, hPieceFace[ index ] );
2987 squareSize, squareSize,
2996 if (appData.monoMode) {
\r
2997 SelectObject(tmphdc, PieceBitmap(piece,
\r
2998 color == sqcolor ? OUTLINE_PIECE : SOLID_PIECE));
\r
2999 BitBlt(hdc, x, y, squareSize, squareSize, tmphdc, 0, 0,
\r
3000 sqcolor ? SRCCOPY : NOTSRCCOPY);
\r
3003 oldBitmap = SelectObject(tmphdc, PieceBitmap(piece, WHITE_PIECE));
\r
3004 oldBrush = SelectObject(hdc, whitePieceBrush);
\r
3005 BitBlt(hdc, x, y, squareSize, squareSize, tmphdc, 0, 0, 0x00B8074A);
\r
3007 /* Use black piece color for outline of white pieces */
\r
3008 /* Not sure this looks really good (though xboard does it).
\r
3009 Maybe better to have another selectable color, default black */
\r
3010 SelectObject(hdc, blackPieceBrush); /* could have own brush */
\r
3011 SelectObject(tmphdc, PieceBitmap(piece, OUTLINE_PIECE));
\r
3012 BitBlt(hdc, x, y, squareSize, squareSize, tmphdc, 0, 0, 0x00B8074A);
\r
3014 /* Use black for outline of white pieces */
\r
3015 SelectObject(tmphdc, PieceBitmap(piece, OUTLINE_PIECE));
\r
3016 BitBlt(hdc, x, y, squareSize, squareSize, tmphdc, 0, 0, SRCAND);
\r
3020 /* Use white piece color for details of black pieces */
\r
3021 /* Requires filled-in solid bitmaps (BLACK_PIECE class); the
\r
3022 WHITE_PIECE ones aren't always the right shape. */
\r
3023 /* Not sure this looks really good (though xboard does it).
\r
3024 Maybe better to have another selectable color, default medium gray? */
\r
3025 oldBitmap = SelectObject(tmphdc, PieceBitmap(piece, BLACK_PIECE));
\r
3026 oldBrush = SelectObject(hdc, whitePieceBrush); /* could have own brush */
\r
3027 BitBlt(hdc, x, y, squareSize, squareSize, tmphdc, 0, 0, 0x00B8074A);
\r
3028 SelectObject(tmphdc, PieceBitmap(piece, SOLID_PIECE));
\r
3029 SelectObject(hdc, blackPieceBrush);
\r
3030 BitBlt(hdc, x, y, squareSize, squareSize, tmphdc, 0, 0, 0x00B8074A);
\r
3032 /* Use square color for details of black pieces */
\r
3033 oldBitmap = SelectObject(tmphdc, PieceBitmap(piece, SOLID_PIECE));
\r
3034 oldBrush = SelectObject(hdc, blackPieceBrush);
\r
3035 BitBlt(hdc, x, y, squareSize, squareSize, tmphdc, 0, 0, 0x00B8074A);
\r
3038 SelectObject(hdc, oldBrush);
\r
3039 SelectObject(tmphdc, oldBitmap);
\r
3043 /* [AS] Compute a drawing mode for a square, based on specified settings (see DrawTile) */
3044 int GetBackTextureMode( int algo )
3046 int result = BACK_TEXTURE_MODE_DISABLED;
3050 case BACK_TEXTURE_MODE_PLAIN:
3051 result = 1; /* Always use identity map */
3053 case BACK_TEXTURE_MODE_FULL_RANDOM:
3054 result = 1 + (myrandom() % 3); /* Pick a transformation at random */
3062 [AS] Compute and save texture drawing info, otherwise we may not be able
3063 to handle redraws cleanly (as random numbers would always be different).
3065 VOID RebuildTextureSquareInfo()
3075 ZeroMemory( &backTextureSquareInfo, sizeof(backTextureSquareInfo) );
3077 if( liteBackTexture != NULL ) {
3078 if( GetObject( liteBackTexture, sizeof(bi), &bi ) > 0 ) {
3079 lite_w = bi.bmWidth;
3080 lite_h = bi.bmHeight;
3084 if( darkBackTexture != NULL ) {
3085 if( GetObject( darkBackTexture, sizeof(bi), &bi ) > 0 ) {
3086 dark_w = bi.bmWidth;
3087 dark_h = bi.bmHeight;
3091 for( row=0; row<BOARD_SIZE; row++ ) {
3092 for( col=0; col<BOARD_SIZE; col++ ) {
3093 if( (col + row) & 1 ) {
3095 if( lite_w >= squareSize && lite_h >= squareSize ) {
3096 backTextureSquareInfo[row][col].x = col * (lite_w - squareSize) / BOARD_SIZE;
3097 backTextureSquareInfo[row][col].y = row * (lite_h - squareSize) / BOARD_SIZE;
3098 backTextureSquareInfo[row][col].mode = GetBackTextureMode(liteBackTextureMode);
3103 if( dark_w >= squareSize && dark_h >= squareSize ) {
3104 backTextureSquareInfo[row][col].x = col * (dark_w - squareSize) / BOARD_SIZE;
3105 backTextureSquareInfo[row][col].y = row * (dark_h - squareSize) / BOARD_SIZE;
3106 backTextureSquareInfo[row][col].mode = GetBackTextureMode(darkBackTextureMode);
3114 DrawBoardOnDC(HDC hdc, Board board, HDC tmphdc)
\r
3116 int row, column, x, y, square_color, piece_color;
\r
3117 ChessSquare piece;
\r
3119 HDC texture_hdc = NULL;
3121 /* [AS] Initialize background textures if needed */
3122 if( liteBackTexture != NULL || darkBackTexture != NULL ) {
3123 if( backTextureSquareSize != squareSize ) {
3124 backTextureSquareSize = squareSize;
3125 RebuildTextureSquareInfo();
3128 texture_hdc = CreateCompatibleDC( hdc );
3131 for (row = 0; row < BOARD_SIZE; row++) {
\r
3132 for (column = 0; column < BOARD_SIZE; column++) {
\r
3134 SquareToPos(row, column, &x, &y);
\r
3136 piece = board[row][column];
\r
3138 square_color = ((column + row) % 2) == 1;
\r
3139 piece_color = (int) piece < (int) BlackPawn;
\r
3141 if (appData.monoMode) {
\r
3142 if (piece == EmptySquare) {
\r
3143 BitBlt(hdc, x, y, squareSize, squareSize, 0, 0, 0,
\r
3144 square_color ? WHITENESS : BLACKNESS);
\r
3146 DrawPieceOnDC(hdc, piece, piece_color, square_color, x, y, tmphdc);
\r
3149 else if( backTextureSquareInfo[row][column].mode > 0 ) {
3150 /* [AS] Draw the square using a texture bitmap */
3151 HBITMAP hbm = SelectObject( texture_hdc, square_color ? liteBackTexture : darkBackTexture );
3154 squareSize, squareSize,
3157 backTextureSquareInfo[row][column].mode,
3158 backTextureSquareInfo[row][column].x,
3159 backTextureSquareInfo[row][column].y );
3161 SelectObject( texture_hdc, hbm );
3163 if (piece != EmptySquare) {
3164 DrawPieceOnDC(hdc, piece, piece_color, -1, x, y, tmphdc);
3168 oldBrush = SelectObject(hdc, square_color ?
\r
3169 lightSquareBrush : darkSquareBrush);
\r
3170 BitBlt(hdc, x, y, squareSize, squareSize, 0, 0, 0, PATCOPY);
\r
3171 SelectObject(hdc, oldBrush);
\r
3172 if (piece != EmptySquare)
\r
3173 DrawPieceOnDC(hdc, piece, piece_color, -1, x, y, tmphdc);
\r
3178 if( texture_hdc != NULL ) {
3179 DeleteDC( texture_hdc );
3183 #define MAX_CLIPS 200 /* more than enough */
\r
3186 HDCDrawPosition(HDC hdc, BOOLEAN repaint, Board board)
\r
3188 static Board lastReq, lastDrawn;
\r
3189 static HighlightInfo lastDrawnHighlight, lastDrawnPremove;
\r
3190 static int lastDrawnFlipView = 0;
\r
3191 static int lastReqValid = 0, lastDrawnValid = 0;
\r
3192 int releaseDC, x, y, x2, y2, row, column, num_clips = 0, i;
\r
3195 HBITMAP bufferBitmap;
\r
3196 HBITMAP oldBitmap;
\r
3198 HRGN clips[MAX_CLIPS];
\r
3199 ChessSquare dragged_piece = EmptySquare;
\r
3201 /* I'm undecided on this - this function figures out whether a full
\r
3202 * repaint is necessary on its own, so there's no real reason to have the
\r
3203 * caller tell it that. I think this can safely be set to FALSE - but
\r
3204 * if we trust the callers not to request full repaints unnessesarily, then
\r
3205 * we could skip some clipping work. In other words, only request a full
\r
3206 * redraw when the majority of pieces have changed positions (ie. flip,
\r
3207 * gamestart and similar) --Hawk
\r
3209 Boolean fullrepaint = repaint;
\r
3211 if (board == NULL) {
\r
3212 if (!lastReqValid) {
\r
3217 CopyBoard(lastReq, board);
\r
3221 if (doingSizing) {
\r
3225 if (IsIconic(hwndMain)) {
\r
3229 if (hdc == NULL) {
\r
3230 hdc = GetDC(hwndMain);
\r
3231 if (!appData.monoMode) {
\r
3232 SelectPalette(hdc, hPal, FALSE);
\r
3233 RealizePalette(hdc);
\r
3237 releaseDC = FALSE;
\r
3241 fprintf(debugFP, "*******************************\n"
\r
3243 "dragInfo.from (%d,%d)\n"
\r
3244 "dragInfo.start (%d,%d)\n"
\r
3245 "dragInfo.pos (%d,%d)\n"
\r
3246 "dragInfo.lastpos (%d,%d)\n",
\r
3247 repaint ? "TRUE" : "FALSE",
\r
3248 dragInfo.from.x, dragInfo.from.y,
\r
3249 dragInfo.start.x, dragInfo.start.y,
\r
3250 dragInfo.pos.x, dragInfo.pos.y,
\r
3251 dragInfo.lastpos.x, dragInfo.lastpos.y);
\r
3252 fprintf(debugFP, "prev: ");
\r
3253 for (row = 0; row < 8; row++) {
\r
3254 for (column = 0; column < 8; column++) {
\r
3255 fprintf(debugFP, "%d ", lastDrawn[row][column]);
\r
3258 fprintf(debugFP, "\n");
\r
3259 fprintf(debugFP, "board: ");
\r
3260 for (row = 0; row < 8; row++) {
\r
3261 for (column = 0; column < 8; column++) {
\r
3262 fprintf(debugFP, "%d ", board[row][column]);
\r
3265 fprintf(debugFP, "\n");
\r
3269 /* Create some work-DCs */
\r
3270 hdcmem = CreateCompatibleDC(hdc);
\r
3271 tmphdc = CreateCompatibleDC(hdc);
\r
3273 /* Figure out which squares need updating by comparing the
\r
3274 * newest board with the last drawn board and checking if
\r
3275 * flipping has changed.
\r
3277 if (!fullrepaint && lastDrawnValid && lastDrawnFlipView == flipView) {
\r
3278 for (row = 0; row < 8; row++) {
\r
3279 for (column = 0; column < 8; column++) {
\r
3280 if (lastDrawn[row][column] != board[row][column]) {
\r
3281 SquareToPos(row, column, &x, &y);
\r
3282 clips[num_clips++] =
\r
3283 CreateRectRgn(x, y, x + squareSize, y + squareSize);
\r
3287 for (i=0; i<2; i++) {
\r
3288 if (lastDrawnHighlight.sq[i].x != highlightInfo.sq[i].x ||
\r
3289 lastDrawnHighlight.sq[i].y != highlightInfo.sq[i].y) {
\r
3290 if (lastDrawnHighlight.sq[i].x >= 0 &&
\r
3291 lastDrawnHighlight.sq[i].y >= 0) {
\r
3292 SquareToPos(lastDrawnHighlight.sq[i].y,
\r
3293 lastDrawnHighlight.sq[i].x, &x, &y);
\r
3294 clips[num_clips++] =
\r
3295 CreateRectRgn(x - lineGap, y - lineGap,
\r
3296 x + squareSize + lineGap, y + squareSize + lineGap);
\r
3298 if (highlightInfo.sq[i].x >= 0 && highlightInfo.sq[i].y >= 0) {
\r
3299 SquareToPos(highlightInfo.sq[i].y, highlightInfo.sq[i].x, &x, &y);
\r
3300 clips[num_clips++] =
\r
3301 CreateRectRgn(x - lineGap, y - lineGap,
\r
3302 x + squareSize + lineGap, y + squareSize + lineGap);
\r
3306 for (i=0; i<2; i++) {
\r
3307 if (lastDrawnPremove.sq[i].x != premoveHighlightInfo.sq[i].x ||
\r
3308 lastDrawnPremove.sq[i].y != premoveHighlightInfo.sq[i].y) {
\r
3309 if (lastDrawnPremove.sq[i].x >= 0 &&
\r
3310 lastDrawnPremove.sq[i].y >= 0) {
\r
3311 SquareToPos(lastDrawnPremove.sq[i].y,
\r
3312 lastDrawnPremove.sq[i].x, &x, &y);
\r
3313 clips[num_clips++] =
\r
3314 CreateRectRgn(x - lineGap, y - lineGap,
\r
3315 x + squareSize + lineGap, y + squareSize + lineGap);
\r
3317 if (premoveHighlightInfo.sq[i].x >= 0 &&
\r
3318 premoveHighlightInfo.sq[i].y >= 0) {
\r
3319 SquareToPos(premoveHighlightInfo.sq[i].y,
\r
3320 premoveHighlightInfo.sq[i].x, &x, &y);
\r
3321 clips[num_clips++] =
\r
3322 CreateRectRgn(x - lineGap, y - lineGap,
\r
3323 x + squareSize + lineGap, y + squareSize + lineGap);
\r
3328 fullrepaint = TRUE;
\r
3331 /* Create a buffer bitmap - this is the actual bitmap
\r
3332 * being written to. When all the work is done, we can
\r
3333 * copy it to the real DC (the screen). This avoids
\r
3334 * the problems with flickering.
\r
3336 GetClientRect(hwndMain, &Rect);
\r
3337 bufferBitmap = CreateCompatibleBitmap(hdc, Rect.right-Rect.left+1,
\r
3338 Rect.bottom-Rect.top+1);
\r
3339 oldBitmap = SelectObject(hdcmem, bufferBitmap);
\r
3340 if (!appData.monoMode) {
\r
3341 SelectPalette(hdcmem, hPal, FALSE);
\r
3344 /* Create clips for dragging */
\r
3345 if (!fullrepaint) {
\r
3346 if (dragInfo.from.x >= 0) {
\r
3347 SquareToPos(dragInfo.from.y, dragInfo.from.x, &x, &y);
\r
3348 clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);
\r
3350 if (dragInfo.start.x >= 0) {
\r
3351 SquareToPos(dragInfo.start.y, dragInfo.start.x, &x, &y);
\r
3352 clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);
\r
3354 if (dragInfo.pos.x >= 0) {
\r
3355 x = dragInfo.pos.x - squareSize / 2;
\r
3356 y = dragInfo.pos.y - squareSize / 2;
\r
3357 clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);
\r
3359 if (dragInfo.lastpos.x >= 0) {
\r
3360 x = dragInfo.lastpos.x - squareSize / 2;
\r
3361 y = dragInfo.lastpos.y - squareSize / 2;
\r
3362 clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);
\r
3366 /* If dragging is in progress, we temporarely remove the piece */
\r
3367 if (dragInfo.from.x >= 0 && dragInfo.pos.x >= 0) {
\r
3368 dragged_piece = board[dragInfo.from.y][dragInfo.from.x];
\r
3369 board[dragInfo.from.y][dragInfo.from.x] = EmptySquare;
\r
3372 /* Are we animating a move?
\r
3374 * - remove the piece from the board (temporarely)
\r
3375 * - calculate the clipping region
\r
3377 if (!fullrepaint) {
\r
3378 if (animInfo.piece != EmptySquare) {
\r
3379 board[animInfo.from.y][animInfo.from.x] = EmptySquare;
\r
3380 x = boardRect.left + animInfo.lastpos.x;
\r
3381 y = boardRect.top + animInfo.lastpos.y;
\r
3382 x2 = boardRect.left + animInfo.pos.x;
\r
3383 y2 = boardRect.top + animInfo.pos.y;
\r
3384 clips[num_clips++] = CreateRectRgn(MIN(x,x2), MIN(y,y2), MAX(x,x2)+squareSize, MAX(y,y2)+squareSize);
\r
3385 /* Slight kludge. The real problem is that after AnimateMove is
\r
3386 done, the position on the screen does not match lastDrawn.
\r
3387 This currently causes trouble only on e.p. captures in
\r
3388 atomic, where the piece moves to an empty square and then
\r
3389 explodes. The old and new positions both had an empty square
\r
3390 at the destination, but animation has drawn a piece there and
\r
3391 we have to remember to erase it. */
\r
3392 lastDrawn[animInfo.to.y][animInfo.to.x] = animInfo.piece;
\r
3396 /* No clips? Make sure we have fullrepaint set to TRUE */
\r
3397 if (num_clips == 0)
\r
3398 fullrepaint = TRUE;
\r
3400 /* Set clipping on the memory DC */
\r
3401 if (!fullrepaint) {
\r
3402 SelectClipRgn(hdcmem, clips[0]);
\r
3403 for (x = 1; x < num_clips; x++) {
\r
3404 if (ExtSelectClipRgn(hdcmem, clips[x], RGN_OR) == ERROR)
\r
3405 abort(); // this should never ever happen!
\r
3409 /* Do all the drawing to the memory DC */
\r
3410 DrawGridOnDC(hdcmem);
\r
3411 DrawHighlightsOnDC(hdcmem);
\r
3412 DrawBoardOnDC(hdcmem, board, tmphdc);
\r
3413 DrawCoordsOnDC(hdcmem);
\r
3415 /* Put the dragged piece back into place and draw it */
\r
3416 if (dragged_piece != EmptySquare) {
\r
3417 board[dragInfo.from.y][dragInfo.from.x] = dragged_piece;
\r
3418 x = dragInfo.pos.x - squareSize / 2;
\r
3419 y = dragInfo.pos.y - squareSize / 2;
\r
3420 DrawPieceOnDC(hdcmem, dragged_piece,
\r
3421 ((int) dragged_piece < (int) BlackPawn),
\r
3422 (dragInfo.from.y + dragInfo.from.x) % 2, x, y, tmphdc);
\r
3425 /* Put the animated piece back into place and draw it */
\r
3426 if (animInfo.piece != EmptySquare) {
\r
3427 board[animInfo.from.y][animInfo.from.x] = animInfo.piece;
\r
3428 x = boardRect.left + animInfo.pos.x;
\r
3429 y = boardRect.top + animInfo.pos.y;
\r
3430 DrawPieceOnDC(hdcmem, animInfo.piece,
\r
3431 ((int) animInfo.piece < (int) BlackPawn),
\r
3432 (animInfo.from.y + animInfo.from.x) % 2, x, y, tmphdc);
\r
3435 /* Release the bufferBitmap by selecting in the old bitmap
\r
3436 * and delete the memory DC
\r
3438 SelectObject(hdcmem, oldBitmap);
\r
3441 /* Set clipping on the target DC */
\r
3442 if (!fullrepaint) {
\r
3443 SelectClipRgn(hdc, clips[0]);
\r
3444 for (x = 1; x < num_clips; x++) {
\r
3445 if (ExtSelectClipRgn(hdc, clips[x], RGN_OR) == ERROR)
\r
3446 abort(); // this should never ever happen!
\r
3450 /* Copy the new bitmap onto the screen in one go.
\r
3451 * This way we avoid any flickering
\r
3453 oldBitmap = SelectObject(tmphdc, bufferBitmap);
\r
3454 BitBlt(hdc, boardRect.left, boardRect.top,
\r
3455 boardRect.right - boardRect.left,
\r
3456 boardRect.bottom - boardRect.top,
\r
3457 tmphdc, boardRect.left, boardRect.top, SRCCOPY);
\r
3458 SelectObject(tmphdc, oldBitmap);
\r
3460 /* Massive cleanup */
\r
3461 for (x = 0; x < num_clips; x++)
\r
3462 DeleteObject(clips[x]);
\r
3465 DeleteObject(bufferBitmap);
\r
3468 ReleaseDC(hwndMain, hdc);
\r
3470 if (lastDrawnFlipView != flipView) {
\r
3472 CheckMenuItem(GetMenu(hwndMain),IDM_FlipView, MF_BYCOMMAND|MF_CHECKED);
\r
3474 CheckMenuItem(GetMenu(hwndMain),IDM_FlipView, MF_BYCOMMAND|MF_UNCHECKED);
\r
3477 CopyBoard(lastDrawn, board);
\r
3478 lastDrawnHighlight = highlightInfo;
\r
3479 lastDrawnPremove = premoveHighlightInfo;
\r
3480 lastDrawnFlipView = flipView;
\r
3481 lastDrawnValid = 1;
\r
3485 /*---------------------------------------------------------------------------*\
\r
3486 | CLIENT PAINT PROCEDURE
\r
3487 | This is the main event-handler for the WM_PAINT message.
\r
3489 \*---------------------------------------------------------------------------*/
\r
3491 PaintProc(HWND hwnd)
\r
3497 if(hdc = BeginPaint(hwnd, &ps)) {
\r
3498 if (IsIconic(hwnd)) {
\r
3499 DrawIcon(hdc, 2, 2, iconCurrent);
\r
3501 if (!appData.monoMode) {
\r
3502 SelectPalette(hdc, hPal, FALSE);
\r
3503 RealizePalette(hdc);
\r
3505 HDCDrawPosition(hdc, 1, NULL);
\r
3507 SelectObject(hdc, font[boardSize][MESSAGE_FONT]->hf);
\r
3508 ExtTextOut(hdc, messageRect.left, messageRect.top,
\r
3509 ETO_CLIPPED|ETO_OPAQUE,
\r
3510 &messageRect, messageText, strlen(messageText), NULL);
\r
3511 SelectObject(hdc, oldFont);
\r
3512 DisplayBothClocks();
\r
3514 EndPaint(hwnd,&ps);
\r
3522 * If the user selects on a border boundary, return -1; if off the board,
\r
3523 * return -2. Otherwise map the event coordinate to the square.
\r
3524 * The offset boardRect.left or boardRect.top must already have been
\r
3525 * subtracted from x.
\r
3528 EventToSquare(int x)
\r
3535 if ((x % (squareSize + lineGap)) >= squareSize)
\r
3537 x /= (squareSize + lineGap);
\r
3538 if (x >= BOARD_SIZE)
\r
3549 DropEnable dropEnables[] = {
\r
3550 { 'P', DP_Pawn, "Pawn" },
\r
3551 { 'N', DP_Knight, "Knight" },
\r
3552 { 'B', DP_Bishop, "Bishop" },
\r
3553 { 'R', DP_Rook, "Rook" },
\r
3554 { 'Q', DP_Queen, "Queen" },
\r
3558 SetupDropMenu(HMENU hmenu)
\r
3560 int i, count, enable;
\r
3562 extern char white_holding[], black_holding[];
\r
3563 char item[MSG_SIZ];
\r
3565 for (i=0; i<sizeof(dropEnables)/sizeof(DropEnable); i++) {
\r
3566 p = strchr(gameMode == IcsPlayingWhite ? white_holding : black_holding,
\r
3567 dropEnables[i].piece);
\r
3569 while (p && *p++ == dropEnables[i].piece) count++;
\r
3570 sprintf(item, "%s %d", dropEnables[i].name, count);
\r
3571 enable = count > 0 || !appData.testLegality
\r
3572 /*!!temp:*/ || (gameInfo.variant == VariantCrazyhouse
\r
3573 && !appData.icsActive);
\r
3574 ModifyMenu(hmenu, dropEnables[i].command,
\r
3575 MF_BYCOMMAND | (enable ? MF_ENABLED : MF_GRAYED) | MF_STRING,
\r
3576 dropEnables[i].command, item);
\r
3580 static int fromX = -1, fromY = -1, toX, toY;
\r
3582 /* Event handler for mouse messages */
\r
3584 MouseEvent(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
3588 static int recursive = 0;
\r
3590 BOOLEAN saveAnimate;
\r
3591 static BOOLEAN sameAgain = FALSE;
\r
3594 if (message == WM_MBUTTONUP) {
\r
3595 /* Hideous kludge to fool TrackPopupMenu into paying attention
\r
3596 to the middle button: we simulate pressing the left button too!
\r
3598 PostMessage(hwnd, WM_LBUTTONDOWN, wParam, lParam);
\r
3599 PostMessage(hwnd, WM_LBUTTONUP, wParam, lParam);
\r
3605 pt.x = LOWORD(lParam);
\r
3606 pt.y = HIWORD(lParam);
\r
3607 x = EventToSquare(pt.x - boardRect.left);
\r
3608 y = EventToSquare(pt.y - boardRect.top);
\r
3609 if (!flipView && y >= 0) {
\r
3610 y = BOARD_SIZE - 1 - y;
\r
3612 if (flipView && x >= 0) {
\r
3613 x = BOARD_SIZE - 1 - x;
\r
3616 switch (message) {
\r
3617 case WM_LBUTTONDOWN:
\r
3619 sameAgain = FALSE;
\r
3621 /* Downclick vertically off board; check if on clock */
\r
3622 if (PtInRect((LPRECT) &whiteRect, pt)) {
\r
3623 if (gameMode == EditPosition) {
\r
3624 SetWhiteToPlayEvent();
\r
3625 } else if (gameMode == IcsPlayingBlack ||
\r
3626 gameMode == MachinePlaysWhite) {
\r
3629 } else if (PtInRect((LPRECT) &blackRect, pt)) {
\r
3630 if (gameMode == EditPosition) {
\r
3631 SetBlackToPlayEvent();
\r
3632 } else if (gameMode == IcsPlayingWhite ||
\r
3633 gameMode == MachinePlaysBlack) {
\r
3637 if (!appData.highlightLastMove) {
\r
3638 ClearHighlights();
\r
3639 DrawPosition(FALSE, NULL);
\r
3641 fromX = fromY = -1;
\r
3642 dragInfo.start.x = dragInfo.start.y = -1;
\r
3643 dragInfo.from = dragInfo.start;
\r
3645 } else if (x < 0 || y < 0) {
\r
3647 } else if (fromX == x && fromY == y) {
\r
3648 /* Downclick on same square again */
\r
3649 ClearHighlights();
\r
3650 DrawPosition(FALSE, NULL);
\r
3651 sameAgain = TRUE;
\r
3652 } else if (fromX != -1) {
\r
3653 /* Downclick on different square */
\r
3654 ChessSquare pdown, pup;
\r
3655 pdown = boards[currentMove][fromY][fromX];
\r
3656 pup = boards[currentMove][y][x];
\r
3657 if (gameMode == EditPosition ||
\r
3658 !((WhitePawn <= pdown && pdown <= WhiteKing &&
\r
3659 WhitePawn <= pup && pup <= WhiteKing) ||
\r
3660 (BlackPawn <= pdown && pdown <= BlackKing &&
\r
3661 BlackPawn <= pup && pup <= BlackKing))) {
\r
3662 /* EditPosition, empty square, or different color piece;
\r
3663 click-click move is possible */
\r
3666 if (IsPromotion(fromX, fromY, toX, toY)) {
\r
3667 if (appData.alwaysPromoteToQueen) {
\r
3668 UserMoveEvent(fromX, fromY, toX, toY, 'q');
\r
3669 if (!appData.highlightLastMove) {
\r
3670 ClearHighlights();
\r
3671 DrawPosition(FALSE, NULL);
\r
3674 SetHighlights(fromX, fromY, toX, toY);
\r
3675 DrawPosition(FALSE, NULL);
\r
3676 PromotionPopup(hwnd);
\r
3678 } else { /* not a promotion */
\r
3679 if (appData.animate || appData.highlightLastMove) {
\r
3680 SetHighlights(fromX, fromY, toX, toY);
\r
3682 ClearHighlights();
\r
3684 UserMoveEvent(fromX, fromY, toX, toY, NULLCHAR);
\r
3685 if (appData.animate && !appData.highlightLastMove) {
\r
3686 ClearHighlights();
\r
3687 DrawPosition(FALSE, NULL);
\r
3690 if (gotPremove) SetPremoveHighlights(fromX, fromY, toX, toY);
\r
3691 fromX = fromY = -1;
\r
3694 ClearHighlights();
\r
3695 DrawPosition(FALSE, NULL);
\r
3697 /* First downclick, or restart on a square with same color piece */
\r
3698 if (!frozen && OKToStartUserMove(x, y)) {
\r
3701 dragInfo.lastpos = pt;
\r
3702 dragInfo.from.x = fromX;
\r
3703 dragInfo.from.y = fromY;
\r
3704 dragInfo.start = dragInfo.from;
\r
3705 SetCapture(hwndMain);
\r
3707 fromX = fromY = -1;
\r
3708 dragInfo.start.x = dragInfo.start.y = -1;
\r
3709 dragInfo.from = dragInfo.start;
\r
3713 case WM_LBUTTONUP:
\r
3715 if (fromX == -1) break;
\r
3716 if (x == fromX && y == fromY) {
\r
3717 dragInfo.from.x = dragInfo.from.y = -1;
\r
3718 /* Upclick on same square */
\r
3720 /* Clicked same square twice: abort click-click move */
\r
3721 fromX = fromY = -1;
\r
3723 ClearPremoveHighlights();
\r
3725 /* First square clicked: start click-click move */
\r
3726 SetHighlights(fromX, fromY, -1, -1);
\r
3728 DrawPosition(FALSE, NULL);
\r
3729 } else if (dragInfo.from.x < 0 || dragInfo.from.y < 0) {
\r
3730 /* Errant click; ignore */
\r
3733 /* Finish drag move */
\r
3734 dragInfo.from.x = dragInfo.from.y = -1;
\r
3737 saveAnimate = appData.animate; /* sorry, Hawk :) */
\r
3738 appData.animate = appData.animate && !appData.animateDragging;
\r
3739 if (IsPromotion(fromX, fromY, toX, toY)) {
\r
3740 if (appData.alwaysPromoteToQueen) {
\r
3741 UserMoveEvent(fromX, fromY, toX, toY, 'q');
\r
3743 DrawPosition(FALSE, NULL);
\r
3744 PromotionPopup(hwnd);
\r
3747 UserMoveEvent(fromX, fromY, toX, toY, NULLCHAR);
\r
3749 if (gotPremove) SetPremoveHighlights(fromX, fromY, toX, toY);
\r
3750 appData.animate = saveAnimate;
\r
3751 fromX = fromY = -1;
\r
3752 if (appData.highlightDragging && !appData.highlightLastMove) {
\r
3753 ClearHighlights();
\r
3755 if (appData.animate || appData.animateDragging ||
\r
3756 appData.highlightDragging || gotPremove) {
\r
3757 DrawPosition(FALSE, NULL);
\r
3760 dragInfo.start.x = dragInfo.start.y = -1;
\r
3761 dragInfo.pos = dragInfo.lastpos = dragInfo.start;
\r
3764 case WM_MOUSEMOVE:
\r
3765 if ((appData.animateDragging || appData.highlightDragging)
\r
3766 && (wParam & MK_LBUTTON)
\r
3767 && dragInfo.from.x >= 0) {
\r
3768 if (appData.animateDragging) {
\r
3769 dragInfo.pos = pt;
\r
3771 if (appData.highlightDragging) {
\r
3772 SetHighlights(fromX, fromY, x, y);
\r
3774 DrawPosition(FALSE, NULL);
\r
3775 dragInfo.lastpos = dragInfo.pos;
\r
3779 case WM_MBUTTONDOWN:
\r
3780 case WM_RBUTTONDOWN:
\r
3783 fromX = fromY = -1;
\r
3784 dragInfo.pos.x = dragInfo.pos.y = -1;
\r
3785 dragInfo.start.x = dragInfo.start.y = -1;
\r
3786 dragInfo.from = dragInfo.start;
\r
3787 dragInfo.lastpos = dragInfo.pos;
\r
3788 if (appData.highlightDragging) {
\r
3789 ClearHighlights();
\r
3791 DrawPosition(TRUE, NULL);
\r
3793 switch (gameMode) {
\r
3794 case EditPosition:
\r
3795 case IcsExamining:
\r
3796 if (x < 0 || y < 0) break;
\r
3799 if (message == WM_MBUTTONDOWN) {
\r
3800 buttonCount = 3; /* even if system didn't think so */
\r