texlive[59455] Master/texmf-dist: ocgx2 (3jun21)

commits+karl at tug.org commits+karl at tug.org
Thu Jun 3 22:49:47 CEST 2021


Revision: 59455
          http://tug.org/svn/texlive?view=revision&revision=59455
Author:   karl
Date:     2021-06-03 22:49:47 +0200 (Thu, 03 Jun 2021)
Log Message:
-----------
ocgx2 (3jun21)

Modified Paths:
--------------
    trunk/Master/texmf-dist/doc/latex/ocgx2/ChangeLog
    trunk/Master/texmf-dist/tex/latex/ocgx2/ocgbase.sty
    trunk/Master/texmf-dist/tex/latex/ocgx2/ocgx2.sty

Modified: trunk/Master/texmf-dist/doc/latex/ocgx2/ChangeLog
===================================================================
--- trunk/Master/texmf-dist/doc/latex/ocgx2/ChangeLog	2021-06-03 20:49:33 UTC (rev 59454)
+++ trunk/Master/texmf-dist/doc/latex/ocgx2/ChangeLog	2021-06-03 20:49:47 UTC (rev 59455)
@@ -1,3 +1,12 @@
+2021-06-03
+	* v0.51: ocgx2.sty
+	* v0.19: ocgbase.sty
+	* fix: pdfmanagement-testphase; ocgcolorlinks
+
+2021-01-25
+	* v0.50: ocgx2.sty
+	* v0.18: ocgbase.sty
+
 2020-06-11
 	* v0.49: ocgx2.sty
 	* fix: `ocgcolorlinks': fixing misplaced page content resulting from

Modified: trunk/Master/texmf-dist/tex/latex/ocgx2/ocgbase.sty
===================================================================
--- trunk/Master/texmf-dist/tex/latex/ocgx2/ocgbase.sty	2021-06-03 20:49:33 UTC (rev 59454)
+++ trunk/Master/texmf-dist/tex/latex/ocgx2/ocgbase.sty	2021-06-03 20:49:47 UTC (rev 59455)
@@ -1,3 +1,11 @@
+%%%%%%%%%%%%%%%%%%%%%% pdfmanagement-testphase %%%%%%%%%%%%%%%%%%%
+\newif\if at ocgbase@testphase
+\ExplSyntaxOn
+\bool_if:nT {
+  \bool_lazy_and_p:nn {\cs_if_exist_p:N \pdfmanagement_if_active_p:} { \pdfmanagement_if_active_p: }
+}{\@ocgbase at testphasetrue}
+\ExplSyntaxOff
+\if at ocgbase@testphase\else
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 %
 % ocgbase.sty
@@ -94,8 +102,8 @@
 
 \RequirePackage{l3keys2e}
 
-\def\g at ocgbase@date at tl{2021/01/25}
-\def\g at ocgbase@version at tl{0.18}
+\def\g at ocgbase@date at tl{2021/06/03}
+\def\g at ocgbase@version at tl{0.19}
 
 \ProvidesExplPackage{ocgbase}{\g at ocgbase@date at tl}{\g at ocgbase@version at tl}
 {support package for ocgx2.sty}
@@ -364,3 +372,378 @@
 \cs_gset_eq:NN\ocgbase at oc@emc\ocgbase_oc_emc:
 \cs_gset_eq:NN\ocgbase at open@stack at pop\ocgbase_open_stack_pop:N
 \cs_gset_eq:NN\ocgbase at open@stack at push\ocgbase_open_stack_push:n
+\endinput
+\fi
+%%%%%%%%%%%%%%%%%%%%%% /pdfmanagement-testphase %%%%%%%%%%%%%%%%%%%
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+% ocgbase.sty
+%
+% low-level macros for OCG creation, marking optional content and
+% for managment of global (document-wide) OCG related lists;
+%
+% (automatic) OCG configuration in the PDF catalog
+%
+% Copyright 2015--\today, Alexander Grahn
+%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+% Support package for ocgx2.sty, media9.sty, animate.sty
+%
+% Supported workflows:
+%
+%   pdflatex, lualatex
+%   latex-->dvips-->ps2pdf or Distiller
+%   latex-->dvipdfmx
+%   xelatex
+%
+%   for `dvipdfmx', set it as document class option
+%
+%
+% Commands defined:
+%
+%   \ocgbase_new_ocg:nnn
+%   \ocgbase at new@ocg (LaTeX2e version)
+%     #1: name (as shown in the Layers Tab of the Reader GUI)
+%     #2: usage dict (may be empty), see PDF reference:
+%         http://wwwimages.adobe.com/content/dam/Adobe/en/devnet/pdf/pdfs/
+%                pdf_reference_1-7.pdf#G9.3858276
+%     #3: initial visibility (1|0|true|false|on|off|visible|invisible)
+%
+%   \ocgbase_last_ocg:
+%   \ocgbase at last@ocg (LaTeX2e version)
+%     inserts ID of PDF object created during most recent call of
+%     \ocgbase_new_ocg:nnn
+%
+%   --------
+%
+%   \ocgbase_tree_node_begin:n
+%   \ocgbase_tree_node_end:
+%   \ocgbase at tree@node at begin (LaTeX2e versions)
+%   \ocgbase at tree@node at end
+%     #1: OCG PDF object
+%     macro pair (begin and end) for inserting OCG object and its children
+%     into Order hierarchy (shown as tree structure in the viewers `Layers' tab
+%
+%   --------
+%
+%   \ocgbase_add_to_off_list:n
+%   \ocgbase at add@to at off@list (LaTeX2e version)
+%     #1: PDF object ID of OCG
+%     macro for setting initial visibility to `off'
+%
+%   --------
+%
+%   \ocgbase_del_from_off_list:n
+%   \ocgbase at del@from at off@list (LaTeX2e version)
+%     #1: PDF object ID of OCG
+%     macro for setting initial visibility to `on'
+%
+%   --------
+%
+%   \ocgbase_add_ocg_to_radiobtn_grp:nn
+%   \ocgbase at add@ocg at to@radiobtn at grp
+%     add OCG #2 (obj ref) to radio button group `#1' (string),
+%
+%   --------
+%
+%   \ocgbase_oc_bdc:n
+%   \ocgbase at oc@bdc
+%     #1: OCG obj ref
+%     mark begin of optional content belonging to OCG #1 in the current
+%     content stream
+%
+%   \ocgbase_oc_emc:
+%   \ocgbase at oc@emc
+%     mark end of optional content in the current content stream
+%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+% This work may be distributed and/or modified under the
+% conditions of the LaTeX Project Public License.
+%
+% The latest version of this license is in
+%   http://mirrors.ctan.org/macros/latex/base/lppl.txt
+%
+% This work has the LPPL maintenance status `maintained'.
+%
+% The Current Maintainer of this work is A. Grahn.
+
+\RequirePackage{l3keys2e}
+
+\def\g at ocgbase@date at tl{2021/06/03}
+\def\g at ocgbase@version at tl{0.19}
+
+\ProvidesExplPackage{ocgbase}{\g at ocgbase@date at tl}{\g at ocgbase@version at tl}
+{support package for ocgx2.sty}
+
+%package options
+
+%unknown package option error message
+\msg_set:nnnn{ocgbase}{unknown~package~option}{Unknown~package~option~`#1'.}{
+  Package option~'#1'~is~unknown;\\
+  perhaps~it~is~spelled~incorrectly.
+}
+
+\keys_define:nn{ocgbase}{
+  xetex .code:n = {}, %dummy
+
+  dvipdfmx .choice:,
+  dvipdfmx / true .code:n = {\PassOptionsToPackage{dvipdfmx}{pdfbase}},
+  dvipdfmx / false .code:n = {},
+  dvipdfmx .default:n = {true},
+
+  unknown .code:n = {
+    \msg_error:nnx{ocgbase}{unknown~package~option}{\l_keys_key_tl}
+  }
+}
+\ProcessKeysOptions{ocgbase}
+
+\RequirePackage{pdfbase}
+
+\msg_set:nnnn{ocgbase}{support~outdated}{
+  Support~package~`#1'~too~old.
+}{
+  Get~an~up~to~date~version~of~`#1'.\\
+  Aborting.
+}
+\@ifpackagelater{pdfbase}{2017/09/29}{}{
+  \msg_error:nnn{ocgbase}{support~outdated}{pdfbase.sty}
+  \tex_endinput:D
+}
+
+\tl_new:N\g_ocgbase_ocgs_tl %takes ocg object refs
+\seq_new:N\g_ocgbase_offocgs_seq
+
+\AddToHook{shipout/lastpage}{
+  \tl_if_empty:NF\g_ocgbase_ocgs_tl{
+    %global OCG array
+    \pbs_pdfobj:nnn{}{array}{\g_ocgbase_ocgs_tl}
+    \tl_set:Nx\l_ocgbase_ocgarray_tl{\pbs_pdflastobj:}
+    \tl_new:N\l_ocgbase_offocgentry_tl
+    %global OFF list
+    \seq_if_empty:NF\g_ocgbase_offocgs_seq{
+      \pbs_pdfobj:nnn{}{array}{\seq_use:Nn\g_ocgbase_offocgs_seq{~}}
+      \tl_set:Nx\l_ocgbase_offocgentry_tl{/OFF~\pbs_pdflastobj:}
+    }
+    %global Order list
+    \tl_new:N\l_ocgbase_ocgorderentry_tl
+    \tl_new:N\l_ocgbase_ocgorder_tl
+    \tl_if_exist:cT{g_ocgbase_nd_0_chld_tl}{
+      \ocgbase_build_order:Nn\l_ocgbase_ocgorder_tl{
+        \tl_use:c{g_ocgbase_nd_0_chld_tl}
+      }
+    }
+    \tl_if_empty:NF\l_ocgbase_ocgorder_tl{
+      \pbs_pdfobj:nnn{}{array}{\l_ocgbase_ocgorder_tl}
+      \tl_set:Nx\l_ocgbase_ocgorderentry_tl{/Order~\pbs_pdflastobj:}
+    }
+    %generate RBGroups entry (radio button groups)
+    \tl_new:N\l_ocgbase_rbtn_groups_tl
+    \seq_map_inline:Nn\g_ocgbase_rbtn_groups_seq{
+      \int_compare:nT{\seq_count:c{g_ocgbase_rbtn_group_#1_seq}>\c_one_int}{
+        \tl_put_right:Nx\l_ocgbase_rbtn_groups_tl{
+          ~[\seq_use:cn{g_ocgbase_rbtn_group_#1_seq}{~}]
+        }
+      }
+    }
+    \tl_new:N\l_ocgbase_rbgroupsentry_tl
+    \tl_if_empty:NF\l_ocgbase_rbtn_groups_tl{
+      \pbs_pdfobj:nnn{}{array}{\l_ocgbase_rbtn_groups_tl}
+      \tl_set:Nx\l_ocgbase_rbgroupsentry_tl{/RBGroups~\pbs_pdflastobj:}
+    }
+    \pdfmanagement_add:nnx{Catalog/OCProperties}{OCGs}{\g_ocgbase_ocgs_tl}
+    \pdfmanagement_add:nnx{Catalog/OCProperties}{D}{<<
+          /AS~[
+            <</Event/View  /Category[/View]  /OCGs~\l_ocgbase_ocgarray_tl>>
+            <</Event/Print /Category[/Print] /OCGs~\l_ocgbase_ocgarray_tl>>
+            <</Event/Export/Category[/Export]/OCGs~\l_ocgbase_ocgarray_tl>>
+          ]
+          /BaseState/ON~\l_ocgbase_offocgentry_tl
+          \l_ocgbase_ocgorderentry_tl
+          \l_ocgbase_rbgroupsentry_tl
+          /ListMode/VisiblePages
+        >>
+    }
+  }
+}
+
+%macro for inserting new OCG object
+\cs_generate_variant:Nn\pdf_object_new:nn{xn}
+\cs_generate_variant:Nn\pdf_object_write:nn{xx}
+\int_new:N\g_ocgbase_int
+\cs_new_protected_nopar:Nn\ocgbase_new_ocg:nnn{
+  \pdf_object_new:xn{g_object_\int_use:N\g_ocgbase_int _pdf}{dict}
+  \pdf_object_write:xx{g_object_\int_use:N\g_ocgbase_int _pdf}{
+    /Type/OCG/Name~(#1)~\str_if_eq:eeF{#2}{}{/Usage<<#2>>}
+  }
+  \tl_gput_right:Nx\g_ocgbase_ocgs_tl{~\pdf_object_ref_last:}
+  \bool_if:nT{
+    \str_if_eq_p:ee{#3}{0} ||
+    \str_if_eq_p:ee{#3}{off} ||
+    \str_if_eq_p:ee{#3}{false} ||
+    \str_if_eq_p:ee{#3}{invisible}
+  }{
+    \ocgbase_add_to_off_list:n{\pdf_object_ref_last:}
+  }
+  \tl_gset:Nx\g_ocgbase_last_ocg_tl{\pdf_object_ref_last:}
+  \tl_gset:cx{g_pbs_objname_\pdf_object_ref_last: _tl}{
+    g_object_\int_use:N\g_ocgbase_int _pdf
+  } 
+  \int_gincr:N\g_ocgbase_int
+}
+
+\cs_new_nopar:Nn\ocgbase_last_ocg:{\g_ocgbase_last_ocg_tl}
+
+\int_new:N\g_ocgbase_nd_int    %node id
+\seq_new:N\g_ocgbase_tree_nd_stack_seq    %stack with open ocg node id
+\seq_new:N\g_ocgbase_tree_ocg_stack_seq    %stack with open ocg obj number
+\seq_gpush:Nn\g_ocgbase_tree_nd_stack_seq{0}    %push root node
+\seq_gpush:Nn\g_ocgbase_tree_ocg_stack_seq{null}    %push root node
+
+%macro for starting OCG object (and nested children) insertion into Order
+%hierarchy (shown as tree structure in the viewers `Layers' tab
+\cs_new_protected:Nn\ocgbase_tree_node_begin:n{ % #1: OCG obj
+  %get the parent node from stack
+  \seq_get:NN\g_ocgbase_tree_nd_stack_seq\l__ocgbase_prnt_tl
+  \tl_if_exist:cTF{g_ocgbase_nd_\l__ocgbase_prnt_tl _chld_tl}{
+    %parent has >=1 children (i. e. my older siblings), traverse them
+    \tl_set:Nv\l__ocgbase_prev_sbl_tl{g_ocgbase_nd_\l__ocgbase_prnt_tl _chld_tl}
+    \tl_set:Nx\l__ocgbase_cur_ocg_tl{#1}
+    \ocgbase_traverse_siblings:NN\l__ocgbase_prev_sbl_tl\l__ocgbase_cur_ocg_tl
+    \str_if_empty:NTF\l__ocgbase_cur_ocg_tl{
+      %I am the first child of my parent to refer to OCG #1
+      \int_gincr:N\g_ocgbase_nd_int
+      \tl_set:Nx\l__ocgbase_cur_nd_tl{\int_use:N\g_ocgbase_nd_int}
+      %set myself as my next-older sibling's `next sibling'
+      \tl_gset:cV{
+        g_ocgbase_nd_\l__ocgbase_prev_sbl_tl _sbl_tl}\l__ocgbase_cur_nd_tl
+    }{
+      %there is already a sibling referring to OCG #1; no new node needs be
+      %created
+      \tl_set:NV\l__ocgbase_cur_nd_tl\l__ocgbase_prev_sbl_tl
+    }
+  }{
+    %I am the very first child of my parent
+    \int_gincr:N\g_ocgbase_nd_int
+    \tl_set:Nx\l__ocgbase_cur_nd_tl{\int_use:N\g_ocgbase_nd_int}
+    %set myself as my parent's first child
+    \tl_gset:cV{g_ocgbase_nd_\l__ocgbase_prnt_tl _chld_tl}\l__ocgbase_cur_nd_tl
+  }
+  %set the OCG I am referring to
+  \tl_gset:cx{g_ocgbase_nd_\l__ocgbase_cur_nd_tl _ocg_tl}{#1}
+  %push current node and its associated OCG obj on the stacks
+  \seq_gpush:NV\g_ocgbase_tree_nd_stack_seq\l__ocgbase_cur_nd_tl
+  \seq_gpush:Nx\g_ocgbase_tree_ocg_stack_seq{#1}
+}
+
+%macro that ends insertion of OCG and sub-OCGs into Order tree
+\cs_new_protected:Nn\ocgbase_tree_node_end:{
+  \seq_get:NN\g_ocgbase_tree_nd_stack_seq\l_tempa_tl
+  \seq_get:NN\g_ocgbase_tree_ocg_stack_seq\l_tempb_tl
+  \str_if_eq:eeT{
+    \cs_if_exist_use:c{g_ocgbase_nd_\l_tempa_tl _ocg_tl}
+  }{
+    \l_tempb_tl
+  }{
+    \seq_gpop:NN\g_ocgbase_tree_nd_stack_seq\g_trash_tl
+    \seq_gpop:NN\g_ocgbase_tree_ocg_stack_seq\g_trash_tl
+  }
+}
+
+% helper macro (recursive); traverses siblings to find either
+% the node which refers to the same OCG (arg #2 remains un-modified), or
+% the last sibling inserted (arg #2 is cleared);
+% the node id of the sibling found is returned in arg #1
+\cs_new:Nn\ocgbase_traverse_siblings:NN{
+  % #1: current node (in/out),  #2: OCG obj (in/out)
+  \str_if_eq:eeF{#2}{\tl_use:c{g_ocgbase_nd_#1_ocg_tl}}{
+    \tl_if_exist:cTF{g_ocgbase_nd_#1_sbl_tl}{
+      \tl_set:Nv#1{g_ocgbase_nd_#1_sbl_tl}
+      \ocgbase_traverse_siblings:NN#1#2
+    }{
+      \tl_clear:N#2
+    }
+  }
+}
+
+\cs_new:Nn\ocgbase_build_order:Nn{
+  % (recursive macro)
+  % #1: tl var to which the OCG order is written (output)
+  % #2: starting node id (input; usually `1')
+  \tl_set:Nx\l__ocgbase_cur_nd_tl{#2}
+  % first, append the OCG obj the current node is referring to
+  \tl_put_right:Nx#1{~\tl_use:c{g_ocgbase_nd_\l__ocgbase_cur_nd_tl _ocg_tl}}
+  % second, traverse the tree starting with the first child node
+  \tl_if_exist:cT{g_ocgbase_nd_\l__ocgbase_cur_nd_tl _chld_tl}{
+    \seq_gpush:NV\g_ocgbase_tree_nd_stack_seq\l__ocgbase_cur_nd_tl
+    \tl_put_right:Nn#1{~[}
+    \ocgbase_build_order:Nn#1{
+      \tl_use:c{g_ocgbase_nd_\l__ocgbase_cur_nd_tl _chld_tl}}
+    \tl_put_right:Nn#1{~]}
+    \seq_gpop:NN\g_ocgbase_tree_nd_stack_seq\l__ocgbase_cur_nd_tl
+  }
+  % third, traverse the tree starting with the next sibling node
+  \tl_if_exist:cT{g_ocgbase_nd_\l__ocgbase_cur_nd_tl _sbl_tl}{
+    \ocgbase_build_order:Nn#1{
+      \tl_use:c{g_ocgbase_nd_\l__ocgbase_cur_nd_tl _sbl_tl}}
+  }
+}
+
+%macro for appending an OCG object to the global `OFF' list
+%(initial non-visibility)
+\cs_new_protected_nopar:Nn\ocgbase_add_to_off_list:n{
+  \seq_if_in:NxF\g_ocgbase_offocgs_seq{#1}{
+    \seq_gput_right:Nx\g_ocgbase_offocgs_seq{#1}
+  }
+}
+
+%macro for removing an OCG object from global `OFF' list
+%(initial non-visibility)
+\cs_new_protected_nopar:Nn\ocgbase_del_from_off_list:n{
+  \seq_if_in:NxT\g_ocgbase_offocgs_seq{#1}{
+    \ocgbase_seq_gremove_all:Nx\g_ocgbase_offocgs_seq{#1}
+  }
+}
+\cs_set_eq:NN\ocgbase_seq_gremove_all:Nn\seq_gremove_all:Nn
+\cs_generate_variant:Nn\ocgbase_seq_gremove_all:Nn{Nx}
+
+\seq_new:N\g_ocgbase_rbtn_groups_seq
+\cs_new_protected_nopar:Nn\ocgbase_add_ocg_to_radiobtn_grp:nn{
+  % #1: rbtn group name,
+  % #2: OCG obj ref
+  \seq_if_exist:cF{g_ocgbase_rbtn_group_#1_seq}{
+    \seq_new:c{g_ocgbase_rbtn_group_#1_seq}
+    \seq_gput_right:Nx\g_ocgbase_rbtn_groups_seq{#1}
+  }
+  \seq_if_in:cxF{g_ocgbase_rbtn_group_#1_seq}{#2}{
+    \seq_gput_right:cx{g_ocgbase_rbtn_group_#1_seq}{#2}
+  }
+}
+
+% OC-marked content
+\cs_new_protected_nopar:Nn\ocgbase_oc_bdc:n{\pbs_pdfbdc:nn{OC}{#1}}
+\cs_new_protected_nopar:Nn\ocgbase_oc_emc:{\pbs_pdfemc:}
+
+%stack of PDF obj references of currently open OCGs
+\seq_new:N\g_ocgbase_open_stack_seq
+%push OCG to stack
+\cs_new_protected_nopar:Nn\ocgbase_open_stack_push:n{
+  \seq_gpush:Nx\g_ocgbase_open_stack_seq{#1}}
+%pop OCG from stack into tl
+\cs_new_protected_nopar:Nn\ocgbase_open_stack_pop:N{
+    \seq_gpop:NN\g_ocgbase_open_stack_seq#1}
+
+%l2e versions
+\cs_gset_eq:NN\ocgbase at new@ocg\ocgbase_new_ocg:nnn
+\cs_gset_eq:NN\ocgbase at last@ocg\ocgbase_last_ocg:
+\cs_gset_eq:NN\ocgbase at tree@node at begin\ocgbase_tree_node_begin:n
+\cs_gset_eq:NN\ocgbase at tree@node at end\ocgbase_tree_node_end:
+\cs_gset_eq:NN\ocgbase at add@to at off@list\ocgbase_add_to_off_list:n
+\cs_gset_eq:NN\ocgbase at del@from at off@list\ocgbase_del_from_off_list:n
+\cs_gset_eq:NN\ocgbase at add@ocg at to@radiobtn at grp\ocgbase_add_ocg_to_radiobtn_grp:nn
+\cs_gset_eq:NN\ocgbase at oc@bdc\ocgbase_oc_bdc:n
+\cs_gset_eq:NN\ocgbase at oc@emc\ocgbase_oc_emc:
+\cs_gset_eq:NN\ocgbase at open@stack at pop\ocgbase_open_stack_pop:N
+\cs_gset_eq:NN\ocgbase at open@stack at push\ocgbase_open_stack_push:n

Modified: trunk/Master/texmf-dist/tex/latex/ocgx2/ocgx2.sty
===================================================================
--- trunk/Master/texmf-dist/tex/latex/ocgx2/ocgx2.sty	2021-06-03 20:49:33 UTC (rev 59454)
+++ trunk/Master/texmf-dist/tex/latex/ocgx2/ocgx2.sty	2021-06-03 20:49:47 UTC (rev 59455)
@@ -1,3 +1,11 @@
+%%%%%%%%%%%%%%%%%%%%%% pdfmanagement-testphase %%%%%%%%%%%%%%%%%%%
+\newif\if at ocgxii@testphase
+\ExplSyntaxOn
+\bool_if:nT {
+  \bool_lazy_and_p:nn {\cs_if_exist_p:N \pdfmanagement_if_active_p:} { \pdfmanagement_if_active_p: }
+}{\@ocgxii at testphasetrue}
+\ExplSyntaxOff
+\if at ocgxii@testphase\else
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 %
 % ocgx2.sty
@@ -39,8 +47,8 @@
 
 \RequirePackage{l3keys2e}
 
-\def\g at ocgxii@date at tl{2021/01/25}
-\def\g at ocgxii@version at tl{0.50}
+\def\g at ocgxii@date at tl{2021/06/03}
+\def\g at ocgxii@version at tl{0.51}
 
 \ProvidesExplPackage{ocgx2}{\g at ocgxii@date at tl}{\g at ocgxii@version at tl}
 {ports `ocgx' functionality to dvips+ps2pdf, xelatex and dvipdfmx}
@@ -1254,20 +1262,18 @@
         /Export<</ExportState/OFF>>
       }{on}
       \tl_gset:cx{ocgxii_ocg_OCView}{\ocgbase_last_ocg:}
-      \ocgbase_add_ocg_to_radiobtn_grp:nn{OCPrintViewGrp}{\ocgbase_last_ocg:}
       %in case somebody wants to reopen with \begin{ocg}...
       \tl_gset:cx{ocgxii_ocg_OCView.opts}{
-        showingui=never,printocg=never,exportocg=never,
-        radiobtngrp=OCPrintViewGrp}
+        showingui=never,printocg=never,exportocg=never
+      }
       \ocgbase_new_ocg:nnn{OCPrint}{
         /Print<</PrintState/ON>>
         /Export<</ExportState/ON>>
       }{off}
       \tl_gset:cx{ocgxii_ocg_OCPrint}{\ocgbase_last_ocg:}
-      \ocgbase_add_ocg_to_radiobtn_grp:nn{OCPrintViewGrp}{\ocgbase_last_ocg:}
       \tl_gset:cx{ocgxii_ocg_OCPrint.opts}{
-        showingui=never,printocg=always,exportocg=always,
-        radiobtngrp=OCPrintViewGrp}
+        showingui=never,printocg=always,exportocg=always
+      }
       \ocgxii_enable_ocglinks:
       \iow_now:Nx\@mainaux{
         \token_to_str:N\ocgxii at newkey{ocgx2.ocg.OCView}{
@@ -1333,6 +1339,1493 @@
     status/invisible/.style={visibility=0},
     status/true/.style={visibility=1},
     status/false/.style={visibility=0},
+    status/on/.style={visibility=1},
+    status/off/.style={visibility=0},
+    status/1/.style={visibility=1},
+    status/0/.style={visibility=0},
+    % default values
+    name=,
+    opts=, % NEW
+    status=on,
+    % ref
+    ref/.style={
+      /tikz/execute at begin scope={%
+        \begin{ocg}[\ocgxii at opts]{%
+            \ifx\empty\ocgxii at name\empty#1\else\ocgxii at name\fi%
+        }{#1}{\ocgxii at visibility}},
+      /tikz/execute at end scope={\end{ocg}},
+    }
+  },
+  ocmd/.style={
+    ocmd/.cd,
+    #1,
+    /tikz/execute at begin scope={%
+      \begin{ocmd}[\ocgxii at ocmdref]{\ocgxii at ocmdvisibility}%
+    },
+    /tikz/execute at end scope={\end{ocmd}},
+    /tikz/.cd
+  },
+  ocmd={
+    % parameters
+    ref/.store in=\ocgxii at ocmdref,
+    visibility/.store in=\ocgxii at ocmdvisibility,
+    % default values
+    ref=,
+    visibility=,
+  },
+  trigger ocg/.store in=\ocgxii at trigger,
+  trigger ocg/.value required,
+  switch ocg/.style={
+    postaction={
+      path picture={
+        \path (path picture bounding box.south west) coordinate (p1)
+          (path picture bounding box.north east) coordinate (p2)
+          (p1) node[inner sep=0pt,anchor=south west,outer sep=0pt] {%
+            \ifdefined\ocgxii at trigger%
+              \switchocg*[\ocgxii at trigger]{#1}{%
+                \tikz \useasboundingbox (p1) rectangle (p2);}%
+            \else%
+              \switchocg*{#1}{\tikz \useasboundingbox (p1) rectangle (p2);}%
+            \fi%
+          };
+      }
+    }
+  },
+  switch ocg with mark on/.style 2 args={
+    postaction={
+      path picture={%
+        \edef\ocgxii at argone{#1}%ocg ref for checkmark
+        \ocgxii at trmspc\ocgxii at argone%
+        \global\let\ocgxii at argone\ocgxii at argone%
+        %default ocg ref for checkmark, if nothing provided in #1
+        \xdef\ocgxii at argtwo{#2.mark}%
+        \xdef\ocgxii at argtwo{\ocgxii at cnvspc{\ocgxii at argtwo}}%
+        \begin{ocg}[showingui=false]{%
+          \ifx\ocgxii at argone\@empty\ocgxii at argtwo\else\ocgxii at argone\fi%
+        }{%
+          \ifx\ocgxii at argone\@empty\ocgxii at argtwo\else\ocgxii at argone\fi%
+        }{on}%
+          \draw
+          (path picture bounding box.south west)
+          --
+          (path picture bounding box.north east)
+          (path picture bounding box.south east)
+          --
+          (path picture bounding box.north west)
+          ;
+        \end{ocg}%
+      },
+      switch ocg={%
+        \ifx\ocgxii at argone\@empty\ocgxii at argtwo\else{\ocgxii at argone}\fi\space #2%
+      }
+    }
+  },
+  switch ocg with mark off/.style 2 args={
+    postaction={
+      path picture={%
+        \edef\ocgxii at argone{#1}%ocg ref for checkmark
+        \ocgxii at trmspc\ocgxii at argone%
+        \global\let\ocgxii at argone\ocgxii at argone%
+        %default ocg ref for checkmark, if nothing provided in #1
+        \xdef\ocgxii at argtwo{#2.mark}%
+        \xdef\ocgxii at argtwo{\ocgxii at cnvspc{\ocgxii at argtwo}}%
+        \begin{ocg}[showingui=false]{%
+          \ifx\ocgxii at argone\@empty\ocgxii at argtwo\else\ocgxii at argone\fi%
+        }{%
+          \ifx\ocgxii at argone\@empty\ocgxii at argtwo\else\ocgxii at argone\fi%
+        }{off}%
+          \draw
+          (path picture bounding box.south west)
+          --
+          (path picture bounding box.north east)
+          (path picture bounding box.south east)
+          --
+          (path picture bounding box.north west)
+          ;
+        \end{ocg}%
+      },
+      switch ocg={%
+        \ifx\ocgxii at argone\@empty\ocgxii at argtwo\else{\ocgxii at argone}\fi\space #2%
+      }
+    }
+  },
+  show ocg/.style={
+    postaction={
+      path picture={
+        \path (path picture bounding box.south west) coordinate (p1)
+          (path picture bounding box.north east) coordinate (p2)
+          (p1) node[inner sep=0pt,anchor=south west,outer sep=0pt] {%
+            \ifdefined\ocgxii at trigger%
+              \showocg*[\ocgxii at trigger]{#1}{%
+                \tikz \useasboundingbox (p1) rectangle (p2);}%
+            \else%
+              \showocg*{#1}{\tikz \useasboundingbox (p1) rectangle (p2);}%
+            \fi%
+          };
+      }
+    }
+  },
+  hide ocg/.style={
+    postaction={
+      path picture={
+        \path (path picture bounding box.south west) coordinate (p1)
+          (path picture bounding box.north east) coordinate (p2)
+          (p1) node[inner sep=0pt,anchor=south west,outer sep=0pt] {%
+            \ifdefined\ocgxii at trigger%
+              \hideocg*[\ocgxii at trigger]{#1}{%
+                \tikz \useasboundingbox (p1) rectangle (p2);}%
+            \else%
+              \hideocg*{#1}{\tikz \useasboundingbox (p1) rectangle (p2);}%
+            \fi%
+          };
+      }
+    }
+  },
+  actions ocg/.style n args={3}{
+    postaction={
+      path picture={
+        \path (path picture bounding box.south west) coordinate (p1)
+          (path picture bounding box.north east) coordinate (p2)
+          (p1) node[inner sep=0pt,anchor=south west,outer sep=0pt] {%
+            \ifdefined\ocgxii at trigger%
+              \actionsocg*[\ocgxii at trigger]{#1}{#2}{#3}{%
+                \tikz \useasboundingbox (p1) rectangle (p2);}%
+            \else%
+              \actionsocg*{#1}{#2}{#3}{%
+                \tikz \useasboundingbox (p1) rectangle (p2);}%
+            \fi%
+          };
+      }
+    }
+  }
+}
+\endinput
+\fi
+%%%%%%%%%%%%%%%%%%%%%% /pdfmanagement-testphase %%%%%%%%%%%%%%%%%%%
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+% ocgx2.sty
+%
+% Copyright 2015--\today, Alexander Grahn
+%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+% The intent of this package is to be a drop-in replacement for the already
+% existing CTAN package `ocgx' by Paul Gaborit, and also for `ocg-p' and `ocg'.
+%
+% It re-implements the functionality of the ocg, ocgx and ocg-p packages
+% and adds support for all known engines and backends including
+% latex+dvips+ps2pdf, xelatex, latex+dvipdfmx, lualatex.
+%
+% With ocgx2, PDF layers may extend across page breaks.
+%
+% ocgx2 implements OCMDs (optional content membership dictionaries)
+%
+% Adds some minor improvements, such as package options, remembering option.
+% settings of reopened ocgs, correct behaviour of ocg switching links that were
+% themselves placed on layers, compatibility with the animate and media9
+% packages.
+%
+% Re-implements hyperref's `ocgcolorlinks' option to produce coloured links
+% that may wrap around line breaks and page breaks.
+%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+% This work may be distributed and/or modified under the
+% conditions of the LaTeX Project Public License.
+%
+% The latest version of this license is in
+%   http://mirrors.ctan.org/macros/latex/base/lppl.txt
+%
+% This work has the LPPL maintenance status `maintained'.
+%
+% The Current Maintainer of this work is A. Grahn.
+
+\RequirePackage{l3keys2e}
+
+\def\g at ocgxii@date at tl{2021/06/03}
+\def\g at ocgxii@version at tl{0.51}
+
+\ProvidesExplPackage{ocgx2}{\g at ocgxii@date at tl}{\g at ocgxii@version at tl}
+{ports `ocgx' functionality to dvips+ps2pdf, xelatex and dvipdfmx}
+
+%creating global definitions
+\cs_new_protected:Npn\ocgxii at newkey#1#2{\tl_gset:cx{#1}{#2}}
+\cs_new_protected:Npn\ocgxii at newkeynoexp#1#2{\tl_gset:cn{#1}{#2}}
+
+\AtBeginDocument{
+  \iow_now:Nx\@mainaux{
+    \token_to_str:N\providecommand\token_to_str:N\ocgxii at newkey[2]{}
+  }
+  \iow_now:Nx\@mainaux{
+    \token_to_str:N\providecommand\token_to_str:N\ocgxii at newkeynoexp[2]{}
+  }
+  \iow_now:Nx\@mainaux{
+    \token_to_str:N\providecommand\token_to_str:N\ocgxii at ocg@stack at on@page[2]{}
+  }
+  \iow_now:Nx\@mainaux{
+    \token_to_str:N\providecommand
+      \token_to_str:N\ocgxii at lnkcol@stack at on@page[2]{}
+  }
+}
+
+\msg_set:nnn{ocgx2}{generic~msg}{#1\\#2}
+
+\msg_set:nnn{ocgx2}{missing~package}{
+  Package~`#1'~must~be~loaded~before~ocgx2.\\\\
+  Put\\\\
+  \space\space\string\usepackage#2{#1}\\
+  \space\space\string\usepackage[ocgcolorlinks]{ocgx2}\\\\
+  to~the~preamble~of~your~document.
+}
+
+\msg_set:nnn{ocgx2}{beamer~and~ocgcolorlinks}{
+  Option~`ocgcolorlinks'~cannot~be~used~with~class~Beamer.\\\\
+  Using~`colorlinks'~instead.
+}
+
+%package opts
+%unknown package option error message
+\msg_set:nnnn{ocgx2}{unknown~package~option}{Unknown~package~option~`#1'.}{
+  Package option~'#1'~is~unknown;\\
+  perhaps~it~is~spelled~incorrectly.
+}
+
+\bool_new:N\g_ocgxii_dvipdfmx_bool
+\bool_new:N\l_ocgxii_tikz_bool
+\bool_new:N\l_ocgxii_ocgcolorlinks_bool
+\bool_new:N\g_ocgxii_showingui_bool
+\bool_new:N\l_ocgxii_showingui_bool
+
+\keys_define:nn{ocgx2}{
+  xetex .code:n = {}, %dummy
+
+  dvipdfmx .code:n = {
+    \PassOptionsToPackage{dvipdfmx}{ocgbase}
+    \PassOptionsToPackage{dvipdfmx}{pdfbase}
+    \bool_gset_true:N\g_ocgxii_dvipdfmx_bool
+  },
+
+  viewocg .choice:,
+  viewocg / always .code:n={
+    \tl_gset:Nn\g_ocgxii_view_tl{/View<</ViewState/ON>>}},
+  viewocg / never .code:n={
+    \tl_gset:Nn\g_ocgxii_view_tl{/View<</ViewState/OFF>>}},
+  viewocg / ifvisible .code:n={\tl_gclear_new:N\g_ocgxii_view_tl},
+  viewocg .default:n={ifvisible},
+
+  printocg .choice:,
+  printocg / always .code:n={
+    \tl_gset:Nn\g_ocgxii_print_tl{/Print<</PrintState/ON>>}},
+  printocg / never .code:n={
+    \tl_gset:Nn\g_ocgxii_print_tl{/Print<</PrintState/OFF>>}},
+  printocg / ifvisible .code:n={\tl_gclear_new:N\g_ocgxii_print_tl},
+  printocg .default:n={ifvisible},
+
+  exportocg .choice:,
+  exportocg / always .code:n={
+    \tl_gset:Nn\g_ocgxii_export_tl{/Export<</ExportState/ON>>}},
+  exportocg / never .code:n={
+    \tl_gset:Nn\g_ocgxii_export_tl{/Export<</ExportState/OFF>>}},
+  exportocg / ifvisible .code:n={\tl_gclear_new:N\g_ocgxii_export_tl},
+  exportocg .default:n={ifvisible},
+
+  showingui .choices:nn = {true,false,always,never,iffirstuse}{
+    \bool_if:nTF{
+      \str_if_eq_p:ee{#1}{false} ||
+      \str_if_eq_p:ee{#1}{never}
+    }{
+      \bool_gset_false:N\g_ocgxii_showingui_bool
+    }{
+      \bool_gset_true:N\g_ocgxii_showingui_bool
+    }
+  },
+  showingui .default:n={true},
+
+  listintoolbar .meta:n = {showingui=#1},
+  listintoolbar .default:n={true},
+
+  tikz .bool_set:N = \l_ocgxii_tikz_bool,
+  tikz .default:n = true,
+
+  ocgcolorlinks .bool_set:N = \l_ocgxii_ocgcolorlinks_bool,
+  ocgcolorlinks .default:n = true,
+
+  unknown .code:n = {
+    \msg_error:nnx{ocgx2}{unknown~package~option}{\l_keys_key_tl}
+  }
+}
+
+%package options preset
+\keys_set:nn{ocgx2}{viewocg,printocg,exportocg,showingui,tikz=false}
+
+%process package options
+\ProcessKeysOptions{ocgx2}
+\sys_if_engine_xetex:T{\bool_gset_true:N\g_ocgxii_dvipdfmx_bool}
+
+\RequirePackage{ocgbase} %also loads pdfbase.sty
+
+%re-implement ocg-p's `ocg' environment
+\DeclareDocumentEnvironment{ocg}{O{}mmm}{
+  \ocgxii_begin_ocg:nnnn{#1}{#2}{#3}{#4}
+}{
+  \ocgxii_end_ocg:
+}
+
+\cs_new_protected_nopar:Nn\ocgxii_begin_ocg:nnnn{
+  \group_begin:
+    \ocgxii_reset_cmd_opts:  % ... to the user-set package options
+    \tl_set:Nx\l_ocgxii_argiv_tl{\tl_trim_spaces:n{#4}}
+    \tl_if_exist:cTF{ocgxii_ocg_#3}{ %re-open existing layer
+      \tl_set:Nx\l_tempa_tl{\tl_use:c{ocgxii_ocg_#3.opts},#1}
+      \tl_gset:cx{ocgxii_ocg_#3.opts}{\l_tempa_tl} %new options appended
+      \keys_set:nV{ocgx2/ocgenv}\l_tempa_tl
+      \bool_if:nTF{ %initial visibility
+        \str_if_eq_p:ee{\l_ocgxii_argiv_tl}{1} ||
+        \str_if_eq_p:ee{\l_ocgxii_argiv_tl}{on} ||
+        \str_if_eq_p:ee{\l_ocgxii_argiv_tl}{true}
+      }{
+        \ocgbase_del_from_off_list:n{\tl_use:c{ocgxii_ocg_#3}}
+      }{
+        \ocgbase_add_to_off_list:n{\tl_use:c{ocgxii_ocg_#3}}
+      }
+    }{
+      \tl_set:Nx\l_tempa_tl{#1}
+      \tl_gset:cx{ocgxii_ocg_#3.opts}{\l_tempa_tl}
+      \keys_set:nV{ocgx2/ocgenv}\l_tempa_tl
+      \ocgbase_new_ocg:nnn{#2}{
+        \l_ocgxii_view_tl\l_ocgxii_print_tl\l_ocgxii_export_tl
+      }{\l_ocgxii_argiv_tl}
+      \tl_gset:cx{ocgxii_ocg_#3}{\ocgbase_last_ocg:}
+      \tl_gset:cx{ocgx2.ocg.\ocgbase_last_ocg:}{\ocgbase_last_ocg:}
+      \tl_gset:cx{ocgx2.ocg.#3}{\ocgbase_last_ocg:}
+      \iow_now:Nx\@mainaux{
+        \token_to_str:N\ocgxii at newkey{ocgx2.ocg.#3}{\ocgbase_last_ocg:}
+      }
+    }
+    \bool_if:nT{
+      !\cs_if_exist:cTF{ocgx2.ocg.#3}{
+        \str_if_eq_p:ee{\tl_use:c{ocgx2.ocg.#3}}{\tl_use:c{ocgxii_ocg_#3}}
+      }{
+        \c_false_bool
+      }
+    }{
+      \tl_if_exist:NF\g_ocgxii_rerunwarned_tl{
+        \tl_new:N\g_ocgxii_rerunwarned_tl
+        \AtEndDocument{\msg_warning:nn{ocgx2}{rerun}}
+      }
+    }
+    \seq_map_inline:Nn\l_ocgxii_rbgrps_seq{% process list of radio btn groups
+      \ocgbase_add_ocg_to_radiobtn_grp:nn{##1}{\tl_use:c{ocgxii_ocg_#3}}
+    }
+    \ocgbase_open_stack_push:n{\tl_use:c{ocgxii_ocg_#3}}
+    \ocgxii_make_oc_entry:
+    \ocgxii_stack_shipout:NN\ocgxii at ocg@stack at on@page\g_ocgbase_open_stack_seq
+    % insert OCG into Order tree
+    \bool_if:NT\l_ocgxii_showingui_bool{
+      \ocgbase_tree_node_begin:n{\tl_use:c{ocgxii_ocg_#3}}
+    }
+  \group_end:
+  \ocgbase_oc_bdc:n{\tl_use:c{ocgxii_ocg_#3}}
+  \ignorespaces
+}
+
+\cs_new_protected_nopar:Nn\ocgxii_end_ocg:{
+  \unskip
+  \ocgbase_oc_emc:
+  \ocgbase_tree_node_end:
+  \ocgbase_open_stack_pop:N\l_trash_tl
+  \ocgxii_make_oc_entry:
+  \ocgxii_stack_shipout:NN\ocgxii at ocg@stack at on@page\g_ocgbase_open_stack_seq
+}
+
+% OCMD implementation
+\DeclareDocumentEnvironment{ocmd}{O{}m}{
+  \ocgxii_begin_ocmd:on{#1}{#2}
+  \ignorespaces
+}{
+  \unskip
+  \ocgxii_end_ocmd:
+}
+
+\cs_new_protected_nopar:Nn\ocgxii_begin_ocmd:nn{ % #1: id,
+  \bool_if:nTF{                                  % #2: visib. expr. or policy
+    \tl_if_blank:oTF{#1}{
+      \c_false_bool
+    }{
+      \tl_if_exist_p:c{ocgxii_ocmd_#1}
+    }
+  }{
+    % re-open existing ocmd
+    \tl_set_eq:Nc\l_ocgxii_cur_ocmd_tl{ocgxii_ocmd_#1}
+  }{
+    % new ocmd
+    \group_begin:
+      \ocgxii_ocmd_read_visbility:nN{#2}\l_ocgxii_ocmd_visibility_tl
+      \pdf_object_new:xn{g_object_\int_use:N\g_ocgbase_int _pdf}{dict}
+      \pdf_object_write:xx{g_object_\int_use:N\g_ocgbase_int _pdf}{
+        /Type/OCMD\l_ocgxii_ocmd_visibility_tl
+      }
+      \tl_gset:cx{g_pbs_objname_\pdf_object_ref_last: _tl}{
+        g_object_\int_use:N\g_ocgbase_int _pdf
+      }
+      \int_gincr:N\g_ocgbase_int
+      %if only visb. policy is given, generate equivalent visib. expression,
+      %needed for stack of open layers and \ocgxii_make_oc_entry: command
+      \ocgxii_ocmd_make_equiv_ve:nN{#2}\l_ocgxii_ocmd_equiv_ve_tl
+      \tl_gset:co{ocgx2.ocmd.\pdf_object_ref_last:}{\l_ocgxii_ocmd_equiv_ve_tl}
+    \group_end:
+    \tl_set:Nx\l_ocgxii_cur_ocmd_tl{\pdf_object_ref_last:}
+    \tl_if_blank:oF{#1}{
+      \tl_gset:cx{ocgxii_ocmd_#1}{\pdf_object_ref_last:}
+      \iow_now:Nn\@mainaux{\ocgxii at newkeynoexp{ocgx2.ocmd.#1}{#2}}
+    }
+  }
+  \ocgbase_open_stack_push:n{\l_ocgxii_cur_ocmd_tl}
+  \ocgxii_make_oc_entry:
+  \ocgxii_stack_shipout:NN\ocgxii at ocg@stack at on@page\g_ocgbase_open_stack_seq
+  \ocgbase_oc_bdc:n{\l_ocgxii_cur_ocmd_tl}
+}
+\cs_generate_variant:Nn\ocgxii_begin_ocmd:nn{on}
+\cs_new_protected_nopar:Nn\ocgxii_end_ocmd:{
+  \ocgbase_oc_emc:
+  \ocgbase_open_stack_pop:N\l_trash_tl
+  \ocgxii_make_oc_entry: %update
+  \ocgxii_stack_shipout:NN\ocgxii at ocg@stack at on@page\g_ocgbase_open_stack_seq
+}
+
+%visibility expressions
+\cs_new_protected_nopar:Nn\ocgxii_ocmd_read_visbility:nN{
+  \int_zero:N\l_ocgxii_ve_cnt_int
+  \int_zero:N\l_ocgxii_vp_cnt_int
+  \tl_clear_new:N#2
+  \clist_map_inline:nn{#1}{\ocgxii_omcd_parse_argument:nN{##1}#2}
+}
+\cs_new_protected_nopar:Nn\ocgxii_omcd_parse_argument:nN{
+  \cs_set_eq:NN\AllOn \ocgxii_vp_check:n
+  \cs_set_eq:NN\AnyOn \ocgxii_vp_check:n
+  \cs_set_eq:NN\AnyOff\ocgxii_vp_check:n
+  \cs_set_eq:NN\AllOff\ocgxii_vp_check:n
+  \cs_set_eq:NN\Not\ocgxii_ve_check:n
+  \cs_set_eq:NN\And\ocgxii_ve_check:n
+  \cs_set_eq:NN\Or \ocgxii_ve_check:n
+  \tl_if_exist:cTF{ocgx2.ocg.#1}{
+    \msg_error:nnxx{ocgx2}{generic~msg}{
+      OCG~ids~cannot~be~directly~used~in~the~visibility~argument~of~an~
+      `ocmd'~environment.
+    }{\g_ocgxii_help_msg_tl}
+  }{
+    \tl_if_exist:cTF{ocgx2.ocmd.#1}{
+      \msg_error:nnxx{ocgx2}{generic~msg}{
+        OCMD~ids~cannot~be~directly~used~in~the~visibility~argument~of~an~
+        `ocmd'~environment.
+      }{\g_ocgxii_help_msg_tl}
+    }{
+      \tl_if_exist:cTF{ocgxii_#1}{
+        \str_case_e:nn{\tl_use:c{ocgxii_#1}}{
+          {VisExpr}{
+            \int_incr:N\l_ocgxii_ve_cnt_int
+            \int_compare:nNnTF{\l_ocgxii_ve_cnt_int}>{1}{
+              \msg_error:nnnn{ocgx2}{generic~msg}{
+                More~than~one~visibility~expression~passed~to~the~`ocmd'~
+                environment.
+              }{
+                At~most~one~visibility~expression~is~allowed.~A~visibility~
+                expression~is~a~boolean~expression~built~by~nesting~any~number~of~
+                \And{...},~\Or{...},~\Not{...}~commands.
+              }
+            }{
+              \tl_put_right:Nx#2{/VE~}
+              \ocgxii_ocmd_expression_parser:nN{#1}#2
+            }
+          }
+          {VisPol}{
+            \int_incr:N\l_ocgxii_vp_cnt_int
+            \int_compare:nNnTF{\l_ocgxii_vp_cnt_int}>{1}{
+              \msg_error:nnnn{ocgx2}{generic~msg}{
+                More~than~one~visibility~policy~passed~to~the~`ocmd'~environment.
+              }{
+                At~most~one~visibility~policy~out~of~\AllOn{...},~\AnyOn{...},~
+                \AnyOff{...},~\AllOff{...}~is~allowed.~Any~number~of~OCG~IDs,~
+                separated~by~commas,~may~be~passed~as~arguments~to~these~
+                commands,~but~commands~may~not~be~nested.~For~complex~visibilty~
+                relations,~consider~using~a~visibility~expression.
+              }
+            }{
+              \ocgxii_ocmd_expression_parser:nN{#1}#2
+            }
+          }
+        }
+      }{
+        \msg_error:nnxx{ocgx2}{generic~msg}{
+          The~visibility~argument~of~the~`ocmd'~environment~cannot~be~parsed.
+        }{\g_ocgxii_help_msg_tl}
+      }
+    }
+  }
+}
+\cs_generate_variant:Nn\ocgxii_omcd_parse_argument:nN{xN}
+\cs_generate_variant:Nn\ocgxii_omcd_parse_argument:nN{oN}
+\cs_new_protected_nopar:Nn\ocgxii_ocmd_expression_parser:nN{
+  \cs_set_eq:NN\AllOn \ocgxii_vp_check:n
+  \cs_set_eq:NN\AnyOn \ocgxii_vp_check:n
+  \cs_set_eq:NN\AnyOff\ocgxii_vp_check:n
+  \cs_set_eq:NN\AllOff\ocgxii_vp_check:n
+  \cs_set_eq:NN\Not\ocgxii_ve_check:n
+  \cs_set_eq:NN\And\ocgxii_ve_check:n
+  \cs_set_eq:NN\Or \ocgxii_ve_check:n
+  \tl_if_exist:cTF{ocgx2.ocg.#1}{% ocg reference
+    \tl_put_right:Nx#2{~\tl_use:c{ocgx2.ocg.#1}}
+  }{
+    \tl_if_exist:cTF{ocgx2.ocmd.#1}{% ocmd reference
+      \ocgxii_ocmd_expression_parser:vN{ocgx2.ocmd.#1}#2
+    }{
+      \tl_if_exist:cTF{ocgxii_#1}{% visib. bool expression or policy directive
+        \bool_if:nTF{
+          \str_if_eq_p:ee{\tl_use:c{ocgxii_#1}}{VisExpr} &&
+          \bool_if_p:N\l_ocgxii_vp_open_bool ||
+          \str_if_eq_p:ee{\tl_use:c{ocgxii_#1}}{VisPol} &&
+          \bool_if_p:N\l_ocgxii_ve_open_bool
+        }{
+          \msg_error:nnxx{ocgx2}{generic~msg}{
+            Visibility~policy~and~expression~commands~cannot~be~mixed.
+          }{\g_ocgxii_help_msg_tl}
+        }{
+          \bool_if:nT{
+            \str_if_eq_p:ee{\tl_use:c{ocgxii_#1}}{VisPol} &&
+            \bool_if_p:N\l_ocgxii_vp_open_bool
+          }{
+            \msg_error:nnxx{ocgx2}{generic~msg}{
+              Visibility~policy~commands~cannot~be~nested.~For~more~complex~
+              visibilty~relations,~consider~using~a~visibility~expression.
+            }{\g_ocgxii_help_msg_tl}
+          }
+        }
+        \cs_set_eq:NN\AllOn \ocgxii_vp_allon:nN
+        \cs_set_eq:NN\AnyOn \ocgxii_vp_anyon:nN
+        \cs_set_eq:NN\AnyOff\ocgxii_vp_anyoff:nN
+        \cs_set_eq:NN\AllOff\ocgxii_vp_alloff:nN
+        \cs_set_eq:NN\Not\ocgxii_ve_not:nN
+        \cs_set_eq:NN\And\ocgxii_ve_and:nN
+        \cs_set_eq:NN\Or \ocgxii_ve_or:nN
+        #1#2
+      }{
+        \msg_warning:nnx{ocgx2}{undefined~OCG}{#1}
+        \tl_if_exist:NF\g_ocgxii_refundefwarned_tl{
+          \tl_new:N\g_ocgxii_refundefwarned_tl
+          \AtEndDocument{\msg_warning:nn{ocgx2}{undefined~OCGs}}
+        }
+      }
+    }
+  }
+}
+\cs_generate_variant:Nn\ocgxii_ocmd_expression_parser:nN{vN}
+% visib. policy directives
+\cs_new_protected_nopar:Nn\ocgxii_vp_allon:nN{
+  \bool_set_true:N\l_ocgxii_vp_open_bool
+  \tl_put_right:Nx#2{/P/AllOn/OCGs~\g_ocgxii_left_bracket_tl}
+  \clist_map_inline:nn{#1}{\ocgxii_ocmd_expression_parser:nN{##1}#2}
+  \tl_put_right:Nx#2{\g_ocgxii_right_bracket_tl}
+  \bool_set_false:N\l_ocgxii_vp_open_bool
+}
+\cs_new_protected_nopar:Nn\ocgxii_vp_anyon:nN{
+  \bool_set_true:N\l_ocgxii_vp_open_bool
+  \tl_gput_right:Nx#2{/P/AnyOn/OCGs~\g_ocgxii_left_bracket_tl}
+  \clist_map_inline:nn{#1}{\ocgxii_ocmd_expression_parser:nN{##1}#2}
+  \tl_gput_right:Nx#2{\g_ocgxii_right_bracket_tl}
+  \bool_set_false:N\l_ocgxii_vp_open_bool
+}
+\cs_new_protected_nopar:Nn\ocgxii_vp_anyoff:nN{
+  \bool_set_true:N\l_ocgxii_vp_open_bool
+  \tl_gput_right:Nx#2{/P/AnyOff/OCGs~\g_ocgxii_left_bracket_tl}
+  \clist_map_inline:nn{#1}{\ocgxii_ocmd_expression_parser:nN{##1}#2}
+  \tl_gput_right:Nx#2{\g_ocgxii_right_bracket_tl}
+  \bool_set_false:N\l_ocgxii_vp_open_bool
+}
+\cs_new_protected_nopar:Nn\ocgxii_vp_alloff:nN{
+  \bool_set_true:N\l_ocgxii_vp_open_bool
+  \tl_gput_right:Nx#2{/P/AllOff/OCGs~\g_ocgxii_left_bracket_tl}
+  \clist_map_inline:nn{#1}{\ocgxii_ocmd_expression_parser:nN{##1}#2}
+  \tl_gput_right:Nx#2{\g_ocgxii_right_bracket_tl}
+  \bool_set_false:N\l_ocgxii_vp_open_bool
+}
+% policy to expression conversion
+\cs_new_protected_nopar:Nn\ocgxii_ocmd_make_equiv_ve:nN{
+  \int_zero:N\l_ocgxii_ve_cnt_int
+  \tl_clear_new:N#2
+  \clist_map_inline:nn{#1}{\ocgxii_omcd_convert_vp:nN{##1}#2}
+}
+\cs_new_protected_nopar:Nn\ocgxii_omcd_convert_vp:nN{
+  \cs_set_eq:NN\AllOn \ocgxii_vp_check:n
+  \cs_set_eq:NN\AnyOn \ocgxii_vp_check:n
+  \cs_set_eq:NN\AnyOff\ocgxii_vp_check:n
+  \cs_set_eq:NN\AllOff\ocgxii_vp_check:n
+  \cs_set_eq:NN\Not\ocgxii_ve_check:n
+  \cs_set_eq:NN\And\ocgxii_ve_check:n
+  \cs_set_eq:NN\Or \ocgxii_ve_check:n
+  \tl_if_exist:cT{ocgxii_#1}{
+    \str_case_e:nn{\tl_use:c{ocgxii_#1}}{
+      {VisExpr}{
+        \int_incr:N\l_ocgxii_ve_cnt_int
+        \tl_set:Nn#2{#1}
+      }
+      {VisPol}{
+        \int_compare:nNnT{\l_ocgxii_ve_cnt_int}={0}{
+          \cs_set_eq:NN\AllOn \ocgxii_allon_to_ve:n
+          \cs_set_eq:NN\AnyOn \ocgxii_anyon_to_ve:n
+          \cs_set_eq:NN\AnyOff\ocgxii_anyoff_to_ve:n
+          \cs_set_eq:NN\AllOff\ocgxii_alloff_to_ve:n
+          \tl_set:No#2{#1}
+        }
+      }
+    }
+  }
+}
+\cs_new_protected_nopar:Nn\ocgxii_allon_to_ve:n{\And{#1}}
+\cs_new_protected_nopar:Nn\ocgxii_anyon_to_ve:n{\Or{#1}}
+\cs_new_protected_nopar:Nn\ocgxii_anyoff_to_ve:n{\Not{\And{#1}}}
+\cs_new_protected_nopar:Nn\ocgxii_alloff_to_ve:n{\Not{\Or{#1}}}
+% visib. boolean expressions
+\cs_new_protected_nopar:Nn\ocgxii_ve_and:nN{
+  \bool_set_true:N\l_ocgxii_ve_open_bool
+  \tl_put_right:Nx#2{\g_ocgxii_left_bracket_tl/And}
+  \clist_map_inline:nn{#1}{\ocgxii_ocmd_expression_parser:nN{##1}#2}
+  \tl_put_right:Nx#2{\g_ocgxii_right_bracket_tl}
+  \bool_set_false:N\l_ocgxii_ve_open_bool
+}
+\cs_new_protected_nopar:Nn\ocgxii_ve_or:nN{
+  \bool_set_true:N\l_ocgxii_ve_open_bool
+  \tl_put_right:Nx#2{\g_ocgxii_left_bracket_tl/Or}
+  \clist_map_inline:nn{#1}{\ocgxii_ocmd_expression_parser:nN{##1}#2}
+  \tl_put_right:Nx#2{\g_ocgxii_right_bracket_tl}
+  \bool_set_false:N\l_ocgxii_ve_open_bool
+}
+\cs_new_protected_nopar:Nn\ocgxii_ve_not:nN{
+  \bool_set_true:N\l_ocgxii_ve_open_bool
+  % only one item allowed in \Not{...} argument
+  \int_compare:nNnT{\clist_count:n{#1}}>{\c_one_int}{
+    \msg_error:nnnn{ocgx2}{generic~msg}{
+      More~than~one~item~passed~to~\Not{...}.
+    }{
+      Only~one~item~is~allowed.
+    }
+  }
+  \int_compare:nNnT{\clist_count:n{#1}}={\c_one_int}{
+    \tl_put_right:Nx#2{\g_ocgxii_left_bracket_tl/Not}
+    \clist_map_inline:nn{#1}{\ocgxii_ocmd_expression_parser:nN{##1}#2}
+    \tl_put_right:Nx#2{\g_ocgxii_right_bracket_tl}
+  }
+  \bool_set_false:N\l_ocgxii_ve_open_bool
+}
+\cs_new_protected_nopar:Nn\ocgxii_ve_check:n{VisExpr}
+\tl_set:cn{ocgxii_VisExpr}{VisExpr}
+\cs_new_protected_nopar:Nn\ocgxii_vp_check:n{VisPol}
+\tl_set:cn{ocgxii_VisPol}{VisPol}
+\tl_set:Nx\g_ocgxii_left_bracket_tl{\tl_to_str:N[}
+\tl_set:Nx\g_ocgxii_right_bracket_tl{\tl_to_str:N]}
+\int_new:N\l_ocgxii_vp_cnt_int %number of visib. policies
+\int_new:N\l_ocgxii_ve_cnt_int %number of visib. expressions
+\bool_new:N\l_ocgxii_vp_open_bool %for nesting test
+\bool_new:N\l_ocgxii_ve_open_bool %for nesting test
+\tl_set:Nn\g_ocgxii_help_msg_tl{
+  At~most~one~visibility~policy~and,~separated~by~a~comma,~at~most~one~
+  visibility~expression~may~be~passed~as~the~2nd~argument~to~the~`ocmd'~
+  environment.~A~visibility~
+  policy~is~defined~by~one~of~\AllOn{...},~\AnyOn{...},~\AnyOff{...},~
+  \AllOff{...}.~A~visibility~expression~is~a~boolean~expression~built~by~
+  nesting~any~number~of~\And{...},~\Or{...},~\Not{...}~commands.~If~both~are~
+  provided,~the~visibility~expression~takes~precedence~over~the~policy,~but~the~
+  latter~may~be~used~as~fallback~by~non-conforming~PDF~viewers.
+}
+%command that builds /OC entry from open layer stack
+\cs_new_nopar:Nn\ocgxii_make_oc_entry:{
+  \group_begin:
+  \tl_gclear:N\g_ocgxii_oc_entry_tl
+  \tl_clear:N\l_tempa_tl
+  \seq_if_empty:NF\g_ocgbase_open_stack_seq{
+    \seq_clear:N\l_tempa_seq
+    %additional level of braces around indirect PDF objects (needed for dvips)
+    \seq_map_inline:Nn\g_ocgbase_open_stack_seq{
+      \seq_put_right:Nn\l_tempa_seq{{##1}}
+    }
+    \ocgxii_omcd_parse_argument:xN{
+      \exp_not:N\And{\seq_use:Nn\l_tempa_seq{,}}
+    }\l_tempa_tl
+    \tl_gset:Nx\g_ocgxii_oc_entry_tl{/OC~<</Type/OCMD\l_tempa_tl>>}
+  }
+  \group_end:
+}
+%programmer/author command that inserts /OC << >> entry; for use in
+%annotation/xobject dicts, in order to make them layer-aware
+\cs_new_nopar:Nn\ocgxii_insert_oc:{\g_ocgxii_oc_entry_tl}
+\cs_gset_eq:NN\ocgbase_insert_oc:\ocgxii_insert_oc:
+\cs_gset_eq:NN\ocgbase at insert@oc\ocgxii_insert_oc:
+\tl_new:N\g_ocgxii_oc_entry_tl
+
+\cs_new_protected_nopar:Nn\ocgxii_stack_shipout:NN{
+  \iow_shipout_x:Nx\@mainaux{
+    \token_to_str:N#1{
+      \exp_not:N\int_use:N\g_ocgxii_page_int
+    }{\seq_use:Nn#2{,}}
+  }
+}
+
+\cs_new_protected_nopar:Npn\ocgxii at ocg@stack at on@page#1#2{
+  \seq_gset_from_clist:cn{g_pending_ocgs_on_#1_seq}{#2}
+  %re-add braces around items for dvips
+  \bool_if:nT{\sys_if_output_dvi_p: && !\g_ocgxii_dvipdfmx_bool}{
+    \seq_map_inline:cn{g_pending_ocgs_on_#1_seq}{
+      \seq_gpop_left:cN{g_pending_ocgs_on_#1_seq}\l_trash_tl
+      \seq_gput_right:cn{g_pending_ocgs_on_#1_seq}{{##1}}
+    }
+  }
+}
+\ocgxii at ocg@stack at on@page{0}{} %initialize
+
+\cs_new_protected_nopar:Npn\ocgxii at lnkcol@stack at on@page#1#2{
+  \seq_gset_from_clist:cn{g_pending_lnkcols_on_#1_seq}{#2}
+}
+\ocgxii at lnkcol@stack at on@page{0}{} %initialize
+
+%end-of-page action
+\pbs_eop_action:n{
+  \seq_if_exist:cT{g_pending_lnkcols_on_\int_use:c{g_ocgxii_page_int}_seq}{
+    %check whether end-of-page link colour stack has settled
+    \iow_shipout:Nx\@mainaux{
+      \token_to_str:N\ocgxii at newkey{ocgx2.oldlnkcol.\int_use:N\g_ocgxii_page_int}{
+        \seq_use:cn{g_pending_lnkcols_on_\int_use:c{g_ocgxii_page_int}_seq}{,}
+      }
+    }
+    \bool_if:nT{
+      !\cs_if_exist:cTF{ocgx2.oldlnkcol.\int_use:N\g_ocgxii_page_int}{
+        \str_if_eq_p:ee{
+          \tl_use:c{ocgx2.oldlnkcol.\int_use:N\g_ocgxii_page_int}
+        }{
+          \seq_use:cn{g_pending_lnkcols_on_\int_use:c{g_ocgxii_page_int}_seq}{,}
+        }
+      }{
+        \c_false_bool
+      }
+    }{
+      \tl_if_exist:NF\g_ocgxii_rerunwarned_tl{
+        \tl_new:N\g_ocgxii_rerunwarned_tl
+        \AtEndDocument{\msg_warning:nn{ocgx2}{rerun}}
+      }
+    }
+    % now close the colourlink opened last
+    \seq_get:cNT{g_pending_lnkcols_on_\int_use:c{g_ocgxii_page_int}_seq}\l_tmpa_tl{
+      \tl_gset_eq:NN\g_ocgxii_lnkcol_tl\l_tmpa_tl
+      \ocgxii_colourlink_end:
+    }
+  }
+  %check whether end-of-page ocg stack has settled
+  \iow_shipout:Nx\@mainaux{
+    \token_to_str:N\ocgxii at newkey{ocgx2.oldstack.\int_use:N\g_ocgxii_page_int}{
+      \seq_use:cn{g_pending_ocgs_on_\int_use:c{g_ocgxii_page_int}_seq}{,}
+    }
+  }
+  \bool_if:nT{
+    !\cs_if_exist:cTF{ocgx2.oldstack.\int_use:N\g_ocgxii_page_int}{
+      \str_if_eq_p:ee{
+        \tl_use:c{ocgx2.oldstack.\int_use:N\g_ocgxii_page_int}
+      }{
+        \seq_use:cn{g_pending_ocgs_on_\int_use:c{g_ocgxii_page_int}_seq}{,}
+      }
+    }{
+      \c_false_bool
+    }
+  }{
+    \tl_if_exist:NF\g_ocgxii_rerunwarned_tl{
+      \tl_new:N\g_ocgxii_rerunwarned_tl
+      \AtEndDocument{\msg_warning:nn{ocgx2}{rerun}}
+    }
+  }
+  %now close pending ocgs
+  \seq_map_variable:cNn{
+    g_pending_ocgs_on_\int_use:c{g_ocgxii_page_int}_seq
+  }\l_tmpb_tl{\ocgbase_oc_emc:}
+}
+
+%begin-of-page action
+\pbs_bop_action:n{
+  % re-open all pending ocgs in original order
+  \seq_set_eq:Nc\l_ocgxii_pending_ocgs_seq{
+    g_pending_ocgs_on_\int_use:c{g_ocgxii_page_int}_seq
+  }
+  \seq_reverse:N\l_ocgxii_pending_ocgs_seq
+  \seq_map_variable:NNn\l_ocgxii_pending_ocgs_seq\l_tmpa_tl{
+    \ocgbase_oc_bdc:n{\l_tmpa_tl}
+  }
+  % re-open the colourlink opened last
+  \seq_get:cNT{g_pending_lnkcols_on_\int_use:c{g_ocgxii_page_int}_seq}\l_tmpa_tl{
+    \tl_gset_eq:NN\g_ocgxii_lnkcol_tl\l_tmpa_tl
+    \ocgxii_colourlink_begin:
+  }
+  \int_gincr:N\g_ocgxii_page_int
+  % copy pending ocg stack from previous page, if it has not been initialized
+  % yet from aux file
+  \seq_if_exist:cF{g_pending_ocgs_on_\int_use:c{g_ocgxii_page_int}_seq}{
+    \seq_gset_eq:cc{
+      g_pending_ocgs_on_\int_use:c{g_ocgxii_page_int}_seq
+    }{
+      g_pending_ocgs_on_\int_eval:n{\g_ocgxii_page_int-\c_one_int}_seq
+    }
+  }
+  %the same for link colour stack
+  \seq_if_exist:cF{g_pending_lnkcols_on_\int_use:c{g_ocgxii_page_int}_seq}{
+    \seq_gset_eq:cc{
+      g_pending_lnkcols_on_\int_use:c{g_ocgxii_page_int}_seq
+    }{
+      g_pending_lnkcols_on_\int_eval:n{\g_ocgxii_page_int-\c_one_int}_seq
+    }
+  }
+}
+\int_new:N\g_ocgxii_page_int %abs. page counter
+
+\cs_new_protected_nopar:Nn\ocgxii_ocglist_reset:{
+  \tl_clear_new:N\l_ocgxii_u_list_tl
+  \tl_clear_new:N\l_ocgxii_d_list_tl
+  \tl_clear_new:N\l_ocgxii_e_list_tl
+  \tl_clear_new:N\l_ocgxii_x_list_tl
+}
+
+\cs_new_protected_nopar:Nn\ocgxii_ocglist_build:Nn{
+  \tl_set:Nx\l_ocglistarg_tl{#2}\tl_trim_spaces:N\l_ocglistarg_tl
+  % first try splitting at commas (ocgx2 syntax)
+  \tl_set_eq:NN\l_tmpa_tl\l_ocglistarg_tl
+  \tl_remove_all:Nn\l_tmpa_tl{~}
+  \seq_set_split:NnV\l_ocgxii_ocglistarg_seq{,}\l_tmpa_tl
+  \seq_remove_all:Nn\l_ocgxii_ocglistarg_seq{}
+  \tl_set:Nx\l_tmpa_tl{\seq_count:N\l_ocgxii_ocglistarg_seq}
+  % now at spaces (legacy ocgx/ocg-p)
+  \tl_set_eq:NN\l_tmpb_tl\l_ocglistarg_tl
+  \tl_remove_all:Nn\l_tmpb_tl{,}
+  \seq_set_split:NnV\l_tmpb_seq{~}\l_tmpb_tl
+  \seq_remove_all:Nn\l_tmpb_seq{}
+  \tl_set:Nx\l_tmpb_tl{\seq_count:N\l_tmpb_seq}
+  %take the seq having more elements (guessing the separator most likely used)
+  \int_compare:nT{\l_tmpb_tl>\l_tmpa_tl}{
+    \seq_set_eq:NN\l_ocgxii_ocglistarg_seq\l_tmpb_seq
+  }
+  \seq_map_variable:NNn\l_ocgxii_ocglistarg_seq\l_tempa_tl{
+    \ocgxii_process_ocgref:NN#1\l_tempa_tl
+  }
+}
+
+\cs_new_protected:Nn\ocgxii_commalist_process:n{
+  \seq_set_split:Nnn\l_tmpa_seq{,}{#1}
+  \ocgxii_ocglist_build:Nn\l_ocgxii_e_list_tl{\seq_item:Nn\l_tmpa_seq{1}}
+  \ocgxii_ocglist_build:Nn\l_ocgxii_x_list_tl{\seq_item:Nn\l_tmpa_seq{2}}
+  \ocgxii_ocglist_build:Nn\l_ocgxii_d_list_tl{\seq_item:Nn\l_tmpa_seq{3}}
+  \ocgxii_ocglist_build:Nn\l_ocgxii_u_list_tl{\seq_item:Nn\l_tmpa_seq{4}}
+}
+
+\cs_new_protected_nopar:Nn\ocgxii_ocglist_process_idlist:nn{
+  \ocgxii_ocglist_reset:
+  \tl_set:Nx\l_ocgxii_opt_tl{#1}\tl_remove_all:Nn\l_ocgxii_opt_tl{~}
+  \str_case_e:nnF{\l_ocgxii_opt_tl}{
+    {onmouseup}{
+      \ocgxii_ocglist_build:Nn\l_ocgxii_u_list_tl{#2}
+    }
+    {onmousedown}{
+      \ocgxii_ocglist_build:Nn\l_ocgxii_d_list_tl{#2}
+    }
+    {onmouseenter}{
+      \ocgxii_ocglist_build:Nn\l_ocgxii_e_list_tl{#2}
+    }
+    {onmouseexit}{
+      \ocgxii_ocglist_build:Nn\l_ocgxii_x_list_tl{#2}
+    }
+    {onmouseall}{
+      \ocgxii_commalist_process:n{#2}
+    }
+  }{
+    \msg_error:nnx{ocgx2}{unknown~option}{\l_ocgxii_opt_tl}
+  }
+}
+
+\int_new:N\g_ocgxii_widcount_int% widget counter
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% re-implement commands from ocgx.sty (all engines including ps2pdf [gs>=9.15])
+% adding optional `*' (arg 1) -> non-breakable link instead of plain (multiline)
+% Link;
+% adding optional 2nd argument -> Button Widget (non-breakable) with one of
+% various mouse triggers (`troggerocgs` option from ocg-p)
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+\DeclareDocumentCommand\switchocg{s O{} m +m}{
+  \ocgxii_actionsocg:nnnnnn{#1}{#2}{#3}{}{}{#4}
+}
+
+\DeclareDocumentCommand\showocg{s O{} m +m}{
+  \ocgxii_actionsocg:nnnnnn{#1}{#2}{}{#3}{}{#4}
+}
+
+\DeclareDocumentCommand\hideocg{s O{} m +m}{
+  \ocgxii_actionsocg:nnnnnn{#1}{#2}{}{}{#3}{#4}
+}
+
+\DeclareDocumentCommand\actionsocg{s O{} m m m +m}{
+  \ocgxii_actionsocg:nnnnnn{#1}{#2}{#3}{#4}{#5}{#6}
+}
+
+\bool_new:N\l_ocgxii_mouse_triggers_bool
+\bool_new:N\l_ocgxii_nobreak_bool
+\cs_new_protected:Nn\ocgxii_actionsocg:nnnnnn{
+  \group_begin:
+  \mode_leave_vertical:
+  \bool_set_false:N\l_ocgxii_mouse_triggers_bool
+  \bool_set_false:N\l_ocgxii_nobreak_bool
+  % explicitly non-breakable?
+  \bool_if:nT{#1}{\bool_set_true:N\l_ocgxii_nobreak_bool}
+  %
+  %clear actions for various mouse triggers (e,d,x)
+  \tl_clear:N\l_ocgxii_toswitch_e_tl
+  \tl_clear:N\l_ocgxii_toswitch_x_tl
+  \tl_clear:N\l_ocgxii_toswitch_d_tl
+  \tl_clear:N\l_ocgxii_toshow_e_tl
+  \tl_clear:N\l_ocgxii_toshow_x_tl
+  \tl_clear:N\l_ocgxii_toshow_d_tl
+  \tl_clear:N\l_ocgxii_tohide_e_tl
+  \tl_clear:N\l_ocgxii_tohide_x_tl
+  \tl_clear:N\l_ocgxii_tohide_d_tl
+  %
+  %process *all* mouse triggers (e,d,u,x)
+  \ocgxii_ocglist_process_idlist:nn{
+    \tl_if_blank:oTF{#2}{onmouseup}{#2}
+  }{#3}
+  \tl_set_eq:NN\l_ocgxii_toswitch_e_tl\l_ocgxii_e_list_tl
+  \tl_set_eq:NN\l_ocgxii_toswitch_x_tl\l_ocgxii_x_list_tl
+  \tl_set_eq:NN\l_ocgxii_toswitch_d_tl\l_ocgxii_d_list_tl
+  \tl_set_eq:NN\l_ocgxii_toswitch_u_tl\l_ocgxii_u_list_tl
+  \ocgxii_ocglist_process_idlist:nn{
+    \tl_if_blank:oTF{#2}{onmouseup}{#2}
+  }{#4}
+  \tl_set_eq:NN\l_ocgxii_toshow_e_tl\l_ocgxii_e_list_tl
+  \tl_set_eq:NN\l_ocgxii_toshow_x_tl\l_ocgxii_x_list_tl
+  \tl_set_eq:NN\l_ocgxii_toshow_d_tl\l_ocgxii_d_list_tl
+  \tl_set_eq:NN\l_ocgxii_toshow_u_tl\l_ocgxii_u_list_tl
+  \ocgxii_ocglist_process_idlist:nn{
+    \tl_if_blank:oTF{#2}{onmouseup}{#2}
+  }{#5}
+  \tl_set_eq:NN\l_ocgxii_tohide_e_tl\l_ocgxii_e_list_tl
+  \tl_set_eq:NN\l_ocgxii_tohide_x_tl\l_ocgxii_x_list_tl
+  \tl_set_eq:NN\l_ocgxii_tohide_d_tl\l_ocgxii_d_list_tl
+  \tl_set_eq:NN\l_ocgxii_tohide_u_tl\l_ocgxii_u_list_tl
+  %any triggers apart from mouse-up?
+  \str_if_eq:eeF{
+    \l_ocgxii_toswitch_e_tl\l_ocgxii_toswitch_x_tl\l_ocgxii_toswitch_d_tl
+    \l_ocgxii_toshow_e_tl\l_ocgxii_toshow_x_tl\l_ocgxii_toshow_d_tl
+    \l_ocgxii_tohide_e_tl\l_ocgxii_tohide_x_tl\l_ocgxii_tohide_d_tl
+  }{}{
+    \bool_set_true:N\l_ocgxii_mouse_triggers_bool
+  }
+  %
+  \bool_if:nTF{\l_ocgxii_nobreak_bool || \l_ocgxii_mouse_triggers_bool}{
+    \hbox_set:Nn\l_tmpa_box{#6}
+    \bool_if:NTF\l_ocgxii_mouse_triggers_bool{
+      % e,d,x mouse triggers require (non-breakable) /Widget annot
+      \pdfannot_dict_put:nnn{link/GoTo}{Subtype}{/Widget}
+      \pdfannot_dict_remove:nn{link/GoTo}{Border}
+    }{
+      \pdfannot_dict_put:nnn{link/GoTo}{Border}{[0~0~0]}
+    }
+    \pdfannot_dict_remove:nn{link/GoTo}{C}
+    \pbs_pdfannot:nnnn{
+      \dim_use:N\box_wd:N\l_tmpa_box}{
+      \dim_use:N\box_ht:N\l_tmpa_box}{
+      \dim_use:N\box_dp:N\l_tmpa_box
+    }{
+      \pdfannot_dict_use:n{link/GoTo}
+      \bool_if:NTF\l_ocgxii_mouse_triggers_bool{
+        /Ff~65536/FT/Btn/BS<</W~0>>
+        /T~(ocgx2@\int_use:N\g_ocgxii_widcount_int)
+        %treat mouse-up as mouse-click --> handle through /A dictionary
+        \str_if_eq:eeF{}{
+          \l_ocgxii_toswitch_u_tl\l_ocgxii_toshow_u_tl\l_ocgxii_tohide_u_tl
+        }{
+          /A <</S/SetOCGState/State [
+            \str_if_eq:VnF\l_ocgxii_toswitch_u_tl{}{
+              /Toggle~\l_ocgxii_toswitch_u_tl
+            }
+            \str_if_eq:VnF\l_ocgxii_toshow_u_tl{}{
+              /ON~\l_ocgxii_toshow_u_tl
+            }
+            \str_if_eq:VnF\l_ocgxii_tohide_u_tl{}{
+              /OFF~\l_ocgxii_tohide_u_tl
+            }
+          ]>>
+        }
+        % other mouse triggers need add. actions dict
+        /AA <<
+          %\str_if_eq:eeF{}{ % mouse-up
+          %  \l_ocgxii_toswitch_u_tl\l_ocgxii_toshow_u_tl\l_ocgxii_tohide_u_tl
+          %}{
+          %  /U <</S/SetOCGState/State [
+          %    \str_if_eq:VnF\l_ocgxii_toswitch_u_tl{}{
+          %      /Toggle~\l_ocgxii_toswitch_u_tl
+          %    }
+          %    \str_if_eq:VnF\l_ocgxii_toshow_u_tl{}{
+          %      /ON~\l_ocgxii_toshow_u_tl
+          %    }
+          %    \str_if_eq:VnF\l_ocgxii_tohide_u_tl{}{
+          %      /OFF~\l_ocgxii_tohide_u_tl
+          %    }
+          %  ]>>
+          %}
+          \str_if_eq:eeF{}{ % mouse-down
+            \l_ocgxii_toswitch_d_tl\l_ocgxii_toshow_d_tl\l_ocgxii_tohide_d_tl
+          }{
+            /D <</S/SetOCGState/State [
+              \str_if_eq:VnF\l_ocgxii_toswitch_d_tl{}{
+                /Toggle~\l_ocgxii_toswitch_d_tl
+              }
+              \str_if_eq:VnF\l_ocgxii_toshow_d_tl{}{
+                /ON~\l_ocgxii_toshow_d_tl
+              }
+              \str_if_eq:VnF\l_ocgxii_tohide_d_tl{}{
+                /OFF~\l_ocgxii_tohide_d_tl
+              }
+            ]>>
+          }
+          \str_if_eq:eeF{}{ % mouse-enter
+            \l_ocgxii_toswitch_e_tl\l_ocgxii_toshow_e_tl\l_ocgxii_tohide_e_tl
+          }{
+            /E <</S/SetOCGState/State [
+              \str_if_eq:VnF\l_ocgxii_toswitch_e_tl{}{
+                /Toggle~\l_ocgxii_toswitch_e_tl
+              }
+              \str_if_eq:VnF\l_ocgxii_toshow_e_tl{}{
+                /ON~\l_ocgxii_toshow_e_tl
+              }
+              \str_if_eq:VnF\l_ocgxii_tohide_e_tl{}{
+                /OFF~\l_ocgxii_tohide_e_tl
+              }
+            ]>>
+          }
+          \str_if_eq:eeF{}{ % mouse-exit
+            \l_ocgxii_toswitch_x_tl\l_ocgxii_toshow_x_tl\l_ocgxii_tohide_x_tl
+          }{
+            /X <</S/SetOCGState/State [
+              \str_if_eq:VnF\l_ocgxii_toswitch_x_tl{}{
+                /Toggle~\l_ocgxii_toswitch_x_tl
+              }
+              \str_if_eq:VnF\l_ocgxii_toshow_x_tl{}{
+                /ON~\l_ocgxii_toshow_x_tl
+              }
+              \str_if_eq:VnF\l_ocgxii_tohide_x_tl{}{
+                /OFF~\l_ocgxii_tohide_x_tl
+              }
+            ]>>
+          }
+        >>
+      }{
+        %mouse-up alone
+        /A <</S/SetOCGState
+          /State [
+            \str_if_eq:VnF{\l_ocgxii_toswitch_u_tl}{}{
+              /Toggle~\l_ocgxii_toswitch_u_tl}~
+            \str_if_eq:VnF{\l_ocgxii_toshow_u_tl}{}{/ON~\l_ocgxii_toshow_u_tl}~
+            \str_if_eq:VnF{\l_ocgxii_tohide_u_tl}{}{/OFF~\l_ocgxii_tohide_u_tl}
+          ]
+        >>
+      }
+    }\box_use_drop:N\l_tmpa_box
+    \bool_if:NT\l_ocgxii_mouse_triggers_bool{
+      \pbs_appendtofields:n{\pbs_pdflastann:}
+      \int_gincr:N\g_ocgxii_widcount_int
+    }
+  }{
+    %line-breakable annotation
+    \pbs_pdflink:nn{
+      %look and feel of hyperref internal links
+      \pdfannot_dict_use:n{link/GoTo}
+      /A <</S/SetOCGState
+        /State [
+          \str_if_eq:VnF{\l_ocgxii_toswitch_u_tl}{}{
+            /Toggle~\l_ocgxii_toswitch_u_tl}~
+          \str_if_eq:VnF{\l_ocgxii_toshow_u_tl}{}{/ON~\l_ocgxii_toshow_u_tl}~
+          \str_if_eq:VnF{\l_ocgxii_tohide_u_tl}{}{/OFF~\l_ocgxii_tohide_u_tl}
+        ]
+      >>
+    }{
+      \hook_use:n{pdfannot/link/GoTo/begin}
+      #6
+      \hook_use:n{pdfannot/link/GoTo/end}
+    }
+  }
+  \group_end:
+}
+
+%mimic commands from ocg-p
+\keys_define:nn{ocgx2/ocgpcmd}{
+  triggerocg .choices:nn = {
+    onmouseenter, onmouseexit, onmousedown, onmouseup, allactions
+  }{
+    \str_if_eq:eeTF{\l_keys_choice_tl}{allactions}{
+      \tl_set:Nn\l_ocgxii_trigger_tl{onmouseall}
+    }{
+      \tl_set_eq:NN\l_ocgxii_trigger_tl\l_keys_choice_tl
+    }
+  }
+}
+\DeclareDocumentCommand\toggleocgs{O{} m +m}{
+  \tl_clear_new:N\l_ocgxii_trigger_tl
+  \keys_set:nn{ocgx2/ocgpcmd}{#1}
+  \switchocg*[\l_ocgxii_trigger_tl]{#2}{#3}
+}
+\DeclareDocumentCommand\showocgs{O{} m +m}{
+  \tl_clear_new:N\l_ocgxii_trigger_tl
+  \keys_set:nn{ocgx2/ocgpcmd}{#1}
+  \showocg*[\l_ocgxii_trigger_tl]{#2}{#3}
+}
+\DeclareDocumentCommand\hideocgs{O{} m +m}{
+  \tl_clear_new:N\l_ocgxii_trigger_tl
+  \keys_set:nn{ocgx2/ocgpcmd}{#1}
+  \hideocg*[\l_ocgxii_trigger_tl]{#2}{#3}
+}
+\DeclareDocumentCommand\setocgs{O{} m m m +m}{
+  \tl_clear_new:N\l_ocgxii_trigger_tl
+  \keys_set:nn{ocgx2/ocgpcmd}{#1}
+  \actionsocg*[\l_ocgxii_trigger_tl]{#2}{#3}{#4}{#5}
+}
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+\cs_new_protected:Nn\ocgxii_process_ocgref:NN{
+  \tl_if_exist:cTF{ocgx2.ocg.#2}{
+    \tl_put_right:Nx#1{~\tl_use:c{ocgx2.ocg.#2}}
+  }{
+    \msg_warning:nnx{ocgx2}{undefined~OCG}{#2}
+    \tl_if_exist:NF\g_ocgxii_refundefwarned_tl{
+      \tl_new:N\g_ocgxii_refundefwarned_tl
+      \AtEndDocument{\msg_warning:nn{ocgx2}{undefined~OCGs}}
+    }
+  }
+}
+
+%ocg environment opts
+\keys_define:nn{ocgx2/ocgenv}{
+  viewocg .choice:,
+  viewocg / always .code:n={
+    \tl_set:Nn\l_ocgxii_view_tl{/View<</ViewState/ON>>}},
+  viewocg / never .code:n={
+    \tl_set:Nn\l_ocgxii_view_tl{/View<</ViewState/OFF>>}},
+  viewocg / ifvisible .code:n={
+    \tl_clear:N\l_ocgxii_view_tl},
+  viewocg .default:n={ifvisible},
+
+  printocg .choice:,
+  printocg / always .code:n={
+    \tl_set:Nn\l_ocgxii_print_tl{/Print<</PrintState/ON>>}},
+  printocg / never .code:n={
+    \tl_set:Nn\l_ocgxii_print_tl{/Print<</PrintState/OFF>>}},
+  printocg / ifvisible .code:n={
+    \tl_clear:N\l_ocgxii_print_tl},
+  printocg .default:n={ifvisible},
+
+  exportocg .choice:,
+  exportocg / always .code:n={
+    \tl_set:Nn\l_ocgxii_export_tl{/Export<</ExportState/ON>>}},
+  exportocg / never .code:n={
+    \tl_set:Nn\l_ocgxii_export_tl{/Export<</ExportState/OFF>>}},
+  exportocg / ifvisible .code:n={\tl_clear:N\l_ocgxii_export_tl},
+  exportocg .default:n={ifvisible},
+
+  showingui .choices:nn = {true,false,always,never,iffirstuse}{
+    \bool_if:nTF{
+      \str_if_eq_p:ee{#1}{false} ||
+      \str_if_eq_p:ee{#1}{never}
+    }{
+      \bool_set_false:N\l_ocgxii_showingui_bool
+    }{
+      \bool_set_true:N\l_ocgxii_showingui_bool
+    }
+  },
+  showingui .default:n={true},
+
+  listintoolbar .meta:n = {showingui=#1},
+  listintoolbar .default:n={true},
+
+  radiobtngrps .code:n = {
+    \clist_map_inline:nn{#1}{
+      \seq_if_in:NxF\l_ocgxii_rbgrps_seq{##1}{
+        \seq_put_right:Nx\l_ocgxii_rbgrps_seq{##1}
+      }
+    }
+  },
+  radiobtngrps .value_required:n = {true},
+  radiobtngrp .meta:n={radiobtngrps={#1}},
+  radiobtngrp .value_required:n = {true}
+}
+
+\cs_new_protected:Nn\ocgxii_reset_cmd_opts:{
+  \tl_set_eq:NN\l_ocgxii_view_tl\g_ocgxii_view_tl
+  \tl_set_eq:NN\l_ocgxii_print_tl\g_ocgxii_print_tl
+  \tl_set_eq:NN\l_ocgxii_export_tl\g_ocgxii_export_tl
+  \bool_set_eq:NN\l_ocgxii_showingui_bool\g_ocgxii_showingui_bool
+  %stack of radio button group names the current ocg belongs to
+  \seq_clear_new:N\l_ocgxii_rbgrps_seq
+}
+
+\msg_set:nnn{ocgx2}{rerun}{Rerun~to~get~OCG~references~right!}
+\msg_set:nnn{ocgx2}{undefined~OCG}{
+  Line~\msg_line_number: :~OCG~`#1'~is~not~defined.
+}
+\msg_set:nnn{ocgx2}{undefined~OCGs}{There~were~undefined~OCGs!}
+\msg_set:nnn{ocgx2}{unknown~option}{
+  Line~\msg_line_number: :~unknown~option~`#1'.
+}
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% allows `ocgcolorlinks' to extend over line-breaks AND page-breaks with
+% pdftex, luatex, xetex, dvipdfmx drivers
+%
+% based on Ben Lerner's idea
+%   http://tex.stackexchange.com/a/104227;
+% with some improvements
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+\bool_if:NT\l_ocgxii_ocgcolorlinks_bool{
+  % option ocgcolorlinks and beamer are not compatible
+  \@ifclassloaded{beamer}{
+    \bool_set_false:N\l_ocgxii_ocgcolorlinks_bool
+    \hypersetup{colorlinks}
+    \msg_warning:nn{ocgx2}{beamer~and~ocgcolorlinks}
+  }{}
+  % make sure that hyperref has been loaded if `ocgcolorlinks' is set via
+  % pkg option
+  \@ifpackageloaded{hyperref}{
+    \hypersetup{ocgcolorlinks}
+  }{
+    \msg_error:nnn{ocgx2}{missing~package}{hyperref}
+  }
+}
+
+% we'll be using the downscaled space character (32) from the pzdr
+% (dingbats) font at the start and at the end of every ocgcolorlink
+\cs_new_nopar:Npn\ocgxii_tiny_space_char:{
+  \group_begin: \font\l_tmpa_tl=pzdr~scaled~1\l_tmpa_tl\char32 \group_end:
+}
+
+\@ifpackageloaded{hyperref}{
+  \bool_if:nTF{\sys_if_output_dvi_p: && !\g_ocgxii_dvipdfmx_bool}{
+    \prop_map_inline:Nn\c__hyp_map_hyp_annot_prop{
+      \hook_gremove_code:nn{pdfannot/link/#2/begin}{hyp/ocg}
+      \hook_gput_code:nnn{pdfannot/link/#2/begin}{hyp/ocg}{
+        \bool_if:cT{l_hyp_annot_ocgcolor#1_bool}{
+          \ocgxii_colorlinks_init:
+          \group_begin:
+          \color_export:nnN{hyp/color/#1}{backend}\l_tempb_tl
+          \tl_set:Nx\l_tempa_tl{\tl_item:Nn\l_tempb_tl{1}}
+          \tl_set:Nx\l_tempb_tl{\tl_item:Nn\l_tempb_tl{2}}
+          \str_replace_all:Nnn\l_tempb_tl{~}{,}
+          \tl_set:Nx\l_ocgxii_lnkcol_tl{{\l_tempa_tl}{\l_tempb_tl}}
+          \ocgxii_colourlink_nobreak_begin:
+        }
+      }
+      \hook_gremove_code:nn{pdfannot/link/#2/end}{hyp/ocg}
+      \hook_gput_code:nnn{pdfannot/link/#2/end}{hyp/ocg}{
+        \bool_if:cT{l_hyp_annot_ocgcolor#1_bool}{
+          \ocgxii_colourlink_nobreak_end:
+          \group_end:
+        }
+      }
+    }
+  }{
+    \prop_map_inline:Nn\c__hyp_map_hyp_annot_prop{
+      \hook_gremove_code:nn{pdfannot/link/#2/begin}{hyp/ocg}
+      \hook_gput_code:nnn{pdfannot/link/#2/begin}{hyp/ocg}{
+        \bool_if:cT{l_hyp_annot_ocgcolor#1_bool}{
+          \ocgxii_colorlinks_init:
+          \seq_get_left:NNT\g_ocgxii_lnk_color_seq\l_tmpa_tl{
+            \tl_gset_eq:NN\g_ocgxii_lnkcol_tl\l_tmpa_tl
+            \ocgxii_colourlink_end:
+          }
+          \group_begin:
+          \ocgxii_colourlink_begin:
+          %query current link colour, export it into backend format
+          %and put it on the link colour stack
+          \color_export:nnN{hyp/color/#1}{backend}\l_tempb_tl
+          \tl_set:Nx\l_tempa_tl{\tl_item:Nn\l_tempb_tl{1}} % model
+          \tl_set:Nx\l_tempb_tl{\tl_item:Nn\l_tempb_tl{2}} % components
+          \str_replace_all:Nnn\l_tempb_tl{~}{,}
+          \seq_gpush:Nx\g_ocgxii_lnk_color_seq{{\l_tempa_tl}{\l_tempb_tl}}
+          \ocgxii_stack_shipout:NN\ocgxii at lnkcol@stack at on@page\g_ocgxii_lnk_color_seq
+        }
+      }
+      \hook_gremove_code:nn{pdfannot/link/#2/end}{hyp/ocg}
+      \hook_gput_code:nnn{pdfannot/link/#2/end}{hyp/ocg}{
+        \bool_if:cT{l_hyp_annot_ocgcolor#1_bool}{
+          \seq_gpop:NN\g_ocgxii_lnk_color_seq\l_tmpa_tl
+          \tl_gset_eq:NN\g_ocgxii_lnkcol_tl\l_tmpa_tl
+          \ocgxii_stack_shipout:NN\ocgxii at lnkcol@stack at on@page\g_ocgxii_lnk_color_seq
+          \ocgxii_colourlink_end:
+          \group_end:
+          \seq_get_left:NNT\g_ocgxii_lnk_color_seq\l_tmpa_tl{
+            \tl_gset_eq:NN\g_ocgxii_lnkcol_tl\l_tmpa_tl
+            \ocgxii_colourlink_begin:
+          }
+        }
+      }
+    }
+  }
+}{}
+
+\seq_new:N\g_ocgxii_lnk_color_seq %stack of colours of currently open links
+
+\cs_new_protected_nopar:Nn\ocgxii_colourlink_begin:{
+  %tiny space char put here in order to neutralise possible transformation
+  %matrix modifications from previous \pdfliteral{} (TikZ makes a lot use of it)
+  \hbox_overlap_left:n{\ocgxii_tiny_space_char:}
+  \pbs_literal:nn{page}{q~7~Tr}
+}
+\cs_new_protected_nopar:Nn\ocgxii_colourlink_end:{
+  %a tiny space char should keep empty link annots from flooding the page
+  % with link colour
+  %tiny space char put here in order to neutralise possible transformation
+  \hbox_overlap_left:n{\ocgxii_tiny_space_char:}
+  \ocgbase_oc_bdc:n{\tl_use:c{ocgxii_ocg_OCPrint}}
+    \pbs_literal:nn{page}{-88888~-88888~99999~99999~re~f}
+  \ocgbase_oc_emc:
+  \ocgbase_oc_bdc:n{\tl_use:c{ocgxii_ocg_OCView}}
+    \group_begin:
+      \exp_after:wN\color_select:nn\g_ocgxii_lnkcol_tl
+      \pbs_literal:nn{page}{-88888~-88888~99999~99999~re~f}
+    \group_end:
+  \ocgbase_oc_emc:
+  \pbs_literal:nn{page}{0~Tr~Q}
+}
+
+\cs_new_protected_nopar:Nn\ocgxii_colourlink_nobreak_begin:{
+  \hbox_set:Nw\l_tmpa_box
+}
+\cs_new_protected_nopar:Nn\ocgxii_colourlink_nobreak_end:{
+  \hbox_set_end:
+  \mbox{
+    \ocgbase_oc_bdc:n{\tl_use:c{ocgxii_ocg_OCPrint}}
+    \hbox_overlap_right:n{\box_use:N\l_tmpa_box}
+    \ocgbase_oc_emc:
+    \ocgbase_oc_bdc:n{\tl_use:c{ocgxii_ocg_OCView}}
+    \group_begin:
+      \exp_after:wN\color_select:nn\l_ocgxii_lnkcol_tl
+      \box_use_drop:N\l_tmpa_box
+    \group_end:
+    \ocgbase_oc_emc:
+  }
+}
+
+% creates OCG objects for printing and viewing
+\cs_new_protected:Npn\ocgxii_colorlinks_init:{
+  \ocgbase_new_ocg:nnn{OCView}{
+    /Print<</PrintState/OFF>>
+    /Export<</ExportState/OFF>>
+  }{on}
+  \tl_gset:cx{ocgxii_ocg_OCView}{\ocgbase_last_ocg:}
+  %in case somebody wants to reopen with \begin{ocg}...
+  \tl_gset:cx{ocgxii_ocg_OCView.opts}{
+    showingui=never,printocg=never,exportocg=never
+  }
+  \ocgbase_new_ocg:nnn{OCPrint}{
+    /Print<</PrintState/ON>>
+    /Export<</ExportState/ON>>
+  }{off}
+  \tl_gset:cx{ocgxii_ocg_OCPrint}{\ocgbase_last_ocg:}
+  \tl_gset:cx{ocgxii_ocg_OCPrint.opts}{
+    showingui=never,printocg=always,exportocg=always
+  }
+  \iow_now:Nx\@mainaux{
+    \token_to_str:N\ocgxii at newkey{ocgx2.ocg.OCView}{
+      \tl_use:c{ocgxii_ocg_OCView}}
+  }
+  \iow_now:Nx\@mainaux{
+    \token_to_str:N\ocgxii at newkey{ocgx2.ocg.OCPrint}{
+      \tl_use:c{ocgxii_ocg_OCPrint}}
+  }
+  \cs_gset:Npn\ocgxii_colorlinks_init:{}
+}
+
+% user command for protecting graphical content (external file, inline
+% [e. g. TikZ], \fbox{...}) inside breakable ocgcolorlink
+\DeclareDocumentCommand\ocglinkprotect{m}{
+  \seq_get_left:NNTF\g_ocgxii_lnk_color_seq\l_tmpa_tl{
+    \tl_gset_eq:NN\g_ocgxii_lnkcol_tl\l_tmpa_tl
+    \ocgxii_colourlink_end:
+    \group_begin:
+      \tl_set_eq:NN\l_ocgxii_lnkcol_tl\l_tmpa_tl
+      \ocgxii_colourlink_nobreak_begin:
+        \cs_set_nopar:Npn\ocglinkprotect##1{##1} % in case of nesting
+        \sys_if_output_pdf:TF{
+          \mode_leave_vertical:
+          \hbox_set:Nn\l_tmpb_box{\skip_horizontal:n{1em}#1\skip_horizontal:n{1em}}
+          \box_set_ht:Nn\l_tmpb_box{\box_ht:N\l_tmpb_box+1em}
+          \box_set_dp:Nn\l_tmpb_box{\box_dp:N\l_tmpb_box+1em}
+          \hbox_to_wd:nn{\box_wd:N\l_tmpb_box-2em}{
+            \vrule~
+              width~\c_zero_dim~
+              height~\dim_eval:n{\box_ht:N\l_tmpb_box-1em}~
+              depth~\dim_eval:n{\box_dp:N\l_tmpb_box -1em}~
+            \pbs_pdfxform:nnnnn{1}{0}{}{}{\l_tmpb_box}
+            \skip_horizontal:n{-1em}
+            \pbs_pdfrefxform:n{\pbs_pdflastxform:}
+            \hss
+          }
+        }{#1}
+      \ocgxii_colourlink_nobreak_end:
+    \group_end:
+    \ocgxii_colourlink_begin:
+  }{#1}
+}
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+% TikZ related code follows (to be enabled with package option `tikz')
+
+\bool_if:NF\l_ocgxii_tikz_bool{\endinput}
+\cs_set_eq:NN\ocgxii at trmspc\tl_trim_spaces:N
+\ExplSyntaxOff
+\RequirePackage{tikz}
+\usetikzlibrary{calc}
+
+% helper, replaces all spaces in #1 with `_'
+\def\ocgxii at cnvspc#1{\expandafter\ocgxii@@cnvspc#1 \@nil}
+\def\ocgxii@@cnvspc#1 #2\@nil{#1\ifx\@nil#2\@nil\else_\ocgxii@@cnvspc#2\@nil\fi}
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Copyright notice: The code that follows until the end of the file was
+% taken in large parts from Paul Gaborit's `tikzlibraryocgx.code.tex' with
+% some additions/fixes:
+%
+%  - opts={...} inside ocg={...} allows ocg-environment options to be passed
+%    to a TikZ scope
+%
+%  - The style ocmd={...} is another way for turning a TikZ scope into a PDF
+%    layer (in addition to ocg={...}). It has two sub-keys, ref={...} and
+%    visibility={...}, which have the same meaning as the optional and the
+%    mandatory arguments of the `ocmd' environment
+%
+%  - TikZ objects to be turned into OCG switching links accept the additional
+%    key
+%
+%      trigger ocg = onmousenter | onmouseexit | onmousedown | onmouseup |
+%                      onmouseall
+%
+%    to react to various mouse gestures
+%
+%  - switching links properly sized and working in scaled tikzpictures
+%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+\tikzset{
+  ocg/.style={ocg/.cd,#1,/tikz/.cd},
+  ocg={
+    % parameters
+    name/.store in=\ocgxii at name,
+    opts/.store in=\ocgxii at opts,
+    visibility/.store in=\ocgxii at visibility,
+    status/.is choice,
+    status/visible/.style={visibility=1},
+    status/invisible/.style={visibility=0},
+    status/true/.style={visibility=1},
+    status/false/.style={visibility=0},
     status/on/.style={visibility=1},
     status/off/.style={visibility=0},
     status/1/.style={visibility=1},



More information about the tex-live-commits mailing list.