[Tex/LaTex] Frame Numbers in Beamer’s Article Mode

beamerbeamerarticlehookspage-numbering

I'm using the beamer package to create a presentation. Additionally I'd like to have a handout containing more information (as presentation slides should not contain much text). For this I use the article mode.

In order to allow my audience to take notes on their handouts, it would be helpful to have frame numbers on the handout. I accomplished this using the following code:

\mode<article>{
    \renewcommand{\frametitle}[1]{\subsubsection*{#1 [Slide \insertframenumber]}}
}

This works perfectly well unless you insert section start frames using

\AtBeginSection[] % nothing for \section*{}
{
    \begin{frame}
        \begin{center}
            \structure{\Huge \insertsection}
        \end{center}
    \end{frame}
}

The problem is that \AtBeginSection doesn't work in article mode. The additional frames are not inserted and thus the frame numbering gets wrong.

So I did the following to fix this:

\mode<article>{ % repair frame numbers in article mode as there are no section start frames
    \newcommand*\oldsectionmacro{}%
    \let\oldsectionmacro\section%
    \renewcommand*\section{%
    \addtocounter{framenumber}{1}\oldsectionmacro}%
}

This works unless there is a \section*. In this case the frame number is incremented but shouldn't as there is no section start frame. I could avoid using \section* but there are also some implicit ones (table of contents, bibliography, …).

Currently I correct this manually (see below) and it works for now but I don't like it. Is there a better way of doing so? Can I rewrite \section* or have an \AtBeginSection for article mode or insert the frame numbers in a different way?

Here is a small example to play around with:

\documentclass[a4paper]{scrartcl} % problem doesn't change if I use article instead
\usepackage{beamerarticle}
%\documentclass{beamer}

\usepackage[utf8]{inputenc}

\setbeamertemplate{footline}[frame number]

\mode<article>{
    % frame number in frametitle
    \renewcommand{\frametitle}[1]{\subsubsection*{#1 [Slide \insertframenumber]}}
}

% section start frame
% this has no effect in article mode
\AtBeginSection[] % nothing for \section*{}
{
    \begin{frame}
        \begin{center}
            \structure{\Huge \insertsection}
        \end{center}
    \end{frame}
}
\mode<article>{ % repair frame numbers in article mode as there are no section start frames
    \newcommand*\oldsectionmacro{}%
    \let\oldsectionmacro\section%
    \renewcommand*\section{%
    \addtocounter{framenumber}{1}\oldsectionmacro}%
%
%   \newcommand*\oldtocmacro{}%
%   \let\oldtocmacro\tableofcontents%
%   \renewcommand*\tableofcontents{%
%   \addtocounter{framenumber}{-1}\oldtocmacro}
}

\begin{document}

    \begin{frame}
        \tableofcontents
    \end{frame}

    \section{Section 1}

        \begin{frame}
            \frametitle{Frame A}

            Frame A
        \end{frame}

    \section{Section 2}
    %\section*{Section Star}

        \begin{frame}
            \frametitle{Frame B}

            Frame B
        \end{frame}

\end{document}

Best Answer

In my opinion, the cleanest approach here is to make \AtBeginSection work in a beamerarticle. The reason why it doesn't is that the \AtBeginSection macro works by defining hooks to be executed at the beginning of theses sections. In article mode, however, the \section macro as defined by the document class is used, so these hooks are never executed.

To overcome this, a redefinition of the \section macro is necessary. This is a bit complicated because it calls \@startsection internally, so simply adding the hook to the end of the macro won't work. Instead, a complete "wrapper" around the original command is necessary:

\mode<article>
\usepackage{xparse}
\makeatletter
\expandafter\let\expandafter\originalsection\expandafter=\csname @orig\string\section\endcsname
\RenewDocumentCommand{\section}{ D<>{} s o m }
{
  \alt<#1>
  {
    \IfBooleanTF {#2}
    {
      \originalsection*{#4}
      %\beamer@atbeginsections % breaks because section* is also used e.g. in the TOC
    }
    {
      \IfNoValueTF {#3} { \originalsection{#4} } { \originalsection[#3]{#4} }
      \beamer@atbeginsection
    }
  }
  {
    \beamer@secgobble
  }
}
\makeatother
\mode<all>

Insert this code into the preamble of your document, after having loaded beamerarticle. What it does is to save the original, beamer-free meaning of the \section macro stored in the macro with the "weird" name @orig\section to \originalsection. Afterwards, \section is redefined to execute the original sectioning command and the hook \beamer@atbeginsection afterwards. As \section has a starred and non-starred version, an optional argument and an (optional) overlay specification, I used xparse which allows you to define such macros in a very convenient way.

Now you can use \AtBeginSection as usual to insert the section start frames. As you probably don't want them to actually show up in article mode, you should use \begin{frame}<article:0> for these (the frame number is still incremented). Additionally, you need to \def\insertsection{} because this command is unknown to beamerarticle and would result in an error otherwise.

Note that using the optional argument of \AtBeginSection to define a hook for starred sections won't work (the line executing it is commented out in the above code). The reason is that \section* is also used for the table of contents etc., where such inserts would result in an error message.

Output of your MWE using the above code

In presentation mode (click on the image to see it full-size):

five frames in presentation mode

In article mode:

beamerarticle with the correct frame numbers

For completeness, the full source that produced the above results can be found on pastebin.com.

Edit: The xparse package I used to redefine \section relies on the experimental LaTeX3 kernel. If it is not available, you can use this plain LaTeX2e solution instead:

\mode<article>
\makeatletter
\expandafter\let\expandafter\originalsection\expandafter=\csname @orig\string\section\endcsname
\def\sectionwithhook{\@ifstar\@sectionwithhook\@@sectionwithhook}
\newcommand{\@sectionwithhook}[1]{\originalsection*{#1}}
\newcommand{\@@sectionwithhook}[2][]{\beamer@ifempty{#1}{\originalsection{#2}}{\originalsection[#1]{#2}}\beamer@atbeginsection}
\renewcommand<>{\section}{\alt#1{\sectionwithhook}{\beamer@secgobble}}
\makeatother
\mode<all>

This replaces the whole code given above, achieving the same as the \RenewDocumentCommand with some helper macros.