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