2 * Engine-settings dialog. The complexity come from an attempt to present the engine-defined options
\r
3 * in a nicey formatted layout. To this end we first run a back-end pre-formatter, which will distribute
\r
4 * the controls over two columns (the minimum required, as some are double width). It also takes care of
\r
5 * grouping options that start with the same word (mainly for "Polyglot ..." options). It assigns relative
\r
6 * suitability to break points between lines, and in the end decides if and where to break up the list
\r
7 * for display in multiple (2*N) columns.
\r
8 * The thus obtained list representing the topology of the layout is then passed to a front-end routine
\r
9 * that generates the actual dialog box from it.
\r
12 //#include "config.h"
\r
17 #include "backend.h"
\r
19 int layoutList[2*MAX_OPTIONS];
\r
20 int checkList[2*MAX_OPTIONS];
\r
21 int comboList[2*MAX_OPTIONS];
\r
22 int buttonList[2*MAX_OPTIONS];
\r
23 int boxList[2*MAX_OPTIONS];
\r
24 int groupNameList[2*MAX_OPTIONS];
\r
25 int breaks[MAX_OPTIONS];
\r
26 int checks, combos, buttons, layout, groups;
\r
29 PrintOpt(int i, int right, ChessProgramState *cps)
\r
32 if(!right) fprintf(debugFP, "%30s", "");
\r
34 Option opt = cps->option[i];
\r
37 fprintf(debugFP, "%20.20s [ +/-]", opt.name);
\r
40 fprintf(debugFP, "%20.20s [______________________________________]", opt.name);
\r
43 fprintf(debugFP, "[x] %-26.25s", opt.name);
\r
46 fprintf(debugFP, "%20.20s [ COMBO ]", opt.name);
\r
50 fprintf(debugFP, "[ %26.26s ]", opt.name);
\r
54 fprintf(debugFP, right ? "\n" : " ");
\r
58 CreateOptionDialogTest(int *list, int nr, ChessProgramState *cps)
\r
62 for(line = 0; line < nr; line+=2) {
\r
63 PrintOpt(list[line+1], 0, cps);
\r
64 PrintOpt(list[line], 1, cps);
\r
69 LayoutOptions(int firstOption, int endOption, char *groupName, Option *optionList)
\r
71 int n, i, b = strlen(groupName), stop, prefix, right, nextOption, firstButton = buttons;
\r
72 Control lastType, nextType;
\r
74 nextOption = firstOption;
\r
75 while(nextOption < endOption) {
\r
76 checks = combos = 0; stop = 0;
\r
77 lastType = Button; // kludge to make sure leading Spin will not be prefixed
\r
78 // first separate out buttons for later treatment, and collect consecutive checks and combos
\r
79 while(nextOption < endOption && !stop) {
\r
80 switch(nextType = optionList[nextOption].type) {
\r
81 case CheckBox: checkList[checks++] = nextOption; lastType = CheckBox; break;
\r
82 case ComboBox: comboList[combos++] = nextOption; lastType = ComboBox; break;
\r
84 case Button: buttonList[buttons++] = nextOption; lastType = Button; break;
\r
90 // We now must be at the end, or looking at a spin or textbox (in nextType)
\r
92 nextType = Button; // kudge to flush remaining checks and combos undistorted
\r
93 // Take a new line if a spin follows combos or checks, or when we encounter a textbox
\r
94 if((combos+checks || nextType == TextBox) && layout&1) {
\r
95 layoutList[layout++] = -1;
\r
97 // The last check or combo before a spin will be put on the same line as that spin (prefix)
\r
98 // and will thus not be grouped with other checks and combos
\r
100 if(nextType == Spin && lastType != Button) {
\r
101 if(lastType == CheckBox) prefix = checkList[--checks]; else
\r
102 if(lastType == ComboBox) prefix = comboList[--combos];
\r
104 // if a combo is followed by a textbox, it must stay at the end of the combo/checks list to appear
\r
105 // immediately above the textbox, so treat it as check. (A check would automatically be and remain there.)
\r
106 if(nextType == TextBox && lastType == ComboBox)
\r
107 checkList[checks++] = comboList[--combos];
\r
108 // Now append the checks behind the (remaining) combos to treat them as one group
\r
109 for(i=0; i< checks; i++)
\r
110 comboList[combos++] = checkList[i];
\r
111 // emit the consecutive checks and combos in two columns
\r
112 right = combos/2; // rounded down if odd!
\r
113 for(i=0; i<right; i++) {
\r
114 breaks[layout/2] = 2;
\r
115 layoutList[layout++] = comboList[i];
\r
116 layoutList[layout++] = comboList[i + right];
\r
118 // An odd check or combo (which could belong to following textBox) will be put in the left column
\r
119 // If there was an even number of checks and combos the last one will automatically be in that position
\r
121 layoutList[layout++] = -1;
\r
122 layoutList[layout++] = comboList[2*right];
\r
124 if(nextType == TextBox) {
\r
125 // A textBox is double width, so must be left-adjusted, and the right column remains empty
\r
126 breaks[layout/2] = lastType == Button ? 0 : 100;
\r
127 layoutList[layout++] = -1;
\r
128 layoutList[layout++] = nextOption - 1;
\r
129 } else if(nextType == Spin) {
\r
130 // A spin will go in the next available position (right to left!). If it had to be prefixed with
\r
131 // a check or combo, this next position must be to the right, and the prefix goes left to it.
\r
132 layoutList[layout++] = nextOption - 1;
\r
133 if(prefix >= 0) layoutList[layout++] = prefix;
\r
136 // take a new line if needed
\r
137 if(layout&1) layoutList[layout++] = -1;
\r
138 // emit the buttons belonging in this group; loose buttons are saved for last, to appear at bottom of dialog
\r
140 while(buttons > firstButton)
\r
141 layoutList[layout++] = buttonList[--buttons];
\r
142 if(layout&1) layoutList[layout++] = -1;
\r
147 EndMatch(char *s1, char *s2)
\r
150 p = s1; while(*p) p++;
\r
151 q = s2; while(*q) q++;
\r
152 while(p > s1 && q > s2 && *p == *q) { p--; q--; }
\r
153 if(p[1] == 0) return NULL;
\r
158 DesignOptionDialog(ChessProgramState *cps)
\r
164 buttons = groups = 0;
\r
165 while(k < cps->nrOptions) { // k steps through 'solitary' options
\r
166 // look if we hit a group of options having names that start with the same word
\r
167 int groupSize = 1, groupNameLength = 50;
\r
168 sscanf(cps->option[k].name, "%s", &buf); // get first word of option name
\r
169 while(k + groupSize < cps->nrOptions &&
\r
170 strstr(cps->option[k+groupSize].name, buf) == cps->option[k+groupSize].name) {
\r
172 for(j=0; j<groupNameLength; j++) // determine common initial part of option names
\r
173 if( cps->option[k].name[j] != cps->option[k+groupSize].name[j]) break;
\r
174 groupNameLength = j;
\r
178 if(groupSize > 3) {
\r
179 // We found a group to terminates the current section
\r
180 LayoutOptions(n, k, "", cps->option); // flush all solitary options appearing before the group
\r
181 groupNameList[groups] = groupNameLength;
\r
182 boxList[groups++] = layout; // group start in even entries
\r
183 LayoutOptions(k, k+groupSize, buf, cps->option); // flush the group
\r
184 boxList[groups++] = layout; // group end in odd entries
\r
185 k = n = k + groupSize;
\r
188 // try to recognize "two-column groups" based on option suffix
\r
190 while((p = EndMatch(cps->option[k].name, EndMatch(cps->option[k+2*j].name)) &&
\r
191 (q = EndMatch(cps->option[k+1].name, EndMatch(cps->option[k+2*j+1].name)) ) j++;
\r
193 } else k += groupSize; // small groups are grouped with the solitary options
\r
195 if(n != k) LayoutOptions(n, k, "", cps->option); // flush remaining solitary options
\r
196 // decide if and where we break into two column pairs
\r
198 // Emit buttons and add OK and cancel
\r
199 // for(k=0; k<buttons; k++) layoutList[layout++] = buttonList[k];
\r
200 // Create the dialog window
\r
201 if(appData.debugMode) CreateOptionDialogTest(layoutList, layout, cps);
\r
202 // CreateOptionDialog(layoutList, layout, cps);
\r
205 #include <windows.h>
\r
207 extern HINSTANCE hInst;
\r
210 DLGITEMTEMPLATE item;
\r
218 DLGTEMPLATE header;
\r
223 wchar_t fontName[14];
\r
224 Item control[MAX_OPTIONS];
\r
226 { DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU | DS_SETFONT, 0, 0, 0, 0, 295, 300 },
\r
227 0x0000, 0x0000, L"Engine #1 Settings ", 8, L"MS Sans Serif"
\r
230 ChessProgramState *activeCps;
\r
233 SetOptionValues(HWND hDlg, ChessProgramState *cps)
\r
234 // Put all current option values in controls, and write option names next to them
\r
238 char **choices, title[MSG_SIZ], *name;
\r
240 for(i=0; i<layout+buttons; i++) {
\r
241 int j=layoutList[i];
\r
242 if(j == -2) SetDlgItemText( hDlg, 2000+2*i, ". . ." );
\r
244 name = cps->option[j].name;
\r
245 if(strstr(name, "Polyglot ") == name) name += 9;
\r
246 SetDlgItemText( hDlg, 2000+2*i, name );
\r
247 //if(appData.debugMode) fprintf(debugFP, "# %s = %d\n",cps->option[j].name, cps->option[j].value );
\r
248 switch(cps->option[j].type) {
\r
250 SetDlgItemInt( hDlg, 2001+2*i, cps->option[j].value, TRUE );
\r
253 SetDlgItemText( hDlg, 2001+2*i, cps->option[j].textValue );
\r
256 CheckDlgButton( hDlg, 2000+2*i, cps->option[j].value != 0);
\r
259 choices = (char**) cps->option[j].textValue;
\r
260 hwndCombo = GetDlgItem(hDlg, 2001+2*i);
\r
261 SendMessage(hwndCombo, CB_RESETCONTENT, 0, 0);
\r
262 for(k=0; k<cps->option[j].max; k++) {
\r
263 SendMessage(hwndCombo, CB_ADDSTRING, 0, (LPARAM) choices[k]);
\r
265 SendMessage(hwndCombo, CB_SELECTSTRING, (WPARAM) -1, (LPARAM) choices[cps->option[j].value]);
\r
272 SetDlgItemText( hDlg, IDOK, "OK" );
\r
273 SetDlgItemText( hDlg, IDCANCEL, "Cancel" );
\r
274 sprintf(title, "%s Engine Settings (%s)", cps->which, cps->tidy);
\r
275 title[0] &= ~32; // capitalize
\r
276 SetWindowText( hDlg, title);
\r
277 for(i=0; i<groups; i+=2) {
\r
278 int id, p; char buf[MSG_SIZ];
\r
279 id = k = boxList[i];
\r
280 if(layoutList[k] < 0) k++;
\r
281 if(layoutList[k] < 0) continue;
\r
282 for(p=0; p<groupNameList[i]; p++) buf[p] = cps->option[layoutList[k]].name[p];
\r
284 SetDlgItemText( hDlg, 2000+2*(id+MAX_OPTIONS), buf );
\r
290 GetOptionValues(HWND hDlg, ChessProgramState *cps)
\r
291 // read out all controls, and if value is altered, remember it and send it to the engine
\r
294 int i, k, new, changed;
\r
295 char **choices, newText[MSG_SIZ], buf[MSG_SIZ];
\r
298 for(i=0; i<layout; i++) {
\r
299 int j=layoutList[i];
\r
301 SetDlgItemText( hDlg, 2000+2*i, cps->option[j].name );
\r
302 switch(cps->option[j].type) {
\r
304 new = GetDlgItemInt( hDlg, 2001+2*i, &success, TRUE );
\r
305 if(!success) break;
\r
306 if(new < cps->option[j].min) new = cps->option[j].min;
\r
307 if(new > cps->option[j].max) new = cps->option[j].max;
\r
308 changed = 2*(cps->option[j].value != new);
\r
309 cps->option[j].value = new;
\r
314 success = GetDlgItemText( hDlg, 2001+2*i, newText, MSG_SIZ - strlen(cps->option[j].name) - 9 );
\r
315 if(!success) break;
\r
316 changed = strcmp(cps->option[j].textValue, newText) != 0;
\r
317 strcpy(cps->option[j].textValue, newText);
\r
320 new = IsDlgButtonChecked( hDlg, 2000+2*i );
\r
321 changed = 2*(cps->option[j].value != new);
\r
322 cps->option[j].value = new;
\r
325 choices = (char**) cps->option[j].textValue;
\r
326 hwndCombo = GetDlgItem(hDlg, 2001+2*i);
\r
327 success = GetDlgItemText( hDlg, 2001+2*i, newText, MSG_SIZ );
\r
328 if(!success) break;
\r
330 for(k=0; k<cps->option[j].max; k++) {
\r
331 if(!strcmp(choices[k], newText)) new = k;
\r
333 changed = new >= 0 && (cps->option[j].value != new);
\r
334 if(changed) cps->option[j].value = new;
\r
337 break; // are treated instantly, so they have been sent already
\r
339 if(changed == 2) sprintf(buf, "option %s=%d\n", cps->option[j].name, new); else
\r
340 if(changed == 1) sprintf(buf, "option %s=%s\n", cps->option[j].name, newText);
\r
341 if(changed) SendToProgram(buf, cps);
\r
345 LRESULT CALLBACK SettingsProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
347 static int * lpIndexFRC;
\r
354 case WM_INITDIALOG:
\r
356 // CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
357 SetOptionValues(hDlg, activeCps);
\r
359 // SetFocus(GetDlgItem(hDlg, IDC_NFG_Edit));
\r
364 switch( LOWORD(wParam) ) {
\r
366 GetOptionValues(hDlg, activeCps);
\r
367 EndDialog( hDlg, 0 );
\r
371 EndDialog( hDlg, 1 );
\r
375 // program-defined push buttons
\r
376 i = LOWORD(wParam);
\r
377 if( i>=2000 && i < 2000+2*(layout+buttons)) {
\r
378 j = layoutList[(i - 2000)/2];
\r
381 "All files\0*.*\0BIN Files\0*.bin\0LOG Files\0*.log\0INI Files\0*.ini\0\0";
\r
384 'A','l','l',' ','F','i','l','e','s', 0,
\r
386 'B','I','N',' ','F','i','l','e','s', 0,
\r
387 '*','.','b','i','n', 0,
\r
394 ZeroMemory( &ofn, sizeof(ofn) );
\r
396 ofn.lStructSize = sizeof(ofn);
\r
397 ofn.hwndOwner = hDlg;
\r
398 ofn.hInstance = hInst;
\r
399 ofn.lpstrFilter = filter;
\r
400 ofn.lpstrFile = buf;
\r
401 ofn.nMaxFile = sizeof(buf);
\r
402 ofn.lpstrTitle = "Choose Book";
\r
403 ofn.Flags = OFN_FILEMUSTEXIST | OFN_LONGNAMES | OFN_HIDEREADONLY;
\r
405 if( GetOpenFileName( &ofn ) ) {
\r
406 SetDlgItemText( hDlg, i+3, buf );
\r
410 if( activeCps->option[j].type == SaveButton)
\r
411 GetOptionValues(hDlg, activeCps);
\r
412 else if( activeCps->option[j].type != Button) break;
\r
413 sprintf(buf, "option %s\n", activeCps->option[j].name);
\r
414 SendToProgram(buf, activeCps);
\r
426 // example copied from MS docs
\r
427 #define ID_HELP 150
\r
428 #define ID_TEXT 200
\r
430 LPWORD lpwAlign(LPWORD lpIn)
\r
441 LRESULT DisplayMyMessage(HINSTANCE hinst, HWND hwndOwner, LPSTR lpszMessage)
\r
444 LPDLGTEMPLATE lpdt;
\r
445 LPDLGITEMTEMPLATE lpdit;
\r
451 hgbl = GlobalAlloc(GMEM_ZEROINIT, 1024);
\r
455 lpdt = (LPDLGTEMPLATE)GlobalLock(hgbl);
\r
457 // Define a dialog box.
\r
459 lpdt->style = WS_POPUP | WS_BORDER | WS_SYSMENU | DS_MODALFRAME | WS_CAPTION;
\r
460 // WS_POPUP | WS_SYSMENU | DS_MODALFRAME | WS_CAPTION | DS_SETFONT
\r
461 lpdt->cdit = 3; // Number of controls
\r
462 lpdt->x = 10; lpdt->y = 10;
\r
463 lpdt->cx = 100; lpdt->cy = 100;
\r
465 lpw = (LPWORD)(lpdt + 1);
\r
466 *lpw++ = 0; // No menu
\r
467 *lpw++ = 0; // Predefined dialog box class (by default)
\r
469 lpwsz = (LPWSTR)lpw;
\r
470 nchar = 1 + MultiByteToWideChar(CP_ACP, 0, "My Dialog", -1, lpwsz, 50);
\r
473 //-----------------------
\r
474 // Define an OK button.
\r
475 //-----------------------
\r
476 lpw = lpwAlign(lpw); // Align DLGITEMTEMPLATE on DWORD boundary
\r
477 lpdit = (LPDLGITEMTEMPLATE)lpw;
\r
478 lpdit->x = 10; lpdit->y = 70;
\r
479 lpdit->cx = 80; lpdit->cy = 20;
\r
480 lpdit->id = IDOK; // OK button identifier
\r
481 lpdit->style = WS_CHILD | WS_VISIBLE | BS_DEFPUSHBUTTON;
\r
483 lpw = (LPWORD)(lpdit + 1);
\r
485 *lpw++ = 0x0080; // Button class
\r
487 lpwsz = (LPWSTR)lpw;
\r
488 nchar = 1 + MultiByteToWideChar(CP_ACP, 0, "OK", -1, lpwsz, 50);
\r
490 lpw = lpwAlign(lpw); // Align creation data on DWORD boundary
\r
491 *lpw++ = 0; // No creation data
\r
493 //-----------------------
\r
494 // Define a Help button.
\r
495 //-----------------------
\r
496 lpw = lpwAlign(lpw); // Align DLGITEMTEMPLATE on DWORD boundary
\r
497 lpdit = (LPDLGITEMTEMPLATE)lpw;
\r
498 lpdit->x = 55; lpdit->y = 10;
\r
499 lpdit->cx = 40; lpdit->cy = 20;
\r
500 lpdit->id = ID_HELP; // Help button identifier
\r
501 lpdit->style = WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON;
\r
503 lpw = (LPWORD)(lpdit + 1);
\r
505 *lpw++ = 0x0080; // Button class atom
\r
507 lpwsz = (LPWSTR)lpw;
\r
508 nchar = 1 + MultiByteToWideChar(CP_ACP, 0, "Help", -1, lpwsz, 50);
\r
510 lpw = lpwAlign(lpw); // Align creation data on DWORD boundary
\r
511 *lpw++ = 0; // No creation data
\r
513 //-----------------------
\r
514 // Define a static text control.
\r
515 //-----------------------
\r
516 lpw = lpwAlign(lpw); // Align DLGITEMTEMPLATE on DWORD boundary
\r
517 lpdit = (LPDLGITEMTEMPLATE)lpw;
\r
518 lpdit->x = 10; lpdit->y = 10;
\r
519 lpdit->cx = 40; lpdit->cy = 20;
\r
520 lpdit->id = ID_TEXT; // Text identifier
\r
521 lpdit->style = WS_CHILD | WS_VISIBLE | SS_LEFT;
\r
523 lpw = (LPWORD)(lpdit + 1);
\r
525 *lpw++ = 0x0082; // Static class
\r
527 for (lpwsz = (LPWSTR)lpw; *lpwsz++ = (WCHAR)*lpszMessage++;);
\r
528 lpw = (LPWORD)lpwsz;
\r
529 lpw = lpwAlign(lpw); // Align creation data on DWORD boundary
\r
530 *lpw++ = 0; // No creation data
\r
532 GlobalUnlock(hgbl);
\r
533 ret = DialogBoxIndirect(hinst,
\r
534 (LPDLGTEMPLATE)hgbl,
\r
536 (DLGPROC)DialogProc);
\r
542 void AddControl(int x, int y, int w, int h, int type, int style, int n)
\r
546 i = template.header.cdit++;
\r
547 template.control[i].item.style = style;
\r
548 template.control[i].item.dwExtendedStyle = 0;
\r
549 template.control[i].item.x = x;
\r
550 template.control[i].item.y = y;
\r
551 template.control[i].item.cx = w;
\r
552 template.control[i].item.cy = h;
\r
553 template.control[i].item.id = 2000 + n;
\r
554 template.control[i].code = 0xFFFF;
\r
555 template.control[i].controlType = type;
\r
556 template.control[i].d1 = ' ';
\r
557 template.control[i].data = 0;
\r
558 template.control[i].creationData = 0;
\r
561 void AddOption(int x, int y, Control type, int i)
\r
566 AddControl(x, y+1, 95, 9, 0x0082, SS_ENDELLIPSIS | WS_VISIBLE | WS_CHILD, i);
\r
567 AddControl(x+95, y, 50, 11, 0x0081, ES_AUTOHSCROLL | ES_NUMBER | WS_BORDER | WS_VISIBLE | WS_CHILD | WS_TABSTOP, i+1);
\r
570 AddControl(x, y+1, 95, 9, 0x0082, SS_ENDELLIPSIS | WS_VISIBLE | WS_CHILD, i);
\r
571 AddControl(x+95, y, 190, 11, 0x0081, ES_AUTOHSCROLL | WS_BORDER | WS_VISIBLE | WS_CHILD | WS_TABSTOP, i+1);
\r
573 case TextBox: // For now all text edits get a browse button, as long as -file and -path options are not yet implemented
\r
576 AddControl(x, y+1, 95, 9, 0x0082, SS_ENDELLIPSIS | WS_VISIBLE | WS_CHILD, i);
\r
577 AddControl(x+95, y, 180, 11, 0x0081, ES_AUTOHSCROLL | WS_BORDER | WS_VISIBLE | WS_CHILD | WS_TABSTOP, i+1);
\r
578 AddControl(x+275, y, 20, 12, 0x0080, BS_PUSHBUTTON | WS_VISIBLE | WS_CHILD | WS_TABSTOP, i-2);
\r
579 layoutList[i/2-1] = -2;
\r
582 AddControl(x, y, 145, 11, 0x0080, BS_AUTOCHECKBOX | WS_VISIBLE | WS_CHILD | WS_TABSTOP, i);
\r
585 AddControl(x, y+1, 95, 9, 0x0082, SS_ENDELLIPSIS | WS_VISIBLE | WS_CHILD, i);
\r
586 AddControl(x+95, y-1, 50, 500, 0x0085, CBS_AUTOHSCROLL | CBS_DROPDOWN | WS_VISIBLE | WS_CHILD | WS_TABSTOP, i+1);
\r
590 AddControl(x-2, y, 65, 13, 0x0080, BS_PUSHBUTTON | WS_VISIBLE | WS_CHILD, i);
\r
597 CreateDialogTemplate(int *layoutList, int nr, ChessProgramState *cps)
\r
599 int i, j, x=1, y=0, buttonRows, breakPoint = -1, k=0;
\r
601 template.header.cdit = 0;
\r
602 template.header.cx = 307;
\r
603 buttonRows = (buttons + 1 + 3)/4; // 4 per row, ronded up
\r
605 breakPoint = (nr+2*buttonRows+1)/2 & ~1;
\r
606 template.header.cx = 625;
\r
609 for(i=0; i<nr; i++) {
\r
610 if(k < groups && i == boxList[k]) {
\r
612 AddControl(x+2, y+13*(i>>1)-2, 301, 13*(boxList[k+1]-boxList[k]>>1)+8,
\r
613 0x0082, WS_VISIBLE | WS_CHILD | SS_BLACKFRAME, 2400);
\r
614 AddControl(x+60, y+13*(i>>1)-6, 10*groupNameList[k]/3, 10,
\r
615 0x0082, SS_ENDELLIPSIS | WS_VISIBLE | WS_CHILD, 2*(i+MAX_OPTIONS));
\r
619 AddOption(x+155-150*(i&1), y+13*(i>>1)+5, cps->option[j].type, 2*i);
\r
620 if(k < groups && i+1 == boxList[k+1]) {
\r
623 if(i+1 == breakPoint) { x += 318; y = -13*(breakPoint>>1); }
\r
625 // add butons at the bottom of dialog window
\r
628 AddControl(x+275, y+18*(buttonRows-1), 25, 15, 0x0080, BS_PUSHBUTTON | WS_VISIBLE | WS_CHILD, IDOK-2000);
\r
629 AddControl(x+235, y+18*(buttonRows-1), 35, 15, 0x0080, BS_PUSHBUTTON | WS_VISIBLE | WS_CHILD, IDCANCEL-2000);
\r
630 for(i=0; i<buttons; i++) {
\r
631 AddControl(x+70*(i%4)+5, y+18*(i/4), 65, 15, 0x0080, BS_PUSHBUTTON | WS_VISIBLE | WS_CHILD, 2*(nr+i));
\r
632 layoutList[nr+i] = buttonList[i];
\r
634 template.title[8] = cps == &first ? '1' : '2';
\r
635 template.header.cy = y += 18*buttonRows+2;
\r
636 template.header.style &= ~WS_VSCROLL;
\r
638 template.header.cx = 295;
\r
639 template.header.cy = 300;
\r
640 template.header.style |= WS_VSCROLL;
\r
645 EngineOptionsPopup(HWND hwnd, ChessProgramState *cps)
\r
647 FARPROC lpProc = MakeProcInstance( (FARPROC) SettingsProc, hInst );
\r
650 DesignOptionDialog(cps);
\r
651 CreateDialogTemplate(layoutList, layout, cps);
\r
654 DialogBoxIndirect( hInst, &template.header, hwnd, (DLGPROC)lpProc );
\r
656 FreeProcInstance(lpProc);
\r