core-fld.tex / last modification: 2007-01-23 14:55
%D \module
%D   [       file=core-fld,
%D        version=1997.05.18,
%D          title=\CONTEXT\ Core Macros,
%D       subtitle=Fill in fields,
%D         author=Hans Hagen,
%D           date=\currentdate,
%D      copyright={PRAGMA / Hans Hagen \& Ton Otten}]
%C
%C This module is part of the \CONTEXT\ macro||package and is
%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
%C details.

% \appendtocommalist  versus \addtocommalist
%
% * as default trigger in radiofields ?
%
% beware: weblink plugin truncates on length, while save as doesn't;
% more precise: (1) first time right string is sent, (2)
% internal string truncated, (3) second time truncated
% string is sent.

\writestatus{loading}{Context Field Macros}

% messages

\definemessageconstant{fields}

\unprotect

%D First we hook fields into the (viewer based) layering mechanism
%D (implemented as properties).

\ifx\currentlayerproperty\undefined\else \let\currentlayerproperty\empty\fi

\appendtoks
  \doif\@@iafieldlayer\v!auto
    {\def\@@iafieldlayer{\currentlayerproperty}}%
\to \everysetupinteraction

\setupinteraction
  [\c!fieldlayer=\v!auto] % auto by default

%D Internal command, linked to \type{\definesymbol}.

