Fixed bug in atomic patch that interfered with non-atomic variants
[xboard.git] / winboard / woptions.c
1 /*
2  * woptions.c -- Options dialog box routines for WinBoard
3  * $Id: woptions.c,v 2.1 2003/10/27 19:21:02 mann Exp $
4  *
5  * Copyright 2000,2009 Free Software Foundation, Inc.
6  *
7  * ------------------------------------------------------------------------
8  *
9  * GNU XBoard is free software: you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation, either version 3 of the License, or (at
12  * your option) any later version.
13  *
14  * GNU XBoard is distributed in the hope that it will be useful, but
15  * WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17  * General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program. If not, see http://www.gnu.org/licenses/.  *
21  *
22  *------------------------------------------------------------------------
23  ** See the file ChangeLog for a revision history.  */
24
25 #include "config.h"
26
27 #include <windows.h>   /* required for all Windows applications */
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <shlobj.h>    /* [AS] Requires NT 4.0 or Win95 */
31 #include <ctype.h>
32
33 #include "common.h"
34 #include "winboard.h"
35 #include "backend.h"
36 #include "woptions.h"
37 #include "defaults.h"
38 #include "wedittags.h"
39 #include <richedit.h>
40
41 #if __GNUC__
42 #include <errno.h>
43 #include <string.h>
44 #endif
45
46 /* Imports from winboard.c */
47
48 extern MyFont *font[NUM_SIZES][NUM_FONTS];
49 extern HINSTANCE hInst;          /* current instance */
50 extern HWND hwndMain;            /* root window*/
51 extern BOOLEAN alwaysOnTop;
52 extern RECT boardRect;
53 extern COLORREF lightSquareColor, darkSquareColor, whitePieceColor, 
54   blackPieceColor, highlightSquareColor, premoveHighlightColor;
55 extern HPALETTE hPal;
56 extern BoardSize boardSize;
57 extern COLORREF consoleBackgroundColor;
58 extern MyColorizeAttribs colorizeAttribs[]; /* do I need the size? */
59 extern MyTextAttribs textAttribs[];
60 extern MySound sounds[];
61 extern ColorClass currentColorClass;
62 extern HWND hwndConsole;
63 extern char *defaultTextAttribs[];
64 extern HWND commentDialog;
65 extern HWND moveHistoryDialog;
66 extern char installDir[];
67 extern HWND hCommPort;    /* currently open comm port */
68 extern DCB dcb;
69 extern BOOLEAN chessProgram;
70 extern int startedFromPositionFile; /* [HGM] loadPos */
71
72 /* types */
73
74 typedef struct {
75   char *label;
76   unsigned value;
77 } ComboData;
78
79 typedef struct {
80   char *label;
81   char *name;
82 } SoundComboData;
83
84 /* module prototypes */
85
86 LRESULT CALLBACK GeneralOptions(HWND, UINT, WPARAM, LPARAM);
87 LRESULT CALLBACK BoardOptions(HWND, UINT, WPARAM, LPARAM);
88 LRESULT CALLBACK NewVariant(HWND, UINT, WPARAM, LPARAM);
89 LRESULT CALLBACK IcsOptions(HWND, UINT, WPARAM, LPARAM);
90 LRESULT CALLBACK FontOptions(HWND, UINT, WPARAM, LPARAM);
91 LRESULT CALLBACK CommPortOptions(HWND, UINT, WPARAM, LPARAM);
92 LRESULT CALLBACK LoadOptions(HWND, UINT, WPARAM, LPARAM);
93 LRESULT CALLBACK SaveOptions(HWND, UINT, WPARAM, LPARAM);
94 LRESULT CALLBACK TimeControl(HWND, UINT, WPARAM, LPARAM);
95 VOID ChangeBoardSize(BoardSize newSize);
96 VOID PaintSampleSquare(
97     HWND     hwnd, 
98     int      ctrlid, 
99     COLORREF squareColor, 
100     COLORREF pieceColor,
101     COLORREF squareOutlineColor,
102     COLORREF pieceDetailColor,
103     BOOL     isWhitePiece,
104     BOOL     isMono,
105     HBITMAP  pieces[3] 
106     );
107 VOID PaintColorBlock(HWND hwnd, int ctrlid, COLORREF color);
108 VOID SetBoardOptionEnables(HWND hDlg);
109 BoardSize BoardOptionsWhichRadio(HWND hDlg);
110 BOOL APIENTRY MyCreateFont(HWND hwnd, MyFont *font);
111 VOID UpdateSampleText(HWND hDlg, int id, MyColorizeAttribs *mca);
112 LRESULT CALLBACK ColorizeTextDialog(HWND , UINT, WPARAM, LPARAM);
113 VOID ColorizeTextPopup(HWND hwnd, ColorClass cc);
114 VOID SetIcsOptionEnables(HWND hDlg);
115 VOID SetSampleFontText(HWND hwnd, int id, const MyFont *mf);
116 VOID CopyFont(MyFont *dest, const MyFont *src);
117 void InitSoundComboData(SoundComboData *scd);
118 void ResetSoundComboData(SoundComboData *scd);
119 void InitSoundCombo(HWND hwndCombo, SoundComboData *scd);
120 int SoundDialogWhichRadio(HWND hDlg);
121 VOID SoundDialogSetEnables(HWND hDlg, int radio);
122 char * SoundDialogGetName(HWND hDlg, int radio);
123 void DisplaySelectedSound(HWND hDlg, HWND hCombo, const char *name);
124 VOID ParseCommSettings(char *arg, DCB *dcb);
125 VOID PrintCommSettings(FILE *f, char *name, DCB *dcb);
126 void InitCombo(HANDLE hwndCombo, ComboData *cd);
127 void SelectComboValue(HANDLE hwndCombo, ComboData *cd, unsigned value);
128 VOID SetLoadOptionEnables(HWND hDlg);
129 VOID SetSaveOptionEnables(HWND hDlg);
130 VOID SetTimeControlEnables(HWND hDlg);
131 void NewSettingEvent(int option, char *command, int value);
132
133 /*---------------------------------------------------------------------------*\
134  *
135  * General Options Dialog functions
136  *
137 \*---------------------------------------------------------------------------*/
138
139
140 LRESULT CALLBACK
141 GeneralOptionsDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
142 {
143   static Boolean oldShowCoords;
144   static Boolean oldBlindfold;
145   static Boolean oldShowButtonBar;
146
147   switch (message) {
148   case WM_INITDIALOG: /* message: initialize dialog box */
149     oldShowCoords = appData.showCoords;
150     oldBlindfold  = appData.blindfold;
151     oldShowButtonBar = appData.showButtonBar;
152
153     /* Center the dialog over the application window */
154     CenterWindow (hDlg, GetWindow (hDlg, GW_OWNER));
155
156     /* Initialize the dialog items */
157 #define CHECK_BOX(x,y) CheckDlgButton(hDlg, (x), (BOOL)(y))
158
159     CHECK_BOX(OPT_AlwaysOnTop, alwaysOnTop);
160     CHECK_BOX(OPT_AlwaysQueen, appData.alwaysPromoteToQueen);
161     CHECK_BOX(OPT_AnimateDragging, appData.animateDragging);
162     CHECK_BOX(OPT_AnimateMoving, appData.animate);
163     CHECK_BOX(OPT_AutoFlag, appData.autoCallFlag);
164     CHECK_BOX(OPT_AutoFlipView, appData.autoFlipView);
165     CHECK_BOX(OPT_AutoRaiseBoard, appData.autoRaiseBoard);
166     CHECK_BOX(OPT_Blindfold, appData.blindfold);
167     CHECK_BOX(OPT_HighlightDragging, appData.highlightDragging);
168     CHECK_BOX(OPT_HighlightLastMove, appData.highlightLastMove);
169     CHECK_BOX(OPT_PeriodicUpdates, appData.periodicUpdates);
170     CHECK_BOX(OPT_PonderNextMove, appData.ponderNextMove);
171     CHECK_BOX(OPT_PopupExitMessage, appData.popupExitMessage);
172     CHECK_BOX(OPT_PopupMoveErrors, appData.popupMoveErrors);
173     CHECK_BOX(OPT_ShowButtonBar, appData.showButtonBar);
174     CHECK_BOX(OPT_ShowCoordinates, appData.showCoords);
175     CHECK_BOX(OPT_ShowThinking, appData.showThinking);
176     CHECK_BOX(OPT_TestLegality, appData.testLegality);
177     CHECK_BOX(OPT_HideThinkFromHuman, appData.hideThinkingFromHuman);
178     CHECK_BOX(OPT_SaveExtPGN, appData.saveExtendedInfoInPGN);
179     CHECK_BOX(OPT_ExtraInfoInMoveHistory, appData.showEvalInMoveHistory);
180     CHECK_BOX(OPT_HighlightMoveArrow, appData.highlightMoveWithArrow);
181
182 #undef CHECK_BOX
183
184     EnableWindow(GetDlgItem(hDlg, OPT_AutoFlag),
185                  appData.icsActive || !appData.noChessProgram);
186     EnableWindow(GetDlgItem(hDlg, OPT_AutoFlipView),
187                  appData.icsActive || !appData.noChessProgram);
188     EnableWindow(GetDlgItem(hDlg, OPT_PonderNextMove),
189                  !appData.noChessProgram);
190     EnableWindow(GetDlgItem(hDlg, OPT_PeriodicUpdates), 
191                  !appData.noChessProgram && !appData.icsActive);
192     EnableWindow(GetDlgItem(hDlg, OPT_ShowThinking), 
193                  !appData.noChessProgram);
194     return TRUE;
195
196
197   case WM_COMMAND: /* message: received a command */
198     switch (LOWORD(wParam)) {
199     case IDOK:
200       /* Read changed options from the dialog box */
201       
202 #define IS_CHECKED(x) (Boolean)IsDlgButtonChecked(hDlg, (x))
203
204       alwaysOnTop                  = IS_CHECKED(OPT_AlwaysOnTop);
205       appData.alwaysPromoteToQueen = IS_CHECKED(OPT_AlwaysQueen);
206       appData.animateDragging      = IS_CHECKED(OPT_AnimateDragging);
207       appData.animate              = IS_CHECKED(OPT_AnimateMoving);
208       appData.autoCallFlag         = IS_CHECKED(OPT_AutoFlag);
209       appData.autoFlipView         = IS_CHECKED(OPT_AutoFlipView);
210       appData.autoRaiseBoard       = IS_CHECKED(OPT_AutoRaiseBoard);
211       appData.blindfold            = IS_CHECKED(OPT_Blindfold);
212       appData.highlightDragging    = IS_CHECKED(OPT_HighlightDragging);
213       appData.highlightLastMove    = IS_CHECKED(OPT_HighlightLastMove);
214       PeriodicUpdatesEvent(          IS_CHECKED(OPT_PeriodicUpdates));
215       PonderNextMoveEvent(           IS_CHECKED(OPT_PonderNextMove));
216       appData.popupExitMessage     = IS_CHECKED(OPT_PopupExitMessage);
217       appData.popupMoveErrors      = IS_CHECKED(OPT_PopupMoveErrors);
218       appData.showButtonBar        = IS_CHECKED(OPT_ShowButtonBar);
219       appData.showCoords           = IS_CHECKED(OPT_ShowCoordinates);
220       // [HGM] thinking: next three moved up
221       appData.saveExtendedInfoInPGN= IS_CHECKED(OPT_SaveExtPGN);
222       appData.hideThinkingFromHuman= IS_CHECKED(OPT_HideThinkFromHuman);
223       appData.showEvalInMoveHistory= IS_CHECKED(OPT_ExtraInfoInMoveHistory);
224 #if 0
225       ShowThinkingEvent(             IS_CHECKED(OPT_ShowThinking));
226 #else
227       appData.showThinking         = IS_CHECKED(OPT_ShowThinking);
228       ShowThinkingEvent(); // [HGM] thinking: tests four options
229 #endif
230       appData.testLegality         = IS_CHECKED(OPT_TestLegality);
231       appData.highlightMoveWithArrow=IS_CHECKED(OPT_HighlightMoveArrow);
232
233 #undef IS_CHECKED
234
235       SetWindowPos(hwndMain, alwaysOnTop ? HWND_TOPMOST : HWND_NOTOPMOST,
236                    0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE);
237 #if AOT_CONSOLE
238       if (hwndConsole) {
239         SetWindowPos(hwndConsole, alwaysOnTop ? HWND_TOPMOST : HWND_NOTOPMOST,
240                      0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE);
241       }
242 #endif
243       if (!appData.highlightLastMove) {
244         ClearHighlights();
245         DrawPosition(FALSE, NULL);
246       }
247       /* 
248        * for some reason the redraw seems smoother when we invalidate
249        * the board rect after the call to EndDialog()
250        */
251       EndDialog(hDlg, TRUE);
252
253       if (oldShowButtonBar != appData.showButtonBar) {
254         InitDrawingSizes(boardSize, 0);
255       } else if ((oldShowCoords != appData.showCoords) || 
256                  (oldBlindfold != appData.blindfold)) {
257         InvalidateRect(hwndMain, &boardRect, FALSE);
258       }
259
260       return TRUE;
261
262     case IDCANCEL:
263       EndDialog(hDlg, FALSE);
264       return TRUE;
265
266     }
267     break;
268   }
269   return FALSE;
270 }
271
272 VOID 
273 GeneralOptionsPopup(HWND hwnd)
274 {
275   FARPROC lpProc;
276
277   lpProc = MakeProcInstance((FARPROC)GeneralOptionsDialog, hInst);
278   DialogBox(hInst, MAKEINTRESOURCE(DLG_GeneralOptions), hwnd,
279             (DLGPROC) lpProc);
280   FreeProcInstance(lpProc);
281 }
282 /*---------------------------------------------------------------------------*\
283  *
284  * Board Options Dialog functions
285  *
286 \*---------------------------------------------------------------------------*/
287
288 const int SAMPLE_SQ_SIZE = 54;
289
290 VOID
291 ChangeBoardSize(BoardSize newSize)
292 {
293   if (newSize != boardSize) {
294     boardSize = newSize;
295     InitDrawingSizes(boardSize, 0);
296   }
297 }
298
299 VOID
300 PaintSampleSquare(
301     HWND     hwnd, 
302     int      ctrlid, 
303     COLORREF squareColor, 
304     COLORREF pieceColor,
305     COLORREF squareOutlineColor,
306     COLORREF pieceDetailColor,
307     BOOL     isWhitePiece,
308     BOOL     isMono,
309     HBITMAP  pieces[3] 
310     )
311 {
312   HBRUSH  brushSquare;
313   HBRUSH  brushSquareOutline;
314   HBRUSH  brushPiece;
315   HBRUSH  brushPieceDetail;
316   HBRUSH  oldBrushPiece = NULL;
317   HBRUSH  oldBrushSquare;
318   HBITMAP oldBitmapMem;
319   HBITMAP oldBitmapTemp;
320   HBITMAP bufferBitmap;
321   RECT    rect;
322   HDC     hdcScreen, hdcMem, hdcTemp;
323   HPEN    pen, oldPen;
324   HWND    hCtrl = GetDlgItem(hwnd, ctrlid);
325   int     x, y;
326
327   const int SOLID   = 0;
328   const int WHITE   = 1;
329   const int OUTLINE = 2;
330   const int BORDER  = 4;
331
332   InvalidateRect(hCtrl, NULL, TRUE);
333   UpdateWindow(hCtrl);
334   GetClientRect(hCtrl, &rect);
335   x = rect.left + (BORDER / 2);
336   y = rect.top  + (BORDER / 2);
337   hdcScreen = GetDC(hCtrl);
338   hdcMem  = CreateCompatibleDC(hdcScreen);
339   hdcTemp = CreateCompatibleDC(hdcScreen);
340
341   bufferBitmap = CreateCompatibleBitmap(hdcScreen, rect.right-rect.left+1,
342                                         rect.bottom-rect.top+1);
343   oldBitmapMem = SelectObject(hdcMem, bufferBitmap);
344   if (!isMono) {
345     SelectPalette(hdcMem, hPal, FALSE);
346   }
347   brushSquare         = CreateSolidBrush(squareColor);
348   brushSquareOutline  = CreateSolidBrush(squareOutlineColor);
349   brushPiece          = CreateSolidBrush(pieceColor);
350   brushPieceDetail    = CreateSolidBrush(pieceDetailColor);
351
352   /* 
353    * first draw the rectangle 
354    */
355   pen      = CreatePen(PS_SOLID, BORDER, squareOutlineColor);
356   oldPen   = (HPEN)  SelectObject(hdcMem, pen);
357   oldBrushSquare = (HBRUSH)SelectObject(hdcMem, brushSquare);
358   Rectangle(hdcMem, rect.left, rect.top, rect.right, rect.bottom);
359
360   /* 
361    * now draw the piece
362    */
363   if (isMono) {
364     oldBitmapTemp = SelectObject(hdcTemp, pieces[OUTLINE]);
365     BitBlt(hdcMem, x, y, SAMPLE_SQ_SIZE, SAMPLE_SQ_SIZE, hdcTemp, 0, 0,
366            isWhitePiece ? SRCCOPY : NOTSRCCOPY);
367     SelectObject(hdcTemp, oldBitmapTemp);
368   } else {
369     if (isWhitePiece) {
370       oldBitmapTemp = SelectObject(hdcTemp, pieces[WHITE]);
371       oldBrushPiece = SelectObject(hdcMem, brushPiece);
372       BitBlt(hdcMem, x, y, SAMPLE_SQ_SIZE, SAMPLE_SQ_SIZE, 
373              hdcTemp, 0, 0, 0x00B8074A);
374 #if 0
375       /* Use pieceDetailColor for outline of white pieces */
376       SelectObject(hdcTemp, pieces[OUTLINE]);
377       SelectObject(hdcMem, brushPieceDetail);
378       BitBlt(hdcMem, x, y, SAMPLE_SQ_SIZE, SAMPLE_SQ_SIZE, 
379              hdcTemp, 0, 0, 0x00B8074A);
380 #else
381       /* Use black for outline of white pieces */
382       SelectObject(hdcTemp, pieces[OUTLINE]);
383       BitBlt(hdcMem, x, y, SAMPLE_SQ_SIZE, SAMPLE_SQ_SIZE, 
384              hdcTemp, 0, 0, SRCAND);
385 #endif
386     } else {
387 #if 0
388       /* Use pieceDetailColor for details of black pieces */
389       /* Requires filled-in solid bitmaps (BLACK_PIECE class); the
390          WHITE_PIECE ones aren't always the right shape. */
391       oldBitmapTemp = SelectObject(hdcTemp, pieces[BLACK]);
392       oldBrushPiece = SelectObject(hdcMem, brushPieceDetail);
393       BitBlt(hdcMem, x, y, SAMPLE_SQ_SIZE, SAMPLE_SQ_SIZE, 
394              hdcTemp, 0, 0, 0x00B8074A);
395       SelectObject(hdcTemp, pieces[SOLID]);
396       SelectObject(hdcMem, brushPiece);
397       BitBlt(hdcMem, x, y, SAMPLE_SQ_SIZE, SAMPLE_SQ_SIZE, 
398              hdcTemp, 0, 0, 0x00B8074A);
399 #else
400       /* Use square color for details of black pieces */
401       oldBitmapTemp = SelectObject(hdcTemp, pieces[SOLID]);
402       oldBrushPiece = SelectObject(hdcMem, brushPiece);
403       BitBlt(hdcMem, x, y, SAMPLE_SQ_SIZE, SAMPLE_SQ_SIZE, 
404              hdcTemp, 0, 0, 0x00B8074A);
405 #endif
406     }
407     SelectObject(hdcMem, oldBrushPiece);
408     SelectObject(hdcTemp, oldBitmapTemp);
409   }
410   /* 
411    * copy the memory dc to the screen
412    */
413   SelectObject(hdcMem, bufferBitmap);
414   BitBlt(hdcScreen, rect.left, rect.top,
415          rect.right - rect.left,
416          rect.bottom - rect.top,
417          hdcMem, rect.left, rect.top, SRCCOPY);
418   SelectObject(hdcMem, oldBitmapMem);
419   /* 
420    * clean up
421    */
422   SelectObject(hdcMem, oldBrushPiece);
423   SelectObject(hdcMem, oldPen);
424   DeleteObject(brushPiece);
425   DeleteObject(brushPieceDetail);
426   DeleteObject(brushSquare);
427   DeleteObject(brushSquareOutline);
428   DeleteObject(pen);
429   DeleteDC(hdcTemp);
430   DeleteDC(hdcMem);
431   ReleaseDC(hCtrl, hdcScreen);
432 }
433
434
435 VOID
436 PaintColorBlock(HWND hwnd, int ctrlid, COLORREF color)
437 {
438   HDC    hdc;
439   HBRUSH brush, oldBrush;
440   RECT   rect;
441   HWND   hCtrl = GetDlgItem(hwnd, ctrlid);
442
443   hdc = GetDC(hCtrl);
444   InvalidateRect(hCtrl, NULL, TRUE);
445   UpdateWindow(hCtrl);
446   GetClientRect(hCtrl, &rect);
447   brush = CreateSolidBrush(color);
448   oldBrush = (HBRUSH)SelectObject(hdc, brush);
449   Rectangle(hdc, rect.left, rect.top, rect.right, rect.bottom);
450   SelectObject(hdc, oldBrush);
451   DeleteObject(brush);
452   ReleaseDC(hCtrl, hdc);
453 }
454
455
456 VOID
457 SetBoardOptionEnables(HWND hDlg)
458 {
459   if (IsDlgButtonChecked(hDlg, OPT_Monochrome)) {
460     ShowWindow(GetDlgItem(hDlg, OPT_LightSquareColor), SW_HIDE);
461     ShowWindow(GetDlgItem(hDlg, OPT_DarkSquareColor), SW_HIDE);
462     ShowWindow(GetDlgItem(hDlg, OPT_WhitePieceColor), SW_HIDE);
463     ShowWindow(GetDlgItem(hDlg, OPT_BlackPieceColor), SW_HIDE);
464
465     EnableWindow(GetDlgItem(hDlg, OPT_ChooseLightSquareColor), FALSE);
466     EnableWindow(GetDlgItem(hDlg, OPT_ChooseDarkSquareColor), FALSE);
467     EnableWindow(GetDlgItem(hDlg, OPT_ChooseWhitePieceColor), FALSE);
468     EnableWindow(GetDlgItem(hDlg, OPT_ChooseBlackPieceColor), FALSE);
469   } else {
470     ShowWindow(GetDlgItem(hDlg, OPT_LightSquareColor), SW_SHOW);
471     ShowWindow(GetDlgItem(hDlg, OPT_DarkSquareColor), SW_SHOW);
472     ShowWindow(GetDlgItem(hDlg, OPT_WhitePieceColor), SW_SHOW);
473     ShowWindow(GetDlgItem(hDlg, OPT_BlackPieceColor), SW_SHOW);
474
475     EnableWindow(GetDlgItem(hDlg, OPT_ChooseLightSquareColor), TRUE);
476     EnableWindow(GetDlgItem(hDlg, OPT_ChooseDarkSquareColor), TRUE);
477     EnableWindow(GetDlgItem(hDlg, OPT_ChooseWhitePieceColor), TRUE);
478     EnableWindow(GetDlgItem(hDlg, OPT_ChooseBlackPieceColor), TRUE);
479   }
480 }
481
482 BoardSize 
483 BoardOptionsWhichRadio(HWND hDlg)
484 {
485   return (IsDlgButtonChecked(hDlg, OPT_SizeTiny) ? SizeTiny :
486          (IsDlgButtonChecked(hDlg, OPT_SizeTeeny) ? SizeTeeny :
487          (IsDlgButtonChecked(hDlg, OPT_SizeDinky) ? SizeDinky :
488          (IsDlgButtonChecked(hDlg, OPT_SizePetite) ? SizePetite :
489          (IsDlgButtonChecked(hDlg, OPT_SizeSlim) ? SizeSlim :
490          (IsDlgButtonChecked(hDlg, OPT_SizeSmall) ? SizeSmall :
491          (IsDlgButtonChecked(hDlg, OPT_SizeMediocre) ? SizeMediocre :
492          (IsDlgButtonChecked(hDlg, OPT_SizeMiddling) ? SizeMiddling :
493          (IsDlgButtonChecked(hDlg, OPT_SizeAverage) ? SizeAverage :
494          (IsDlgButtonChecked(hDlg, OPT_SizeModerate) ? SizeModerate :
495          (IsDlgButtonChecked(hDlg, OPT_SizeMedium) ? SizeMedium :
496          (IsDlgButtonChecked(hDlg, OPT_SizeBulky) ? SizeBulky :
497          (IsDlgButtonChecked(hDlg, OPT_SizeLarge) ? SizeLarge :
498          (IsDlgButtonChecked(hDlg, OPT_SizeBig) ? SizeBig :
499          (IsDlgButtonChecked(hDlg, OPT_SizeHuge) ? SizeHuge :
500          (IsDlgButtonChecked(hDlg, OPT_SizeGiant) ? SizeGiant :
501          (IsDlgButtonChecked(hDlg, OPT_SizeColossal) ? SizeColossal :
502           SizeTitanic )))))))))))))))));
503 }
504
505 LRESULT CALLBACK
506 BoardOptionsDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
507 {
508   static Boolean  mono, white, flip;
509   static BoardSize size;
510   static COLORREF lsc, dsc, wpc, bpc, hsc, phc;
511   static HBITMAP pieces[3];
512
513   switch (message) {
514   case WM_INITDIALOG: /* message: initialize dialog box */
515     /* Center the dialog over the application window */
516     CenterWindow (hDlg, GetWindow (hDlg, GW_OWNER));
517     /* Initialize the dialog items */
518     switch (boardSize) {
519     case SizeTiny:
520       CheckDlgButton(hDlg, OPT_SizeTiny, TRUE);
521       break;
522     case SizeTeeny:
523       CheckDlgButton(hDlg, OPT_SizeTeeny, TRUE);
524       break;
525     case SizeDinky:
526       CheckDlgButton(hDlg, OPT_SizeDinky, TRUE);
527       break;
528     case SizePetite:
529       CheckDlgButton(hDlg, OPT_SizePetite, TRUE);
530       break;
531     case SizeSlim:
532       CheckDlgButton(hDlg, OPT_SizeSlim, TRUE);
533       break;
534     case SizeSmall:
535       CheckDlgButton(hDlg, OPT_SizeSmall, TRUE);
536       break;
537     case SizeMediocre:
538       CheckDlgButton(hDlg, OPT_SizeMediocre, TRUE);
539       break;
540     case SizeMiddling:
541       CheckDlgButton(hDlg, OPT_SizeMiddling, TRUE);
542       break;
543     case SizeAverage:
544       CheckDlgButton(hDlg, OPT_SizeAverage, TRUE);
545       break;
546     case SizeModerate:
547       CheckDlgButton(hDlg, OPT_SizeModerate, TRUE);
548       break;
549     case SizeMedium:
550       CheckDlgButton(hDlg, OPT_SizeMedium, TRUE);
551       break;
552     case SizeBulky:
553       CheckDlgButton(hDlg, OPT_SizeBulky, TRUE);
554       break;
555     case SizeLarge:
556       CheckDlgButton(hDlg, OPT_SizeLarge, TRUE);
557       break;
558     case SizeBig:
559       CheckDlgButton(hDlg, OPT_SizeBig, TRUE);
560       break;
561     case SizeHuge:
562       CheckDlgButton(hDlg, OPT_SizeHuge, TRUE);
563       break;
564     case SizeGiant:
565       CheckDlgButton(hDlg, OPT_SizeGiant, TRUE);
566       break;
567     case SizeColossal:
568       CheckDlgButton(hDlg, OPT_SizeColossal, TRUE);
569       break;
570     case SizeTitanic:
571       CheckDlgButton(hDlg, OPT_SizeTitanic, TRUE);
572     default: ; // should not happen, but suppresses warning on pedantic compilers
573     }
574
575     if (appData.monoMode)
576       CheckDlgButton(hDlg, OPT_Monochrome, TRUE);
577
578     if (appData.allWhite)
579       CheckDlgButton(hDlg, OPT_AllWhite, TRUE);
580
581     if (appData.upsideDown)
582       CheckDlgButton(hDlg, OPT_UpsideDown, TRUE);
583
584     pieces[0] = DoLoadBitmap(hInst, "n", SAMPLE_SQ_SIZE, "s");
585     pieces[1] = DoLoadBitmap(hInst, "n", SAMPLE_SQ_SIZE, "w");
586     pieces[2] = DoLoadBitmap(hInst, "n", SAMPLE_SQ_SIZE, "o");
587         
588     lsc = lightSquareColor;
589     dsc = darkSquareColor;
590     wpc = whitePieceColor;
591     bpc = blackPieceColor;
592     hsc = highlightSquareColor;
593     phc = premoveHighlightColor;
594     mono = appData.monoMode;
595     white= appData.allWhite;
596     flip = appData.upsideDown;
597     size = boardSize;
598
599     SetBoardOptionEnables(hDlg);
600     return TRUE;
601
602   case WM_PAINT:
603     PaintColorBlock(hDlg, OPT_LightSquareColor, lsc);
604     PaintColorBlock(hDlg, OPT_DarkSquareColor,  dsc);
605     PaintColorBlock(hDlg, OPT_WhitePieceColor,  wpc);
606     PaintColorBlock(hDlg, OPT_BlackPieceColor,  bpc);
607     PaintColorBlock(hDlg, OPT_HighlightSquareColor, hsc);
608     PaintColorBlock(hDlg, OPT_PremoveHighlightColor, phc);
609     PaintSampleSquare(hDlg, OPT_SampleLightSquare, lsc, wpc, hsc, bpc,
610         TRUE, mono, pieces);
611     PaintSampleSquare(hDlg, OPT_SampleDarkSquare, dsc, bpc, phc, wpc,
612         FALSE, mono, pieces);
613
614     return FALSE;
615
616   case WM_COMMAND: /* message: received a command */
617     switch (LOWORD(wParam)) {
618     case IDOK:
619       /* 
620        * if we call EndDialog() after the call to ChangeBoardSize(),
621        * then ChangeBoardSize() does not take effect, although the new
622        * boardSize is saved. Go figure...
623        */
624       EndDialog(hDlg, TRUE);
625
626       size = BoardOptionsWhichRadio(hDlg);
627
628       /*
629        * did any settings change?
630        */
631       if (size != boardSize) {
632         ChangeBoardSize(size);
633       }
634
635       if ((mono != appData.monoMode) ||
636           (lsc  != lightSquareColor) ||
637           (dsc  != darkSquareColor) ||
638           (wpc  != whitePieceColor) ||
639           (bpc  != blackPieceColor) ||
640           (hsc  != highlightSquareColor) ||
641           (flip != appData.upsideDown) ||
642           (white != appData.allWhite) ||
643           (phc  != premoveHighlightColor)) {
644
645           lightSquareColor = lsc;
646           darkSquareColor = dsc;
647           whitePieceColor = wpc;
648           blackPieceColor = bpc;
649           highlightSquareColor = hsc;
650           premoveHighlightColor = phc;
651           appData.monoMode = mono;
652           appData.allWhite = white;
653           appData.upsideDown = flip;
654
655           InitDrawingColors();
656           InitDrawingSizes(boardSize, 0);
657           InvalidateRect(hwndMain, &boardRect, FALSE);
658       }
659       DeleteObject(pieces[0]);
660       DeleteObject(pieces[1]);
661       DeleteObject(pieces[2]);
662       return TRUE;
663
664     case IDCANCEL:
665       DeleteObject(pieces[0]);
666       DeleteObject(pieces[1]);
667       DeleteObject(pieces[2]);
668       EndDialog(hDlg, FALSE);
669       return TRUE;
670
671     case OPT_ChooseLightSquareColor:
672       if (ChangeColor(hDlg, &lsc)) 
673         PaintColorBlock(hDlg, OPT_LightSquareColor, lsc);
674         PaintSampleSquare(hDlg, OPT_SampleLightSquare, lsc, wpc, hsc, bpc,
675             TRUE, mono, pieces);
676       break;
677
678     case OPT_ChooseDarkSquareColor:
679       if (ChangeColor(hDlg, &dsc)) 
680         PaintColorBlock(hDlg, OPT_DarkSquareColor, dsc);
681         PaintSampleSquare(hDlg, OPT_SampleDarkSquare, dsc, bpc, phc, wpc,
682             FALSE, mono, pieces);
683       break;
684
685     case OPT_ChooseWhitePieceColor:
686       if (ChangeColor(hDlg, &wpc)) 
687         PaintColorBlock(hDlg, OPT_WhitePieceColor, wpc);
688         PaintSampleSquare(hDlg, OPT_SampleLightSquare, lsc, wpc, hsc, bpc,
689             TRUE, mono, pieces);
690       break;
691
692     case OPT_ChooseBlackPieceColor:
693       if (ChangeColor(hDlg, &bpc)) 
694         PaintColorBlock(hDlg, OPT_BlackPieceColor, bpc);
695         PaintSampleSquare(hDlg, OPT_SampleDarkSquare, dsc, bpc, phc, wpc,
696             FALSE, mono, pieces);
697       break;
698
699     case OPT_ChooseHighlightSquareColor:
700       if (ChangeColor(hDlg, &hsc)) 
701         PaintColorBlock(hDlg, OPT_HighlightSquareColor, hsc);
702         PaintSampleSquare(hDlg, OPT_SampleLightSquare, lsc, wpc, hsc, bpc,
703             TRUE, mono, pieces);
704       break;
705
706     case OPT_ChoosePremoveHighlightColor:
707       if (ChangeColor(hDlg, &phc)) 
708         PaintColorBlock(hDlg, OPT_PremoveHighlightColor, phc);
709         PaintSampleSquare(hDlg, OPT_SampleDarkSquare, dsc, bpc, phc, wpc,
710             FALSE, mono, pieces);
711       break;
712
713     case OPT_DefaultBoardColors:
714       lsc = ParseColorName(LIGHT_SQUARE_COLOR);
715       dsc = ParseColorName(DARK_SQUARE_COLOR);
716       wpc = ParseColorName(WHITE_PIECE_COLOR);
717       bpc = ParseColorName(BLACK_PIECE_COLOR);
718       hsc = ParseColorName(HIGHLIGHT_SQUARE_COLOR);
719       phc = ParseColorName(PREMOVE_HIGHLIGHT_COLOR);
720       mono = FALSE;
721       white= FALSE;
722       flip = FALSE;
723       CheckDlgButton(hDlg, OPT_Monochrome, FALSE);
724       CheckDlgButton(hDlg, OPT_AllWhite,   FALSE);
725       CheckDlgButton(hDlg, OPT_UpsideDown, FALSE);
726       PaintColorBlock(hDlg, OPT_LightSquareColor, lsc);
727       PaintColorBlock(hDlg, OPT_DarkSquareColor,  dsc);
728       PaintColorBlock(hDlg, OPT_WhitePieceColor,  wpc);
729       PaintColorBlock(hDlg, OPT_BlackPieceColor,  bpc);
730       PaintColorBlock(hDlg, OPT_HighlightSquareColor, hsc);
731       PaintColorBlock(hDlg, OPT_PremoveHighlightColor, phc);
732       SetBoardOptionEnables(hDlg);
733       PaintSampleSquare(hDlg, OPT_SampleLightSquare, lsc, wpc, hsc, bpc,
734           TRUE, mono, pieces);
735       PaintSampleSquare(hDlg, OPT_SampleDarkSquare, dsc, bpc, phc, wpc,
736           FALSE, mono, pieces);
737       break;
738
739     case OPT_Monochrome:
740       mono = !mono;
741       SetBoardOptionEnables(hDlg);
742       break;
743
744     case OPT_AllWhite:
745       white = !white;
746       SetBoardOptionEnables(hDlg);
747       break;
748
749     case OPT_UpsideDown:
750       flip = !flip;
751       SetBoardOptionEnables(hDlg);
752       break;
753     }
754     break;
755   }
756   return FALSE;
757 }
758
759
760 VOID
761 BoardOptionsPopup(HWND hwnd)
762 {
763   FARPROC lpProc = MakeProcInstance((FARPROC)BoardOptionsDialog, hInst);
764   DialogBox(hInst, MAKEINTRESOURCE(DLG_BoardOptions), hwnd,
765           (DLGPROC) lpProc);
766   FreeProcInstance(lpProc);
767 }
768
769 VariantClass
770 VariantWhichRadio(HWND hDlg)
771 {
772   return (IsDlgButtonChecked(hDlg, OPT_VariantFairy) ? VariantFairy :
773          (IsDlgButtonChecked(hDlg, OPT_VariantGothic) ? VariantGothic :
774          (IsDlgButtonChecked(hDlg, OPT_VariantCrazyhouse) ? VariantCrazyhouse :
775          (IsDlgButtonChecked(hDlg, OPT_VariantBughouse) ? VariantBughouse :
776          (IsDlgButtonChecked(hDlg, OPT_VariantCourier) ? VariantCourier :
777          (IsDlgButtonChecked(hDlg, OPT_VariantShatranj) ? VariantShatranj :
778          (IsDlgButtonChecked(hDlg, OPT_VariantShogi) ? VariantShogi :
779          (IsDlgButtonChecked(hDlg, OPT_VariantXiangqi) ? VariantXiangqi :
780          (IsDlgButtonChecked(hDlg, OPT_VariantCapablanca) ? VariantCapablanca :
781          (IsDlgButtonChecked(hDlg, OPT_VariantTwoKings) ? VariantTwoKings :
782          (IsDlgButtonChecked(hDlg, OPT_VariantKnightmate) ? VariantKnightmate :
783          (IsDlgButtonChecked(hDlg, OPT_VariantLosers) ? VariantLosers :
784          (IsDlgButtonChecked(hDlg, OPT_VariantSuicide) ? VariantSuicide :
785          (IsDlgButtonChecked(hDlg, OPT_VariantAtomic) ? VariantAtomic :
786          (IsDlgButtonChecked(hDlg, OPT_VariantShatranj) ? VariantShatranj :
787          (IsDlgButtonChecked(hDlg, OPT_VariantFRC) ? VariantFischeRandom :
788          (IsDlgButtonChecked(hDlg, OPT_VariantCylinder) ? VariantCylinder :
789          (IsDlgButtonChecked(hDlg, OPT_VariantFalcon) ? VariantFalcon :
790          (IsDlgButtonChecked(hDlg, OPT_VariantCRC) ? VariantCapaRandom :
791          (IsDlgButtonChecked(hDlg, OPT_VariantSuper) ? VariantSuper :
792          (IsDlgButtonChecked(hDlg, OPT_VariantBerolina) ? VariantBerolina :
793          (IsDlgButtonChecked(hDlg, OPT_VariantJanus) ? VariantJanus :
794          (IsDlgButtonChecked(hDlg, OPT_VariantWildcastle) ? VariantWildCastle :
795          (IsDlgButtonChecked(hDlg, OPT_VariantNocastle) ? VariantNoCastle :
796          (IsDlgButtonChecked(hDlg, OPT_Variant3Check) ? Variant3Check :
797          (IsDlgButtonChecked(hDlg, OPT_VariantGreat) ? VariantGreat :
798           VariantNormal ))))))))))))))))))))))))));
799 }
800
801 LRESULT CALLBACK
802 NewVariantDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
803 {
804   static VariantClass v;
805   static int n1_ok, n2_ok, n3_ok;
806
807   switch (message) {
808   case WM_INITDIALOG: /* message: initialize dialog box */
809     /* Center the dialog over the application window */
810     CenterWindow (hDlg, GetWindow (hDlg, GW_OWNER));
811     /* Initialize the dialog items */
812     switch (gameInfo.variant) {
813     case VariantNormal:
814       CheckDlgButton(hDlg, OPT_VariantNormal, TRUE);
815       break;
816     case VariantCrazyhouse:
817       CheckDlgButton(hDlg, OPT_VariantCrazyhouse, TRUE);
818       break;
819     case VariantBughouse:
820       CheckDlgButton(hDlg, OPT_VariantBughouse, TRUE);
821       break;
822     case VariantShogi:
823       CheckDlgButton(hDlg, OPT_VariantShogi, TRUE);
824       break;
825     case VariantXiangqi:
826       CheckDlgButton(hDlg, OPT_VariantXiangqi, TRUE);
827       break;
828     case VariantCapablanca:
829       CheckDlgButton(hDlg, OPT_VariantCapablanca, TRUE);
830       break;
831     case VariantGothic:
832       CheckDlgButton(hDlg, OPT_VariantGothic, TRUE);
833       break;
834     case VariantCourier:
835       CheckDlgButton(hDlg, OPT_VariantCourier, TRUE);
836       break;
837     case VariantKnightmate:
838       CheckDlgButton(hDlg, OPT_VariantKnightmate, TRUE);
839       break;
840     case VariantTwoKings:
841       CheckDlgButton(hDlg, OPT_VariantTwoKings, TRUE);
842       break;
843     case VariantFairy:
844       CheckDlgButton(hDlg, OPT_VariantFairy, TRUE);
845       break;
846     case VariantAtomic:
847       CheckDlgButton(hDlg, OPT_VariantAtomic, TRUE);
848       break;
849     case VariantSuicide:
850       CheckDlgButton(hDlg, OPT_VariantSuicide, TRUE);
851       break;
852     case VariantLosers:
853       CheckDlgButton(hDlg, OPT_VariantLosers, TRUE);
854       break;
855     case VariantShatranj:
856       CheckDlgButton(hDlg, OPT_VariantShatranj, TRUE);
857       break;
858     case VariantFischeRandom:
859       CheckDlgButton(hDlg, OPT_VariantFRC, TRUE);
860       break;
861     case VariantCapaRandom:
862       CheckDlgButton(hDlg, OPT_VariantCRC, TRUE);
863       break;
864     case VariantFalcon:
865       CheckDlgButton(hDlg, OPT_VariantFalcon, TRUE);
866       break;
867     case VariantCylinder:
868       CheckDlgButton(hDlg, OPT_VariantCylinder, TRUE);
869       break;
870     case Variant3Check:
871       CheckDlgButton(hDlg, OPT_Variant3Check, TRUE);
872       break;
873     case VariantSuper:
874       CheckDlgButton(hDlg, OPT_VariantSuper, TRUE);
875       break;
876     case VariantBerolina:
877       CheckDlgButton(hDlg, OPT_VariantBerolina, TRUE);
878       break;
879     case VariantJanus:
880       CheckDlgButton(hDlg, OPT_VariantJanus, TRUE);
881       break;
882     case VariantWildCastle:
883       CheckDlgButton(hDlg, OPT_VariantWildcastle, TRUE);
884       break;
885     case VariantNoCastle:
886       CheckDlgButton(hDlg, OPT_VariantNocastle, TRUE);
887       break;
888     case VariantGreat: // Note to self: must still make this button (and GiveAway too).
889       CheckDlgButton(hDlg, OPT_VariantGreat, TRUE);
890       break;
891     default: ;
892     }
893
894     SetDlgItemInt( hDlg, IDC_Files, -1, TRUE );
895     SendDlgItemMessage( hDlg, IDC_Files, EM_SETSEL, 0, -1 );
896
897     SetDlgItemInt( hDlg, IDC_Ranks, -1, TRUE );
898     SendDlgItemMessage( hDlg, IDC_Ranks, EM_SETSEL, 0, -1 );
899
900     SetDlgItemInt( hDlg, IDC_Holdings, -1, TRUE );
901     SendDlgItemMessage( hDlg, IDC_Ranks, EM_SETSEL, 0, -1 );
902
903     n1_ok = n2_ok = n3_ok = FALSE;
904
905     return TRUE;
906
907   case WM_COMMAND: /* message: received a command */
908     switch (LOWORD(wParam)) {
909     case IDOK:
910       /* 
911        * if we call EndDialog() after the call to ChangeBoardSize(),
912        * then ChangeBoardSize() does not take effect, although the new
913        * boardSize is saved. Go figure...
914        */
915       EndDialog(hDlg, TRUE);
916
917       v = VariantWhichRadio(hDlg);
918       if(!appData.noChessProgram) { char *name = VariantName(v), buf[MSG_SIZ];
919         if (first.protocolVersion > 1 && StrStr(first.variants, name) == NULL) {
920             /* [HGM] in protocol 2 we check if variant is suported by engine */
921             sprintf(buf, "Variant %s not supported by %s", name, first.tidy);
922             DisplayError(buf, 0);
923             return TRUE; /* treat as "Cancel" if first engine does not support it */
924         } else
925         if (second.initDone && second.protocolVersion > 1 && StrStr(second.variants, name) == NULL) {
926             sprintf(buf, "Warning: second engine (%s) does not support this!", second.tidy);
927             DisplayError(buf, 0);   /* use of second engine is optional; only warn user */
928         }
929       }
930
931       gameInfo.variant = v;
932       appData.variant = VariantName(v);
933
934       appData.NrFiles = (int) GetDlgItemInt(hDlg, IDC_Files, NULL, FALSE );
935       appData.NrRanks = (int) GetDlgItemInt(hDlg, IDC_Ranks, NULL, FALSE );
936       appData.holdingsSize = (int) GetDlgItemInt(hDlg, IDC_Holdings, NULL, FALSE );
937
938       if(!n1_ok) appData.NrFiles = -1;
939       if(!n2_ok) appData.NrRanks = -1;
940       if(!n3_ok) appData.holdingsSize = -1;
941
942       shuffleOpenings = FALSE; /* [HGM] shuffle: possible shuffle reset when we switch */
943       startedFromPositionFile = FALSE; /* [HGM] loadPos: no longer valid in new variant */
944       appData.pieceToCharTable = NULL;
945       Reset(TRUE, TRUE);
946
947       return TRUE;
948
949     case IDCANCEL:
950       EndDialog(hDlg, FALSE);
951       return TRUE;
952
953     case IDC_Ranks:
954     case IDC_Files:
955     case IDC_Holdings:
956         if( HIWORD(wParam) == EN_CHANGE ) {
957
958             GetDlgItemInt(hDlg, IDC_Files, &n1_ok, FALSE );
959             GetDlgItemInt(hDlg, IDC_Ranks, &n2_ok, FALSE );
960             GetDlgItemInt(hDlg, IDC_Holdings, &n3_ok, FALSE );
961
962             /*EnableWindow( GetDlgItem(hDlg, IDOK), n1_ok && n2_ok && n3_ok ? TRUE : FALSE );*/
963         }
964         return TRUE;
965     }
966     break;
967   }
968   return FALSE;
969 }
970
971
972 VOID
973 NewVariantPopup(HWND hwnd)
974 {
975   FARPROC lpProc = MakeProcInstance((FARPROC)NewVariantDialog, hInst);
976   DialogBox(hInst, MAKEINTRESOURCE(DLG_NewVariant), hwnd,
977           (DLGPROC) lpProc);
978   FreeProcInstance(lpProc);
979 }
980
981 /*---------------------------------------------------------------------------*\
982  *
983  * ICS Options Dialog functions
984  *
985 \*---------------------------------------------------------------------------*/
986
987 BOOL APIENTRY
988 MyCreateFont(HWND hwnd, MyFont *font)
989 {
990   CHOOSEFONT cf;
991   HFONT hf;
992
993   /* Initialize members of the CHOOSEFONT structure. */
994   cf.lStructSize = sizeof(CHOOSEFONT);
995   cf.hwndOwner = hwnd;
996   cf.hDC = (HDC)NULL;
997   cf.lpLogFont = &font->lf;
998   cf.iPointSize = 0;
999   cf.Flags = CF_SCREENFONTS|/*CF_ANSIONLY|*/CF_INITTOLOGFONTSTRUCT;
1000   cf.rgbColors = RGB(0,0,0);
1001   cf.lCustData = 0L;
1002   cf.lpfnHook = (LPCFHOOKPROC)NULL;
1003   cf.lpTemplateName = (LPSTR)NULL;
1004   cf.hInstance = (HINSTANCE) NULL;
1005   cf.lpszStyle = (LPSTR)NULL;
1006   cf.nFontType = SCREEN_FONTTYPE;
1007   cf.nSizeMin = 0;
1008   cf.nSizeMax = 0;
1009
1010   /* Display the CHOOSEFONT common-dialog box. */
1011   if (!ChooseFont(&cf)) {
1012     return FALSE;
1013   }
1014
1015   /* Create a logical font based on the user's   */
1016   /* selection and return a handle identifying   */
1017   /* that font. */
1018   hf = CreateFontIndirect(cf.lpLogFont);
1019   if (hf == NULL) {
1020     return FALSE;
1021   }
1022
1023   font->hf = hf;
1024   font->mfp.pointSize = (float) (cf.iPointSize / 10.0);
1025   font->mfp.bold = (font->lf.lfWeight >= FW_BOLD);
1026   font->mfp.italic = font->lf.lfItalic;
1027   font->mfp.underline = font->lf.lfUnderline;
1028   font->mfp.strikeout = font->lf.lfStrikeOut;
1029   strcpy(font->mfp.faceName, font->lf.lfFaceName);
1030   return TRUE;
1031 }
1032
1033
1034 VOID
1035 UpdateSampleText(HWND hDlg, int id, MyColorizeAttribs *mca)
1036 {
1037   CHARFORMAT cf;
1038   cf.cbSize = sizeof(CHARFORMAT);
1039   cf.dwMask = 
1040     CFM_COLOR|CFM_BOLD|CFM_ITALIC|CFM_UNDERLINE|CFM_STRIKEOUT|CFM_FACE|CFM_SIZE;
1041   cf.crTextColor = mca->color;
1042   cf.dwEffects = mca->effects;
1043   strcpy(cf.szFaceName, font[boardSize][CONSOLE_FONT]->mfp.faceName);
1044   /* 
1045    * The 20.0 below is in fact documented. yHeight is expressed in twips.
1046    * A twip is 1/20 of a font's point size. See documentation of CHARFORMAT.
1047    * --msw
1048    */
1049   cf.yHeight = (int)(font[boardSize][CONSOLE_FONT]->mfp.pointSize * 20.0 + 0.5);
1050   cf.bCharSet = DEFAULT_CHARSET; /* should be ignored anyway */
1051   cf.bPitchAndFamily = DEFAULT_PITCH|FF_DONTCARE;
1052   SendDlgItemMessage(hDlg, id, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&cf);
1053 }
1054
1055 LRESULT CALLBACK
1056 ColorizeTextDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
1057 {
1058   static MyColorizeAttribs mca;
1059   static ColorClass cc;
1060   COLORREF background = (COLORREF)0;
1061
1062   switch (message) {
1063   case WM_INITDIALOG:
1064     cc = (ColorClass)lParam;
1065     mca = colorizeAttribs[cc];
1066     /* Center the dialog over the application window */
1067     CenterWindow (hDlg, GetWindow (hDlg, GW_OWNER));
1068     /* Initialize the dialog items */
1069     CheckDlgButton(hDlg, OPT_Bold, (mca.effects & CFE_BOLD) != 0);
1070     CheckDlgButton(hDlg, OPT_Italic, (mca.effects & CFE_ITALIC) != 0);
1071     CheckDlgButton(hDlg, OPT_Underline, (mca.effects & CFE_UNDERLINE) != 0);
1072     CheckDlgButton(hDlg, OPT_Strikeout, (mca.effects & CFE_STRIKEOUT) != 0);
1073
1074     /* get the current background color from the parent window */
1075     SendMessage(GetWindow(hDlg, GW_OWNER),WM_COMMAND, 
1076                 (WPARAM)WM_USER_GetConsoleBackground, 
1077                 (LPARAM)&background);
1078
1079     /* set the background color */
1080     SendDlgItemMessage(hDlg, OPT_Sample, EM_SETBKGNDCOLOR, FALSE, background);
1081
1082     SetDlgItemText(hDlg, OPT_Sample, mca.name);
1083     UpdateSampleText(hDlg, OPT_Sample, &mca);
1084     return TRUE;
1085
1086   case WM_COMMAND: /* message: received a command */
1087     switch (LOWORD(wParam)) {
1088     case IDOK:
1089       /* Read changed options from the dialog box */
1090       colorizeAttribs[cc] = mca;
1091       textAttribs[cc].color = mca.color;
1092       textAttribs[cc].effects = mca.effects;
1093       Colorize(currentColorClass, TRUE);
1094       if (cc == ColorNormal) {
1095         CHARFORMAT cf;
1096         cf.cbSize = sizeof(CHARFORMAT);
1097         cf.dwMask = CFM_COLOR;
1098         cf.crTextColor = mca.color;
1099         SendDlgItemMessage(hwndConsole, OPT_ConsoleInput, 
1100           EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&cf);
1101       }
1102       EndDialog(hDlg, TRUE);
1103       return TRUE;
1104
1105     case IDCANCEL:
1106       EndDialog(hDlg, FALSE);
1107       return TRUE;
1108
1109     case OPT_ChooseColor:
1110       ChangeColor(hDlg, &mca.color);
1111       UpdateSampleText(hDlg, OPT_Sample, &mca);
1112       return TRUE;
1113
1114     default:
1115       mca.effects =
1116         (IsDlgButtonChecked(hDlg, OPT_Bold) ? CFE_BOLD : 0) |
1117         (IsDlgButtonChecked(hDlg, OPT_Italic) ? CFE_ITALIC : 0) |
1118         (IsDlgButtonChecked(hDlg, OPT_Underline) ? CFE_UNDERLINE : 0) |
1119         (IsDlgButtonChecked(hDlg, OPT_Strikeout) ? CFE_STRIKEOUT : 0);
1120       UpdateSampleText(hDlg, OPT_Sample, &mca);
1121       break;
1122     }
1123     break;
1124   }
1125   return FALSE;
1126 }
1127
1128 VOID
1129 ColorizeTextPopup(HWND hwnd, ColorClass cc)
1130 {
1131   FARPROC lpProc;
1132
1133   lpProc = MakeProcInstance((FARPROC)ColorizeTextDialog, hInst);
1134   DialogBoxParam(hInst, MAKEINTRESOURCE(DLG_Colorize),
1135     hwnd, (DLGPROC)lpProc, (LPARAM) cc);
1136   FreeProcInstance(lpProc);
1137 }
1138
1139 VOID
1140 SetIcsOptionEnables(HWND hDlg)
1141 {
1142 #define ENABLE_DLG_ITEM(x,y) EnableWindow(GetDlgItem(hDlg,(x)), (y))
1143
1144   UINT state = IsDlgButtonChecked(hDlg, OPT_Premove);
1145   ENABLE_DLG_ITEM(OPT_PremoveWhite, state);
1146   ENABLE_DLG_ITEM(OPT_PremoveWhiteText, state);
1147   ENABLE_DLG_ITEM(OPT_PremoveBlack, state);
1148   ENABLE_DLG_ITEM(OPT_PremoveBlackText, state);
1149
1150   ENABLE_DLG_ITEM(OPT_IcsAlarmTime, IsDlgButtonChecked(hDlg, OPT_IcsAlarm));
1151
1152 #undef ENABLE_DLG_ITEM
1153 }
1154
1155
1156 LRESULT CALLBACK
1157 IcsOptionsDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
1158 {
1159   char buf[MSG_SIZ];
1160   int number;
1161   int i;
1162   static COLORREF cbc;
1163   static MyColorizeAttribs *mca;
1164   COLORREF *colorref;
1165
1166   switch (message) {
1167   case WM_INITDIALOG: /* message: initialize dialog box */
1168
1169     mca = colorizeAttribs;
1170
1171     for (i=0; i < NColorClasses - 1; i++) {
1172       mca[i].color   = textAttribs[i].color;
1173       mca[i].effects = textAttribs[i].effects;
1174     }
1175     cbc = consoleBackgroundColor;
1176
1177     /* Center the dialog over the application window */
1178     CenterWindow (hDlg, GetWindow (hDlg, GW_OWNER));
1179
1180     /* Initialize the dialog items */
1181 #define CHECK_BOX(x,y) CheckDlgButton(hDlg, (x), (BOOL)(y))
1182
1183     CHECK_BOX(OPT_AutoComment, appData.autoComment);
1184     CHECK_BOX(OPT_AutoObserve, appData.autoObserve);
1185     CHECK_BOX(OPT_GetMoveList, appData.getMoveList);
1186     CHECK_BOX(OPT_LocalLineEditing, appData.localLineEditing);
1187     CHECK_BOX(OPT_QuietPlay, appData.quietPlay);
1188     CHECK_BOX(OPT_Premove, appData.premove);
1189     CHECK_BOX(OPT_PremoveWhite, appData.premoveWhite);
1190     CHECK_BOX(OPT_PremoveBlack, appData.premoveBlack);
1191     CHECK_BOX(OPT_IcsAlarm, appData.icsAlarm);
1192     CHECK_BOX(OPT_DontColorize, !appData.colorize);
1193
1194 #undef CHECK_BOX
1195
1196     sprintf(buf, "%d", appData.icsAlarmTime / 1000);
1197     SetDlgItemText(hDlg, OPT_IcsAlarmTime, buf);
1198     SetDlgItemText(hDlg, OPT_PremoveWhiteText, appData.premoveWhiteText);
1199     SetDlgItemText(hDlg, OPT_PremoveBlackText, appData.premoveBlackText);
1200
1201     SendDlgItemMessage(hDlg, OPT_SampleShout,     EM_SETBKGNDCOLOR, 0, cbc);
1202     SendDlgItemMessage(hDlg, OPT_SampleSShout,    EM_SETBKGNDCOLOR, 0, cbc);
1203     SendDlgItemMessage(hDlg, OPT_SampleChannel1,  EM_SETBKGNDCOLOR, 0, cbc);
1204     SendDlgItemMessage(hDlg, OPT_SampleChannel,   EM_SETBKGNDCOLOR, 0, cbc);
1205     SendDlgItemMessage(hDlg, OPT_SampleKibitz,    EM_SETBKGNDCOLOR, 0, cbc);
1206     SendDlgItemMessage(hDlg, OPT_SampleTell,      EM_SETBKGNDCOLOR, 0, cbc);
1207     SendDlgItemMessage(hDlg, OPT_SampleChallenge, EM_SETBKGNDCOLOR, 0, cbc);
1208     SendDlgItemMessage(hDlg, OPT_SampleRequest,   EM_SETBKGNDCOLOR, 0, cbc);
1209     SendDlgItemMessage(hDlg, OPT_SampleSeek,      EM_SETBKGNDCOLOR, 0, cbc);
1210     SendDlgItemMessage(hDlg, OPT_SampleNormal,    EM_SETBKGNDCOLOR, 0, cbc);
1211
1212     SetDlgItemText(hDlg, OPT_SampleShout,     mca[ColorShout].name);
1213     SetDlgItemText(hDlg, OPT_SampleSShout,    mca[ColorSShout].name);
1214     SetDlgItemText(hDlg, OPT_SampleChannel1,  mca[ColorChannel1].name);
1215     SetDlgItemText(hDlg, OPT_SampleChannel,   mca[ColorChannel].name);
1216     SetDlgItemText(hDlg, OPT_SampleKibitz,    mca[ColorKibitz].name);
1217     SetDlgItemText(hDlg, OPT_SampleTell,      mca[ColorTell].name);
1218     SetDlgItemText(hDlg, OPT_SampleChallenge, mca[ColorChallenge].name);
1219     SetDlgItemText(hDlg, OPT_SampleRequest,   mca[ColorRequest].name);
1220     SetDlgItemText(hDlg, OPT_SampleSeek,      mca[ColorSeek].name);
1221     SetDlgItemText(hDlg, OPT_SampleNormal,    mca[ColorNormal].name);
1222
1223     UpdateSampleText(hDlg, OPT_SampleShout,     &mca[ColorShout]);
1224     UpdateSampleText(hDlg, OPT_SampleSShout,    &mca[ColorSShout]);
1225     UpdateSampleText(hDlg, OPT_SampleChannel1,  &mca[ColorChannel1]);
1226     UpdateSampleText(hDlg, OPT_SampleChannel,   &mca[ColorChannel]);
1227     UpdateSampleText(hDlg, OPT_SampleKibitz,    &mca[ColorKibitz]);
1228     UpdateSampleText(hDlg, OPT_SampleTell,      &mca[ColorTell]);
1229     UpdateSampleText(hDlg, OPT_SampleChallenge, &mca[ColorChallenge]);
1230     UpdateSampleText(hDlg, OPT_SampleRequest,   &mca[ColorRequest]);
1231     UpdateSampleText(hDlg, OPT_SampleSeek,      &mca[ColorSeek]);
1232     UpdateSampleText(hDlg, OPT_SampleNormal,    &mca[ColorNormal]);
1233
1234     SetIcsOptionEnables(hDlg);
1235     return TRUE;
1236
1237   case WM_COMMAND: /* message: received a command */
1238     switch (LOWORD(wParam)) {
1239
1240     case WM_USER_GetConsoleBackground: 
1241       /* the ColorizeTextDialog needs the current background color */
1242       colorref = (COLORREF *)lParam;
1243       *colorref = cbc;
1244       return FALSE;
1245
1246     case IDOK:
1247       /* Read changed options from the dialog box */
1248       GetDlgItemText(hDlg, OPT_IcsAlarmTime, buf, MSG_SIZ);
1249       if (sscanf(buf, "%d", &number) != 1 || (number < 0)){
1250           MessageBox(hDlg, "Invalid ICS Alarm Time",
1251                      "Option Error", MB_OK|MB_ICONEXCLAMATION);
1252           return FALSE;
1253       }
1254
1255 #define IS_CHECKED(x) (Boolean)IsDlgButtonChecked(hDlg, (x))
1256
1257       appData.icsAlarm         = IS_CHECKED(OPT_IcsAlarm);
1258       appData.premove          = IS_CHECKED(OPT_Premove);
1259       appData.premoveWhite     = IS_CHECKED(OPT_PremoveWhite);
1260       appData.premoveBlack     = IS_CHECKED(OPT_PremoveBlack);
1261       appData.autoComment      = IS_CHECKED(OPT_AutoComment);
1262       appData.autoObserve      = IS_CHECKED(OPT_AutoObserve);
1263       appData.getMoveList      = IS_CHECKED(OPT_GetMoveList);
1264       appData.localLineEditing = IS_CHECKED(OPT_LocalLineEditing);
1265       appData.quietPlay        = IS_CHECKED(OPT_QuietPlay);
1266
1267 #undef IS_CHECKED
1268
1269       appData.icsAlarmTime = number * 1000;
1270       GetDlgItemText(hDlg, OPT_PremoveWhiteText, appData.premoveWhiteText, 5);
1271       GetDlgItemText(hDlg, OPT_PremoveBlackText, appData.premoveBlackText, 5);
1272
1273       if (appData.localLineEditing) {
1274         DontEcho();
1275         EchoOn();
1276       } else {
1277         DoEcho();
1278         EchoOff();
1279       }
1280
1281       appData.colorize =
1282         (Boolean)!IsDlgButtonChecked(hDlg, OPT_DontColorize);
1283
1284       if (!appData.colorize) {
1285         CHARFORMAT cf;
1286         COLORREF background = ParseColorName(COLOR_BKGD);
1287         /*
1288         SetDefaultTextAttribs();
1289         Colorize(currentColorClass);
1290         */
1291         cf.cbSize = sizeof(CHARFORMAT);
1292         cf.dwMask = CFM_COLOR;
1293         cf.crTextColor = ParseColorName(COLOR_NORMAL);
1294
1295         SendDlgItemMessage(hwndConsole, OPT_ConsoleInput, 
1296           EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&cf);
1297         SendDlgItemMessage(hwndConsole, OPT_ConsoleText, 
1298           EM_SETBKGNDCOLOR, FALSE, background);
1299         SendDlgItemMessage(hwndConsole, OPT_ConsoleInput, 
1300           EM_SETBKGNDCOLOR, FALSE, background);
1301       }
1302
1303       if (cbc != consoleBackgroundColor) {
1304         consoleBackgroundColor = cbc;
1305         if (appData.colorize) {
1306           SendDlgItemMessage(hwndConsole, OPT_ConsoleText, 
1307             EM_SETBKGNDCOLOR, FALSE, consoleBackgroundColor);
1308           SendDlgItemMessage(hwndConsole, OPT_ConsoleInput, 
1309             EM_SETBKGNDCOLOR, FALSE, consoleBackgroundColor);
1310         }
1311       }
1312
1313       for (i=0; i < NColorClasses - 1; i++) {
1314         textAttribs[i].color   = mca[i].color;
1315         textAttribs[i].effects = mca[i].effects;
1316       }
1317
1318       EndDialog(hDlg, TRUE);
1319       return TRUE;
1320
1321     case IDCANCEL:
1322       EndDialog(hDlg, FALSE);
1323       return TRUE;
1324
1325     case OPT_ChooseShoutColor:
1326       ColorizeTextPopup(hDlg, ColorShout);
1327       UpdateSampleText(hDlg, OPT_SampleShout, &mca[ColorShout]);
1328       break;
1329
1330     case OPT_ChooseSShoutColor:
1331       ColorizeTextPopup(hDlg, ColorSShout);
1332       UpdateSampleText(hDlg, OPT_SampleSShout, &mca[ColorSShout]);
1333       break;
1334
1335     case OPT_ChooseChannel1Color:
1336       ColorizeTextPopup(hDlg, ColorChannel1);
1337       UpdateSampleText(hDlg, OPT_SampleChannel1, 
1338                        &colorizeAttribs[ColorChannel1]);
1339       break;
1340
1341     case OPT_ChooseChannelColor:
1342       ColorizeTextPopup(hDlg, ColorChannel);
1343       UpdateSampleText(hDlg, OPT_SampleChannel, &mca[ColorChannel]);
1344       break;
1345
1346     case OPT_ChooseKibitzColor:
1347       ColorizeTextPopup(hDlg, ColorKibitz);
1348       UpdateSampleText(hDlg, OPT_SampleKibitz, &mca[ColorKibitz]);
1349       break;
1350
1351     case OPT_ChooseTellColor:
1352       ColorizeTextPopup(hDlg, ColorTell);
1353       UpdateSampleText(hDlg, OPT_SampleTell, &mca[ColorTell]);
1354       break;
1355
1356     case OPT_ChooseChallengeColor:
1357       ColorizeTextPopup(hDlg, ColorChallenge);
1358       UpdateSampleText(hDlg, OPT_SampleChallenge, &mca[ColorChallenge]);
1359       break;
1360
1361     case OPT_ChooseRequestColor:
1362       ColorizeTextPopup(hDlg, ColorRequest);
1363       UpdateSampleText(hDlg, OPT_SampleRequest, &mca[ColorRequest]);
1364       break;
1365
1366     case OPT_ChooseSeekColor:
1367       ColorizeTextPopup(hDlg, ColorSeek);
1368       UpdateSampleText(hDlg, OPT_SampleSeek, &mca[ColorSeek]);
1369       break;
1370
1371     case OPT_ChooseNormalColor:
1372       ColorizeTextPopup(hDlg, ColorNormal);
1373       UpdateSampleText(hDlg, OPT_SampleNormal, &mca[ColorNormal]);
1374       break;
1375
1376     case OPT_ChooseBackgroundColor:
1377       if (ChangeColor(hDlg, &cbc)) {
1378         SendDlgItemMessage(hDlg, OPT_SampleShout,     EM_SETBKGNDCOLOR, 0, cbc);
1379         SendDlgItemMessage(hDlg, OPT_SampleSShout,    EM_SETBKGNDCOLOR, 0, cbc);
1380         SendDlgItemMessage(hDlg, OPT_SampleChannel1,  EM_SETBKGNDCOLOR, 0, cbc);
1381         SendDlgItemMessage(hDlg, OPT_SampleChannel,   EM_SETBKGNDCOLOR, 0, cbc);
1382         SendDlgItemMessage(hDlg, OPT_SampleKibitz,    EM_SETBKGNDCOLOR, 0, cbc);
1383         SendDlgItemMessage(hDlg, OPT_SampleTell,      EM_SETBKGNDCOLOR, 0, cbc);
1384         SendDlgItemMessage(hDlg, OPT_SampleChallenge, EM_SETBKGNDCOLOR, 0, cbc);
1385         SendDlgItemMessage(hDlg, OPT_SampleRequest,   EM_SETBKGNDCOLOR, 0, cbc);
1386         SendDlgItemMessage(hDlg, OPT_SampleSeek,      EM_SETBKGNDCOLOR, 0, cbc);
1387         SendDlgItemMessage(hDlg, OPT_SampleNormal,    EM_SETBKGNDCOLOR, 0, cbc);
1388       }
1389       break;
1390
1391     case OPT_DefaultColors:
1392       for (i=0; i < NColorClasses - 1; i++)
1393         ParseAttribs(&mca[i].color, 
1394                      &mca[i].effects,
1395                      defaultTextAttribs[i]);
1396
1397       cbc = ParseColorName(COLOR_BKGD);
1398       SendDlgItemMessage(hDlg, OPT_SampleShout,     EM_SETBKGNDCOLOR, 0, cbc);
1399       SendDlgItemMessage(hDlg, OPT_SampleSShout,    EM_SETBKGNDCOLOR, 0, cbc);
1400       SendDlgItemMessage(hDlg, OPT_SampleChannel1,  EM_SETBKGNDCOLOR, 0, cbc);
1401       SendDlgItemMessage(hDlg, OPT_SampleChannel,   EM_SETBKGNDCOLOR, 0, cbc);
1402       SendDlgItemMessage(hDlg, OPT_SampleKibitz,    EM_SETBKGNDCOLOR, 0, cbc);
1403       SendDlgItemMessage(hDlg, OPT_SampleTell,      EM_SETBKGNDCOLOR, 0, cbc);
1404       SendDlgItemMessage(hDlg, OPT_SampleChallenge, EM_SETBKGNDCOLOR, 0, cbc);
1405       SendDlgItemMessage(hDlg, OPT_SampleRequest,   EM_SETBKGNDCOLOR, 0, cbc);
1406       SendDlgItemMessage(hDlg, OPT_SampleSeek,      EM_SETBKGNDCOLOR, 0, cbc);
1407       SendDlgItemMessage(hDlg, OPT_SampleNormal,    EM_SETBKGNDCOLOR, 0, cbc);
1408
1409       UpdateSampleText(hDlg, OPT_SampleShout,     &mca[ColorShout]);
1410       UpdateSampleText(hDlg, OPT_SampleSShout,    &mca[ColorSShout]);
1411       UpdateSampleText(hDlg, OPT_SampleChannel1,  &mca[ColorChannel1]);
1412       UpdateSampleText(hDlg, OPT_SampleChannel,   &mca[ColorChannel]);
1413       UpdateSampleText(hDlg, OPT_SampleKibitz,    &mca[ColorKibitz]);
1414       UpdateSampleText(hDlg, OPT_SampleTell,      &mca[ColorTell]);
1415       UpdateSampleText(hDlg, OPT_SampleChallenge, &mca[ColorChallenge]);
1416       UpdateSampleText(hDlg, OPT_SampleRequest,   &mca[ColorRequest]);
1417       UpdateSampleText(hDlg, OPT_SampleSeek,      &mca[ColorSeek]);
1418       UpdateSampleText(hDlg, OPT_SampleNormal,    &mca[ColorNormal]);
1419       break;
1420
1421     default:
1422       SetIcsOptionEnables(hDlg);
1423       break;
1424     }
1425     break;
1426   }
1427   return FALSE;
1428 }
1429
1430 VOID
1431 IcsOptionsPopup(HWND hwnd)
1432 {
1433   FARPROC lpProc = MakeProcInstance((FARPROC)IcsOptionsDialog, hInst);
1434   DialogBox(hInst, MAKEINTRESOURCE(DLG_IcsOptions), hwnd,
1435             (DLGPROC) lpProc);
1436   FreeProcInstance(lpProc);
1437 }
1438
1439 /*---------------------------------------------------------------------------*\
1440  *
1441  * Fonts Dialog functions
1442  *
1443 \*---------------------------------------------------------------------------*/
1444
1445 VOID
1446 SetSampleFontText(HWND hwnd, int id, const MyFont *mf)
1447 {
1448   char buf[MSG_SIZ];
1449   HWND hControl;
1450   HDC hdc;
1451   CHARFORMAT cf;
1452   SIZE size;
1453   RECT rectClient, rectFormat;
1454   HFONT oldFont;
1455   POINT center;
1456   int len;
1457
1458   len = sprintf(buf, "%.0f pt. %s%s%s\n",
1459                 mf->mfp.pointSize, mf->mfp.faceName,
1460                 mf->mfp.bold ? " bold" : "",
1461                 mf->mfp.italic ? " italic" : "");
1462   SetDlgItemText(hwnd, id, buf);
1463
1464   hControl = GetDlgItem(hwnd, id);
1465   hdc = GetDC(hControl);
1466   SetMapMode(hdc, MM_TEXT);     /* 1 pixel == 1 logical unit */
1467   oldFont = SelectObject(hdc, mf->hf);
1468   
1469   /* get number of logical units necessary to display font name */
1470   GetTextExtentPoint32(hdc, buf, len, &size);
1471
1472   /* calculate formatting rectangle in the rich edit control.  
1473    * May be larger or smaller than the actual control.
1474    */
1475   GetClientRect(hControl, &rectClient);
1476   center.x = (rectClient.left + rectClient.right) / 2;
1477   center.y = (rectClient.top  + rectClient.bottom) / 2;
1478   rectFormat.top    = center.y - (size.cy / 2) - 1;
1479   rectFormat.bottom = center.y + (size.cy / 2) + 1;
1480   rectFormat.left   = center.x - (size.cx / 2) - 1;
1481   rectFormat.right  = center.x + (size.cx / 2) + 1;
1482
1483 #if 0
1484   fprintf(debugFP, "\nfont: %s\n"
1485                    "center.x   %d, centerY %d\n"
1486                    "size.cx    %d, size.cy %d\n"
1487                    "client.top %d, bottom %d, left %d, right %d\n"
1488                    "format.top %d, bottom %d, left %d, right %d\n",
1489                    buf,
1490                    center.x, center.y,
1491                    size.cx, size.cy,
1492                    rectClient.top, rectClient.bottom, rectClient.left,
1493                    rectClient.right,
1494                    rectFormat.top, rectFormat.bottom, rectFormat.left,
1495                    rectFormat.right);
1496 #endif
1497
1498   cf.cbSize = sizeof(CHARFORMAT);
1499   cf.dwMask = CFM_FACE|CFM_SIZE|CFM_CHARSET|CFM_BOLD|CFM_ITALIC;
1500   cf.dwEffects = 0;
1501   if (mf->lf.lfWeight == FW_BOLD) cf.dwEffects |= CFE_BOLD;
1502   if (mf->lf.lfItalic) cf.dwEffects |= CFE_ITALIC;
1503   strcpy(cf.szFaceName, mf->mfp.faceName);
1504   /*
1505    * yHeight is expressed in twips.  A twip is 1/20 of a font's point
1506    * size. See documentation of CHARFORMAT.  --msw
1507    */
1508   cf.yHeight = (int)(mf->mfp.pointSize * 20.0 + 0.5);
1509   cf.bCharSet = mf->lf.lfCharSet;
1510   cf.bPitchAndFamily = mf->lf.lfPitchAndFamily;
1511
1512   /* format the text in the rich edit control */
1513   SendMessage(hControl, EM_SETCHARFORMAT, SCF_ALL, (LPARAM) &cf);
1514   SendMessage(hControl, EM_SETRECT, (WPARAM)0, (LPARAM) &rectFormat);
1515
1516   /* clean up */
1517   SelectObject(hdc, oldFont);
1518   ReleaseDC(hControl, hdc);
1519 }
1520
1521 VOID
1522 CopyFont(MyFont *dest, const MyFont *src)
1523 {
1524   dest->mfp.pointSize = src->mfp.pointSize;
1525   dest->mfp.bold      = src->mfp.bold;
1526   dest->mfp.italic    = src->mfp.italic;
1527   dest->mfp.underline = src->mfp.underline;
1528   dest->mfp.strikeout = src->mfp.strikeout;
1529   lstrcpy(dest->mfp.faceName, src->mfp.faceName);
1530   CreateFontInMF(dest);
1531 }
1532
1533
1534 LRESULT CALLBACK
1535 FontOptionsDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
1536 {
1537   static MyFont workFont[NUM_FONTS];
1538   static BOOL firstPaint;
1539   int i;
1540   RECT rect;
1541
1542   switch (message) {
1543   case WM_INITDIALOG:
1544
1545     /* copy the current font settings into a working copy */
1546     for (i=0; i < NUM_FONTS; i++)
1547       CopyFont(&workFont[i], font[boardSize][i]);
1548
1549     if (!appData.icsActive)
1550       EnableWindow(GetDlgItem(hDlg, OPT_ChooseConsoleFont), FALSE);
1551
1552     firstPaint = TRUE;  /* see rant below */
1553
1554     /* If I don't call SetFocus(), the dialog won't respond to the keyboard
1555      * when first drawn. Why is this the only dialog that behaves this way? Is
1556      * is the WM_PAINT stuff below?? Sigh...
1557      */
1558     SetFocus(GetDlgItem(hDlg, IDOK));
1559     break;
1560
1561   case WM_PAINT:
1562     /* This should not be necessary. However, if SetSampleFontText() is called
1563      * in response to WM_INITDIALOG, the strings are not properly centered in
1564      * the controls when the dialog first appears. I can't figure out why, so
1565      * this is the workaround.  --msw
1566      */
1567     if (firstPaint) {
1568       SetSampleFontText(hDlg, OPT_SampleClockFont, &workFont[CLOCK_FONT]);
1569       SetSampleFontText(hDlg, OPT_SampleMessageFont, &workFont[MESSAGE_FONT]);
1570       SetSampleFontText(hDlg, OPT_SampleCoordFont, &workFont[COORD_FONT]);
1571       SetSampleFontText(hDlg, OPT_SampleTagFont, &workFont[EDITTAGS_FONT]);
1572       SetSampleFontText(hDlg, OPT_SampleCommentsFont, &workFont[COMMENT_FONT]);
1573       SetSampleFontText(hDlg, OPT_SampleConsoleFont, &workFont[CONSOLE_FONT]);
1574       SetSampleFontText(hDlg, OPT_SampleMoveHistoryFont, &workFont[MOVEHISTORY_FONT]);
1575       firstPaint = FALSE;
1576     }
1577     break;
1578
1579   case WM_COMMAND: /* message: received a command */
1580     switch (LOWORD(wParam)) {
1581
1582     case IDOK:
1583       /* again, it seems to avoid redraw problems if we call EndDialog first */
1584       EndDialog(hDlg, FALSE);
1585
1586       /* copy modified settings back to the fonts array */
1587       for (i=0; i < NUM_FONTS; i++)
1588         CopyFont(font[boardSize][i], &workFont[i]);
1589
1590       /* a sad necessity due to the original design of having a separate
1591        * console font, tags font, and comment font for each board size.  IMHO
1592        * these fonts should not be dependent on the current board size.  I'm
1593        * running out of time, so I am doing this hack rather than redesign the
1594        * data structure. Besides, I think if I redesigned the data structure, I
1595        * might break backwards compatibility with old winboard.ini files.
1596        * --msw
1597        */
1598       for (i=0; i < NUM_SIZES; i++) {
1599         CopyFont(font[i][EDITTAGS_FONT], &workFont[EDITTAGS_FONT]);
1600         CopyFont(font[i][CONSOLE_FONT],  &workFont[CONSOLE_FONT]);
1601         CopyFont(font[i][COMMENT_FONT],  &workFont[COMMENT_FONT]);
1602         CopyFont(font[i][MOVEHISTORY_FONT],  &workFont[MOVEHISTORY_FONT]);
1603       }
1604       /* end sad necessity */
1605
1606       InitDrawingSizes(boardSize, 0);
1607       InvalidateRect(hwndMain, NULL, TRUE);
1608
1609       if (commentDialog) {
1610         SendDlgItemMessage(commentDialog, OPT_CommentText,
1611           WM_SETFONT, (WPARAM)font[boardSize][COMMENT_FONT]->hf, 
1612           MAKELPARAM(TRUE, 0));
1613         GetClientRect(GetDlgItem(commentDialog, OPT_CommentText), &rect);
1614         InvalidateRect(commentDialog, &rect, TRUE);
1615       }
1616
1617       if (editTagsDialog) {
1618         SendDlgItemMessage(editTagsDialog, OPT_TagsText,
1619           WM_SETFONT, (WPARAM)font[boardSize][EDITTAGS_FONT]->hf, 
1620           MAKELPARAM(TRUE, 0));
1621         GetClientRect(GetDlgItem(editTagsDialog, OPT_TagsText), &rect);
1622         InvalidateRect(editTagsDialog, &rect, TRUE);
1623       }
1624
1625       if( moveHistoryDialog != NULL ) {
1626         SendDlgItemMessage(moveHistoryDialog, IDC_MoveHistory,
1627           WM_SETFONT, (WPARAM)font[boardSize][MOVEHISTORY_FONT]->hf, 
1628           MAKELPARAM(TRUE, 0));
1629         InvalidateRect(editTagsDialog, NULL, TRUE);
1630       }
1631
1632       if (hwndConsole) {
1633         ChangedConsoleFont();
1634       }
1635
1636       for (i=0; i<NUM_FONTS; i++)
1637         DeleteObject(&workFont[i].hf);
1638
1639       return TRUE;
1640
1641     case IDCANCEL:
1642       for (i=0; i<NUM_FONTS; i++)
1643         DeleteObject(&workFont[i].hf);
1644       EndDialog(hDlg, FALSE);
1645       return TRUE;
1646
1647     case OPT_ChooseClockFont:
1648       MyCreateFont(hDlg, &workFont[CLOCK_FONT]);
1649       SetSampleFontText(hDlg, OPT_SampleClockFont, &workFont[CLOCK_FONT]);
1650       break;
1651
1652     case OPT_ChooseMessageFont:
1653       MyCreateFont(hDlg, &workFont[MESSAGE_FONT]);
1654       SetSampleFontText(hDlg, OPT_SampleMessageFont, &workFont[MESSAGE_FONT]);
1655       break;
1656
1657     case OPT_ChooseCoordFont:
1658       MyCreateFont(hDlg, &workFont[COORD_FONT]);
1659       SetSampleFontText(hDlg, OPT_SampleCoordFont, &workFont[COORD_FONT]);
1660       break;
1661
1662     case OPT_ChooseTagFont:
1663       MyCreateFont(hDlg, &workFont[EDITTAGS_FONT]);
1664       SetSampleFontText(hDlg, OPT_SampleTagFont, &workFont[EDITTAGS_FONT]);
1665       break;
1666
1667     case OPT_ChooseCommentsFont:
1668       MyCreateFont(hDlg, &workFont[COMMENT_FONT]);
1669       SetSampleFontText(hDlg, OPT_SampleCommentsFont, &workFont[COMMENT_FONT]);
1670       break;
1671
1672     case OPT_ChooseConsoleFont:
1673       MyCreateFont(hDlg, &workFont[CONSOLE_FONT]);
1674       SetSampleFontText(hDlg, OPT_SampleConsoleFont, &workFont[CONSOLE_FONT]);
1675       break;
1676
1677     case OPT_ChooseMoveHistoryFont:
1678       MyCreateFont(hDlg, &workFont[MOVEHISTORY_FONT]);
1679       SetSampleFontText(hDlg, OPT_SampleMoveHistoryFont, &workFont[MOVEHISTORY_FONT]);
1680       break;
1681
1682     case OPT_DefaultFonts:
1683       for (i=0; i<NUM_FONTS; i++) {
1684         DeleteObject(&workFont[i].hf);
1685         ParseFontName(font[boardSize][i]->def, &workFont[i].mfp);
1686         CreateFontInMF(&workFont[i]);
1687       }
1688       SetSampleFontText(hDlg, OPT_SampleClockFont, &workFont[CLOCK_FONT]);
1689       SetSampleFontText(hDlg, OPT_SampleMessageFont, &workFont[MESSAGE_FONT]);
1690       SetSampleFontText(hDlg, OPT_SampleCoordFont, &workFont[COORD_FONT]);
1691       SetSampleFontText(hDlg, OPT_SampleTagFont, &workFont[EDITTAGS_FONT]);
1692       SetSampleFontText(hDlg, OPT_SampleCommentsFont, &workFont[COMMENT_FONT]);
1693       SetSampleFontText(hDlg, OPT_SampleConsoleFont, &workFont[CONSOLE_FONT]);
1694       SetSampleFontText(hDlg, OPT_SampleMoveHistoryFont, &workFont[MOVEHISTORY_FONT]);
1695       break;
1696     }
1697   }
1698   return FALSE;
1699 }
1700
1701 VOID
1702 FontsOptionsPopup(HWND hwnd)
1703 {
1704   FARPROC lpProc = MakeProcInstance((FARPROC)FontOptionsDialog, hInst);
1705   DialogBox(hInst, MAKEINTRESOURCE(DLG_Fonts), hwnd,
1706           (DLGPROC) lpProc);
1707   FreeProcInstance(lpProc);
1708 }
1709
1710 /*---------------------------------------------------------------------------*\
1711  *
1712  * Sounds Dialog functions
1713  *
1714 \*---------------------------------------------------------------------------*/
1715
1716
1717 SoundComboData soundComboData[] = {
1718   {"Move", NULL},
1719   {"Bell", NULL},
1720   {"ICS Alarm", NULL},
1721   {"ICS Win", NULL},
1722   {"ICS Loss", NULL},
1723   {"ICS Draw", NULL},
1724   {"ICS Unfinished", NULL},
1725   {"Shout", NULL},
1726   {"SShout/CShout", NULL},
1727   {"Channel 1", NULL},
1728   {"Channel", NULL},
1729   {"Kibitz", NULL},
1730   {"Tell", NULL},
1731   {"Challenge", NULL},
1732   {"Request", NULL},
1733   {"Seek", NULL},
1734   {NULL, NULL},
1735 };
1736
1737
1738 void
1739 InitSoundComboData(SoundComboData *scd)
1740 {
1741   SoundClass sc;
1742   ColorClass cc;
1743   int index;
1744
1745   /* copy current sound settings to combo array */
1746
1747   for ( sc = (SoundClass)0; sc < NSoundClasses; sc++) {
1748     scd[sc].name = strdup(sounds[sc].name);
1749   }
1750   for ( cc = (ColorClass)0; cc < NColorClasses - 2; cc++) {
1751     index = (int)cc + (int)NSoundClasses;
1752     scd[index].name = strdup(textAttribs[cc].sound.name);
1753   }
1754 }
1755
1756
1757 void
1758 ResetSoundComboData(SoundComboData *scd)
1759 {
1760   while (scd->label) {
1761     if (scd->name != NULL) {
1762       free (scd->name);
1763       scd->name = NULL;
1764     }
1765     scd++;
1766   }
1767 }
1768
1769 void
1770 InitSoundCombo(HWND hwndCombo, SoundComboData *scd)
1771 {
1772   char buf[255];
1773   DWORD err;
1774   DWORD cnt = 0;
1775   SendMessage(hwndCombo, CB_RESETCONTENT, 0, 0);
1776
1777   /* send the labels to the combo box */
1778   while (scd->label) {
1779     err = SendMessage(hwndCombo, CB_ADDSTRING, 0, (LPARAM) scd->label);
1780     if (err != cnt++) {
1781       sprintf(buf, "InitSoundCombo(): err '%d', cnt '%d'\n",
1782           (int)err, (int)cnt);
1783       MessageBox(NULL, buf, NULL, MB_OK);
1784     }
1785     scd++;
1786   }
1787   SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) 0, (LPARAM) 0);
1788 }
1789
1790 int
1791 SoundDialogWhichRadio(HWND hDlg)
1792 {
1793   if (IsDlgButtonChecked(hDlg, OPT_NoSound)) return OPT_NoSound;
1794   if (IsDlgButtonChecked(hDlg, OPT_DefaultBeep)) return OPT_DefaultBeep;
1795   if (IsDlgButtonChecked(hDlg, OPT_BuiltInSound)) return OPT_BuiltInSound;
1796   if (IsDlgButtonChecked(hDlg, OPT_WavFile)) return OPT_WavFile;
1797   return -1;
1798 }
1799
1800 VOID
1801 SoundDialogSetEnables(HWND hDlg, int radio)
1802 {
1803   EnableWindow(GetDlgItem(hDlg, OPT_BuiltInSoundName),
1804                radio == OPT_BuiltInSound);
1805   EnableWindow(GetDlgItem(hDlg, OPT_WavFileName), radio == OPT_WavFile);
1806   EnableWindow(GetDlgItem(hDlg, OPT_BrowseSound), radio == OPT_WavFile);
1807 }
1808
1809 char *
1810 SoundDialogGetName(HWND hDlg, int radio)
1811 {
1812   static char buf[MSG_SIZ], buf2[MSG_SIZ], buf3[MSG_SIZ];
1813   char *dummy, *ret;
1814   switch (radio) {
1815   case OPT_NoSound:
1816   default:
1817     return "";
1818   case OPT_DefaultBeep:
1819     return "$";
1820   case OPT_BuiltInSound:
1821     buf[0] = '!';
1822     GetDlgItemText(hDlg, OPT_BuiltInSoundName, buf + 1, sizeof(buf) - 1);
1823     return buf;
1824   case OPT_WavFile:
1825     GetDlgItemText(hDlg, OPT_WavFileName, buf, sizeof(buf));
1826     GetCurrentDirectory(MSG_SIZ, buf3);
1827     SetCurrentDirectory(installDir);
1828     if (GetFullPathName(buf, MSG_SIZ, buf2, &dummy)) {
1829       ret = buf2;
1830     } else {
1831       ret = buf;
1832     }
1833     SetCurrentDirectory(buf3);
1834     return ret;
1835   }
1836 }
1837
1838 void
1839 DisplaySelectedSound(HWND hDlg, HWND hCombo, const char *name)
1840 {
1841   int radio;
1842   /* 
1843    * I think it's best to clear the combo and edit boxes. It looks stupid
1844    * to have a value from another sound event sitting there grayed out.
1845    */
1846   SetDlgItemText(hDlg, OPT_WavFileName, "");
1847   SendMessage(hCombo, CB_SETCURSEL, (WPARAM) -1, (LPARAM) 0);
1848
1849   if (appData.debugMode)
1850       fprintf(debugFP, "DisplaySelectedSound(,,'%s'):\n", name);
1851   switch (name[0]) {
1852   case NULLCHAR:
1853     radio = OPT_NoSound;
1854     break;
1855   case '$':
1856     if (name[1] == NULLCHAR) {
1857       radio = OPT_DefaultBeep;
1858     } else {
1859       radio = OPT_WavFile;
1860       SetDlgItemText(hDlg, OPT_WavFileName, name);
1861     }
1862     break;
1863   case '!':
1864     if (name[1] == NULLCHAR) {
1865       radio = OPT_NoSound;
1866     } else {
1867       radio = OPT_BuiltInSound;
1868       if (SendMessage(hCombo, CB_SELECTSTRING, (WPARAM) -1, 
1869                       (LPARAM) (name + 1)) == CB_ERR) {
1870         SendMessage(hCombo, CB_SETCURSEL, (WPARAM) -1, (LPARAM) 0);
1871         SendMessage(hCombo, WM_SETTEXT, (WPARAM) 0, (LPARAM) (name + 1));
1872       }
1873     }
1874     break;
1875   default:
1876     radio = OPT_WavFile;
1877     SetDlgItemText(hDlg, OPT_WavFileName, name);
1878     break;
1879   }
1880   SoundDialogSetEnables(hDlg, radio);
1881   CheckRadioButton(hDlg, OPT_NoSound, OPT_WavFile, radio);
1882 }
1883     
1884
1885 char *builtInSoundNames[] = BUILT_IN_SOUND_NAMES;
1886
1887 LRESULT CALLBACK
1888 SoundOptionsDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
1889 {
1890   static HWND hSoundCombo;
1891   static DWORD index;
1892   static HWND hBISN;
1893   int radio;
1894   MySound tmp;
1895   FILE *f;
1896   char buf[MSG_SIZ];
1897   char *newName;
1898   SoundClass sc;
1899   ColorClass cc;
1900   SoundComboData *scd;
1901
1902   switch (message) {
1903   case WM_INITDIALOG:
1904     /* Center the dialog over the application window */
1905     CenterWindow (hDlg, GetWindow (hDlg, GW_OWNER));
1906
1907     /* Initialize the built-in sounds combo */
1908     hBISN = GetDlgItem(hDlg, OPT_BuiltInSoundName);
1909      InitComboStrings(hBISN, builtInSoundNames);
1910
1911     /* Initialize the  sound events combo */
1912     index = 0;
1913     InitSoundComboData(soundComboData);
1914     hSoundCombo = GetDlgItem(hDlg, CBO_Sounds);
1915     InitSoundCombo(hSoundCombo, soundComboData);
1916
1917     /* update the dialog */
1918     DisplaySelectedSound(hDlg, hBISN, soundComboData[index].name);
1919     return TRUE;
1920
1921   case WM_COMMAND: /* message: received a command */
1922
1923     if (((HWND)lParam == hSoundCombo) && 
1924         (HIWORD(wParam) == CBN_SELCHANGE)) {
1925       /* 
1926        * the user has selected a new sound event. We must store the name for
1927        * the previously selected event, then retrieve the name for the
1928        * newly selected event and update the dialog. 
1929        */
1930       radio = SoundDialogWhichRadio(hDlg);
1931       newName = strdup(SoundDialogGetName(hDlg, radio));
1932       
1933       if (strcmp(newName, soundComboData[index].name) != 0) {
1934         free(soundComboData[index].name);
1935         soundComboData[index].name = newName;
1936       } else {
1937         free(newName);
1938         newName = NULL;
1939       }
1940       /* now get the settings for the newly selected event */
1941       index = SendMessage(hSoundCombo, CB_GETCURSEL, (WPARAM)0, (LPARAM)0);
1942       DisplaySelectedSound(hDlg, hBISN, soundComboData[index].name);
1943       
1944       return TRUE;
1945     }
1946     switch (LOWORD(wParam)) {
1947     case IDOK:
1948       /* 
1949        * save the name for the currently selected sound event 
1950        */
1951       radio = SoundDialogWhichRadio(hDlg);
1952       newName = strdup(SoundDialogGetName(hDlg, radio));
1953
1954       if (strcmp(soundComboData[index].name, newName) != 0) {
1955         free(soundComboData[index].name);
1956         soundComboData[index].name = newName;
1957       } else {
1958         free(newName);
1959         newName = NULL;
1960       }
1961
1962       /* save all the sound names that changed and load the sounds */
1963
1964       for ( sc = (SoundClass)0; sc < NSoundClasses; sc++) {
1965         if (strcmp(soundComboData[sc].name, sounds[sc].name) != 0) {
1966           free(sounds[sc].name);
1967           sounds[sc].name = strdup(soundComboData[sc].name);
1968           MyLoadSound(&sounds[sc]);
1969         }
1970       }
1971       for ( cc = (ColorClass)0; cc < NColorClasses - 2; cc++) {
1972         index = (int)cc + (int)NSoundClasses;
1973         if (strcmp(soundComboData[index].name, 
1974                    textAttribs[cc].sound.name) != 0) {
1975           free(textAttribs[cc].sound.name);
1976           textAttribs[cc].sound.name = strdup(soundComboData[index].name);
1977           MyLoadSound(&textAttribs[cc].sound);
1978         }
1979       }
1980
1981       ResetSoundComboData(soundComboData);
1982       EndDialog(hDlg, TRUE);
1983       return TRUE;
1984
1985     case IDCANCEL:
1986       ResetSoundComboData(soundComboData);
1987       EndDialog(hDlg, FALSE);
1988       return TRUE;
1989
1990     case OPT_DefaultSounds:
1991       /* can't use SetDefaultSounds() because we need to be able to "undo" if
1992        * user selects "Cancel" later on. So we do it the hard way here.
1993        */
1994       scd = &soundComboData[0];
1995       while (scd->label != NULL) {
1996         if (scd->name != NULL) free(scd->name);
1997         scd->name = strdup("");
1998         scd++;
1999       }
2000       free(soundComboData[(int)SoundBell].name);
2001       soundComboData[(int)SoundBell].name = strdup(SOUND_BELL);
2002       DisplaySelectedSound(hDlg, hBISN, soundComboData[index].name);
2003       break;
2004
2005     case OPT_PlaySound:
2006       radio = SoundDialogWhichRadio(hDlg);
2007       tmp.name = strdup(SoundDialogGetName(hDlg, radio));
2008       tmp.data = NULL;
2009       MyLoadSound(&tmp);
2010       MyPlaySound(&tmp);
2011       if (tmp.data  != NULL) FreeResource(tmp.data); // technically obsolete fn, but tmp.data is NOT malloc'd mem
2012       if (tmp.name != NULL) free(tmp.name);
2013       return TRUE;
2014
2015     case OPT_BrowseSound:
2016       f = OpenFileDialog(hDlg, "rb", NULL, "wav", SOUND_FILT,
2017         "Browse for Sound File", NULL, NULL, buf);
2018       if (f != NULL) {
2019         fclose(f);
2020         SetDlgItemText(hDlg, OPT_WavFileName, buf);
2021       }
2022       return TRUE;
2023
2024     default:
2025       radio = SoundDialogWhichRadio(hDlg);
2026       SoundDialogSetEnables(hDlg, radio);
2027       break;
2028     }
2029     break;
2030   }
2031   return FALSE;
2032 }
2033
2034
2035 VOID SoundOptionsPopup(HWND hwnd)
2036 {
2037   FARPROC lpProc;
2038
2039   lpProc = MakeProcInstance((FARPROC)SoundOptionsDialog, hInst);
2040   DialogBox(hInst, MAKEINTRESOURCE(DLG_Sound), hwnd, (DLGPROC)lpProc);
2041   FreeProcInstance(lpProc);
2042 }
2043
2044
2045 /*---------------------------------------------------------------------------*\
2046  *
2047  * Comm Port dialog functions
2048  *
2049 \*---------------------------------------------------------------------------*/
2050
2051
2052 #define FLOW_NONE   0
2053 #define FLOW_XOFF   1
2054 #define FLOW_CTS    2
2055 #define FLOW_DSR    3
2056
2057 #define PORT_NONE
2058
2059 ComboData cdPort[]     = { {"None", PORT_NONE}, {"COM1", 1}, {"COM2", 2},
2060                            {"COM3", 3}, {"COM4", 4}, {NULL, 0} };
2061 ComboData cdDataRate[] = { {"110", 110}, {"300", 300}, {"600", 600}, {"1200", 1200},
2062                            {"2400", 2400}, {"4800", 4800}, {"9600", 9600}, {"19200", 19200},
2063                            {"38400", 38400}, {NULL, 0} };
2064 ComboData cdDataBits[] = { {"5", 5}, {"6", 6}, {"7", 7}, {"8", 8}, {NULL, 0} };
2065 ComboData cdParity[]   = { {"None", NOPARITY}, {"Odd", ODDPARITY}, {"Even", EVENPARITY},
2066                            {"Mark", MARKPARITY}, {"Space", SPACEPARITY}, {NULL, 0} };
2067 ComboData cdStopBits[] = { {"1", ONESTOPBIT}, {"1.5", ONE5STOPBITS},
2068                            {"2", TWOSTOPBITS}, {NULL, 0} };
2069 ComboData cdFlow[]     = { {"None", FLOW_NONE}, {"Xoff/Xon", FLOW_XOFF}, {"CTS", FLOW_CTS},
2070                            {"DSR", FLOW_DSR}, {NULL, 0} };
2071
2072
2073 VOID
2074 ParseCommSettings(char *arg, DCB *dcb)
2075 {
2076   int dataRate, count;
2077   char bits[MSG_SIZ], parity[MSG_SIZ], stopBits[MSG_SIZ], flow[MSG_SIZ];
2078   ComboData *cd;
2079   count = sscanf(arg, "%d%*[, ]%[^, ]%*[, ]%[^, ]%*[, ]%[^, ]%*[, ]%[^, ]",
2080     &dataRate, bits, parity, stopBits, flow);
2081   if (count != 5) goto cant_parse;
2082   dcb->BaudRate = dataRate;
2083   cd = cdDataBits;
2084   while (cd->label != NULL) {
2085     if (StrCaseCmp(cd->label, bits) == 0) {
2086       dcb->ByteSize = cd->value;
2087       break;
2088     }
2089     cd++;
2090   }
2091   if (cd->label == NULL) goto cant_parse;
2092   cd = cdParity;
2093   while (cd->label != NULL) {
2094     if (StrCaseCmp(cd->label, parity) == 0) {
2095       dcb->Parity = cd->value;
2096       break;
2097     }
2098     cd++;
2099   }
2100   if (cd->label == NULL) goto cant_parse;
2101   cd = cdStopBits;
2102   while (cd->label != NULL) {
2103     if (StrCaseCmp(cd->label, stopBits) == 0) {
2104       dcb->StopBits = cd->value;
2105       break;
2106     }
2107     cd++;
2108   }
2109   cd = cdFlow;
2110   if (cd->label == NULL) goto cant_parse;
2111   while (cd->label != NULL) {
2112     if (StrCaseCmp(cd->label, flow) == 0) {
2113       switch (cd->value) {
2114       case FLOW_NONE:
2115         dcb->fOutX = FALSE;
2116         dcb->fOutxCtsFlow = FALSE;
2117         dcb->fOutxDsrFlow = FALSE;
2118         break;
2119       case FLOW_CTS:
2120         dcb->fOutX = FALSE;
2121         dcb->fOutxCtsFlow = TRUE;
2122         dcb->fOutxDsrFlow = FALSE;
2123         break;
2124       case FLOW_DSR:
2125         dcb->fOutX = FALSE;
2126         dcb->fOutxCtsFlow = FALSE;
2127         dcb->fOutxDsrFlow = TRUE;
2128         break;
2129       case FLOW_XOFF:
2130         dcb->fOutX = TRUE;
2131         dcb->fOutxCtsFlow = FALSE;
2132         dcb->fOutxDsrFlow = FALSE;
2133         break;
2134       }
2135       break;
2136     }
2137     cd++;
2138   }
2139   if (cd->label == NULL) goto cant_parse;
2140   return;
2141 cant_parse:
2142     ExitArgError("Can't parse com port settings", arg);
2143 }
2144
2145
2146 VOID PrintCommSettings(FILE *f, char *name, DCB *dcb)
2147 {
2148   char *flow = "??", *parity = "??", *stopBits = "??";
2149   ComboData *cd;
2150   
2151   cd = cdParity;
2152   while (cd->label != NULL) {
2153     if (dcb->Parity == cd->value) {
2154       parity = cd->label;
2155       break;
2156     }
2157     cd++;
2158   }
2159   cd = cdStopBits;
2160   while (cd->label != NULL) {
2161     if (dcb->StopBits == cd->value) {
2162       stopBits = cd->label;
2163       break;
2164     }
2165     cd++;
2166   }
2167   if (dcb->fOutX) {
2168     flow = cdFlow[FLOW_XOFF].label;
2169   } else if (dcb->fOutxCtsFlow) {
2170     flow = cdFlow[FLOW_CTS].label;
2171   } else if (dcb->fOutxDsrFlow) {
2172     flow = cdFlow[FLOW_DSR].label;
2173   } else {
2174     flow = cdFlow[FLOW_NONE].label;
2175   }
2176   fprintf(f, "/%s=%d,%d,%s,%s,%s\n", name,
2177     (int)dcb->BaudRate, dcb->ByteSize, parity, stopBits, flow);
2178 }
2179
2180
2181 void
2182 InitCombo(HANDLE hwndCombo, ComboData *cd)
2183 {
2184   SendMessage(hwndCombo, CB_RESETCONTENT, 0, 0);
2185
2186   while (cd->label != NULL) {
2187     SendMessage(hwndCombo, CB_ADDSTRING, 0, (LPARAM) cd->label);
2188     cd++;
2189   }
2190 }
2191
2192 void
2193 SelectComboValue(HANDLE hwndCombo, ComboData *cd, unsigned value)
2194 {
2195   int i;
2196
2197   i = 0;
2198   while (cd->label != NULL) {
2199     if (cd->value == value) {
2200       SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) i, (LPARAM) 0);
2201       return;
2202     }
2203     cd++;
2204     i++;
2205   }
2206 }
2207
2208 LRESULT CALLBACK
2209 CommPortOptionsDialog(HWND hDlg, UINT message, WPARAM wParam,   LPARAM lParam)
2210 {
2211   char buf[MSG_SIZ];
2212   HANDLE hwndCombo;
2213   char *p;
2214   LRESULT index;
2215   unsigned value;
2216   int err;
2217
2218   switch (message) {
2219   case WM_INITDIALOG: /* message: initialize dialog box */
2220     /* Center the dialog over the application window */
2221     CenterWindow (hDlg, GetWindow(hDlg, GW_OWNER));
2222     /* Initialize the dialog items */
2223     /* !! There should probably be some synchronization
2224        in accessing hCommPort and dcb.  Or does modal nature
2225        of this dialog box do it for us?
2226        */
2227     hwndCombo = GetDlgItem(hDlg, OPT_Port);
2228     InitCombo(hwndCombo, cdPort);
2229     p = strrchr(appData.icsCommPort, '\\');
2230     if (p++ == NULL) p = appData.icsCommPort;
2231     if ((*p == '\0') ||
2232         (SendMessage(hwndCombo, CB_SELECTSTRING, (WPARAM) -1, (LPARAM) p) == CB_ERR)) {
2233       SendMessage(hwndCombo, CB_SELECTSTRING, (WPARAM) -1, (LPARAM) "None");
2234     }
2235     EnableWindow(hwndCombo, hCommPort == NULL); /*!! don't allow change for now*/
2236
2237     hwndCombo = GetDlgItem(hDlg, OPT_DataRate);
2238     InitCombo(hwndCombo, cdDataRate);
2239     sprintf(buf, "%u", (int)dcb.BaudRate);
2240     if (SendMessage(hwndCombo, CB_SELECTSTRING, (WPARAM) -1, (LPARAM) buf) == CB_ERR) {
2241       SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) -1, (LPARAM) 0);
2242       SendMessage(hwndCombo, WM_SETTEXT, (WPARAM) 0, (LPARAM) buf);
2243     }
2244
2245     hwndCombo = GetDlgItem(hDlg, OPT_Bits);
2246     InitCombo(hwndCombo, cdDataBits);
2247     SelectComboValue(hwndCombo, cdDataBits, dcb.ByteSize);
2248
2249     hwndCombo = GetDlgItem(hDlg, OPT_Parity);
2250     InitCombo(hwndCombo, cdParity);
2251     SelectComboValue(hwndCombo, cdParity, dcb.Parity);
2252
2253     hwndCombo = GetDlgItem(hDlg, OPT_StopBits);
2254     InitCombo(hwndCombo, cdStopBits);
2255     SelectComboValue(hwndCombo, cdStopBits, dcb.StopBits);
2256
2257     hwndCombo = GetDlgItem(hDlg, OPT_Flow);
2258     InitCombo(hwndCombo, cdFlow);
2259     if (dcb.fOutX) {
2260       SelectComboValue(hwndCombo, cdFlow, FLOW_XOFF);
2261     } else if (dcb.fOutxCtsFlow) {
2262       SelectComboValue(hwndCombo, cdFlow, FLOW_CTS);
2263     } else if (dcb.fOutxDsrFlow) {
2264       SelectComboValue(hwndCombo, cdFlow, FLOW_DSR);
2265     } else {
2266       SelectComboValue(hwndCombo, cdFlow, FLOW_NONE);
2267     }
2268     return TRUE;
2269
2270   case WM_COMMAND: /* message: received a command */
2271     switch (LOWORD(wParam)) {
2272     case IDOK:
2273       /* Read changed options from the dialog box */
2274 #ifdef NOTDEF
2275       /* !! Currently we can't change comm ports in midstream */
2276       hwndCombo = GetDlgItem(hDlg, OPT_Port);
2277       index = SendMessage(hwndCombo, CB_GETCURSEL, (WPARAM) 0, (LPARAM) 0);
2278       if (index == PORT_NONE) {
2279         appData.icsCommPort = "";
2280         if (hCommPort != NULL) {
2281           CloseHandle(hCommPort);
2282           hCommPort = NULL;
2283         }
2284         EndDialog(hDlg, TRUE);
2285         return TRUE;
2286       }
2287       SendMessage(hwndCombo, WM_GETTEXT, (WPARAM) MSG_SIZ, (LPARAM) buf);
2288       appData.icsCommPort = strdup(buf);
2289       if (hCommPort != NULL) {
2290         CloseHandle(hCommPort);
2291         hCommPort = NULL;
2292       }
2293       /* now what?? can't really do this; have to fix up the ChildProc
2294          and InputSource records for the comm port that we gave to the
2295          back end. */
2296 #endif /*NOTDEF*/
2297
2298       hwndCombo = GetDlgItem(hDlg, OPT_DataRate);
2299       SendMessage(hwndCombo, WM_GETTEXT, (WPARAM) MSG_SIZ, (LPARAM) buf);
2300       if (sscanf(buf, "%u", &value) != 1) {
2301         MessageBox(hDlg, "Invalid data rate",
2302                    "Option Error", MB_OK|MB_ICONEXCLAMATION);
2303         return TRUE;
2304       }
2305       dcb.BaudRate = value;
2306
2307       hwndCombo = GetDlgItem(hDlg, OPT_Bits);
2308       index = SendMessage(hwndCombo, CB_GETCURSEL, (WPARAM) 0, (LPARAM) 0);
2309       dcb.ByteSize = cdDataBits[index].value;
2310
2311       hwndCombo = GetDlgItem(hDlg, OPT_Parity);
2312       index = SendMessage(hwndCombo, CB_GETCURSEL, (WPARAM) 0, (LPARAM) 0);
2313       dcb.Parity = cdParity[index].value;
2314
2315       hwndCombo = GetDlgItem(hDlg, OPT_StopBits);
2316       index = SendMessage(hwndCombo, CB_GETCURSEL, (WPARAM) 0, (LPARAM) 0);
2317       dcb.StopBits = cdStopBits[index].value;
2318
2319       hwndCombo = GetDlgItem(hDlg, OPT_Flow);
2320       index = SendMessage(hwndCombo, CB_GETCURSEL, (WPARAM) 0, (LPARAM) 0);
2321       switch (cdFlow[index].value) {
2322       case FLOW_NONE:
2323         dcb.fOutX = FALSE;
2324         dcb.fOutxCtsFlow = FALSE;
2325         dcb.fOutxDsrFlow = FALSE;
2326         break;
2327       case FLOW_CTS:
2328         dcb.fOutX = FALSE;
2329         dcb.fOutxCtsFlow = TRUE;
2330         dcb.fOutxDsrFlow = FALSE;
2331         break;
2332       case FLOW_DSR:
2333         dcb.fOutX = FALSE;
2334         dcb.fOutxCtsFlow = FALSE;
2335         dcb.fOutxDsrFlow = TRUE;
2336         break;
2337       case FLOW_XOFF:
2338         dcb.fOutX = TRUE;
2339         dcb.fOutxCtsFlow = FALSE;
2340         dcb.fOutxDsrFlow = FALSE;
2341         break;
2342       }
2343       if (!SetCommState(hCommPort, (LPDCB) &dcb)) {
2344         err = GetLastError();
2345         switch(MessageBox(hDlg, 
2346                          "Failed to set comm port state;\r\ninvalid options?",
2347                          "Option Error", MB_ABORTRETRYIGNORE|MB_ICONQUESTION)) {
2348         case IDABORT:
2349           DisplayFatalError("Failed to set comm port state", err, 1);
2350           exit(1);  /*is it ok to do this from here?*/
2351
2352         case IDRETRY:
2353           return TRUE;
2354
2355         case IDIGNORE:
2356           EndDialog(hDlg, TRUE);
2357           return TRUE;
2358         }
2359       }
2360
2361       EndDialog(hDlg, TRUE);
2362       return TRUE;
2363
2364     case IDCANCEL:
2365       EndDialog(hDlg, FALSE);
2366       return TRUE;
2367
2368     default:
2369       break;
2370     }
2371     break;
2372   }
2373   return FALSE;
2374 }
2375
2376 VOID
2377 CommPortOptionsPopup(HWND hwnd)
2378 {
2379   FARPROC lpProc = MakeProcInstance((FARPROC)CommPortOptionsDialog, hInst);
2380   DialogBox(hInst, MAKEINTRESOURCE(DLG_CommPort), hwnd, (DLGPROC) lpProc);
2381   FreeProcInstance(lpProc);
2382 }
2383
2384 /*---------------------------------------------------------------------------*\
2385  *
2386  * Load Options dialog functions
2387  *
2388 \*---------------------------------------------------------------------------*/
2389
2390 VOID
2391 SetLoadOptionEnables(HWND hDlg)
2392 {
2393   UINT state;
2394
2395   state = IsDlgButtonChecked(hDlg, OPT_Autostep);
2396   EnableWindow(GetDlgItem(hDlg, OPT_ASTimeDelay), state);
2397   EnableWindow(GetDlgItem(hDlg, OPT_AStext1), state);
2398 }
2399
2400 LRESULT CALLBACK
2401 LoadOptions(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
2402 {
2403   char buf[MSG_SIZ];
2404   float fnumber;
2405
2406   switch (message) {
2407   case WM_INITDIALOG: /* message: initialize dialog box */
2408     /* Center the dialog over the application window */
2409     CenterWindow (hDlg, GetWindow (hDlg, GW_OWNER));
2410     /* Initialize the dialog items */
2411     if (appData.timeDelay >= 0.0) {
2412       CheckDlgButton(hDlg, OPT_Autostep, TRUE);
2413       sprintf(buf, "%.2g", appData.timeDelay);
2414       SetDlgItemText(hDlg, OPT_ASTimeDelay, buf);
2415     } else {
2416       CheckDlgButton(hDlg, OPT_Autostep, FALSE);
2417     }
2418     SetLoadOptionEnables(hDlg);
2419     return TRUE;
2420
2421   case WM_COMMAND: /* message: received a command */
2422     switch (LOWORD(wParam)) {
2423     case IDOK:
2424       /* Read changed options from the dialog box */
2425       if (IsDlgButtonChecked(hDlg, OPT_Autostep)) {
2426         GetDlgItemText(hDlg, OPT_ASTimeDelay, buf, MSG_SIZ);
2427         if (sscanf(buf, "%f", &fnumber) != 1) {
2428           MessageBox(hDlg, "Invalid load game step rate",
2429                      "Option Error", MB_OK|MB_ICONEXCLAMATION);
2430           return FALSE;
2431         }
2432         appData.timeDelay = fnumber;
2433       } else {
2434         appData.timeDelay = (float) -1.0;
2435       }
2436       EndDialog(hDlg, TRUE);
2437       return TRUE;
2438
2439     case IDCANCEL:
2440       EndDialog(hDlg, FALSE);
2441       return TRUE;
2442
2443     default:
2444       SetLoadOptionEnables(hDlg);
2445       break;
2446     }
2447     break;
2448   }
2449   return FALSE;
2450 }
2451
2452
2453 VOID 
2454 LoadOptionsPopup(HWND hwnd)
2455 {
2456   FARPROC lpProc = MakeProcInstance((FARPROC)LoadOptions, hInst);
2457   DialogBox(hInst, MAKEINTRESOURCE(DLG_LoadOptions), hwnd, (DLGPROC) lpProc);
2458   FreeProcInstance(lpProc);
2459 }
2460
2461 /*---------------------------------------------------------------------------*\
2462  *
2463  * Save Options dialog functions
2464  *
2465 \*---------------------------------------------------------------------------*/
2466
2467 VOID
2468 SetSaveOptionEnables(HWND hDlg)
2469 {
2470   UINT state;
2471
2472   state = IsDlgButtonChecked(hDlg, OPT_Autosave);
2473   EnableWindow(GetDlgItem(hDlg, OPT_AVPrompt), state);
2474   EnableWindow(GetDlgItem(hDlg, OPT_AVToFile), state);
2475   if (state && !IsDlgButtonChecked(hDlg, OPT_AVPrompt) &&
2476       !IsDlgButtonChecked(hDlg, OPT_AVToFile)) {
2477     CheckRadioButton(hDlg, OPT_AVPrompt, OPT_AVToFile, OPT_AVPrompt);
2478   }
2479
2480   state = state && IsDlgButtonChecked(hDlg, OPT_AVToFile);
2481   EnableWindow(GetDlgItem(hDlg, OPT_AVFilename), state);
2482   EnableWindow(GetDlgItem(hDlg, OPT_AVBrowse), state);
2483 }
2484
2485 LRESULT CALLBACK
2486 SaveOptionsDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
2487 {
2488   char buf[MSG_SIZ];
2489   FILE *f;
2490
2491   switch (message) {
2492   case WM_INITDIALOG: /* message: initialize dialog box */
2493     /* Center the dialog over the application window */
2494     CenterWindow (hDlg, GetWindow (hDlg, GW_OWNER));
2495     /* Initialize the dialog items */
2496     if (*appData.saveGameFile != NULLCHAR) {
2497       CheckDlgButton(hDlg, OPT_Autosave, (UINT) TRUE);
2498       CheckRadioButton(hDlg, OPT_AVPrompt, OPT_AVToFile, OPT_AVToFile);
2499       SetDlgItemText(hDlg, OPT_AVFilename, appData.saveGameFile);
2500     } else if (appData.autoSaveGames) {
2501       CheckDlgButton(hDlg, OPT_Autosave, (UINT) TRUE);
2502       CheckRadioButton(hDlg, OPT_AVPrompt, OPT_AVToFile, OPT_AVPrompt);
2503     } else {
2504       CheckDlgButton(hDlg, OPT_Autosave, (UINT) FALSE);
2505     }
2506     if (appData.oldSaveStyle) {
2507       CheckRadioButton(hDlg, OPT_PGN, OPT_Old, OPT_Old);
2508     } else {
2509       CheckRadioButton(hDlg, OPT_PGN, OPT_Old, OPT_PGN);
2510     }
2511     CheckDlgButton( hDlg, OPT_OutOfBookInfo, appData.saveOutOfBookInfo );
2512     SetSaveOptionEnables(hDlg);
2513     return TRUE;
2514
2515   case WM_COMMAND: /* message: received a command */
2516     switch (LOWORD(wParam)) {
2517     case IDOK:
2518       /* Read changed options from the dialog box */
2519       if (IsDlgButtonChecked(hDlg, OPT_Autosave)) {
2520         appData.autoSaveGames = TRUE;
2521         if (IsDlgButtonChecked(hDlg, OPT_AVPrompt)) {
2522           appData.saveGameFile = "";
2523         } else /*if (IsDlgButtonChecked(hDlg, OPT_AVToFile))*/ {
2524           GetDlgItemText(hDlg, OPT_AVFilename, buf, MSG_SIZ);
2525           if (*buf == NULLCHAR) {
2526             MessageBox(hDlg, "Invalid save game file name",
2527                        "Option Error", MB_OK|MB_ICONEXCLAMATION);
2528             return FALSE;
2529           }
2530           if ((isalpha(buf[0]) && buf[1] == ':') ||
2531             (buf[0] == '\\' && buf[1] == '\\')) {
2532             appData.saveGameFile = strdup(buf);
2533           } else {
2534             char buf2[MSG_SIZ], buf3[MSG_SIZ];
2535             char *dummy;
2536             GetCurrentDirectory(MSG_SIZ, buf3);
2537             SetCurrentDirectory(installDir);
2538             if (GetFullPathName(buf, MSG_SIZ, buf2, &dummy)) {
2539               appData.saveGameFile = strdup(buf2);
2540             } else {
2541               appData.saveGameFile = strdup(buf);
2542             }
2543             SetCurrentDirectory(buf3);
2544           }
2545         }
2546       } else {
2547         appData.autoSaveGames = FALSE;
2548         appData.saveGameFile = "";
2549       }
2550       appData.oldSaveStyle = IsDlgButtonChecked(hDlg, OPT_Old);
2551       appData.saveOutOfBookInfo = IsDlgButtonChecked( hDlg, OPT_OutOfBookInfo );
2552       EndDialog(hDlg, TRUE);
2553       return TRUE;
2554
2555     case IDCANCEL:
2556       EndDialog(hDlg, FALSE);
2557       return TRUE;
2558
2559     case OPT_AVBrowse:
2560       f = OpenFileDialog(hDlg, "a", NULL, 
2561                          appData.oldSaveStyle ? "gam" : "pgn", 
2562                          GAME_FILT, "Browse for Auto Save File", 
2563                          NULL, NULL, buf);
2564       if (f != NULL) {
2565         fclose(f);
2566         SetDlgItemText(hDlg, OPT_AVFilename, buf);
2567       }
2568       break;
2569
2570     default:
2571       SetSaveOptionEnables(hDlg);
2572       break;
2573     }
2574     break;
2575   }
2576   return FALSE;
2577 }
2578
2579 VOID
2580 SaveOptionsPopup(HWND hwnd)
2581 {
2582   FARPROC lpProc = MakeProcInstance((FARPROC)SaveOptionsDialog, hInst);
2583   DialogBox(hInst, MAKEINTRESOURCE(DLG_SaveOptions), hwnd, (DLGPROC) lpProc);
2584   FreeProcInstance(lpProc);
2585 }
2586
2587 /*---------------------------------------------------------------------------*\
2588  *
2589  * Time Control Options dialog functions
2590  *
2591 \*---------------------------------------------------------------------------*/
2592
2593 VOID
2594 SetTimeControlEnables(HWND hDlg)
2595 {
2596   UINT state;
2597
2598   state = IsDlgButtonChecked(hDlg, OPT_TCUseMoves);
2599   EnableWindow(GetDlgItem(hDlg, OPT_TCTime), state);
2600   EnableWindow(GetDlgItem(hDlg, OPT_TCMoves), state);
2601   EnableWindow(GetDlgItem(hDlg, OPT_TCtext1), state);
2602   EnableWindow(GetDlgItem(hDlg, OPT_TCtext2), state);
2603   EnableWindow(GetDlgItem(hDlg, OPT_TCTime2), !state);
2604   EnableWindow(GetDlgItem(hDlg, OPT_TCInc), !state);
2605   EnableWindow(GetDlgItem(hDlg, OPT_TCitext1), !state);
2606   EnableWindow(GetDlgItem(hDlg, OPT_TCitext2), !state);
2607   EnableWindow(GetDlgItem(hDlg, OPT_TCitext3), !state);
2608 }
2609
2610
2611 LRESULT CALLBACK
2612 TimeControl(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
2613 {
2614   char buf[MSG_SIZ];
2615   int mps, increment, odds1, odds2;
2616   BOOL ok, ok2;
2617
2618   switch (message) {
2619   case WM_INITDIALOG: /* message: initialize dialog box */
2620     /* Center the dialog over the application window */
2621     CenterWindow (hDlg, GetWindow (hDlg, GW_OWNER));
2622     /* Initialize the dialog items */
2623     if (appData.clockMode && !appData.icsActive) {
2624       if (appData.timeIncrement == -1) {
2625         CheckRadioButton(hDlg, OPT_TCUseMoves, OPT_TCUseInc,
2626                          OPT_TCUseMoves);
2627         SetDlgItemText(hDlg, OPT_TCTime, appData.timeControl);
2628         SetDlgItemInt(hDlg, OPT_TCMoves, appData.movesPerSession,
2629                       FALSE);
2630         SetDlgItemText(hDlg, OPT_TCTime2, "");
2631         SetDlgItemText(hDlg, OPT_TCInc, "");
2632       } else {
2633         CheckRadioButton(hDlg, OPT_TCUseMoves, OPT_TCUseInc,
2634                          OPT_TCUseInc);
2635         SetDlgItemText(hDlg, OPT_TCTime, "");
2636         SetDlgItemText(hDlg, OPT_TCMoves, "");
2637         SetDlgItemText(hDlg, OPT_TCTime2, appData.timeControl);
2638         SetDlgItemInt(hDlg, OPT_TCInc, appData.timeIncrement, FALSE);
2639       }
2640       SetDlgItemInt(hDlg, OPT_TCOdds1, 1, FALSE);
2641       SetDlgItemInt(hDlg, OPT_TCOdds2, 1, FALSE);
2642       SetTimeControlEnables(hDlg);
2643     }
2644     return TRUE;
2645
2646   case WM_COMMAND: /* message: received a command */
2647     switch (LOWORD(wParam)) {
2648     case IDOK:
2649       /* Read changed options from the dialog box */
2650       if (IsDlgButtonChecked(hDlg, OPT_TCUseMoves)) {
2651         increment = -1;
2652         mps = GetDlgItemInt(hDlg, OPT_TCMoves, &ok, FALSE);
2653         if (!ok || mps <= 0) {
2654           MessageBox(hDlg, "Invalid moves per time control",
2655                      "Option Error", MB_OK|MB_ICONEXCLAMATION);
2656           return FALSE;
2657         }
2658         GetDlgItemText(hDlg, OPT_TCTime, buf, MSG_SIZ);
2659         if (!ParseTimeControl(buf, increment, mps)) {
2660           MessageBox(hDlg, "Invalid minutes per time control",
2661                      "Option Error", MB_OK|MB_ICONEXCLAMATION);
2662           return FALSE;
2663         }
2664       } else {
2665         increment = GetDlgItemInt(hDlg, OPT_TCInc, &ok, FALSE);
2666         mps = appData.movesPerSession;
2667         if (!ok || increment < 0) {
2668           MessageBox(hDlg, "Invalid increment",
2669                      "Option Error", MB_OK|MB_ICONEXCLAMATION);
2670           return FALSE;
2671         }
2672         GetDlgItemText(hDlg, OPT_TCTime2, buf, MSG_SIZ);
2673         if (!ParseTimeControl(buf, increment, mps)) {
2674           MessageBox(hDlg, "Invalid initial time",
2675                      "Option Error", MB_OK|MB_ICONEXCLAMATION);
2676           return FALSE;
2677         }
2678       }
2679       odds1 = GetDlgItemInt(hDlg, OPT_TCOdds1, &ok, FALSE);
2680       odds2 = GetDlgItemInt(hDlg, OPT_TCOdds2, &ok2, FALSE);
2681       if (!ok || !ok2 || odds1 <= 0 || odds2 <= 0) {
2682           MessageBox(hDlg, "Invalid time-odds factor",
2683                      "Option Error", MB_OK|MB_ICONEXCLAMATION);
2684           return FALSE;
2685       }
2686       appData.timeControl = strdup(buf);
2687       appData.movesPerSession = mps;
2688       appData.timeIncrement = increment;
2689       appData.firstTimeOdds  = first.timeOdds  = odds1;
2690       appData.secondTimeOdds = second.timeOdds = odds2;
2691       Reset(TRUE, TRUE);
2692       EndDialog(hDlg, TRUE);
2693       return TRUE;
2694
2695     case IDCANCEL:
2696       EndDialog(hDlg, FALSE);
2697       return TRUE;
2698
2699     default:
2700       SetTimeControlEnables(hDlg);
2701       break;
2702     }
2703     break;
2704   }
2705   return FALSE;
2706 }
2707
2708 VOID
2709 TimeControlOptionsPopup(HWND hwnd)
2710 {
2711   if (gameMode != BeginningOfGame) {
2712     DisplayError("Changing time control during a game is not implemented", 0);
2713   } else {
2714     FARPROC lpProc = MakeProcInstance((FARPROC)TimeControl, hInst);
2715     DialogBox(hInst, MAKEINTRESOURCE(DLG_TimeControl), hwnd, (DLGPROC) lpProc);
2716     FreeProcInstance(lpProc);
2717   }
2718 }
2719
2720 /*---------------------------------------------------------------------------*\
2721  *
2722  * Engine Options Dialog functions
2723  *
2724 \*---------------------------------------------------------------------------*/
2725 #define CHECK_BOX(x,y) CheckDlgButton(hDlg, (x), (BOOL)(y))
2726 #define IS_CHECKED(x) (Boolean)IsDlgButtonChecked(hDlg, (x))
2727
2728 #define INT_ABS( n )    ((n) >= 0 ? (n) : -(n))
2729
2730 LRESULT CALLBACK EnginePlayOptionsDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
2731 {
2732   switch (message) {
2733   case WM_INITDIALOG: /* message: initialize dialog box */
2734
2735     /* Center the dialog over the application window */
2736     CenterWindow (hDlg, GetWindow (hDlg, GW_OWNER));
2737
2738     /* Initialize the dialog items */
2739     CHECK_BOX(IDC_EpPeriodicUpdates, appData.periodicUpdates);
2740     CHECK_BOX(IDC_EpPonder, appData.ponderNextMove);
2741     CHECK_BOX(IDC_EpShowThinking, appData.showThinking);
2742     CHECK_BOX(IDC_EpHideThinkingHuman, appData.hideThinkingFromHuman);
2743
2744     CHECK_BOX(IDC_TestClaims, appData.testClaims);
2745     CHECK_BOX(IDC_DetectMates, appData.checkMates);
2746     CHECK_BOX(IDC_MaterialDraws, appData.materialDraws);
2747     CHECK_BOX(IDC_TrivialDraws, appData.trivialDraws);
2748
2749     CHECK_BOX(IDC_ScoreAbs1, appData.firstScoreIsAbsolute);
2750     CHECK_BOX(IDC_ScoreAbs2, appData.secondScoreIsAbsolute);
2751
2752     SetDlgItemInt( hDlg, IDC_EpDrawMoveCount, appData.adjudicateDrawMoves, TRUE );
2753     SendDlgItemMessage( hDlg, IDC_EpDrawMoveCount, EM_SETSEL, 0, -1 );
2754
2755     SetDlgItemInt( hDlg, IDC_EpAdjudicationThreshold, INT_ABS(appData.adjudicateLossThreshold), TRUE );
2756     SendDlgItemMessage( hDlg, IDC_EpAdjudicationThreshold, EM_SETSEL, 0, -1 );
2757
2758     SetDlgItemInt( hDlg, IDC_RuleMoves, appData.ruleMoves, TRUE );
2759     SendDlgItemMessage( hDlg, IDC_RuleMoves, EM_SETSEL, 0, -1 );
2760
2761     SetDlgItemInt( hDlg, IDC_DrawRepeats, INT_ABS(appData.drawRepeats), TRUE );
2762     SendDlgItemMessage( hDlg, IDC_DrawRepeats, EM_SETSEL, 0, -1 );
2763
2764     return TRUE;
2765
2766   case WM_COMMAND: /* message: received a command */
2767     switch (LOWORD(wParam)) {
2768     case IDOK:
2769       /* Read changed options from the dialog box */
2770       PeriodicUpdatesEvent(          IS_CHECKED(IDC_EpPeriodicUpdates));
2771       PonderNextMoveEvent(           IS_CHECKED(IDC_EpPonder));
2772       appData.hideThinkingFromHuman= IS_CHECKED(IDC_EpHideThinkingHuman); // [HGM] thinking: moved up
2773 #if 0
2774       ShowThinkingEvent(             IS_CHECKED(IDC_EpShowThinking));
2775 #else
2776       appData.showThinking   = IS_CHECKED(IDC_EpShowThinking);
2777       ShowThinkingEvent(); // [HGM] thinking: tests all options that need thinking output
2778 #endif
2779       appData.testClaims    = IS_CHECKED(IDC_TestClaims);
2780       appData.checkMates    = IS_CHECKED(IDC_DetectMates);
2781       appData.materialDraws = IS_CHECKED(IDC_MaterialDraws);
2782       appData.trivialDraws  = IS_CHECKED(IDC_TrivialDraws);
2783
2784       appData.adjudicateDrawMoves = GetDlgItemInt(hDlg, IDC_EpDrawMoveCount, NULL, FALSE );
2785       appData.adjudicateLossThreshold = - (int) GetDlgItemInt(hDlg, IDC_EpAdjudicationThreshold, NULL, FALSE );
2786       appData.ruleMoves = GetDlgItemInt(hDlg, IDC_RuleMoves, NULL, FALSE );
2787       appData.drawRepeats = (int) GetDlgItemInt(hDlg, IDC_DrawRepeats, NULL, FALSE );
2788
2789       appData.firstScoreIsAbsolute  = IS_CHECKED(IDC_ScoreAbs1);
2790       appData.secondScoreIsAbsolute = IS_CHECKED(IDC_ScoreAbs2);
2791
2792       EndDialog(hDlg, TRUE);
2793       return TRUE;
2794
2795     case IDCANCEL:
2796       EndDialog(hDlg, FALSE);
2797       return TRUE;
2798
2799     case IDC_EpDrawMoveCount:
2800     case IDC_EpAdjudicationThreshold:
2801     case IDC_DrawRepeats:
2802     case IDC_RuleMoves:
2803         if( HIWORD(wParam) == EN_CHANGE ) {
2804             int n1_ok;
2805             int n2_ok;
2806             int n3_ok;
2807             int n4_ok;
2808
2809             GetDlgItemInt(hDlg, IDC_EpDrawMoveCount, &n1_ok, FALSE );
2810             GetDlgItemInt(hDlg, IDC_EpAdjudicationThreshold, &n2_ok, FALSE );
2811             GetDlgItemInt(hDlg, IDC_RuleMoves, &n3_ok, FALSE );
2812             GetDlgItemInt(hDlg, IDC_DrawRepeats, &n4_ok, FALSE );
2813
2814             EnableWindow( GetDlgItem(hDlg, IDOK), n1_ok && n2_ok && n3_ok && n4_ok ? TRUE : FALSE );
2815         }
2816         return TRUE;
2817     }
2818     break;
2819   }
2820   return FALSE;
2821 }
2822
2823 VOID EnginePlayOptionsPopup(HWND hwnd)
2824 {
2825   FARPROC lpProc;
2826
2827   lpProc = MakeProcInstance((FARPROC)EnginePlayOptionsDialog, hInst);
2828   DialogBox(hInst, MAKEINTRESOURCE(DLG_EnginePlayOptions), hwnd, (DLGPROC) lpProc);
2829   FreeProcInstance(lpProc);
2830 }
2831
2832 /*---------------------------------------------------------------------------*\
2833  *
2834  * UCI Options Dialog functions
2835  *
2836 \*---------------------------------------------------------------------------*/
2837 static BOOL BrowseForFolder( const char * title, char * path )
2838 {
2839     BOOL result = FALSE;
2840     BROWSEINFO bi;
2841     LPITEMIDLIST pidl;
2842
2843     ZeroMemory( &bi, sizeof(bi) );
2844
2845     bi.lpszTitle = title == 0 ? "Choose Folder" : title;
2846     bi.ulFlags = BIF_RETURNONLYFSDIRS;
2847
2848     pidl = SHBrowseForFolder( &bi );
2849
2850     if( pidl != 0 ) {
2851         IMalloc * imalloc = 0;
2852
2853         if( SHGetPathFromIDList( pidl, path ) ) {
2854             result = TRUE;
2855         }
2856
2857         if( SUCCEEDED( SHGetMalloc ( &imalloc ) ) ) {
2858             imalloc->lpVtbl->Free(imalloc,pidl);
2859             imalloc->lpVtbl->Release(imalloc);
2860         }
2861     }
2862
2863     return result;
2864 }
2865
2866 LRESULT CALLBACK UciOptionsDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
2867 {
2868   char buf[MAX_PATH];
2869   int oldCores;
2870
2871   switch (message) {
2872   case WM_INITDIALOG: /* message: initialize dialog box */
2873
2874     /* Center the dialog over the application window */
2875     CenterWindow (hDlg, GetWindow (hDlg, GW_OWNER));
2876
2877     /* Initialize the dialog items */
2878     SetDlgItemText( hDlg, IDC_PolyglotDir, appData.polyglotDir );
2879     SetDlgItemInt( hDlg, IDC_HashSize, appData.defaultHashSize, TRUE );
2880     SetDlgItemText( hDlg, IDC_PathToEGTB, appData.defaultPathEGTB );
2881     SetDlgItemInt( hDlg, IDC_SizeOfEGTB, appData.defaultCacheSizeEGTB, TRUE );
2882     CheckDlgButton( hDlg, IDC_UseBook, (BOOL) appData.usePolyglotBook );
2883     SetDlgItemText( hDlg, IDC_BookFile, appData.polyglotBook );
2884     // [HGM] smp: input field for nr of cores:
2885     SetDlgItemInt( hDlg, IDC_Cores, appData.smpCores, TRUE );
2886     // [HGM] book: tick boxes for own book use
2887     CheckDlgButton( hDlg, IDC_OwnBook1, (BOOL) appData.firstHasOwnBookUCI );
2888     CheckDlgButton( hDlg, IDC_OwnBook2, (BOOL) appData.secondHasOwnBookUCI );
2889
2890     SendDlgItemMessage( hDlg, IDC_PolyglotDir, EM_SETSEL, 0, -1 );
2891
2892     return TRUE;
2893
2894   case WM_COMMAND: /* message: received a command */
2895     switch (LOWORD(wParam)) {
2896     case IDOK:
2897       GetDlgItemText( hDlg, IDC_PolyglotDir, buf, sizeof(buf) );
2898       appData.polyglotDir = strdup(buf);
2899       appData.defaultHashSize = GetDlgItemInt(hDlg, IDC_HashSize, NULL, FALSE );
2900       appData.defaultCacheSizeEGTB = GetDlgItemInt(hDlg, IDC_SizeOfEGTB, NULL, FALSE );
2901       GetDlgItemText( hDlg, IDC_PathToEGTB, buf, sizeof(buf) );
2902       appData.defaultPathEGTB = strdup(buf);
2903       GetDlgItemText( hDlg, IDC_BookFile, buf, sizeof(buf) );
2904       appData.polyglotBook = strdup(buf);
2905       appData.usePolyglotBook = (Boolean) IsDlgButtonChecked( hDlg, IDC_UseBook );
2906       // [HGM] smp: get nr of cores:
2907       oldCores = appData.smpCores;
2908       appData.smpCores = GetDlgItemInt(hDlg, IDC_Cores, NULL, FALSE );
2909       if(appData.smpCores != oldCores) NewSettingEvent(FALSE, "cores", appData.smpCores);
2910       // [HGM] book: read tick boxes for own book use
2911       appData.firstHasOwnBookUCI  = (Boolean) IsDlgButtonChecked( hDlg, IDC_OwnBook1 );
2912       appData.secondHasOwnBookUCI = (Boolean) IsDlgButtonChecked( hDlg, IDC_OwnBook2 );
2913
2914       if(gameMode == BeginningOfGame) Reset(TRUE, TRUE);
2915       EndDialog(hDlg, TRUE);
2916       return TRUE;
2917
2918     case IDCANCEL:
2919       EndDialog(hDlg, FALSE);
2920       return TRUE;
2921
2922     case IDC_BrowseForBook:
2923       {
2924           char filter[] = { 
2925               'A','l','l',' ','F','i','l','e','s', 0,
2926               '*','.','*', 0,
2927               'B','I','N',' ','F','i','l','e','s', 0,
2928               '*','.','b','i','n', 0,
2929               0 };
2930
2931           OPENFILENAME ofn;
2932
2933           strcpy( buf, "" );
2934
2935           ZeroMemory( &ofn, sizeof(ofn) );
2936
2937           ofn.lStructSize = sizeof(ofn);
2938           ofn.hwndOwner = hDlg;
2939           ofn.hInstance = hInst;
2940           ofn.lpstrFilter = filter;
2941           ofn.lpstrFile = buf;
2942           ofn.nMaxFile = sizeof(buf);
2943           ofn.lpstrTitle = "Choose Book";
2944           ofn.Flags = OFN_FILEMUSTEXIST | OFN_LONGNAMES | OFN_HIDEREADONLY;
2945
2946           if( GetOpenFileName( &ofn ) ) {
2947               SetDlgItemText( hDlg, IDC_BookFile, buf );
2948           }
2949       }
2950       return TRUE;
2951
2952     case IDC_BrowseForPolyglotDir:
2953       if( BrowseForFolder( "Choose Polyglot Directory", buf ) ) {
2954         SetDlgItemText( hDlg, IDC_PolyglotDir, buf );
2955
2956         strcat( buf, "\\polyglot.exe" );
2957
2958         if( GetFileAttributes(buf) == 0xFFFFFFFF ) {
2959             MessageBox( hDlg, "Polyglot was not found in the specified folder!", "Warning", MB_OK | MB_ICONWARNING );
2960         }
2961       }
2962       return TRUE;
2963
2964     case IDC_BrowseForEGTB:
2965       if( BrowseForFolder( "Choose EGTB Directory:", buf ) ) {
2966         SetDlgItemText( hDlg, IDC_PathToEGTB, buf );
2967       }
2968       return TRUE;
2969
2970     case IDC_HashSize:
2971     case IDC_SizeOfEGTB:
2972         if( HIWORD(wParam) == EN_CHANGE ) {
2973             int n1_ok;
2974             int n2_ok;
2975
2976             GetDlgItemInt(hDlg, IDC_HashSize, &n1_ok, FALSE );
2977             GetDlgItemInt(hDlg, IDC_SizeOfEGTB, &n2_ok, FALSE );
2978
2979             EnableWindow( GetDlgItem(hDlg, IDOK), n1_ok && n2_ok ? TRUE : FALSE );
2980         }
2981         return TRUE;
2982     }
2983     break;
2984   }
2985   return FALSE;
2986 }
2987
2988 VOID UciOptionsPopup(HWND hwnd)
2989 {
2990   FARPROC lpProc;
2991
2992   lpProc = MakeProcInstance((FARPROC)UciOptionsDialog, hInst);
2993   DialogBox(hInst, MAKEINTRESOURCE(DLG_OptionsUCI), hwnd, (DLGPROC) lpProc);
2994   FreeProcInstance(lpProc);
2995 }