% \iffalse meta-comment % %% File: l3pdfpdffield-choice.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} % % \fi % \providecommand\hook[1]{\texttt{#1}} % \title{^^A % The \pkg{l3pdffield-choice} module\\ Commands to create choice 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.96n, released 2024-10-27} % % \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 % % \end{macrocode} % \end{macro} %\end{implementation} % \PrintIndex