\def\dogetfieldsymbol#1%
  {\getobject{SYM}{#1}}

\def\dopresetfieldsymbol#1%
  {\checkobjectreferences
   \doifobjectfoundelse{SYM}{#1}
     {}
     {\settightobject{SYM}{#1}\hbox{\symbol[#1]}%
      \flushatshipout
        {\setbox0\hbox{\hskip-\maxdimen\getobject{SYM}{#1}}%
         \smashbox0\box0}}}

\def\presetfieldsymbols[#1]% slow
  {\def\dopresetfieldsymbols##1%
     {\processcommalist[##1]\dopresetfieldsymbol}%
   \@EA\processcommalist\@EA[#1]\dopresetfieldsymbols}

\def\definedefaultsymbols
  {\definesymbol[defaultyes][$\times$]%
   \definesymbol[defaultno][$\cdot$]}

\def\resetfieldsymbol[#1]% for experimental usage only
  {\resetobject{SYM}{#1}}

%D The interface to the specials. DEFAULT NOG ANDERS

\def\preparefieldvariables % evt \def's at the outer level (test) or \edef's here for fast testing
  {\let\@@DriverFieldNumber         \@@fdn
   \let\@@DriverFieldStyle          \@@fdstyle
   \let\@@DriverFieldColor          \@@fdcolor
   \let\@@DriverFieldBackgroundColor\@@fdfieldbackgroundcolor
   \let\@@DriverFieldFrameColor     \@@fdfieldframecolor
   \let\@@DriverFieldLayer          \@@fdfieldlayer
   \let\@@DriverFieldOption         \@@fdoption
   \let\@@DriverFieldAlign          \@@fdalign
   \let\@@DriverFieldClickIn        \@@fdclickin
   \let\@@DriverFieldClickOut       \@@fdclickout
   \let\@@DriverFieldRegionIn       \@@fdregionin
   \let\@@DriverFieldRegionOut      \@@fdregionout
   \let\@@DriverFieldAfterKey       \@@fdafterkey
   \let\@@DriverFieldFormat         \@@fdformat
   \let\@@DriverFieldValidate       \@@fdvalidate
   \let\@@DriverFieldCalculate      \@@fdcalculate
   \let\@@DriverFieldFocusIn        \@@fdfocusin
   \let\@@DriverFieldFocusOut       \@@fdfocusout}

% todo : remove arguments, consider DriverField a namespace

\def\presetlinefield
  {\preparefieldvariables
   \dopresetlinefield
     {\@@DriverFieldName}
     {\@@DriverFieldWidth}
     {\@@DriverFieldHeight}
     {\@@DriverFieldDefault}
     {\@@DriverFieldNumber}
     {\@@DriverFieldStyle,\@@DriverFieldColor,\@@DriverFieldBackgroundColor,\@@DriverFieldFrameColor}
     {\@@DriverFieldOption}
     {\@@DriverFieldAlign}
     {\@@DriverFieldClickIn,\@@DriverFieldClickOut,\@@DriverFieldRegionIn,\@@DriverFieldRegionOut,%
      \@@DriverFieldAfterKey,\@@DriverFieldFormat,\@@DriverFieldValidate,\@@DriverFieldCalculate,%
      \@@DriverFieldFocusIn,\@@DriverFieldFocusOut}}

\def\presettextfield
  {\preparefieldvariables
   \dopresettextfield
     {\@@DriverFieldName}
     {\@@DriverFieldWidth}
     {\@@DriverFieldHeight}
     {\@@DriverFieldDefault}
     {\@@DriverFieldNumber}
     {\@@DriverFieldStyle,\@@DriverFieldColor,\@@DriverFieldBackgroundColor,\@@DriverFieldFrameColor}
     {\@@DriverFieldOption}
     {\@@DriverFieldAlign}
     {\@@DriverFieldClickIn,\@@DriverFieldClickOut,\@@DriverFieldRegionIn,\@@DriverFieldRegionOut,%
      \@@DriverFieldAfterKey,\@@DriverFieldFormat,\@@DriverFieldValidate,\@@DriverFieldCalculate,%
      \@@DriverFieldFocusIn,\@@DriverFieldFocusOut}}

\def\presetchoicefield
  {\preparefieldvariables
   \dopresetchoicefield
     {\@@DriverFieldName}
     {\@@DriverFieldWidth}
     {\@@DriverFieldHeight}
     {\@@DriverFieldDefault}
     {\@@DriverFieldStyle,\@@DriverFieldColor,\@@DriverFieldBackgroundColor,\@@DriverFieldFrameColor}
     {\@@DriverFieldOption}
     {\@@DriverFieldValues}
     {\@@DriverFieldClickIn,\@@DriverFieldClickOut,\@@DriverFieldRegionIn,\@@DriverFieldRegionOut,%
      \@@DriverFieldAfterKey,\@@DriverFieldFormat,\@@DriverFieldValidate,\@@DriverFieldCalculate,%
      \@@DriverFieldFocusIn,\@@DriverFieldFocusOut}}

\def\presetpopupfield
  {\preparefieldvariables
   \dopresetpopupfield
     {\@@DriverFieldName}
     {\@@DriverFieldWidth}
     {\@@DriverFieldHeight}
     {\@@DriverFieldDefault}
     {\@@DriverFieldStyle,\@@DriverFieldColor,\@@DriverFieldBackgroundColor,\@@DriverFieldFrameColor}
     {\@@DriverFieldOption}
     {\@@DriverFieldValues}
     {\@@DriverFieldClickIn,\@@DriverFieldClickOut,\@@DriverFieldRegionIn,\@@DriverFieldRegionOut,%
      \@@DriverFieldAfterKey,\@@DriverFieldFormat,\@@DriverFieldValidate,\@@DriverFieldCalculate,%
      \@@DriverFieldFocusIn,\@@DriverFieldFocusOut}}

\def\presetcombofield
  {\preparefieldvariables
   \dopresetcombofield
     {\@@DriverFieldName}
     {\@@DriverFieldWidth}
     {\@@DriverFieldHeight}
     {\@@DriverFieldDefault}
     {\@@DriverFieldStyle,\@@DriverFieldColor,\@@DriverFieldBackgroundColor,\@@DriverFieldFrameColor}
     {\@@DriverFieldOption}
     {\@@DriverFieldValues}
     {\@@DriverFieldClickIn,\@@DriverFieldClickOut,\@@DriverFieldRegionIn,\@@DriverFieldRegionOut,%
      \@@DriverFieldAfterKey,\@@DriverFieldFormat,\@@DriverFieldValidate,\@@DriverFieldCalculate,%
      \@@DriverFieldFocusIn,\@@DriverFieldFocusOut}}

\def\presetcheckfield
  {\preparefieldvariables
   \presetfieldsymbols[\@@DriverFieldValues]%
   \dopresetcheckfield
     {\@@DriverFieldName}
     {\@@DriverFieldWidth}
     {\@@DriverFieldHeight}
     {\@@DriverFieldDefault}
     {\@@DriverFieldOption}
     {\@@DriverFieldValues}
     {\@@DriverFieldClickIn,\@@DriverFieldClickOut,\@@DriverFieldRegionIn,\@@DriverFieldRegionOut,%
      \@@DriverFieldAfterKey,\@@DriverFieldFormat,\@@DriverFieldValidate,\@@DriverFieldCalculate,%
      \@@DriverFieldFocusIn,\@@DriverFieldFocusOut}}

\def\presetpushfield
  {\preparefieldvariables
   %\edef\@@DriverFieldValues{{\@@DriverFieldValues}}% makes sure {a,b,c} is passed
   \presetfieldsymbols[\@@DriverFieldValues]%
   \dopresetpushfield
     {\@@DriverFieldName}
     {\@@DriverFieldWidth}
     {\@@DriverFieldHeight}
     {\@@DriverFieldDefault}
     {\@@DriverFieldOption}
     {\@@DriverFieldValues}
     {\@@DriverFieldClickIn,\@@DriverFieldClickOut,\@@DriverFieldRegionIn,\@@DriverFieldRegionOut,%
      \@@DriverFieldAfterKey,\@@DriverFieldFormat,\@@DriverFieldValidate,\@@DriverFieldCalculate,%
      \@@DriverFieldFocusIn,\@@DriverFieldFocusOut}}

\def\presetradiofield
  {\preparefieldvariables
   \presetfieldsymbols[\@@DriverFieldValues]%
   \dopresetradiofield
     {\@@DriverFieldName}
     {\@@DriverFieldWidth}
     {\@@DriverFieldHeight}
     {\@@DriverFieldDefault}
     {\@@DriverFieldOption}
     {\@@DriverFieldRoot}
     {\@@DriverFieldValues}
     {\@@DriverFieldClickIn,\@@DriverFieldClickOut,\@@DriverFieldRegionIn,\@@DriverFieldRegionOut,%
      \@@DriverFieldAfterKey,\@@DriverFieldFormat,\@@DriverFieldValidate,\@@DriverFieldCalculate,%
      \@@DriverFieldFocusIn,\@@DriverFieldFocusOut}}

\def\presetradiorecord
  {\preparefieldvariables
   \dopresetradiorecord
     {\@@DriverFieldName}
     {\@@DriverFieldDefault}
     {\@@DriverFieldOption}
     {\@@DriverFieldKids}
     {\@@DriverFieldClickIn,\@@DriverFieldClickOut,\@@DriverFieldRegionIn,\@@DriverFieldRegionOut,%
      \@@DriverFieldAfterKey,\@@DriverFieldFormat,\@@DriverFieldValidate,\@@DriverFieldCalculate,%
      \@@DriverFieldFocusIn,\@@DriverFieldFocusOut}}

\def\setfieldmodes#1#2#3%
  {\xdef\@@DriverFieldMode{#1}%  % 0 1 2 3
   \xdef\@@DriverFieldFree{#2}%  % 0 1
   \xdef\@@DriverFieldAuto{#3}}  % 0 1

\newevery\everysetfield\relax

\def\doiffieldelse#1{\doifdefinedelse{fielddata#1}}

\def\setfield#1#2#3#4#5#6#7#8#9%
  {\bgroup
   \doglobal\increment\numberoffields
   \iftracefields
     \doglobal\addtocommalist{#1}\collectedfields
   \fi
   \the\everysetfield
   \setxvalue{fielddata#1}% kortere tag #7 needs expansion etc
     {\noexpand\dosetfield{#1}{#2}{#3}{#4}{#5}{#6}{#7}{#8}{#9}}%
   \egroup}

\def\dosetfield#1#2#3#4#5#6#7#8#9%
  {\xdef\@@DriverFieldName   {#1}%
   \xdef\@@DriverFieldType   {#2}%
   \xdef\@@DriverFieldRoot   {#3}%
   \xdef\@@DriverFieldParent {#4}%
   \xdef\@@DriverFieldKids   {#5}%
   \xdef\@@DriverFieldGroup  {#6}%
   \setfieldmodes             #7%
   \bgroup
     \def\par{\string\n\string\n}%
     \xdef\@@DriverFieldValues {#8}%
     \xdef\@@DriverFieldDefault{#9}%
   \egroup}

\def\changefield#1%
  {\setfield{#1}\@@DriverFieldType\@@DriverFieldRoot\@@DriverFieldParent\@@DriverFieldKids\@@DriverFieldGroup
     {\@@DriverFieldMode\@@DriverFieldFree\@@DriverFieldAuto}\@@DriverFieldValues\@@DriverFieldDefault}

\def\getfield#1% name
  {\doifundefinedelse{fielddata#1}
     {\dosetfield{#1}\empty\empty\empty\empty\empty{\empty00}\empty\empty}
     {\getvalue{fielddata#1}}}

\newif\iftracefields \tracefieldsfalse

\let\tracefields\tracefieldstrue

\def\doshowfields[#1]% todo: tabulate van maken en runtime
  {\bgroup
   \switchtobodyfont[8pt,tt]%
   \doifsomething{#1}{\def\collectedfields{#1}}%
   \ifx\collectedfields\empty
     \par specify [fieldlist] or say \type{\tracefieldstrue} first\par
   \else
     \def\normalizedfieldmode##1##2##3%
       {\ifcase0##2 \else\sl\fi
        \ifcase0##1 loner\or parent\or clone\or copy\fi}%
     \def\dosetfield##1##2##3##4##5##6##7##8##9%
       {##1&##2&##3&##4&##5&##6&\normalizedfieldmode##7&##8&##9\cr}%
     \halign
       {&##\strut\hss\quad\cr
        \noalign{\hrule}%
        NAME  &TYPE  &ROOT   &
        PARENT&KIDS  &GROUP  &
        MODE  &VALUES&DEFAULT\cr
        \noalign{\hrule}%
        \@EA\globalprocesscommalist\@EA[\collectedfields]\getfield
        \noalign{\hrule}}%
   \fi
   \egroup}

\def\showfields
  {\dosingleempty\doshowfields}

\def\dologfields[#1]%
  {\bgroup
   \immediate\openout\scratchwrite=fields.log
   \doifsomething{#1}{\def\collectedfields{#1}}%
   \ifx\colledtedfields\empty
     \immediate\write\scratchwrite{use \tracefieldstrue}%
   \else
     \def\normalizedfieldmode##1##2##3%
       {\edef\@@DriverFieldMode
          {\ifcase##1 loner \or parent \or clone \or copy \fi
           \ifcase##2 \else(done)\fi}}%
     \def\dosetfield##1##2##3##4##5##6##7##8##9%
       {\normalizedfieldmode##7%
        \immediate\write\scratchwrite
          {N=##1 / T=##2 / R=##3 / P=##4 / K=##5 / G=##6 /
           M=\@@DriverFieldMode\space/ V=##8 / D=##9}}%
     \processcommacommand[\collectedfields]\getfield
   \fi
   \immediate\closeout\scratchwrite
   \egroup}

\def\logfields
  {\dosingleempty\doLogFields}

%D \starttyping
%D \definefield [name] [type] [group] [values] [default]
%D
%D \definefield [WWWW] [text]  [textsetup]            [default text]
%D \definefield [XXXX] [push]  [pushsetup]  [yes,no]  [yes]
%D \definefield [XXXX] [check] [checksetup] [yes,no]  [yes]
%D \definefield [YYYY] [combo] [combosetup] [a,b,c,d] [b]
%D \definefield [ZZZZ] [radio] [radiosetup] [W,X,Y,Z] [Y]
%D
%D \definesubfield [W]   [subsetup] [p,q]
%D \definesubfield [X,Y] [subsetup] [p,r]
%D \definesubfield [Z]   [subsetup] [y,z]
%D
%D evt \definemainfield ... wanneer geplaatst voor subs gegeven
%D
%D \clonefield [XXXX] [XX,YY] [mysetup]      [on,off]
%D \clonefield [Z]    [AA,BB] [somesetup]    [true,false]
%D \clonefield [Z]    [CC,DD] [anothersetup]
%D
%D \copyfield [XXXX] [PP,QQ,RR]
%D
%D \field[XXXX]
%D \fitfield[XXXX]
%D \stoptyping

\newif\ifdefinemainfield \definemainfieldfalse

%D We need to keep track of cloned (related) fields and so by
%D maintaining lists of field clones.
%D
%D The first alternative used a two pass data list and was
%D implemented as follows:
%D
%D \starttyping
%D \def\getmainfieldkids#1%
%D   {\let\@@DriverFieldKids\empty
%D    \ifdefinemainfield
%D      \definetwopasslist{fld:#1}% defined by system
%D      \doloop
%D        {\gettwopassdata{fld:#1}%
%D         \iftwopassdatafound
%D          %\addtocommalist\twopassdata\@@DriverFieldKids
%D           \appendtocommalist\twopassdata\@@DriverFieldKids
%D         \else
%D           \exitloop
%D         \fi}%
%D    \fi}
%D \stoptyping
%D
%D However, the next alternative is much faster when we have
%D a field with thousands of clones, something not that
%D imaginary.
%D
%D \starttyping
%D \def\getmainfieldkids#1%
%D   {\let\@@DriverFieldKids\empty
%D    \ifdefinemainfield
%D      \definetwopasslist{fld:#1}% runtime defined by system
%D      \getnamedtwopassdatalist{fld:#1}\@@DriverFieldKids
%D    \fi}
%D \stoptyping
%D
%D The data is written by file using:
%D
%D \starttyping
%D \newcounter\nofmainfieldkids
%D
%D \def\setmainfieldkid#1#2%
%D   {\doglobal\increment\nofmainfieldkids
%D    \savetwopassdata{fld:#1}{\nofmainfieldkids}{#2}}
%D \stoptyping
%D
%D The trade of of this mechanism is that for each cloned or
%D copied field, the uitlity file is to be read in order to
%D fetch the data.
%D
%D The next, much faster alternative uses a dedicated %
%D reference mechanism.

\def\setmainfieldkid#1#2%
  {\immediatewriteutilitycommand{\fieldreference{#1}{#2}}}

\def\checkfieldreferences
  {\startnointerference
   \protectlabels
   \doutilities{fieldreferences}\jobname\empty\relax\relax
   \global\let\checkfieldreferences\relax
   \stopnointerference}

\def\setfieldreferences
  {\def\fieldreference##1##2%
     {\ifundefined{\r!widget##1}%
        \setxvalue{\r!widget##1}{##2}%
      \else
        \edef\!!stringa{\getvalue{\r!widget##1}}%
        \setxvalue{\r!widget##1}{\!!stringa,##2}%
      \fi}}

\def\resetfieldreferences
  {\let\fieldreference\gobbletwoarguments}

\def\getmainfieldkids#1%
  {\checkfieldreferences
   \ifdefinemainfield
     \doifundefinedelse{\r!widget#1}%
       {\let\@@DriverFieldKids\empty}
       {\@EA\let\@EA\@@DriverFieldKids\csname\r!widget#1\endcsname}%
   \else
     \let\@@DriverFieldKids\empty
   \fi}

\resetfieldreferences

%D Of course it costs a few more tokens to implement, but it's
%D worth the memory: running for instance the 2000 page
%D english examns publishing on demand document went down from
%D 1350 seconds to less than 950 on a 650 Mhz pentium.

\def\definefield
  {\definemainfieldfalse\doquintupleempty\dodefinefield}

\def\definemainfield
  {\definemainfieldtrue \doquintupleempty\dodefinefield}

\let\collectedfields\empty
\newcounter\numberoffields
\newcounter\totalnumberoffields

\def\savenumberoffields
  {\ifcase\numberoffields\relax\else
     \savecurrentvalue\totalnumberoffields\numberoffields
   \fi}

\appendtoks \savenumberoffields \to \everybye % \everylastshipout

% \def\presetfieldreferences
%   {\ifnum\totalnumberoffields>0
%      \definereference[AtOpenInitializeForm][\v!ResetForm]%
%    \fi}
%
% \definereference[AtOpenInitializeForm][\v!geen]
%
% \appendtoks \presetfieldreferences \to \everycheckreferences

\def\dodefinefield[#1][#2][#3][#4][#5]%
  {\ifsecondargument
     \edef\currentfieldname{#1}% just in case we're inside a loop
     \doifundefinedelse{define#2field}
       {\writestatus\m!fields{unknown field type #2}}
       {\doifundefined{fielddata\currentfieldname}
          {\getmainfieldkids\currentfieldname
           \ifdefinemainfield
             \ifx\@@DriverFieldKids\empty
               \let\@@DriverFieldMode\fieldlonermode
             \else
               \let\@@DriverFieldMode\fieldparentmode
             \fi
             \def\@@DriverFieldAuto{1}%
           \else
             \let\@@DriverFieldMode\fieldlonermode
             \def\@@DriverFieldAuto{0}%
           \fi
           \def\@@DriverFieldFree{0}%
           \getvalue{define#2field}{\currentfieldname}{#2}{#3}{#4}{#5}}}%
   \else
     \writestatus\m!fields{pass fieldname and fieldtype}%
   \fi}

\def\definelinefield#1#2#3#4#5%
  {\setfield{#1}{#2}{}{}{\@@DriverFieldKids}{#3}{\@@DriverFieldMode\@@DriverFieldFree\@@DriverFieldAuto}{}{#4}}

\let\definetextfield=\definelinefield

\def\definechoicefield#1#2#3#4#5%
  {\doifelsenothing{#4}
     {\def\@@DriverFieldValues{yes,no}}
     {\def\@@DriverFieldValues{#4}}%
   \doifelsenothing{#5}
     {\dogetcommacommandelement2\from\@@DriverFieldValues \to\@@DriverFieldDefault
      \dogetcommacommandelement1\from\@@DriverFieldDefault\to\@@DriverFieldDefault}
     {\def\@@DriverFieldDefault{#5}}%
   \setfield{#1}{#2}{}{}{\@@DriverFieldKids}{#3}{\@@DriverFieldMode\@@DriverFieldFree\@@DriverFieldAuto}{\@@DriverFieldValues}{\@@DriverFieldDefault}}

\let\definepopupfield=\definechoicefield
\let\definecombofield=\definechoicefield

%\def\definecheckfield#1#2#3#4#5%
%  {\doifelsenothing{#4}
%     {\definedefaultsymbols
%      \def\@@DriverFieldValues{defaultyes}}
%     {\def\@@DriverFieldValues{#4}}%
%   \doifelsenothing{#5}
%     {\dogetcommacommandelement2\from\@@DriverFieldValues\to\@@DriverFieldDefault
%      \dogetcommacommandelement1\from\@@DriverFieldDefault\to\@@DriverFieldDefault}
%     {\def\@@DriverFieldDefault{#5}}%
%   \setfield{#1}{#2}{}{}{\@@DriverFieldKids}{#3}{\@@DriverFieldMode\@@DriverFieldFree\@@DriverFieldAuto}{\@@DriverFieldValues}{\@@DriverFieldDefault}}

%D Since these fields have an on/off state only, we pass 1/0
%D to the driver as default values.

\def\definecheckfield#1#2#3#4#5%
  {\doifelsenothing{#4}
     {\definedefaultsymbols
      \def\@@DriverFieldValues{defaultyes}}
     {\def\@@DriverFieldValues{#4}}%
   \doifelsenothing{#5}
     {\def\@@DriverFieldDefault{2}}
     {\dogetcommacommandelement1\from\@@DriverFieldValues\to\@@DriverFieldDefault
      \doifinstringelse{#5}{\@@DriverFieldDefault}
        {\def\@@DriverFieldDefault{1}}
        {\def\@@DriverFieldDefault{0}}}%
   \setfield
     {#1}{#2}{}{}{\@@DriverFieldKids}{#3}%
     {\@@DriverFieldMode\@@DriverFieldFree\@@DriverFieldAuto}%
     {\@@DriverFieldValues}{\@@DriverFieldDefault}}

\let\definepushfield=\definecheckfield

\def\defineradiofield#1#2#3#4#5%
  {\iffourthargument
     \doifelsenothing{#5}
       {\dogetcommacommandelement1\from#4\to\SavedFieldDefault
        \dogetcommacommandelement1\from\SavedFieldDefault\to\SavedFieldDefault}
       {\def\SavedFieldDefault{#5}}%
% when opt works
% \@EA\beforesplitstring\SavedFieldDefault\at=>\to\SavedFieldDefault
     \ifx\@@DriverFieldKids\empty
       \setfield{#1}{#2}{}{}{#4}{#3}{\@@DriverFieldMode\@@DriverFieldFree\@@DriverFieldAuto}{}{\SavedFieldDefault}%
     \else
       \setfield{#1}{#2}{}{}{#4,\@@DriverFieldKids}{#3}{\@@DriverFieldMode\@@DriverFieldFree\@@DriverFieldAuto}{}{\SavedFieldDefault}%
     \fi
%
     \def\docommand##1%
       {\doifelse{##1}\SavedFieldDefault
          {\def\@@DriverFieldDefault{##1}}%
          {\let\@@DriverFieldDefault\empty}%
        \setfield{##1}{#2}{#1}{}{}{#3}{\@@DriverFieldMode\@@DriverFieldFree\@@DriverFieldAuto}{}{\@@DriverFieldDefault}}%
% when opt works
%     \def\docommand##1%
%       {\@EA\beforesplitstring##1\at=>\to\FieldValue
%        \doifelse\FieldValue\SavedFieldDefault
%          {\let\@@DriverFieldDefault\FieldValue}%
%          {\let\@@DriverFieldDefault\empty}%
%        \setfield\FieldValue{#2}{#1}{}{}{#3}{\@@DriverFieldMode\@@DriverFieldFree\@@DriverFieldAuto}{}{\@@DriverFieldDefault}}%
     \processcommalist[#4]\docommand
  \else
     \writestatus\m!fields{pass values too}%
  \fi}

\def\definesubfield
  {\dotripleempty\dodefinesubfield}

\def\dodefinesubfield[#1][#2][#3]% for the moment only radio ones
  {\ifsecondargument
     \def\docommand##1%
       {\getfield{##1}%
        \ifx\@@DriverFieldType\empty
          \writestatus\m!fields{unknown field ##1}% to do
        \else
          \doifsomething{#2}
            {\edef\@@DriverFieldGroup{#2}}%
          \doifelsenothing{#3}
            {\definedefaultsymbols
             \def\@@DriverFieldValues{defaultyes}}
            {\def\@@DriverFieldValues{#3}}%
          \changefield{##1}%
        \fi}%
      \processcommalist[#1]\docommand
   \else
     \writestatus\m!fields{pass fieldname, setupgroup, values and default}%
   \fi}

\def\doclonefield[#1][#2][#3][#4]% parent children setupgroup values
  {\ifsecondargument
     \getfield{#1}%
\iftrialtypesetting\else
     \ifx\@@DriverFieldType\empty
       \writestatus\m!fields{unknown field #1}%
     \else
       \let\@@DriverFieldMode\fieldparentmode
      %\def\docommand##1{\addtocommalist{##1}\@@DriverFieldKids}%
       \def\docommand##1{\appendtocommalist{##1}\@@DriverFieldKids}%
       \processcommalist[#2]\docommand
       \changefield{#1}%
       \let\@@DriverFieldAutoParent\@@DriverFieldAuto
       \def\@@DriverFieldParent{#1}%
       \let\@@DriverFieldKids\empty
       \let\@@DriverFieldRoot\empty
       \let\@@DriverFieldMode\fieldchildmode
       \def\@@DriverFieldFree{0}%
       \def\@@DriverFieldAuto{0}%
       \doifsomething{#3}{\edef\@@DriverFieldGroup{#3}}%
       \doifsomething{#4}{\edef\@@DriverFieldValues{#4}}%
       \def\docommand##1%
         {\ifcase\@@DriverFieldAutoParent\else
            \setmainfieldkid{\@@DriverFieldParent}{##1}%
          \fi
          \changefield{##1}}%
       \processcommalist[#2]\docommand
     \fi
\fi
   \else
     \writestatus\m!fields{pass parent field and clones}%
   \fi}

\def\clonefield
  {\doquadrupleempty\doclonefield}

\def\docopyfield[#1][#2]% parent children
  {\ifsecondargument
     \getfield{#1}%
\iftrialtypesetting\else
     \ifx\@@DriverFieldType\empty
       \writestatus\m!fields{unknown field #1}%
     \else
       \let\@@DriverFieldMode\fieldparentmode
      %\def\docommand##1{\addtocommalist{##1}\@@DriverFieldKids}%
       \def\docommand##1{\appendtocommalist{##1}\@@DriverFieldKids}%
       \processcommalist[#2]\docommand
       \changefield{#1}%
       \let\@@DriverFieldAutoParent\@@DriverFieldAuto
       \def\@@DriverFieldParent{#1}%
       \let\@@DriverFieldKids\empty
       \let\@@DriverFieldRoot\empty
       \let\@@DriverFieldMode\fieldcopymode
       \def\@@DriverFieldFree{0}%
       \def\@@DriverFieldAuto{0}%