From e0c6872cf40896c7be36b11dcc744620f10adf1d Mon Sep 17 00:00:00 2001 From: Norbert Preining Date: Mon, 2 Sep 2019 13:46:59 +0900 Subject: Initial commit --- macros/latex/contrib/ocgx2/ChangeLog | 225 +++++ macros/latex/contrib/ocgx2/README.md | 283 ++++++ macros/latex/contrib/ocgx2/fixocgx.sty | 22 + macros/latex/contrib/ocgx2/ocgbase.sty | 351 ++++++++ macros/latex/contrib/ocgx2/ocgx2.sty | 1489 ++++++++++++++++++++++++++++++++ 5 files changed, 2370 insertions(+) create mode 100644 macros/latex/contrib/ocgx2/ChangeLog create mode 100644 macros/latex/contrib/ocgx2/README.md create mode 100644 macros/latex/contrib/ocgx2/fixocgx.sty create mode 100644 macros/latex/contrib/ocgx2/ocgbase.sty create mode 100644 macros/latex/contrib/ocgx2/ocgx2.sty (limited to 'macros/latex/contrib/ocgx2') diff --git a/macros/latex/contrib/ocgx2/ChangeLog b/macros/latex/contrib/ocgx2/ChangeLog new file mode 100644 index 0000000000..94f2402057 --- /dev/null +++ b/macros/latex/contrib/ocgx2/ChangeLog @@ -0,0 +1,225 @@ +2019-07-04 + * v0.43: ocgx2.sty + * v0.16: ocgbase.sty + * fix: ocmd-related refactoring; now, \ocgbase@insert@oc takes into account + open OCMD layers; + * new: OCMD visibility expressions also accept references to other ocmd + +2019-05-28 + * v0.42: ocgx2.sty + * new: `ocmd' TikZ style added; option `radiobtngrp' renamed to + `radiobtngrps' and accepting multiple RB group names passed as a + comma-separated list (`radiobtngrp' still available as an alias) + +2019-05-24 + * v0.41: ocgx2.sty + * v0.15: ocgbase.sty + * new: `ocmd' environment (PDF Optional content membership dictionary) + * fix: passing driver options to expl3 + +2019-01-02 + * v0.40: ocgx2.sty + * fix: merge request incorporated (latex3 end-of-2018 deprecations) + +2018-10-01 + * v0.39: ocgx2.sty + * fix: ocgcolorlinks: simpler and better link-colour-spill prevention + +2018-09-27 + * v0.38: ocgx2.sty + * fix: /ocglinkprotect{...} underfull box message and colour issue when + nested + +2018-09-25 + * v0.37: ocgx2.sty + * new: /tikz/trigger ocg={...} for various mouse triggers + +2018-06-27 + * v0.36: ocgx2.sty + * fix: code of previous fix simplified + +2018-06-26 + * v0.35: ocgx2.sty + * fix: wrong link size of clickable paths in scaled `tikzpicture' + +2018-06-07 + * v0.34: ocgx2.sty + * v0.14: ocgbase.sty + * fix: many cs now def'ed `protected'; adjustments after migration to GitLab + +2018-04-06 + * v0.33: ocgx2.sty + * v0.13: ocgbase.sty + * fix: documentation section in ocgbase.sty + +2017-09-29 + * v0.32: ocgx2.sty + * v0.12: ocgbase.sty + * fix: \ocglinkprotect improved + +2017-09-19 + * v0.31: ocgx2.sty + * fix: colour flooding caused by empty links with XeTeX driver and + `ocgcolorlinks' option + +2017-09-14 + * v0.30: ocgx2.sty + * v0.11: ocgbase.sty + * fix: link size (XeTeX driver) with `ocgcolorlinks' option set; + OCG switching links in Evince viewer now working; correct listing of + nested OCGs in layer tree (`Layers' navigation panel in the gui) + +2017-06-08 + * v0.29: ocgx2.sty + * fix: wrong box number in internal macro, ocgcolorlinks broken for dvips + +2017-06-07 + * v0.28: ocgx2.sty + * fix: hotfix from v0.27 replaced + +2017-06-07 + * v0.27: ocgx2.sty + * fix: hotfix to cope with a change of \hbox:n in expl3 [2017/05/13] + +2017-05-12 + * v0.26: ocgx2.sty + * fix: OCView, OCPrint (ocgcolorlinks related OCGs) settings saved for + possible re-opening by the user + +2017-04-25 + * v0.25: ocgx2.sty + * new:OCG switching links (\showocg, \hideocg etc.) with hyperref look + & feel if hyperref is loaded (link border or colorlinks/ocgcolorlinks) + +2017-03-30 + * v0.24: ocgx2.sty + * fix: \ocglinkprotect{...} messing up the graphics state (CTM) + +2017-03-30 + * v0.23: ocgx2.sty + * v0.10: ocgbase.sty + * fix: nested ocgcolorlinks over multiple pages + +2017-03-26 + * v0.22: ocgx2.sty + * fix: nested ocgcolorlinks + +2017-03-23 + * v0.21: ocgx2.sty + * v0.9: ocgbase.sty + * fix: error when building document with nested OCGs + * new: ocgcolorlinks extending over line and page breaks + +2017-03-16 + * v0.20: ocgx2.sty + * v0.8: ocgbase.sty + * fix: compatibility with other pkgs (pdfbase, xsavebox, media9, animate) + +2017-03-09 + * v0.19: ocgx2.sty + * v0.7: ocgbase.sty + * fix: minor code fixes + +2017-03-07 + * v0.18: ocgx2.sty + * fix: workaround for A-Reader bug when placing OCG switches on OCGs + +2016-03-22 + * v0.17: ocgx2.sty + * new: option `ocgcolorlinks', enables OCG colour links for hyperref package + +2016-03-11 + * v0.16: ocgx2.sty + * v0.6: ocgbase.sty + * fix: minor adjustments + +2016-01-29 + * v0.15: ocgx2.sty + * fix: adjusted `atendvi'-related warning message + +2015-12-07 + * v0.14: ocgx2.sty + * v0.5: ocgbase.sty + * fix: `0' and `1' could not be used for setting initial + visibility; \actionsocg macro caused compilation error when used + without optional argument + +2015-12-03 + * v0.13: ocgx2.sty + * fix: bug occasionally creating wrong OCG listing in the layers + tab of the pdf viewer in connection with nested OCGs + * new: parameter `opts' added to TikZ style `ocg' + +2015-11-26 + * v0.12: ocgx2.sty + * v0.4: ocgbase.sty + * fix: last argument of `ocg' environment (initial visibility) + had no effect when re-opening an OCG + +2015-11-23 + * v0.11: ocgx2.sty + * v0.3: ocgbase.sty + * new: PDF layers spanning multiple pages + +2015-11-02 + * v0.10: ocgx2.sty + * v0.2: ocgbase.sty + * new: commands \ocgbase@oc@bdc, \ocgbase_oc_bdc:n and \ocgbase@oc@emc, + \ocgbase_oc_emc: for marking optional content in content streams + +2015-10-28 + * v0.9: ocgx2.sty + * v0.1: ocgbase.sty + * new: Environment option `radiobtngrp' (adding layers to Radio Button + Groups), option `showingui' as a synonym for `listintoolbar'; + code restructured for better maintenance (new file ocgbase.sty) + +2015-09-11 + * v0.8 + * fix: missing option processing for ocg-p command replacements + (\toggleocgs, \showocgs etc.) + +2015-07-20 + * v0.7 + * fix: expl3-related adjustments + +2015-06-19 + * v0.6a + * fix: typos fixed + +2015-06-18 + * v0.6 + * new: package renamed to `ocgx2'; no more dependency on ocgx and ocg-p + packages + * new: options `viewocg', `printocg', `exportocg', `listintoolbar' also + available as package options + * new: package-only option `tikz' enables P. Gaborit's `ocgx' TikZ library + +2015-06-15 + * v0.5 + * Fix: OCG ID lists with leading/trailings spaces passed as + argument to the OCG visibilty setting commands caused an error; the same + with empty arguments. + Improved behaviour of visibilty setting links that are themselves + part of OCGs. + +2015-03-16 + * v0.4 + * Fix: no more PS specials from `ocg-p.sty' in dvipdfmx mode + +2015-03-11 + * v0.3 + * New: ocg environment option `viewocg=always|never|ifvisible' added; + macro \fxocg@insert@OC allows package authors to insert + /OC <> entries into (suitable) pdf objects, + i. e. XObjects & Annotations, to make them PDF-layer aware. + * Fix: dead tikz-generated ocg buttons (from tikzlibraryocgx.code.tex) with + dvipdfmx/xelatex + +2015-01-26 + * v0.2 + * Fix: It was not possible to reference an OCG before defining it. + +2015-01-23 + * v0.1 + * New: initial release as `fixocgx' diff --git a/macros/latex/contrib/ocgx2/README.md b/macros/latex/contrib/ocgx2/README.md new file mode 100644 index 0000000000..e8b100e0cd --- /dev/null +++ b/macros/latex/contrib/ocgx2/README.md @@ -0,0 +1,283 @@ +# The `ocgx2` LaTeX Package + +© 2015--`\today`, Alexander Grahn + +https://gitlab.com/agrahn/ocgx2 + +## Introduction + +This package serves as a drop-in replacement for the already existing packages +[**`ocgx`**](https://ctan.org/pkg/ocgx) by Paul Gaborit and +[**`ocg-p`**](https://ctan.org/pkg/ocg-p) by Werner Moshammer for the creation of PDF +Layers. + +It re-implements the functionality of the **`ocg`**, **`ocgx`** and **`ocg-p`** +packages and adds support for all known engines and back-ends including + +* LaTeX ⇒ dvips ⇒ ps2pdf/Distiller +* (Xe)LaTeX ⇒ (x)dvipdfmx +* pdfLaTeX, LuaLaTeX + +To enable dvipdfmx support, pass **`dvipdfmx`** globally as a class option. + +Also, it adds some features, improvements and bug fixes, such as package +options, remembering option settings of re-opened OCGs, correct behaviour of +layer switching links that were themselves placed on layers, correct listing +of (nested) OCGs in the "Layers" tab of PDF viewers, compatibility with the +`animate` and `media9` packages, a re-implementation of **`hyperref`**'s +**`ocgcolorlinks`** option. + +---- + +## New features + +* layers extending across **page breaks** +* **OCMD**s (Optional Content Membership Dictionaries) for creating layers with + complex visibility dependency +* grouping OCGs into **Radio Button Groups** (`ocg` environment option + **`radiobtngrps=...`**) +* additional keys for the TikZ interface of package `ocgx` +* re-implementing **`ocgcolorlinks`** option of package **`hyperref`** for links + that wrap around line and page breaks + +---- + +## Usage + +````latex +\usepackage[]{ocgx2} +```` + +````latex +\begin{ocg}[]{}{}{} + ... material to be put on a PDF layer ... +\end{ocg} +```` +`` is the name shown in the PDF viewer's "Layers" panel, +`` is an identifier used for referencing the layer elsewhere in the +document (e. g. layer switching buttons, visibility configuration of an `ocmd` +environment, re-opening the OCG at another place using the `ocg` environment). + +`` is `on`, `true`, `1` or `off`, `false`, `0`. + +````latex +\begin{ocmd}[]{[][,]} + ... material to be put on a PDF layer ... + visibility calculated by (Boolean expression) from + other OCGs visibility, or according to +\end{ocmd} +```` + +Package and `ocg` environment options: +````latex +viewocg = always | never | ifvisible +printocg = always | never | ifvisible +exportocg = always | never | ifvisible + +showingui = true | false +radiobtngrps = {[,[, ...]]} +tikz +ocgcolorlinks +```` + +**Options not in** `ocgx`, `ocg-p`: + +* `showingui` (to be preferred over `listintoolbar` of `ocgx/ocg-p`) +* `radiobtngrps = {, ...}` (comma-separated strings; environment-only + option) +* `tikz` (package-only option; enable TikZ styles, see below) +* `ocgcolorlinks` (package-only option, see below) + +Package options have global scope. Environment options override package options +locally. + +OCGs can be added to one or multiple **Radio Button Groups** using the new +option `radiobtngrps`. From all OCGs within a Radio Button Group only *one* +can be enabled at a time. Enabling an OCG, e. g. in the Layers tab of the PDF +viewer, automatically hides the previously visible OCG in the group. An OCG +can be added to multiple Radio Button Groups, passing a comma-separated list of +group names. This list must be enclosed in braces, `{...}`. + +`ocg` as well as `ocmd` environments can be nested and span multiple pages. + +See the +[`ocg-p` manual](http://mirrors.ctan.org/macros/latex/contrib/ocg-p/ocg-p.pdf#subsection.2.3) +about the `ocg` environment usage and the meaning of the remaining options. + +---- + +## The **`ocmd`** environment (Optional Content Membership Dictionary) + +````latex +\begin{ocmd}[]{[][,]} + ... material to be put on a PDF layer ... +\end{ocmd} +```` +This environment creates a PDF layer whose visibility is determined by the +current visibilities of other OCGs in the document according to at most one +visibility policy plus at most one visibility expression. If both are given +(with a comma in between) `` takes precedence over +``, but the latter may serve as a fallback in older PDF +viewers. + +`` is an optional identifier which can be used to re-open the same +layer with the same visibility setting at another place further down in the +document. + +A `` can be *one* of + +````latex +\AllOn{, , ...} +\AnyOn{, , ...} +\AnyOff{, , ...} +\AllOff{, , ...} +```` +All four directives take a list of OCG ids from wich the OCMD visibility is +calculated. If the condition represented by the policy is met, the content +associated with the OCMD is shown. The listed OCGs can be defined anywhere in +the document. These directives can neither be combined nor nested in order to +define the policy. Thus, a visibility policy has limited capabilities. + +A `` is much more flexible than a policy. Arbitrarily +complex visibility relationships can be formulated, based on the Boolean +functions + +````latex +\And{, , ...} +\Or{, , ...} +\Not{} +```` +In the argument list, items represent OCG/OCMD ids and nested Boolean +functions. As nesting of the three functions is possible, any thinkable +visibility relationship can be defined. Note that `\Not{...}` accepts only +one item, either an OCG/OCMD id or a nested function. Also note that Boolean +functions and policy directives cannot be intermixed. + +As a trivial example, the visibility expression equivalent of the policy +directive `\AllOff{...}` is written as `\Not{ \Or{ ... } }`. + +---- + +## Clickable links for switching PDF layer visibility + +These are the available commands: +````latex +\switchocg[]{}{} +\showocg[]{}{} +\hideocg[]{}{} +\actionsocg[]{}{}{}{} +```` +For details about their usage, read the +[`ocgx` manual](http://mirrors.ctan.org/macros/latex/contrib/ocgx/ocgx-manual-en.pdf#subsection.1.2). + +By default, links are triggered on mouse-click. Other triggers are possible +with `ocgx2`. For this, `ocgx2` provides the optional argument `[]` to +the commands listed above. Choose one of +````latex + onmousenter, onmouseexit, onmousedown, onmouseup, onmouseall +```` +for ``. In order to listen to more than one mouse event, use +`onmouseall`. OCG ids in the mandatory argument(s) must then be grouped with +commas as follows: +````latex + , , , +```` +Any of these groups may be left empty in order to configure only some +triggers. Inside the groups, OCG ids are separated by spaces. + +---- + +## Package option `ocgcolorlinks` + +Is a re-implementation of the same `hyperref` option for creating OCG- +coloured links, which are printed on paper in the default text colour. +````latex +\usepackage{hyperref} % do NOT set [ocgcolorlinks] here! +\usepackage[ocgcolorlinks]{ocgx2} +```` +Unlike the original `hyperref` implementation, OCG-coloured links are +now allowed to extend over **line** and **page breaks**. Moreover, with +pdfLaTeX/LuaLaTeX, OCG coloured links can be **nested**. + +Breakable OCG-coloured links work best with normal text as link text. If the +link text is mixed with graphical content, such as from external files or +inline graphics (e. g. TikZ) and even `\fbox`-ed text, these graphical parts +must be enclosed in +````latex +\ocglinkprotect{...} +```` +For example: +````latex +\href{http://ctan.org}{Visit me on \ocglinkprotect{\includegraphics{ctan-lion}}!} +```` + +---- + +## Usage with TikZ + +Package `ocgx2` uses code from file `tikzlibraryocgx.code.tex` by P. Gaborit to +enable TikZ styles for creating PDF Layers and clickable layer switching links +in the `tikzpicture` context. + +Just say: + +````latex +\usepackage[tikz]{ocgx2} +```` +instead of + +````latex +\usepackage{tikz} +\usetikzlibrary{ocgx} +```` +to enable these TikZ styles and read the +[`ocgx` manual](http://mirrors.ctan.org/macros/latex/contrib/ocgx/ocgx-manual-en.pdf#subsection.1.3) +about their usage. + +Package `ocgx2` adds the key `/tikz/ocg/opts` to the list in section "How to +add TikZ scopes into OCGs" in the `ocgx` manual: + +````latex +/tikz/ocg/opts={} +```` +It can be used inside the `ocg` style + +````latex +\begin{scope}[ + ocg={ref=..., name=..., opts={..., ...}}, + ... +] + ... +\end{scope} +```` +and allows passing `ocg`-environment options (`viewocg`, `printocg`, `exportocg`, +`showingui`, `radiobtngrps`) to the 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: + +````latex +\begin{scope}[ + ocmd={ref=..., visibility=...}, + ... +] + ... +\end{scope} +```` +Moreover, TikZ objects to be turned into OCG switching hyperlinks (section "How +to transform nodes or paths into clickable links" in the `ocgx` manual) accept +the additional key + +````latex +/tikz/trigger ocg = onmousenter | onmouseexit | onmousedown | onmouseup | onmouseall +```` +which makes them listen to various mouse events, as explained above. + +---- + +## License + +This material is subject to the [LaTeX Project Public License](http://mirrors.ctan.org/macros/latex/base/lppl.txt). + diff --git a/macros/latex/contrib/ocgx2/fixocgx.sty b/macros/latex/contrib/ocgx2/fixocgx.sty new file mode 100644 index 0000000000..256a71b2e0 --- /dev/null +++ b/macros/latex/contrib/ocgx2/fixocgx.sty @@ -0,0 +1,22 @@ +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% +% fixocgx.sty +% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\usepackage{expl3} + +\ExplSyntaxOn + +\msg_interrupt:nnn{Package~`fixocgx':}{ + This~package~is~obsolete~and~replaced~by~package~`ocgx2'.\\\\ + Remove\\\\ + \space\space\string\usepackage{ocgx}\\ + \space\space\string\usepackage{fixocgx}\\\\ + from~and~add\\\\ + \space\space\string\usepackage{ocgx2}\\\\ + to~the~document~preamble. +}{ + Read~the~manual~(`texdoc~ocgx2')~for~further~information. +} + +\ExplSyntaxOff diff --git a/macros/latex/contrib/ocgx2/ocgbase.sty b/macros/latex/contrib/ocgx2/ocgbase.sty new file mode 100644 index 0000000000..fd1abcfc3a --- /dev/null +++ b/macros/latex/contrib/ocgx2/ocgbase.sty @@ -0,0 +1,351 @@ +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% +% 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. + +%process non-detectable dvipdfmx driver for passing to expl3 +\RequirePackage{xkeyval} +\DeclareOptionX{dvipdfmx}{% + \PassOptionsToPackage{driver=dvipdfmx}{expl3} + \PassOptionsToPackage{dvipdfmx}{pdfbase} +} +\DeclareOptionX*{}\ProcessOptionsX*\relax %allow anything as an option + +\RequirePackage{pdfbase} +\RequirePackage{expl3} + +\def\g@ocgbase@date@tl{2019/07/04} +\def\g@ocgbase@version@tl{0.16} + +\ProvidesExplPackage{ocgbase}{\g@ocgbase@date@tl}{\g@ocgbase@version@tl} +{support package for ocgx2.sty} + +\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 + +\pbs_at_end_dvi:n{ + \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:} + } + \pbs_pdfcatalog:n{ + /OCProperties~<< + /OCGs~\l_ocgbase_ocgarray_tl + /D~<< + /AS~[ + <> + <> + <> + ] + /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} + +\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@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 diff --git a/macros/latex/contrib/ocgx2/ocgx2.sty b/macros/latex/contrib/ocgx2/ocgx2.sty new file mode 100644 index 0000000000..dd46efcfe5 --- /dev/null +++ b/macros/latex/contrib/ocgx2/ocgx2.sty @@ -0,0 +1,1489 @@ +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% +% 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. + +%process non-detectable dvipdfmx driver for passing to expl3 +\RequirePackage{xkeyval} +\DeclareOptionX{dvipdfmx}{% + \PassOptionsToPackage{dvipdfmx}{ocgbase} + \PassOptionsToPackage{driver=dvipdfmx}{expl3} +} +\DeclareOptionX*{}\ProcessOptionsX*\relax %allow anything as an option + +\RequirePackage{xparse} +\RequirePackage{l3keys2e} + +\def\g@ocgxii@date@tl{2019/07/04} +\def\g@ocgxii@version@tl{0.43} + +\ProvidesExplPackage{ocgx2}{\g@ocgxii@date@tl}{\g@ocgxii@version@tl} +{ports `ocgx' functionality to dvips+ps2pdf, xelatex and dvipdfmx} + +%creating global definitions +\cs_new_protected:Npn\ocgxii@newkey#1#2{\tl_gset:cx{#1}{#2}} +\cs_new_protected:Npn\ocgxii@newkeynoexp#1#2{\tl_gset:cn{#1}{#2}} + +\AtBeginDocument{ + \iow_now:Nx\@mainaux{ + \token_to_str:N\providecommand\token_to_str:N\ocgxii@newkey[2]{} + } + \iow_now:Nx\@mainaux{ + \token_to_str:N\providecommand\token_to_str:N\ocgxii@newkeynoexp[2]{} + } + \iow_now:Nx\@mainaux{ + \token_to_str:N\providecommand\token_to_str:N\ocgxii@ocg@stack@on@page[2]{} + } + \iow_now:Nx\@mainaux{ + \token_to_str:N\providecommand + \token_to_str:N\ocgxii@lnkcol@stack@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 = { + \PassOptionsToPackage{xetex}{pdfbase} + }, + + dvipdfmx .code:n = { + \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<>}}, + viewocg / never .code:n={ + \tl_gset:Nn\g_ocgxii_view_tl{/View<>}}, + 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<>}}, + printocg / never .code:n={ + \tl_gset:Nn\g_ocgxii_print_tl{/Print<>}}, + 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<>}}, + exportocg / never .code:n={ + \tl_gset:Nn\g_ocgxii_export_tl{/Export<>}}, + 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@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@ocg@stack@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@ocg@stack@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 + \pbs_pdfobj:nnn{}{dict}{/Type/OCMD\l_ocgxii_ocmd_visibility_tl} + %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.\pbs_pdflastobj:}{\l_ocgxii_ocmd_equiv_ve_tl} + \group_end: + \tl_set:Nx\l_ocgxii_cur_ocmd_tl{\pbs_pdflastobj:} + \tl_if_blank:oF{#1}{ + \tl_gset:cx{ocgxii_ocmd_#1}{\pbs_pdflastobj:} + \iow_now:Nn\@mainaux{\ocgxii@newkeynoexp{ocgx2.ocmd.#1}{#2}} + } + } + \ocgbase_open_stack_push:n{\l_ocgxii_cur_ocmd_tl} + \ocgxii_make_oc_entry: + \ocgxii_stack_shipout:NN\ocgxii@ocg@stack@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@ocg@stack@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~<>} + } + \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@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@ocg@stack@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@ocg@stack@on@page{0}{} %initialize + +\cs_new_protected_nopar:Npn\ocgxii@lnkcol@stack@on@page#1#2{ + \seq_gset_from_clist:cn{g_pending_lnkcols_on_#1_seq}{#2} + %re-add braces around items + \seq_map_inline:cn{g_pending_lnkcols_on_#1_seq}{ + \seq_gpop_left:cN{g_pending_lnkcols_on_#1_seq}\l_trash_tl + \seq_gput_right:cn{g_pending_lnkcols_on_#1_seq}{{##1}} + } +} +\ocgxii@lnkcol@stack@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@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:Nx\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@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:Nx\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 + \seq_set_split:NnV\l_ocgxii_ocglistarg_seq{~}\l_ocglistarg_tl + \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{ + \leavevmode + \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{ + \IfValueTF{#2}{#2}{onmouseup} + }{#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{ + \IfValueTF{#2}{#2}{onmouseup} + }{#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{ + \IfValueTF{#2}{#2}{onmouseup} + }{#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} + \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 + }{ + \bool_if:NTF\l_ocgxii_mouse_triggers_bool{ + % e,d,x mouse triggers require (non-breakable) /Widget annot with AA + % (additional actions) dict + /Subtype/Widget/Ff~65536/FT/Btn/BS<> + /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 <> + } + /AA << + %\str_if_eq:eeF{}{ % mouse-up + % \l_ocgxii_toswitch_u_tl\l_ocgxii_toshow_u_tl\l_ocgxii_tohide_u_tl + %}{ + % /U <> + %} + \str_if_eq:eeF{}{ % mouse-down + \l_ocgxii_toswitch_d_tl\l_ocgxii_toshow_d_tl\l_ocgxii_tohide_d_tl + }{ + /D <> + } + \str_if_eq:eeF{}{ % mouse-enter + \l_ocgxii_toswitch_e_tl\l_ocgxii_toshow_e_tl\l_ocgxii_tohide_e_tl + }{ + /E <> + } + \str_if_eq:eeF{}{ % mouse-exit + \l_ocgxii_toswitch_x_tl\l_ocgxii_toshow_x_tl\l_ocgxii_tohide_x_tl + }{ + /X <> + } + >> + }{ + %mouse-up alone may go with simple /Link annot + /Subtype/Link + /A <> + /Border~[0~0~0] + } + \cs_if_exist:NT\@pdfhighlight{ + \ifx\@pdfhighlight\@empty\else/H\@pdfhighlight\fi + } + }\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{ + /Subtype/Link + /A <> + %look and feel of hyperref links, if hyperref has been loaded + \cs_if_exist:NTF\Hy@setpdfborder{ + \Hy@setpdfborder\g_ocgxii_patch_tl + \ifx\@pdfhighlight\@empty\else/H\@pdfhighlight\fi + \ifx\@linkbordercolor\relax\else/C[\@linkbordercolor]\fi + \ifHy@pdfa /F~4\fi + }{ + /Border~[0~0~0] + } + }{ + \cs_if_exist:NTF\Hy@colorlink{ + \Hy@colorlink\@linkcolor#6\Hy@endcolorlink\Hy@VerboseLinkStop + }{#6} + } + } +} + +%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{ + \str_if_eq:eeF{#2}{}{ + \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<>}}, + viewocg / never .code:n={ + \tl_set:Nn\l_ocgxii_view_tl{/View<>}}, + 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<>}}, + printocg / never .code:n={ + \tl_set:Nn\l_ocgxii_print_tl{/Print<>}}, + 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<>}}, + exportocg / never .code:n={ + \tl_set:Nn\l_ocgxii_export_tl{/Export<>}}, + 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'. +} + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% patch hyperref to ensure compatibility with our `ocgcolorlinks' option +% +% Plus: +% +% * add `ocgcolorlinks' support to all drivers +% +% * allows for `ocgcolorlinks' extending 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 +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +\cs_new_protected_nopar:Nn\ocgxii_colourlink_begin:{} +\cs_new_protected_nopar:Nn\ocgxii_colourlink_end:{} +\cs_new_protected_nopar:Nn\ocgxii_colourlink_nobreak_begin:{ + \hbox_set:Nw\l_tmpa_box\color@begingroup + \tl_set_eq:NN\color@setgroup\group_begin: +} +\cs_new_protected_nopar:Nn\ocgxii_colourlink_nobreak_end:{ + \color@endgroup\hbox_set_end: + \mbox{ + \ocgbase_oc_bdc:n{\tl_use:c{ocgxii_ocg_OCPrint}} + \hbox_to_zero:n{\box_use:N\l_tmpa_box\hss} + \ocgbase_oc_emc: + \ocgbase_oc_bdc:n{\tl_use:c{ocgxii_ocg_OCView}} + \group_begin: + \exp_after:wN\HyColor@UseColor\l_ocgxii_lnkcol_tl + \box_use_drop:N\l_tmpa_box + \group_end: + \ocgbase_oc_emc: + } +} + +\seq_new:N\g_ocgxii_lnk_color_seq %stack of colours of currently open links +\tl_new:N\g_ocgxii_patch_tl % `BorderArrayPatch' for dvips + +%we'll be using the downscaled space character (32) from the pzdr +% (dingbats) font at the end of every ocgcolorlink in order to prevent +% empty links from flooding the page with link colour +\cs_new_nopar:Npn\ocgxii_tiny_space_char:{ + \group_begin: + \font\l_tmpa_tl=pzdr~scaled~1\l_tmpa_tl\char32 + \group_end: +} + +\bool_if:nTF{\sys_if_output_dvi_p: && !\g_ocgxii_dvipdfmx_bool}{ + % non-breakable links in dvips + \cs_new_protected_nopar:Nn\ocgxii_enable_ocglinks:{ + \def\Hy@colorlink##1{ + \group_begin: + \tl_set:Nn\l_ocgxii_lnkcol_tl{##1} + \ocgxii_colourlink_nobreak_begin: + } + \def\Hy@endcolorlink{ + \ocgxii_colourlink_nobreak_end: + \group_end: + } + } + \tl_gset:Nn\g_ocgxii_patch_tl{BorderArrayPatch} +}{ + % pdftex,luatex,xetex,dvipdfmx: + % ocgcolorlinks that extend over line and page breaks + \cs_new_protected_nopar:Nn\ocgxii_enable_ocglinks:{ + \def\Hy@colorlink##1{ + \ifx\Hy@setbreaklinks\@gobble\else + \Hy@breaklinkstrue + \fi + \ifHy@breaklinks + \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: + \seq_gpush:Nx\g_ocgxii_lnk_color_seq{{##1}} + \ocgxii_stack_shipout:NN\ocgxii@lnkcol@stack@on@page\g_ocgxii_lnk_color_seq + \else + \group_begin: + \tl_set:Nn\l_ocgxii_lnkcol_tl{##1} + \ocgxii_colourlink_nobreak_begin: + \fi + } + \def\Hy@endcolorlink{ + \ifHy@breaklinks + \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@lnkcol@stack@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: + } + \else + \ocgxii_colourlink_nobreak_end: + \group_end: + \fi + } + } + \bool_if:NT\l_ocgxii_ocgcolorlinks_bool{ + \cs_gset_nopar:Nn\ocgxii_colourlink_begin:{ + \pbs_literal:nn{page}{q~7~Tr} + } + \cs_gset_nopar:Nn\ocgxii_colourlink_end:{ + %a tiny space char should keep empty link annots from flooding the page + % with link colour + \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\HyColor@UseColor\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} + } + } +} + +% user command for protecting graphical content (external file, inline +% [e. g. TikZ], \fbox{...}) inside breakable ocgcolorlink +\bool_if:NTF\l_ocgxii_ocgcolorlinks_bool{ + \DeclareDocumentCommand\ocglinkprotect{m}{ + \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: + \tl_set_eq:NN\l_ocgxii_lnkcol_tl\l_tmpa_tl + \ocgxii_colourlink_nobreak_begin: + } + \group_begin: + \cs_set_nopar:Npn\ocglinkprotect##1{##1} % in case of nesting + \sys_if_output_pdf:TF{ + \leavevmode + \hbox_set:Nn\l_tmpb_box{#1} + \hbox_to_wd:nn{\box_wd:N\l_tmpb_box}{ + \vrule~width~\c_zero_dim~height~\box_ht:N\l_tmpb_box~ + depth~\box_dp:N\l_tmpb_box + \pbs_pdfxform:nnnnn{1}{0}{}{}{\l_tmpb_box} + \pbs_pdfrefxform:n{\pbs_pdflastxform:} + \hss + } + }{#1} + \group_end: + \seq_get_left:NNT\g_ocgxii_lnk_color_seq\l_tmpa_tl{ + \ocgxii_colourlink_nobreak_end: + \group_end: + \ocgxii_colourlink_begin: + } + } +}{ + \DeclareDocumentCommand\ocglinkprotect{m}{#1} +} + +% option ocgcolorlinks and beamer are not compatible +\bool_if:NT\l_ocgxii_ocgcolorlinks_bool{ + \@ifclassloaded{beamer}{ + \bool_set_false:N\l_ocgxii_ocgcolorlinks_bool + \hypersetup{colorlinks} + \msg_warning:nn{ocgx2}{beamer~and~ocgcolorlinks} + }{} +} + +\bool_if:NT\l_ocgxii_ocgcolorlinks_bool{ + \@ifpackageloaded{hyperref}{ + \Hy@colorlinkstrue + \AtBeginDocument{ + \ocgbase_new_ocg:nnn{OCView}{ + /Print<> + /Export<> + }{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<> + /Export<> + }{off} + \tl_gset:cx{ocgxii_ocg_OCPrint}{\ocgbase_last_ocg:} + \tl_gset:cx{ocgxii_ocg_OCPrint.opts}{ + showingui=never,printocg=always,exportocg=always} + \ocgxii_enable_ocglinks: + \iow_now:Nx\@mainaux{ + \token_to_str:N\ocgxii@newkey{ocgx2.ocg.OCView}{ + \tl_use:c{ocgxii_ocg_OCView}} + } + \iow_now:Nx\@mainaux{ + \token_to_str:N\ocgxii@newkey{ocgx2.ocg.OCPrint}{ + \tl_use:c{ocgxii_ocg_OCPrint}} + } + } + }{ + \msg_error:nnn{ocgx2}{missing~package}{hyperref} + } +} + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +% TikZ related code follows (to be enabled with package option `tikz') + +\bool_if:NF\l_ocgxii_tikz_bool{\endinput} +\cs_set_eq:NN\ocgxii@trmspc\tl_trim_spaces:N +\ExplSyntaxOff +\RequirePackage{tikz} +\usetikzlibrary{calc} + +% helper, replaces all spaces in #1 with `_' +\def\ocgxii@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@name, + opts/.store in=\ocgxii@opts, + visibility/.store in=\ocgxii@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}, + status/0/.style={visibility=0}, + % default values + name=, + opts=, % NEW + status=on, + % ref + ref/.style={ + /tikz/execute at begin scope={% + \begin{ocg}[\ocgxii@opts]{% + \ifx\empty\ocgxii@name\empty#1\else\ocgxii@name\fi% + }{#1}{\ocgxii@visibility}}, + /tikz/execute at end scope={\end{ocg}}, + } + }, + ocmd/.style={ + ocmd/.cd, + #1, + /tikz/execute at begin scope={% + \begin{ocmd}[\ocgxii@ocmdref]{\ocgxii@ocmdvisibility}% + }, + /tikz/execute at end scope={\end{ocmd}}, + /tikz/.cd + }, + ocmd={ + % parameters + ref/.store in=\ocgxii@ocmdref, + visibility/.store in=\ocgxii@ocmdvisibility, + % default values + ref=, + visibility=, + }, + trigger ocg/.store in=\ocgxii@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@trigger% + \switchocg*[\ocgxii@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@argone{#1}%ocg ref for checkmark + \ocgxii@trmspc\ocgxii@argone% + \global\let\ocgxii@argone\ocgxii@argone% + %default ocg ref for checkmark, if nothing provided in #1 + \xdef\ocgxii@argtwo{#2.mark}% + \xdef\ocgxii@argtwo{\ocgxii@cnvspc{\ocgxii@argtwo}}% + \begin{ocg}[showingui=false]{% + \ifx\ocgxii@argone\@empty\ocgxii@argtwo\else\ocgxii@argone\fi% + }{% + \ifx\ocgxii@argone\@empty\ocgxii@argtwo\else\ocgxii@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@argone\@empty\ocgxii@argtwo\else{\ocgxii@argone}\fi\space #2% + } + } + }, + switch ocg with mark off/.style 2 args={ + postaction={ + path picture={% + \edef\ocgxii@argone{#1}%ocg ref for checkmark + \ocgxii@trmspc\ocgxii@argone% + \global\let\ocgxii@argone\ocgxii@argone% + %default ocg ref for checkmark, if nothing provided in #1 + \xdef\ocgxii@argtwo{#2.mark}% + \xdef\ocgxii@argtwo{\ocgxii@cnvspc{\ocgxii@argtwo}}% + \begin{ocg}[showingui=false]{% + \ifx\ocgxii@argone\@empty\ocgxii@argtwo\else\ocgxii@argone\fi% + }{% + \ifx\ocgxii@argone\@empty\ocgxii@argtwo\else\ocgxii@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@argone\@empty\ocgxii@argtwo\else{\ocgxii@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@trigger% + \showocg*[\ocgxii@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@trigger% + \hideocg*[\ocgxii@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@trigger% + \actionsocg*[\ocgxii@trigger]{#1}{#2}{#3}{% + \tikz \useasboundingbox (p1) rectangle (p2);}% + \else% + \actionsocg*{#1}{#2}{#3}{% + \tikz \useasboundingbox (p1) rectangle (p2);}% + \fi% + }; + } + } + } +} -- cgit v1.2.3