# Automated overlay specification with \only and \enumerate

Sometimes, when a list of items is too long to fit on a slide, I do the following to achieve a somewhat better result (ignore commented lines for now):

\documentclass[t,10pt]{beamer}
\setbeamercovered{transparent}

\begin{document}
\begin{frame}
%\begin{itemize}[<+->] \item a \item b \end{itemize}
\begin{enumerate}
\only<1-2>{
%\item We agree that
\item<1>[1.] all men
\item<2>[2.] are
}\only<3->{
\item<3>[3.] equal
}
\end{enumerate}
\end{frame}
\end{document}


This produces:

Unfortunately this construction is not very robust, in a sense that upon uncommenting either or both of the commented lines, I will have to manually alter the numbering of the items and the overlay specifications.

Question: Is it possible to achieve the same result without any manual numbering or overlay specifying?

(Further comment: I attempted to resolve this, and this is about as far as I got:

\begin{enumerate}[<+->]
\only<.(1)-.(2)>{
\item All men
\item are
}\only<.(3)>{
\item[3.] equal
}
\end{enumerate}


Unfortunately, there are still a lot of magic numbers involved and I still have to count manually how many \itemss each \only contains. Apart from that, LaTeX will complain about a missing \item on slides where none of the \onlys is active

It would, for instance be extremely convenient to have a command \clearenumerate that produces the above with (probably with some heavy altering of the enumerate environment):

\begin{enumerate}[<+->]
\item all men
\item are
\clearenumerate
\item equal
\end{enumerate}


But I'm assuming such a thing, if possible, requires a lot of TeX/LaTeX mastery.)

-

Here's a solution that uses a feature of the onlyenv environment: it typesets its contents and then throws it away. This means that any assignments get carried out even if they don't get displayed. So by putting the first \items in an onlyenv environment, they increment their counters but (on the relevant slides) the actual text is ditched. Getting the \items in to an onlyenv environment is made easy by the action syntax of beamer. The tricky bit is getting the overlay specification right. Due to grouping, I had to use \gdef when I would really rather not have done which means that this probably isn't robust with regard to iterated lists, or to more than one list using it on the same frame (though it does work with lists on different frames). Maybe someone can improve on it a little.

Anyway, here's the code.

\documentclass[t,10pt]{beamer}
%\url{http://tex.stackexchange.com/q/25548/86}
\setbeamercovered{transparent}

\def\onlybetween{+-|only@\lbst-\lbend}
\makeatletter
\def\lbend{}
\def\lbst{1}
\newcounter{listbetween}
\def\startlistbetween{%
\setcounter{listbetween}{0}%
\gdef\lbst{1}%
\expandafter\ifx\csname listto\the\value{listbetween}\endcsname\relax
\gdef\lbend{}%
\else
\expandafter\global\expandafter\let\expandafter\lbend\csname listto\the\value{listbetween}\endcsname
\fi
\def\beamer@defaultospec{<\onlybetween>}%
}

\def\listbetween{%
\expandafter\xdef\csname listto\the\value{listbetween}\endcsname{\the\value{beamerpauses}}%
\xdef\lbst{\the\value{beamerpauses}}%
\stepcounter{listbetween}%
\expandafter\ifx\csname listto\the\value{listbetween}\endcsname\relax
\gdef\lbend{}%
\else
\expandafter\global\expandafter\let\expandafter\lbend\csname listto\the\value{listbetween}\endcsname
\fi
}
\makeatother

\begin{document}
\begin{frame}
\begin{enumerate}
\startlistbetween
\item first
\item second
\listbetween
\item third
\item fourth
\item fifth
\listbetween
\item sixth
\item seventh
\end{enumerate}
\end{frame}
\begin{frame}
\begin{enumerate}
\startlistbetween
\item first
\item second
\listbetween
\item third
\item fourth
\item fifth
\listbetween
\item sixth
\item seventh
\end{enumerate}
\end{frame}
\end{document}


The default overlay specification for the enumerate environment is held in the macro \beamer@defaultospec. Fortunately, for us, this is not expanded when it is read in. We can therefore embed a macro to be computed later. This is the macro which controls when the onlyenv is to stop actually printing its stuff. At the start, it is set to 1- which effectively means "always print" (note that this is in addition to the overlay specification which is +-, so both need to be satisfied for the item to display). As we go through the frame, we record where we want the breaks to be and store those in macros. On the second run through the frame (slide 2) then we use those macros to decide when the onlyenv bit takes effect.

So it works by using the fact that the contents of the frame are processed each time a new slide is produced. On the first run through (first slide) we make note of all the places where you want to break the list. Then on subsequent runs we use that information to control the display.

-
Very interesting, I'll take some time to understand what exactly you did. Unfortunately, that last restriction is precisely the reason I use the \only environment in the first place: I have too many items to fit on one slide without squeezing, yet they belong together and are grouped inside an example environment. –  Archibald Aug 12 '11 at 18:01
@Archibald: I thought that might be the case, but was waiting for confirmation before looking at it further. –  Andrew Stacey Aug 12 '11 at 18:59
@Archibald: Updated my answer. Not perfect yet, but on the way. –  Andrew Stacey Aug 12 '11 at 19:20
@Archibald: New version, should now be easy to use if there's only one list on the frame where you need this. –  Andrew Stacey Aug 14 '11 at 19:52
Wow, it works... Thank you! I don't fully understand how it works, to be honest, but I'll wait with asking questions until I finished the TeXbook. –  Archibald Aug 16 '11 at 7:11

One possible solution (perhaps not the most automated one), would be to use a command to store the value of the enumi counter and then use another command to set enumi to the stored value; using this approach you only have to issue the commands in the appropriate places:

\documentclass[t,10pt]{beamer}
\setbeamercovered{transparent}

\newcounter{mycntr}
\newcommand\savecntr{\setcounter{mycntr}{\theenumi}}
\newcommand\usecntr{\setcounter{enumi}{\themycntr}}

\begin{document}

\begin{frame}
\begin{enumerate}
\only<1-2>{
%\item We agree that
\item<1> all men
\item<2> are\savecntr
}\only<3->{\usecntr
\item<3> equal,
\item<4> or not?
}
\end{enumerate}
\end{frame}

\end{document}

-
Nice, that solves half of the problem, I guess! (Perhaps a command \myonly that works like \myonly<1-2> == \only<1-2>{\usecntr #1 \savecntr} (after some further fine-tuning of the \usecntr and \savecntr commands) would further leviate the task, I'll give it a try one of these days.) –  Archibald Aug 12 '11 at 18:04