[Tex/LaTex] Setting colour of beamer itemize bullet depending on alert mode

beamercoloritemizelists

I know how to globally set the colour of beamer's itemize bullets. I've defined my own symbols for them and I'd like to colour them in \alert mode. (At the moment only the colour of the text changes, but not the colour of the bullets.)

At the moment I'm using the following definition for the "bullets":

\setbeamertemplate{itemize        item}{\CorkSquare[size=0.18,linewidth=0.70pt]}
\setbeamertemplate{itemize     subitem}{\CorkSquare[size=0.16,linewidth=0.67pt]}
\setbeamertemplate{itemize  subsubitem}{\CorkSquare[size=0.14,linewidth=0.65pt]}
\def\CorkSquare[size=#1,linewidth=#2]{%
    \begin{tikzpicture}
    \draw[use as bounding box]
         (+0.75*#1,-0.15*#1)
         (+0.80*#1,+0.75*#1)
         (+0.75*#1,-0.15*#1);
    \filldraw[line width=#2,draw=cork@colour@normal,fill=cork@colour@normal!19!white]
             (0,0) rectangle (#1,#1);
    \end{tikzpicture}%
}

Any help would be greatly appreciated.

Best Answer

This assumes you can use an action specification (that is, you want to highlight the entire \item and not just a part of it). Normally the action specification works like \item<1-|alert@1> text which will show the item from slide 1 onwards and highlights it only on slide 1. What we can do is define our own version of alert to change the itemize item for that specific item and then perform the normal alert as well. This is done by creating a new environment <actionname>env. So to get a myalert action we define the myalertenv environment. We can do this as follows:

\newenvironment{myalertenv}{\only{\setbeamertemplate{itemize item}{\def\mycolor{red}\CorkSquare[size=0.18,linewidth=0.70pt]}}\alertenv}{\endalertenv}

Since I don't know the definition of your cork@colour@normal I change the code a bit to use the \mycolor command. You can just modify it to use what you want. The full code would look like this:

\documentclass{beamer}
\usepackage{tikz}
\begin{document}
  \setbeamertemplate{itemize        item}{\CorkSquare[size=0.18,linewidth=0.70pt]}
\setbeamertemplate{itemize     subitem}{\CorkSquare[size=0.16,linewidth=0.67pt]}
\setbeamertemplate{itemize  subsubitem}{\CorkSquare[size=0.14,linewidth=0.65pt]}
\def\mycolor{blue}
\def\CorkSquare[size=#1,linewidth=#2]{%
    \begin{tikzpicture}
    \draw[use as bounding box]
         (+0.75*#1,-0.15*#1)
         (+0.80*#1,+0.75*#1)
         (+0.75*#1,-0.15*#1);
    \filldraw[line width=#2,draw=\mycolor,fill=\mycolor!19!white]
             (0,0) rectangle (#1,#1);
    \end{tikzpicture}%
}
\newenvironment{myalertenv}{\only{\setbeamertemplate{itemize item}{\def\mycolor{red}\CorkSquare[size=0.18,linewidth=0.70pt]}}\alertenv}{\endalertenv}
\begin{frame}
  \begin{itemize}
    \item<1-> test
    \item<2-|myalert@2> test
  \end{itemize}
\end{frame}
\end{document}

Edit: By the way, you should realyl consider changing your \CorkSquare command to just \def\CorkSquare[#1,#2]. Then you can use #1 as the size and put #2 in the options to \filldraw. right now you can also just put , other options behind the linewidth=... but that looks a bit strange when you call it and it would require you to change the order because otherwise draw and fillcolor would be overwritten. This way you would not need the \mycolor construct. Your code would then become the following, which I believe to be a bit cleaner.

\documentclass{beamer}
\usepackage{tikz}
\begin{document}
  \setbeamertemplate{itemize        item}{\CorkSquare[size=0.18,line width=0.70pt]}
\setbeamertemplate{itemize     subitem}{\CorkSquare[size=0.16,line width=0.67pt]}
\setbeamertemplate{itemize  subsubitem}{\CorkSquare[size=0.14,line width=0.65pt]}
\def\CorkSquare[size=#1,#2]{%
    \begin{tikzpicture}
    \draw[use as bounding box]
         (+0.75*#1,-0.15*#1)
         (+0.80*#1,+0.75*#1)
         (+0.75*#1,-0.15*#1);
    \filldraw[draw=blue,fill=blue!19!white,#2]
             (0,0) rectangle (#1,#1);
    \end{tikzpicture}%
}
\newenvironment{myalertenv}{\only{\setbeamertemplate{itemize item}{\CorkSquare[size=0.18,line width=0.70pt,draw=red,fill=red!19!white]}}\alertenv}{\endalertenv}
\begin{frame}
  \begin{itemize}
    \item<1-> test
    \item<2-|myalert@2> test
  \end{itemize}
\end{frame}
\end{document}

Edit: After your comment that there was an issue when multiple frames have an alert specification I looked into it. This is in fact the case. It is caused because normally the frame specification created by the action are put on the \only. Actually they are placed after the expansion of the begin of the environment, and so the \only should be last. Right now the \alertenv is last and therefore the frame specification is passed to the alert and not to the \only. We can't put the \alertenv in the \only, because at the end of the environment there is no frame specification and therefore \endalertenv won't be in the only and thus show up in every frame, causiing problems. What we need to do is place some extra code in the \only such that the command at the end is only defined to be \endalertenv when the \only is executed and otherwise is equal to \relax. You can use the following as the environment definition:

\newenvironment{myalertenv}{\let\neweae\relax\only{\setbeamertemplate{itemize item}{\CorkSquare[size=0.18,line width=0.70pt,draw=red,fill=red!19!white]}\alertenv\let\neweae\endalertenv}}{\neweae}

This will only place the modified item label and the alert on frames specified by the frame specification.