[Tex/LaTex] Re-cover Beamer overlays, while keeping a subphrase uncovered

beameroverlaystransparency

Original question

In a Beamer presentation that I am writing, I have an itemize list and would like to make each item visible one-by-one. Then, starting on the slide after a given item appears, I would like that item to be re-covered in a transparent way. This is easy enough to accomplish using again covered with \setbeamercovered:

\documentclass{beamer}
\setbeamercovered{again covered={\opaqueness<1->{25}}}
\begin{document}
\begin{frame}{Frame Title}
  \begin{itemize}[<+>]
  \item Who's on first
  \item What's on second
  \item I don't know's on third
  \end{itemize}
  \uncover<+->{-- Abbott and Costello}
\end{frame}
\end{document}

But here's the twist: I would like to modify the above example so that, once uncovered, the words 'Who', 'What', 'I don't know' remain uncovered even after their respective \items are re-covered. The following code tries three different ways to make this work:

\documentclass{beamer}
\setbeamercovered{again covered={\opaqueness<1->{25}}}
\begin{document}
\begin{frame}{Frame Title}
  \begin{itemize}[<+>]
  \item \uncover<.->{Who}'s on first
  \item {\color<.->{black} What}'s on second
  \item<+-> I don't know\uncover<.>{'s on third}
  \end{itemize}
  \uncover<+->{-- Abbott and Costello}
\end{frame}
\end{document}

enter image description here

The first two attempts do not work at all. The third attempt is closer, but still not quite right: I want the triangular item marker to be transparent whenever 's on third is re-covered.

So, my question is: How can I cleanly and correctly keep certain subphrases uncovered even when the surrounding context is re-covered?

There might be a way to hook into the item marker and make it transparent, but I would like to avoid this; I will be using an answer with inference rules (set with the lkproof package) for which such hooks would be difficult to create (because of my limited TeX knowledge).

Revised question

@alexurba's answer is useful and almost, but not quite, does what I need. First, I've slightly modified his suggestion:

