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<>
。