%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 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$]}

%D The interface to the specials. DEFAULT NOG ANDERS  

\def\presetlinefield
  {\dopresetlinefield
     {\@@FieldName}
     {\@@FieldWidth}
     {\@@FieldHeight}
     {\@@FieldDefault}  
     {\@@fdn}
     {\@@fdletter,\@@fdkleur,\@@fdveldachtergrondkleur,\@@fdveldkaderkleur}
     {\@@fdoptie}
     {\@@fduitlijnen}
     {\@@fdklikin,\@@fdklikuit,\@@fdgebiedin,\@@fdgebieduit,\@@fdnatoets,%
      \@@fdformatteer,\@@fdvalideer,\@@fdbereken,\@@fdfocusin,\@@fdfocusuit}}

\def\presettextfield
  {\dopresettextfield
     {\@@FieldName}
     {\@@FieldWidth}
     {\@@FieldHeight}
     {\@@FieldDefault}  
     {\@@fdn}
     {\@@fdletter,\@@fdkleur,\@@fdveldachtergrondkleur,\@@fdveldkaderkleur}
     {\@@fdoptie}
     {\@@fduitlijnen}
     {\@@fdklikin,\@@fdklikuit,\@@fdgebiedin,\@@fdgebieduit,\@@fdnatoets,%
      \@@fdformatteer,\@@fdvalideer,\@@fdbereken,\@@fdfocusin,\@@fdfocusuit}}

\def\presetchoicefield
  {\dopresetchoicefield
     {\@@FieldName}
     {\@@FieldWidth}
     {\@@FieldHeight}
     {\@@FieldDefault}  
     {\@@fdletter,\@@fdkleur,\@@fdveldachtergrondkleur,\@@fdveldkaderkleur}
     {\@@fdoptie}
     {\@@FieldValues}
     {\@@fdklikin,\@@fdklikuit,\@@fdgebiedin,\@@fdgebieduit,\@@fdnatoets,%
      \@@fdformatteer,\@@fdvalideer,\@@fdbereken,\@@fdfocusin,\@@fdfocusuit}}

\def\presetpopupfield
  {\dopresetpopupfield
     {\@@FieldName}
     {\@@FieldWidth}
     {\@@FieldHeight}
     {\@@FieldDefault}  
     {\@@fdletter,\@@fdkleur,\@@fdveldachtergrondkleur,\@@fdveldkaderkleur}
     {\@@fdoptie}
     {\@@FieldValues}
     {\@@fdklikin,\@@fdklikuit,\@@fdgebiedin,\@@fdgebieduit,\@@fdnatoets,%
      \@@fdformatteer,\@@fdvalideer,\@@fdbereken,\@@fdfocusin,\@@fdfocusuit}}

\def\presetcombofield
  {\dopresetcombofield
     {\@@FieldName}
     {\@@FieldWidth}
     {\@@FieldHeight}
     {\@@FieldDefault}  
     {\@@fdletter,\@@fdkleur,\@@fdveldachtergrondkleur,\@@fdveldkaderkleur}
     {\@@fdoptie}
     {\@@FieldValues}
     {\@@fdklikin,\@@fdklikuit,\@@fdgebiedin,\@@fdgebieduit,\@@fdnatoets,%
      \@@fdformatteer,\@@fdvalideer,\@@fdbereken,\@@fdfocusin,\@@fdfocusuit}}

\def\presetcheckfield
  {\presetfieldsymbols[\@@FieldValues]%
   \dopresetcheckfield
     {\@@FieldName}
     {\@@FieldWidth}
     {\@@FieldHeight}
     {\@@FieldDefault}  
     {\@@fdoptie}
     {\@@FieldValues}
     {\@@fdklikin,\@@fdklikuit,\@@fdgebiedin,\@@fdgebieduit,\@@fdnatoets,%
      \@@fdformatteer,\@@fdvalideer,\@@fdbereken,\@@fdfocusin,\@@fdfocusuit}}

