Implement Load Engine dialog in WinBoard
[xboard.git] / winboard / wsettings.c
index caacb0c..43fcd06 100644 (file)
@@ -21,6 +21,7 @@
 #include "backendz.h"\r
 \r
 #define _(s) T_(s)\r
+#define N_(s) s\r
 \r
 int layoutList[2*MAX_OPTIONS];\r
 int checkList[2*MAX_OPTIONS];\r
@@ -30,14 +31,25 @@ int boxList[2*MAX_OPTIONS];
 int groupNameList[2*MAX_OPTIONS];\r
 int breaks[MAX_OPTIONS];\r
 int checks, combos, buttons, layout, groups;\r
+char title[MSG_SIZ];\r
+char *engineName, *engineDir, *engineChoice, *engineLine, *nickName, *params;\r
+Boolean isUCI, hasBook, storeVariant, v1, addToList;\r
+extern Option installOptions[], matchOptions[];\r
+char *engineNr[] = { N_("First"), N_("Second"), NULL };\r
+char *engineList[1000] = {" "}, *engineMnemonic[1000] = {""};\r
+void (*okFunc)();\r
+ChessProgramState *activeCps;\r
+Option *activeList;\r
+void InstallOK P((void));\r
+typedef void ButtonCallback(HWND h);\r
 \r
 void\r
