I am authoring Beamer presentations that feature numerous code listings, and I am required to highlight portions of code with semi-transparent balloons. Yet I've come up with a solution that uses a variant of tikzmark. Inside listings, I am placing anchors manually, stretching a balloon over them afterwards.
\documentclass{beamer}
\usepackage{listings}
\usepackage{tikz}
\usetikzlibrary{fit,calc,shadows}
% Define styles for balloons and lines
\tikzstyle{line} = [draw, rounded corners=3pt, -latex]
\tikzstyle{balloon} = [draw, fill=blue!20, opacity=0.4, inner sep=4pt, rounded corners=2pt]
\tikzstyle{comment} = [draw, fill=blue!70, text=white, text width=3cm, minimum height=1cm, rounded corners, drop shadow, align=left, font=\scriptsize]
% Command to place a TikZ anchor at the current position
\newcommand{\tikzmark}[1]{%
\tikz[overlay,remember picture,baseline] \coordinate (#1) at (0,0) {};}
% Command to draw a balloon over two anchors
\newcommand<>{\balloon}[3][balloon]{%
\coordinate (c) at ($(#2)+(0,1ex)$);
\node#4 (#1) [balloon, fit=(#3) (c)] {};}
\begin{document}
\begin{frame}[fragile]{Foo!}
\begin{lstlisting}[language=c,escapechar=\$]
$\tikzmark{sw1}$#include <stdio.h>$\tikzmark{ne1}$
int main(void)
{
printf("hello, world\n");$\tikzmark{ne2}$
$\tikzmark{sw2}$return 0;
}
\end{lstlisting}
\pause
\begin{tikzpicture}[overlay,remember picture]
\balloon<2>{ne1}{sw1};
\balloon<3>{ne2}{sw2};
\node (comment) [comment] at (\textwidth-1.5cm, .5\textheight+1cm) {%
\only<2>{Include headers}%
\only<3>{Do stuff}%
};
\draw<2-3> [line] (comment.south) |- (balloon.east);
\end{tikzpicture}
\end{frame}
\end{document}
As you see, this approach requires a lot of redundant work. I have dozens of presentations to do, many of them containing similar code samples, and placing tikzmarks manually all over the code seems to be an overkill. Additionally, this approach fails if we need to highlight a block of code that contains long lines inside (for example, the whole "main" function in the example above).
In fact, the two line numbers is the only necessary input for this case. It would be good if I could write some macro that would accept two numbers (beginning line and ending line) and the comment text, and do the rest automatically. Could this be done with somehow intercepting lstlisting's output and, for each line, remembering coordinates of the first non-whitespace character and line ending? After that, we would have an array of coordinates that could be, for instance, fed to tikz "fit" facility.
It would be also good if the macro worked not only with inline listings, but with external code too. We are relying on system TTF fonts, that's why we target XeTeX and luaTex (with latter being even preferred). As I'm relatively new to TeX, I would also appreciate any comments and suggestions on the example above.
Thanks!
listings
to insert some code at the start of each line containing something like\tikzmark{<listingID>-<line number>}
and then a macro could just use these tikzmarks to draw the highlighting. It has to be listing-width and page-break aware …