\def\presetpushfield
  {%\edef\@@FieldValues{{\@@FieldValues}}% makes sure {a,b,c} is passed
   \presetfieldsymbols[\@@FieldValues]%
   \dopresetpushfield
     {\@@FieldName}
     {\@@FieldWidth}
     {\@@FieldHeight}
     {\@@FieldDefault}  
     {\@@fdoptie}
     {\@@FieldValues}
     {\@@fdklikin,\@@fdklikuit,\@@fdgebiedin,\@@fdgebieduit,\@@fdnatoets,%
      \@@fdformatteer,\@@fdvalideer,\@@fdbereken,\@@fdfocusin,\@@fdfocusuit}}

\def\presetradiofield
  {\presetfieldsymbols[\@@FieldValues]%
   \dopresetradiofield
     {\@@FieldName}
     {\@@FieldWidth}
     {\@@FieldHeight}
     {\@@FieldDefault}  
     {\@@fdoptie}
     {\@@FieldRoot}
     {\@@FieldValues}
     {\@@fdklikin,\@@fdklikuit,\@@fdgebiedin,\@@fdgebieduit,\@@fdnatoets,%
      \@@fdformatteer,\@@fdvalideer,\@@fdbereken,\@@fdfocusin,\@@fdfocusuit}}

\def\presetradiorecord
  {\dopresetradiorecord
     {\@@FieldName}
     {\@@FieldDefault}  
     {\@@fdoptie}
     {\@@FieldKids}
     {\@@fdklikin,\@@fdklikuit,\@@fdgebiedin,\@@fdgebieduit,\@@fdnatoets,%
      \@@fdformatteer,\@@fdvalideer,\@@fdbereken,\@@fdfocusin,\@@fdfocusuit}}

