%%%%%%%%%%%%%%%%%%%%%% pdfmanagement-testphase %%%%%%%%%%%%%%%%%%%
\newif\if@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@testphasetrue}
\ExplSyntaxOff
\if@ocgbase@testphase\else
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% 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@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@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@tree@node@begin (LaTeX2e versions)
%   \ocgbase@tree@node@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@add@to@off@list (LaTeX2e version)
%     #1: PDF object ID of OCG
%     macro for setting initial visibility to `off'
%
%   --------
%
%   \ocgbase_del_from_off_list:n
%   \ocgbase@del@from@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@add@ocg@to@radiobtn@grp
%     add OCG #2 (obj ref) to radio button group `#1' (string),
%
%   --------
%
%   \ocgbase_oc_bdc:n
%   \ocgbase@oc@bdc
%     #1: OCG obj ref
%     mark begin of optional content belonging to OCG #1 in the current
%     content stream
%
%   \ocgbase_oc_emc:
%   \ocgbase@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.

\def\g@ocgbase@date@tl{2024/09/15}
\def\g@ocgbase@version@tl{0.24}

\ProvidesExplPackage{ocgbase}{\g@ocgbase@date@tl}{\g@ocgbase@version@tl}
{support package for ocgx2.sty}

%package options

\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}{
  pdftex.code:n = {},
  pdftex.value_forbidden:n = true,

  luatex.code:n = {},
  luatex.value_forbidden:n = true,

  xetex.code:n = {},
  xetex.value_forbidden:n = true,

  dvips.code:n = {},
  dvips.value_forbidden:n = true,

  dvipdfmx .code:n = {
    \PassOptionsToPackage{dvipdfmx}{pdfbase}
  },
  dvipdfmx .value_forbidden:n = true,

  unknown .code:n = {
    \msg_error:nnx{ocgbase}{unknown~package~option}{\l_keys_key_tl}
  }
}
\ProcessKeyOptions[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}{2022/08/04}{}{
  \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
    \seq_if_empty:NF\g_ocgbase_order_root_seq{
      \ocgbase_build_order:Nn\l_ocgbase_ocgorder_tl{root}
    }
    \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:}
    }
    \pbs_pdfcatalog:n{
      /OCProperties~<<
        /OCGs~\l_ocgbase_ocgarray_tl
        /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_new_protected_nopar:Nn\ocgbase_new_ocg:nnn{
  \pbs_pdfobj:nnn{}{dict}{
    /Type/OCG/Name~(#1)~\str_if_eq:eeF{#2}{}{/Usage<<#2>>}
  }
  \tl_gput_right:Nx\g_ocgbase_ocgs_tl{~\pbs_pdflastobj:}
  \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{\pbs_pdflastobj:}
  }
  \tl_gset:Nx\g_ocgbase_last_ocg_tl{\pbs_pdflastobj:}
}

\cs_new_nopar:Nn\ocgbase_last_ocg:{\g_ocgbase_last_ocg_tl}

\seq_new:N\g_ocgbase_open_ocg_seq  %stack with open ocg ref
\seq_new:N\g_ocgbase_order_root_seq  %seq taking ocg ref /Order root

%macro for starting OCG object (and nested children) insertion into order
%hierarchy (shown as tree structure in the viewers `Layers' tab
\cs_new_protected_nopar:Nn\ocgbase_tree_node_begin:n{ % #1: OCG obj
  % get parent (either currently open ocg or root)
  \seq_get:NNF\g_ocgbase_open_ocg_seq\l__ocgbase_prnt_tl{
    \tl_set:Nn\l__ocgbase_prnt_tl{root}
  }
  %push current ocg ref on stack with open ocgs
  \seq_gpush:Nx\g_ocgbase_open_ocg_seq{#1}
  %create seq for current ocg if not yet existing and
  %append ocg ref to its parent seq
  \seq_if_exist:cF{g_ocgbase_order_#1_seq}{
    \seq_new:c{g_ocgbase_order_#1_seq}
    \seq_gput_right:cx{g_ocgbase_order_ \l__ocgbase_prnt_tl _seq}{#1}
  }
}

%macro that ends insertion of current OCG into order tree
\cs_new_protected:Nn\ocgbase_tree_node_end:{
  %pop top ocg ref from stack with open ocgs
  \seq_gpop:NN\g_ocgbase_open_ocg_seq\g_trash_tl
}

%macro that builds global ocg order from hierarchy and saves it into tl var
\cs_new_protected_nopar:Nn\ocgbase_build_order:Nn{
  % (recursive macro)
  % #1: tl var to which the OCG order is written (output)
  % #2: starting node (input; usually `root')
  \seq_map_inline:cn{g_ocgbase_order_#2_seq}{
    % first, append ocg ref to result tl var
    \tl_put_right:Nx#1{~##1}
    \seq_if_empty:cF{g_ocgbase_order_##1_seq}{
      \tl_put_right:Nn#1{~[}
      \ocgbase_build_order:Nn#1{##1}
      \tl_put_right:Nn#1{~]}
    }
  }
}

%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@new@ocg\ocgbase_new_ocg:nnn
\cs_gset_eq:NN\ocgbase@last@ocg\ocgbase_last_ocg:
\cs_gset_eq:NN\ocgbase@tree@node@begin\ocgbase_tree_node_begin:n
\cs_gset_eq:NN\ocgbase@tree@node@end\ocgbase_tree_node_end:
\cs_gset_eq:NN\ocgbase@add@to@off@list\ocgbase_add_to_off_list:n
\cs_gset_eq:NN\ocgbase@del@from@off@list\ocgbase_del_from_off_list:n
\cs_gset_eq:NN\ocgbase@add@ocg@to@radiobtn@grp\ocgbase_add_ocg_to_radiobtn_grp:nn
\cs_gset_eq:NN\ocgbase@oc@bdc\ocgbase_oc_bdc:n
\cs_gset_eq:NN\ocgbase@oc@emc\ocgbase_oc_emc:
\cs_gset_eq:NN\ocgbase@open@stack@pop\ocgbase_open_stack_pop:N
\cs_gset_eq:NN\ocgbase@open@stack@push\ocgbase_open_stack_push:n
\fi
\begingroup
\if@ocgbase@testphase\else\aftergroup\endinput\fi
\endgroup
%%%%%%%%%%%%%%%%%%%%%% /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@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@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@tree@node@begin (LaTeX2e versions)
%   \ocgbase@tree@node@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@add@to@off@list (LaTeX2e version)
%     #1: PDF object ID of OCG
%     macro for setting initial visibility to `off'
%
%   --------
%
%   \ocgbase_del_from_off_list:n
%   \ocgbase@del@from@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@add@ocg@to@radiobtn@grp
%     add OCG #2 (obj ref) to radio button group `#1' (string),
%
%   --------
%
%   \ocgbase_oc_bdc:n
%   \ocgbase@oc@bdc
%     #1: OCG obj ref
%     mark begin of optional content belonging to OCG #1 in the current
%     content stream
%
%   \ocgbase_oc_emc:
%   \ocgbase@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.

\def\g@ocgbase@date@tl{2024/09/15}
\def\g@ocgbase@version@tl{0.24}

\ProvidesExplPackage{ocgbase}{\g@ocgbase@date@tl}{\g@ocgbase@version@tl}
{support package for ocgx2.sty}

%package options

\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}{
  pdftex.code:n = {},
  pdftex.value_forbidden:n = true,

  luatex.code:n = {},
  luatex.value_forbidden:n = true,

  xetex.code:n = {},
  xetex.value_forbidden:n = true,

  dvips.code:n = {},
  dvips.value_forbidden:n = true,

  dvipdfmx .code:n = {
    \PassOptionsToPackage{dvipdfmx}{pdfbase}
  },
  dvipdfmx .value_forbidden:n = true,

  unknown .code:n = {
    \msg_error:nnx{ocgbase}{unknown~package~option}{\l_keys_key_tl}
  }
}
\ProcessKeyOptions[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}{2022/08/04}{}{
  \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
    \pdf_object_unnamed_write:ne{array}{\g_ocgbase_ocgs_tl}
    \tl_set:Nx\l_ocgbase_ocgarray_tl{\pdf_object_ref_last:}
    %global OFF list
    \tl_new:N\l_ocgbase_offocgentry_tl
    \seq_if_empty:NF\g_ocgbase_offocgs_seq{
      \pdf_object_unnamed_write:ne{array}{\seq_use:Nn\g_ocgbase_offocgs_seq{~}}
      \tl_set:Nx\l_ocgbase_offocgentry_tl{/OFF~\pdf_object_ref_last:}
    }
    %global Order list
    \tl_new:N\l_ocgbase_ocgorderentry_tl
    \tl_new:N\l_ocgbase_ocgorder_tl
    \seq_if_empty:NF\g_ocgbase_order_root_seq{
      \ocgbase_build_order:Nn\l_ocgbase_ocgorder_tl{root}
    }
    \tl_if_empty:NF\l_ocgbase_ocgorder_tl{
      \pdf_object_unnamed_write:ne{array}{\l_ocgbase_ocgorder_tl}
      \tl_set:Nx\l_ocgbase_ocgorderentry_tl{/Order~\pdf_object_ref_last:}
    }
    %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{
      \pdf_object_unnamed_write:ne{array}{\l_ocgbase_rbtn_groups_tl}
      \tl_set:Nx\l_ocgbase_rbgroupsentry_tl{/RBGroups~\pdf_object_ref_last:}
    }
    \pdfmanagement_add:nnx{Catalog/OCProperties}{OCGs}{\g_ocgbase_ocgs_tl}
    \pdfmanagement_add:nnx{Catalog/OCProperties}{D}{<<
          /Name~(OC~default~configuration)
          \pdfmeta_standard_verify:nT{Catalog_OCProperties_no_AS}{ %for pdf/a compliance
            /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
\int_new:N\g_ocgbase_int
\cs_new_protected_nopar:Nn\ocgbase_new_ocg:nnn{
  \exp_args:Ne\pdf_object_new:n{g_object_\int_use:N\g_ocgbase_int _pdf}
  \exp_args:Neee\pdf_object_write:nnn{g_object_ \int_use:N\g_ocgbase_int _pdf}{dict}{
    /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}

\seq_new:N\g_ocgbase_open_ocg_seq  %stack with open ocg ref
\seq_new:N\g_ocgbase_order_root_seq  %seq taking ocg ref /Order root

%macro for starting OCG object (and nested children) insertion into order
%hierarchy (shown as tree structure in the viewers `Layers' tab
\cs_new_protected_nopar:Nn\ocgbase_tree_node_begin:n{ % #1: OCG obj
  % get parent (either currently open ocg or root)
  \seq_get:NNF\g_ocgbase_open_ocg_seq\l__ocgbase_prnt_tl{
    \tl_set:Nn\l__ocgbase_prnt_tl{root}
  }
  %push current ocg ref on stack with open ocgs
  \seq_gpush:Nx\g_ocgbase_open_ocg_seq{#1}
  %create seq for current ocg if not yet existing and
  %append ocg ref to its parent seq
  \seq_if_exist:cF{g_ocgbase_order_#1_seq}{
    \seq_new:c{g_ocgbase_order_#1_seq}
    \seq_gput_right:cx{g_ocgbase_order_ \l__ocgbase_prnt_tl _seq}{#1}
  }
}

%macro that ends insertion of current OCG into order tree
\cs_new_protected:Nn\ocgbase_tree_node_end:{
  %pop top ocg ref from stack with open ocgs
  \seq_gpop:NN\g_ocgbase_open_ocg_seq\g_trash_tl
}

%macro that builds global ocg order from hierarchy and saves it into tl var
\cs_new_protected_nopar:Nn\ocgbase_build_order:Nn{
  % (recursive macro)
  % #1: tl var to which the OCG order is written (output)
  % #2: starting node (input; usually `root')
  \seq_map_inline:cn{g_ocgbase_order_#2_seq}{
    % first, append ocg ref to result tl var
    \tl_put_right:Nx#1{~##1}
    \seq_if_empty:cF{g_ocgbase_order_##1_seq}{
      \tl_put_right:Nn#1{~[}
      \ocgbase_build_order:Nn#1{##1}
      \tl_put_right:Nn#1{~]}
    }
  }
}

%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_eq: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@new@ocg\ocgbase_new_ocg:nnn
\cs_gset_eq:NN\ocgbase@last@ocg\ocgbase_last_ocg:
\cs_gset_eq:NN\ocgbase@tree@node@begin\ocgbase_tree_node_begin:n
\cs_gset_eq:NN\ocgbase@tree@node@end\ocgbase_tree_node_end:
\cs_gset_eq:NN\ocgbase@add@to@off@list\ocgbase_add_to_off_list:n
\cs_gset_eq:NN\ocgbase@del@from@off@list\ocgbase_del_from_off_list:n
\cs_gset_eq:NN\ocgbase@add@ocg@to@radiobtn@grp\ocgbase_add_ocg_to_radiobtn_grp:nn
\cs_gset_eq:NN\ocgbase@oc@bdc\ocgbase_oc_bdc:n
\cs_gset_eq:NN\ocgbase@oc@emc\ocgbase_oc_emc:
\cs_gset_eq:NN\ocgbase@open@stack@pop\ocgbase_open_stack_pop:N
\cs_gset_eq:NN\ocgbase@open@stack@push\ocgbase_open_stack_push:n
