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