% \iffalse meta-comment
%
%% File: l3pdfpdffield-textfield.dtx
%
% Copyright (C) 2021-2024 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}
\hypersetup{pdfauthor=The LaTeX Project,
 pdftitle=l3pdffield (LaTeX PDF management testphase bundle)}
\begin{document}
  \DocInput{\jobname.dtx}
\end{document}
%</driver>
% \fi
% \providecommand\hook[1]{\texttt{#1}}
% \title{^^A
%   The \pkg{l3pdffield-textfield} module\\ Commands to create textfield 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.96l, released 2024-09-13}
%
% \maketitle
% \begin{documentation}
% \section{\pkg{l3pdffield-textfield} Introduction}
% \ExplSyntaxOn
%  Enter~your~name:\quad \pdffield_textfield:n{name=name,fontcolor=[RGB]{00,33,99},width=5cm}
% \ExplSyntaxOff
%
% This is the documentation for textfield fields, for general information about form fields
% check the documentation l3pdffield.
%
% Textfields allows the user to input text which is then rendered by the PDF viewer and
% often can also be saved together with the PDF.
%
% Currently the package doesn't initialize the font |/Helv|
% used by default in the fields (It works also without it, but this isn't fully compliant.)
% I don't want to setup the same font twice and haven't yet decided how
% to organize the collaboration with hyperref. So for now you should load hyperref
% and issue the \cs{Form} command.
%
% Please keep in mind
% \begin{itemize}
% \item Not every PDF viewer supports textfields.
% \item The font and the exact position of the chars depends on the PDF viewer.
% \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}
%
% \subsection{About fonts}
%
% The font color and font size can be changed with the keys |fontcolor| and
% |fontsize| described below. This works quite reliably (but e.g.
% the PDF viewer of my browser insists to show the font in blue while editing).
%
% Much more difficult is the font family:
% a typical wish for textfields is that a font matching the document font is used
% in the fields.  But how can that be done?
% Obviously it is not possible like with a checkbox to prepare and include appearances
% with the right look, the PDF reader has to render the text dynamically.

% The PDF reference mentions only one way to pass a font setting to the text field:
% The |DA| key can contain a font operator and the fontname used should be added
% along with a object reference of the font to the form resources
% in the |AcroForm/DR/Font| dictionary. The question is: what does a PDF renderer
% make with this data? Clearly the main resources to render
% the text can not be to rely on an embedded font and a PDF font operator as both
% is not enough
% to guarantee a sensible text support: a font operator is normally used in
% the page stream along with glyph indices and positioning instructions, not
% with unicode input, and typically a font is only partially embedded.
% This means the PDF viewers and editors actually have to use external
% resources--system fonts, or fonts that come along with the viewer and libraries
% to handle font shaping.
%
% Hyperref may add a reference the type1 font helvetica to the DA key, but
% PDF viewers use actually Arial. And if one doesn't add a font with
% |DA| and |DR/Font| the text field works nevertheless.
%
% This doesn't mean that the DA/DR info is ignored altogether.
% Adobe Reader and Pro seems to use it to choose a fitting fallback font:
% \begin{itemize}
% \item One can change the font by simply using the font name (the examples use
% the |font| key of this module). One get courier with |font=courier|,
% times with |font=times|,
% comic sans with |font=ComicSansMS|, DejaVu with |font=DejaVuSans|. The fonts
% don't need to be used in the document or added as resources in the DR/Font dictionary.
% Some fonts work better than other: comic sans is quite unproblematic,
% but DejaVu seems to trigger a font search first and so is slower (perhaps the.
% \item If one fill and then save such a PDF at least adobe adds
% the missing font resources to the PDF.
% \end{itemize}
%
% This lazy font setting doesn't work with other PDF viewers.
% In other test I had better results by actually embedding a few glyphs
% of the font and then adding the font
% as resource to the DR/Font dictionary. Sadly this requires lualatex, only there is
% possible to retrieve the internal font name and font object number for a larger set
% of fonts---with pdflatex it works only for fonts not using a virtual font, and xelatex
% has no access at all. The code for lualatex looked like this (the font one wants
% to use should be active)
% \begin{verbatim}
% \pdffield_textfield:n {name=text,font=F\pdffeedback~fontname\font}
% \pdfmanagement_add:nee{Catalog/AcroForm/DR/Font}
%       {F\pdffeedback~fontname\font}
%       {\pdffeedback~fontobjnum\font \c_space_tl 0 \c_space_tl R}
% \end{verbatim}
%
% \subsection{Vertical alignment}
% There is no way to set a reference point for the baseline.
% Alignment must achieved by
% fiddling with the height and depth of the field. The defaults (which uses as
% height the fontsize, and a bit depth) works okay in adobe reader with arial.
% If the font is set to courier, the text jumps up and one has to decrease the height
% by around 30\%. For a multiline field which should be top aligned you should
% increase the depth by the wanted amount \emph{and} the height by around 2pt.
%
% The geometry of the fields is seen by TeX, and so can influence the line spacing.
% If needed you should hide the height with \cs{raisebox} or \cs{smash}.
%
% \section{Textfields}
% Input a value:
% \ExplSyntaxOn
%  \pdffield_textfield:n{name=test,width=4cm,height=0.7\baselineskip,depth=0.3\baselineskip}
% \ExplSyntaxOff
%
% \bigskip
% \subsection{Commands}
% \begin{function}{\pdffield_textfield:n}
% \begin{syntax}
%  \cs{pdffield_textfield:n}\Arg{key val list}
% \end{syntax}
% This creates a textfield. The list of allowed keys is described below.
% The \meta{key val list} should at least set the name, without it the default name
% |textfield| is used. Textfields with the same
% name belong to the same field and are filled together. The default appearance
% is a light gray background.
% The default appearance is setup at the first use.
% \end{function}
%
%
% \subsection{Keys}
%
% The new textfield command accept all field and annot keys from l3pdffield,
% please check the documentation there. The list here mentions only a few
% central keys, and the keys which are either specific for textfields, or have
% changed functionality.
%
% Disabled keys are
%  \begin{itemize}
%  \item |FT| is overwritten.
%  \item |AS| is cleared.
%  \item |DA| is overwritten.
%  Locally use |fontcolor|, |fontsize| and |font| instead.
%  Globally you can set the |DA| key in the catalog with for example
%  \begin{verbatim}
%  \pdfmanagement_add:nnn{Catalog/AcroForm}{DA}{(/Helv~10~Tf~1~1~0~rg)}
%  \end{verbatim}
%  \item For textfields only the field flags  |ReadOnly|, |Required| |NoExport|
%  |Multiline|, |Password|, |FileSelect|, |DoNotSpellCheck|, |DoNotScroll| and |Comb|
%  make sense.
%  If |Comb| is set, |Multiline|, |Password| and |FileSelect| are unset, |MaxLen| is
%  set to 10 if it hasn't been set previously.
%  \end{itemize}
%
% The keys |value| and |default| are mapped to |V| and |DV| for this field type, see
% below.
%
%
% \begin{function}{preset-textfield}
%  \begin{syntax}
%   |preset-textfield| = \Arg{key-val-list}
%  \end{syntax}
% This allows to set default keys for a textfield.
% \end{function}
%
% \begin{function}{name,T}
%  \begin{syntax}
%   |name| = \meta{partial name}\\
%   |T| = \meta{partial name}
%  \end{syntax}
% This sets like the |T| key for fields 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 textfield with the same partial name are annotations
% with the same field as parent and are filled 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 textfield 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 an 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 textfield 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 textfield 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 textfield instance.
% The value should be a dimension expression. By default
% |width| is 3cm, the |height| uses the fontsize (\cs{f@size} in pt),
% the |depth| is 0.3\cs{f@size}.
% \end{function}
%
% \begin{function}{appearance,rollover-appearance,down-appearance}
%  \begin{syntax}
%   |appearance| = \meta{name}\\
%   |rollover-appearance| = \meta{name}\\
%   |down-appearance| = \meta{name}
%  \end{syntax}
% This keys sets the normal appearance, the rollover appearance (when the
% mouse hovers over the textfield) and the down appearance (when the
% mouse clicks). They expect the name of an existing form Xobject as value.
% The initial value is |pdffield/textfield/default|
% for the normal appearance and shows a light gray background.
% The other appearance are not set by default (and it is quite unclear if they
% make sense for a textfield).
% \end{function}
%
% \begin{function}{V,value}
%  \begin{syntax}
%   |V| = \meta{text}\\
%   |value| = \meta{text}
%  \end{syntax}
% This sets the start text in the field. The keys have an effect only at the first
% instance of the textfield, when the field is initialized.
% \end{function}
%
% \begin{function}{DV,default}
%  \begin{syntax}
%   |DV| = \meta{text}\\
%   |default| = \meta{text}
%  \end{syntax}
% This sets the text which is shown if the form is reset.
% The keys have an effect only at the first
% instance of the textfield, when the field is initialized.
% \end{function}
%
% \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}
% The \cs{TextField} command from hyperref also prints a label, something that the
% command here doesn't do. A redefinition like the following should allow \cs{TextField}
% 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\@TextField[#1]#2{\LayoutTextField{#2}{\pdffield_textfield:n {name=#2,#1}}}
% \ExplSyntaxOff\makeatother
% \end{verbatim}
%
%
% \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
% ,\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
% ,\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_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
% ,\quark_if_no_value:NT
% ,\raisebox
% ,\rule
% ,\seq_gput_right:Nn
% ,\seq_if_exist:NTF
% ,\seq_new:N
% ,\seq_use:Nn
% ,\smash
% ,\str_if_empty:NTF
% ,\str_if_in:NnTF
% ,\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_empty:nTF
% ,\tl_if_head_eq_charcode:nNTF
% ,\tl_new:N
% ,\tl_set:Nn
% ,\tl_to_str:n
% ,\use:c
%   }
% \section{\pkg{l3pdffield-textfield} Implementation}
%    \begin{macrocode}
%<*package>
%<@@=pdffield>
%    \end{macrocode}
% \subsection{Variables}
% \begin{variable}
%  {
%    \l_@@_DA_fontcolor_tl, \l_@@_DA_fontsize_dim, \l_@@_DA_fontname_tl
%  }
%  Variables for the font setup in the DA key.
%    \begin{macrocode}
\tl_new:N  \l_@@_DA_fontcolor_tl
\dim_new:N \l_@@_DA_fontsize_dim
\tl_new:N  \l_@@_DA_fontname_tl
%    \end{macrocode}
% \end{variable}
%
% \subsection{Appearances}
% The default appearance is a light gray background.
%
%  \begin{macro}{\@@_textfield_default_appearance:}
%  This defines the standard appearance. It is setup at the first
%  use of a textfield.
%    \begin{macrocode}
\cs_new_protected:Npn {\@@_textfield_default_appearance:}
  {
    \pdffield_appearance:nn {pdffield/textfield/default}
     {
       { \color_select:n{black!5!white}\rule{\paperwidth}{\paperheight} }
     }
    \cs_gset_eq:NN \@@_textfield_default_appearance: \prg_do_nothing:
  }
%    \end{macrocode}
% \end{macro}
%
%\subsection{Creating the field}
% \begin{macro}{\@@_textfield_field:n}
% A field should be created only if the name doesn't exist
%    \begin{macrocode}
\cs_new_protected:Npn \@@_textfield_field:n #1 %name
  {
    \pdf_object_if_exist:nF {@@/field/@@/textfield/#1}
      {
        \@@_field:n { @@/textfield/#1 }
      }
    \keys_set:nn {pdffield}{parent=@@/textfield/#1}
  }
\cs_generate_variant:Nn \@@_textfield_field:n {V}
%    \end{macrocode}
% \end{macro}
%
% \subsection{Assembling the textfield}
%
% \begin{macro}{\@@_textfield:n}
% At first we map the handler and setup the appearance.
%    \begin{macrocode}
\cs_new_protected:Npn \@@_textfield:n #1
  {
    \group_begin:
    \cs_set_eq:NN\@@_V_handler:nN \@@_textfield_V_handler:nN
    \cs_set_eq:NN\@@_value_handler:n \@@_textfield_value_handler:n
    \cs_set_eq:NN\@@_default_handler:n \@@_textfield_default_handler:n
    \@@_textfield_default_appearance:
%    \end{macrocode}
% Setting up the defaults and processing the keys.
%    \begin{macrocode}
    \keys_set:nn {pdffield}
      {
        ,fieldID=
        ,name=textfield
        ,appearance = pdffield/textfield/default
        ,width  = 3cm
        ,fontsize= \f@size pt
        ,height =  \f@size pt,
         depth  =   \fp_eval:n {0.3*\f@size} pt,
        % font defaults!!
      }
    \keys_set:nn { pdffield }{@@/preset/textfield,#1}
%    \end{macrocode}
%  We need to check if Comb is used and setup some flags in this case.
%    \begin{macrocode}
    \int_compare:nNnT {\bitset_item:Nn \l_@@_Ff_bitset {Comb}}={1}
      {
        % warning if set?
        \keys_set:nn { pdffield }
          {
            ,unsetFf={FileSelect,Multiline,Password}
          }
        \pdfdict_get:nnN {l_@@/field}{MaxLen}\l_@@_tmpa_tl
        \quark_if_no_value:NT \l_@@_tmpa_tl
         {
           \keys_set:nn { pdffield}
            {
              MaxLen = 10 %variable
            }
            % warning
         }
      }
%    \end{macrocode}
%  Now the postprocessing.
%    \begin{macrocode}
    \keys_set:nn { pdffield }
      {
        ,FT= Tx
        ,AS=
        ,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 no field ID exists, we get it from the 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 {@@/textfield/}
      }
    \@@_textfield_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}{fontcolor,fontsize,font}
%    \begin{macrocode}
\keys_define:nn {pdffield}
  {
    ,fontcolor .code:n =
       {
         \@@_color_set:nn {@@/tmp}{#1}
         \color_export:nnN{@@/tmp}{space-sep-rgb}\l_@@_DA_fontcolor_tl
         \tl_put_right:Nn \l_@@_DA_fontcolor_tl{~rg}
       }
    ,fontcolor .initial:n = black,
    ,fontcolor .groups:n = {textfield}
    ,font .tl_set:N      = \l_@@_DA_fontname_tl
    ,font .initial:n     = {Helv}
    ,font .groups:n = {textfield}
    ,fontsize .dim_set:N = \l_@@_DA_fontsize_dim
    ,fontsize .initial:n = {10bp}
    ,fontsize .groups:n = {textfield}
  }
%    \end{macrocode}
% \end{macro}
%
% \subsection{Handler}
% \begin{macro}{\@@_textfield_V_handler:nN}
% The handler for V/DV, it creates a string.
%    \begin{macrocode}
\cs_new_protected:Npn \@@_textfield_V_handler:nN #1#2
  {
     \pdf_string_from_unicode:nnN {utf16/hex}{#1}#2
  }
%    \end{macrocode}
% \end{macro}
% \begin{macro}{\@@_textfield_value_handler:n,\@@_textfield_default_handler:n}
% The handler for value and default. They simply map to V,DV here.
%    \begin{macrocode}
\cs_new_protected:Npn \@@_textfield_value_handler:n #1
  {
     \keys_set:nn{pdffield}{V={#1}}
  }
\cs_new_protected:Npn \@@_textfield_default_handler:n #1
  {
     \keys_set:nn{pdffield}{DV={#1}}
  }
%    \end{macrocode}
% \end{macro}
% \subsection{User command}
% \begin{macro}{\pdffield_textfield:n}
%    \begin{macrocode}
\cs_set_eq:NN \pdffield_textfield:n \@@_textfield:n
%</package>
%    \end{macrocode}
% \end{macro}
%\end{implementation}
%\PrintIndex
