summaryrefslogtreecommitdiff
path: root/tex/context/base/mkii/scrn-fld.mkii
diff options
context:
space:
mode:
Diffstat (limited to 'tex/context/base/mkii/scrn-fld.mkii')
-rw-r--r--tex/context/base/mkii/scrn-fld.mkii1247
1 files changed, 1247 insertions, 0 deletions
diff --git a/tex/context/base/mkii/scrn-fld.mkii b/tex/context/base/mkii/scrn-fld.mkii
new file mode 100644
index 000000000..993b510ea
--- /dev/null
+++ b/tex/context/base/mkii/scrn-fld.mkii
@@ -0,0 +1,1247 @@
+%D \module
+%D [ file=scrn-fld,
+%D version=1997.05.18,
+%D title=\CONTEXT\ Screen Macros,
+%D subtitle=Fields,
+%D author=Hans Hagen,
+%D date=\currentdate,
+%D copyright={PRAGMA ADE \& \CONTEXT\ Development Team}]
+%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 Screen Macros / Fields}
+
+% 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
+%D
+%D Beware, in \MKII\ we don't support autocloning for radiofields.
+
+\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}%
+ \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 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\@@DriverFieldLabel{#3}%
+ \else
+ \let\@@DriverFieldLabel\@@DriverFieldName
+ \fi
+ \ifx\@@DriverFieldType\empty
+ \writestatus\m!fields{unknown field #2}%
+ \else\ifcase\@@DriverFieldFree\relax
+ \doifdefinedelse{\strippedcsname\setupfield\@@DriverFieldGroup}
+ {\let\dosetupfield=#1\getvalue{\strippedcsname\setupfield\@@DriverFieldGroup}}
+ {#1[\@@DriverFieldName][\v!label,\v!frame,\v!horizontal][][][]}%
+\iftrialtypesetting\else
+ \def\@@DriverFieldFree{1}%
+ \changefield{#2}%
+\fi
+ \else\ifcase\@@DriverFieldAuto\relax
+ % \writestatus\m!fields{field #2 already typeset}%
+ \else
+ % \writestatus\m!fields{field #2 automatically copied}%
+ \nextsystemfield
+ \copyfield[\@@DriverFieldName][\currentsystemfield]%
+ \dotripleempty\dofield[#1][\currentsystemfield][#3]% get the if's right
+ \fi\fi\fi
+ \egroup
+ \fi}
+
+\def\typesetfield
+ {\useJSscripts[fld]%
+ \ifx\@@DriverFieldRoot\empty \else
+ \let\@@SavedFieldName\@@DriverFieldName
+ \getfield\@@DriverFieldRoot
+ \ifcase\@@DriverFieldFree\relax
+ \dosetfieldstatus\@@DriverFieldMode\@@DriverFieldParent\@@DriverFieldKids\@@DriverFieldRoot
+ \dopresetrecord
+\iftrialtypesetting\else
+ \def\@@DriverFieldFree{1}%
+ \changefield\@@DriverFieldName
+\fi
+ \fi
+ \getfield\@@SavedFieldName
+ \fi
+ \ifx\@@DriverFieldKids\empty
+ \donefalse
+ \else
+ \donetrue
+ \fi
+ \ifdone
+ \let\@@DriverFieldParent\@@DriverFieldName
+ %\addtocommalist\@@DriverFieldParent\@@DriverFieldKids
+ \appendtocommalist\@@DriverFieldParent\@@DriverFieldKids
+ \dosetfieldstatus\@@DriverFieldMode\@@DriverFieldParent\@@DriverFieldKids\@@DriverFieldRoot
+ \dopresetfield
+ \let\@@DriverFieldMode\fieldchildmode
+ \fi
+ \dosetfieldstatus\@@DriverFieldMode\@@DriverFieldParent\@@DriverFieldKids\@@DriverFieldRoot
+ \dopresetfield}
+
+\def\dopresetfield
+ {\iftrialtypesetting\else\iflocation\getvalue{preset\@@DriverFieldType field}\fi\fi}
+
+\def\dopresetrecord
+ {\iftrialtypesetting\else\iflocation\getvalue{preset\@@DriverFieldType 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\docommand##1{\dodosetupfield[##1][#2][#3][#4][#5]}%
+ \processcommalist[#1]\docommand
+ \else\ifthirdargument
+ \def\docommand##1{\dodosetupfield[##1][#2][][][#3]}%
+ \processcommalist[#1]\docommand
+ \else\ifsecondargument
+ \doifelse{#2}\v!reset
+ {\def\docommand##1{\donosetupfield[#1][][][][]}}
+ {\def\docommand##1{\dodosetupfield[##1][][][][#2]}}%
+ \processcommalist[#1]\docommand
+ \else\iffirstargument
+ \def\docommand##1{\dodosetupfield[##1][][][][]}%
+ \processcommalist[#1]\docommand
+ \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
+ {\resetfields}
+ {\setupfields[][][][#1]}% checken
+ \else
+ \writestatus\m!fields{provide either 1 or 4 arguments}%
+ \fi\fi}
+
+\def\setupfields
+ {\doquadrupleempty\dosetupfields}
+
+\def\resetfields
+ {\let\dodosetupfield\normaldodosetupfield}
+
+% \setupfields[\v!reset]
+
+% opties: veld, label, kader, vertikaal/horizontaal
+
+\newif\ifShowFieldLabel
+\newif\ifShowFieldFrame
+\newif\ifVerticalField
+\newif\ifHorizontalField
+
+% way to slow/complicated, we need some simple alternative
+% as well
+
+\def\dohandlefield[#1][#2][#3][#4][#5]%
+ {\presetlocalframed[\??fd]%
+ \processallactionsinset
+ [#2]
+ [ \v!reset=>\ShowFieldLabelfalse\ShowFieldFramefalse
+ \HorizontalFieldfalse\VerticalFieldfalse,
+ \v!label=>\ShowFieldLabeltrue,
+ \v!frame=>\ShowFieldFrametrue,
+ \v!horizontal=>\HorizontalFieldtrue,
+ \v!vertical=>\VerticalFieldtrue]%
+ \ifVerticalField
+ \getparameters[\??fd]
+ [\c!distance=\!!zeropoint,\c!inbetween=\vskip\@@localoffset,
+ \c!align=\v!right,\c!width=20em]%
+ \else\ifHorizontalField
+ \getparameters[\??fd]
+ [\c!distance=\@@localoffset,\c!inbetween=,\c!align=\c!left,
+ \c!height=10ex]%
+ \else
+ \getparameters[\??fd]
+ [\c!distance=\!!zeropoint,\c!inbetween=,\c!align=\c!left]%
+ \fi\fi
+ \getparameters[\??fd]
+ [\c!n=,\c!before=,\c!after=\vss,\c!style=,\c!color=,#3]%
+ \reshapeframeboxfalse % else ugly spacing
+ \ifShowFieldFrame
+ \localframed[\??fd][\c!strut=\v!no,\c!align=]\bgroup
+ \else
+ \vbox\bgroup
+ \fi
+ \dontcomplain
+ \ifShowFieldLabel
+ \setbox0\hbox
+ {\reshapeframeboxtrue % else wrong dimensions
+ \framed
+ [\c!style=,\c!color=,\c!align=\c!right,#4]
+ {\@@DriverFieldLabel}}%
+ \fi
+ \setbox2\hbox
+ {\reshapeframeboxtrue % else wrong dimensions
+ \ifVerticalField
+ \setupframed[\c!height=6ex,\c!width=\hsize]%
+ \else\ifHorizontalField
+ \setupframed[\c!height=\vsize,\c!width=20em]%
+ \else
+ \setupframed[\c!height=2cm,\c!width=2cm]%
+ \fi\fi
+ \framed
+ [\c!align=\v!right,\c!strut=\v!no,#5]
+ {\getparameters
+ [\??fd]
+ [\c!color=,\c!style=,\c!align=\v!right,\c!option=,
+ \c!clickin=,\c!clickout=,\c!regionin=,\c!regionout=,
+ \c!afterkey=,\c!format=,\c!validate=,\c!calculate=,
+ \c!focusin=,\c!focusout=,
+ \c!fieldoffset=\!!zeropoint,\c!fieldbackgroundcolor=,
+ \c!fieldframecolor=,\c!fieldlayer=\@@iafieldlayer,#5]%
+ \scratchdimen\framedwidth \edef\@@DriverFieldWidth {\the\scratchdimen}%
+ \scratchdimen\framedheight\edef\@@DriverFieldHeight{\the\scratchdimen}%
+ \vfill
+ \hbox{\lower\@@fdfieldoffset\hbox{\typesetfield}}
+ \vss}}%
+ \ifShowFieldLabel
+ \ifVerticalField
+ \vbox
+ {\copy0
+ \@@fdinbetween
+ \copy2}%
+ \else
+ \hbox
+ {\vbox \ifdim\ht2>\ht0 to \ht2 \fi
+ {\@@fdbefore
+ \copy0
+ \@@fdafter}%
+ \hskip\@@fddistance
+ \vbox \ifdim\ht0>\ht2 to \ht0 \fi
+ {\@@fdbefore
+ \box2
+ \@@fdafter}}%
+ \fi
+ \else
+ \box2
+ \fi
+ \egroup}
+
+\chardef\fitfieldmode\plusone % 3 = best
+
+\def\dohandlefitfield[#1][#2][#3][#4][#5]% alleen check
+ {\presetlocalframed[\??fd]%
+ \localframed
+ [\??fd]
+ [\c!n=1024, % beware: weblink plug in truncates
+ \c!strut=\v!no,\c!color=,\c!style=,\c!option=,
+ \c!clickin=,\c!clickout=,\c!regionin=,\c!regionout=,
+ \c!focusin=,\c!focusout=,
+ \c!afterkey=,\c!format=,\c!validate=,\c!calculate=,
+ \c!fieldoffset=\!!zeropoint,\c!fieldbackgroundcolor=,
+ \c!fieldframecolor=,\c!fieldlayer=\@@iafieldlayer,#5,\c!align=]
+ {\dogetcommacommandelement1\from\@@DriverFieldValues\to\@@DriverFieldValue
+ \ifx\@@DriverFieldValue\empty
+ \let\@@DriverFieldValue\@@DriverFieldDefault
+ \fi
+ \dopresetfieldsymbol\@@DriverFieldValue
+ \setbox\scratchbox\hbox{\dogetfieldsymbol\@@DriverFieldValue}%
+ \scratchdimen\wd\scratchbox \edef\@@DriverFieldWidth {\the\scratchdimen}%
+ \scratchdimen\ht\scratchbox \edef\@@DriverFieldHeight{\the\scratchdimen}%
+ \ifcase\fitfieldmode
+ \typesetfield
+ \or % 1 = ignore depth (original, assumed no depth, actually a bug)
+ \vbox to \ht\scratchbox{\vfill\hbox to \wd\scratchbox{\typesetfield\hfill}\vss}%
+ \or % 2 = add depth to height, but no depth in result
+ \advance\scratchdimen\dp\scratchbox \edef\@@DriverFieldHeight{\the\scratchdimen}%
+ \vbox to \ht\scratchbox{\vfill\hbox to \wd\scratchbox{\typesetfield\hfill}\vss}%
+ \or % 3 = add depth to height, and apply depth to result
+ \advance\scratchdimen\dp\scratchbox \edef\@@DriverFieldHeight{\the\scratchdimen}%
+ \hbox to \wd\scratchbox{\lower\dp\scratchbox\hbox{\typesetfield}\hfill}%
+ \fi}}
+
+%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%
+ {\dontleavehmode
+ \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!location=\v!low,\c!strut=\v!yes,\c!fieldoffset=0pt,
+ \c!height=1.2\openlineheight,\c!width=\dimen0,\c!offset=\v!overlay,
+ \c!style=,\c!align=\v!middle,\c!frame=\v!off,
+ \c!color=red,\c!fieldbackgroundcolor=\s!white,\c!fieldframecolor=blue,
+ \c!validate=JS(Check_Answer{\currentsystemfield,\therightanswer})]%
+ \switchtobodyfont
+ [\c!small]%
+ \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
+ {\dontcomplain
+ \nextsystemfield
+ \setbox0\hbox{#2}%
+ \definesymbol
+ [\currentsystemfield:txt]
+ [{\inframed[\c!frame=\v!off,\c!background=\v!screen]{#3}}]%
+ \setbox2\hbox{\symbol[\currentsystemfield:txt]}%
+ \definefield
+ [\currentsystemfield:txt][check]
+ [dummy][\currentsystemfield:txt][\currentsystemfield:txt]%
+ \setupfield
+ [dummy]
+ [\c!frame=\v!off,
+ \c!regionout=JS(Hide_Field{\currentsystemfield:txt}),
+ \c!option=\v!hidden]%
+ \hbox to \zeropoint
+ {\dimen0\wd2\advance\dimen0 -\wd0
+ \doifelse{#1}\v!left
+ {\hskip-\dimen0}
+ {\doif{#1}\v!middle
+ {\hskip-.5\dimen0}}%
+ \lower\openlineheight\hbox to \zeropoint
+ {\fitfield[\currentsystemfield:txt]}}%
+ \dimen0=\ifdim\wd0=\zeropoint 3em\else\wd0\fi
+ \definesymbol
+ [\currentsystemfield:but]
+ [{\framed[\c!height=2ex,\c!width=\dimen0,\c!frame=\v!off]{}}]%
+ \definefield
+ [\currentsystemfield:but][push]
+ [dummy][\currentsystemfield:but][\currentsystemfield:but]%
+ \setupfield
+ [dummy]
+ [\c!frame=\v!off,
+ \c!option=,
+ \c!regionin=JS(Vide_Field{\currentsystemfield:txt}),
+ \c!regionout=JS(Hide_Field{\currentsystemfield:txt}),
+ \c!fieldlayer=\@@iafieldlayer]%
+ \lower2ex\hbox to \zeropoint
+ {\fitfield[\currentsystemfield:but]}%
+ #2}%
+ \ht0\strutht\dp0\strutdp\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!empty][]%
+ \useJSscripts[fld][FieldStack]%
+ \newcounter\stackedfieldnumber
+ \def\dododofieldstack##1%
+ {\increment\stackedfieldnumber
+ \ifnum\stackedfieldnumber=\@@fdstart\relax
+ \definefield[#1:\stackedfieldnumber][check][#1][##1,\v!empty][##1]%
+ \else
+ \definefield[#1:\stackedfieldnumber][check][#1][##1,\v!empty][\v!empty]%
+ \fi}%
+ \processcommalist[#2]\dododofieldstack
+ \setupfield[#1][\v!reset]% added
+ \setupfield[#1][\c!option=\v!readonly,#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\@@frmethod}
+
+\setexecutecommandcheck {submitform} \checksubmitform
+
+\setupforms
+ [\c!method=HTML]
+
+%D Goodie:
+
+\def\definepushbutton % name optional setup
+ {\dodoubleempty\dodefinepushbutton}
+
+\def\dodefinepushbutton[#1][#2]% name setup
+ {\dododefinepushbutton{#1}{n}{push}%
+ \dododefinepushbutton{#1}{r}{\symbol[psym:#1:n]}%
+ \dododefinepushbutton{#1}{d}{\symbol[psym:#1:r]}%
+ \setvalue{pushbutton:#1}{\dohandlepushbutton{#1}{#2}}}
+
+\def\dododefinepushbutton#1#2#3%
+ {\doifsymboldefinedelse{psym:#1:#2}%
+ \donothing{\definesymbol[psym:#1:#2][{#3}]}}
+
+\def\definepushsymbol
+ {\dotripleargument\dodefinepushsymbol}
+
+\def\dodefinepushsymbol[#1][#2]% [#3]
+ {\definesymbol[psym:#1:#2]}
+
+\def\dopushbutton[#1][#2]%
+ {\executeifdefined{pushbutton:#1}\gobbleoneargument{#2}}
+
+\def\pushbutton
+ {\dodoubleargument\dopushbutton}
+
+\def\dohandlepushbutton#1#2#3% identifier setup script
+ {\bgroup
+ \nextsystemfield
+ \setupfield
+ [pushbutton]
+ [\c!frame=\v!overlay,
+ \c!offset=\v!overlay,
+ \c!clickout=#3,#2]%
+ \definefield
+ [\currentsystemfield]
+ [push]
+ [pushbutton]
+ [psym:#1:n,psym:#1:r,psym:#1:d]%
+ \fitfield
+ [\currentsystemfield]%
+ \egroup}
+
+% \def\do@@ampsh
+% {\dodoubleargument\dodo@@ampsh}
+%
+% \def\dodo@@ampsh[#1][#2]#3\\%
+% {\txt\pushbutton[#1][#2]\\}%
+%
+%\appendtoks \let\psh\do@@ampsh \to \everysetmenucommands
+
+\def\@@ampsh{\txt\pushbutton}
+
+\appendtoks \let\psh\@@ampsh \to \everysetmenucommands
+
+% \definepushbutton [reset]
+%
+% \definepushsymbol [reset] [n] [\uniqueMPgraphic{whatever}{color=green}]
+% \definepushsymbol [reset] [r] [\uniqueMPgraphic{whatever}{color=white}]
+%
+% \startinteractionmenu[bottom]
+% \psh [reset] [JS(reset_something)] \\
+% \stopinteractionmenu
+
+%D Another goodie:
+
+% \definecolor[rollover:n][red]
+% \definecolor[rollover:r][green]
+% \definecolor[rollover:d][blue]
+
+\definepalet
+ [rollover]
+ [n=red,
+ r=green,
+ d=blue]
+
+\newcounter\nofrollovers
+\newcounter\nofrollbuttons
+
+\def\dorollbutton[#1][#2]#3[#4]%
+ {\dontleavehmode
+ \bgroup
+ \doglobal\increment\nofrollovers
+ \doglobal\increment\nofrollbuttons
+ \unexpanded\def\dosetlocationbox[##1]##2[##3]%
+ {\getparameters[##1][##3]%
+ \definecolor[rollover][rollover:##2]%
+ \doifelse{##2}{n}{\doifelsevalue{##1\c!alternative}\v!hidden\phantom\hbox}\hbox
+ {\localframed[##1]
+ [\c!framecolor=rollover,\c!backgroundcolor=rollover,\c!color=rollover]%
+ {\dolocationattributes{##1}\c!style\c!color{#3}}}}%
+ \iffirstargument
+ \ifsecondargument
+ \def\setlocationbox##1{\dosetlocationbox[\??am#1]{##1}[#2]}%
+ \else
+ \doifassignmentelse{#1}
+ {\def\setlocationbox##1{\dosetlocationbox[\??bt]{##1}[#1]}}
+ {\def\setlocationbox##1{\dosetlocationbox[\??am#1]{##1}[]}}%
+ \fi
+ \else
+ \def\setlocationbox##1{\dosetlocationbox[\??bt]{##1}[]}%
+ \fi
+ % todo: share symbols, tricky since different dimensions
+ \definesymbol[rsym:\nofrollovers:n][\setlocationbox n]%
+ \definesymbol[rsym:\nofrollovers:r][\setlocationbox r]%
+ \definesymbol[rsym:\nofrollovers:d][\setlocationbox d]%
+ \setupfield
+ [rollbutton]
+ [\c!frame=\v!off,
+ \c!offset=\v!overlay,
+ \c!clickout={#4}]%
+ \definefield
+ [roll:\nofrollbuttons][push][rollbutton]
+ [rsym:\nofrollovers:n,%
+ rsym:\nofrollovers:r,%
+ rsym:\nofrollovers:d]%
+ \fitfield[roll:\nofrollbuttons]%
+ \egroup}
+
+\unexpanded\def\rollbutton
+ {\dodoubleempty\dorollbutton}
+
+\def\menu@rob[#1]#2\\%
+ {\txt\rollbutton[\currentmenu]{\ignorespaces#2\unskip}[#1]\\}%
+
+\appendtoks \let\rob\menu@rob \to \everysetmenucommands
+
+% calls:
+% {..} [JS..]
+% [left] {..} [JS..]
+% [a=b] {..} [JS..]
+% [left] [a=b] {..} [JS..]
+%
+% \setupbuttons[offset=0pt,frame=off] % alternative=hidden
+%
+% \rollbutton {Manuals} [JS(Goto_File{show-man.pdf})]
+% \rollbutton {Articles} [JS(Goto_File{show-art.pdf})]
+% \rollbutton {Papers} [JS(Goto_File{show-pap.pdf})]
+% \rollbutton {Presentations} [JS(Goto_File{show-pre.pdf})]
+% \rollbutton {Resources} [JS(Goto_File{show-res.pdf})]
+%
+% \rob [JS(...)] bla bla \\
+
+\unexpanded\def\overlayrollbutton
+ {\dodoubleargument\dooverlayrollbutton}
+
+\def\dooverlayrollbutton[#1][#2]%
+ {\bgroup
+ \nextsystemfield
+ \setupfield
+ [overlayrollbutton]
+ [\c!frame=\v!off,\c!offset=\v!overlay,\c!regionin={#1},\c!regionout={#2}]%
+ \definesymbol
+ [\currentsystemfield]
+ [{\framed[\c!frame=\v!off,\c!width=\overlaywidth,\c!height=\overlayheight]{}}]%
+ \definefield
+ [\currentsystemfield][push][overlayrollbutton][\currentsystemfield][\currentsystemfield]%
+ \fitfield[\currentsystemfield]%
+ \egroup}
+
+% \defineoverlay
+% [ShowMenu]
+% [{\overlayrollbutton[VideLayer{navigation}][HideLayer{navigation}]}]
+
+\protect \endinput