%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% fixocgx.sty
%
% Copyright 2015--\today, Alexander Grahn
%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% This package extends the usability of `ocgx' to all known engines including
% latex+dvips+ps2pdf, xelatex and latex+dvipdfmx.
%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

% This work may be distributed and/or modified under the
% conditions of the LaTeX Project Public License, either version 1.3
% of this license or (at your option) any later version.
% The latest version of this license is in
%   http://mirrors.ctan.org/help/Catalogue/licenses.lppl.html
% and version 1.3 or later is part of all distributions of LaTeX
% version 2005/12/01 or later.
%
% This work has the LPPL maintenance status `maintained'.
%
% The Current Maintainer of this work is A. Grahn.

\RequirePackage{xparse}
\RequirePackage{atenddvi}
\RequirePackage{ifpdf}

%prevent ocg-p from inserting PS specials in dvipdfmx mode
\ifpdf\else
 \DeclareOption{dvipdfmx}{\@ocgp@ifpsfalse}
 \ProcessOptions\relax
\fi

\@ifpackageloaded{ocgx}{}{
 \PackageError{fixocgx}{%
   Package `fixocgx' must be loaded /after/ one of\MessageBreak
   \space\space\string\usepackage{ocgx}\MessageBreak
   or\MessageBreak
   \space\space\string\usetikzlibrary{ocgx}
 }{}%
}

\AtBeginDocument{
 \@ifpackageloaded{media9}{}{\RequirePackage{media9}}
 \@ifpackagelater{media9}{2015/01/21}{}{
   \PackageError{fixocgx}{%
     Requires package `media9' v0.49 [2015/01/21] or\MessageBreak
     newer, but only v\g@mix@version@tl\space[\g@mix@date@tl] is available
   }{}%
 }
}

