% \iffalse meta-comment
%
%% File: l3pdfpdffield-checkbox.dtx
%
% Copyright (C) 2021-2025 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>
\DocumentMetadata{}
\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_appearance:nn {pdffield/bear/Yes}
%  {
%    \tikz\bear\bearwear[shirt=red,body~deco={\node[font=\tiny\bfseries,white]~at~(beartummy){Yes};}];
%  }
% \pdffield_appearance:nn {pdffield/bear/Off}
%  {
%   \tikz\bear\bearwear[body~deco={\node[font=\tiny\bfseries,white]~at~(beartummy){Off};}];
%  }
% \ExplSyntaxOff
% \title{^^A
%   The \pkg{l3pdffield-checkbox} module\\ Commands to create checkbox 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.96r, released 2025-05-15}
%
% \maketitle
% \begin{documentation}
% \section{\pkg{l3pdffield-checkbox} Introduction}
% This is the documentation for checkbox fields, for general information about form fields
% check the documentation l3pdffield.
%
%
%
% 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 features of form fields too
% (as you typically can't change the PDF).
% \end{itemize}
% \section{Checkboxes}
% Click me:
% \ExplSyntaxOn
%  \pdffield_checkbox:n{name=bear,appearance=pdffield/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.
% The \meta{key val list} should at least set the name, without it the default name
% |checkbox| is used. 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.
% The default appearance is setup at the first use and will use the font family
% active at that time.
% \end{function}
%
%
% \subsection{Keys}
%
% The new checkbox command accept all field and annot keys from l3pdffield.
% A few keys are disabled or are forced to specific values.
% The |appearance| keys have a more checkbox specific
% behaviour, other keys have other defaults than with the basic commands.
% Additionally there
% are a small number of keys specific  to a checkbox.
% For convenience a number of important keys are documented here too, even if
% they are already in the document from l3pdffield.
%
%
% Disabled keys are
%  \begin{itemize}
%  \item |V|, |DV|, |AS|: use |checked| instead.
%  \item |FT| is overwritten.
%  \item For checkboxes only the field flags  |ReadOnly|, |Required| and |NoExport|
%   make sense.
%  |Radio|, |Pushbotton| are set automatically automatically by the code
% as this is required for a checkbox.
%  \end{itemize}
%
% \begin{function}{preset-checkbox}
%  \begin{syntax}
%   |preset-checkbox| = \Arg{key-val-list}
%  \end{syntax}
% This allows to set default keys for a checkbox.
% \end{function}
%
% \begin{function}{name,T}
%  \begin{syntax}
%   |name| = \meta{partial name}\\
%   |T| = \meta{partial name}
%  \end{syntax}
% This sets the partial name of the field. The value
% shouldn't contain a period, be not empty and sensibly consist of simple chars.
% Additionally the value is used to create the field ID.
% This means that checkboxes with the same partial name are annotations
% with the same field as parent and are checked and unchecked together---this
% what is typically expected.
% The field ID is then internal and can not be used to
% attach another annotation.
% For explicit control of the field ID  use the |fieldID| key.
% \end{function}
%
% \begin{function}{fieldID}
%  \begin{syntax}
%   |fieldID| = \meta{field ID}\\
%  \end{syntax}
% \emph{For experts only!}
% This allows to give the checkbox field a specific ID. This is only useful
% in the context of a larger fieldset, if for example you want to use
% the same partial name for more than one field, or if you want to attach another annotation
% to the field with \cs{pdffield_annot:n}. If used wrongly you can
% easily create invalid fieldset. It allows you to create to fields with the
% same partial name, but if you want to see both
% you need to ensure that their full names are
% different---for example by adding some parent fields.
% \end{function}
%
% \begin{function}{parent}
%  \begin{syntax}
%   |parent| = \meta{field ID}\\
%  \end{syntax}
% This is only needed if the field should be part
% of a larger fieldset. The value should be a field ID of a field created previously
% with \cs{pdffield_field:nn}.
% \end{function}
%
% \begin{function}{altname,TU}
%  \begin{syntax}
%   |altname| = \meta{string}\\
%   |TU| = \meta{string}\\
%  \end{syntax}
% This is sets an alternative name for user interaction.
% This name can only be set at the first checkbox instance, when the field is initialized.
% \end{function}
%
% \begin{function}{mappingname,TM}
%  \begin{syntax}
%   |mappingname| = \meta{string}\\
%   |TM| = \meta{string}\\
%  \end{syntax}
% This is sets an alternative name for export.
% This name can only be set at the first checkbox instance, when the field is initialized.
% \end{function}
%
% \begin{function}{width,height,depth}
% \begin{syntax}
% |width| = \meta{dim expression}\\
% |height| = \meta{dim expression}\\
% |depth| = \meta{dim expression}
% \end{syntax}
% These keys allow to set the dimensions of checkbox instance.
% The value should be a dimension expression. By default
% |width| and |height| use \cs{normalbaselineskip}, the |depth| is zero.
% \end{function}
%
% \begin{function}{AP/N,appearance,AP/R,rollover-appearance,AP/D,down-appearance}
%  \begin{syntax}
%   |AP/N| = \meta{partial appearance name}\\
%   |appearance| = \meta{partial appearance name}\\
%   |AP/R| = \meta{partial appearance name}\\
%   |rollover-appearance| = \meta{partial appearance name}\\
%   |AP/D| = \meta{partial appearance name}\\
%   |down-appearance| = \meta{partial appearance name}
%  \end{syntax}
% This keys sets the normal appearance, the rollover appearance (when the
% mouse hovers over the checkbox) and the down appearance (when the
% mouse clicks). They take as value a
% \meta{partial appearance name} and expects that \emph{two} form Xobjects
% \meta{partial appearance name}|/Yes| and \meta{partial appearance name}|/Off|
% has been created. The initial value is |pdffield/checkbox/default|
% for the normal appearance and shows a \cs{texttimes}.
% The other appearances are not set by default.
% \end{function}
%
% \begin{function}{checked}
%  \begin{syntax}
%   |checked| = |true|\verb"|"|false|
%  \end{syntax}
% 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.
% \end{function}
%
% \begin{function}{value,default}
%  \begin{syntax}
%   |value| = |Yes|\verb"|"|Off|\\
%   |default| = |Yes|\verb"|"|Off|\\
%  \end{syntax}
% With checkboxes this two key are simply an alternative input for |checked|.
% \end{function}
%
% \subsection{Using with hyperref}
% The \cs{CheckBox} command from hyperref also prints a label, something that the
% command here doesn't do. A redefinition like the following should allow \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}
% For some general background about fieldsets, fields and field annotations, please
% check \pkg{l3pdffield}. Here are only some remarks about the special case of
% checkboxes.
%
% A checkbox consist of a field along with one or more field annotations.
% The annotations can appear on more than one page or locations and if one instance
% is checked all other instances follows and are checked too.
%
% A checkbox has two different looks: checked and unchecked. The hyperref
% implementation uses symbolic names for the two states and adds some
% values with the /MK key and lets the PDF viewer
% create a look from them. But this doesn't work reliably and is one of the reasons
% why a reimplementation is needed. Also newer PDF versions
% deprecate the /NeedAppearances setting and require that such a look,
% an \enquote{appearance}, is given as form XObjects.
% So the code forces the use of two appearances.
%
% \end{documentation}
%
% \begin{implementation}
% \DoNotIndex
%  {\\
% ,\bitset_clear:N
% ,\bitset_new:Nn
% ,\bitset_set_false:Nn
% ,\bitset_set_true:Nn
% ,\bitset_to_arabic:N
% ,\bool_new:N
% ,\box_dp:N
% ,\box_ht:N
% ,\clist_map_inline:nn
% ,\color_export:nnN
% ,\color_set:nn
% ,\color_set:nnn
% ,\cs_new_protected:Npn
% ,\cs_new_protected:cpn
% ,\cs_set_eq:NN
% ,\cs_gset_eq:cN
% ,\cs_set_protected:Npn
% ,\cs_generate_variant:Nn
% ,\cs_gset_eq:NN
% ,\csname
% ,\dim_eval:n
% ,\dim_new:N
% ,\endcsname
% ,\exp_args:Ne
% ,\fboxsep
% ,\group_begin:
% ,\group_end:
% ,\hbox_to_wd:nn
% ,\hfill
% ,\hook_gput_code:nnn
% ,\int_eval:n
% ,\l_keys_choice_int
% ,\keys_define:nn
% ,\keys_set:nn
% ,\mode_leave_vertical:
% ,\msg_error:nnn
% ,\msg_error:nnnn
% ,\msg_new:nnn
% ,\msg_warning:nn
% ,\msg_warning:nnn
% ,\msg_warning:nnnnn
% ,\NeedsTeXFormat
% ,\normalsize
% ,\pdf_name_from_unicode_e:n
% ,\pdf_object_if_exist:nTF
% ,\pdf_object_if_exist:nF
% ,\pdf_object_new:n
% ,\pdf_object_ref:n
% ,\pdf_object_ref_last:
% ,\pdf_object_unnamed_write:nn
% ,\pdf_object_write:nnn
% ,\pdf_string_from_unicode:nnN
% ,\pdfannot_box_ref_last:
% ,\pdfannot_dict_put:nnn
% ,\pdfannot_dict_remove:nn
% ,\pdfannot_widget_box:nnn
% ,\pdfdict_if_empty:nTF
% ,\pdfdict_get:nnN
% ,\pdfdict_new:n
% ,\pdfdict_put:nnn
% ,\pdfdict_remove:nn
% ,\pdfdict_use:n
% ,\pdfmanagement_add:nnn
% ,\pdfmeta_standard_verify:nTF
% ,\pdfxform_if_exist:nTF
% ,\pdfxform_new:nnn
% ,\pdfxform_ref:n
% ,\phantom
% ,\prg_do_nothing:
% ,\ProvidesExplPackage
% ,\rule
% ,\seq_gput_right:Nn
% ,\seq_if_exist:NTF
% ,\seq_new:N
% ,\seq_use:Nn
% ,\str_if_empty:NTF
% ,\str_if_in:NnTF
% ,\str_new:N
% ,\strut
% ,\strutbox
% ,\tl_if_empty:NTF
% ,\tl_if_empty:NT
% ,\tl_if_empty:NF
% ,\tl_put_left:Nn
% ,\tl_if_empty:nTF
% ,\tl_if_head_eq_charcode:nNTF
% ,\tl_new:N
% ,\tl_set:Nn
% ,\tl_to_str:n
% ,\use:c
%   }
% \section{\pkg{l3pdffield-checkbox} Implementation}
%    \begin{macrocode}
%<*package>
%<@@=pdffield>
%    \end{macrocode}
% \subsection{Variables}
% There are no specific variables.
% \subsection{Messages}
% There are no specific messages.
% \subsection{Appearances}
% The default appearances are a quadratic frame with cross (\cs{texttimes}) if
% checked.
% User appearances should have two versions and follow the naming
% module/\meta{name}/Yes and module/\meta{name}/Off.
%  \begin{macro}[int]
%   {
%    \@@_checkbox_default_appearances:,
%    pdffield/checkbox/default/Yes,
%    pdffield/checkbox/default/Off
%   }
%  This defines the standard appearance. It is setup at the first
%  use of a checkbox, and will adapt to the font family in use then.
%    \begin{macrocode}
\cs_new_protected:Npn \@@_checkbox_default_appearances:
  {
     \pdffield_appearance:nn {pdffield/checkbox/default/Yes}
       {
         \normalsize
         \fboxsep 0pt
         \framebox
           [ \dim_eval:n { \box_ht:N\strutbox+\box_dp:N\strutbox } ]
           { \texttimes \strut }
       }
     \pdffield_appearance:nn {pdffield/checkbox/default/Off}
       {
         \normalsize
         \fboxsep 0pt
         \framebox
           [ \dim_eval:n { \box_ht:N\strutbox+\box_dp:N\strutbox } ]
           { \phantom{\texttimes} \strut }
       }
    \cs_gset_eq:NN \@@_checkbox_default_appearances: \prg_do_nothing:
  }
%    \end{macrocode}
% \end{macro}
%
%\subsection{Creating the field}
% A field should be created if the name doesn't exist
%  \begin{macro}{ \@@_checkbox_field:n }
%    \begin{macrocode}
\cs_new_protected:Npn \@@_checkbox_field:n #1 %name
  {
    \pdf_object_if_exist:nF {@@/field/@@/checkbox/#1}
      {
        \@@_field:n { @@/checkbox/#1 }
      }
    \keys_set:nn {pdffield}{parent={@@/checkbox/#1}}
  }
\cs_generate_variant:Nn \@@_checkbox_field:n {V}
%    \end{macrocode}
% \end{macro}
% \subsection{Assembling the checkbox}
%
% \begin{macro}{\@@_checkbox:n}
%    \begin{macrocode}
\cs_new_protected:Npn \@@_checkbox:n #1
  {
    \group_begin:
    \@@_checkbox_default_appearances:
    \cs_set_eq:NN\@@_appearance_handler:nnn \@@_checkbox_appearance_handler:nnn
    \cs_set_eq:NN\@@_value_handler:n   \@@_checkbox_value_handler:n
    \cs_set_eq:NN\@@_default_handler:n \@@_checkbox_default_handler:n
%    \end{macrocode}
% Setting up the defaults.
%    \begin{macrocode}
    \keys_set:nn {pdffield}
      {
        fieldID=,
        name=checkbox,
        appearance = pdffield/checkbox/default,
        checked=false,
        width  = \normalbaselineskip,
        height = \normalbaselineskip,
      }
%    \end{macrocode}
% Value keys should be undefined.
%    \begin{macrocode}
    \@@_key_disable:nnn{checkbox}{V}{checked}
    \@@_key_disable:nnn{checkbox}{DV}{checked}
    \@@_key_disable:nnn{checkbox}{AS}{checked}
    \keys_set:nn { pdffield }{@@/preset/checkbox,#1}
    \keys_set:nn { pdffield }
      {
        ,unsetFf={Radio,Pushbutton}
        ,FT= Btn
      }
    \tl_if_empty:NT\l_@@_fieldID_tl
      {
        \pdfdict_get:nnN {l_@@/field}{T}\l_@@_fieldID_tl
        \tl_put_left:Nn \l_@@_fieldID_tl {@@/checkbox/}
      }
    \@@_checkbox_field:V\l_@@_fieldID_tl
    \@@_annot:
    \group_end:
  }
%    \end{macrocode}
% \end{macro}
%
% \subsection{Keys}
% Most keys are inherited simply the ones from the generic field and annot keys.
% A key to decide if the box is initially checked or not.
% We stay in the same family so that we can build a style.
%  \begin{macro}{checked}
%  This is a key specific for checkbox, it sets both field and annotation keys.
%    \begin{macrocode}
\keys_define:nn { pdffield  }
 {
   ,checked .choice:
   ,checked / false .code:n =
     {
       \pdfdict_put:nne { l_@@/field }{V} { /Off }
       \pdfdict_put:nne { l_@@/field }{DV}{ /Off }
       \pdfannot_dict_put:nnn {widget}{AS}{ /Off }
     }
   ,checked / true .code:n =
     {
       \pdfdict_put:nne { l_@@/field }{V} { /Yes }
       \pdfdict_put:nne { l_@@/field }{DV}{ /Yes }
       \pdfannot_dict_put:nnn {widget}{AS}{ /Yes }
     }
   ,checked .default:n = {true}
   ,checked .groups:n  = {checkbox}
 }
\keys_define:nn { pdffield  }
 {
   ,__value .choice:
   ,__value / Off .code:n =
     {
       \pdfdict_put:nne { l_@@/field }{V} { /Off }
       \pdfdict_put:nne { l_@@/field }{DV}{ /Off }
       \pdfannot_dict_put:nnn {widget}{AS}{ /Off }
     }
   ,__value / Yes .code:n =
     {
       \pdfdict_put:nne { l_@@/field }{V} { /Yes }
       \pdfdict_put:nne { l_@@/field }{DV}{ /Yes }
       \pdfannot_dict_put:nnn {widget}{AS}{ /Yes }
     }
 }
%    \end{macrocode}
% \end{macro}
% \begin{macro}{\@@_checkbox_value_handler:n,\@@_checkbox_default_handler:n}
% |value| and |default| do the same as checked.
%    \begin{macrocode}
\cs_new_protected:Npn \@@_checkbox_value_handler:n #1
  {
    \keys_set:nn{pdffield}{__value={#1}}
  }
\cs_new_protected:Npn \@@_checkbox_default_handler:n #1
  {
    \keys_set:nn{pdffield}{__value={#1}}
  }
%    \end{macrocode}
% \end{macro}
% \begin{macro}{\@@_checkbox_appearance_handler:nnn}
% Appearances must create a dictionary, so we define a special handler.
% \Arg{name} is the xform name without the /Yes, /Off, \Arg{type} is N, R, or D,
% \Arg{text} is a word for the error message.
%    \begin{macrocode}
\cs_new_protected:Npn \@@_checkbox_appearance_handler:nnn #1 #2 #3 %name, type, text
  {
    \pdfxform_if_exist:nTF {  #1/Yes }
      {
        \pdf_object_if_exist:nF {@@/checkbox/AP/#1}
          {
            \pdf_object_new:n {@@/checkbox/AP/#1}
            \pdf_object_write:nne
              {@@/checkbox/AP/#1} { dict }
              {
                /Yes ~ \pdfxform_ref:n { #1/Yes}
                /Off ~ \pdfxform_ref:n { #1/Off}
              }
          }
        \pdfannot_dict_put:nne {widget/AP}{#2}{\pdf_object_ref:n{@@/checkbox/AP/#1}}
      }
      {
         \msg_error:nnnn{pdffield}{appearance-missing}{#1}{#3}
      }
   }

%    \end{macrocode}
%
% \end{macro}
%
% \subsection{user commands}
% \begin{macro}{\pdffield_checkbox:n}
%    \begin{macrocode}
\cs_set_eq:NN \pdffield_checkbox:n \@@_checkbox:n
%</package>
%    \end{macrocode}
% \end{macro}
%\end{implementation}

% \PrintIndex