\newcommand<>{\myuncover}[1]{%
  \alt#2{\mbox{\beamer@endcovered #1}}{\mbox{#1}}}

By using \alt and \mbox rather than using \only and \makebox[0pt][r], we can avoid over-printing the text #1.

Yet this command interacts poorly with \color, as the following example shows:

\documentclass{beamer}
\setbeamercovered{again covered={\opaqueness<1->{25}}}

\makeatletter
\newcommand<>{\alexurbauncover}[1]{%
  #1\only#2{\makebox[0pt][r]{\beamer@endcovered #1}}}

\newcommand<>{\myuncover}[1]{%
  \alt#2{\mbox{\beamer@endcovered #1}}{\mbox{#1}}}
\makeatother

\begin{document}
\begin{frame}{Frame Title}
  \begin{itemize}[<+>]
  \item Who's on {\color{structure} first}
  \item \myuncover<.->{What}'s on {\color{structure} second}
  \item \alexurbauncover<.->{I don't know}'s on {\color{structure} third}
  \end{itemize}
  \uncover<+>{-- Abbott and Costello}
\end{frame}
\end{document}

enter image description here

The first bullet shows an ordinary \uncover and re-cover, which makes the structure-colored text appropriately transparent when re-covered. The second bullet shows that the revised \myuncover command somehow breaks this treatment of the structure-colored text: it stays completely opaque when re-covered. The third bullet shows that this behavior wasn't inadvertantly introduced by my revisions to @alexurba's original \myuncover.

So, my revised question is: How can I have something like the above \myuncover that correctly respects the \color switch in re-covered text?

Attempted solution

From what I can tell, in the above \myuncover, the \mbox appears to serve to delimit the scope of \beamer@endcovered. Another idea is to end and then restart the covering behavior, such as with

\newcommand<>{\myuncover}[1]{%
  \alt#2{\beamer@endcovered #1\beamer@startcovered}{#1}}

However, this command doesn't work the way I would have liked:

\documentclass{beamer}
\setbeamercovered{again covered={\opaqueness<1->{25}}}

\makeatletter
\newcommand<>{\myuncover}[1]{%
  \alt#2{\beamer@endcovered #1\beamer@startcovered}{#1}}
\makeatother

\begin{document}
\begin{frame}{Frame Title}
  \begin{itemize}[<+>]
  \item \myuncover<.->{Who}'s on {\color{structure} first}
  \item \myuncover<.->{What}'s on {\color{structure} second}
  \item \myuncover<.->{I don't know}'s on {\color{structure} third}
  \end{itemize}
  \uncover<+>{-- Abbott and Costello}
\end{frame}
\end{document}

enter image description here

My guess is that \beamer@startcovered is preventing Beamer from recognizing that 's on first etc. is being re-covered, and therefore the again covered does not kick in at the right point. But that's just a guess since I don't understand exactly how \beamer@startcovered works.

Best Answer

Edit 5

Following the OP's suggestion an alternative solution is to interrupt the covering and restart it (in contrast to locally uncovering the text). This could be done with the following macro:

\newcommand<>{\myinterruptcover}[1]{%
  \expandafter\ifx%
    \csname beamer@doafter\the\beamer@coveringdepth\endcsname\relax
  #1%
  \else
  \alt#2{\beamer@endcovered #1\beamer@startcovered}{#1}%
  \fi
}

The conditional checks if we currently are in a covered region, i.e. if \beamer@doafter<N> (see below) is defined.

I still prefer the \myuncover macro, because it just locally undoes the color change of the covering.

Edit 4

@Henry DeYoung asked for an explanation of how I came up with the macro. I added a rather longish one below.

Edit 3

After some more digging in the beamer sources I came up with the following, which also keeps the structure color (by using local color definitions):

\documentclass{beamer}

\makeatletter
\newcommand{\my@endcovered}{%
  % check if \beamer@doafterN is different from \relax
  % where N is the current covering level
  \expandafter\ifx%
    \csname beamer@doafter\the\beamer@coveringdepth\endcsname\relax
  \else
  % reset the color hook, but only locally
  % -- in the 'real' \beamer@doafter the global \xdef is used 
  %    instead of \edef
  \edef\beamer@colorhook{%
    \csname beamer@oldcolorhook\the\beamer@coveringdepth\endcsname}%
  % I think the following is not needed here, though I don't really
  % know what effect it has
  % \edef\beamer@pgfextension{%
  %  \csname beamer@oldpgfextension\the\beamer@coveringdepth\endcsname}%
  % finally, set colors
  \color{.}%
  \fi%
}%
\newcommand<>{\myuncover}[1]{\alt#2{{\my@endcovered #1}}{#1}}
\makeatother

\setbeamercovered{again covered={\opaqueness<1->{25}}}

\begin{document}
\begin{frame}{Frame Title}
  \begin{itemize}[<+>]
  \item \myuncover<.->{Who}'s on {\color{structure} first}
  \item \myuncover<.->{What}'s on {\color{structure} second}
  \item \myuncover<.->{I don't know}'s on {\color{structure} third}
  \end{itemize}
  \uncover<+>{-- Abbott and Costello}
\end{frame}
\end{document}

enter image description here

I think that solves all the problems.

Explanation

The beamer command \uncover (like all commands related to overlay features) is defined in beamerbaseoverlay.sty as

\newcommand{\uncover}{\alt{\beamer@fakeinvisible}{\beamer@makecovered}}

so that \beamer@makecovered is triggered when the overlay specification matches. That macro, in turn, is defined at the same place as

\long\def\beamer@makecovered#1{\beamer@startcovered#1\beamer@endcovered}

which is why I first suggested to locally use \beamer@endcovered to end the covering. However, \beamer@endcovered has some undesired global effects, so it is necessary to go one level deeper. Looking at the macro definition

\def\beamer@endcovered{%
  \beamer@smuggle{%
  \csname beamer@doafter\the\beamer@coveringdepth\endcsname%
  \global\advance\beamer@coveringdepth by -1\relax%
  }%
}%

we see that \beamer@endcovered basically expands to \beamer@doafter<N>, where <N> is the current value of the counter \beamer@coveringdepth, which keeps track of the covering level. Finally, that counter is decreased by 1. As a comment in the sources says, \beamer@smuggle is used to "smuggle skips past", and I decided to ignore this one for the moment (if anyone reads this who knows better, please correct me).

Now it is getting a bit more complicated: every \beamer@doafter<N> has a corresponding \beamer@do. Both macros are defined by \beamer@actions

\def\beamer@actions#1#2{%
  \gdef\beamer@do{#1%
    \expandafter\gdef\csname beamer@doafter%
    \the\beamer@coveringdepth\endcsname{#2}}}

which is executed in \beamer@startcovered. As you can see, actually the doafter macro is defined when the do macro is expanded. The relevant piece of code from \beamer@starcovered is in the definition of \opaqueness:

\def\opaqueness<##1>##2{%
\only<##1>{%
  \beamer@actions{%
    \expandafter\xdef\csname beamer@oldcolorhook%
    \the\beamer@coveringdepth\endcsname{\beamer@colorhook}%
    \expandafter\xdef\csname beamer@oldpgfextension%
    \the\beamer@coveringdepth\endcsname{\beamer@pgfextension}%
    {\globalcolorstrue\colorlet{beamer@freeze\the\beamer@coveringdepth}{bg}}%
    \xdef\beamer@colorhook{!##2!beamer@freeze%
      \the\beamer@coveringdepth\beamer@colorhook}%
    \gdef\beamer@pgfextension{!##2opaque}%
    \color{.}%
  }%
  {%
    \xdef\beamer@colorhook{\csname beamer@oldcolorhook%
      \the\beamer@coveringdepth\endcsname}%
    \xdef\beamer@pgfextension{\csname beamer@oldpgfextension%
      \the\beamer@coveringdepth\endcsname}%
    \color{.}%
  }}}%

Here, the \beamer@actions is called, if the overlay specification matches. The macros \beamer@do and \beamer@doafter<N> are then set to the arguments. Now it is obvious that the \beamer@do macro is responsible for setting the color of the covered object (which depends on the user settings). The previous color hook is saved to a macro named \beamer@oldcolorhook<N>, where <N> again is the covering level. Exactly this color hook is then restored when \beamer@doafter is expanded:

    \xdef\beamer@colorhook{\csname beamer@oldcolorhook%
      \the\beamer@coveringdepth\endcsname}%
    \xdef\beamer@pgfextension{\csname beamer@oldpgfextension%
      \the\beamer@coveringdepth\endcsname}%
    \color{.}%

and those are just the lines of code we were after. I simply replaced the global \xdef by the local \gdef to limit the scope of the color redefinition.

Finally just one bit is missing: as mentioned above this definition of \beamer@doafter is only true if the overlay specification (of \only) in \opaqueness is matched. If that is not the case, the macro does not do anything and is equal to \relax. So my macro checks if \beamer@doafter is equal to \relax in which case it also does nothing.


Edit 2

Now this should really yield the desired result:

\documentclass{beamer}
\setbeamercovered{again covered={\opaqueness<1->{25}}}
\makeatletter
\newcommand*{\myuncover}[1]{%
#1\only<.->{\makebox[0pt][r]{\beamer@endcovered #1}}%
}
\makeatother
\begin{document}
\begin{frame}{Frame Title}
  \begin{itemize}[<+>]
  \item \myuncover{Who}'s on first
  \item \myuncover{What}'s on second
  \item \myuncover{I don't know}'s on third
  \end{itemize}
  \uncover<+>{-- Abbott and Costello}
\end{frame}
\end{document}

enter image description here