\ProvidesExplPackage{fixocgx}{2015/06/15}{0.5}
{ports `ocgx' functionality to dvips+ps2pdf, xelatex and dvipdfmx}

%re-implement ocg-p's `ocg' environment
\DeclareDocumentEnvironment{ocg}{O{}mmm}{
 \bool_if:NT\g_fxocg_nestedB_bool{\tl_gput_right:Nx\@ocgbase@ocgorder{~[}}
 \bool_gset_true:N\g_fxocg_nestedB_bool
 \bool_gset_false:N\g_fxocg_nestedE_bool
 \group_begin:
   \tl_if_exist:cTF{fxocg@#3}{ %re-open existing layer
     \tl_set:Nx\l_tempa_tl{[ocgp]{ocg}{\use:c{fxocg@#3.opts},#1}}
     \exp_after:wN\setkeys\l_tempa_tl
     \int_compare:nT{\@ocgp@listno=\c_zero}{
       \tl_gput_right:Nx\@ocgbase@ocgorder{~\use:c{fxocg@#3}}
     }
   }{
     \tl_gset:cn{fxocg@#3.opts}{#1}
     \setkeys[ocgp]{ocg}{#1}
     \mix_pdfobj:nnn{}{dict}{
       /Type/OCG/Name~(#2)/Usage<<\l_fxocg_view_tl\@ocgp@print\@ocgp@export>>
     }
     \tl_gput_right:Nx\@ocgbase@ocgs{\space\g_mix_pdflastobj_tl}
     \int_compare:nT{#4==\c_zero}{
       \tl_gput_right:Nx\@ocgbase@offocgs{\space\g_mix_pdflastobj_tl}
     }
     \tl_gset:cx{fxocg@#3}{\g_mix_pdflastobj_tl}
     \int_compare:nF{\@ocgp@listno=\c_one}{
       \tl_gput_right:Nx\@ocgbase@ocgorder{~\g_mix_pdflastobj_tl}
     }
     \iow_now:Nx\@auxout{
       \token_to_str:N\expandafter\xdef\token_to_str:N\csname
       \space OCGpdfobj#3\endcsname{\g_mix_pdflastobj_tl}
     }
   }
   \bool_if:nT{
     !\cs_if_exist_p:c{OCGpdfobj#3} ||
     !\str_if_eq_x_p:nn{\use:c{OCGpdfobj#3}}{\use:c{fxocg@#3}}
   }{
     \cs_if_exist:NF\g_fxocg_rerunwarned_tl{
       \tl_new:N\g_fxocg_rerunwarned_tl
       \AtEndDocument{\msg_warning:nn{fixocgx}{rerun}}
     }
   }
   \tl_gset:cx{OCGpdfobj#3}{\use:c{fxocg@#3}}
   \seq_gput_left:Nx\g_fixocg_ocgstack_seq{\use:c{fxocg@#3}}
 \group_end:
 \mix_pdfbdc:nn{/OC}{\use:c{fxocg@#3}}
 \ignorespaces
}{
 \unskip
 \mix_pdfemc:
 \seq_gpop_left:NN\g_fixocg_ocgstack_seq\l_tempa_tl
 \bool_if:NT\g_fxocg_nestedE_bool{\tl_gput_right:Nx\@ocgbase@ocgorder{~]}}
 \bool_gset_true:N\g_fxocg_nestedE_bool
 \bool_gset_false:N\g_fxocg_nestedB_bool
}
\bool_new:N\g_fxocg_nestedB_bool % nested OCG begin
\bool_new:N\g_fxocg_nestedE_bool % nested OCG end

%stack of PDF obj references of currently open OCGs
\seq_new:N\g_fixocg_ocgstack_seq
%macro that inserts /OC <<OCMD with currently open OCGs>> entry;
%for use within annotation dicts
\tl_set:Nn\fxocg@insert@OC{
 \seq_if_empty:NF\g_fixocg_ocgstack_seq{
   /OC~<</Type/OCMD/OCGs~[\seq_use:Nn\g_fixocg_ocgstack_seq{~}]/P/AllOn>>
 }
}

%workaround for ocg buttons (from tikzlibraryocgx.code.tex)
%with dvipdfmx and xelatex
\cs_set:Nn\fxocg_pdflink:nn{
 \bool_if:nTF{
   \g_mix_dvipdfmx_bool && \cs_if_exist_p:N\pgfpictureid
 }{
   \hbox_set:Nn\l_tmpa_box{#2}
   \mix_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
   }{#1}
   \box_use_clear:N\l_tmpa_box
 }{
   \mix_pdflink:nn{#1}{#2}
 }
}

%re-implement commands from ocgx.sty (all engines including ps2pdf [gs>=9.15])
\DeclareDocumentCommand\switchocg{mm}{
 \tl_set:Nn\l_fxocg_ocglist_tl{}
 \tl_set:Nx\l_ocglistarg_tl{#1}\tl_trim_spaces:N\l_ocglistarg_tl
 \seq_set_split:NnV\l_fxocg_ocglistarg_seq{~}\l_ocglistarg_tl
 \seq_map_variable:NNn\l_fxocg_ocglistarg_seq\l_tempa_tl{
   \fxocg_process_ocgref:NN\l_fxocg_ocglist_tl\l_tempa_tl
 }
 \leavevmode
 \fxocg_pdflink:nn{
   /Subtype/Link\fxocg@insert@OC
   /A <</S/SetOCGState/State [
     \str_if_eq:VnF{\l_fxocg_ocglist_tl}{}{/Toggle~\l_fxocg_ocglist_tl}]>>
   /Border [0~0~0]
 }{#2}
}

\DeclareDocumentCommand\showocg{mm}{
 \tl_set:Nn\l_fxocg_ocglist_tl{}
 \tl_set:Nx\l_ocglistarg_tl{#1}\tl_trim_spaces:N\l_ocglistarg_tl
 \seq_set_split:NnV\l_fxocg_ocglistarg_seq{~}\l_ocglistarg_tl
 \seq_map_variable:NNn\l_fxocg_ocglistarg_seq\l_tempa_tl{
   \fxocg_process_ocgref:NN\l_fxocg_ocglist_tl\l_tempa_tl
 }
 \leavevmode
 \fxocg_pdflink:nn{
   /Subtype/Link\fxocg@insert@OC
   /A <</S/SetOCGState/State [
     \str_if_eq:VnF{\l_fxocg_ocglist_tl}{}{/ON~\l_fxocg_ocglist_tl}]>>
   /Border [0~0~0]
 }{#2}
}

\DeclareDocumentCommand\hideocg{mm}{
 \tl_set:Nn\l_fxocg_ocglist_tl{}
 \tl_set:Nx\l_ocglistarg_tl{#1}\tl_trim_spaces:N\l_ocglistarg_tl
 \seq_set_split:NnV\l_fxocg_ocglistarg_seq{~}\l_ocglistarg_tl
 \seq_map_variable:NNn\l_fxocg_ocglistarg_seq\l_tempa_tl{
   \fxocg_process_ocgref:NN\l_fxocg_ocglist_tl\l_tempa_tl
 }
 \leavevmode
 \fxocg_pdflink:nn{
   /Subtype/Link\fxocg@insert@OC
   /A <</S/SetOCGState/State [
     \str_if_eq:VnF{\l_fxocg_ocglist_tl}{}{/OFF~\l_fxocg_ocglist_tl}]>>
   /Border [0~0~0]
 }{#2}
}

\DeclareDocumentCommand\actionsocg{mmmm}{
 \tl_set:Nx\l_ocglistarg_tl{#1}\tl_trim_spaces:N\l_ocglistarg_tl
 \tl_set:Nn\l_fxocg_toswitch_tl{}
 \seq_set_split:NnV\l_fxocg_ocglistarg_seq{~}\l_ocglistarg_tl
 \seq_map_variable:NNn\l_fxocg_ocglistarg_seq\l_tempa_tl{
   \fxocg_process_ocgref:NN\l_fxocg_toswitch_tl\l_tempa_tl
 }
 \tl_set:Nx\l_ocglistarg_tl{#2}\tl_trim_spaces:N\l_ocglistarg_tl
 \tl_set:Nn\l_fxocg_toshow_tl{}
 \seq_set_split:NnV\l_fxocg_ocglistarg_seq{~}\l_ocglistarg_tl
 \seq_map_variable:NNn\l_fxocg_ocglistarg_seq\l_tempa_tl{
   \fxocg_process_ocgref:NN\l_fxocg_toshow_tl\l_tempa_tl
 }
 \tl_set:Nx\l_ocglistarg_tl{#3}\tl_trim_spaces:N\l_ocglistarg_tl
 \tl_set:Nn\l_fxocg_tohide_tl{}
 \seq_set_split:NnV\l_fxocg_ocglistarg_seq{~}\l_ocglistarg_tl
 \seq_map_variable:NNn\l_fxocg_ocglistarg_seq\l_tempa_tl{
   \fxocg_process_ocgref:NN\l_fxocg_tohide_tl\l_tempa_tl
 }
 \leavevmode
 \fxocg_pdflink:nn{
   /Subtype/Link\fxocg@insert@OC
   /A <</S/SetOCGState
     /State [
       \str_if_eq:VnF{\l_fxocg_toswitch_tl}{}{/Toggle~\l_fxocg_toswitch_tl}~
       \str_if_eq:VnF{\l_fxocg_toshow_tl}{}{/ON~\l_fxocg_toshow_tl}~
       \str_if_eq:VnF{\l_fxocg_tohide_tl}{}{/OFF~\l_fxocg_tohide_tl}
     ]
   >>
   /Border [0~0~0]
 }{#4}
}

\cs_new:Nn\fxocg_process_ocgref:NN{
 \str_if_eq_x:nnF{#2}{}{
   \tl_if_exist:cTF{OCGpdfobj#2}{\tl_put_right:Nx#1{~\use:c{OCGpdfobj#2}}}{
     \msg_warning:nnx{fixocgx}{undefined~OCG}{#2}
     \cs_if_exist:NF\g_fxocg_refundefwarned_tl{
       \tl_new:N\g_fxocg_refundefwarned_tl
       \AtEndDocument{\msg_warning:nn{fixocgx}{undefined~OCGs}}
     }
   }
 }
}

\define@choicekey*[ocgp]{ocg}{viewocg}[\l_fxocg_viewbin_tl\l_fxocg_viewno_tl]{always,never,ifvisible}[ifvisible]{%
 \if_case:w\l_fxocg_viewno_tl
   \def\l_fxocg_view_tl{/View<</ViewState/ON>>}
 \or:%
   \def\l_fxocg_view_tl{/View<</ViewState/OFF>>}
 \or:
   \def\l_fxocg_view_tl{}
 \fi:
}
\presetkeys[ocgp]{ocg}{viewocg=ifvisible,printocg=ifvisible,exportocg=ifvisible,listintoolbar=iffirstuse}{}

\group_begin:
\char_set_catcode_active:N\+\let+\space
\tl_gset:Nx\g_fxocg_gsoldwarning_tl{
 {product~(Ghostscript)~search~{pop~pop~pop~true}{pop~false}ifelse~
  revision~915~lt~and~{
 (\token_to_str:N\n
 @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@\token_to_str:N\n
 @@++++++++++++Warning:+Ghostscript+too+old!++++++++++++++++@@\token_to_str:N\n
 @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@\token_to_str:N\n
 @@+++++++++++++++++++++++++++++++++++++++++++++++++++++++++@@\token_to_str:N\n
 @@+Package+`fixocgx'+requires+Ghostscript+version+>=+9.15.+@@\token_to_str:N\n
 @@+Otherwise,+PDF+layers+will+not+work.++++++++++++++++++++@@\token_to_str:N\n
 @@+++++++++++++++++++++++++++++++++++++++++++++++++++++++++@@\token_to_str:N\n
 @@+Get+current+version+from++++++++++++++++++++++++++++++++@@\token_to_str:N\n
 @@+http://www.ghostscript.com/download+++++++++++++++++++++@@\token_to_str:N\n
 @@+++++++++++++++++++++++++++++++++++++++++++++++++++++++++@@\token_to_str:N\n
 @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@\token_to_str:N\n)
 print}~if}~?pdfmark
}
\group_end:

\AtBeginDocument{
 \ifpdf\else
   \bool_if:NF\g_mix_dvipdfmx_bool{
     \AtEndDvi{\special{ps::[nobreak]\g_fxocg_gsoldwarning_tl}}
   }
 \fi
}

\msg_set:nnn{fixocgx}{rerun}{Rerun~to~get~OCG~references~right!}
\msg_set:nnn{fixocgx}{undefined~OCG}{
 Line~\msg_line_number: :~OCG~`#1'~is~not~defined.
}
\msg_set:nnn{fixocgx}{undefined~OCGs}{There~were~undefined~OCGs!}