% \iffalse meta-comment % %% File: l3pdfpdffield-radiobutton.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,bearwear,tikzlings,tikzducks} \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}} % \ExplSyntaxOn % \box_new:N\l_pdffield_bear_box % \box_new:N\l_pdffield_hippo_box % \box_new:N\l_pdffield_duck_box % \hbox_set:Nn \l_pdffield_bear_box {\tikz\bear\bearwear[shirt=red,body~deco={\node[font=\tiny\bfseries,white]~at~(beartummy){Yes};}];} % \hbox_set:Nn \l_pdffield_hippo_box {\vphantom{\tikz\bear;}\tikz\hippo;} % \hbox_set:Nn \l_pdffield_duck_box {\vphantom{\tikz\bear;}\tikz\duck;} % % % \pdffield_appearance:nn {pdffield/bear/Yes} % { % \fbox{\box_use:N \l_pdffield_bear_box} % } % \pdffield_appearance:nn {pdffield/bear/Off} % { % \fbox{\phantom{\box_use:N \l_pdffield_bear_box}} % } % \pdffield_appearance:nn {pdffield/hippo/Yes} % { % \fbox{\box_use:N \l_pdffield_hippo_box} % } % \pdffield_appearance:nn {pdffield/hippo/Off} % { % \fbox{\phantom{\box_use:N \l_pdffield_hippo_box}} % }% % \pdffield_appearance:nn {pdffield/duck/Yes} % { % \fbox{\box_use:N \l_pdffield_duck_box} % } % \pdffield_appearance:nn {pdffield/duck/Off} % { % \fbox{\phantom{\box_use:N \l_pdffield_duck_box}} % }% % \ExplSyntaxOff % \title{^^A % The \pkg{l3pdffield-radiobutton} module\\ Commands to create radio 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.96o, released 2024-12-20} % % \maketitle % \begin{documentation} % \section{\pkg{l3pdffield-radiobutton} Introduction} % This is the documentation for radio buttons fields, for general information about form fields % check the documentation l3pdffield. % % \begin{center} % Choose your favorite % % \medskip % \ExplSyntaxOn % \begin{tabular}{ccc} % \pdffield_radio:n{name=A,value=Bär,default=B,appearance=pdffield/bear,width=\box_wd:N\l_pdffield_bear_box,height=\box_ht:N\l_pdffield_bear_box}& % \pdffield_radio:n{name=A,value=Sieglinde,appearance=pdffield/hippo,width=\box_wd:N\l_pdffield_hippo_box,height=\box_ht:N\l_pdffield_hippo_box}& % \pdffield_radio:n{name=A,value=Duck,appearance=pdffield/duck,width=\box_wd:N\l_pdffield_duck_box,height=\box_ht:N\l_pdffield_duck_box}\\[1ex] % \pdffield_radio:n{name=A,value=Bär}& % \pdffield_radio:n{name=A,value=Sieglinde}& % \pdffield_radio:n{name=A,value=Duck} % \end{tabular} % \par not in unison: \par % % \begin{tabular}{ccc} % \pdffield_radio:n{inunison=false,name=C,value=Bär,appearance=pdffield/bear,width=\box_wd:N\l_pdffield_bear_box,height=\box_ht:N\l_pdffield_bear_box}& % \pdffield_radio:n{name=C,value=Sieglinde,default,appearance=pdffield/hippo,width=\box_wd:N\l_pdffield_hippo_box,height=\box_ht:N\l_pdffield_hippo_box}& % \pdffield_radio:n{name=C,value=Duck,appearance=pdffield/duck,width=\box_wd:N\l_pdffield_duck_box,height=\box_ht:N\l_pdffield_duck_box}\\[1ex] % \pdffield_radio:n{name=C,value=Bär}& % \pdffield_radio:n{name=C,value=Sieglinde}& % \pdffield_radio:n{name=C,value=Duck} % \end{tabular} % \ExplSyntaxOff % \end{center} % % Please keep in mind % \begin{itemize} % \item Not every PDF viewer supports radio buttons. % \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{Radio buttons} % Click me: % \ExplSyntaxOn % ^^A \pdffield_radio:n{name=bear,appearance=pdffield/bear,width=23pt,height=30pt,depth=10pt} % \ExplSyntaxOff % % Radio buttons are similar to checkboxes and % they have like checkboxes two \enquote{states}: % checked and unchecked. % % The difference is that multiple checkboxes are either \enquote{clones} of each other % which are checked and unchecked together, % or they are independent of each other. % Radio buttons on the other side build \emph{groups} % where checking one of the buttons unchecks all other buttons. % The elements of a such a radio button group are annotations of one field which % has a flag set which makes it into a radio button group. % % In a checkbox field the two states have the % fix names |/Yes| and |/Off|. % % \begin{center} % \begin{tikzpicture}[level 2/.style={level distance=7mm}, % level 1/.style={sibling distance=25mm}, % level 2/.style={sibling distance=15mm}] % \node[draw] {checkbox field} % child {node[draw,dashed,align=left,font=\ttfamily] % {\textrm{annotation}\\ /Yes\\ % /Off % }} % child {node[draw,dashed,align=left,font=\ttfamily] % {\textrm{annotation}\\ /Yes\\ % /Off % }} % ; % \end{tikzpicture} % \end{center} % % In radio buttons % the off state should still always have the name |/Off|\footnote{% % the PDF reference doesn't say anything about this, but various tests showed that % one better should stick to this name, with other names the buttons disappeared.} % but the on state should be a specific value for every button. % The field dictionary should then set % in the |/V| key as the value of one of the button. % This button is then set as selected and all the other are deselected when the % PDF is opened or reset. % % It is theoretically possible to control the start appearance state for every % button so e.g. all buttons could have the \enquote{selected} state when the PDF is opened. % But as soon as one button is clicked % you get one selected button and the other are unselected. You can't select or % deselect all buttons. The PDF reference mentions an flag |NoToggleToOff| but this % doesn't do anything, at least not in the PDF viewers I tried. For this % reason setting special start states is currently not supported: it complicates the code and the % input for no real gain. % % % The values of the individual buttons can be coded as annotation state names: % % \begin{center} % \begin{tikzpicture}[level 2/.style={level distance=7mm}, % level 1/.style={sibling distance=25mm}, % level 2/.style={sibling distance=15mm}] % \node[draw,align=left,font=\ttfamily] {\textrm{radio button field}\\/V /value1 } % child {node[draw,dashed,align=left,font=\ttfamily] % {\textrm{annotation}\\ /value0 \\ % /Off % }} % child {node[draw,dashed,align=left,font=\ttfamily] % {\textrm{annotation}\\ /value1 \\ % /Off % }} % child {node[draw,dashed,align=left,font=\ttfamily] % {\textrm{annotation}\\ /value2 \\ % /Off % }} % ; % \end{tikzpicture} % \end{center} % % But it can be awkward to have to use the values also as names of appearances states, it % makes it for example difficult to use unicode for the value names, so there is another % option: One can set up an |/Opt| array which contains the values as strings, % and used \enquote{named numbers} as appearance state name: The numbers % |/0|, |/1| point then to the index position in the array. % % \begin{center} % \begin{tikzpicture}[level 2/.style={level distance=7mm}, % level 1/.style={sibling distance=25mm}, % level 2/.style={sibling distance=15mm}] % \node[draw,align=left,font=\ttfamily] {\textrm{radio button field}\\ % /Opt [(value0) (value1) (value2)] % /V /0 } % child {node[draw,dashed,align=left,font=\ttfamily] % {\textrm{annotation}\\ /0 \\ % /Off % }} % child {node[draw,dashed,align=left,font=\ttfamily] % {\textrm{annotation}\\ /1 \\ % /Off % }} % child {node[draw,dashed,align=left,font=\ttfamily] % {\textrm{annotation}\\ /2 \\ % /Off % }} % ; % \end{tikzpicture} % \end{center} % % This method is clearly more flexible, and so it is used in this module. % % As radio buttons build a group of buttons, there is more interaction going on, % and more values have to be set. Also the first command, which initializes the field, % has to set the default value of the group. % % This means a typical setup should do something like this % % \begin{verbatim} % \pdffield_radio:n % { % group = A, % required, can also be given as name=A or T=A % value = button1, % required, on-state of this button % % if not given choice (button1) is used % % should refer to an existing button! % % It will set the V and the DV key % % button4 will be checked % } % \pdffield_radio:n % { % group = A, % required, can also be given as name=A or T=A % value = button2 % required, export value of this button % default % this button is default of the group, % } % \pdffield_radio:n % { % group = A, % required, can also be given as name=A or T=A % value = button3, % required, choice/export value of this button % } % \pdffield_radio:n % { % group = A, % required, can also be given as name=A or T=A % value = button4 % required, choice/export value of this button % } % \end{verbatim} % % % If two radio field annotations use the same |value| this value can be mapped either % to the same index or to two different indices in the \texttt{/Opt} array. % In the first case they are selected and unselected together (\enquote{in unison}), % like checkboxes with the same |/Yes| state. The key |inunison| below allows to switch % between the two cases. The flag |RadiosInUnison| % is neither needed for this (but doesn't harm either) nor % does it change the behaviour, at least again not in the PDF viewers I tried, % nevertheless the key will set it accordingly just in case. The two examples at % the begin of the document show the two variants. % % % The button with the key |default| will be selected at the start (together with the % buttons with the same value). If no default is set this is the first button. % % \bigskip % \subsection{Commands} % \begin{function}{\pdffield_radio:n} % \begin{syntax} % \cs{pdffield_radio:n}\Arg{key val list} % \end{syntax} % This creates a radio button to check and uncheck. % The list of allowed keys is described below. % The \meta{key val list} should at least set the group name, % without it the default group % |radio| is used. Radiobuttons with the same % group name belong to the same field and if checked, the others are unchecked. % The default appearance % is a circle frame with a black bullet in it for the checked case. % The default appearance is setup at the first use. Its geometry is quadratic. % % The first radio button setups the field and should also set the button which % should be shown as selected when the PDF is opened. % \end{function} % % % \subsection{Keys} % % The new radio 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 radio specific % behaviour, other keys have other defaults than with the basic commands. % Additionally there % are a small number of keys specific to a radio button. % |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 radio buttons only the field flags |ReadOnly|, |Required|, |NoExport|, % |NoToggleToOff| and |RadiosInUnison| make sense. The last two are as mentioned % above probably useless. % |Radio| is set automatically automatically by the code % as this is required for a radio button set. % \end{itemize} % % % \begin{function}{preset-radiobutton} % \begin{syntax} % |preset-radiobutton| = \Arg{key-val-list} % \end{syntax} % This allows to set default keys for a radio button. % \end{function} % % \begin{function}{group,name,T} % \begin{syntax} % |group| = \meta{partial name}\\ % |name| = \meta{partial name}\\ % |T| = \meta{partial name} % \end{syntax} % These keys set the partial name of the field. They all 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 radio buttons with the same partial name are annotations % with the same field as parent and so build a radio button group. % 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} % \begin{syntax} % |value| = \meta{string} % \end{syntax} % With this key you set the export value name for the individual buttons. % Every button should have a value. % buttons with the same value are checked in unison. The value can use unicode. % \end{function} % % \begin{function}{default} % \begin{syntax} % |default| % \end{syntax} % With this key you set the button which is checked when the PDF is opened. % The key must be used in the command of the button which should be the default. % If it is missing the first button is used as default. % A label-ref system is used to get the right numbers, so normally two compilations % are needed if the first button is not the default % \end{function} % % \begin{function}{inunison} % \begin{syntax} % |inunison| = |true|\verb+|+|false| % \end{syntax} % As described above this handle the \enquote{inunison} behaviour. % If set to true (the default) % buttons with the same value will be selected and unselected together. % The keys sets or unsets also the flag |RadiosInUnison| accordingly % (but it is unknown if it has any effect). The key should be set on the first % field. Normally it should be unneeded to use the key: % to avoid the unison effect it makes more sense to use different values. % \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 radio button. % 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/radio/default| % for the normal appearance and shows a button. % The down appearance enlarges the middle button a bit to give a visual feed back. % \end{function} % % \subsection{Using with hyperref} % Radio buttons in hyperref are created with \cs{ChoiceMenu} command, and % they also print a label. choices are actually a different field type and % so created with different commands. It is not quite clear yet, % how this could be mapped. % % % \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-radiobutton} Implementation} % \begin{macrocode} %<*package> %<@@=pdffield> \RequirePackage{l3draw} % \end{macrocode} % \subsection{Variables} % \begin{variable} % { % \l_@@_radio_value_tl % ,\l_@@_radio_default_bool % ,\l_@@_radio_value_num_int % ,\l_@@_radio_appearance_code_tl % } % variables to hold the value, its index numbers and the default value. % radio buttons can setup the appearance only after the value is known, % so the code is stored and executed later. % \begin{macrocode} \tl_new:N \l_@@_radio_value_tl \bool_new:N \l_@@_radio_default_bool \int_new:N \l_@@_radio_value_num_int \tl_new:N \l_@@_radio_appearance_code_tl \bool_new:N \l_@@_radio_unison_bool % if true use same name (e.g. /1) for same value \bool_set_true:N \l_@@_radio_unison_bool % \end{macrocode} % \end{variable} % % \subsection{Appearances} % The default appearances are a circle with button in it. % Every appearance should have two versions and follow the naming % module/\meta{name}/Yes and module/\meta{name}/Off. % % \begin{macro}[int] % { % \@@_radio_default_appearances:, % pdffield/radio/default/Yes, % pdffield/radio/default/Off, % pdffield/radio/defaultdown/Yes, % pdffield/radio/defaultdown/Off % } % This defines the standard appearances. They are setup at the first % use of a radiobutton. % \begin{macrocode} \cs_new_protected:Npn \@@_radio_default_appearances: { \pdffield_appearance:nn {pdffield/radio/default/Yes} { \normalsize \draw_begin: \draw_path_circle:nn {0pt,0pt}{0.5\normalbaselineskip} \draw_path_use_clear:n { stroke } \draw_path_circle:nn {0pt,0pt}{0.2\normalbaselineskip} \draw_path_use_clear:n { fill } \draw_end: } \pdffield_appearance:nn {pdffield/radio/default/Off} { \normalsize \draw_begin: \draw_path_circle:nn {0pt,0pt}{0.5\normalbaselineskip} \draw_path_use_clear:n { stroke } \draw_end: } \pdffield_appearance:nn {pdffield/radio/defaultdown/Yes} { \normalsize \draw_begin: \draw_path_circle:nn {0pt,0pt}{0.5\normalbaselineskip} \draw_path_use_clear:n { stroke } \draw_path_circle:nn {0pt,0pt}{0.25\normalbaselineskip} \draw_path_use_clear:n { fill } \draw_end: } \pdffield_appearance:nn {pdffield/radio/defaultdown/Off} { \normalsize \draw_begin: \draw_path_circle:nn {0pt,0pt}{0.5\normalbaselineskip} \draw_path_use_clear:n { stroke } \draw_path_circle:nn {0pt,0pt}{0.25\normalbaselineskip} \draw_path_use_clear:n { fill } \draw_end: } \cs_gset_eq:NN \@@_radio_default_appearances: \prg_do_nothing: } % \end{macrocode} % \end{macro} % %\subsection{Creating the field} % We need to retrieve the index of the default through a % label, so we need an ref attribute or with newer LaTeX % a property: % % \begin{macrocode} \cs_if_exist:NTF \property_new:nnnn { \property_new:nnnn {pdfradioindex}{now} {0} { \int_use:N\l_@@_radio_value_num_int } \cs_new_eq:NN \@@_property_record:nn \property_record:nn \cs_new_eq:NN \@@_property_ref:nn \property_ref:nn } { \ref_attribute_gset:nnnn {pdfradioindex}{0}{now} { \int_use:N\l_@@_radio_value_num_int } \cs_new_eq:NN \@@_property_record:nn \ref_label:nn \cs_new_eq:NN \@@_property_ref:nn \ref_value:nn } \cs_generate_variant:Nn \@@_property_record:nn {V} \cs_generate_variant:Nn \@@_property_ref:nn {V} % \end{macrocode} % A field should be created if the name doesn't exist yet % \begin{macro}{\@@_radio_field:n} % \begin{macrocode} \cs_new_protected:Npn \@@_radio_field:n #1 %name { \pdf_object_if_exist:nF {@@/field/@@/radio/#1} { % \end{macrocode} % We need an object and a seq for the Opt array. % The object is written at the end of the document. % \begin{macrocode} \pdf_object_new:n {@@/field/@@/radio-Opt/#1} \pdfdict_put:nne { l_@@/field }{Opt} { \pdf_object_ref:n {@@/field/@@/radio-Opt/#1} } \seq_new:c { g_@@_radio_opt_#1_seq } \hook_gput_code:nnn {shipout/lastpage}{pdffield/radio} { \pdf_object_write:nne {@@/field/@@/radio-Opt/#1} { array } {\seq_use:cn {g_@@_radio_opt_#1_seq}{~}} } % \end{macrocode} % The default value is retrieved through a label: % \begin{macrocode} \pdfdict_put:nne { l_@@/field }{V} { /\@@_property_ref:nn{#1}{pdfradioindex} } \pdfdict_put:nne { l_@@/field }{DV} { /\@@_property_ref:nn{#1}{pdfradioindex} } % \end{macrocode} % now we create the field and set it as parent for the following annotation. % \begin{macrocode} \@@_field:n { @@/radio/#1 } % \end{macrocode} % If the inunison bool has been set to false we need to pass this to the % kids. % \begin{macrocode} \bool_if:NF \l_@@_radio_unison_bool { \cs_new:cpn {g_@@_radio_unison_state_#1_tl} { \bool_set_false:N \l_@@_radio_unison_bool } } } \keys_set:nn {pdffield}{parent={@@/radio/#1}} } \cs_generate_variant:Nn \@@_radio_field:n {V} % \end{macrocode} % \end{macro} % % \subsection{Assembling the radio} % % \begin{macro}{\@@_radio:n} % The argument are key-val settings. % At first we map the handlers. To setup the appearance we need the % Opt array, so the appearance handler only stores the code. % \begin{macrocode} \cs_new_protected:Npn \@@_radio:n #1 { \group_begin: \cs_set_eq:NN\@@_appearance_handler:nnn \@@_radio_appearance_handler:nnn \cs_set_eq:NN\@@_value_handler:n \@@_radio_value_handler:n \cs_set_eq:NN\@@_default_handler:n \@@_radio_default_handler:n % \end{macrocode} % Setting up the defaults. % \begin{macrocode} \tl_set:Nn\l_@@_radio_appearance_code_tl{} \bool_set_false:N\l_@@_radio_default_bool \keys_set:nn {pdffield} { fieldID= ,name=radio ,width = \normalbaselineskip ,height = \normalbaselineskip ,inunison ,@@/preset/radiobutton ,#1 ,unsetFf={Pushbutton} ,setFf={Radio} ,FT= Btn } % \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 {@pdffield/radio/} } % \end{macrocode} % If unison has been set for the field pass it on: % \begin{macrocode} \cs_if_exist_use:c {g_@@_radio_unison_state_ \l_@@_fieldID_tl _tl} % \end{macrocode} % Now we build the field % \begin{macrocode} \@@_radio_field:V\l_@@_fieldID_tl % \end{macrocode} % Put the value into the seq % \begin{macrocode} \seq_gput_right:cV { g_@@_radio_opt_ \l_@@_fieldID_tl _seq }\l_@@_radio_value_tl % \end{macrocode} % Retrieve the number for the label % \begin{macrocode} \bool_if:NTF \l_@@_radio_unison_bool { \int_zero:N \l_@@_radio_value_num_int \exp_args:Nc \seq_map_inline:Nn { g_@@_radio_opt_ \l_@@_fieldID_tl _seq } { \str_if_eq:nVTF { ##1 } \l_@@_radio_value_tl { \seq_map_break: } { \int_incr:N \l_@@_radio_value_num_int } } } { \int_set:Nn \l_@@_radio_value_num_int {\seq_count:c { g_@@_radio_opt_ \l_@@_fieldID_tl _seq } -1 } } \bool_if:NT\l_@@_radio_default_bool { \@@_property_record:Vn\l_@@_fieldID_tl{pdfradioindex} } % \end{macrocode} % Annotations with the default value are set to on, the rest to off % \begin{macrocode} \int_compare:nNnTF { \l_@@_radio_value_num_int } = { \@@_property_ref:Vn\l_@@_fieldID_tl{pdfradioindex} } { \pdfannot_dict_put:nne {widget}{AS}{/\@@_property_ref:Vn\l_@@_fieldID_tl{pdfradioindex}} } { \pdfannot_dict_put:nne {widget}{AS}{/Off} } % \end{macrocode} % Now we set the appearances, if no key has been use we take the default. % \begin{macrocode} \tl_if_empty:NT\l_@@_radio_appearance_code_tl { \@@_radio_default_appearances: \keys_set:nn {pdffield} { appearance = pdffield/radio/default, down-appearance = pdffield/radio/defaultdown, } } \l_@@_radio_appearance_code_tl \@@_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}{\@@_radio_value_handler:n,\@@_radio_default_handler:n} % \begin{macrocode} \cs_new_protected:Npn \@@_radio_value_handler:n #1 { \pdf_string_from_unicode:nnN {utf16/string}{#1}\l_@@_radio_value_tl } \cs_new_protected:Npn \@@_radio_default_handler:n #1 { %\pdf_string_from_unicode:nnN {utf8/string}{#1}\l_@@_radio_default_tl \bool_set_true:N \l_@@_radio_default_bool } % \end{macrocode} % \end{macro} % % \begin{macro}{group} % \begin{macrocode} \keys_define:nn { pdffield } { group .meta:n = {T=#1} } % \end{macrocode} % \end{macro} % % \begin{macro}{inunison} % \begin{macrocode} \keys_define:nn { pdffield } { inunison .choice: ,inunison / true .code:n = { \bool_set_true:N \l_@@_radio_unison_bool \bitset_set_true:Nn \l_@@_Ff_bitset {RadiosInUnison} } ,inunison / false .code:n = { \bool_set_false:N \l_@@_radio_unison_bool \bitset_set_false:Nn \l_@@_Ff_bitset {RadiosInUnison} } ,inunison .default:n = {true} } % \end{macrocode} % \end{macro} % \begin{macro}{\@@_radio_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 \@@_radio_appearance_handler:nnn #1 #2 #3 %name, type, text { \tl_put_right:Nn \l_@@_radio_appearance_code_tl { \pdfxform_if_exist:nTF { #1 / Yes } { \pdf_object_unnamed_write:ne {dict} { /\int_use:N \l_@@_radio_value_num_int \c_space_tl \pdfxform_ref:n { #1/Yes} /Off ~ \pdfxform_ref:n { #1/Off} } \pdfannot_dict_put:nne {widget/AP}{#2}{\pdf_object_ref_last:} } { \msg_error:nnnn{pdffield}{appearance-missing}{#1}{#3} } } } % \end{macrocode} % % \end{macro} % % \subsection{User commands} % \begin{macro}{\pdffield_radio:n} % \begin{macrocode} \cs_set_eq:NN \pdffield_radio:n \@@_radio:n % % \end{macrocode} % \end{macro} %\end{implementation} % \PrintIndex