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