\def\setfieldmodes#1#2#3%
  {\xdef\@@FieldMode{#1}%  % 0 1 2 3 
   \xdef\@@FieldFree{#2}%  % 0 1 
   \xdef\@@FieldAuto{#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 
     {\noexpand\dosetfield{#1}{#2}{#3}{#4}{#5}{#6}{#7}{#8}{#9}}%
   \egroup}

\def\dosetfield#1#2#3#4#5#6#7#8#9%
  {\xdef\@@FieldName   {#1}%
   \xdef\@@FieldType   {#2}%
   \xdef\@@FieldRoot   {#3}%
   \xdef\@@FieldParent {#4}%
   \xdef\@@FieldKids   {#5}%
   \xdef\@@FieldGroup  {#6}%
   \setfieldmodes       #7%
   \bgroup
     \def\par{\string\n\string\n}%
     \xdef\@@FieldValues {#8}%
     \xdef\@@FieldDefault{#9}%
   \egroup}

\def\changefield#1%
  {\setfield{#1}\@@FieldType\@@FieldRoot\@@FieldParent\@@FieldKids\@@FieldGroup
     {\@@FieldMode\@@FieldFree\@@FieldAuto}\@@FieldValues\@@FieldDefault}

\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\@@FieldMode
          {\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=\@@FieldMode\space/ V=##8 / D=##9}}%
     \processcommacommand[\collectedfields]\getfield
   \fi
   \immediate\closeout\scratchwrite
   \egroup}

\def\logfields
  {\dosingleempty\doLogFields}

%D \starttypen    
%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 \stoptypen

\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 \starttypen
%D \def\getmainfieldkids#1%
%D   {\let\@@FieldKids\empty
%D    \ifdefinemainfield 
%D      \definetwopasslist{fld:#1}% defined by system 
%D      \doloop
%D        {\gettwopassdata{fld:#1}%
%D         \iftwopassdatafound
%D          %\addtocommalist\twopassdata\@@FieldKids
%D           \appendtocommalist\twopassdata\@@FieldKids
%D         \else
%D           \exitloop
%D         \fi}%
%D    \fi}
%D \stoptypen
%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 \starttypen
%D \def\getmainfieldkids#1%
%D   {\let\@@FieldKids\empty
%D    \ifdefinemainfield 
%D      \definerawpasslist{fld:#1}% runtime defined by system 
%D      \moverawpasslist{fld:#1}\@@FieldKids
%D    \fi}
%D \stoptypen
%D 
%D The data is written by file using: 
%D
%D \starttypen
%D \newcounter\nofmainfieldkids
%D
%D \def\setmainfieldkid#1#2%
%D   {\doglobal\increment\nofmainfieldkids
%D    \immediatewriteutilitycommand
%D      {\twopassentry%
%D         {fld:#1}%
%D         {\nofmainfieldkids}%
%D         {#2}}}
%D \stoptypen
%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\@@FieldKids\empty}
       {\@EA\let\@EA\@@FieldKids\csname\r!widget#1\endcsname}%
   \else
     \let\@@FieldKids\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\@@FieldKids\empty
               \let\@@FieldMode\fieldlonermode
             \else
               \let\@@FieldMode\fieldparentmode
             \fi
             \def\@@FieldAuto{1}%
           \else
             \let\@@FieldMode\fieldlonermode
             \def\@@FieldAuto{0}%
           \fi         
           \def\@@FieldFree{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}{}{}{\@@FieldKids}{#3}{\@@FieldMode\@@FieldFree\@@FieldAuto}{}{#4}}

\let\definetextfield=\definelinefield

\def\definechoicefield#1#2#3#4#5%
  {\doifelsenothing{#4}
     {\def\@@FieldValues{yes,no}}
     {\def\@@FieldValues{#4}}%
   \doifelsenothing{#5}
     {\dogetcommacommandelement2\from\@@FieldValues\to\@@FieldDefault
      \dogetcommacommandelement1\from\@@FieldDefault\to\@@FieldDefault}
     {\def\@@FieldDefault{#5}}%
   \setfield{#1}{#2}{}{}{\@@FieldKids}{#3}{\@@FieldMode\@@FieldFree\@@FieldAuto}{\@@FieldValues}{\@@FieldDefault}}

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

%\def\definecheckfield#1#2#3#4#5%
%  {\doifelsenothing{#4}
%     {\definedefaultsymbols  
%      \def\@@FieldValues{defaultyes}}
%     {\def\@@FieldValues{#4}}%
%   \doifelsenothing{#5}
%     {\dogetcommacommandelement2\from\@@FieldValues\to\@@FieldDefault
%      \dogetcommacommandelement1\from\@@FieldDefault\to\@@FieldDefault}
%     {\def\@@FieldDefault{#5}}%
%   \setfield{#1}{#2}{}{}{\@@FieldKids}{#3}{\@@FieldMode\@@FieldFree\@@FieldAuto}{\@@FieldValues}{\@@FieldDefault}}

%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\@@FieldValues{defaultyes}}
     {\def\@@FieldValues{#4}}%
   \doifelsenothing{#5}
     {\def\@@FieldDefault{2}}
     {\dogetcommacommandelement1\from\@@FieldValues\to\@@FieldDefault
      \doifinstringelse{#5}{\@@FieldDefault}
        {\def\@@FieldDefault{1}}
        {\def\@@FieldDefault{0}}}%   
   \setfield
     {#1}{#2}{}{}{\@@FieldKids}{#3}%
     {\@@FieldMode\@@FieldFree\@@FieldAuto}%
     {\@@FieldValues}{\@@FieldDefault}}

\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\@@FieldKids\empty
       \setfield{#1}{#2}{}{}{#4}{#3}{\@@FieldMode\@@FieldFree\@@FieldAuto}{}{\SavedFieldDefault}%
     \else
       \setfield{#1}{#2}{}{}{#4,\@@FieldKids}{#3}{\@@FieldMode\@@FieldFree\@@FieldAuto}{}{\SavedFieldDefault}%
     \fi
%
     \def\docommando##1%
       {\doifelse{##1}\SavedFieldDefault
          {\def\@@FieldDefault{##1}}% 
          {\let\@@FieldDefault\empty}%
        \setfield{##1}{#2}{#1}{}{}{#3}{\@@FieldMode\@@FieldFree\@@FieldAuto}{}{\@@FieldDefault}}%
% when opt works 
%     \def\docommando##1%
%       {\@EA\beforesplitstring##1\at=>\to\FieldValue
%        \doifelse\FieldValue\SavedFieldDefault
%          {\let\@@FieldDefault\FieldValue}% 
%          {\let\@@FieldDefault\empty}%
%        \setfield\FieldValue{#2}{#1}{}{}{#3}{\@@FieldMode\@@FieldFree\@@FieldAuto}{}{\@@FieldDefault}}%
     \processcommalist[#4]\docommando
  \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\docommando##1%
       {\getfield{##1}%
        \ifx\@@FieldType\empty 
          \writestatus\m!fields{unknown field ##1}% to do
        \else   
          \doifsomething{#2}
            {\edef\@@FieldGroup{#2}}%
          \doifelsenothing{#3}
            {\definedefaultsymbols  
             \def\@@FieldValues{defaultyes}}
            {\def\@@FieldValues{#3}}%
          \changefield{##1}%
        \fi}%
      \processcommalist[#1]\docommando
   \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\@@FieldType\empty
       \writestatus\m!fields{unknown field #1}%
     \else
       \let\@@FieldMode=\fieldparentmode
      %\def\docommando##1{\addtocommalist{##1}\@@FieldKids}%
       \def\docommando##1{\appendtocommalist{##1}\@@FieldKids}%
       \processcommalist[#2]\docommando
       \changefield{#1}%
       \let\@@FieldAutoParent\@@FieldAuto
       \def\@@FieldParent{#1}%
       \let\@@FieldKids\empty
       \let\@@FieldRoot\empty
       \let\@@FieldMode\fieldchildmode
       \def\@@FieldFree{0}%
       \def\@@FieldAuto{0}%
       \doifsomething{#3}{\edef\@@FieldGroup{#3}}%
       \doifsomething{#4}{\edef\@@FieldValues{#4}}%
       \def\docommando##1%
         {\ifcase\@@FieldAutoParent\else
            \setmainfieldkid{\@@FieldParent}{##1}%
          \fi
          \changefield{##1}}%
       \processcommalist[#2]\docommando
     \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\@@FieldType\empty
       \writestatus{\m!fields}{unknown field #1}%
     \else
       \let\@@FieldMode\fieldparentmode
      %\def\docommando##1{\addtocommalist{##1}\@@FieldKids}%
       \def\docommando##1{\appendtocommalist{##1}\@@FieldKids}%
       \processcommalist[#2]\docommando
       \changefield{#1}%
       \let\@@FieldAutoParent=\@@FieldAuto
       \def\@@FieldParent{#1}%
       \let\@@FieldKids\empty
       \let\@@FieldRoot\empty
       \let\@@FieldMode\fieldcopymode
       \def\@@FieldFree{0}%
       \def\@@FieldAuto{0}%
       \def\docommando##1%
         {\ifcase\@@FieldAutoParent\else
            \setmainfieldkid{\@@FieldParent}{##1}%
          \fi
          \changefield{##1}}%
       \processcommalist[#2]\docommando
     \fi
\fi
   \else
     \writestatus\m!fields{pass parent field and copies}%
   \fi}

\def\copyfield%
  {\dodoubleempty\docopyfield}

\unexpanded\def\field%
  {\dotripleempty\dofield[\dohandlefield]}

\unexpanded\def\fitfield%
  {\dotripleempty\dofield[\dohandlefitfield]}

\def\dofield[#1][#2][#3]%
  {\iffirstargument
     \bgroup
     \getfield{#2}%
     \ifsecondargument
       \def\@@FieldLabel{#3}%
     \else
       \let\@@FieldLabel\@@FieldName
     \fi
     \ifx\@@FieldType\empty
       \writestatus{\m!fields}{unknown field #2}%
     \else\ifcase\@@FieldFree\relax
       \doifdefinedelse{\strippedcsname\setupfield\@@FieldGroup}
         {\let\dosetupfield=#1\getvalue{\strippedcsname\setupfield\@@FieldGroup}}
         {#1[\@@FieldName][\v!label,\v!kader,\v!horizontaal][][][]}%
\iftrialtypesetting\else
       \def\@@FieldFree{1}%
       \changefield{#2}%
\fi
     \else\ifcase\@@FieldAuto\relax
     % \writestatus{\m!fields}{field #2 already typeset}%
     \else
     % \writestatus{\m!fields}{field #2 automatically copied}%
       \nextsystemfield
       \copyfield[\@@FieldName][\currentsystemfield]%
       \dotripleempty\dofield[#1][\currentsystemfield][#3]% get the if's right
     \fi\fi\fi
     \egroup
   \fi}

\def\typesetfield%
  {\useJSscripts[fld]%
   \ifx\@@FieldRoot\empty \else
     \let\@@SavedFieldName\@@FieldName
     \getfield\@@FieldRoot
     \ifcase\@@FieldFree\relax
       \dosetfieldstatus\@@FieldMode\@@FieldParent\@@FieldKids\@@FieldRoot
       \dopresetrecord
\iftrialtypesetting\else
       \def\@@FieldFree{1}%
       \changefield\@@FieldName
\fi
     \fi
     \getfield\@@SavedFieldName
   \fi
   \ifx\@@FieldKids\empty
     \donefalse
   \else
     \donetrue
   \fi
   \ifdone
     \let\@@FieldParent\@@FieldName
    %\addtocommalist\@@FieldParent\@@FieldKids
     \appendtocommalist\@@FieldParent\@@FieldKids
     \dosetfieldstatus\@@FieldMode\@@FieldParent\@@FieldKids\@@FieldRoot
     \dopresetfield
     \let\@@FieldMode\fieldchildmode
   \fi
   \dosetfieldstatus\@@FieldMode\@@FieldParent\@@FieldKids\@@FieldRoot
   \dopresetfield}

\def\dopresetfield
  {\iftrialtypesetting\else\iflocation\getvalue{preset\@@FieldType  field}\fi\fi}

\def\dopresetrecord
  {\iftrialtypesetting\else\iflocation\getvalue{preset\@@FieldType record}\fi\fi}

\def\dodefinethefieldset[#1][#2]% 
  {\dodefinefieldset{#1}{#2}}

\def\definefieldset%
  {\dodoubleargument\dodefinethefieldset}

\def\normaldodosetupfield[#1][#2][#3][#4][#5]%
  {\doifdefinedelse{\strippedcsname\setupfield#1}
     {\pushmacro\dosetupfield
      \def\dosetupfield[##1][##2][##3][##4][##5]%
        {\setvalue{\strippedcsname\setupfield#1}{\dosetupfield[#1][##2,#2][##3,#3][##4,#4][##5,#5]}}%
      \getvalue{\strippedcsname\setupfield#1}%
      \popmacro\dosetupfield}
     {\setvalue{\strippedcsname\setupfield#1}{\dosetupfield[#1][#2][#3][#4][#5]}}}

\let\dodosetupfield\normaldodosetupfield

\def\donosetupfield[#1][#2][#3][#4][#5]%
  {\setvalue{\strippedcsname\setupfield#1}{\dosetupfield[#1][#2][#3][#4][#5]}}

\def\dosetupfield[#1][#2][#3][#4][#5]%
  {\iffifthargument
     \def\docommando##1{\dodosetupfield[##1][#2][#3][#4][#5]}%
     \processcommalist[#1]\docommando
   \else\ifthirdargument
     \def\docommando##1{\dodosetupfield[##1][#2][][][#3]}%
     \processcommalist[#1]\docommando
   \else\ifsecondargument
     \doifelse{#2}{\v!reset}
       {\def\docommando##1{\donosetupfield[#1][][][][]}}
       {\def\docommando##1{\dodosetupfield[##1][][][][#2]}}%
     \processcommalist[#1]\docommando
   \else\iffirstargument
     \def\docommando##1{\dodosetupfield[##1][][][][]}%
     \processcommalist[#1]\docommando
   \else
     \writestatus{\m!fields}{provide either 1, 2, 3 or 5 arguments}%
   \fi\fi\fi\fi}

\def\setupfield%
  {\doquintupleempty\dosetupfield}

\def\dosetupfields[#1][#2][#3][#4]%
  {\ifsecondargument
     \def\dodosetupfield[##1][##2][##3][##4][##5]%
       {\doifdefinedelse{\strippedcsname\setupfield##1}
          {\def\dosetupfield[####1][####2][####3][####4][####5]%
             {\setvalue{\strippedcsname\setupfield##1}{\dosetupfield[##1][#1,####2,##2][#2,####3,##3][#3,####4,##4][#4,####5,##5]}}%
           \getvalue{\strippedcsname\setupfield##1}}
          {\setvalue{\strippedcsname\setupfield##1}{\dosetupfield[##1][#1,##2][#2,##3][#3,##4][#4,##5]}}}%
   \else\iffirstargument
     \doifelse{#1}{\v!reset}
       {\let\dodosetupfield\normaldodosetupfield}
       {\setupfields[][][][#1]}% checken 
   \else
     \writestatus{\m!fields}{provide either 1 or 4 arguments}%
   \fi\fi}

\def\setupfields%
  {\doquadrupleempty\dosetupfields}

% opties: veld, label, kader, vertikaal/horizontaal

\newif\ifShowFieldLabel
\newif\ifShowFieldFrame
\newif\ifVerticalField
\newif\ifHorizontalField

\def\dohandlefield[#1][#2][#3][#4][#5]%
  {\presetlocalframed[\??fd]%
   \processallactionsinset
     [#2]
     [      \v!reset=>\ShowFieldLabelfalse\ShowFieldFramefalse
                      \HorizontalFieldfalse\VerticalFieldfalse,
            \v!label=>\ShowFieldLabeltrue,
            \v!kader=>\ShowFieldFrametrue,
      \v!horizontaal=>\HorizontalFieldtrue,
        \v!vertikaal=>\VerticalFieldtrue]%
   \ifVerticalField
     \getparameters[\??fd]
       [\c!afstand=\!!zeropoint,\c!tussen=\vskip\@@localoffset,
        \c!uitlijnen=\v!rechts,\c!breedte=20em]%
   \else\ifHorizontalField
     \getparameters[\??fd]
       [\c!afstand=\@@localoffset,\c!tussen=,\c!uitlijnen=\c!links, 
        \c!hoogte=10ex]%
   \else
     \getparameters[\??fd]
       [\c!afstand=\!!zeropoint,\c!tussen=,\c!uitlijnen=\c!links]% 
   \fi\fi
   \getparameters[\??fd]
     [\c!n=,\c!voor=,\c!na=\vss,\c!letter=,\c!kleur=,#3]%
   \reshapeframeboxfalse % else ugly spacing 
   \ifShowFieldFrame
     \localframed[\??fd][\c!strut=\v!nee,\c!uitlijnen=]\bgroup
   \else
     \vbox\bgroup
   \fi
     \mindermeldingen
     \ifShowFieldLabel
       \setbox0=\hbox
         {\reshapeframeboxtrue % else wrong dimensions 
          \framed
            [\c!letter=,\c!kleur=,\c!uitlijnen=\c!rechts,#4]
            {\@@FieldLabel}}%
     \fi
     \setbox2=\hbox
       {\reshapeframeboxtrue % else wrong dimensions 
        \ifVerticalField
          \setupframed[\c!hoogte=6ex,\c!breedte=\hsize]%
        \else\ifHorizontalField
          \setupframed[\c!hoogte=\vsize,\c!breedte=20em]%
        \else
          \setupframed[\c!hoogte=2cm,\c!breedte=2cm]%
        \fi\fi
        \framed
          [\c!uitlijnen=\v!rechts,\c!strut=\v!nee,#5]
          {\getparameters
             [\??fd]
             [\c!kleur=,\c!letter=,\c!uitlijnen=\v!rechts,\c!optie=,
              \c!klikin=,\c!klikuit=,\c!gebiedin=,\c!gebieduit=,
              \c!natoets=,\c!formatteer=,\c!valideer=,\c!bereken=,
              \c!focusin=,\c!focusuit=,
              \c!veldoffset=\!!zeropoint,\c!veldachtergrondkleur=,
              \c!veldkaderkleur=,#5]%
            \dimen0=\framedwidth \edef\@@FieldWidth {\the\dimen0}% 
            \dimen0=\framedheight\edef\@@FieldHeight{\the\dimen0}% 
            \vfill
            \hbox{\lower\@@fdveldoffset\hbox{\typesetfield}}
            \vss}}%
     \ifShowFieldLabel
       \ifVerticalField
         \vbox
           {\copy0
            \@@fdtussen
            \copy2}%
       \else
         \hbox
           {\vbox \ifdim\ht2>\ht0 to \ht2 \fi
              {\@@fdvoor
               \copy0
               \@@fdna}%
            \hskip\@@fdafstand
            \vbox \ifdim\ht0>\ht2 to \ht0 \fi
              {\@@fdvoor
               \box2
               \@@fdna}}%
       \fi
     \else
       \box2
     \fi
   \egroup}

\def\dohandlefitfield[#1][#2][#3][#4][#5]% alleen check 
  {\presetlocalframed[\??fd]%
   \localframed
     [\??fd]
     [\c!n=1024, % beware: weblink plug in truncates
      \c!strut=\v!nee,\c!kleur=,\c!letter=,\c!optie=,
      \c!klikin=,\c!klikuit=,\c!gebiedin=,\c!gebieduit=,
      \c!focusin=,\c!focusuit=,
      \c!natoets=,\c!formatteer=,\c!valideer=,\c!bereken=,
      \c!veldoffset=\!!zeropoint,\c!veldachtergrondkleur=,
      \c!veldkaderkleur=,#5,\c!uitlijnen=]
     {\dogetcommacommandelement1\from\@@FieldValues\to\@@FieldValue
      \ifx\@@FieldValue\empty
        \let\@@FieldValue\@@FieldDefault
      \fi
      \dopresetfieldsymbol\@@FieldValue
      \setbox0=\hbox{\dogetfieldsymbol{\@@FieldValue}}%
      \dimen0=\wd0 \edef\@@FieldWidth {\the\dimen0}% 
      \dimen0=\ht0 \edef\@@FieldHeight{\the\dimen0}% 
      \vbox to \ht0 
        {\vfill\hbox to \wd0{\typesetfield\hfill}\vss}}}

%D Common stuff 

\newcounter\nofsystemfields

\def\nextsystemfield
  {\doglobal\increment\nofsystemfields
   \def\currentsystemfield{sys::\nofsystemfields}}

%D An example:

\def\fillinfield
  {\dosingleempty\dofillinfield}

\def\dofillinfield[#1]#2%
  {\leavevmode
   \hbox
     {\forgetall  
      \setupfields[\v!reset]%
      \nextsystemfield
      \useJSscripts[ans]% 
      \doifelsenothing{#1}
        {\def\therightanswer{#2}}
        {\def\therightanswer{#1}}%
      \setbox0=\hbox{#2}%
      \setbox2=\hbox{\therightanswer}%
      \dimen0=\ifdim\wd0>\wd2 \wd0 \else \wd2 \fi 
      \advance\dimen0 .2em
      \definefield
        [\currentsystemfield][line][systemfield]%
      \setupfield
        [systemfield]
        [\c!n=1024, % beware: weblink plugin truncates 
         \c!plaats=\v!laag,\c!strut=\v!ja,\c!veldoffset=0pt,
         \c!hoogte=1.2\openlineheight,\c!breedte=\dimen0,\c!offset=\v!overlay,
         \c!letter=,\c!uitlijnen=\v!midden,\c!kader=\v!uit,
         \c!kleur=red,\c!veldachtergrondkleur=white,\c!veldkaderkleur=blue,
         \c!valideer=JS(Check_Answer{\currentsystemfield,\therightanswer})]%
      \switchtobodyfont
        [\c!klein]%
      \hbox to \wd0
        {\copy0\hskip-\wd0\hss\field[\currentsystemfield]\hss}}}

%D and another one:

\def\tooltip%
  {\dosingleempty\dotooltip}

\def\dotooltip[#1]#2#3%
  {\bgroup 
   \setupfields[\v!reset]%
   \useJSscripts[fld]%
   \setbox0\hbox
     {\mindermeldingen
      \nextsystemfield
      \setbox0=\hbox{#2}%
      \definesymbol
        [\currentsystemfield:txt]
        [{\inframed[\c!kader=\v!uit,\c!achtergrond=\v!raster]{#3}}]%
      \setbox2=\hbox{\symbol[\currentsystemfield:txt]}%
      \definefield
        [\currentsystemfield:txt][check]
        [dummy][\currentsystemfield:txt][\currentsystemfield:txt]%
      \setupfield
        [dummy]
        [\c!kader=\v!uit,
         \c!gebieduit=JS(Hide_Field{\currentsystemfield:txt}),
         \c!optie=\v!verborgen]%
      \hbox to \zeropoint
         {\dimen0\wd2\advance\dimen0 -\wd0
          \doifelse{#1}\v!links
            {\hskip-\dimen0}
            {\doif{#1}\v!midden
               {\hskip-.5\dimen0}}%    
          \lower\openlineheight\hbox to \zeropoint
            {\fitfield[\currentsystemfield:txt]}}%
      \dimen0=\ifdim\wd0=\zeropoint 3em\else\wd0\fi
      \definesymbol
        [\currentsystemfield:but]
        [{\framed[\c!hoogte=2ex,\c!breedte=\dimen0,\c!kader=\v!uit]{}}]%
      \definefield
        [\currentsystemfield:but][push]
        [dummy][\currentsystemfield:but][\currentsystemfield:but]%
      \setupfield
        [dummy]
        [\c!kader=\v!uit,
         \c!optie=,
         \c!gebiedin=JS(Vide_Field{\currentsystemfield:txt}),
         \c!gebieduit=JS(Hide_Field{\currentsystemfield:txt})]%
       \lower2ex\hbox to \zeropoint
         {\fitfield[\currentsystemfield:but]}%
      #2}%
  \ht0=\ht\strutbox\dp0=\dp\strutbox\box0
  \egroup}

%D And one more: 

\def\definefieldstack%
  {\dotripleargument\dodefinefieldstack}

\def\dodefinefieldstack[#1][#2][#3]% name, symbols, settings 
  {\doifundefined{fieldstack:#1}
     {\setgvalue{fieldstack:#1}{\dodofieldstack[#1][#2][#3]}}}

\def\dodofieldstack[#1][#2][#3]% start=n, 0 == leeg 
  {\bgroup
   \getparameters[\??fd][\c!start=1,#3]%
   \setupfields[\v!reset]%
   \definesymbol[\v!leeg][]%
   \useJSscripts[fld][FieldStack]%
   \newcounter\stackedfieldnumber
   \def\dododofieldstack##1%
     {\increment\stackedfieldnumber
      \ifnum\stackedfieldnumber=\@@fdstart\relax
        \definefield[#1:\stackedfieldnumber][check][#1][##1,\v!leeg][##1]%
      \else
        \definefield[#1:\stackedfieldnumber][check][#1][##1,\v!leeg][\v!leeg]%
      \fi}%  
   \processcommalist[#2]\dododofieldstack
   \setupfield[#1][\v!reset]% added
   \setupfield[#1][\c!optie=\v!alleenleesbaar,#3]% #3 swapped 
   \newcounter\stackedfieldnumber
   \def\dododofieldstack##1%
     {\doglobal\increment\stackedfieldnumber
      \fitfield[#1:\stackedfieldnumber]\egroup\bgroup}% 
   \startoverlay
     \bgroup
     \globalprocesscommalist[#2]\dododofieldstack
     \egroup
   \stopoverlay
   \egroup}

\def\dofieldstack[#1][#2][#3]%
  {\ifsecondargument
     \dodefinefieldstack[#1][#2][#3]\fieldstack[#1]%
   \else
     \getvalue{fieldstack:#1}\setgvalue{fieldstack:#1}{[#1]}%
   \fi}

\def\fieldstack
  {\dotripleempty\dofieldstack}

%D When submitting a form, we need to tell the driver module
%D that we want \FDF\ or \HTML. 

\def\setupforms
  {\dodoubleargument\getparameters[\??fr]}

\def\checksubmitform#1%
  {\setsubmitoutputformat\@@frmethode}

\setexecutecommandcheck {submitform} \checksubmitform

\setupforms
  [\c!methode=HTML]

\protect

\endinput