-PrintOpt(int i, int right, ChessProgramState *cps)\r
+PrintOpt(int i, int right, Option *optionList)\r
 {\r
     if(i<0) {\r
        if(!right) fprintf(debugFP, "%30s", "");\r
     } else {\r
-       Option opt = cps->option[i];\r
+       Option opt = optionList[i];\r
        switch(opt.type) {\r
            case Slider:\r
            case Spin:\r
@@ -48,6 +60,9 @@ PrintOpt(int i, int right, ChessProgramState *cps)
            case PathName:\r
                fprintf(debugFP, "%20.20s [______________________________________]", opt.name);\r
                break;\r
+           case Label:\r
+               fprintf(debugFP, "%41.41s", opt.name);\r
+               break;\r
            case CheckBox:\r
                fprintf(debugFP, "[x] %-26.25s", opt.name);\r
                break;\r
@@ -67,13 +82,13 @@ PrintOpt(int i, int right, ChessProgramState *cps)
 }\r
 \r
 void\r
-CreateOptionDialogTest(int *list, int nr, ChessProgramState *cps)\r
+CreateOptionDialogTest(int *list, int nr, Option *optionList)\r
 {\r
     int line;\r
 \r
     for(line = 0; line < nr; line+=2) {\r
-       PrintOpt(list[line+1], 0, cps);\r
-       PrintOpt(list[line], 1, cps);\r
+       PrintOpt(list[line+1], 0, optionList);\r
+       PrintOpt(list[line], 1, optionList);\r
     }\r
 }\r
 \r
@@ -99,6 +114,7 @@ LayoutOptions(int firstOption, int endOption, char *groupName, Option *optionLis
                case FileName:\r
                case PathName:\r
                case Slider:\r
+               case Label:\r
                case Spin: stop++;\r
                default:\r
                case Message: ; // cannot happen\r
@@ -109,7 +125,7 @@ LayoutOptions(int firstOption, int endOption, char *groupName, Option *optionLis
        if(!stop)\r
            nextType = Button; // kudge to flush remaining checks and combos undistorted\r
        // Take a new line if a spin follows combos or checks, or when we encounter a textbox\r
-       if((combos+checks || nextType == TextBox || nextType == FileName || nextType == PathName) && layout&1) {\r
+       if((combos+checks || nextType == TextBox || nextType == FileName || nextType == PathName || nextType == Label) && layout&1) {\r
            layoutList[layout++] = -1;\r
        }\r
        // The last check or combo before a spin will be put on the same line as that spin (prefix)\r
@@ -139,7 +155,7 @@ LayoutOptions(int firstOption, int endOption, char *groupName, Option *optionLis
            layoutList[layout++] = -1;\r
            layoutList[layout++] = comboList[2*right];\r
        }\r
-       if(nextType == TextBox || nextType == FileName || nextType == PathName) {\r
+       if(nextType == TextBox || nextType == FileName || nextType == PathName || nextType == Label) {\r
            // A textBox is double width, so must be left-adjusted, and the right column remains empty\r
            breaks[layout/2] = lastType == Button ? 0 : 100;\r
            layoutList[layout++] = -1;\r
@@ -173,44 +189,46 @@ EndMatch(char *s1, char *s2)
 }\r
 \r
 void\r
-DesignOptionDialog(ChessProgramState *cps)\r
+DesignOptionDialog(int nrOpt, Option *optionList)\r
 {\r
     int k=0, n=0;\r
     char buf[MSG_SIZ];\r
 \r
     layout = 0;\r
     buttons = groups = 0;\r
-    while(k < cps->nrOptions) { // k steps through 'solitary' options\r
+    while(k < nrOpt) { // k steps through 'solitary' options\r
        // look if we hit a group of options having names that start with the same word\r
        int groupSize = 1, groupNameLength = 50;\r
-       sscanf(cps->option[k].name, "%s", buf); // get first word of option name\r
-       while(k + groupSize < cps->nrOptions &&\r
-             strstr(cps->option[k+groupSize].name, buf) == cps->option[k+groupSize].name) {\r
+       sscanf(optionList[k].name, "%s", buf); // get first word of option name\r
+       while(k + groupSize < nrOpt &&\r
+             strstr(optionList[k+groupSize].name, buf) == optionList[k+groupSize].name) {\r
                int j;\r
                for(j=0; j<groupNameLength; j++) // determine common initial part of option names\r
-                   if( cps->option[k].name[j] != cps->option[k+groupSize].name[j]) break;\r
+                   if( optionList[k].name[j] != optionList[k+groupSize].name[j]) break;\r
                groupNameLength = j;\r
                groupSize++;\r
 \r
        }\r
        if(groupSize > 3) {\r
                // We found a group to terminates the current section\r
-               LayoutOptions(n, k, "", cps->option); // flush all solitary options appearing before the group\r
+               LayoutOptions(n, k, "", optionList); // flush all solitary options appearing before the group\r
                groupNameList[groups] = groupNameLength;\r
                boxList[groups++] = layout; // group start in even entries\r
-               LayoutOptions(k, k+groupSize, buf, cps->option); // flush the group\r
+               LayoutOptions(k, k+groupSize, buf, optionList); // flush the group\r
                boxList[groups++] = layout; // group end in odd entries\r
                k = n = k + groupSize;\r
        } else k += groupSize; // small groups are grouped with the solitary options\r
     }\r
-    if(n != k) LayoutOptions(n, k, "", cps->option); // flush remaining solitary options\r
+    if(n != k) LayoutOptions(n, k, "", optionList); // flush remaining solitary options\r
     // decide if and where we break into two column pairs\r
 \r
     // Emit buttons and add OK and cancel\r
 //    for(k=0; k<buttons; k++) layoutList[layout++] = buttonList[k];\r
-    // Create the dialog window\r
-    if(appData.debugMode) CreateOptionDialogTest(layoutList, layout, cps);\r
-//    CreateOptionDialog(layoutList, layout, cps);\r
\r
+   // Create the dialog window\r
+    if(appData.debugMode) CreateOptionDialogTest(layoutList, layout, optionList);\r
+//    CreateOptionDialog(layoutList, layout, optionList);\r
+    if(!activeCps) okFunc = optionList[nrOpt].target;\r
 }\r
 \r
 #include <windows.h>\r
@@ -238,44 +256,42 @@ struct {
     0x0000, 0x0000, L"Engine #1 Settings ", 8, L"MS Sans Serif"\r
 };\r
 \r
-ChessProgramState *activeCps;\r
-\r
 void\r
-SetOptionValues(HWND hDlg, ChessProgramState *cps)\r
+SetOptionValues(HWND hDlg, ChessProgramState *cps, Option *optionList)\r
 // Put all current option values in controls, and write option names next to them\r
 {\r
     HANDLE hwndCombo;\r
     int i, k;\r
-    char **choices, title[MSG_SIZ], *name;\r
+    char **choices, *name;\r
 \r
     for(i=0; i<layout+buttons; i++) {\r
        int j=layoutList[i];\r
        if(j == -2) SetDlgItemText( hDlg, 2000+2*i, ". . ." );\r
        if(j<0) continue;\r
-       name = cps->option[j].name;\r
+       name = optionList[j].name;\r
        if(strstr(name, "Polyglot ") == name) name += 9;\r
        SetDlgItemText( hDlg, 2000+2*i, name );\r
-//if(appData.debugMode) fprintf(debugFP, "# %s = %d\n",cps->option[j].name, cps->option[j].value );\r
-       switch(cps->option[j].type) {\r
+//if(appData.debugMode) fprintf(debugFP, "# %s = %d\n",optionList[j].name, optionList[j].value );\r
+       switch(optionList[j].type) {\r
            case Spin:\r
-               SetDlgItemInt( hDlg, 2001+2*i, cps->option[j].value, TRUE );\r
+               SetDlgItemInt( hDlg, 2001+2*i, cps ? optionList[j].value : *(int*)optionList[j].target, TRUE );\r
                break;\r
            case TextBox:\r
            case FileName:\r
            case PathName:\r
-               SetDlgItemText( hDlg, 2001+2*i, cps->option[j].textValue );\r
+               SetDlgItemText( hDlg, 2001+2*i, cps ? optionList[j].textValue : *(char**)optionList[j].target );\r
                break;\r
            case CheckBox:\r
-               CheckDlgButton( hDlg, 2000+2*i, cps->option[j].value != 0);\r
+               CheckDlgButton( hDlg, 2000+2*i, (cps ? optionList[j].value : *(Boolean*)optionList[j].target) != 0);\r
                break;\r
            case ComboBox:\r
-               choices = (char**) cps->option[j].textValue;\r
+               choices = (char**) optionList[j].textValue;\r
                hwndCombo = GetDlgItem(hDlg, 2001+2*i);\r
                SendMessage(hwndCombo, CB_RESETCONTENT, 0, 0);\r
-               for(k=0; k<cps->option[j].max; k++) {\r
+               for(k=0; k<optionList[j].max; k++) {\r
                    SendMessage(hwndCombo, CB_ADDSTRING, 0, (LPARAM) choices[k]);\r
                }\r
-               SendMessage(hwndCombo, CB_SELECTSTRING, (WPARAM) -1, (LPARAM) choices[cps->option[j].value]);\r
+               SendMessage(hwndCombo, CB_SELECTSTRING, (WPARAM) -1, (LPARAM) choices[optionList[j].value]);\r
                break;\r
            case Button:\r
            case SaveButton:\r
@@ -285,7 +301,6 @@ SetOptionValues(HWND hDlg, ChessProgramState *cps)
     }\r
     SetDlgItemText( hDlg, IDOK, _("OK") );\r
     SetDlgItemText( hDlg, IDCANCEL, _("Cancel") );\r
-    snprintf(title, MSG_SIZ, _("%s Engine Settings (%s)"), T_(cps->which), cps->tidy);\r
     title[0] &= ~32; // capitalize\r
     SetWindowText( hDlg, title);\r
     for(i=0; i<groups; i+=2) {\r
@@ -293,7 +308,7 @@ SetOptionValues(HWND hDlg, ChessProgramState *cps)
        id = k = boxList[i];\r
        if(layoutList[k] < 0) k++;\r
        if(layoutList[k] < 0) continue;\r
-       for(p=0; p<groupNameList[i]; p++) buf[p] = cps->option[layoutList[k]].name[p];\r
+       for(p=0; p<groupNameList[i]; p++) buf[p] = optionList[layoutList[k]].name[p];\r
        buf[p] = 0;\r
        SetDlgItemText( hDlg, 2000+2*(id+MAX_OPTIONS), buf );\r
     }\r
@@ -301,7 +316,7 @@ SetOptionValues(HWND hDlg, ChessProgramState *cps)
 \r
 \r
 void\r
-GetOptionValues(HWND hDlg, ChessProgramState *cps)\r
+GetOptionValues(HWND hDlg, ChessProgramState *cps, Option *optionList)\r
 // read out all controls, and if value is altered, remember it and send it to the engine\r
 {\r
     HANDLE hwndCombo;\r
@@ -312,50 +327,63 @@ GetOptionValues(HWND hDlg, ChessProgramState *cps)
     for(i=0; i<layout; i++) {\r
        int j=layoutList[i];\r
        if(j<0) continue;\r
-       switch(cps->option[j].type) {\r
+       switch(optionList[j].type) {\r
            case Spin:\r
                new = GetDlgItemInt( hDlg, 2001+2*i, &success, TRUE );\r
                if(!success) break;\r
-               if(new < cps->option[j].min) new = cps->option[j].min;\r
-               if(new > cps->option[j].max) new = cps->option[j].max;\r
-               changed = 2*(cps->option[j].value != new);\r
-               cps->option[j].value = new;\r
+               if(new < optionList[j].min) new = optionList[j].min;\r
+               if(new > optionList[j].max) new = optionList[j].max;\r
+               if(!cps) { *(int*)optionList[j].target = new; break; }\r
+               changed = 2*(optionList[j].value != new);\r
+               optionList[j].value = new;\r
                break;\r
            case TextBox:\r
            case FileName:\r
            case PathName:\r
-               success = GetDlgItemText( hDlg, 2001+2*i, newText, MSG_SIZ - strlen(cps->option[j].name) - 9 );\r
+               success = GetDlgItemText( hDlg, 2001+2*i, newText, MSG_SIZ - strlen(optionList[j].name) - 9 );\r
                if(!success) break;\r
-               changed = strcmp(cps->option[j].textValue, newText) != 0;\r
-               safeStrCpy(cps->option[j].textValue, newText, MSG_SIZ - (cps->option[j].textValue - cps->option[j].name) );\r
+               if(!cps) {\r
+                   if(*(char**)optionList[j].target) free(*(char**)optionList[j].target);\r
+                   *(char**)optionList[j].target = strdup(newText);\r
+                   break;\r
+               }\r
+               changed = strcmp(optionList[j].textValue, newText) != 0;\r
+               safeStrCpy(optionList[j].textValue, newText, MSG_SIZ - (optionList[j].textValue - optionList[j].name) );\r
                break;\r
            case CheckBox:\r
                new = IsDlgButtonChecked( hDlg, 2000+2*i );\r
-               changed = 2*(cps->option[j].value != new);\r
-               cps->option[j].value = new;\r
+               if(!cps) { *(Boolean*)optionList[j].target = new; break; }\r
+               changed = 2*(optionList[j].value != new);\r
+               optionList[j].value = new;\r
                break;\r
            case ComboBox:\r
-               choices = (char**) cps->option[j].textValue;\r
+               choices = (char**) optionList[j].textValue;\r
                hwndCombo = GetDlgItem(hDlg, 2001+2*i);\r
                success = GetDlgItemText( hDlg, 2001+2*i, newText, MSG_SIZ );\r
                if(!success) break;\r
                new = -1;\r
-               for(k=0; k<cps->option[j].max; k++) {\r
+               for(k=0; k<optionList[j].max; k++) {\r
                    if(!strcmp(choices[k], newText)) new = k;\r
                }\r
-               changed = new >= 0 && (cps->option[j].value != new);\r
-               if(changed) cps->option[j].value = new;\r
+               if(!cps && new) {\r
+                   if(*(char**)optionList[j].target) free(*(char**)optionList[j].target);\r
+                   *(char**)optionList[j].target = strdup(optionList[j].choice[new]);\r
+                   break;\r
+               }\r
+               changed = new >= 0 && (optionList[j].value != new);\r
+               if(changed) optionList[j].value = new;\r
                break;\r
            case Button:\r
            default:\r
                break; // are treated instantly, so they have been sent already\r
        }\r
        if(changed == 2)\r
-         snprintf(buf, MSG_SIZ, "option %s=%d\n", cps->option[j].name, new); else\r
+         snprintf(buf, MSG_SIZ, "option %s=%d\n", optionList[j].name, new); else\r
        if(changed == 1)\r
-         snprintf(buf, MSG_SIZ, "option %s=%s\n", cps->option[j].name, newText);\r
+         snprintf(buf, MSG_SIZ, "option %s=%s\n", optionList[j].name, newText);\r
        if(changed) SendToProgram(buf, cps);\r
     }\r
+    if(!cps && okFunc) ((ButtonCallback*) okFunc)(0);\r
 }\r
 \r
 LRESULT CALLBACK SettingsProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)\r
@@ -368,7 +396,7 @@ LRESULT CALLBACK SettingsProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lPa
     case WM_INITDIALOG:\r
 \r
 //        CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));\r
-       SetOptionValues(hDlg, activeCps);\r
+       SetOptionValues(hDlg, activeCps, activeList);\r
 \r
 //        SetFocus(GetDlgItem(hDlg, IDC_NFG_Edit));\r
 \r
@@ -377,12 +405,14 @@ LRESULT CALLBACK SettingsProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lPa
     case WM_COMMAND:\r
         switch( LOWORD(wParam) ) {\r
         case IDOK:\r
-           GetOptionValues(hDlg, activeCps);\r
+           GetOptionValues(hDlg, activeCps, activeList);\r
             EndDialog( hDlg, 0 );\r
+           activeCps = NULL;\r
             return TRUE;\r
 \r
         case IDCANCEL:\r
             EndDialog( hDlg, 1 );\r
+           activeCps = NULL;\r
             return TRUE;\r
 \r
        default:\r
@@ -426,10 +456,10 @@ LRESULT CALLBACK SettingsProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lPa
                    }\r
                }\r
                if(j < 0) break;\r
-               if( activeCps->option[j].type  == SaveButton)\r
-                    GetOptionValues(hDlg, activeCps);\r
-               else if( activeCps->option[j].type  != Button) break;\r
-               snprintf(buf, MSG_SIZ, "option %s\n", activeCps->option[j].name);\r
+               if( activeList[j].type  == SaveButton)\r
+                    GetOptionValues(hDlg, activeCps, activeList);\r
+               else if( activeList[j].type  != Button) break;\r
+               snprintf(buf, MSG_SIZ, "option %s\n", activeList[j].name);\r
                SendToProgram(buf, activeCps);\r
            }\r
            break;\r
@@ -471,7 +501,11 @@ void AddOption(int x, int y, Control type, int i)
            break;\r
        case TextBox:\r
            AddControl(x, y+1, 95, 9, 0x0082, SS_ENDELLIPSIS | WS_VISIBLE | WS_CHILD, i);\r
-           AddControl(x+95, y, 190, 11, 0x0081, ES_AUTOHSCROLL | WS_BORDER | WS_VISIBLE | WS_CHILD | WS_TABSTOP, i+1);\r
+           AddControl(x+95, y, 200, 11, 0x0081, ES_AUTOHSCROLL | WS_BORDER | WS_VISIBLE | WS_CHILD | WS_TABSTOP, i+1);\r
+           break;\r
+       case Label:\r
+           extra = activeList[layoutList[i/2]].value;\r
+           AddControl(x+extra, y+1, 290-extra, 9, 0x0082, SS_ENDELLIPSIS | WS_VISIBLE | WS_CHILD, i);\r
            break;\r
        case FileName:\r
        case PathName:\r
@@ -485,7 +519,8 @@ void AddOption(int x, int y, Control type, int i)
            break;\r
        case ComboBox:\r
            AddControl(x, y+1, 95, 9, 0x0082, SS_ENDELLIPSIS | WS_VISIBLE | WS_CHILD, i);\r
-           AddControl(x+95, y-1, 50, 500, 0x0085, CBS_AUTOHSCROLL | CBS_DROPDOWN | WS_VISIBLE | WS_CHILD | WS_TABSTOP, i+1);\r
+           AddControl(x+95, y-1, !activeCps && x<10 ? 120 : 50, 500, 0x0085,\r
+                       CBS_AUTOHSCROLL | CBS_DROPDOWN | WS_VISIBLE | WS_CHILD | WS_TABSTOP | WS_VSCROLL, i+1);\r
            break;\r
        case Button:\r
        case ResetButton:\r
@@ -499,7 +534,7 @@ void AddOption(int x, int y, Control type, int i)
 }\r
 \r
 void\r
-CreateDialogTemplate(int *layoutList, int nr, ChessProgramState *cps)\r
+CreateDialogTemplate(int *layoutList, int nr, Option *optionList)\r
 {\r
     int i, j, x=1, y=0, buttonRows, breakPoint = -1, k=0;\r
 \r
@@ -521,7 +556,7 @@ CreateDialogTemplate(int *layoutList, int nr, ChessProgramState *cps)
        }\r
        j = layoutList[i];\r
        if(j >= 0)\r
-           AddOption(x+155-150*(i&1), y+13*(i>>1)+5, cps->option[j].type, 2*i);\r
+           AddOption(x+155-150*(i&1), y+13*(i>>1)+5, optionList[j].type, 2*i);\r
        if(k < groups && i+1 == boxList[k+1]) {\r
            k += 2; y += 4;\r
        }\r
@@ -536,7 +571,7 @@ CreateDialogTemplate(int *layoutList, int nr, ChessProgramState *cps)
        AddControl(x+70*(i%4)+5, y+18*(i/4), 65, 15, 0x0080, BS_PUSHBUTTON | WS_VISIBLE | WS_CHILD, 2*(nr+i));\r
        layoutList[nr+i] = buttonList[i];\r
     }\r
-    template.title[8] = cps == &first ? '1' :  '2';\r
+    template.title[8] = optionList == first.option ? '1' :  '2';\r
     template.header.cy = y += 18*buttonRows+2;\r
     template.header.style &= ~WS_VSCROLL;\r
 }\r
@@ -546,9 +581,10 @@ EngineOptionsPopup(HWND hwnd, ChessProgramState *cps)
 {\r
     FARPROC lpProc = MakeProcInstance( (FARPROC) SettingsProc, hInst );\r
 \r
-    activeCps = cps;\r
-    DesignOptionDialog(cps);\r
-    CreateDialogTemplate(layoutList, layout, cps);\r
+    activeCps = cps; activeList = cps->option;\r
+    snprintf(title, MSG_SIZ, _("%s Engine Settings (%s)"), T_(cps->which), cps->tidy);\r
+    DesignOptionDialog(cps->nrOptions, cps->option);\r
+    CreateDialogTemplate(layoutList, layout, cps->option);\r
 \r
 \r
     DialogBoxIndirect( hInst, &template.header, hwnd, (DLGPROC)lpProc );\r
@@ -558,4 +594,59 @@ EngineOptionsPopup(HWND hwnd, ChessProgramState *cps)
     return;\r
 }\r
 \r
+void InstallOK()\r
+{\r
+    if(engineChoice[0] == engineNr[0][0])  Load(&first, 0); else Load(&second, 1);\r
+}\r
 \r
+Option installOptions[] = {\r
+  {   0,  0,    0, NULL, (void*) &engineLine, (char*) engineMnemonic, engineList, ComboBox, N_("Select engine from list:") },\r
+  {   0,  0,    0, NULL, NULL, NULL, NULL, Label, N_("or specify one below:") },\r
+  {   0,  0,    0, NULL, (void*) &nickName, NULL, NULL, TextBox, N_("Nickname (optional):") },\r
+  {   0,  0,    3, NULL, (void*) &engineName, NULL, NULL, FileName, N_("Engine Executable:") },\r
+  {   0,  0,    0, NULL, (void*) &params, NULL, NULL, TextBox, N_("Engine command-line Parameters:") },\r
+  {   0,  0,    0, NULL, (void*) &engineDir, NULL, NULL, PathName, N_("Engine Directory:") },\r
+  {  95,  0,    0, NULL, NULL, NULL, NULL, Label, N_("(Directory will be derived from engine path when empty)") },\r
+  {   0,  0,    0, NULL, (void*) &isUCI, NULL, NULL, CheckBox, N_("UCI") },\r
+  {   0,  0,    0, NULL, (void*) &v1, NULL, NULL, CheckBox, N_("WB protocol v1 (skip waiting for features)") },\r
+  {   0,  0,    0, NULL, (void*) &addToList, NULL, NULL, CheckBox, N_("Add this engine to the list") },\r
+  {   0,  0,    0, NULL, (void*) &hasBook, NULL, NULL, CheckBox, N_("Must not use GUI book") },\r
+  {   0,  0,    0, NULL, (void*) &storeVariant, NULL, NULL, CheckBox, N_("Force current variant with this engine") },\r
+  {   0,  0,    2, NULL, (void*) &engineChoice, (char*) engineNr, engineNr, ComboBox, N_("Load mentioned engine as") },\r
+  {   0,  1,    0, NULL, (void*) &InstallOK, "", NULL, EndMark , "" }\r
+};\r
+\r
+void\r
+GenericPopup(HWND hwnd, Option *optionList)\r
+{\r
+    FARPROC lpProc = MakeProcInstance( (FARPROC) SettingsProc, hInst );\r
+    int n=0;\r
+\r
+    while(optionList[n].type != EndMark) n++;\r
+    activeCps = NULL; activeList = optionList;\r
+    DesignOptionDialog(n, optionList);\r
+    CreateDialogTemplate(layoutList, layout, optionList);\r
+\r
+    DialogBoxIndirect( hInst, &template.header, hwnd, (DLGPROC)lpProc );\r
+\r
+    FreeProcInstance(lpProc);\r
+\r
+    return;\r
+}\r
+\r
+void LoadEnginePopUp(HWND hwnd)\r
+{\r
+    int n=0;\r
+\r
+    isUCI = addToList = storeVariant = v1 = FALSE; hasBook = TRUE; // defaults\r
+    if(engineDir)    free(engineDir);    engineDir = strdup("");\r
+    if(params)       free(params);       params = strdup("");\r
+    if(nickName)     free(nickName);     nickName = strdup("");\r
+    if(engineChoice) free(engineChoice); engineChoice = strdup(engineNr[0]);\r
+    if(engineLine)   free(engineLine);   engineLine = strdup("");\r
+    NamesToList(firstChessProgramNames, engineList, engineMnemonic);\r
+    while(engineList[n]) n++; installOptions[0].max = n;\r
+    snprintf(title, MSG_SIZ, _("Load Engine"));\r
+\r
+    GenericPopup(hwnd, installOptions);\r
+}\r