Noframenumbering in Metropolis’ standout frames

beamerbeamer-metropoliskey-value

I would like to make it optional to exclude the standout frames from the beamer theme Metropolis from the frame count. This works as long as I write my frame options as noframenumbering, standout. But if I reverse the order and write standout, noframenumbering then I get an error

Package keyval Error: noframenumbering undefined. [  \end{frame}]

in my MWE (below). What should I do to allow both orders?

\documentclass{beamer}
% Standout frame code from [Metropolis' inner theme](https://github.com/matze/mtheme/blob/master/source/beamerinnerthememetropolis.dtx)
\usepackage{keyval}
\makeatletter
\define@key{beamerframe}{c}[true]{% centered
  \beamer@frametopskip=0pt plus 1fill\relax%
  \beamer@framebottomskip=0pt plus 1fill\relax%
  \beamer@frametopskipautobreak=0pt plus .4\paperheight\relax%
  \beamer@framebottomskipautobreak=0pt plus .6\paperheight\relax%
  \def\beamer@initfirstlineunskip{}%
}
\providebool{metropolis@standout}
\define@key{beamerframe}{standout}[true]{%
  \booltrue{metropolis@standout}
  \begingroup
    \setkeys{beamerframe}{c}
    \setbeamertemplate{frame numbering}{}
    % \setkeys{beamerframe}{noframenumbering}
    \ifbeamercolorempty[bg]{palette primary}{
      \setbeamercolor{background canvas}{
        use=palette primary,
        bg=-palette primary.fg
      }
    }{
      \setbeamercolor{background canvas}{
        use=palette primary,
        bg=palette primary.bg
      }
    }
  \centering
  \usebeamercolor[fg]{palette primary}
  \usebeamerfont{standout}
}
\pretocmd{\beamer@reseteecodes}{%
  \ifbool{metropolis@standout}{
    \endgroup
    \boolfalse{metropolis@standout}
  }{}
}{}{}
\makeatother
\begin{document}
  \begin{frame}[standout]
    standout
  \end{frame}

  \begin{frame}[noframenumbering, standout]
    noframenumbering, standout
  \end{frame}

  % This frame produces the error message
  \begin{frame}[standout, noframenumbering]
    standout, noframenumbering
  \end{frame}
\end{document}

Best Answer

This answer was only possible due to the kind help of @samcarter!

The issue is that \setbeamercolor uses \setkeys internally, and keyval's \setkeys can't be nested, if you nest them the key prefix of the inner call is used for the remainder of the outer call, so noframenumbering isn't parsed as part of beamerframe, but beamerthc (which is used internally by \setbeamercolor).

To fix this you have two fundamentally different approaches:

  1. Don't use \setbeamercolor but the internals this would call directly. (approach taken by @samcarter, could theoretically break if beamer changed its own internals)
  2. Fix \setkeys to be nestable. (general fix for keyval, shouldn't have evil side effects, but theoretically could if some code relies on this limitation of \setkeys)

Using internals of \setbeamercolor

\documentclass{beamer}

% Standout frame code from [Metropolis' inner theme](https://github.com/matze/mtheme/blob/master/source/beamerinnerthememetropolis.dtx)
%\usepackage{keyval}
\makeatletter
\define@key{beamerframe}{c}[true]{% centered
  \beamer@frametopskip=0pt plus 1fill\relax%
  \beamer@framebottomskip=0pt plus 1fill\relax%
  \beamer@frametopskipautobreak=0pt plus .4\paperheight\relax%
  \beamer@framebottomskipautobreak=0pt plus .6\paperheight\relax%
  \def\beamer@initfirstlineunskip{}%
}
\providebool{metropolis@standout}
\define@key{beamerframe}{standout}[true]{%
  \booltrue{metropolis@standout}%
  \begingroup
    \setkeys{beamerframe}{c}%
    \setbeamertemplate{frame numbering}{}%
    % \setkeys{beamerframe}{noframenumbering}%
    \def\beamer@temp{background canvas}%
    \expandafter\def\csname beamer@thcuse@\beamer@temp\endcsname{%
        \@for\@temp:={palette primary}\do{\expandafter\beamer@thc@usecolor\expandafter{\@temp}}}%
    \ifbeamercolorempty[bg]{palette primary}{%
       \expandafter\def\csname beamer@thcbg@\beamer@temp\endcsname{\def\beamer@thc@bg{-palette primary.fg}}%
    }{%
       \expandafter\def\csname beamer@thcbg@\beamer@temp\endcsname{\def\beamer@thc@bg{palette primary.bg}}%
    }%
  \centering
  \usebeamercolor[fg]{palette primary}%
  \usebeamerfont{standout}%
}
\pretocmd{\beamer@reseteecodes}{%
  \ifbool{metropolis@standout}{%
    \endgroup
    \boolfalse{metropolis@standout}%
  }{}%
}{}{}
\makeatother

\begin{document}
  \begin{frame}[standout]
    standout
  \end{frame}

  \begin{frame}[noframenumbering, standout]
    noframenumbering, standout
  \end{frame}

  % This frame produces the error message
  \begin{frame}[standout, noframenumbering]
    standout, noframenumbering
  \end{frame}
  
  \begin{frame}
  content...
  \insertframenumber
  \end{frame}
\end{document}

Patching \setkeys

\documentclass{beamer}
% Standout frame code from [Metropolis' inner theme](https://github.com/matze/mtheme/blob/master/source/beamerinnerthememetropolis.dtx)
%\usepackage{keyval} % loaded by beamer

\makeatletter
% patch \setkeys to be nestable:
\NewCommandCopy\my@setkeys@orig\setkeys
\def\setkeys{\expandafter\my@setkeys@aux\expandafter{\KV@prefix}}
\long\def\my@setkeys@aux#1#2#3{\my@setkeys@orig{#2}{#3}\def\KV@prefix{#1}}

\define@key{beamerframe}{c}[true]{% centered
  \beamer@frametopskip=0pt plus 1fill\relax
  \beamer@framebottomskip=0pt plus 1fill\relax
  \beamer@frametopskipautobreak=0pt plus .4\paperheight\relax
  \beamer@framebottomskipautobreak=0pt plus .6\paperheight\relax
  \def\beamer@initfirstlineunskip{}%
}
\providebool{metropolis@standout}
\let\KV@beamerframe@cx\KV@beamerframe@c
\let\KV@beamerframe@cx@default\KV@beamerframe@c@default
\define@key{beamerframe}{standout}[true]{%
  \booltrue{metropolis@standout}%
  \begingroup
    \setkeys{beamerframe}{cx}%
    \setbeamertemplate{frame numbering}{}%
    % \setkeys{beamerframe}{noframenumbering}%
    \ifbeamercolorempty[bg]{palette primary}{%
      \setbeamercolor{unrelated beamer color}{%
        use=palette primary,
        bg=-palette primary.fg
      }%
    }{%
      \setbeamercolor{unrelated beamer color}{%
        use=palette primary,
        bg=palette primary.bg
      }%
    }%
  \centering
  \usebeamercolor[fg]{palette primary}%
  \usebeamerfont{standout}%
}
\pretocmd{\beamer@reseteecodes}{%
  \ifbool{metropolis@standout}{%
    \endgroup
    \boolfalse{metropolis@standout}%
  }{}%
}{}{}
\makeatother

\begin{document}
  \begin{frame}[standout]
    standout
  \end{frame}

  \makeatletter
  \begin{frame}[noframenumbering, standout]
    noframenumbering, standout
  \end{frame}

  % This frame produces the error message
  \begin{frame}[standout, noframenumbering]
      %\show\KV@beamerframe@noframenumbering
    standout, noframenumbering
  \end{frame}

  \begin{frame}
    normal
    \insertframenumber
  \end{frame}
\end{document}
Related Question