% \iffalse meta-comment
%
%% File: l3pdffield-choice.dtx
%
% Copyright (C) 2021-2026 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 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{tagging=on,pdfstandard=ua-2} 
\documentclass[full]{l3doc}
\usepackage{latex-lab-testphase-l3doc}
\usepackage{array,booktabs}
\usepackage{l3pdffield}
\hypersetup{pdfauthor=The LaTeX Project,
 pdftitle=l3pdffield (LaTeX PDF management bundle)}
\begin{document}
  \DocInput{\jobname.dtx}
\end{document}
%</driver>
% \fi
% \providecommand\hook[1]{\texttt{#1}}
% \title{^^A
%   The \pkg{l3pdffield-choice} module\\ Commands to create choice fields   ^^A
%   \\ \LaTeX{} PDF management 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.96y, released 2026-01-23}
%
% \maketitle
% \begin{documentation}
% \section{\pkg{l3pdffield-choice} Introduction}
% This is the documentation for choice fields, for general information about form fields
% check the documentation l3pdffield.
%
%
% Please keep in mind
% \begin{itemize}
% \item Not every PDF viewer supports choice field.
% \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{Choice fields}
%
% Choice fields are drop down menus or scrollable lists where
% the user can select one or more entries. They can also contain a field where
% users can insert a free text. The export value and the displayed value can differ.
% Some values can be preselected.
%
% This means that various data will have to be set, and the sorting matters.
% The module here will assume that the various values are stored in sequences:
%
% \begin{verbatim}
% \seq_const_from_clist:Nn \c_my_values_seq {hippo,duck,bear}
% \seq_const_from_clist:Nn \c_my_displayvalues_seq {Sieglinde,,Bär}
% \seq_const_from_clist:Nn \c_my_defaultvalues_seq {duck,Bär} 
% \end{verbatim}
%
% Only the first sequence is required.
% Empty values in the display sequence are possible, then the normal value is used.
%
% \subsection{Types}
% Choice fields can be a drop down menu (called |Combo|), which can contain an editable
% field.
%
% |setfieldflags={Combo,Edit}| or |setfieldflags={Combo}|
%
% If |Edit| is set, one can also set |DoNotSpellCheck|.
%
% Or they can be a list.
%
% |unsetfieldflags={Combo,Edit,DoNotSpellCheck}|
%
%
% For both types it is possible to set or unset |MultiSelect| and |CommitOnSelChange|.
%
%
% \subsection{Appearance}
% By default the fields use a grey background as appearance, another appearance 
% can be defined with |\pdffield_appearance:nn| (described in the documentation of
% l3pdffield) or directly with |\pdfxform_new:nnn| (in l3pdfxfom)
% and then used with the |appearance| as in other form fields.
%
% 
% \subsection{Commands}
% \begin{function}{\pdffield_choice:n}
% \begin{syntax}
%  \cs{pdffield_choice:n} \Arg{key val list}
% \end{syntax}
% This creates a choice field.
% The list of allowed keys is described below.
% The \meta{key val list} should at least set the name,
% without it the default |choice| is used. Choice fields with the same name
% belong to the same field and if changed, the others are changed accordingly.
% As default appearance we reuse the text appearance: a simple gray background.
%
% The first choice field setups the field and so should setup values and field flags.
% \end{function}
%
%
% \subsection{Keys}
%
% The new choice 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 ...
% behaviour, other keys have other defaults than with the basic commands.
% Additionally there
% are a small number of keys specific to a choice field.
% |value| and |default| have a special meaning.
%
%
% Disabled keys are
%  \begin{itemize}
%  \item |V|, |DV|, |AS|: they are set by the other keys.
%  \item |FT| is overwritten.
%  \item For fields only the field flags  |ReadOnly|, |Required|, |NoExport|,
%  |Combo|, |Edit|, |MultiSelect|, |Sort|, |DoNotSpellCheck| and |CommitOnSelChange|
%   make sense. The code will force some values (e.g. disable |Edit| if |Combo| is false).
%  \end{itemize}
%
%
% \begin{function}{preset-choice}
%  \begin{syntax}
%   |preset-choice| = \Arg{key val list}
%  \end{syntax}
% This allows to set default keys for a choice field.
% \end{function}

% \begin{function}{type}
%  \begin{syntax}
%   |type| = \texttt{combo}\verb+|+\texttt{combo-edit}\verb+|+\texttt{list}
%  \end{syntax}
% This key is a choice key that allows to set the three types.
% \end{function}

%
% \begin{function}{name,T}
%  \begin{syntax}
%   |name| = \meta{partial name}\\
%   |T| = \meta{partial name}
%  \end{syntax}
% These keys set the partial name of the field. They both do the same
% thing, use the one you are more comfortable with. 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 choice field with the same partial name are annotations
% with the same field as parent.
% 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}{value,values}
%  \begin{syntax}
%   |value| = \Arg{comma separated list of values}
%   |values| = \Arg{comma separated list of values}
%  \end{syntax}
%  With these keys you set the export value names. \meta{comma separated list of values} should contain
%  the values in the order as wanted. The values are passed through |\pdf_string_from_unicode:nnN|
%  and can use unicode.
%  \end{function}
%
%  \begin{function}{display-values}
%  \begin{syntax}
%   |display-values| = \Arg{comma separated list of values}
%  \end{syntax}
%  With this key you set the display value names if they should be
%  different from the export values. They should be given in the same order as the values.
%  The values are passed through |\pdf_string_from_unicode:nnN|
%  and can use unicode.
%  \end{function}
%
%  \begin{function}{default,default-values}
%  \begin{syntax}
%   |default|        = \Arg{comma separated list of values}
%   |default-values| = \Arg{comma separated list of values}
%  \end{syntax}
%  With this keys you set the values which are selected when the PDF is opened.
%  The use of this keys is a bit dubious. It seems to work okay for combo fields,
%  but not for list fields. According to the PDF reference the
%  values should be the display values, but it is not clear if the PDF viewer
%  really implement it that way or if the export value should be preferred.
%  Depending on the values it could be needed to
%  add also an |I| array to the field.
%  \end{function}

%  \begin{function}{top-index}
%  \begin{syntax}
%   |top-index| = \Arg{integer}
%  \end{syntax}
%  With this key you set for a scrollable list field the number of the
%  value  shown at the top. The first value has number 1 (that is the default).
%  I'm not sure if viewers handle this correctly, so the setting should be used with
%  care.
%  \end{function}

% \begin{function}{fieldID}
%  \begin{syntax}
%   |fieldID| = \meta{field ID}\\
%  \end{syntax}
% \emph{For experts only!}
% This allows to give the radio field a specific ID. This is only useful
% in the context of a larger fieldset 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}{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 the choice field.
% The value should be a dimension expression. By default
% |width| and |height| and |depth| are ....
% \end{function}
%
% \begin{function}{AP/N,appearance,AP/R,rollover-appearance,AP/D,down-appearance}
%  \begin{syntax}
%   |AP/N| = \meta{appearance name}\\
%   |appearance| = \meta{appearance name}\\
%   |AP/R| = \meta{appearance name}\\
%   |rollover-appearance| = \meta{appearance name}\\
%   |AP/D| = \meta{appearance name}\\
%   |down-appearance| = \meta{appearance name}
%  \end{syntax}
%  This adds appearances. \meta{appearance name} should be the name of an form Xobjects.
%  The default normal appearance is a simple gray background, the same as with
%  text fields.
% \end{function}
%
% The font are handled in a similar way as in textfield. Most of the remarks made there
% are true for choice fields too.
%
% \begin{function}{fontcolor}
%  \begin{syntax}
%   |fontcolor| = \meta{color expression} \verb"|" [\meta{model}]\Arg{values}\\
%  \end{syntax}
% This is sets the color of font in the textfield. Internally currently RGB is used.
% The colors used in
% \meta{color expression} must be known to the \pkg{l3color} commands.
% The initial color is black. It is a \emph{field} setting, that means instances
% share the color.
% \end{function}
%
% \begin{function}{fontsize}
%  \begin{syntax}
%   |fontsize| = \meta{dim expression}
%  \end{syntax}
% This is sets the size of the font in the textfield.
% The default value is the current font size (\cs{f@size} in pt).
% It is a \emph{field} setting, that means instances
% share the size.
% \end{function}
%
% \begin{function}{font}
%  \begin{syntax}
%   |font| = \meta{symbolic font name}
%  \end{syntax}
% This is sets the font in the textfield. See the discussion at the begin of
% the documentation about some background. The default value is |Helv| and this
% name is setup if you load hyperref and issue the \cs{Form} command.
% The default value is the current font size (\cs{f@size} in pt).
% It is a \emph{field} setting, that means instances
% share the font.
% \end{function}
% \subsection{Using with hyperref}
%
% hyperref combines radio button and choice field in one command. This makes it
% difficult to replicate the hyperref commands here.
%
% \end{documentation}
%
% \begin{implementation}
% % \DoNotIndex
%  {\\
% ,\bitset_clear:N
% ,\bitset_new:Nn
% ,\bitset_set_false:Nn
% ,\bitset_set_true:Nn
% ,\bitset_to_arabic:N
% ,\bitset_item:Nn
% ,\bool_new:N
% ,\box_dp:N
% ,\box_ht:N
% ,\clist_map_inline:nn
% ,\color_export:nnN
% ,\color_set:nn
% ,\color_set:nnn
% ,\color_select:n
% ,\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
% ,\c_space_tl
% ,\csname
% ,\dim_eval:n
% ,\dim_new:N
% ,\dim_to_decimal_in_bp:n
% ,\endcsname
% ,\exp_args:Ne
% ,\exp_args:Nc
% ,\fboxsep
% ,\fp_eval:n
% ,\f@size
% ,\group_begin:
% ,\group_end:
% ,\hbox_to_wd:nn
% ,\hfill
% ,\hook_gput_code:nnn
% ,\int_eval:n
% ,\int_compare:nNnT
% ,\int_compare:nNnTF
% ,\int_incr:N
% ,\int_new:N
% ,\int_use:N
% ,\int_zero: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
% ,\paperheight
% ,\paperwidth
% ,\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_unnamed_write:ne
% ,\pdf_object_write:nne
% ,\pdf_object_write:nnn
% ,\pdf_string_from_unicode:nnN
% ,\pdfannot_box_ref_last:
% ,\pdfannot_dict_put:nnn
% ,\pdfannot_dict_put:nne
% ,\pdfdict_put:nne
% ,\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
% ,\quark_if_no_value:NT
% ,\raisebox
% ,\RequirePackage
% ,\rule
% ,\seq_gput_right:Nn
% ,\seq_gput_right:cV
% ,\seq_gput_left:cV
% ,\seq_if_in:cVF
% ,\seq_map_break:
% ,\seq_map_inline:Nn
% ,\seq_new:c
% ,\seq_use:cn
% ,\seq_if_exist:NTF
% ,\seq_new:N
% ,\seq_use:Nn
% ,\smash
% ,\str_if_empty:NTF
% ,\str_if_in:NnTF
% ,\str_if_eq:nVTF
% ,\str_new:N
% ,\strut
% ,\strutbox
% ,\tl_put_right:Nn
% ,\tl_if_empty:NTF
% ,\tl_if_empty:NT
% ,\tl_if_empty:NF
% ,\tl_put_left:Nn
% ,\tl_if_eq:NnF
% ,\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-choice} Implementation}
%    \begin{macrocode}
%<*package>
%<@@=pdffield>
\RequirePackage{l3draw}
%    \end{macrocode}
% \subsection{Variables}
% \begin{variable}
%  {
%      \l_@@_choice_values_seq
%     ,\l_@@_choice_defaultvalues_seq
%     ,\l_@@_choice_displayvalues_seq
%     ,\l_@@_choice_opt_seq
%  }
% variables to hold the value, the default value, and display variants. The opt
% seq will be used to build the content of opt
%    \begin{macrocode}
\seq_new:N  \l_@@_choice_values_seq
\seq_new:N  \l_@@_choice_defaultvalues_seq
\seq_new:N  \l_@@_choice_displayvalues_seq
\seq_new:N  \l_@@_choice_opt_seq
%    \end{macrocode}
% \end{variable}
%
% \subsection{Appearances}
% (probably take from textfield ...)
%
%\subsection{Creating the field}
% A field should be created if the name doesn't exist yet
%  \begin{macro}{\@@_choice_field:n}
%    \begin{macrocode}
\cs_new_protected:Npn \@@_choice_field:n #1 %name
  {
    \pdf_object_if_exist:nF {@@/field/@@/choice/#1}
      {
%    \end{macrocode}
% We must at first build the Opt array.
%    \begin{macrocode}
        \seq_clear:N \l_@@_choice_opt_seq
        \seq_map_indexed_inline:Nn \l_@@_choice_values_seq
          {
            \pdf_string_from_unicode:nnN{utf16/hex}{##2}\l_@@_tmpa_str
            \tl_set:Ne \l_@@_tmpa_tl {\seq_item:Nn \l_@@_choice_displayvalues_seq {##1} }
            \tl_if_empty:NTF \l_@@_tmpa_tl
              {
                \seq_put_right:NV \l_@@_choice_opt_seq \l_@@_tmpa_str
              }
              {
                \exp_args:NnV
                \pdf_string_from_unicode:nnN{utf16/hex}\l_@@_tmpa_tl\l_@@_tmpb_str
                \seq_put_right:Ne \l_@@_choice_opt_seq
                  { [ \l_@@_tmpa_str\c_space_tl\l_@@_tmpb_str] }
              }
          }
        \pdf_object_unnamed_write:ne {array}{\seq_use:Nn\l_@@_choice_opt_seq {~}}
        \pdfdict_put:nne { l_@@/field }{Opt}  { \pdf_object_ref_last: }
%    \end{macrocode}
% Now we handle the V value. If MultiSelect is set, we use the full
% displayvalues seq, if not only the first value.
%    \begin{macrocode}
        \int_compare:nNnTF {\bitset_item:Nn \l_@@_Ff_bitset {MultiSelect}} = {1}
          {
            \tl_clear:N \l_@@_tmpa_tl
            \seq_map_inline:Nn \l_@@_choice_defaultvalues_seq
             {
                \pdf_string_from_unicode:nnN{utf16/hex}{##1}\l_@@_tmpa_str
                \tl_put_right:NV \l_@@_tmpa_tl \l_@@_tmpa_str
                \pdfdict_put:nne { l_@@/field }{V}  { [ \l_@@_tmpa_tl ] }
             }
          }
          {
            \tl_set:Ne \l_@@_tmpa_tl {\seq_item:Nn \l_@@_choice_defaultvalues_seq {1} }
            \exp_args:NnV
              \pdf_string_from_unicode:nnN{utf16/hex}\l_@@_tmpa_tl\l_@@_tmpb_str
            \pdfdict_put:nne { l_@@/field }{V}  { \l_@@_tmpb_str }
          }
%    \end{macrocode}
% now we create the field and set it as parent for the following annotation.
%    \begin{macrocode}
        \@@_field:n { @@/choice/#1 }
      }
    \keys_set:nn {pdffield}{parent={@@/choice/#1}}
  }
\cs_generate_variant:Nn \@@_choice_field:n {V}
%    \end{macrocode}
% \end{macro}
%
% \subsection{Assembling the choice field}
%
% \begin{macro}{\@@_choice:n}
% The argument are key-val settings.
% At first we map the handlers.
% As default appearance we reuse the text appearance: a simple gray background.
%    \begin{macrocode}
\cs_new_protected:Npn \@@_choice:n #1
  {
    \group_begin:
    \cs_set_eq:NN\@@_value_handler:n      \@@_choice_value_handler:n
    \cs_set_eq:NN\@@_default_handler:n    \@@_choice_default_handler:n
    \@@_textfield_default_appearance:
%    \end{macrocode}
% Setting up the defaults.
%   \begin{macrocode}
    \keys_set:nn {pdffield}
      {
         fieldID=
        ,name=choice
        ,appearance = pdffield/textfield/default
        ,width  = 3cm
        ,height = \normalbaselineskip
        ,type=combo-edit
        ,@@/preset/choice
        ,#1
        ,FT= Ch
      }
     \@@_choice_set_type:
     \keys_set:nn {pdffield}
      {
        ,DA=
           {
              \pdf_name_from_unicode_e:n{\l_@@_DA_fontname_tl}
              \c_space_tl
              \dim_to_decimal_in_bp:n{\l_@@_DA_fontsize_dim}
              \c_space_tl
              Tf
              \c_space_tl
              \l_@@_DA_fontcolor_tl
              \c_space_tl
              %\l_@@_text_DAextra_tl
           }
      }
%    \end{macrocode}
% If the fieldID has not been set explicitly, we use the name/T key
%    \begin{macrocode}
   \tl_if_empty:NT\l_@@_fieldID_tl
      {
        \pdfdict_get:nnN {l_@@/field}{T}\l_@@_fieldID_tl
        \tl_put_left:Nn \l_@@_fieldID_tl {@@/choice/}
      }
%    \end{macrocode}
% Now we build the field
%    \begin{macrocode}
    \@@_choice_field:V\l_@@_fieldID_tl
%    \end{macrocode}
% And add the annotation.
%    \begin{macrocode}
    \@@_annot:
    \group_end:
  }
%    \end{macrocode}
% \end{macro}
%
% \subsection{Keys and handlers}
% Most keys are inherited simply the ones from the generic field and annot keys.
% We define a group key, as the name is better.
% The value key sets the export value. default the button which is checked on.
% At first the two handlers
% \begin{macro}{\@@_choice_value_handler:n,\@@_choice_default_handler:n,display-values}
%    \begin{macrocode}
\cs_new_protected:Npn \@@_choice_value_handler:n #1
  {
    \seq_set_from_clist:Nn \l_@@_choice_values_seq {#1}
  }
\cs_new_protected:Npn \@@_choice_default_handler:n #1
  {
    \seq_set_from_clist:Nn \l_@@_choice_defaultvalues_seq {#1}
  }
\keys_define:nn{pdffield}
  {
     values .meta:n = {value={#1}}
    ,default-values .meta:n = {default={#1}}
    ,display-values .code:n =
     {
       \seq_set_from_clist:Nn \l_@@_choice_displayvalues_seq {#1}
     }
   ,top-index .code:n =
     {
       \pdfdict_put:nne {l_@@/field}{TI}{\int_eval:n{#1-1}}
     }
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{type}
%    \begin{macrocode}
\cs_new_protected:Npn \@@_choice_set_type: {}

\keys_define:nn { pdffield }
  {
    type .choice:
   ,type / combo      .code:n =
     {
       \cs_set_protected:Npn\@@_choice_set_type:
        {
          \keys_set:nn{pdffield}{setFf={Combo},unsetFf={Edit,DoNotSpellCheck}}
        }
     }
   ,type / combo-edit .code:n =
     {
       \cs_set_protected:Npn\@@_choice_set_type:
         {
           \keys_set:nn{pdffield}{setFf={Combo,Edit}}
         }
     }
   ,type / list       .code:n =
     {
       \cs_set_protected:Npn\@@_choice_set_type:
         {
           \keys_set:nn{pdffield}{unsetFf={Combo,Edit,},unsetFf={Edit,DoNotSpellCheck}}
         }
     }
  }
%    \end{macrocode}
% \end{macro}
%
%
%
% \begin{macro}{\@@_choice_appearance_handler:nnn}
% The handler for the appearances stores only the code
% as it must be executed rather late.
%    \begin{macrocode}
\cs_new_protected:Npn \@@_choice_appearance_handler:nnn #1 #2 #3 %name, type, text
  {
  }

%    \end{macrocode}
%
% \end{macro}
%
% \subsection{User commands}
% \begin{macro}{\pdffield_choice:n}
%    \begin{macrocode}
\cs_set_eq:NN \pdffield_choice:n \@@_choice:n
%</package>
%    \end{macrocode}
% \end{macro}
%\end{implementation}
% \PrintIndex
