# How to define a new environment with a fancy box (tikz) around sample source-code (listings)?

This is what I want to do:

\documentclass{beamer}

\begin{document}

\begin{frame}[fragile]{Frame 1}

Some \structure{Python} code here:

% I want to define a new "pythoncode" environment, so I can use it like this:
\begin{pythoncode}[hello.py]
#!/usr/bin/env python
def main():
print "Hello, World!"
if __name__ == '__main__':
main()
\end{pythoncode}

\end{frame}

\end{document}


But I want to customize the source-code box beyond what listings package allow me. Jan Hlavacek suggested me to use tikz package for that, and pointed me to a few examples.

Okay, that's great! Tikz gives me enough power and freedom for customization! All I need now is creating a new environment, so that I can use this environment just like in the code above.

However, I'm having trouble mixing tikz with listings inside a new environment. I've tried the following code, but it doesn't work (I get Missing \endcsname inserted.):

\usepackage{listings}
\usepackage{tikz}
\usepackage{environ}

\tikzstyle{sourcecodebox} = [
draw=blue, very thick,
rectangle, rounded corners,
inner sep=10pt
]
\tikzstyle{sourcecodetitle} = [
fill=black, text=white,
rectangle, rounded corners
]
\NewEnviron{pythoncode}[1]{
\begin{tikzpicture}
\node[sourcecodebox](box){
\begin{lstlisting}[
language=Python,
basicstyle=\ttfamily\footnotesize,
escapeinside={(*@}{@*)},
%numbers=left,
breaklines=true,
breakatwhitespace=true,
showspaces=false,
showstringspaces=false,
frameround=rrrt,
rulecolor=\color{black},
rulesepcolor=\color{gray}
]
\BODY
\end{lstlisting}
};
\node[sourcecodetitle] at (box.north west) {#1};
\end{tikzpicture}
}


Related questions:

-
Not really answering your question, but how about actually having a hello.py file with the code, and then use \lstinputlisting{hello.py}. You avoid the problem altogether because you don't need to define an environment anymore. –  Juan A. Navarro Jan 20 '11 at 14:52
@Denilson Use the listings environment command to create the environment \lstnewenvironment –  Yiannis Lazarides Jan 20 '11 at 15:16
@Juan: No, I don't want to put an external file because I'm going to use several snippets of source code throughout several slides, so it's a lot better to have them inline with the slide text. Also, sometimes I'll want to highlight some lines from the source code, and thus I need the source inline, mixed with TeX. See this question: tex.stackexchange.com/questions/8851/… –  Denilson Sá Jan 21 '11 at 2:06
@Yiannis: Before writing the code from my question, I've tried using \lstnewenvironment, but I failed completely, because I needed to open \begin{tikzpicture} inside the first pair of braces and then close it inside another set of braces. Since that is not possible, another question from this site suggested using the environ package. Anyway, if you have a working solution, please share with us! –  Denilson Sá Jan 21 '11 at 2:08
@Denilson, this question looks like a duplicate of your earlier question. In order to avoid duplicating efforts trying to answer your question, perhaps you would like to delete this question and update the earlier one with any new information, the things you have tried and why they didn't work? –  Juan A. Navarro Jan 24 '11 at 13:59

Note that \NewEnviron does not support verbatim. The documentation should point that out. As already commented the \lstnewenvironment must be used for this. Alternatively place the verbatim files into external files which are then read using \listinputlisting.

Find below my solution which stores the resulting listings first into a box which is then used inside the TikZ node. IMHO you should not mix the listings frame argument with additional frames from TikZ. You should produce all framing using TikZ (not to be confused with beamers \frame macro/environment). Beamer provides some nice framed boxes as well!

I had to add the linewidth argument and a \makebox, otherwise the listings frame is to wide. You might want to adjust that.

Best Regards, Martin

\documentclass{beamer}

\usepackage{listings}
\usepackage{tikz}

\tikzstyle{sourcecodebox} = [
draw=blue, very thick,
rectangle, rounded corners,
inner sep=10pt
]
\tikzstyle{sourcecodetitle} = [
fill=black, text=white,
rectangle, rounded corners
]

\makeatletter
\lstnewenvironment{pythoncode}[1][]{%
\def\pythoncodetitle{#1}%
\lstset{%
language=Python,
basicstyle=\ttfamily\footnotesize,
escapeinside={(*@}{@*)},
%numbers=left,
breaklines=true,
breakatwhitespace=true,
showspaces=false,
showstringspaces=false,
frameround=rrrt,
linewidth=.75\linewidth,
rulecolor=\color{black},
rulesepcolor=\color{gray}
}%
\setbox\@tempboxa=\hbox\bgroup\color@setgroup
}%
{%
\color@endgroup\egroup
\begin{tikzpicture}
\node[sourcecodebox] (box)
% Makebox is needed to take the frame added by listings into account
{\makebox[.75\linewidth][l]{\box\@tempboxa}};
\node[sourcecodetitle] at (box.north west) {\pythoncodetitle};
\end{tikzpicture}
}

\begin{document}

\begin{frame}[fragile]{Frame 1}

Some \structure{Python} code here:
\begin{pythoncode}[hello.py]
#!/usr/bin/env python
def main():
print "Hello, World!"
if __name__ == '__main__':
main()
\end{pythoncode}

\end{frame}

\end{document}

-