From: H.G. Muller Date: Mon, 19 Mar 2012 20:55:58 +0000 (+0100) Subject: Major refactoring of GenericPopUp X-Git-Url: http://winboard.nl/cgi-bin?a=commitdiff_plain;h=fa8cdd39eca80f4bdbf6e8e8a290fa1b8979224e;p=xboard.git Major refactoring of GenericPopUp Allow more transient dialogs in GenericPopUp Remove grab from promotion popup Fix other generic popup over transient popup To use the generic dialog generator for 'asynchronous' popups (Ask Qustion or Error popup caused by engine), the currentOptions setting has to be restored for the combo and checkbox callbacks of the transient to still work after the asynchronous dialog returns. Note that only transient dialogs can have check and combo controls. Make generic calcel button suppressible Also #define some more symbols for Option.min flags, and move them to dialogs.h. Change TypeInProc to general OK handler The move type-in now has its own option list, to distinguish it from the ICS input box, and give it its own OK handler. Rather than having the translation for on the text widget call TypeInEvent directly, we let it call GenericCallback, which calls GenericReadout, which calls the OK proc, which does the job. To be able to call GenericCallback from the TypeInProc, the recognition of OK and cancel buttons had to be changed. This because it was too difficult to arrange the calling widget had label OK or cancell. So these buttons are no longer recognized by name, but by the option number passed as client data. (This solves the problem that a user could not make buttons named 'cancel' or 'OK'.) Make Cancel button optional Fix closing multiple popups of same kind The GenericCallback figures out its own shell, so all buttons of multiple dialogs keep working. External calls to PopDown only work on the lastcreated instance of that kind, though (including those from the Delete Window button, which can do 'cross-closing'). shellUp is now a counter, and PopDowns are only prevented when it reaches 0 or the current shell does not exist. (To know this, PopDown now resets shells[n] to NULL when is shell is destroyed. Beware of double PopDowns (through OK procs); they wreck the system. Fix Delete Window button of multipe ErrorPopUps The action routine for handling the Delete Window now pays attention to the shell widget that the system passes to it, and temporarily replaces shells[n] by it to let PopDown act on the proper instance. Add ListBox dialog type to GenericPopUp Fix vert sizing of ListBox Put listbox widgets in viewport Put listbox in viewport Improved xoptions.c support for focussing and listboxes Fix OK-row button positioning Let GenericPopUp take parent and modality as arguments This makes the code a bit more explicit and less kludgy. It also becomes possible to call the same dialog (e.g. Load Options) from the main menu and from another dialog (e.g. the Game List). Support scroll function for generic popup listboxes Fix scrolling Move HighlightWithScroll to xoptions.c Change scroll algorithm Add mouse-wheel scroll to generic list boxes Implement tabbing between text edits Implement same-row text labels in generic dialog Allow labels to specify their chaining in generic popup The opt.min variable is used to specify the chaining: 0xF0 are the bits for (left, right) chaining of the left side (0xC0) and right side (0x30). The 0xC bits determine top or bottom chaining of the entire label. Without anything spcified (0), the chaining is XtRubber. TextBox options can also specify top-chaining of their top. All this was needed to allow decent implementation of the Engine Output window with the generic popup. (Although tags and comment popup ca benefit from the latter feature.) Let GenericPopUp support a Graph option The Graph option results in an area where one can draw something. It is positioned / chained similar to Label options. A handler for expose events can be specified in the textValue field of the option. Implement box widgets and menu buttons in GenericPopup To enhance the capabilities of GenericPopUp such that it could create the main window, it needs to be able tha packaging of controls into a box widget (for mennu and button bar). Menu buttons are also required elements (although they do look a lot like comboboxes?) Option types BoxBegin and BoxEnd can now be used to bracket a group of controls that will be put in a box widget. (Cannot be used recursively!) The positioning of the box is similar to that of a Label, and is specified in the BogBegin option. The code to shrink the menu buttons to fit is also incorporated, to act on any box widget: if the BoxBegin option specifies a width, the elements in it are shrunk to meet the requirement. Otherwise the box just gets the size of the sum of its children (plus spacings). Label options can now specify a font, casted into their textValue field. (This is needed to get the proper size for the clock widgets.) Implement callback in BoxEnd options BoxEnd is a pseudo-option, to trigger packing the preceeding ones in an earlier-opened box widget. In the process it calculates the size of the box widget (and trims it if a size was specified for it in the corresponding BoxBegin). The Option.target field of BoxEnd is now interpreted as a callback, which can be use to take decisions based on the determined size for the remaining options in the list, before these are processed b GenericPopUp. Refactor xoptions.c Make a subroutine to set args shared by almost all widgets. Swap meaning of '1'-bit in option.min flag of Break option, to be consistent with SAME_ROW interpretation in other option types. Make option tables consistent with refactored GenericPopUp The flag for stacking in the Break option needed to be inverted, and the BoardPopUp needed to pass the font in another field. Better use was made of the improved chaining options too. Improve Graph-option event handling The user-supplied callback now gets 3 arguments passed: the event type (0 = pointer motion, 1...5 button press, -1...-5 release, 10 = expose), and two coordinates. For ouse events these are the pointer (x,y), while for expose events they are the window size (w,h). The callback is now specified in the option.target field of the Graph option. Store engine options in malloc'ed memory The Option.name field has been re-declared as (char*), from (char[MSG_SIZ]). There are still MSG_SIZ chars allocated irrespective of actual size, because the field is also supposed to store the textValue, which can be changed by the user. But at least it means that unused options of the generous list now don't waste much space. (And the prparated Option tables in dialogs.c will shrink by a large factor as well.) Improve GenericPopUp ComboBox handling. The dialog type is now passed to the combobox callback as well, and this is used to really figure out what option it is called for. Allow numeric comboboxes When no list of strings is given in Option.choice, the target is assumed to be (int), and the number of the slected entry is stored there. Also adapts the Label options that act as fillers to the new method for making dummies (namely NULL in the Option.name field). Put comboCallback in Option struct Rather than having a general comboCallback variable for the entire current dialog, each ComboBox option can now specify its own callback in the target field of the option: the COMBO_CALLBACK bit of Option.min indicates whether the target is a variable to be set or a callback. The callback can still fetch the choice from the values array. Allow generic CreateComboPopup also to do main menus An extra parameter to CreateComboPopup determines if the menu texts should be taken from a list of strings (the old method with engine- supplied choices), or from a menu table of MenuItems. It can now also recognize "----" as a menu break, and keeps margins (for the marking). Make subroutine for determining curren combo selection Various fixes to GenericPopUp Delete one border-width setting Fix max nr of args in GenerocPopUp Fix button release events of Graph options Fix generic Graph callback pointer motion coordinates Make all format referencing in Option tables symbolic Let Option.choice define menu texts, rather than Option.textValue This is more logical than ussing textValue for it, because choice already has the correct (char**) type, while textValue was (char*), and needed casting everywhere. Note that for engine options, the fields were the same anyway, so no back-end change was required. The textValue now contains the (casted) list of actual string values, where these are needed. (But for numeric and function menus they aren't.) Add PopUp Option type An new pseudo-Option is defined, to add a popup menu to a previous Graph option. The actual popping up is done by the expose handler. The function XUngrabPointer is the key to success here. A PopUp option specifies a callback for handling the selection from the menu, which will be called with the option number, exacty as with ComboBox options. Update option explanation in dialogs.h Make Spin and CheckBox callbacks pass dialog number No longer rely on 'currentOptions' for getting the option belonging to the callback, but get it out of the dialogOptions array indexed by dialog type. This way things cannot be messed up by an asynchrounous error popup. It also means that it is now save for non-modal dialogs to use these options. Use button widget for text behind checkbox Let listboxes use general formatting hints Let GenericPopUp option always finish last pane after Break Allow LisBox to specify select callback in Option.textValue Use double-click to trigger ListBox callback Make ListBox callback re-entrant Fix multi-line Label options Separate CreateMenuItem out from CreateComboPopup Chain checkbox texts entirely left Allow a user-specified callback to Label options This is needed to implement the clocks. Let the CheckBox callback handle it. For now ther is no distinction between different mouse buttons. --- diff --git a/backend.c b/backend.c index 90a63c0..3f6229d 100644 --- a/backend.c +++ b/backend.c @@ -15534,8 +15534,8 @@ ParseOption (Option *opt, ChessProgramState *cps) if(sscanf(p, " -check %d", &def) < 1) return FALSE; opt->value = (def != 0); opt->type = CheckBox; - } else if(p = strstr(opt->name, " -combo ")) { - opt->textValue = (char*) (&cps->comboList[cps->comboCnt]); // cheat with pointer type + } else if(p = strstr(opt->name, " -combo ")) { + opt->textValue = (char*) (opt->choice = &cps->comboList[cps->comboCnt]); // cheat with pointer type cps->comboList[cps->comboCnt++] = q = p+8; // holds possible choices if(*q == '*') cps->comboList[cps->comboCnt-1]++; opt->value = n = 0; @@ -15656,7 +15656,10 @@ ParseFeatures (char *args, ChessProgramState *cps) if (BoolFeature(&p, "memory", &cps->memSize, cps)) continue; if (BoolFeature(&p, "smp", &cps->maxCores, cps)) continue; if (StringFeature(&p, "egt", cps->egtFormats, cps)) continue; - if (StringFeature(&p, "option", cps->option[cps->nrOptions].name, cps)) { + if (StringFeature(&p, "option", buf, cps)) { + FREE(cps->option[cps->nrOptions].name); + cps->option[cps->nrOptions].name = malloc(MSG_SIZ); + safeStrCpy(cps->option[cps->nrOptions].name, buf, MSG_SIZ); if(!ParseOption(&(cps->option[cps->nrOptions++]), cps)) { // [HGM] options: add option feature snprintf(buf, MSG_SIZ, "rejected option %s\n", cps->option[--cps->nrOptions].name); SendToProgram(buf, cps); diff --git a/backend.h b/backend.h index 2fc012f..a5b1056 100644 --- a/backend.h +++ b/backend.h @@ -318,16 +318,8 @@ extern Boolean set_cont_sequence P((char *new_seq)); extern int wrap P((char *dest, char *src, int count, int width, int *lp)); int Explode P((Board board, int fromX, int fromY, int toX, int toY)); -typedef enum { CheckBox, ComboBox, TextBox, Button, Spin, ResetButton, SaveButton, ListBox, - FileName, PathName, Slider, Message, Fractional, Label, Break, EndMark } Control; - -/* Flags Option.min used for ComboBox: */ -#define COMBO_CALLBACK (1 << 0) -#define NO_GETTEXT (1 << 1) - -/* Flags for Option.min used for Button, SaveButton, EndMark: */ -#define SAME_ROW (1 << 0) -#define NO_OK (1 << 1) +typedef enum { CheckBox, ComboBox, TextBox, Button, Spin, ResetButton, SaveButton, ListBox, Graph, PopUp, + FileName, PathName, Slider, Message, Fractional, Label, BoxBegin, BoxEnd, DropDown, Break, EndMark } Control; typedef struct _OPT { // [HGM] options: descriptor of UCI-style option int value; // current setting, starts as default @@ -338,7 +330,7 @@ typedef struct _OPT { // [HGM] options: descriptor of UCI-style option char *textValue; // points to beginning of text value in name field char **choice; // points to array of combo choices in cps->combo Control type; - char name[MSG_SIZ]; // holds both option name and text value + char *name; // holds both option name and text value (in allocated memory) } Option; typedef struct _CPS { diff --git a/dialogs.c b/dialogs.c index 16cf978..ba47eac 100644 --- a/dialogs.c +++ b/dialogs.c @@ -65,7 +65,6 @@ extern char *getenv(); int values[MAX_OPTIONS]; ChessProgramState *currentCps; -ButtonCallback *comboCallback; //----------------------------Generic dialog -------------------------------------------- @@ -89,6 +88,18 @@ AddLine (Option *opt, char *s) //---------------------------------------------- Update dialog controls ------------------------------------ +int +SetCurrentComboSelection (Option *opt) +{ + int j; + if(!opt->textValue) opt->value = *(int*)opt->target; /* numeric */else { + for(j=0; opt->choice[j]; j++) // look up actual value in list of possible values, to get selection nr + if(*(char**)opt->target && !strcmp(*(char**)opt->target, ((char**)opt->textValue)[j])) break; + opt->value = j + (opt->choice[j] == NULL); + } + return opt->value; +} + void GenericUpdate (Option *opts, int selected) { @@ -115,15 +126,15 @@ GenericUpdate (Option *opts, int selected) SetWidgetState(&opts[i], *(Boolean*) opts[i].target); break; case ComboBox: - for(j=0; opts[i].choice[j]; j++) - if(*(char**)opts[i].target && !strcmp(*(char**)opts[i].target, opts[i].choice[j])) break; - values[i] = opts[i].value = j + (opts[i].choice[j] == NULL); - // TODO: actually display this + if(opts[i].min & COMBO_CALLBACK) break; + SetCurrentComboSelection(opts+i); + // TODO: actually display this (but it is never used that way...) break; case EndMark: return; default: printf("GenericUpdate: unexpected case in switch.\n"); + case ListBox: case Button: case SaveButton: case Label: @@ -190,12 +201,13 @@ GenericReadout (Option *opts, int selected) } break; case ComboBox: - val = ((char**)opts[i].choice)[values[i]]; + if(opts[i].min & COMBO_CALLBACK) break; + if(!opts[i].textValue) { *(int*)opts[i].target == opts[i].value; break; } // numeric + val = ((char**)opts[i].textValue)[values[i]]; if(currentCps) { if(opts[i].value == values[i]) break; // not changed opts[i].value = values[i]; - snprintf(buf, MSG_SIZ, "option %s=%s\n", opts[i].name, - ((char**)opts[i].textValue)[values[i]]); + snprintf(buf, MSG_SIZ, "option %s=%s\n", opts[i].name, opts[i].choice[values[i]]); SendToProgram(buf, currentCps); } else if(val && (*(char**) opts[i].target == NULL || strcmp(*(char**) opts[i].target, val))) { if(*(char**) opts[i].target) free(*(char**) opts[i].target); @@ -208,6 +220,7 @@ GenericReadout (Option *opts, int selected) break; default: printf("GenericReadout: unexpected case in switch.\n"); + case ListBox: case Button: case SaveButton: case Label: @@ -243,9 +256,10 @@ static Option matchOptions[] = { { 0, 0, 0, NULL, (void*) &tfName, ".trn", NULL, FileName, N_("Tournament file:") }, { 0, 0, 0, NULL, (void*) &appData.roundSync, "", NULL, CheckBox, N_("Sync after round (for concurrent playing of a single") }, { 0, 0, 0, NULL, (void*) &appData.cycleSync, "", NULL, CheckBox, N_("Sync after cycle tourney with multiple XBoards)") }, -{ 0xD, 150, 0, NULL, (void*) &engineName, "", NULL, TextBox, N_("Tourney participants:") }, +{ 150, T_VSCRL | T_FILL | T_WRAP, + 0, NULL, (void*) &engineName, "", NULL, TextBox, N_("Tourney participants:") }, { 0, COMBO_CALLBACK | NO_GETTEXT, - 0, NULL, (void*) &engineChoice, (char*) (engineMnemonic+1), (engineMnemonic+1), ComboBox, N_("Select Engine:") }, + 0, NULL, (void*) &AddToTourney, (char*) (engineMnemonic+1), (engineMnemonic+1), ComboBox, N_("Select Engine:") }, { 0, 0, 10, NULL, (void*) &appData.tourneyType, "", NULL, Spin, N_("Tourney type (0 = round-robin, 1 = gauntlet):") }, { 0, 1, 1000000000, NULL, (void*) &appData.tourneyCycles, "", NULL, Spin, N_("Number of tourney cycles (or Swiss rounds):") }, { 0, 1, 1000000000, NULL, (void*) &appData.defaultMatchGames, "", NULL, Spin, N_("Default Number of Games in Match (or Pairing):") }, @@ -258,9 +272,9 @@ static Option matchOptions[] = { { 0, 0, 1000000000, NULL, (void*) &appData.rewindIndex, "", NULL, Spin, N_("Rewind Index after this many Games (0 = never):") }, { 0, 0, 0, NULL, (void*) &appData.defNoBook, "", NULL, CheckBox, N_("Disable own engine books by default") }, { 0, 0, 0, NULL, (void*) &ReplaceParticipant, NULL, NULL, Button, N_("Replace Engine") }, -{ 0, 1, 0, NULL, (void*) &UpgradeParticipant, NULL, NULL, Button, N_("Upgrade Engine") }, -{ 0, 1, 0, NULL, (void*) &CloneTourney, NULL, NULL, Button, N_("Clone Tourney") }, -{ 0, 1, 0, NULL, (void*) &MatchOK, "", NULL, EndMark , "" } +{ 0, SAME_ROW, 0, NULL, (void*) &UpgradeParticipant, NULL, NULL, Button, N_("Upgrade Engine") }, +{ 0, SAME_ROW, 0, NULL, (void*) &CloneTourney, NULL, NULL, Button, N_("Clone Tourney") }, +{ 0, SAME_ROW, 0, NULL, (void*) &MatchOK, "", NULL, EndMark , "" } }; static void @@ -295,19 +309,17 @@ CloneTourney () static void AddToTourney (int n) { - GenericReadout(matchOptions, 4); // selected engine - AddLine(&matchOptions[3], engineChoice); + AddLine(&matchOptions[3], engineMnemonic[values[4]+1]); } void MatchOptionsProc () { NamesToList(firstChessProgramNames, engineList, engineMnemonic, "all"); - comboCallback = &AddToTourney; matchOptions[5].min = -(appData.pairingEngine[0] != NULLCHAR); // with pairing engine, allow Swiss ASSIGN(tfName, appData.tourneyFile[0] ? appData.tourneyFile : MakeName(appData.defName)); ASSIGN(engineName, appData.participants); - GenericPopUp(matchOptions, _("Match Options"), TransientDlg); + GenericPopUp(matchOptions, _("Match Options"), TransientDlg, BoardWindow, MODAL); } // ------------------------------------------- General Options -------------------------------------------------- @@ -348,10 +360,10 @@ static Option generalOptions[] = { { 0, 0, 0, NULL, (void*) &appData.markers, "", NULL, CheckBox, N_("Show Target Squares") }, { 0, 0, 0, NULL, (void*) &appData.useStickyWindows, "", NULL, CheckBox, N_("Sticky Windows") }, { 0, 0, 0, NULL, (void*) &appData.testLegality, "", NULL, CheckBox, N_("Test Legality") }, -{ 0, 0, 10, NULL, (void*) &appData.flashCount, "", NULL, Spin, N_("Flash Moves (0 = no flashing):") }, -{ 0, 1, 10, NULL, (void*) &appData.flashRate, "", NULL, Spin, N_("Flash Rate (high = fast):") }, -{ 0, 5, 100,NULL, (void*) &appData.animSpeed, "", NULL, Spin, N_("Animation Speed (high = slow):") }, -{ 0, 1, 5, NULL, (void*) &appData.zoom, "", NULL, Spin, N_("Zoom factor in Evaluation Graph:") }, +{ 0, 0,10, NULL, (void*) &appData.flashCount, "", NULL, Spin, N_("Flash Moves (0 = no flashing):") }, +{ 0, 1,10, NULL, (void*) &appData.flashRate, "", NULL, Spin, N_("Flash Rate (high = fast):") }, +{ 0, 5,100, NULL, (void*) &appData.animSpeed, "", NULL, Spin, N_("Animation Speed (high = slow):") }, +{ 0, 1,5, NULL, (void*) &appData.zoom, "", NULL, Spin, N_("Zoom factor in Evaluation Graph:") }, { 0, 0, 0, NULL, (void*) &GeneralOptionsOK, "", NULL, EndMark , "" } }; @@ -360,7 +372,7 @@ OptionsProc () { oldPonder = appData.ponderNextMove; oldShow = appData.showCoords; oldBlind = appData.blindfold; - GenericPopUp(generalOptions, _("General Options"), TransientDlg); + GenericPopUp(generalOptions, _("General Options"), TransientDlg, BoardWindow, MODAL); } //---------------------------------------------- New Variant ------------------------------------------------ @@ -368,37 +380,37 @@ OptionsProc () static void Pick P((int n)); static Option variantDescriptors[] = { -{ VariantNormal, 0, 135, NULL, (void*) &Pick, "#FFFFFF", NULL, Button, N_("normal")}, -{ VariantFairy, 1, 135, NULL, (void*) &Pick, "#BFBFBF", NULL, Button, N_("fairy")}, -{ VariantFischeRandom, 0, 135, NULL, (void*) &Pick, "#FFFFFF", NULL, Button, N_("FRC")}, -{ VariantSChess, 1, 135, NULL, (void*) &Pick, "#FFBFBF", NULL, Button, N_("Seirawan")}, -{ VariantWildCastle, 0, 135, NULL, (void*) &Pick, "#FFFFFF", NULL, Button, N_("wild castle")}, -{ VariantSuper, 1, 135, NULL, (void*) &Pick, "#FFBFBF", NULL, Button, N_("Superchess")}, -{ VariantNoCastle, 0, 135, NULL, (void*) &Pick, "#FFFFFF", NULL, Button, N_("no castle")}, -{ VariantCrazyhouse, 1, 135, NULL, (void*) &Pick, "#FFBFBF", NULL, Button, N_("crazyhouse")}, -{ VariantKnightmate, 0, 135, NULL, (void*) &Pick, "#FFFFFF", NULL, Button, N_("knightmate")}, -{ VariantBughouse, 1, 135, NULL, (void*) &Pick, "#FFBFBF", NULL, Button, N_("bughouse")}, -{ VariantBerolina, 0, 135, NULL, (void*) &Pick, "#FFFFFF", NULL, Button, N_("berolina")}, -{ VariantShogi, 1, 135, NULL, (void*) &Pick, "#BFFFFF", NULL, Button, N_("shogi (9x9)")}, -{ VariantCylinder, 0, 135, NULL, (void*) &Pick, "#FFFFFF", NULL, Button, N_("cylinder")}, -{ VariantXiangqi, 1, 135, NULL, (void*) &Pick, "#BFFFFF", NULL, Button, N_("xiangqi (9x10)")}, -{ VariantShatranj, 0, 135, NULL, (void*) &Pick, "#FFFFFF", NULL, Button, N_("shatranj")}, -{ VariantCourier, 1, 135, NULL, (void*) &Pick, "#BFFFBF", NULL, Button, N_("courier (12x8)")}, -{ VariantMakruk, 0, 135, NULL, (void*) &Pick, "#FFFFFF", NULL, Button, N_("makruk")}, -{ VariantGreat, 1, 135, NULL, (void*) &Pick, "#BFBFFF", NULL, Button, N_("Great Shatranj (10x8)")}, -{ VariantAtomic, 0, 135, NULL, (void*) &Pick, "#FFFFFF", NULL, Button, N_("atomic")}, -{ VariantFalcon, 1, 135, NULL, (void*) &Pick, "#BFBFFF", NULL, Button, N_("falcon (10x8)")}, -{ VariantTwoKings, 0, 135, NULL, (void*) &Pick, "#FFFFFF", NULL, Button, N_("two kings")}, -{ VariantCapablanca, 1, 135, NULL, (void*) &Pick, "#BFBFFF", NULL, Button, N_("Capablanca (10x8)")}, -{ Variant3Check, 0, 135, NULL, (void*) &Pick, "#FFFFFF", NULL, Button, N_("3-checks")}, -{ VariantGothic, 1, 135, NULL, (void*) &Pick, "#BFBFFF", NULL, Button, N_("Gothic (10x8)")}, -{ VariantSuicide, 0, 135, NULL, (void*) &Pick, "#FFFFBF", NULL, Button, N_("suicide")}, -{ VariantJanus, 1, 135, NULL, (void*) &Pick, "#BFBFFF", NULL, Button, N_("janus (10x8)")}, -{ VariantGiveaway, 0, 135, NULL, (void*) &Pick, "#FFFFBF", NULL, Button, N_("give-away")}, -{ VariantCapaRandom, 1, 135, NULL, (void*) &Pick, "#BFBFFF", NULL, Button, N_("CRC (10x8)")}, -{ VariantLosers, 0, 135, NULL, (void*) &Pick, "#FFFFBF", NULL, Button, N_("losers")}, -{ VariantGrand, 1, 135, NULL, (void*) &Pick, "#5070FF", NULL, Button, N_("grand (10x10)")}, -{ VariantSpartan, 0, 135, NULL, (void*) &Pick, "#FF0000", NULL, Button, N_("Spartan")}, +{ VariantNormal, 0, 135, NULL, (void*) &Pick, "#FFFFFF", NULL, Button, N_("normal")}, +{ VariantFairy, SAME_ROW, 135, NULL, (void*) &Pick, "#BFBFBF", NULL, Button, N_("fairy")}, +{ VariantFischeRandom, 0, 135, NULL, (void*) &Pick, "#FFFFFF", NULL, Button, N_("FRC")}, +{ VariantSChess, SAME_ROW, 135, NULL, (void*) &Pick, "#FFBFBF", NULL, Button, N_("Seirawan")}, +{ VariantWildCastle, 0, 135, NULL, (void*) &Pick, "#FFFFFF", NULL, Button, N_("wild castle")}, +{ VariantSuper, SAME_ROW, 135, NULL, (void*) &Pick, "#FFBFBF", NULL, Button, N_("Superchess")}, +{ VariantNoCastle, 0, 135, NULL, (void*) &Pick, "#FFFFFF", NULL, Button, N_("no castle")}, +{ VariantCrazyhouse,SAME_ROW,135,NULL,(void*) &Pick, "#FFBFBF", NULL, Button, N_("crazyhouse")}, +{ VariantKnightmate, 0, 135, NULL, (void*) &Pick, "#FFFFFF", NULL, Button, N_("knightmate")}, +{ VariantBughouse,SAME_ROW,135, NULL, (void*) &Pick, "#FFBFBF", NULL, Button, N_("bughouse")}, +{ VariantBerolina, 0, 135, NULL, (void*) &Pick, "#FFFFFF", NULL, Button, N_("berolina")}, +{ VariantShogi, SAME_ROW, 135, NULL, (void*) &Pick, "#BFFFFF", NULL, Button, N_("shogi (9x9)")}, +{ VariantCylinder, 0, 135, NULL, (void*) &Pick, "#FFFFFF", NULL, Button, N_("cylinder")}, +{ VariantXiangqi, SAME_ROW,135, NULL, (void*) &Pick, "#BFFFFF", NULL, Button, N_("xiangqi (9x10)")}, +{ VariantShatranj, 0, 135, NULL, (void*) &Pick, "#FFFFFF", NULL, Button, N_("shatranj")}, +{ VariantCourier, SAME_ROW,135, NULL, (void*) &Pick, "#BFFFBF", NULL, Button, N_("courier (12x8)")}, +{ VariantMakruk, 0, 135, NULL, (void*) &Pick, "#FFFFFF", NULL, Button, N_("makruk")}, +{ VariantGreat, SAME_ROW, 135, NULL, (void*) &Pick, "#BFBFFF", NULL, Button, N_("Great Shatranj (10x8)")}, +{ VariantAtomic, 0, 135, NULL, (void*) &Pick, "#FFFFFF", NULL, Button, N_("atomic")}, +{ VariantFalcon, SAME_ROW, 135, NULL, (void*) &Pick, "#BFBFFF", NULL, Button, N_("falcon (10x8)")}, +{ VariantTwoKings, 0, 135, NULL, (void*) &Pick, "#FFFFFF", NULL, Button, N_("two kings")}, +{ VariantCapablanca,SAME_ROW,135,NULL,(void*) &Pick, "#BFBFFF", NULL, Button, N_("Capablanca (10x8)")}, +{ Variant3Check, 0, 135, NULL, (void*) &Pick, "#FFFFFF", NULL, Button, N_("3-checks")}, +{ VariantGothic, SAME_ROW, 135, NULL, (void*) &Pick, "#BFBFFF", NULL, Button, N_("Gothic (10x8)")}, +{ VariantSuicide, 0, 135, NULL, (void*) &Pick, "#FFFFBF", NULL, Button, N_("suicide")}, +{ VariantJanus, SAME_ROW, 135, NULL, (void*) &Pick, "#BFBFFF", NULL, Button, N_("janus (10x8)")}, +{ VariantGiveaway, 0, 135, NULL, (void*) &Pick, "#FFFFBF", NULL, Button, N_("give-away")}, +{ VariantCapaRandom,SAME_ROW,135,NULL,(void*) &Pick, "#BFBFFF", NULL, Button, N_("CRC (10x8)")}, +{ VariantLosers, 0, 135, NULL, (void*) &Pick, "#FFFFBF", NULL, Button, N_("losers")}, +{ VariantGrand, SAME_ROW, 135, NULL, (void*) &Pick, "#5070FF", NULL, Button, N_("grand (10x10)")}, +{ VariantSpartan, 0, 135, NULL, (void*) &Pick, "#FF0000", NULL, Button, N_("Spartan")}, { 0, 0, 0, NULL, NULL, NULL, NULL, Label, N_("Board size ( -1 = default for selected variant):")}, { 0, -1, BOARD_RANKS-1, NULL, (void*) &appData.NrRanks, "", NULL, Spin, N_("Number of Board Ranks:") }, { 0, -1, BOARD_FILES, NULL, (void*) &appData.NrFiles, "", NULL, Spin, N_("Number of Board Files:") }, @@ -409,7 +421,7 @@ static Option variantDescriptors[] = { "for -boardSize middling, bulky and\n" "petite, and substitute king or amazon\n" "for missing bitmaps. (See manual.)")}, -{ 0, 2, 0, NULL, NULL, "", NULL, EndMark , "" } +{ 0, NO_OK, 0, NULL, NULL, "", NULL, EndMark , "" } }; static void @@ -448,7 +460,7 @@ Pick (int n) void NewVariantProc () { - GenericPopUp(variantDescriptors, _("New Variant"), TransientDlg); + GenericPopUp(variantDescriptors, _("New Variant"), TransientDlg, BoardWindow, MODAL); } //------------------------------------------- Common Engine Options ------------------------------------- @@ -472,19 +484,19 @@ CommonOptionsOK (int n) } static Option commonEngineOptions[] = { -{ 0, 0, 0, NULL, (void*) &appData.ponderNextMove, "", NULL, CheckBox, N_("Ponder Next Move") }, +{ 0, 0, 0, NULL, (void*) &appData.ponderNextMove, "", NULL, CheckBox, N_("Ponder Next Move") }, { 0, 0, 1000, NULL, (void*) &appData.smpCores, "", NULL, Spin, N_("Maximum Number of CPUs per Engine:") }, -{ 0, 0, 0, NULL, (void*) &appData.polyglotDir, "", NULL, PathName, N_("Polygot Directory:") }, -{ 0, 0, 16000, NULL, (void*) &appData.defaultHashSize, "", NULL, Spin, N_("Hash-Table Size (MB):") }, -{ 0, 0, 0, NULL, (void*) &appData.defaultPathEGTB, "", NULL, PathName, N_("Nalimov EGTB Path:") }, +{ 0, 0, 0, NULL, (void*) &appData.polyglotDir, "", NULL, PathName, N_("Polygot Directory:") }, +{ 0, 0,16000, NULL, (void*) &appData.defaultHashSize, "", NULL, Spin, N_("Hash-Table Size (MB):") }, +{ 0, 0, 0, NULL, (void*) &appData.defaultPathEGTB, "", NULL, PathName, N_("Nalimov EGTB Path:") }, { 0, 0, 1000, NULL, (void*) &appData.defaultCacheSizeEGTB, "", NULL, Spin, N_("EGTB Cache Size (MB):") }, -{ 0, 0, 0, NULL, (void*) &appData.usePolyglotBook, "", NULL, CheckBox, N_("Use GUI Book") }, -{ 0, 0, 0, NULL, (void*) &appData.polyglotBook, ".bin", NULL, FileName, N_("Opening-Book Filename:") }, -{ 0, 0, 100, NULL, (void*) &appData.bookDepth, "", NULL, Spin, N_("Book Depth (moves):") }, -{ 0, 0, 100, NULL, (void*) &appData.bookStrength, "", NULL, Spin, N_("Book Variety (0) vs. Strength (100):") }, -{ 0, 0, 0, NULL, (void*) &appData.firstHasOwnBookUCI, "", NULL, CheckBox, N_("Engine #1 Has Own Book") }, -{ 0, 0, 0, NULL, (void*) &appData.secondHasOwnBookUCI, "", NULL, CheckBox, N_("Engine #2 Has Own Book ") }, -{ 0, 1, 0, NULL, (void*) &CommonOptionsOK, "", NULL, EndMark , "" } +{ 0, 0, 0, NULL, (void*) &appData.usePolyglotBook, "", NULL, CheckBox, N_("Use GUI Book") }, +{ 0, 0, 0, NULL, (void*) &appData.polyglotBook, ".bin", NULL, FileName, N_("Opening-Book Filename:") }, +{ 0, 0, 100, NULL, (void*) &appData.bookDepth, "", NULL, Spin, N_("Book Depth (moves):") }, +{ 0, 0, 100, NULL, (void*) &appData.bookStrength, "", NULL, Spin, N_("Book Variety (0) vs. Strength (100):") }, +{ 0, 0, 0, NULL, (void*) &appData.firstHasOwnBookUCI, "", NULL, CheckBox, N_("Engine #1 Has Own Book") }, +{ 0, 0, 0, NULL, (void*) &appData.secondHasOwnBookUCI, "", NULL, CheckBox, N_("Engine #2 Has Own Book ") }, +{ 0,SAME_ROW,0,NULL, (void*) &CommonOptionsOK, "", NULL, EndMark , "" } }; void @@ -492,7 +504,7 @@ UciMenuProc () { oldCores = appData.smpCores; oldPonder = appData.ponderNextMove; - GenericPopUp(commonEngineOptions, _("Common Engine Settings"), TransientDlg); + GenericPopUp(commonEngineOptions, _("Common Engine Settings"), TransientDlg, BoardWindow, MODAL); } //------------------------------------------ Adjudication Options -------------------------------------- @@ -502,19 +514,19 @@ static Option adjudicationOptions[] = { { 0, 0, 0, NULL, (void*) &appData.testClaims, "", NULL, CheckBox, N_("Verify Engine Result Claims") }, { 0, 0, 0, NULL, (void*) &appData.materialDraws, "", NULL, CheckBox, N_("Draw if Insufficient Mating Material") }, { 0, 0, 0, NULL, (void*) &appData.trivialDraws, "", NULL, CheckBox, N_("Adjudicate Trivial Draws (3-Move Delay)") }, -{ 0, 0, 100, NULL, (void*) &appData.ruleMoves, "", NULL, Spin, N_("N-Move Rule:") }, +{ 0, 0,100, NULL, (void*) &appData.ruleMoves, "", NULL, Spin, N_("N-Move Rule:") }, { 0, 0, 6, NULL, (void*) &appData.drawRepeats, "", NULL, Spin, N_("N-fold Repeats:") }, -{ 0, 0, 1000, NULL, (void*) &appData.adjudicateDrawMoves, "", NULL, Spin, N_("Draw after N Moves Total:") }, -{ 0,-5000, 0, NULL, (void*) &appData.adjudicateLossThreshold, "", NULL, Spin, N_("Win / Loss Threshold:") }, +{ 0, 0,1000, NULL, (void*) &appData.adjudicateDrawMoves, "", NULL, Spin, N_("Draw after N Moves Total:") }, +{ 0, -5000,0, NULL, (void*) &appData.adjudicateLossThreshold, "", NULL, Spin, N_("Win / Loss Threshold:") }, { 0, 0, 0, NULL, (void*) &first.scoreIsAbsolute, "", NULL, CheckBox, N_("Negate Score of Engine #1") }, { 0, 0, 0, NULL, (void*) &second.scoreIsAbsolute, "", NULL, CheckBox, N_("Negate Score of Engine #2") }, -{ 0, 1, 0, NULL, NULL, "", NULL, EndMark , "" } +{ 0,SAME_ROW, 0, NULL, NULL, "", NULL, EndMark , "" } }; void EngineMenuProc () { - GenericPopUp(adjudicationOptions, _("Adjudicate non-ICS Games"), TransientDlg); + GenericPopUp(adjudicationOptions, _("Adjudicate non-ICS Games"), TransientDlg, BoardWindow, MODAL); } //--------------------------------------------- ICS Options --------------------------------------------- @@ -542,7 +554,7 @@ Option icsOptions[] = { { 0, 0, 0, NULL, (void*) &appData.premoveWhiteText, "", NULL, TextBox, N_("First White Move:") }, { 0, 0, 0, NULL, (void*) &appData.premoveBlack, "", NULL, CheckBox, N_("Premove for Black") }, { 0, 0, 0, NULL, (void*) &appData.premoveBlackText, "", NULL, TextBox, N_("First Black Move:") }, -{ 0, 0, 0, NULL, NULL, NULL, NULL, Break, "" }, +{ 0, SAME_ROW, 0, NULL, NULL, NULL, NULL, Break, "" }, { 0, 0, 0, NULL, (void*) &appData.icsAlarm, "", NULL, CheckBox, N_("Alarm") }, { 0, 0, 100000000, NULL, (void*) &appData.icsAlarmTime, "", NULL, Spin, N_("Alarm Time (msec):") }, //{ 0, 0, 0, NULL, (void*) &appData.chatBoxes, "", NULL, TextBox, N_("Startup Chat Boxes:") }, @@ -562,7 +574,7 @@ Option icsOptions[] = { void IcsOptionsProc () { - GenericPopUp(icsOptions, _("ICS Options"), TransientDlg); + GenericPopUp(icsOptions, _("ICS Options"), TransientDlg, BoardWindow, MODAL); } //-------------------------------------------- Load Game Options --------------------------------- @@ -580,28 +592,28 @@ LoadOptionsOK () } static Option loadOptions[] = { -{ 0, 0, 0, NULL, (void*) &appData.autoDisplayTags, "", NULL, CheckBox, N_("Auto-Display Tags") }, -{ 0, 0, 0, NULL, (void*) &appData.autoDisplayComment, "", NULL, CheckBox, N_("Auto-Display Comment") }, -{ 0, 0, 0, NULL, NULL, NULL, NULL, Label, N_("Auto-Play speed of loaded games\n(0 = instant, -1 = off):") }, -{ 0, -1, 10000000, NULL, (void*) &appData.timeDelay, "", NULL, Fractional, N_("Seconds per Move:") }, -{ 0, 0, 0, NULL, NULL, NULL, NULL, Label, N_("\noptions to use in game-viewer mode:") }, -{ 0, 0, 300, NULL, (void*) &appData.viewerOptions, "", NULL, TextBox, "" }, -{ 0, 0, 0, NULL, NULL, NULL, NULL, Label, N_("\nThresholds for position filtering in game list:") }, -{ 0, 0, 5000, NULL, (void*) &appData.eloThreshold1, "", NULL, Spin, N_("Elo of strongest player at least:") }, -{ 0, 0, 5000, NULL, (void*) &appData.eloThreshold2, "", NULL, Spin, N_("Elo of weakest player at least:") }, -{ 0, 0, 5000, NULL, (void*) &appData.dateThreshold, "", NULL, Spin, N_("No games before year:") }, -{ 0, 1, 50, NULL, (void*) &appData.stretch, "", NULL, Spin, N_("Minimum nr consecutive positions:") }, -{ 1, 0, 180, NULL, (void*) &searchMode, (char*) modeNames, modeValues, ComboBox, N_("Search mode:") }, -{ 0, 0, 0, NULL, (void*) &appData.ignoreColors, "", NULL, CheckBox, N_("Also match reversed colors") }, -{ 0, 0, 0, NULL, (void*) &appData.findMirror, "", NULL, CheckBox, N_("Also match left-right flipped position") }, -{ 0, 0, 0, NULL, (void*) &LoadOptionsOK, "", NULL, EndMark , "" } +{ 0, 0, 0, NULL, (void*) &appData.autoDisplayTags, "", NULL, CheckBox, N_("Auto-Display Tags") }, +{ 0, 0, 0, NULL, (void*) &appData.autoDisplayComment, "", NULL, CheckBox, N_("Auto-Display Comment") }, +{ 0, LR, 0, NULL, NULL, NULL, NULL, Label, N_("Auto-Play speed of loaded games\n(0 = instant, -1 = off):") }, +{ 0, -1,10000000, NULL, (void*) &appData.timeDelay, "", NULL, Fractional, N_("Seconds per Move:") }, +{ 0, LR, 0, NULL, NULL, NULL, NULL, Label, N_("\noptions to use in game-viewer mode:") }, +{ 0, 0,300, NULL, (void*) &appData.viewerOptions, "", NULL, TextBox, "" }, +{ 0, LR, 0, NULL, NULL, NULL, NULL, Label, N_("\nThresholds for position filtering in game list:") }, +{ 0, 0,5000, NULL, (void*) &appData.eloThreshold1, "", NULL, Spin, N_("Elo of strongest player at least:") }, +{ 0, 0,5000, NULL, (void*) &appData.eloThreshold2, "", NULL, Spin, N_("Elo of weakest player at least:") }, +{ 0, 0,5000, NULL, (void*) &appData.dateThreshold, "", NULL, Spin, N_("No games before year:") }, +{ 0, 1,50, NULL, (void*) &appData.stretch, "", NULL, Spin, N_("Minimum nr consecutive positions:") }, +{ 0, 0,205, NULL, (void*) &searchMode, (char*) modeValues, modeNames, ComboBox, N_("Search mode:") }, +{ 0, 0, 0, NULL, (void*) &appData.ignoreColors, "", NULL, CheckBox, N_("Also match reversed colors") }, +{ 0, 0, 0, NULL, (void*) &appData.findMirror, "", NULL, CheckBox, N_("Also match left-right flipped position") }, +{ 0, 0, 0, NULL, (void*) &LoadOptionsOK, "", NULL, EndMark , "" } }; void LoadOptionsProc () { ASSIGN(searchMode, modeValues[appData.searchMode-1]); - GenericPopUp(loadOptions, _("Load Game Options"), TransientDlg); + GenericPopUp(loadOptions, _("Load Game Options"), TransientDlg, BoardWindow, MODAL); } //------------------------------------------- Save Game Options -------------------------------------------- @@ -615,13 +627,13 @@ static Option saveOptions[] = { { 0, 0, 0, NULL, (void*) &appData.numberTag, "", NULL, CheckBox, N_("Include Number Tag in tourney PGN") }, { 0, 0, 0, NULL, (void*) &appData.saveExtendedInfoInPGN, "", NULL, CheckBox, N_("Save Score/Depth Info in PGN") }, { 0, 0, 0, NULL, (void*) &appData.saveOutOfBookInfo, "", NULL, CheckBox, N_("Save Out-of-Book Info in PGN ") }, -{ 0, 1, 0, NULL, NULL, "", NULL, EndMark , "" } +{ 0, SAME_ROW, 0, NULL, NULL, "", NULL, EndMark , "" } }; void SaveOptionsProc () { - GenericPopUp(saveOptions, _("Save Game Options"), TransientDlg); + GenericPopUp(saveOptions, _("Save Game Options"), TransientDlg, BoardWindow, MODAL); } //----------------------------------------------- Sound Options --------------------------------------------- @@ -669,24 +681,24 @@ static Option soundOptions[] = { { 0, 0, 0, NULL, (void*) &appData.soundProgram, "", NULL, TextBox, N_("Sound Program:") }, { 0, 0, 0, NULL, (void*) &appData.soundDirectory, "", NULL, PathName, N_("Sounds Directory:") }, { 0, 0, 0, NULL, (void*) (soundFiles+2) /* kludge! */, ".wav", NULL, FileName, N_("User WAV File:") }, -{ 0, 0, 0, NULL, (void*) &trialSound, (char*) soundNames, soundFiles, ComboBox, N_("Try-Out Sound:") }, -{ 0, 1, 0, NULL, (void*) &Test, NULL, NULL, Button, N_("Play") }, -{ 0, 0, 0, NULL, (void*) &appData.soundMove, (char*) soundNames, soundFiles, ComboBox, N_("Move:") }, -{ 0, 0, 0, NULL, (void*) &appData.soundIcsWin, (char*) soundNames, soundFiles, ComboBox, N_("Win:") }, -{ 0, 0, 0, NULL, (void*) &appData.soundIcsLoss, (char*) soundNames, soundFiles, ComboBox, N_("Lose:") }, -{ 0, 0, 0, NULL, (void*) &appData.soundIcsDraw, (char*) soundNames, soundFiles, ComboBox, N_("Draw:") }, -{ 0, 0, 0, NULL, (void*) &appData.soundIcsUnfinished, (char*) soundNames, soundFiles, ComboBox, N_("Unfinished:") }, -{ 0, 0, 0, NULL, (void*) &appData.soundIcsAlarm, (char*) soundNames, soundFiles, ComboBox, N_("Alarm:") }, -{ 0, 0, 0, NULL, (void*) &appData.soundShout, (char*) soundNames, soundFiles, ComboBox, N_("Shout:") }, -{ 0, 0, 0, NULL, (void*) &appData.soundSShout, (char*) soundNames, soundFiles, ComboBox, N_("S-Shout:") }, -{ 0, 0, 0, NULL, (void*) &appData.soundChannel, (char*) soundNames, soundFiles, ComboBox, N_("Channel:") }, -{ 0, 0, 0, NULL, (void*) &appData.soundChannel1, (char*) soundNames, soundFiles, ComboBox, N_("Channel 1:") }, -{ 0, 0, 0, NULL, (void*) &appData.soundTell, (char*) soundNames, soundFiles, ComboBox, N_("Tell:") }, -{ 0, 0, 0, NULL, (void*) &appData.soundKibitz, (char*) soundNames, soundFiles, ComboBox, N_("Kibitz:") }, -{ 0, 0, 0, NULL, (void*) &appData.soundChallenge, (char*) soundNames, soundFiles, ComboBox, N_("Challenge:") }, -{ 0, 0, 0, NULL, (void*) &appData.soundRequest, (char*) soundNames, soundFiles, ComboBox, N_("Request:") }, -{ 0, 0, 0, NULL, (void*) &appData.soundSeek, (char*) soundNames, soundFiles, ComboBox, N_("Seek:") }, -{ 0, 1, 0, NULL, NULL, "", NULL, EndMark , "" } +{ 0, 0, 0, NULL, (void*) &trialSound, (char*) soundFiles, soundNames, ComboBox, N_("Try-Out Sound:") }, +{ 0, SAME_ROW, 0, NULL, (void*) &Test, NULL, NULL, Button, N_("Play") }, +{ 0, 0, 0, NULL, (void*) &appData.soundMove, (char*) soundFiles, soundNames, ComboBox, N_("Move:") }, +{ 0, 0, 0, NULL, (void*) &appData.soundIcsWin, (char*) soundFiles, soundNames, ComboBox, N_("Win:") }, +{ 0, 0, 0, NULL, (void*) &appData.soundIcsLoss, (char*) soundFiles, soundNames, ComboBox, N_("Lose:") }, +{ 0, 0, 0, NULL, (void*) &appData.soundIcsDraw, (char*) soundFiles, soundNames, ComboBox, N_("Draw:") }, +{ 0, 0, 0, NULL, (void*) &appData.soundIcsUnfinished, (char*) soundFiles, soundNames, ComboBox, N_("Unfinished:") }, +{ 0, 0, 0, NULL, (void*) &appData.soundIcsAlarm, (char*) soundFiles, soundNames, ComboBox, N_("Alarm:") }, +{ 0, 0, 0, NULL, (void*) &appData.soundShout, (char*) soundFiles, soundNames, ComboBox, N_("Shout:") }, +{ 0, 0, 0, NULL, (void*) &appData.soundSShout, (char*) soundFiles, soundNames, ComboBox, N_("S-Shout:") }, +{ 0, 0, 0, NULL, (void*) &appData.soundChannel, (char*) soundFiles, soundNames, ComboBox, N_("Channel:") }, +{ 0, 0, 0, NULL, (void*) &appData.soundChannel1, (char*) soundFiles, soundNames, ComboBox, N_("Channel 1:") }, +{ 0, 0, 0, NULL, (void*) &appData.soundTell, (char*) soundFiles, soundNames, ComboBox, N_("Tell:") }, +{ 0, 0, 0, NULL, (void*) &appData.soundKibitz, (char*) soundFiles, soundNames, ComboBox, N_("Kibitz:") }, +{ 0, 0, 0, NULL, (void*) &appData.soundChallenge, (char*) soundFiles, soundNames, ComboBox, N_("Challenge:") }, +{ 0, 0, 0, NULL, (void*) &appData.soundRequest, (char*) soundFiles, soundNames, ComboBox, N_("Request:") }, +{ 0, 0, 0, NULL, (void*) &appData.soundSeek, (char*) soundFiles, soundNames, ComboBox, N_("Seek:") }, +{ 0, SAME_ROW, 0, NULL, NULL, "", NULL, EndMark , "" } }; static void @@ -701,7 +713,7 @@ SoundOptionsProc () { free(soundFiles[2]); soundFiles[2] = strdup("*"); - GenericPopUp(soundOptions, _("Sound Options"), TransientDlg); + GenericPopUp(soundOptions, _("Sound Options"), TransientDlg, BoardWindow, MODAL); } //--------------------------------------------- Board Options -------------------------------------- @@ -721,46 +733,46 @@ BoardOptionsOK (int n) } static Option boardOptions[] = { -{ 0, 0, 70, NULL, (void*) &appData.whitePieceColor, "", NULL, TextBox, N_("White Piece Color:") }, -{ 1000, 1, 0, NULL, (void*) &DefColor, NULL, (char**) "#FFFFCC", Button, " " }, +{ 0, 0, 70, NULL, (void*) &appData.whitePieceColor, "", NULL, TextBox, N_("White Piece Color:") }, +{ 1000, SAME_ROW, 0, NULL, (void*) &DefColor, NULL, (char**) "#FFFFCC", Button, " " }, /* TRANSLATORS: R = single letter for the color red */ -{ 1, 1, 0, NULL, (void*) &AdjustColor, NULL, NULL, Button, N_("R") }, +{ 1, SAME_ROW, 0, NULL, (void*) &AdjustColor, NULL, NULL, Button, N_("R") }, /* TRANSLATORS: G = single letter for the color green */ -{ 2, 1, 0, NULL, (void*) &AdjustColor, NULL, NULL, Button, N_("G") }, +{ 2, SAME_ROW, 0, NULL, (void*) &AdjustColor, NULL, NULL, Button, N_("G") }, /* TRANSLATORS: B = single letter for the color blue */ -{ 3, 1, 0, NULL, (void*) &AdjustColor, NULL, NULL, Button, N_("B") }, +{ 3, SAME_ROW, 0, NULL, (void*) &AdjustColor, NULL, NULL, Button, N_("B") }, /* TRANSLATORS: D = single letter to make a color darker */ -{ 4, 1, 0, NULL, (void*) &AdjustColor, NULL, NULL, Button, N_("D") }, -{ 0, 0, 70, NULL, (void*) &appData.blackPieceColor, "", NULL, TextBox, N_("Black Piece Color:") }, -{ 1000, 1, 0, NULL, (void*) &DefColor, NULL, (char**) "#202020", Button, " " }, -{ 1, 1, 0, NULL, (void*) &AdjustColor, NULL, NULL, Button, N_("R") }, -{ 2, 1, 0, NULL, (void*) &AdjustColor, NULL, NULL, Button, N_("G") }, -{ 3, 1, 0, NULL, (void*) &AdjustColor, NULL, NULL, Button, N_("B") }, -{ 4, 1, 0, NULL, (void*) &AdjustColor, NULL, NULL, Button, N_("D") }, -{ 0, 0, 70, NULL, (void*) &appData.lightSquareColor, "", NULL, TextBox, N_("Light Square Color:") }, -{ 1000, 1, 0, NULL, (void*) &DefColor, NULL, (char**) "#C8C365", Button, " " }, -{ 1, 1, 0, NULL, (void*) &AdjustColor, NULL, NULL, Button, N_("R") }, -{ 2, 1, 0, NULL, (void*) &AdjustColor, NULL, NULL, Button, N_("G") }, -{ 3, 1, 0, NULL, (void*) &AdjustColor, NULL, NULL, Button, N_("B") }, -{ 4, 1, 0, NULL, (void*) &AdjustColor, NULL, NULL, Button, N_("D") }, -{ 0, 0, 70, NULL, (void*) &appData.darkSquareColor, "", NULL, TextBox, N_("Dark Square Color:") }, -{ 1000, 1, 0, NULL, (void*) &DefColor, NULL, (char**) "#77A26D", Button, " " }, -{ 1, 1, 0, NULL, (void*) &AdjustColor, NULL, NULL, Button, N_("R") }, -{ 2, 1, 0, NULL, (void*) &AdjustColor, NULL, NULL, Button, N_("G") }, -{ 3, 1, 0, NULL, (void*) &AdjustColor, NULL, NULL, Button, N_("B") }, -{ 4, 1, 0, NULL, (void*) &AdjustColor, NULL, NULL, Button, N_("D") }, -{ 0, 0, 70, NULL, (void*) &appData.highlightSquareColor, "", NULL, TextBox, N_("Highlight Color:") }, -{ 1000, 1, 0, NULL, (void*) &DefColor, NULL, (char**) "#FFFF00", Button, " " }, -{ 1, 1, 0, NULL, (void*) &AdjustColor, NULL, NULL, Button, N_("R") }, -{ 2, 1, 0, NULL, (void*) &AdjustColor, NULL, NULL, Button, N_("G") }, -{ 3, 1, 0, NULL, (void*) &AdjustColor, NULL, NULL, Button, N_("B") }, -{ 4, 1, 0, NULL, (void*) &AdjustColor, NULL, NULL, Button, N_("D") }, -{ 0, 0, 70, NULL, (void*) &appData.premoveHighlightColor, "", NULL, TextBox, N_("Premove Highlight Color:") }, -{ 1000, 1, 0, NULL, (void*) &DefColor, NULL, (char**) "#FF0000", Button, " " }, -{ 1, 1, 0, NULL, (void*) &AdjustColor, NULL, NULL, Button, N_("R") }, -{ 2, 1, 0, NULL, (void*) &AdjustColor, NULL, NULL, Button, N_("G") }, -{ 3, 1, 0, NULL, (void*) &AdjustColor, NULL, NULL, Button, N_("B") }, -{ 4, 1, 0, NULL, (void*) &AdjustColor, NULL, NULL, Button, N_("D") }, +{ 4, SAME_ROW, 0, NULL, (void*) &AdjustColor, NULL, NULL, Button, N_("D") }, +{ 0, 0, 70, NULL, (void*) &appData.blackPieceColor, "", NULL, TextBox, N_("Black Piece Color:") }, +{ 1000, SAME_ROW, 0, NULL, (void*) &DefColor, NULL, (char**) "#202020", Button, " " }, +{ 1, SAME_ROW, 0, NULL, (void*) &AdjustColor, NULL, NULL, Button, N_("R") }, +{ 2, SAME_ROW, 0, NULL, (void*) &AdjustColor, NULL, NULL, Button, N_("G") }, +{ 3, SAME_ROW, 0, NULL, (void*) &AdjustColor, NULL, NULL, Button, N_("B") }, +{ 4, SAME_ROW, 0, NULL, (void*) &AdjustColor, NULL, NULL, Button, N_("D") }, +{ 0, 0, 70, NULL, (void*) &appData.lightSquareColor, "", NULL, TextBox, N_("Light Square Color:") }, +{ 1000, SAME_ROW, 0, NULL, (void*) &DefColor, NULL, (char**) "#C8C365", Button, " " }, +{ 1, SAME_ROW, 0, NULL, (void*) &AdjustColor, NULL, NULL, Button, N_("R") }, +{ 2, SAME_ROW, 0, NULL, (void*) &AdjustColor, NULL, NULL, Button, N_("G") }, +{ 3, SAME_ROW, 0, NULL, (void*) &AdjustColor, NULL, NULL, Button, N_("B") }, +{ 4, SAME_ROW, 0, NULL, (void*) &AdjustColor, NULL, NULL, Button, N_("D") }, +{ 0, 0, 70, NULL, (void*) &appData.darkSquareColor, "", NULL, TextBox, N_("Dark Square Color:") }, +{ 1000, SAME_ROW, 0, NULL, (void*) &DefColor, NULL, (char**) "#77A26D", Button, " " }, +{ 1, SAME_ROW, 0, NULL, (void*) &AdjustColor, NULL, NULL, Button, N_("R") }, +{ 2, SAME_ROW, 0, NULL, (void*) &AdjustColor, NULL, NULL, Button, N_("G") }, +{ 3, SAME_ROW, 0, NULL, (void*) &AdjustColor, NULL, NULL, Button, N_("B") }, +{ 4, SAME_ROW, 0, NULL, (void*) &AdjustColor, NULL, NULL, Button, N_("D") }, +{ 0, 0, 70, NULL, (void*) &appData.highlightSquareColor, "", NULL, TextBox, N_("Highlight Color:") }, +{ 1000, SAME_ROW, 0, NULL, (void*) &DefColor, NULL, (char**) "#FFFF00", Button, " " }, +{ 1, SAME_ROW, 0, NULL, (void*) &AdjustColor, NULL, NULL, Button, N_("R") }, +{ 2, SAME_ROW, 0, NULL, (void*) &AdjustColor, NULL, NULL, Button, N_("G") }, +{ 3, SAME_ROW, 0, NULL, (void*) &AdjustColor, NULL, NULL, Button, N_("B") }, +{ 4, SAME_ROW, 0, NULL, (void*) &AdjustColor, NULL, NULL, Button, N_("D") }, +{ 0, 0, 70, NULL, (void*) &appData.premoveHighlightColor, "", NULL, TextBox, N_("Premove Highlight Color:") }, +{ 1000, SAME_ROW, 0, NULL, (void*) &DefColor, NULL, (char**) "#FF0000", Button, " " }, +{ 1, SAME_ROW, 0, NULL, (void*) &AdjustColor, NULL, NULL, Button, N_("R") }, +{ 2, SAME_ROW, 0, NULL, (void*) &AdjustColor, NULL, NULL, Button, N_("G") }, +{ 3, SAME_ROW, 0, NULL, (void*) &AdjustColor, NULL, NULL, Button, N_("B") }, +{ 4, SAME_ROW, 0, NULL, (void*) &AdjustColor, NULL, NULL, Button, N_("D") }, { 0, 0, 0, NULL, (void*) &appData.upsideDown, "", NULL, CheckBox, N_("Flip Pieces Shogi Style (Colored buttons restore default)") }, //{ 0, 0, 0, NULL, (void*) &appData.allWhite, "", NULL, CheckBox, N_("Use Outline Pieces for Black") }, { 0, 0, 0, NULL, (void*) &appData.monoMode, "", NULL, CheckBox, N_("Mono Mode") }, @@ -818,7 +830,7 @@ AdjustColor (int i) void BoardOptionsProc () { - GenericPopUp(boardOptions, _("Board Options"), TransientDlg); + GenericPopUp(boardOptions, _("Board Options"), TransientDlg, BoardWindow, MODAL); } //-------------------------------------------- ICS Text Menu Options ------------------------------ @@ -870,7 +882,7 @@ IcsTextProc () textOptions[i].target = NULL; textOptions[i].min = 2; MarkMenu("ICStex", TextMenuDlg); - GenericPopUp(textOptions, _("ICS text menu"), TextMenuDlg); + GenericPopUp(textOptions, _("ICS text menu"), TextMenuDlg, BoardWindow, NONMODAL); } //---------------------------------------------------- Edit Comment ----------------------------------- @@ -888,10 +900,10 @@ NewComCallback (int n) } Option commentOptions[] = { -{ 0xD, 200, 250, NULL, (void*) &commentText, "", NULL, TextBox, "" }, -{ 0, 0, 50, NULL, (void*) &ClearComment, NULL, NULL, Button, N_("clear") }, -{ 0, 1, 100, NULL, (void*) &SaveChanges, NULL, NULL, Button, N_("save changes") }, -{ 0, 1, 0, NULL, (void*) &NewComCallback, "", NULL, EndMark , "" } +{ 200, T_VSCRL | T_FILL | T_WRAP | T_TOP, 250, NULL, (void*) &commentText, "", NULL, TextBox, "" }, +{ 0, 0, 50, NULL, (void*) &ClearComment, NULL, NULL, Button, N_("clear") }, +{ 0, SAME_ROW, 100, NULL, (void*) &SaveChanges, NULL, NULL, Button, N_("save changes") }, +{ 0, SAME_ROW, 0, NULL, (void*) &NewComCallback, "", NULL, EndMark , "" } }; static void @@ -917,7 +929,7 @@ NewCommentPopup (char *title, char *text, int index) if(commentText) free(commentText); commentText = strdup(text); commentIndex = index; MarkMenu("Show Comments", CommentDlg); - if(GenericPopUp(commentOptions, title, CommentDlg)) + if(GenericPopUp(commentOptions, title, CommentDlg, BoardWindow, NONMODAL)) AddHandler(&commentOptions[0], 1); } @@ -945,10 +957,10 @@ NewTagsCallback (int n) } static Option tagsOptions[] = { -{ 0, 0, 0, NULL, NULL, NULL, NULL, Label, "" }, -{ 0xD, 200, 200, NULL, (void*) &tagsText, "", NULL, TextBox, "" }, -{ 0, 0, 100, NULL, (void*) &changeTags, NULL, NULL, Button, N_("save changes") }, -{ 0, 1, 0, NULL, (void*) &NewTagsCallback, "", NULL, EndMark , "" } +{ 0, 0, 0, NULL, NULL, NULL, NULL, Label, NULL }, +{ 200, T_VSCRL | T_FILL | T_WRAP | T_TOP, 200, NULL, (void*) &tagsText, "", NULL, TextBox, "" }, +{ 0, 0, 100, NULL, (void*) &changeTags, NULL, NULL, Button, N_("save changes") }, +{ 0,SAME_ROW, 0, NULL, (void*) &NewTagsCallback, "", NULL, EndMark , "" } }; static void @@ -969,9 +981,9 @@ NewTagsPopup (char *text, char *msg) SetDialogTitle(TagsDlg, title); } if(tagsText) free(tagsText); tagsText = strdup(text); - tagsOptions[0].textValue = msg; + tagsOptions[0].name = msg; MarkMenu("Show Tags", TagsDlg); - GenericPopUp(tagsOptions, title, TagsDlg); + GenericPopUp(tagsOptions, title, TagsDlg, BoardWindow, NONMODAL); } //---------------------------------------------- ICS Input Box ---------------------------------- @@ -1023,6 +1035,11 @@ NextInHistory () } // end of borrowed code +Option boxOptions[] = { +{ 30, 0, 400, NULL, (void*) &icsText, "", NULL, TextBox, "" }, +{ 0,SAME_ROW | NO_OK, 0, NULL, NULL, "", NULL, EndMark , "" } +}; + void ICSInputSendText () { @@ -1054,11 +1071,6 @@ IcsKey (int n) SetWidgetText(&boxOptions[0], val ? val : "", InputBoxDlg); } -Option boxOptions[] = { -{ 0, 30, 400, NULL, (void*) &icsText, "", NULL, TextBox, "" }, -{ 0, 3, 0, NULL, NULL, "", NULL, EndMark , "" } -}; - static void PutText (char *text, int pos) { @@ -1077,7 +1089,7 @@ void ICSInputBoxPopUp () { MarkMenu("ICS Input Box", InputBoxDlg); - if(GenericPopUp(boxOptions, _("ICS input box"), InputBoxDlg)) + if(GenericPopUp(boxOptions, _("ICS input box"), InputBoxDlg, BoardWindow, NONMODAL)) AddHandler(&boxOptions[0], 3); } @@ -1089,13 +1101,27 @@ IcsInputBoxProc () //--------------------------------------------- Move Type In ------------------------------------------ +static int TypeInOK P((int n)); + +Option typeOptions[] = { +{ 30, 0, 400, NULL, (void*) &icsText, "", NULL, TextBox, "" }, +{ 0, SAME_ROW | NO_OK, 0, NULL, (void*) &TypeInOK, "", NULL, EndMark , "" } +}; + +static int +TypeInOK (int n) +{ + TypeInDoneEvent(icsText); + return TRUE; +} + void PopUpMoveDialog (char firstchar) { static char buf[2]; - buf[0] = firstchar; icsText = buf; - if(GenericPopUp(boxOptions, _("Type a move"), TransientDlg)) - AddHandler(&boxOptions[0], 2); + buf[0] = firstchar; ASSIGN(icsText, buf); + if(GenericPopUp(typeOptions, _("Type a move"), TransientDlg, BoardWindow, MODAL)) + AddHandler(&typeOptions[0], 2); } void @@ -1119,7 +1145,7 @@ void SettingsPopUp (ChessProgramState *cps) { currentCps = cps; - GenericPopUp(cps->option, _("Engine Settings"), TransientDlg); + GenericPopUp(cps->option, _("Engine Settings"), TransientDlg, BoardWindow, MODAL); } void @@ -1150,20 +1176,20 @@ InstallOK (int n) } static Option installOptions[] = { -{ 0, NO_GETTEXT, 0, NULL, (void*) &engineLine, (char*) engineMnemonic, engineList, ComboBox, N_("Select engine from list:") }, -{ 0, 0, 0, NULL, NULL, NULL, NULL, Label, N_("or specify one below:") }, +{ 0, NO_GETTEXT, 0, NULL, (void*) &engineLine, (char*) engineList, engineMnemonic, ComboBox, N_("Select engine from list:") }, +{ 0, LR, 0, NULL, NULL, NULL, NULL, Label, N_("or specify one below:") }, { 0, 0, 0, NULL, (void*) &nickName, NULL, NULL, TextBox, N_("Nickname (optional):") }, { 0, 0, 0, NULL, (void*) &useNick, NULL, NULL, CheckBox, N_("Use nickname in PGN player tags of engine-engine games") }, { 0, 0, 0, NULL, (void*) &engineDir, NULL, NULL, PathName, N_("Engine Directory:") }, { 0, 0, 0, NULL, (void*) &engineName, NULL, NULL, FileName, N_("Engine Command:") }, -{ 0, 0, 0, NULL, NULL, NULL, NULL, Label, N_("(Directory will be derived from engine path when empty)") }, +{ 0, LR, 0, NULL, NULL, NULL, NULL, Label, N_("(Directory will be derived from engine path when empty)") }, { 0, 0, 0, NULL, (void*) &isUCI, NULL, NULL, CheckBox, N_("UCI") }, { 0, 0, 0, NULL, (void*) &v1, NULL, NULL, CheckBox, N_("WB protocol v1 (do not wait for engine features)") }, { 0, 0, 0, NULL, (void*) &hasBook, NULL, NULL, CheckBox, N_("Must not use GUI book") }, { 0, 0, 0, NULL, (void*) &addToList, NULL, NULL, CheckBox, N_("Add this engine to the list") }, { 0, 0, 0, NULL, (void*) &storeVariant, NULL, NULL, CheckBox, N_("Force current variant with this engine") }, { 0, 0, 0, NULL, (void*) &engineChoice, (char*) engineNr, engineNr, ComboBox, N_("Load mentioned engine as") }, -{ 0, 1, 0, NULL, (void*) &InstallOK, "", NULL, EndMark , "" } +{ 0,SAME_ROW, 0, NULL, (void*) &InstallOK, "", NULL, EndMark , "" } }; void @@ -1176,7 +1202,7 @@ LoadEngineProc () if(nickName) free(nickName); nickName = strdup(""); if(params) free(params); params = strdup(""); NamesToList(firstChessProgramNames, engineList, engineMnemonic, "all"); - GenericPopUp(installOptions, _("Load engine"), TransientDlg); + GenericPopUp(installOptions, _("Load engine"), TransientDlg, BoardWindow, MODAL); } //----------------------------------------------------- Edit Book ----------------------------------------- @@ -1202,8 +1228,8 @@ static Option shuffleOptions[] = { { 0, 0, 50, NULL, (void*) &shuffleOpenings, NULL, NULL, CheckBox, N_("shuffle") }, { 0,-1,2000000000, NULL, (void*) &appData.defaultFrcPosition, "", NULL, Spin, N_("Start-position number:") }, { 0, 0, 0, NULL, (void*) &SetRandom, NULL, NULL, Button, N_("randomize") }, - { 0, 1, 0, NULL, (void*) &SetRandom, NULL, NULL, Button, N_("pick fixed") }, - { 0, 1, 0, NULL, (void*) &ShuffleOK, "", NULL, EndMark , "" } + { 0, SAME_ROW, 0, NULL, (void*) &SetRandom, NULL, NULL, Button, N_("pick fixed") }, + { 0,SAME_ROW, 0, NULL, (void*) &ShuffleOK, "", NULL, EndMark , "" } }; static void @@ -1219,7 +1245,7 @@ SetRandom (int n) void ShuffleMenuProc () { - GenericPopUp(shuffleOptions, _("New Shuffle Game"), TransientDlg); + GenericPopUp(shuffleOptions, _("New Shuffle Game"), TransientDlg, BoardWindow, MODAL); } //------------------------------------------------------ Time Control ----------------------------------- @@ -1244,11 +1270,11 @@ Value (int n) static Option tcOptions[] = { { 0, 0, 0, NULL, (void*) &SetTcType, NULL, NULL, Button, N_("classical") }, -{ 0, 1, 0, NULL, (void*) &SetTcType, NULL, NULL, Button, N_("incremental") }, -{ 0, 1, 0, NULL, (void*) &SetTcType, NULL, NULL, Button, N_("fixed max") }, +{ 0,SAME_ROW,0,NULL, (void*) &SetTcType, NULL, NULL, Button, N_("incremental") }, +{ 0,SAME_ROW,0,NULL, (void*) &SetTcType, NULL, NULL, Button, N_("fixed max") }, { 0, 0, 200, NULL, (void*) &tmpMoves, NULL, NULL, Spin, N_("Moves per session:") }, -{ 0, 0,10000, NULL, (void*) &tmpTc, NULL, NULL, Spin, N_("Initial time (min):") }, -{ 0, 0, 10000, NULL, (void*) &tmpInc, NULL, NULL, Spin, N_("Increment or max (sec/move):") }, +{ 0, 0,10000, NULL, (void*) &tmpTc, NULL, NULL, Spin, N_("Initial time (min):") }, +{ 0, 0, 10000, NULL, (void*) &tmpInc, NULL, NULL, Spin, N_("Increment or max (sec/move):") }, { 0, 0, 0, NULL, NULL, NULL, NULL, Label, N_("Time-Odds factors:") }, { 0, 1, 1000, NULL, (void*) &tmpOdds1, NULL, NULL, Spin, N_("Engine #1") }, { 0, 1, 1000, NULL, (void*) &tmpOdds2, NULL, NULL, Spin, N_("Engine #2 / Human") }, @@ -1312,7 +1338,7 @@ TimeControlProc () tmpInc = appData.timeIncrement; if(tmpInc < 0) tmpInc = 0; tmpOdds1 = tmpOdds2 = 1; tcType = 0; tmpTc = atoi(appData.timeControl); - GenericPopUp(tcOptions, _("Time Control"), TransientDlg); + GenericPopUp(tcOptions, _("Time Control"), TransientDlg, BoardWindow, MODAL); } //---------------------------- Chat Windows ---------------------------------------------- diff --git a/dialogs.h b/dialogs.h index d7d763f..810bf7d 100644 --- a/dialogs.h +++ b/dialogs.h @@ -20,10 +20,76 @@ *------------------------------------------------------------------------ ** See the file ChangeLog for a revision history. */ -typedef enum { -TransientDlg=0, CommentDlg, TagsDlg, TextMenuDlg, InputBoxDlg, ErrorDlg, BrowserDlg, HistoryDlg, NrOfDialogs +// [HGM] Some remarks about the generic dialog creator of XBoard: +// GenericPopUp is needed to create a dialog from the lists of options supplied by the engines. +// But once it is there, it provides a very easy way for creating other settings dialogs as well, +// by letting XBoard provide its own, compiled-in lists of XBoard options (located in dialogs.c). +// The Option struct uses the following fields (E = for engine options, X = for XBoard options): +// Option types | XBoard-only -> +// TYPE NAME spin check string combo button box label list graph menu break end +// int value E E (h) X/E [w] (h) (h) +// int min X/E (2) (3) (1) (1) (1) (1) (3) (1) (4) +// int max X/E (w) (w) (w) (w) (w) (w) (w) (w) +// void* handle X/E X/E X/E X/E X/E X X X X X +// void* target X X X X C X X C C +// char* textValue E X/E * +// char ** choice X/E * X +// enum type X/E X/E X/E X/E X X X X X X X X +// char[] name X/E X/E X/E X/E X X X X X +// File and Path options are like String (but get a browse button added in the dialog), and Slider +// is like Spin. Menu can be PopUp or PopDown; both need the COMBO_CALLBACK bit (1) set, and the +// latter also uses the min flags for positioning the menu button. +// (h) or (w) means the field optionally (when non-null) specifies the height or width of the main +// control element (excluding accompanying description texts). [w] means the width is written there. +// C specifies the 'target' is a user-supplied callback function, which will be executed when the +// option is exercised. + + +/* Flags Option.min used (2) for TextBox (-string): */ +#define T_VSCRL (1 << 0) +#define T_HSCRL (1 << 1) +#define T_FILL (1 << 2) +#define T_WRAP (1 << 3) +#define T_TOP (1 << 4) + +/* Flags Option.min used (3) for ComboBox (-combo): */ +#define COMBO_CALLBACK (1 << 0) +#define NO_GETTEXT (1 << 2) + +/* Flags for Option.min used (1) for Button, SaveButton, ListBox, Label: */ +#define SAME_ROW (1 << 0) /* also in Break & EndMark */ +#define BORDER (1 << 1) /* Label */ +#define FIX_H (1 << 1) /* in other, this bit specifies top and botom of the control chain to same window edge */ +#define B2B (1 << 2) /* chain bottom to bottom (by default, no chaining is done) */ +#define T2T (1 << 3) +#define R2R (1 << 4) +#define L2R (1 << 5) +#define R2L (1 << 6) +#define L2L (1 << 7) +#define TT (T2T|FIX_H) /* useful combinations: 0xA = entirely to top */ +#define BB (B2B|FIX_H) /* 6 = entirely to bottom */ +#define TB (B2B|T2T) /* 0xC = absorb all vertical size change */ +#define LL (L2L|R2L) /* 0xC0 = entirely to left */ +#define RR (L2R|R2R) /* 0x30 = entirely to right */ +#define LR (L2L|R2R) /* 0x90 = absorb all horizontal size change */ + +/* Flags for Option.min used (3) for EndMark: */ +#define NO_OK (1 << 1) +#define NO_CANCEL (1 << 2) + +#define MODAL 1 +#define NONMODAL 0 + +typedef enum { // identifier of dialogs done by GenericPopup +TransientDlg=0, // transient: grabs mouse events and is destroyed at pop-down (so other dialog can use this ID next time) +CommentDlg, TagsDlg, TextMenuDlg, InputBoxDlg, NoDlg, BrowserDlg, HistoryDlg, // persistent: no grab and reused +PromoDlg, // this and beyond are destroyed at pop-down +AskDlg, // this and beyond do grab mouse events (and are destroyed) +BoardWindow, +NrOfDialogs // dummy for total } DialogClass; +typedef Option *PointerCallback(int n, int x, int y); typedef void ButtonCallback(int n); typedef int OKCallback(int n); @@ -38,11 +104,11 @@ extern ButtonCallback *comboCallback; extern WindowPlacement wpComment, wpTags, wpMoveHistory; extern char *marked[]; extern Boolean shellUp[]; -extern Option textOptions[], boxOptions[]; +extern Option textOptions[], typeOptions[]; int DialogExists P((DialogClass n)); -int GenericPopUp P((Option *option, char *title, DialogClass dlgNr)); +int GenericPopUp P((Option *option, char *title, DialogClass dlgNr, DialogClass parent, int modal)); int GenericReadout P((Option *currentOption, int selected)); int PopDown P((DialogClass n)); int AppendText P((Option *opt, char *s)); @@ -55,6 +121,16 @@ void SetWidgetText P((Option *opt, char *buf, int n)); void GetWidgetState P((Option *opt, int *state)); void SetWidgetState P((Option *opt, int state)); void SetDialogTitle P((DialogClass dlg, char *title)); +void LoadListBox P((Option *opt, char *emptyText)); +void HighlightListBoxItem P((Option *opt, int nr)); +void HighlightWithScroll P((Option *opt, int sel, int max)); +int SelectedListBoxItem P((Option *opt)); +void BoardFocus P((void)); +void FocusOnWidget P((Option *opt, DialogClass dlg)); +void UnCaret P((void)); +void SetIconName P((DialogClass dlg, char *name)); +int ReadScroll P((Option *opt, float *top, float *bottom)); +void SetScroll P((Option *opt, float f)); void AddHandler P((Option *opt, int nr)); void SendText P((int n)); @@ -62,6 +138,7 @@ void InitDrawingParams P(()); // in xboard.c void ErrorPopUp P((char *title, char *text, int modal)); int ShiftKeys P((void)); +int SetCurrentComboSelection P((Option *opt)); void BoxAutoPopUp P((char *buf)); void IcsKey P((int n)); void ICSInputBoxPopUp P((void)); diff --git a/xboard.c b/xboard.c index 080204b..959dfdd 100644 --- a/xboard.c +++ b/xboard.c @@ -545,6 +545,8 @@ XtActionsRec boardActions[] = { { "EnterKeyProc", EnterKeyProc }, { "UpKeyProc", UpKeyProc }, { "DownKeyProc", DownKeyProc }, + { "WheelProc", WheelProc }, + { "TabProc", TabProc }, }; char globalTranslations[] = diff --git a/xboard.h b/xboard.h index 4d05265..7f12900 100644 --- a/xboard.h +++ b/xboard.h @@ -144,6 +144,9 @@ void InitDrawingSizes P((int i, int j)); void SendToICS P((char *buf)); void SendToProgram P((char *message, ChessProgramState *cps)); void TypeInProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms)); +void WheelProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms)); +void TabProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms)); +void GenericMenu P((Widget w, XEvent *event, String *prms, Cardinal *nprms)); FILE * XsraSelFile P((Widget w, char *prompt, char *ok, char *cancel, char *failed, char *init_path, char *filter, char *mode, int (*show_entry)(), char **name_return)); diff --git a/xhistory.c b/xhistory.c index 6eb335a..2824fa2 100644 --- a/xhistory.c +++ b/xhistory.c @@ -130,8 +130,8 @@ SelectMove (Widget w, XEvent * event, String * params, Cardinal * nParams) } Option historyOptions[] = { -{ 0xD, 200, 400, NULL, (void*) &historyText, "", NULL, TextBox, "" }, -{ 0, 2, 0, NULL, (void*) NULL, "", NULL, EndMark , "" } +{ 200, T_VSCRL | T_FILL | T_WRAP | T_TOP, 400, NULL, (void*) &historyText, "", NULL, TextBox, "" }, +{ 0, NO_OK, 0, NULL, (void*) NULL, "", NULL, EndMark , "" } }; // ------------ standard entry points into MoveHistory code ----------- @@ -151,7 +151,7 @@ MoveHistoryDialogExists () void HistoryPopUp () { - if(GenericPopUp(historyOptions, _("Move list"), HistoryDlg)) + if(GenericPopUp(historyOptions, _("Move list"), HistoryDlg, BoardWindow, NONMODAL)) AddHandler(&historyOptions[0], 0); MarkMenu("Show Move History", HistoryDlg); } diff --git a/xoptions.c b/xoptions.c index e591d74..99ca568 100644 --- a/xoptions.c +++ b/xoptions.c @@ -66,11 +66,13 @@ extern char *getenv(); #include #include #include +#include #include "common.h" #include "backend.h" #include "xboard.h" #include "dialogs.h" +#include "menus.h" #include "gettext.h" #ifdef ENABLE_NLS @@ -87,16 +89,25 @@ static Widget previous = NULL; static Option *currentOption; void -SetFocus (Widget w, XtPointer data, XEvent *event, Boolean *b) +UnCaret () { Arg args[2]; - char *s; - int j; if(previous) { XtSetArg(args[0], XtNdisplayCaret, False); XtSetValues(previous, args, 1); } + previous = NULL; +} + +void +SetFocus (Widget w, XtPointer data, XEvent *event, Boolean *b) +{ + Arg args[2]; + char *s; + int j; + + UnCaret(); XtSetArg(args[0], XtNstring, &s); XtGetValues(w, args, 1); j = 1; @@ -107,10 +118,17 @@ SetFocus (Widget w, XtPointer data, XEvent *event, Boolean *b) previous = w; } +void +BoardFocus () +{ + XtSetKeyboardFocus(shellWidget, formWidget); +} + //--------------------------- Engine-specific options menu ---------------------------------- int dialogError; static Boolean browserUp; +Option *dialogOptions[NrOfDialogs]; void GetWidgetText (Option *opt, char **buf) @@ -146,6 +164,14 @@ SetWidgetState (Option *opt, int state) } void +SetWidgetLabel (Option *opt, char *buf) +{ + Arg arg; + XtSetArg(arg, XtNlabel, (XtArgVal) buf); + XtSetValues(opt->handle, &arg, 1); +} + +void SetDialogTitle (DialogClass dlg, char *title) { Arg args[16]; @@ -153,16 +179,101 @@ SetDialogTitle (DialogClass dlg, char *title) XtSetValues(shells[dlg], args, 1); } -static void -CheckCallback (Widget ww, XtPointer data, XEvent *event, Boolean *b) +void +LoadListBox (Option *opt, char *emptyText) { - Widget w = currentOption[(int)(intptr_t)data].handle; - Boolean s; + static char *dummyList[2]; + dummyList[0] = emptyText; // empty listboxes tend to crash X, so display user-supplied warning string instead + XawListChange(opt->handle, *(char*)opt->target ? opt->target : dummyList, 0, 0, True); +} + +int +ReadScroll (Option *opt, float *top, float *bottom) +{ // retreives fractions of top and bottom of thumb Arg args[16]; + Widget w = XtParent(opt->handle); // viewport + Widget v = XtNameToWidget(w, "vertical"); + int j=0; + float h; + if(!v) return FALSE; // no scroll bar + XtSetArg(args[j], XtNshown, &h); j++; + XtSetArg(args[j], XtNtopOfThumb, top); j++; + XtGetValues(v, args, j); + *bottom = *top + h; + return TRUE; +} - XtSetArg(args[0], XtNstate, &s); - XtGetValues(w, args, 1); - SetWidgetState(¤tOption[(int)(intptr_t)data], !s); +void +SetScroll (Option *opt, float f) +{ // sets top of thumb to given fraction + static char *params[3] = { "", "Continuous", "Proportional" }; + static XEvent event; + Widget w = XtParent(opt->handle); // viewport + Widget v = XtNameToWidget(w, "vertical"); + if(!v) return; // no scroll bar + XtCallActionProc(v, "StartScroll", &event, params+1, 1); + XawScrollbarSetThumb(v, f, -1.0); + XtCallActionProc(v, "NotifyThumb", &event, params, 0); +// XtCallActionProc(v, "NotifyScroll", &event, params+2, 1); + XtCallActionProc(v, "EndScroll", &event, params, 0); +} + +void +HighlightListBoxItem (Option *opt, int nr) +{ + XawListHighlight(opt->handle, nr); +} + +void +HighlightWithScroll (Option *opt, int sel, int max) +{ + float top, bottom, f, g; + HighlightListBoxItem(opt, sel); + if(!ReadScroll(opt, &top, &bottom)) return; // no scroll bar + bottom = bottom*max - 1.; + f = g = top; + top *= max; + if(sel > (top + 3*bottom)/4) f = (sel - 0.75*(bottom-top))/max; else + if(sel < (3*top + bottom)/4) f = (sel - 0.25*(bottom-top))/max; + if(f < 0.) f = 0.; if(f + 1./max > 1.) f = 1. - 1./max; + if(f != g) SetScroll(opt, f); +} + +int +SelectedListBoxItem (Option *opt) +{ + XawListReturnStruct *rs; + rs = XawListShowCurrent(opt->handle); + return rs->list_index; +} + +void +FocusOnWidget (Option *opt, DialogClass dlg) +{ + UnCaret(); + XtSetKeyboardFocus(shells[dlg], opt->handle); +} + +void +SetIconName (DialogClass dlg, char *name) +{ + Arg args[16]; + int j = 0; + XtSetArg(args[j], XtNiconName, (XtArgVal) name); j++; +// XtSetArg(args[j], XtNtitle, (XtArgVal) name); j++; + XtSetValues(shells[dlg], args, j); +} + +static void +CheckCallback (Widget ww, XtPointer client_data, XEvent *event, Boolean *b) +{ + int s, data = (intptr_t) client_data; + Option *opt = dialogOptions[data >> 8] + (data & 255); + + if(opt->type == Label) { ((ButtonCallback*) opt->target)(data&255); return; } + + GetWidgetState(opt, &s); + SetWidgetState(opt, !s); } static void @@ -171,95 +282,116 @@ SpinCallback (Widget w, XtPointer client_data, XtPointer call_data) String name, val; Arg args[16]; char buf[MSG_SIZ], *p; - int j = 0; // Initialiasation is necessary because the text value may be non-numeric causing the scanf conversion to fail + int j = 0; // Initialisation is necessary because the text value may be non-numeric causing the scanf conversion to fail int data = (intptr_t) client_data; + Option *opt = dialogOptions[data >> 8] + (data & 255); XtSetArg(args[0], XtNlabel, &name); XtGetValues(w, args, 1); - GetWidgetText(¤tOption[data], &val); + GetWidgetText(opt, &val); sscanf(val, "%d", &j); if (strcmp(name, _("browse")) == 0) { char *q=val, *r; for(r = ""; *q; q++) if(*q == '.') r = q; else if(*q == '/') r = ""; // last dot after last slash - if(!strcmp(r, "") && !currentCps && currentOption[data].type == FileName && currentOption[data].textValue) - r = currentOption[data].textValue; + if(!strcmp(r, "") && !currentCps && opt->type == FileName && opt->textValue) + r = opt->textValue; browserUp = True; - if(XsraSelFile(shells[TransientDlg], currentOption[data].name, NULL, NULL, "", "", r, - currentOption[data].type == PathName ? "p" : "f", NULL, &p)) { + if(XsraSelFile(shells[TransientDlg], opt->name, NULL, NULL, "", "", r, + opt->type == PathName ? "p" : "f", NULL, &p)) { int len = strlen(p); if(len && p[len-1] == '/') p[len-1] = NULLCHAR; XtSetArg(args[0], XtNstring, p); - XtSetValues(currentOption[data].handle, args, 1); + XtSetValues(opt->handle, args, 1); } browserUp = False; - SetFocus(currentOption[data].handle, shells[TransientDlg], (XEvent*) NULL, False); + SetFocus(opt->handle, shells[TransientDlg], (XEvent*) NULL, False); return; } else if (strcmp(name, "+") == 0) { - if(++j > currentOption[data].max) return; + if(++j > opt->max) return; } else if (strcmp(name, "-") == 0) { - if(--j < currentOption[data].min) return; + if(--j < opt->min) return; } else return; snprintf(buf, MSG_SIZ, "%d", j); - SetWidgetText(¤tOption[data], buf, TransientDlg); + SetWidgetText(opt, buf, TransientDlg); } static void ComboSelect (Widget w, caddr_t addr, caddr_t index) // callback for all combo items { Arg args[16]; - int i = ((intptr_t)addr)>>8; - int j = 255 & (intptr_t) addr; + Option *opt = dialogOptions[((intptr_t)addr)>>24]; // applicable option list + int i = ((intptr_t)addr)>>16 & 255; // option number + int j = 0xFFFF & (intptr_t) addr; - values[i] = j; // store in temporary, for transfer at OK + values[i] = j; // store selected value in Option struct, for retrieval at OK - if(currentOption[i].min & NO_GETTEXT) - XtSetArg(args[0], XtNlabel, ((char**)currentOption[i].textValue)[j]); - else - XtSetArg(args[0], XtNlabel, _(((char**)currentOption[i].textValue)[j])); + if(opt[i].type == Graph || opt[i].min & COMBO_CALLBACK && !currentCps) { + ((ButtonCallback*) opt[i].target)(i); + return; + } - XtSetValues(currentOption[i].handle, args, 1); + if(opt[i].min & NO_GETTEXT) + XtSetArg(args[0], XtNlabel, ((char**)opt[i].choice)[j]); + else + XtSetArg(args[0], XtNlabel, _(((char**)opt[i].choice)[j])); - if(currentOption[i].min & COMBO_CALLBACK && !currentCps && comboCallback) (comboCallback)(i); + XtSetValues(opt[i].handle, args, 1); } -static void -CreateComboPopup (Widget parent, Option *option, int n) +Widget +CreateMenuItem (Widget menu, char *msg, XtCallbackProc CB, int n) { - int i=0, j; - Widget menu, entry; + int j=0; + Widget entry; Arg args[16]; - char **mb = (char **) option->textValue; - - if(mb[0] == NULL) return; // avoid empty menus, as they cause crash - menu = XtCreatePopupShell(option->name, simpleMenuWidgetClass, - parent, NULL, 0); - j = 0; - XtSetArg(args[j], XtNwidth, 100); j++; - while (mb[i] != NULL) + XtSetArg(args[j], XtNleftMargin, 20); j++; + XtSetArg(args[j], XtNrightMargin, 20); j++; + if(!strcmp(msg, "----")) { XtCreateManagedWidget(msg, smeLineObjectClass, menu, args, j); return NULL; } + XtSetArg(args[j], XtNlabel, msg); + entry = XtCreateManagedWidget("item", smeBSBObjectClass, menu, args, j+1); + XtAddCallback(entry, XtNcallback, CB, (caddr_t)(intptr_t) n); + return entry; +} + +static Widget +CreateComboPopup (Widget parent, Option *opt, int n, int fromList, int def) +{ // fromList determines if the item texts are taken from a list of strings, or from a menu table + int i, j; + Widget menu, entry; + Arg arg; + MenuItem *mb = (MenuItem *) opt->choice; + char **list = (char **) opt->choice; + + if(list[0] == NULL) return NULL; // avoid empty menus, as they cause crash + menu = XtCreatePopupShell(opt->name, simpleMenuWidgetClass, parent, NULL, 0); + + for (i=0; 1; i++) { - if (option->min & NO_GETTEXT) - XtSetArg(args[j], XtNlabel, mb[i]); - else - XtSetArg(args[j], XtNlabel, _(mb[i])); - entry = XtCreateManagedWidget((String) mb[i], smeBSBObjectClass, - menu, args, j+1); - XtAddCallback(entry, XtNcallback, - (XtCallbackProc) ComboSelect, - (caddr_t)(intptr_t) (256*n+i)); - i++; + char *msg = fromList ? list[i] : mb[i].string, *msg2; + if(!msg) break; + entry = CreateMenuItem(menu, opt->min & NO_GETTEXT ? msg : _(msg), (XtCallbackProc) ComboSelect, (n<<16)+i); + if(!fromList) mb[i].handle = (void*) entry; // save item ID, for enabling / checkmarking + if(i==def) { + XtSetArg(arg, XtNpopupOnEntry, entry); + XtSetValues(menu, &arg, 1); + } } + return menu; } char moveTypeInTranslations[] = "Return: TypeInProc(1) \n" "Escape: TypeInProc(0) \n"; +extern char filterTranslations[]; +extern char gameListTranslations[]; char *translationTable[] = { historyTranslations, commentTranslations, moveTypeInTranslations, ICSInputTranslations, + filterTranslations, gameListTranslations, }; void @@ -273,22 +405,24 @@ AddHandler (Option *opt, int nr) // cloned from Engine Settings dialog (and later merged with it) Widget shells[NrOfDialogs]; -WindowPlacement *wp[NrOfDialogs] = { NULL, &wpComment, &wpTags, NULL, NULL, NULL, NULL, &wpMoveHistory }; -static Option *dialogOptions[NrOfDialogs]; +DialogClass parents[NrOfDialogs]; +WindowPlacement *wp[NrOfDialogs] = { // Beware! Order must correspond to DialogClass enum + NULL, &wpComment, &wpTags, NULL, NULL, NULL, NULL, &wpMoveHistory, &wpGameList, &wpEngineOutput +}; int DialogExists (DialogClass n) -{ +{ // accessor for use in back-end return shells[n] != NULL; } int PopDown (DialogClass n) -{ +{ // pops down any dialog created by GenericPopUp (or returns False if it wasn't up), unmarks any associated marked menu int j; Arg args[10]; Dimension windowH, windowW; Position windowX, windowY; - if (!shellUp[n]) return 0; + if (!shellUp[n] || !shells[n]) return 0; if(n && wp[n]) { // remember position j = 0; XtSetArg(args[j], XtNx, &windowX); j++; @@ -303,21 +437,27 @@ PopDown (DialogClass n) } previous = NULL; XtPopdown(shells[n]); - if(n == 0) XtDestroyWidget(shells[n]); - shellUp[n] = False; + shellUp[n]--; // count rather than clear + if(n == 0 || n >= PromoDlg) XtDestroyWidget(shells[n]), shells[n] = NULL; if(marked[n]) { MarkMenuItem(marked[n], False); marked[n] = NULL; } if(!n) currentCps = NULL; // if an Engine Settings dialog was up, we must be popping it down now + currentOption = dialogOptions[TransientDlg]; // just in case a transient dialog was up (to allow its check and combo callbacks to work) + XtSetKeyboardFocus(shells[parents[n]], n == BoardWindow ? formWidget: shells[parents[n]]); return 1; } void GenericPopDown (Widget w, XEvent *event, String *prms, Cardinal *nprms) -{ +{ // to cause popdown through a translation (Delete Window button!) + int dlg = atoi(prms[0]); + Widget sh = shells[dlg]; if(browserUp || dialogError) return; // prevent closing dialog when it has an open file-browse daughter - PopDown(prms[0][0] - '0'); + shells[dlg] = w; + PopDown(dlg); + shells[dlg] = sh; // restore } int @@ -335,7 +475,7 @@ AppendText (Option *opt, char *s) void SetColor (char *colorName, Option *box) -{ +{ // sets the color of a widget Arg args[5]; Pixel buttonColor; XrmValue vFrom, vTo; @@ -355,58 +495,208 @@ SetColor (char *colorName, Option *box) void ColorChanged (Widget w, XtPointer data, XEvent *event, Boolean *b) -{ +{ // for detecting a typed change in color char buf[10]; if ( (XLookupString(&(event->xkey), buf, 2, NULL, NULL) == 1) && *buf == '\r' ) RefreshColor((int)(intptr_t) data, 0); } -void +static void +GraphEventProc(Widget widget, caddr_t client_data, XEvent *event) +{ // handle expose and mouse events on Graph widget + Dimension w, h; + Arg args[16]; + int j, button=10, f=1; + Option *opt; + if (!XtIsRealized(widget)) return; + + switch(event->type) { + case Expose: + if (((XExposeEvent*)event)->count > 0) return; // don't bother if further exposure is pending + /* Get client area */ + j = 0; + XtSetArg(args[j], XtNwidth, &w); j++; + XtSetArg(args[j], XtNheight, &h); j++; + XtGetValues(widget, args, j); + break; + case MotionNotify: + f = 0; + w = ((XButtonEvent*)event)->x; h = ((XButtonEvent*)event)->y; + break; + case ButtonRelease: + f = -1; // release indicated by negative button numbers + case ButtonPress: + w = ((XButtonEvent*)event)->x; h = ((XButtonEvent*)event)->y; + switch(((XButtonEvent*)event)->button) { + case Button1: button = 1; break; + case Button2: button = 2; break; + case Button3: button = 3; break; + case Button4: button = 4; break; + case Button5: button = 5; break; + } + } + button *= f; + opt = ((PointerCallback*) client_data)(button, w, h); + if(opt) { // user callback specifies a context menu; pop it up + XUngrabPointer(xDisplay, CurrentTime); + XtCallActionProc(widget, "XawPositionSimpleMenu", event, &(opt->name), 1); + XtPopupSpringLoaded(opt->handle); + } + XSync(xDisplay, False); +} + +static void GenericCallback (Widget w, XtPointer client_data, XtPointer call_data) -{ +{ // all Buttons in a dialog (including OK, cancel) invoke this String name; Arg args[16]; char buf[MSG_SIZ]; int data = (intptr_t) client_data; + DialogClass dlg; + Widget sh = XtParent(XtParent(XtParent(w))), oldSh; - currentOption = dialogOptions[data>>16]; data &= 0xFFFF; - - XtSetArg(args[0], XtNlabel, &name); - XtGetValues(w, args, 1); + currentOption = dialogOptions[dlg=data>>16]; data &= 0xFFFF; + oldSh = shells[dlg]; shells[dlg] = sh; // bow to reality + if (data == 30000) { // cancel + PopDown(dlg); + } else + if (data == 30001) { // save buttons imply OK + if(GenericReadout(currentOption, -1)) PopDown(dlg); // calls OK-proc after full readout, but no popdown if it returns false + } else - if (strcmp(name, _("cancel")) == 0) { - PopDown(data); - return; - } - if (strcmp(name, _("OK")) == 0) { // save buttons imply OK - if(GenericReadout(currentOption, -1)) PopDown(data); - return; - } if(currentCps) { + XtSetArg(args[0], XtNlabel, &name); + XtGetValues(w, args, 1); if(currentOption[data].type == SaveButton) GenericReadout(currentOption, -1); snprintf(buf, MSG_SIZ, "option %s\n", name); SendToProgram(buf, currentCps); } else ((ButtonCallback*) currentOption[data].target)(data); + + shells[dlg] = oldSh; // in case of multiple instances, restore previous (as this one could be popped down now) +} + +void +TabProc (Widget w, XEvent *event, String *prms, Cardinal *nprms) +{ // for transfering focus to the next text-edit + Option *opt; + for(opt = currentOption; opt->type != EndMark; opt++) { + if(opt->handle == w) { + while(++opt) { + if(opt->type == EndMark) opt = currentOption; // wrap + if(opt->handle == w) return; // full circle + if(opt->type == TextBox || opt->type == Spin || opt->type == Fractional || opt->type == FileName || opt->type == PathName) { + SetFocus(opt->handle, XtParent(XtParent(XtParent(w))), NULL, 0); + return; + } + } + } + } +} + +void +WheelProc (Widget w, XEvent *event, String *prms, Cardinal *nprms) +{ // for scrolling a widget seen through a viewport with the mouse wheel (ListBox!) + int j=0, n = atoi(prms[0]); + static char *params[3] = { "", "Continuous", "Proportional" }; + Arg args[16]; + float f, h, top; + Widget v; + if(!n) { // transient dialogs also use this for list-selection callback + n = prms[1][0]-'0'; + Option *opt=dialogOptions[prms[2][0]-'A'] + n; + if(opt->textValue) ((ListBoxCallback*) opt->textValue)(n, SelectedListBoxItem(opt)); + return; + } + v = XtNameToWidget(XtParent(w), "vertical"); + if(!v) return; + XtSetArg(args[j], XtNshown, &h); j++; + XtSetArg(args[j], XtNtopOfThumb, &top); j++; + XtGetValues(v, args, j); + top += 0.1*h*n; if(top < 0.) top = 0.; + XtCallActionProc(v, "StartScroll", event, params+1, 1); + XawScrollbarSetThumb(v, top, -1.0); + XtCallActionProc(v, "NotifyThumb", event, params, 0); +// XtCallActionProc(w, "NotifyScroll", event, params+2, 1); + XtCallActionProc(v, "EndScroll", event, params, 0); +} + +static char *oneLiner = + "Return: redraw-display() \n \ + Tab: TabProc() \n "; +static char scrollTranslations[] = + "(2): WheelProc(0 0 A) \n \ + : WheelProc(-1) \n \ + : WheelProc(1) \n "; + +static void +SqueezeIntoBox (Option *opt, int nr, int width) +{ // size buttons in bar to fit, clipping button names where necessary + int i, j, wtot = 0; + Dimension widths[20], oldWidths[20]; + Arg arg; + for(i=1; imin = wtot; + if(width <= 0) return; + while(wtot > width) { + int wmax=0, imax=0; + for(i=1; i wmax) wmax = widths[imax=i]; + widths[imax]--; + wtot--; + } + for(i=1; imin = wtot; } -static char *oneLiner = "Return: redraw-display()\n"; +int +SetPositionAndSize (Arg *args, Widget leftNeigbor, Widget topNeigbor, int b, int w, int h, int chaining) +{ // sizing and positioning most widgets have in common + int j = 0; + // first position the widget w.r.t. earlier ones + if(chaining & 1) { // same row: position w.r.t. last (on current row) and lastrow + XtSetArg(args[j], XtNfromVert, topNeigbor); j++; + XtSetArg(args[j], XtNfromHoriz, leftNeigbor); j++; + } else // otherwise it goes at left margin (which is default), below the previous element + XtSetArg(args[j], XtNfromVert, leftNeigbor), j++; + // arrange chaining ('2'-bit indicates top and bottom chain the same) + if((chaining & 14) == 6) XtSetArg(args[j], XtNtop, XtChainBottom), j++; + if((chaining & 14) == 10) XtSetArg(args[j], XtNbottom, XtChainTop ), j++; + if(chaining & 4) XtSetArg(args[j], XtNbottom, XtChainBottom ), j++; + if(chaining & 8) XtSetArg(args[j], XtNtop, XtChainTop), j++; + if(chaining & 0x10) XtSetArg(args[j], XtNright, XtChainRight), j++; + if(chaining & 0x20) XtSetArg(args[j], XtNleft, XtChainRight), j++; + if(chaining & 0x40) XtSetArg(args[j], XtNright, XtChainLeft ), j++; + if(chaining & 0x80) XtSetArg(args[j], XtNleft, XtChainLeft ), j++; + // set size (if given) + if(w) XtSetArg(args[j], XtNwidth, w), j++; + if(h) XtSetArg(args[j], XtNheight, h), j++; + // border + XtSetArg(args[j], XtNborderWidth, b); j++; + return j; +} int -GenericPopUp (Option *option, char *title, DialogClass dlgNr) +GenericPopUp (Option *option, char *title, DialogClass dlgNr, DialogClass parent, int modal) { - Arg args[16]; - Widget popup, layout, dialog=NULL, edit=NULL, form, last, b_ok, b_cancel, leftMargin = NULL, textField = NULL; + Arg args[24]; + Widget popup, layout, dialog=NULL, edit=NULL, form, last, b_ok, b_cancel, previousPane = NULL, textField = NULL, oldForm, oldLastRow, oldForeLast; Window root, child; - int x, y, i, j, height=999, width=1, h, c, w, shrink=FALSE; + int x, y, i, j, height=999, width=1, h, c, w, shrink=FALSE, stack = 0, box, chain; int win_x, win_y, maxWidth, maxTextWidth; unsigned int mask; char def[MSG_SIZ], *msg; static char pane[6] = "paneX"; Widget texts[100], forelast = NULL, anchor, widest, lastrow = NULL, browse = NULL; - Dimension bWidth = 50; + Dimension bWidth = 50, m; - if(shellUp[dlgNr]) return 0; // already up - if(dlgNr && shells[dlgNr]) { + if(dlgNr < PromoDlg && shellUp[dlgNr]) return 0; // already up + if(dlgNr && dlgNr < PromoDlg && shells[dlgNr]) { // reusable, and used before (but popped down) XtPopup(shells[dlgNr], XtGrabNone); shellUp[dlgNr] = True; return 0; @@ -427,9 +717,15 @@ GenericPopUp (Option *option, char *title, DialogClass dlgNr) } i = 0; XtSetArg(args[i], XtNresizable, True); i++; + shells[BoardWindow] = shellWidget; parents[dlgNr] = parent; + popup = shells[dlgNr] = +#if TOPLEVEL + XtCreatePopupShell(title, modal ? transientShellWidgetClass : topLevelShellWidgetClass, +#else XtCreatePopupShell(title, transientShellWidgetClass, - shellWidget, args, i); +#endif + shells[parent], args, i); layout = XtCreateManagedWidget(layoutName, formWidgetClass, popup, @@ -440,14 +736,16 @@ GenericPopUp (Option *option, char *title, DialogClass dlgNr) XtCreateManagedWidget(pane, formWidgetClass, layout, formArgs, XtNumber(formArgs)); j=0; - XtSetArg(args[j], XtNfromHoriz, leftMargin); j++; + XtSetArg(args[j], stack ? XtNfromVert : XtNfromHoriz, previousPane); j++; XtSetValues(form, args, j); - leftMargin = form; + lastrow = forelast = NULL; + previousPane = form; last = widest = NULL; anchor = lastrow; - for(h=0; h and if(option[i].type == TextBox || option[i].type == Fractional) break; // add increment and decrement controls for spin - j=0; - XtSetArg(args[j], XtNfromVert, edit); j++; - XtSetArg(args[j], XtNfromHoriz, last); j++; - XtSetArg(args[j], XtNleft, XtChainRight); j++; - XtSetArg(args[j], XtNright, XtChainRight); j++; if(option[i].type == FileName || option[i].type == PathName) { - msg = _("browse"); w = 0; - /* automatically scale to width of text */ - XtSetArg(args[j], XtNwidth, (XtArgVal) NULL ); j++; - if(textHeight) XtSetArg(args[j], XtNheight, textHeight), j++; + msg = _("browse"); w = 0; // automatically scale to width of text + j = textHeight ? textHeight : 0; } else { - w = 20; msg = "+"; - XtSetArg(args[j], XtNheight, textHeight/2); j++; - XtSetArg(args[j], XtNwidth, w); j++; + w = 20; msg = "+"; j = textHeight/2; // spin button } + j = SetPositionAndSize(args, last, edit, 1 /* border */, + w /* w */, j /* h */, 0x31 /* chain to right edge */); edit = XtCreateManagedWidget(msg, commandWidgetClass, form, args, j); - XtAddCallback(edit, XtNcallback, SpinCallback, (XtPointer)(intptr_t) i); + XtAddCallback(edit, XtNcallback, SpinCallback, (XtPointer)(intptr_t) i + 256*dlgNr); if(w == 0) browse = edit; if(option[i].type != Spin) break; - j=0; - XtSetArg(args[j], XtNfromVert, edit); j++; - XtSetArg(args[j], XtNfromHoriz, last); j++; + j = SetPositionAndSize(args, last, edit, 1 /* border */, + 20 /* w */, textHeight/2 /* h */, 0x31 /* chain to right edge */); XtSetArg(args[j], XtNvertDistance, -1); j++; - XtSetArg(args[j], XtNheight, textHeight/2); j++; - XtSetArg(args[j], XtNwidth, 20); j++; - XtSetArg(args[j], XtNleft, XtChainRight); j++; - XtSetArg(args[j], XtNright, XtChainRight); j++; last = XtCreateManagedWidget("-", commandWidgetClass, form, args, j); - XtAddCallback(last, XtNcallback, SpinCallback, (XtPointer)(intptr_t) i); + XtAddCallback(last, XtNcallback, SpinCallback, (XtPointer)(intptr_t) i + 256*dlgNr); break; case CheckBox: - if(!currentCps) option[i].value = *(Boolean*)option[i].target; - j=0; - XtSetArg(args[j], XtNfromVert, last); j++; + if(!currentCps) option[i].value = *(Boolean*)option[i].target; // where checkbox callback uses it + j = SetPositionAndSize(args, last, lastrow, 1 /* border */, + textHeight/2 /* w */, textHeight/2 /* h */, 0xC0 /* chain both to left edge */); XtSetArg(args[j], XtNvertDistance, (textHeight+2)/4 + 3); j++; - XtSetArg(args[j], XtNwidth, textHeight/2); j++; - XtSetArg(args[j], XtNheight, textHeight/2); j++; - XtSetArg(args[j], XtNleft, XtChainLeft); j++; - XtSetArg(args[j], XtNright, XtChainLeft); j++; XtSetArg(args[j], XtNstate, option[i].value); j++; + lastrow = last; option[i].handle = (void*) - (dialog = XtCreateManagedWidget(" ", toggleWidgetClass, form, args, j)); + (last = XtCreateManagedWidget(" ", toggleWidgetClass, form, args, j)); + j = SetPositionAndSize(args, last, lastrow, 0 /* border */, + option[i].max /* w */, textHeight /* h */, 0xC1 /* chain */); + XtSetArg(args[j], XtNjustify, XtJustifyLeft); j++; + XtSetArg(args[j], XtNlabel, _(option[i].name)); j++; + last = XtCreateManagedWidget("label", commandWidgetClass, form, args, j); + // make clicking the text toggle checkbox + XtAddEventHandler(last, ButtonPressMask, False, CheckCallback, (XtPointer)(intptr_t) i + 256*dlgNr); + shrink = TRUE; // following buttons must get text height + break; case Label: msg = option[i].name; - if(*msg == NULLCHAR) msg = option[i].textValue; if(!msg) break; - j=0; - XtSetArg(args[j], XtNfromVert, last); j++; - XtSetArg(args[j], XtNfromHoriz, option[i].type != Label ? dialog : NULL); j++; - if(option[i].type != Label) XtSetArg(args[j], XtNheight, textHeight), j++, shrink = TRUE; - XtSetArg(args[j], XtNleft, XtChainLeft); j++; - XtSetArg(args[j], XtNborderWidth, 0); j++; + chain = option[i].min; + if(chain & SAME_ROW) forelast = lastrow; else shrink = FALSE; + j = SetPositionAndSize(args, last, lastrow, (chain & 2) != 0 /* border */, + option[i].max /* w */, shrink ? textHeight : 0 /* h */, chain | 2 /* chain */); +#if ENABLE_NLS + if(option[i].choice) XtSetArg(args[j], XtNfontSet, *(XFontSet*)option[i].choice), j++; +#else + if(option[i].choice) XtSetArg(args[j], XtNfont, *(XFontStruct*)option[i].choice), j++; +#endif + XtSetArg(args[j], XtNresizable, False); j++; XtSetArg(args[j], XtNjustify, XtJustifyLeft); j++; XtSetArg(args[j], XtNlabel, _(msg)); j++; - last = XtCreateManagedWidget(msg, labelWidgetClass, form, args, j); - if(option[i].type == CheckBox) - XtAddEventHandler(last, ButtonPressMask, False, CheckCallback, (XtPointer)(intptr_t) i); + option[i].handle = (void*) (last = XtCreateManagedWidget("label", labelWidgetClass, form, args, j)); + if(option[i].target) // allow user to specify event handler for button presses + XtAddEventHandler(last, ButtonPressMask, False, CheckCallback, (XtPointer)(intptr_t) i + 256*dlgNr); break; case SaveButton: case Button: - j=0; if(option[i].min & SAME_ROW) { - XtSetArg(args[j], XtNfromVert, lastrow); j++; - XtSetArg(args[j], XtNfromHoriz, last); j++; - XtSetArg(args[j], XtNleft, XtChainRight); j++; - XtSetArg(args[j], XtNright, XtChainRight); j++; - if(shrink) XtSetArg(args[j], XtNheight, textHeight), j++; - } else { - XtSetArg(args[j], XtNfromVert, last); j++; - XtSetArg(args[j], XtNfromHoriz, NULL); j++; lastrow = forelast; - shrink = FALSE; - } + chain = 0x31; // 0011.0001 = both left and right side to right edge + forelast = lastrow; + } else chain = 0, shrink = FALSE; + j = SetPositionAndSize(args, last, lastrow, 1 /* border */, + option[i].max /* w */, shrink ? textHeight : 0 /* h */, chain /* chain */); XtSetArg(args[j], XtNlabel, _(option[i].name)); j++; - if(option[i].max) { XtSetArg(args[j], XtNwidth, option[i].max); j++; } if(option[i].textValue) { // special for buttons of New Variant dialog XtSetArg(args[j], XtNsensitive, appData.noChessProgram || option[i].value < 0 || strstr(first.variants, VariantName(option[i].value))); j++; @@ -590,49 +868,100 @@ GenericPopUp (Option *option, char *title, DialogClass dlgNr) } option[i].handle = (void*) (dialog = last = XtCreateManagedWidget(option[i].name, commandWidgetClass, form, args, j)); - if(option[i].choice && ((char*)option[i].choice)[0] == '#' && !currentCps) { + if(option[i].choice && ((char*)option[i].choice)[0] == '#' && !currentCps) { // for the color picker default-reset SetColor( *(char**) option[i-1].target, &option[i]); XtAddEventHandler(option[i-1].handle, KeyReleaseMask, False, ColorChanged, (XtPointer)(intptr_t) i-1); } - XtAddCallback(last, XtNcallback, GenericCallback, - (XtPointer)(intptr_t) i + (dlgNr<<16)); - if(option[i].textValue) SetColor( option[i].textValue, &option[i]); - forelast = lastrow; // next button can go on same row + XtAddCallback(last, XtNcallback, GenericCallback, (XtPointer)(intptr_t) i + (dlgNr<<16)); // invokes user callback + if(option[i].textValue) SetColor( option[i].textValue, &option[i]); // for new-variant buttons break; case ComboBox: - j=0; - XtSetArg(args[j], XtNfromVert, last); j++; - XtSetArg(args[j], XtNleft, XtChainLeft); j++; - XtSetArg(args[j], XtNright, XtChainLeft); j++; - XtSetArg(args[j], XtNheight, textHeight), j++; - XtSetArg(args[j], XtNborderWidth, 0); j++; + j = SetPositionAndSize(args, last, lastrow, 0 /* border */, + 0 /* w */, textHeight /* h */, 0xC0 /* chain both sides to left edge */); XtSetArg(args[j], XtNjustify, XtJustifyLeft); j++; XtSetArg(args[j], XtNlabel, _(option[i].name)); j++; texts[h] = dialog = XtCreateManagedWidget(option[i].name, labelWidgetClass, form, args, j); - if(currentCps) option[i].choice = (char**) option[i].textValue; else { - for(j=0; option[i].choice[j]; j++) - if(*(char**)option[i].target && !strcmp(*(char**)option[i].target, option[i].choice[j])) break; - option[i].value = j + (option[i].choice[j] == NULL); + if(option[i].min & COMBO_CALLBACK) msg = _(option[i].name); else { + if(!currentCps) SetCurrentComboSelection(option+i); + msg=_(((char**)option[i].choice)[option[i].value]); } - j=0; - XtSetArg(args[j], XtNfromVert, last); j++; - XtSetArg(args[j], XtNfromHoriz, dialog); j++; - XtSetArg(args[j], XtNwidth, option[i].max && !currentCps ? option[i].max : 100); j++; - XtSetArg(args[j], XtNleft, XtChainLeft); j++; + j = SetPositionAndSize(args, dialog, last, (option[i].min & 2) == 0 /* border */, + option[i].max && !currentCps ? option[i].max : 100 /* w */, + textHeight /* h */, 0x91 /* chain */); // same row as its label! XtSetArg(args[j], XtNmenuName, XtNewString(option[i].name)); j++; - XtSetArg(args[j], XtNlabel, _(((char**)option[i].textValue)[option[i].value])); j++; - XtSetArg(args[j], XtNheight, textHeight), j++; + XtSetArg(args[j], XtNlabel, msg); j++; shrink = TRUE; option[i].handle = (void*) (last = XtCreateManagedWidget(" ", menuButtonWidgetClass, form, args, j)); - CreateComboPopup(last, option + i, i); + CreateComboPopup(last, option + i, i + 256*dlgNr, TRUE, -1); values[i] = option[i].value; break; + case ListBox: + // Listbox goes in viewport, as needed for game list + if(option[i].min & SAME_ROW) forelast = lastrow; + j = SetPositionAndSize(args, last, lastrow, 1 /* border */, + option[i].max /* w */, option[i].value /* h */, option[i].min /* chain */); + XtSetArg(args[j], XtNresizable, False); j++; + XtSetArg(args[j], XtNallowVert, True); j++; // scoll direction + last = + XtCreateManagedWidget("viewport", viewportWidgetClass, form, args, j); + j = 0; // now list itself + XtSetArg(args[j], XtNdefaultColumns, 1); j++; + XtSetArg(args[j], XtNforceColumns, True); j++; + XtSetArg(args[j], XtNverticalList, True); j++; + option[i].handle = (void*) + (edit = XtCreateManagedWidget("list", listWidgetClass, last, args, j)); + XawListChange(option[i].handle, option[i].target, 0, 0, True); + XawListHighlight(option[i].handle, 0); + scrollTranslations[25] = '0' + i; + scrollTranslations[27] = 'A' + dlgNr; + XtOverrideTranslations(edit, XtParseTranslationTable(scrollTranslations)); // for mouse-wheel + break; + case Graph: + j = SetPositionAndSize(args, last, lastrow, 0 /* border */, + option[i].max /* w */, option[i].value /* h */, option[i].min /* chain */); + option[i].handle = (void*) + (last = XtCreateManagedWidget("graph", widgetClass, form, args, j)); + XtAddEventHandler(last, ExposureMask | ButtonPressMask | ButtonReleaseMask | PointerMotionMask, False, + (XtEventHandler) GraphEventProc, option[i].target); // mandatory user-supplied expose handler + break; + case PopUp: // note: used only after Graph, so 'last' refers to the Graph widget + option[i].handle = (void*) CreateComboPopup(last, option + i, i + 256*dlgNr, TRUE, option[i].value); + break; + case BoxBegin: + if(option[i].min & SAME_ROW) forelast = lastrow; + j = SetPositionAndSize(args, last, lastrow, 0 /* border */, + 0 /* w */, 0 /* h */, option[i].min /* chain */); + XtSetArg(args[j], XtNorientation, XtorientHorizontal); j++; + XtSetArg(args[j], XtNvSpace, 0); j++; + option[box=i].handle = (void*) + (last = XtCreateWidget("box", boxWidgetClass, form, args, j)); + oldForm = form; form = last; oldLastRow = lastrow; oldForeLast = forelast; + lastrow = NULL; last = NULL; + break; + case DropDown: + j = SetPositionAndSize(args, last, lastrow, 0 /* border */, + 0 /* w */, 0 /* h */, 1 /* chain (always on same row) */); + forelast = lastrow; + msg = _(option[i].name); // write name on the menu button + XtSetArg(args[j], XtNmenuName, XtNewString(option[i].name)); j++; + XtSetArg(args[j], XtNlabel, msg); j++; + option[i].handle = (void*) + (last = XtCreateManagedWidget(option[i].name, menuButtonWidgetClass, form, args, j)); + option[i].textValue = (char*) CreateComboPopup(last, option + i, i + 256*dlgNr, FALSE, -1); + break; + case BoxEnd: + XtManageChildren(&form, 1); + SqueezeIntoBox(&option[box], i-box, option[box].max); + if(option[i].target) ((ButtonCallback*)option[i].target)(box); // callback that can make sizing decisions + last = form; lastrow = oldLastRow; form = oldForm; forelast = oldForeLast; + break; case Break: width++; height = i+1; + stack = !(option[i].min & SAME_ROW); break; default: printf("GenericPopUp: unexpected case in switch.\n"); @@ -647,7 +976,7 @@ GenericPopUp (Option *option, char *title, DialogClass dlgNr) XtSetArg(args[j], XtNwidth, &bWidth); j++; XtGetValues(browse, args, j); } - for(h=0; hwidth > 0) { // if persistent window-info available, reposition j = 0; XtSetArg(args[j], XtNheight, (Dimension) (wp[dlgNr]->height)); j++; @@ -744,7 +1070,7 @@ GenericPopUp (Option *option, char *title, DialogClass dlgNr) XtSetArg(args[j], XtNy, (Position) (wp[dlgNr]->y)); j++; XtSetValues(popup, args, j); } - return 1; + return 1; // tells caller he must do initialization (e.g. add specific event handlers) } @@ -789,14 +1115,15 @@ SetInsertPos (Option *opt, int pos) void TypeInProc (Widget w, XEvent *event, String *prms, Cardinal *nprms) -{ - char *val; - - if(prms[0][0] == '1') { - GetWidgetText(&boxOptions[0], &val); - TypeInDoneEvent(val); +{ // can be used as handler for any text edit in any dialog (from GenericPopUp, that is) + int n = prms[0][0] - '0'; + Widget sh = XtParent(XtParent(XtParent(w))); // popup shell + + if(n<2) { // Enter or Esc typed from primed text widget: treat as if dialog OK or cancel button hit. + int dlgNr; // figure out what the dialog number is by comparing shells (because we must pass it :( ) + for(dlgNr=0; dlgNr