如何编写无需 beamer 类即可工作的覆盖规范感知宏

如何编写无需 beamer 类即可工作的覆盖规范感知宏

LaTeXbeamer类提供了 和\newcommand<>接口\newenvironment<>,用于定义自己的命令,这些命令可以处理 beamer 的叠加规范。在内部,以这种方式定义的命令通常会使用其他 beamer 提供的叠加感知命令(例如\only<>\onslide<>)来实现所需的效果。

但是,如何编写一个包,使其与一起使用时能够提供覆盖感知的命令beamer,但也可以与其他文档类一起使用?

强力解决方案是定义每个命令两次,取决于它是否在 beamer 中使用:

\@ifclassloaded{beamer}{%
  % beamer
  \newcommand<>{\foo}[1]{\only#2{...}}
  \newcommand<>{\bar}[1]{... \onslide#2{...}}
}{%
  % other class
  \newcommand{\foo}[1]{...}
  \newcommand{\bar}[1]{...}
}

然而,我更喜欢一种仅模仿 beamer 类界面的方法,这样实际的宏定义就可以保持原样:

\@ifclassloaded{beamer}{%
  % beamer ==> do nothing
}{%
  % other class ==> provide beamer command mockups
  \def\newcommand ...
  \def\onslide ...
  \def\only ...
}

\newcommand<>{\foo}[1]{\only#2{...}}
\newcommand<>{\bar}[1]{... \onslide#2{...}}

有一个beamerarticle包旨在为 beamer 的文章模式提供这些命令(在下面的 MWE 中使用)。但是,它beamerarticle走得太远了,因为它还定义了命令,例如\frame\note和补丁,以及beamer基本上所有用于分段和列表的标准命令,这使得它与许多其他包和文档类不兼容。我正在寻找一种更轻量、侵入性更小的解决方案。

我还尝试单独加载beamerbaseoverlay子包,它似乎提供了 的定义\newcommand<>\only<>等等。但是,这个包不打算单独使用;我试图寻找它的依赖项,但在加载了六个额外的包却没有成功后放弃了。

还有其他想法吗?我忽略了什么软件包吗?

MWE 使用我目前正在编写的包中的一些真实代码来试用:

\documentclass{article}
\usepackage[T1]{fontenc}
\usepackage{listings}

% BEGIN package content
\makeatletter

  \@ifclassloaded{beamer}{}{
    \RequirePackage{beamerarticle} % <-- I would like to avoid this!
  }  
  \RequirePackage{tikz}

  % uses beamer's \only<> 
  \tikzset{onslide/.code args={<#1>#2}{%
    \only<#1>{\pgfkeysalso{#2}} 
  }}

  % uses beamer's \newenvironment<>, onlyenv
  \newenvironment<>{btHighlight}[1][]
  {\begin{onlyenv}#2\begingroup\tikzset{bt@Highlight@par/.style={#1}}\begin{lrbox}{\@tempboxa}}
  {\end{lrbox}\bt@HL@box[bt@Highlight@par]{\@tempboxa}\endgroup\end{onlyenv}}

  % uses beamer's \newcommand<>, \only<>
  \newcommand<>\btHL[1][]{%
    \only#2{\begin{btHighlight}[#1]\bgroup\aftergroup\bt@HL@endenv}%
  }
  \def\bt@HL@endenv{%
    \end{btHighlight}%   
    \egroup
  }
  \newcommand{\bt@HL@box}[2][]{%
    \begin{tikzpicture}[remember picture]%
      \pgfpathrectangle{\pgfpoint{1pt}{0pt}}{\pgfpoint{\wd #2}{\ht #2}}%
      \pgfusepath{use as bounding box}%
      \node[anchor=base west,  fill=orange!30,outer sep=0pt,inner xsep=1pt, inner ysep=0pt, rounded corners=3pt, minimum height=\ht\strutbox+1pt,#1]{\raisebox{1pt}{\strut}\strut\usebox{#2}};
    \end{tikzpicture}
  }

\makeatother
% END package content

\begin{document}

  \begin{lstlisting}[%
      language=C, numbers=left, gobble=4,
      moredelim={**[is][{\btHL[pin=30:The applications entry point, onslide=<2->{fill=red!50}]}]{@}{@}}%
    ]
    @int main (void)@ { 
      printf("Hello World!"); return 0;
    } 
  \end{lstlisting}

\end{document}

在此处输入图片描述

答案1

根据 beamer 手册,用 声明的命令\newcommand<>可以访问包含覆盖规范的额外参数;因此,作为一般原则,不可能编写一个可以在没有 beamer 的情况下不经更改而运行的覆盖感知命令。

然而,人们可以采取另一种方式,并且 Beamer 提供了一种现成的方法来做到这一点:

\newcommand\foo[2][]{...}
\renewcommand<>\foo[2][]{...\beameroriginal\foo...}

在更新的 中\foo,您可以使用\beameroriginal\foo来调用原始定义,甚至可以添加基于它构建的覆盖感知命令。将其放入 中,\@ifclassloaded您就可以开始了。

如果本身有这个功能,那将非常方便\renewcommand。但事实上它没有,并不意味着类比

\renewcommand<>\newcommand<>:: \renewcommand\newcommand

失败;它不是 的“覆盖感知”版本\renewcommand,并且不用于更新使用 创建的命令\newcommand<>;相反,它旨在更新使用 创建的命令以\newcommand使其表现仿佛它们是用 创建的\newcommand<>

相关内容