% \iffalse meta-comment
%
%% File: l3pdfpdffield-checkbox.dtx
%
% Copyright (C) 2021 The LaTeX Project
%
% It may be distributed and/or modified under the conditions of the
% LaTeX Project Public License (LPPL), either version 1.3c of this
% license or (at your option) any later version.  The latest version
% of this license is in the file
%
%    http://www.latex-project.org/lppl.txt
%
% This file is part of the "LaTeX PDF management testphase bundle" (The Work in LPPL)
% and all files in that bundle must be distributed together.
%
% -----------------------------------------------------------------------
%
% The development version of the bundle can be found at
%
%    https://github.com/latex3/pdfresources
%
% for those people who are interested.
%
%<*driver>
\RequirePackage{pdfmanagement-testphase}
\DeclareDocumentMetadata{}
\makeatletter
\declare@file@substitution{doc.sty}{doc-v3beta.sty}
\makeatother
\documentclass[full]{l3doc}
\usepackage{array,booktabs}
\usepackage{l3pdffield-testphase,bearwear}
\hypersetup{pdfauthor=The LaTeX Project,
 pdftitle=l3pdffield (LaTeX PDF management testphase bundle)}
\begin{document}
  \DocInput{\jobname.dtx}
\end{document}
%</driver>
% \fi
% \NewDocElement[
%   idxgroup=checkbox keys,
%   idxtype = {checkbox key},
%   printtype= \textit{checkbox key}
%    ]{Checkboxkey}{checkboxkey}
% \providecommand\hook[1]{\texttt{#1}}
% \ExplSyntaxOn
% \pdffield_store_appearance:nn {bear/Yes}
%  {
%    \tikz\bear\bearwear[shirt=red,body~deco={\node[font=\tiny\bfseries,white]~at~(beartummy){Yes};}];
%  }
% \pdffield_store_appearance:nn {bear/Off}
%  {
%   \tikz\bear\bearwear[body~deco={\node[font=\tiny\bfseries,white]~at~(beartummy){Off};}];
%  }
% \ExplSyntaxOff
% \title{^^A
%   The \pkg{l3pdffield} module\\ Commands to create form fields   ^^A
%   \\ \LaTeX{} PDF management testphase bundle
% }
%
% \author{^^A
%  The \LaTeX{} Project\thanks
%    {^^A
%      E-mail:
%        \href{mailto:latex-team@latex-project.org}
%          {latex-team@latex-project.org}^^A
%    }^^A
% }
%
% \date{Version 0.95c, released 2021-03-17}
%
% \maketitle
% \begin{documentation}
% \section{\pkg{l3pdffield} Introduction}
% The implementation of form fields in hyperref has some bugs, see for example
% \url{https://github.com/latex3/hyperref/issues/94}. This package is a first step
% towards the goal to review and improve the code of form fields.
%
% Like the \pkg{pdfmanagement-testphase} package itself it is a temporary package:
% the definite home of the code is not yet decided.
%
% It handles for now \emph{only} checkboxes, other form fields like pushbutton,
% radio buttons or text fields will follow later. As currently no fonts are used,
% it doesn't relies on the hyperref code
% to initialize the form, but it can be used with hyperref.
%
% The code requires the new PDF management. The code makes use of
% \pkg{l3pdfxform} to create the Xobjects. This code doesn't support yet the
% the dvips backend.
%
%
%
% Please keep in mind
% \begin{itemize}
% \item Not every PDF viewer supports checkboxes.
% \item The handling can depend on settings in the PDF viewer. In adobe reader for
% example I had to disable an option to avoid that it tries to create an appearance
% itself
% \item Standards like pdf/A disable form fields too (as you typically can't change the PDF).
% \end{itemize}
%
% If \pkg{hyperref} is loaded before
% the package will suppress the deprecated |/NeedAppearances| setting. If \pkg{hyperref}
% is loaded later you should do it in the \cs{Form} options.
%
% So a typical use together with hyperref could look like this
%
% \begin{verbatim}
% \RequirePackage{pdfmanagement-testphase}
% \DeclareDocumentMetadata{uncompress}
% \documentclass{article}
% \usepackage{hyperref}
% \usepackage{l3pdffield-testphase}
% \begin{document}
% \Form
% \end{verbatim}
% \section{Step 1: Checkboxes}
% Click me:
% \ExplSyntaxOn\pdffield_checkbox:n{name=bear,appearance=bear,width=23pt,height=30pt,depth=10pt}\ExplSyntaxOff
%
% \bigskip
% \subsection{Commands}
% \begin{function}{\pdffield_checkbox:n}
% \begin{syntax}
%  \cs{pdffield_checkbox:n}\Arg{key val list}
% \end{syntax}
% This creates a checkbox to check and uncheck. The list of allowed keys is described below.
% Typically the \meta{key val list} should at least set the name. Checkboxes with the same
% name belong to the same field and are checked and unchecked together. The default appearance
% is a quadratic frame with a \cs{texttimes} in it for the checked case.
% \end{function}
%
%\begin{function}{\pdffield_setup:nn}
% \begin{syntax}
%  \cs{pdffield_setup:nn}\Arg{field type}\Arg{key val list}
% \end{syntax}
% This allows to setup up values for following fields. \Arg{field type}
% should be a field, currently the only allowed value is |checkbox|.
% \end{function}
%
%\begin{function}{\pdffield_store_appearance:nn}
% \begin{syntax}
%  \cs{pdffield_store_appearance:nn}\Arg{name/state}\Arg{content}
% \end{syntax}
% This is a small wrapper around \cs{pdfxform_new:nn} and store appearances for the fields.
% \meta{state} should be for checkboxes either |Yes| or |Off| (and typically
% you should define both). \meta{name} is the name
% that is used in the |appearance| key, |checkbox/default| is predefined and so can't be used.
% \meta{content} is arbitrary content. The dimensions should fit to the planed size of the
% checkbox.%
% \end{function}
% \subsection{Keys}
%
% The new checkbox commands accepts following keys:
%
% \DescribeCheckboxkey{name} This sets the (internal) name of the field. It shouldn't contain
% a period, be not empty and sensibly consist of simple chars. Checkboxes instances
% with the same name belong to the same field and are checked and unchecked together.
%
% \DescribeCheckboxkey{altname} This sets an alternative name for user interaction.
% This name can only be set at the first checkbox instance, when the field is initialized.
% \DescribeCheckboxkey{mappingname} This sets an alternative name for export.
% This name can only be set at the first checkbox instance, when the field is initialized.
%
% \DescribeCheckboxkey{width}
% \DescribeCheckboxkey{height}
% \DescribeCheckboxkey{depth} These keys allow to set the dimensions of checkbox instance.
% The value should be a command that expands to a dimension expression. By default
% |width| and |height| use \cs{normalbaselineskip}, the |depth| is zero.
%
% \DescribeCheckboxkey{appearance} This key sets the normal appearance. It takes as value a
% \meta{name} and expects that the two appearances \meta{name}|/Yes| and \meta{name}|/Off|
% has been created with the command described below. The initial value is |checkbox/default|
% and shows a \cs{texttimes}.
%
% \DescribeCheckboxkey{rollover-appearance} This key sets the rollover appearance (when the
% mouse hovers over the checkbox). It takes as value a
% \meta{name} and expects that the two appearances \meta{name}|/Yes| and \meta{name}|/Off|
% has been created with the command described below. Initially this is not set.
% An empty value removes the entry.
%
% \DescribeCheckboxkey{down-appearance} This key sets the down appearance (when the
% mouse clicks). It takes as value a
% \meta{name} and expects that the two appearances \meta{name}|/Yes| and \meta{name}|/Off|
% has been created with the command described below. Initially this is not set.
% An empty value removes the entry.
%
% \DescribeCheckboxkey{checked} This is a boolean key which allows to set if the
% checkbox should be initially checked or not. It sets the |/V| and |/DV| key of the field
% and the |/AS| key of the annotation instance. It is possible to use different
% values for different instances, if one wants to confuse the user.
%
% \DescribeCheckboxkey{setfieldflags}
% \DescribeCheckboxkey{unsetfieldflags}
% These keys allow to set or unset the field flags.  They expect a comma lists of
% flag names. Allowed names |ReadOnly|, |Required|,
% |NoExport|, |Multiline|, |Password|,    |NoToggleToOff|, |Radio|, |Pushbotton|,
% |Combo|, |Edit|,   |Sort|, |FileSelect|,  |MultiSelect|, |DoNotSpellCheck|,
% |DoNotScroll|, |Comb|,  |RadiosInUnison|, |RichText|, |CommitOnSelChange|.
%
% From these |Radio|, |Pushbotton| are set automatically automatically by the code
% as this is required for a checkbox. Not every one from the rest makes sense for
% checkboxes but the same key will be used for other fields too.
% Check the PDF reference to decide which one to set or unset.
%
% \begin{checkboxkey}{keystroke,format,validate,calculate}
% These keys add the |/K, |/F, |/V|, |/C| key to the |/AA| dictionary of the field object.
% Their value should be javascript code. The |/AA| dictionary is suppressed
% if a pdf/A standard is set. These keys are probably not of much used with a checkbox.
% \end{checkboxkey}
%
% \vspace{2\baselineskip}
% \begin{checkboxkey}{onfocus,onblur,onmousedown,onmouseup,onenter,onexit}
% These keys adds the |/F, |/Bl, |/D|, |/U|, |E| and |X| key to the |/AA| dictionary
% of the widget  annotation (the checkbox instance) object.
% Their value should be javascript code. The |/AA| dictionary
% is suppressed if a pdf/A standard is set.
%
% For example
% \begin{verbatim}
%    onenter={app.alert('Hello');}
% \end{verbatim}
% \end{checkboxkey}
%
% \subsection{Using with hyperref}
% The \cs{CheckBox} command from hyperref also prints a label, something that the
% command here don't do. A redefinition like the following should allow to \cs{CheckBox}
% to use the commands of this module. Be aware that the behaviour will not be identical!
% Not every setting and key from \pkg{hyperref} has been copied.
%
% \begin{verbatim}
% \ExplSyntaxOn\makeatletter
% \def\@CheckBox[#1]#2{\LayoutCheckField{#2}{\pdffield_checkbox:n {name=#2,#1}}}
% \ExplSyntaxOff\makeatother
% \end{verbatim}
%
% \subsection{Some background}
% Form fields consist of a field object and number of instances of the field:
% A checkbox can appear on more than one page or location and if one instance
% is checked all other instances follows and are checked too.
%
% All instances are in this case widget annotations and are referenced in the Kid array of the field
% object\footnote{Fields can actually build a tree: between the root field and
% widget annotations there can be more fields. The last one before the widget is
% the \emph{terminal} field, but unless a sensible
% use case comes up, I will assume that the widget annotations are direct children of
% the root and that the root field is the terminal field.}.
% This means that the code has to collect all the children and write
% out the field object at the end of the document.
%
% If a field has only one children the content of the field dictionary and the
% widget annotation dictionary can be merged---some examples in the PDF reference
% show such merged dictionaries---but the code here keeps them separate, at the end
% this is clearer.
%
% All the root field objects must be referenced in the AcroForm dictionary in the
% Fields entry. This can be done with
%
% \begin{verbatim}
% \pdfmanagement_add:nnx{Catalog/AcroForm}{Fields}{<obj ref>}
% \end{verbatim}
%
% A checkbox has two different looks: checked and unchecked. The current hyperref
% implementation uses symbolic names for the two states and and adds some
% values with the /MK key and lets the PDF viewer
% create a look from them. But this doesn't work reliably. Also newer PDF versions
% deprecate the /NeedAppearances setting and require that such a look,
% an \enquote{appearance}, is given as form XObjects:
% such form XObjects are like small pictures stored in the PDF and can be referenced
% in various part of the PDF. They can be created with the commands of
% the \pkg{l3pdfxform} package.
%
% The checkbox instances---the widget annotations---cover a rectangular area on
% the page, the XObjects are squeezed into this rectangle. So for the best result
% both should have the same ratio of width and height.
% XObjects used as appearances can not be rotated, if needed one has to
% create a new appearance.
%
% \subsubsection{The field dictionary}
%
% The field dictionary shall or can have the following entries
%
% \begin{description}
% \item[FT] required for terminal fields (here for the root field),
%  the value is always \texttt{Btn}, so this entry is set by the code.
% \item[Parents] currently irrelevant as we don't have a field hierarchy.
% \item[Kids] an array. Contains references to the children, in our case to
% the widget annotations. The array is build by the code.
%
% \item[T] required, the name, a (unique) text string without a period.
% This field is a mandatory argument which must be given by the user.
% The value should be passed through a suitable string conversion and checked
% if it contains a period (which is not allowed).
%
% \item[TU,TM] optional, alternative names for user messages (TU) and export (TM).
% As these fields are optional they should be set by some key-val option.
%
% \item[Ff] A bitset, two flags must be unset for a checkbox (Radio and Pushbotton),
% for the rest we need a keyval interface.
%
% \item[V] describes the initial value, for checkboxes is should be either |/Yes|
%   or |/Off|. The initial value will be |/Yes|, keys are need to set both the local
%   and the default value.
%
% \item[DV] optional, the default value after a reset. Should  like |V| be either
% |/Yes| or |/Off|.
%
% \item[AA] An action dictionary. For this we need a special command to setup such
% dictionaries, so that they then can be used in various places.
%
% \end{description}
%
% \subsubsection{The widget annotation dictionary}
%
% \begin{description}
% \item[Type] Value: |/Annot|, set automatically
% \item[Subtype] Value: |/Widget| this is added automatically.
%  We use an internal dictionary which is locally copied over the one from l3pdfannot.
%  It can be filled with keyval options.
% \item[Parent] The reference to the field, automatically added.
% \item[Rect] the size, calculated from the box size
% \item[Contents] a text string, not really needed but an optional key should allow to
% set it,
% \item[AP] the appearance dictionary. It should look like this
%  |/AP <</N <</Yes 17 0 R/Off 15 0 R>>>>|. I need to test if it makes sense here to
%  have a |/R| and |/D| entry too. The objects refer to suitable xforms.
% \item[AS] should be either |/Yes| or |/Off|, and sensibly by default be
%  the same as the V entry in the field dictionary. If they differ the AS entry wins.
%
% \item[A] Action, this must be checked.
% \item[AA] additional actions. This must be checked too.
%
% \item[Border, C, OC, AF, BM, Lang, P, NM, M, F, BS, H]: These are not specifically
% needed for checkbox. An interface to add something to the used annot dictionary
% is needed (or already there), but probably no special key-val support for now.
%
% \item[MK] this is what hyperref uses to set the appearance, but I
%  explicitly leave it out and use |AP|.
%
% \item[Q] (alignment), used by hyperref but not relevant as we don't have variable
% text here.
% \end{description}
% \end{documentation}
%
% \begin{implementation}
% \section{\pkg{l3pdffield-checkbox} Implementation}
%    \begin{macrocode}
%<*package>
%<@@=pdffield>
\NeedsTeXFormat{LaTeX2e}
\ProvidesExplPackage{l3pdffield-testphase}{2021-03-17}{0.95c}%
  {form field checkboxes}
%    \end{macrocode}
% \subsection{hyperref specific command}
% hyperref sets NeedAppearances by default. As this is deprecated we disable this.
%    \begin{macrocode}
\csname HyField@NeedAppearancesfalse\endcsname % suppress NeedAppearances
% values from hyperref:
%\def\DefaultOptionsofCheckBox{print}
%\def\DefaultHeightofCheckBox{\normalbaselineskip}
%\def\DefaultWidthofCheckBox{\normalbaselineskip}
%    \end{macrocode}
% \subsection{local variables}
%    \begin{macrocode}
\str_new:N \l_@@_field_name_str
\str_new:N \l_@@_tmpa_str
\str_new:N \l_@@_name_tmpa_str
\tl_new:N \l_@@_keys_tmpa_tl
%    \end{macrocode}
%
% \subsection{messages}
%    \begin{macrocode}
\msg_new:nnn {pdffield}{no-period}
  {
    The~field~name~`#1`~contains~a~period. \\
    This~is~not~allowed. `
  }
\msg_new:nnn {pdffield}{empty-name}
  {
    The~field~name~is~empty. \\
    This~is~not~allowed. `
  }
\msg_new:nnn {pdffield}{appearance-missing}
  {
    The~appearance~`#1`~is~missing~for~the~#2~appearance.
  }
\msg_new:nnn {pdffield}{field-keys-ignored}
  {
    The~field~`#1`~is~already~initialized\\
    The~field~keys~`#2`~are~ignored.
  }
%    \end{macrocode}

% \subsection{bitsets}
% A bitset for the field flag Ff
% and an internal copy of the annot bitset.
%    \begin{macrocode}
\bitset_new:Nn \l_@@_Ff_bitset
 {
    ReadOnly          = 1,
    Required          = 2,
    NoExport          = 3,
    Multiline         = 13,%Tx
    Password          = 14,
    NoToggleToOff     = 15,%Btn, radio button
    Radio             = 16,%Btn: Radio:    15=1, 16=0
    Pushbutton        = 17,%Btn: Checkbox: 15=0, 16=0
                           %Btn: Pushbutton: 16=1
    Combo             = 18,%Ch: Combo=1 List=0
    Edit              = 19,%Ch, Combo=1 -> + edit field
    Sort              = 20,%Ch, not relevant for view...
    FileSelect        = 21,%Tx
    MultiSelect       = 22,%Ch
    DoNotSpellCheck   = 23,%Tx, Ch (if Combo + Edit set)
    DoNotScroll       = 24,%Tx
    Comb              = 25,%Tx, requires MaxLen in dict
    RadiosInUnison    = 26,%Btn Radio
    RichText          = 26,%Tx
    CommitOnSelChange = 27
  }

\bitset_new:Nn \l_@@_F_bitset
  {
    Invisible      = 1,
    Hidden         = 2,
    Print          = 3,
    NoZoom         = 4,
    NoRotate       = 5,
    NoView         = 6,
    ReadOnly       = 7,
    Locked         = 8,
    ToggleNoView   = 9,
    LockedContents = 10
  }
%    \end{macrocode}
% \subsection{The field dictionary}
% The field dictionary is the main object. It references the
% actual widget annotations as kids. It is created at the first
% checkbox with a specific name.
% To be able to set values from the outside it will use a
% dictionary which can be filled by key-val.
%    \begin{macrocode}
\pdfdict_new:n   {l_@@/checkbox/field}
\pdfdict_put:nnn {l_@@/checkbox/field}{FT}{/Btn}
%    \end{macrocode}
% We need to check if the name contains a dot. But we will do this in an external command
% to avoid to have it twice. Here we assume that the name is already converted and safe.
%
% We also assume that values that can be changed by the user are set outside
% in the dictionary.
% If the field object already exists nothing is done.
% \begin{macro}{\@@_checkbox_field_add:n}
% \begin{syntax}
% \cs{@@_checkbox_field_add:n}\Arg{name}
% \end{syntax}
% \meta{name} should be a PDF text string without period. It identifies the
% field.
%    \begin{macrocode}
\cs_new_protected:Npn \@@_checkbox_field_new:n #1
  {
      \group_begin:
      \pdf_object_new:nn {@@_checkbox/field/#1}      {dict}
      \pdf_object_new:nn {@@_checkbox/field/#1/Kids} {array}
      \seq_new:c {g_@@_checkbox/field/#1/Kids_seq}
      \hook_gput_code:nnn {shipout/lastpage}{pdffield} %xetex needs this ...
        {
          \pdf_object_write:nx {@@_checkbox/field/#1/Kids}
            {
              \seq_use:cn{g_@@_checkbox/field/#1/Kids_seq}{~}
            }
        }
      \pdfdict_put:nnn {l_@@/checkbox/field}{T}{(#1)}
     % V,DV are names describing the appearance. With checkboxes
     % the values /Yes and /Off are used.
     % this values are taken from the outside
      \pdfdict_put:nnx {l_@@/checkbox/field}
         {Kids}
         {
           \pdf_object_ref:n {@@_checkbox/field/#1/Kids}
         }
      \bitset_set_false:Nn \l_@@_Ff_bitset  {Radio}
      \bitset_set_false:Nn \l_@@_Ff_bitset  {Pushbutton}
      \pdfdict_put:nnx {l_@@/checkbox/field}
        {Ff}
        {\bitset_to_arabic:N \l_@@_Ff_bitset }
      \pdfdict_if_empty:nF{l_@@/checkbox/field/AA}
        {
          \pdfmeta_standard_verify:nT
            {annot_widget_no_AA}
            {
              \pdfdict_put:nnx
                {l_@@/checkbox/field}
                {AA}
                {<<\pdfdict_use:n {l_@@/checkbox/field/AA}>>}
            }
        }
      \pdf_object_write:nx {@@_checkbox/field/#1} { \pdfdict_use:n {l_@@/checkbox/field} }
      \pdfmanagement_add:nnx
        { Catalog / AcroForm }
        { Fields }
        {\pdf_object_ref:n {@@_checkbox/field/#1} }
      \group_end:
  }

%    \end{macrocode}
% \end{macro}
% \subsection{The annot dictionary}
% We assume that the annotation should really occupy space on the page and
% leave vertical mode.
% We also assume that keys like AP, AS are added before through keys to
% the dictionary.
% We use a local dictionary which is copied into |l__pdfannot/widget| in the code.
%    \begin{macrocode}
\pdfdict_new:n   {l_@@/checkbox/annot}
\pdfdict_put:nnn {l_@@/checkbox/annot}{Subtype}{/Widget}
%    \end{macrocode}
%
% \begin{macro}{\@@_checkbox_annot_add:nnnn}
%    \begin{macrocode}
\cs_new_protected:Npn \@@_checkbox_annot_add:nnnn #1 #2 #3 #4 %name, wd, ht, dp,
  {
    \group_begin:
%    \end{macrocode}
% Copy the internal dictionary to the pdfannot dictionary. This
% perhaps need a function in l3pdfannot,
% as it actually uses an internal name of another module.
%    \begin{macrocode}
    \pdfdict_put:nnx {l_@@/checkbox/annot}{AP}{<<\pdfdict_use:n{l_@@/checkbox/annot/AP}>>}
    \pdfmeta_standard_verify:nF
      {annot_flags}
      {
        \bitset_set_true:Nn  \l_@@_F_bitset {Print}
        \bitset_set_false:Nn \l_@@_F_bitset {Hidden}
        \bitset_set_false:Nn \l_@@_F_bitset {Invisible}
        \bitset_set_false:Nn \l_@@_F_bitset {NoView}
      }
    \pdfdict_if_empty:nF{l_@@/checkbox/annot/AA}
      {
        \pdfmeta_standard_verify:nT
         {annot_widget_no_AA}
         {
            \pdfdict_put:nnx
              {l_@@/checkbox/annot}
              {AA}
              {<<\pdfdict_use:n {l_@@/checkbox/annot/AA}>>}
         }
      }
    \pdfdict_put:nnx {l_@@/checkbox/annot}{F}{ \bitset_to_arabic:N \l_@@_F_bitset }
    \pdfdict_set_eq:nn {l__pdfannot/widget}{l_@@/checkbox/annot}
    \pdfannot_dict_put:nnx {widget}{Parent}{\pdf_object_ref:n{@@_checkbox/field/#1}}
    \mode_leave_vertical:
    \hbox_to_wd:nn
      { #2  }
      {
        \rule [-#4]{0pt}{\dim_eval:n{#3+#4} }
        \pdfannot_widget_box:nnn
           { #2 }
           { #3 }
           { #4 }
         \hfill
      }
    \seq_gput_right:cx {g_@@_checkbox/field/#1/Kids_seq}{ \pdfannot_box_ref_last:}
    \group_end:
  }

%    \end{macrocode}
% \end{macro}
% \subsection{Appearances}
% We don't try to force a size or content here.
% The default appearances are a cross (\cs{texttimes}),
% Every appearance should have two versions and follow the naming
% checkbox/\meta{name}/Yes and checkbox/\meta{name}/Off.
% TODO check if one delay the creation to a sensible place
% (and don't forget that the appearance key sets an initial
% value)
%  \begin{macro}{\pdffield_store_appearance:nn,\@@_store_default_appearances:}
%    \begin{macrocode}
\cs_new_protected:Npn \pdffield_store_appearance:nn #1 #2
  {
     \pdfxform_new:nnn {@@_#1}{}{#2}
  }

\cs_new_protected:Nn \@@_store_default_appearances:
  {
     \pdffield_store_appearance:nn {checkbox/default/Yes}
       {
         \normalsize
         \fboxsep 0pt
         \framebox
           [ \dim_eval:n { \box_ht:N\strutbox+\box_dp:N\strutbox } ]
           { \texttimes \strut }
       }
     \pdffield_store_appearance:nn {checkbox/default/Off}
       {
         \normalsize
         \fboxsep 0pt
         \framebox
           [ \dim_eval:n { \box_ht:N\strutbox+\box_dp:N\strutbox } ]
           { \phantom{\texttimes} \strut }
       }
  }

\@@_store_default_appearances:
%    \end{macrocode}
% \end{macro}
% We define a dictionary for the AP content, so that we can add R and D too
%    \begin{macrocode}
\pdfdict_new:n   {l_@@/checkbox/annot/AP}
%    \end{macrocode}
%
% \subsection{Assembling the checkbox}
% \begin{macro}{\@@_checkbox_add:n}
%    \begin{macrocode}

\cs_new_protected:Npn \@@_checkbox_add:n #1
  {
    \group_begin:
    \keys_set_filter:nnnN {pdffield / checkbox }{field}{#1}\l_@@_keys_tmpa_tl
    \str_if_empty:NT \l_@@_field_name_str
      {
        \msg_error:nn {pdffield}{empty-name}
      }
    \exp_args:Nx
      \pdf_object_if_exist:nTF {@@_checkbox/field/\l_@@_field_name_str}
       {
          \tl_if_empty:NF \l_@@_keys_tmpa_tl
           {
             \msg_warning:nnxx
               {pdffield}
               {field-keys-ignored}
               {\l_@@_field_name_str}
               {\l_@@_keys_tmpa_tl}
           }
       }
       {
         \keys_set:nV { pdffield/checkbox } \l_@@_keys_tmpa_tl
         \exp_args:No
         \@@_checkbox_field_new:n {\l_@@_field_name_str}
       }
    \exp_args:No
      \@@_checkbox_annot_add:nnnn
        {\l_@@_field_name_str}
        {\l_@@_annot_wd_tl }
        {\l_@@_annot_ht_tl }
        {\l_@@_annot_dp_tl }
    \group_end:
  }
%    \end{macrocode}
% \end{macro}
% \subsection{Keys}
% The size of the checkbox
%
%    \begin{macrocode}
\tl_new:N \l_@@_annot_ht_tl
\tl_new:N \l_@@_annot_wd_tl
\tl_new:N \l_@@_annot_dp_tl

\keys_define:nn { pdffield / checkbox }
  {
    ,width  .tl_set:N = \l_@@_annot_wd_tl
    ,height .tl_set:N = \l_@@_annot_ht_tl
    ,depth  .tl_set:N = \l_@@_annot_dp_tl
    ,width  .initial:n = \normalbaselineskip
    ,height .initial:n = \normalbaselineskip
    ,depth  .initial:n = 0pt
  }
%    \end{macrocode}
% The names. The main name should not be empty, it is added to the dictionary
% when the field is created. A new name means a new field.
% The other names can only be set when the field is created,
% so we put them in the field group.
%    \begin{macrocode}
\keys_define:nn { pdffield / checkbox }
  {
    ,name .code:n =
      {
        \pdf_string_from_unicode:nnN {utf8/string-raw}{#1}\l_@@_field_name_str
        \str_if_in:NnT \l_@@_field_name_str {.}
          {
            \msg_error:nnx {pdffield}{no-period}{\l_@@_field_name_str}
          }
        \str_if_empty:NT\l_@@_field_name_str
          {
            \msg_error:nn {pdffield}{empty-name}
          }
      }
    ,name .value_required:n = true
    ,name .initial:n = checkbox
    ,altname .code:n =
      {
        \pdf_string_from_unicode:nnN {utf8/string}{#1}\l_@@_name_tmpa_str
        \pdfdict_put:nnx { l_@@/checkbox/field }{TU}{\l_@@_name_tmpa_str}
      }
    ,altname .groups:n = {field}
    ,mappingname .code:n =
      {
        \pdf_string_from_unicode:nnN {utf8/string}{#1}\l_@@_name_tmpa_str
        \pdfdict_put:nnx { l_@@/checkbox/field }{TM}{\l_@@_name_tmpa_str}
      }
    ,mappingname .groups:n = {field}
  }
%    \end{macrocode}

% A key to decide if the Box is initially checked or not
%    \begin{macrocode}
\keys_define:nn { pdffield / checkbox }
 {
   ,checked .choice:
   ,checked / false .code:n =
     {
       \pdfdict_put:nnn {l_@@/checkbox/field}{V}{/Off}
       \pdfdict_put:nnn {l_@@/checkbox/annot}{AS}{/Off}
       \pdfdict_put:nnn {l_@@/checkbox/field}{DV}{/Off}
     }
   ,checked / true .code:n =
     {
       \pdfdict_put:nnn {l_@@/checkbox/field}{V}{/Yes}
       \pdfdict_put:nnn {l_@@/checkbox/annot}{AS}{/Yes}
       \pdfdict_put:nnn {l_@@/checkbox/field}{DV}{/Yes}
     }
   ,checked .default:n = {true}
   ,checked .initial:n = {false}
 }
%    \end{macrocode}
% Flags. We don't add lots of individual keys but mapped the key names directly
%    \begin{macrocode}
\keys_define:nn { pdffield / checkbox }
  {
    ,setfieldflags .code:n =
      {
          \clist_map_inline:nn {#1}
           {
             \bitset_set_true:Nn \l_@@_Ff_bitset {##1}
           }
      }
    ,setfieldflags .groups:n = {field}
    ,unsetfieldflags .code:n =
      {
          \clist_map_inline:nn {#1}
           {
             \bitset_set_false:Nn \l_@@_Ff_bitset {##1}
           }
      }
    ,unsetfieldflags .groups:n = {field}
    ,setannotflags .code:n =
      {
          \clist_map_inline:nn {#1}
           {
             \bitset_set_true:Nn \l_@@_F_bitset {##1}
           }
      }
    ,unsetannotflags .code:n =
      {
          \clist_map_inline:nn {#1}
           {
             \bitset_set_false:Nn \l_@@_F_bitset {##1}
           }
      }
  }

\keys_define:nn { pdffield / checkbox }
  {
    appearance .code:n = %value is a name of an appearance
      {
        \pdfxform_if_exist:nTF {  @@_#1/Yes }
          {
            \pdfdict_put:nnn {l_@@/checkbox/annot/AP}
              {N}
              {
                 <<
                    /Yes ~ \pdfxform_ref:n { @@_#1/Yes}
                    /Off ~ \pdfxform_ref:n { @@_#1/Off}
                 >>
              }
          }
          {
            \msg_error:nnnn{pdffield}{appearance-missing}{#1}{normal}
          }
      },
    appearance .initial:n = checkbox/default,
  }

\keys_define:nn { pdffield / checkbox }
  {
    rollover-appearance .code:n = %value is a name of an appearance
      {
       \tl_if_empty:nTF {#1}
         {
           \pdfdict_remove:nn {l_@@/checkbox/annot/AP} {R}
         }
         {
           \pdfxform_if_exist:nTF {  @@_#1/Yes }
             {
               \pdfdict_put:nnn {l_@@/checkbox/annot/AP}
                 {R}
                 {
                    <<
                       /Yes ~ \pdfxform_ref:n { @@_#1/Yes}
                       /Off ~ \pdfxform_ref:n { @@_#1/Off}
                    >>
                 }
              }
              {
                \msg_warning:nnnn{pdffield}{appearance-missing}{#1}{rollover}
              }

         }
      },
  }

\keys_define:nn { pdffield / checkbox }
  {
    down-appearance .code:n = %value is a name of an appearance
      {
       \tl_if_empty:nTF {#1}
         {
           \pdfdict_remove:nn {l_@@/checkbox/annot/AP} {D}
         }
         {
           \pdfxform_if_exist:nTF {  @@_#1/Yes }
            {
              \pdfdict_put:nnn {l_@@/checkbox/annot/AP}
                {D}
                {
                   <<
                      /Yes ~ \pdfxform_ref:n { @@_#1/Yes}
                      /Off ~ \pdfxform_ref:n { @@_#1/Off}
                   >>
                }
            }
            {
              \msg_warning:nnnn{pdffield}{appearance-missing}{#1}{down}
            }
         }
      },
  }
%    \end{macrocode}
%
%  Keys for the AA dictionary. They all trigger javascript option.
%  \begin{macro}{\@@_define_AAaction_key:nnn}
%    \begin{macrocode}
\pdfdict_new:n {l_@@/checkbox/annot/AA}
\pdfdict_new:n {l_@@/checkbox/field/AA}

\cs_new_protected:Npn \@@_define_AAaction_key:nnn #1 #2 #3 %#1 key, #2 pdf, #3 dict
  {
    \keys_define:nn { pdffield / checkbox }
      {
         #1 .code:n =
           {
             \pdf_string_from_unicode:nnN {utf8/string}{##1}\l_@@_tmpa_str
             \str_if_empty:NTF \l_@@_tmpa_str
               {
                 \pdfdict_remove:nn {l_@@/checkbox/#3/AA}{#2}
               }
               {
                 \pdfdict_put:nnx {l_@@/checkbox/#3/AA}
                  {#2}
                  {<</S/JavaScript/JS\l_@@_tmpa_str>>}
               }
           },
        #1 .groups:n = {#3}
      }
  }
\@@_define_AAaction_key:nnn {keystroke}{K}{field}
\@@_define_AAaction_key:nnn {format}   {F}{field}
\@@_define_AAaction_key:nnn {validate} {V}{field}
\@@_define_AAaction_key:nnn {calculate}{C}{field}
\@@_define_AAaction_key:nnn {onfocus}  {Fo}{annot}
\@@_define_AAaction_key:nnn {onblur}   {Bl}{annot}
\@@_define_AAaction_key:nnn {onmousedown}{D}{annot}
\@@_define_AAaction_key:nnn {onmouseup}{U}{annot}
\@@_define_AAaction_key:nnn {onenter}  {E}{annot}
\@@_define_AAaction_key:nnn {onexit}   {X}{annot}
%    \end{macrocode}
% \end{macro}
% \subsection{user commands}
% \begin{macro}{\pdffield_checkbox:n,\pdffield_setup:nn}
%    \begin{macrocode}
\cs_set_eq:NN \pdffield_checkbox:n \@@_checkbox_add:n

\cs_new_protected:Npn \pdffield_setup:nn #1 #2
 {
   \keys_set:nn {pdffield / #1 } {#2}
 }
%</package>
%    \end{macrocode}
% \end{macro}
%\end{implementation}

\endinput%
%%%%
%
%Field dict
%Ft     : /Btn /Tx /Ch /Sig
%Parent : OR
%Kids: array, other fields or annot/widget
%T: partial fieldname (test string)
%TU: alternate description (test string)
%TM: mapping name
%Q integer (variable text field)
%Ff: flags ->pdffield/checkbox/field
%V: value            % not pushbutton
%DV: default value   % not pushbutton
%AA: Action dict ... -> see below
%Opt: array of strings, connected to kids
%     or for choices, choices
%TI integer (lists)
%I array Ch (complicated ...)
%
%/DA ( 0 0 1 rg /Ti 12 Tf ) %text field
%/MaxLen                    %text field
%
%Lock dict (Sig)
%SV dict (Sig)
%
%
%
%
%Connected widget:
%/AS default appearance from AP ( here/Yes or /Off)
%% Appearance
%%checkbox
%/AP <</N <</Yes 2 0 R /Off 3 0 R>>>>
%/C / Border /BS
%
%/OC ?
%/Structparens?
%/F flags
%
%
%AA: Submit:
%  /S   /SubmitForm
%  /F   file /URI (/F ( ftp : / / www . beatles . com / Movies / AbbeyRoad . mov )
%  /Fields array
%
%  /S /ImportData
%  /F file
%
%  /S /ResetData
%  /Fields array
%
%  /S /JavaScript
%  /JS text string or stream
%  %\pdf_flag_new:nn {annot/field/submit} %name is wrong ...
%  {
%    Include/Exclude       = 0,
%    IncludeNoValueFields  = 1,
%    ExportFormat          = 2,
%    GetMethod             = 3, % if ExportFormat=0 -> =0 to
%    SubmitCoordinates     = 4, % if ExportFormat=0 -> =0 to
%    XFDF                  = 5,
%    IncludeAppendSaves    = 6,
%    IncludeAnnotations    = 7,
%    SubmitPDF             = 8,
%    CanonicalFormat       = 9,
%    ExclNonUserAnnots     = 10,
%    ExclFKey              = 11,
%    EmbedForm             = 12
%  }
% source: %adapted from https://chat.stackexchange.com/transcript/message/54421537#54421537
