# How to pass tikz code as an argument?

I want to prepare an environment to show a view of a display and use some tikz code as an optional argument to mark some things on it. The first "screen" shows result with hardcoded nodes but I need to pass it as an argument like in the second "screen" but it throws errors during compilation.

How to solve it?

Code

\documentclass{article}

\usepackage{geometry}
\usepackage{float}
\usepackage{graphicx}

\usepackage{tikz}
\usetikzlibrary{arrows.meta}
\usetikzlibrary{fit}

\usepackage{blindtext}
\usepackage{wrapfig}
\usepackage[babel=true]{microtype}

\newcommand{\fontsmall}{\fontsize{5pt}{6pt}\selectfont}
\newcommand{\fontnormal}{\fontsize{10pt}{12pt}\selectfont}

\floatstyle{boxed}
\newfloat{myfloat}{tbp}{extdisplay}
\newcommand\displayenvargument{}
\newenvironment{display}[1][]{%
\renewcommand{\displayenvargument}{#1}
\setlength{\intextsep}{10pt}%
\SetTracking{encoding={*}}{150}%
\bfseries%
\fontnormal%
\wrapfloat{myfloat}{O}[0ex]{17\baselineskip}%
\begin{tikzpicture}[
numer/.style={draw, red, thick, circle, inner sep=0.2ex},
element/.style={draw, blue, thick, rectangle, rounded corners, inner sep=0},
strzala/.style={-stealth,red,thick},
linia/.style={red,thick},
]
\node[anchor=south west,inner sep=0] (image) at (0,0)
\bgroup
\begin{minipage}[][7.75\baselineskip][t]{12\baselineskip}%
\lsstyle%
}{%
\end{minipage}%
\egroup
\egroup;
\begin{scope}[x={(image.south east)},y={(image.north west)}]
% grid
\draw[help lines,ultra thin,xstep=.10,ystep=.10,lightgray] (0,0) grid (1,1);
\foreach \x in {1,...,9} { \node [red,anchor=north] at (\x/10,0) {\tiny 0.\x}; }
\foreach \y in {1,...,9} { \node [red,anchor=east] at (0,\y/10) {\tiny 0.\y}; }
% argument
\displayenvargument
% BEGIN OF ARGUMENT CONTENT
\node (text_num) at (0.2,0.3) [numer] {1};
\node (text) [element, fit={(0.4,0.6)(0.6,0.73)}] {};
\draw [strzala] (text_num) -- (text);
% END OF ARGUMENT CONTENT
\end{scope}
\end{tikzpicture}
\endwrapfloat%
\par%
}

\begin{document}

\begin{display}%
~\par
~\par
\begin{center}
text
\end{center}\par
~\par
~\par
~\par
~\par
~\par
\end{display}%

\blindtext

\begin{display}[%
% this doesn't work
% BEGIN OF ARGUMENT CONTENT
%   \node (text_num) at (0.8,0.7) [numer] {1};
%   \node (text) [element, fit={(0.4,0.22)(0.6,0.34)}] {};
%   \draw [strzala] (text_num) -- (text);
% END OF ARGUMENT CONTENT
]
~\par
~\par
~\par
~\par
~\par
\begin{center}
text
\end{center}\par
~\par
~\par
\end{display}%

\blindtext

\end{document}


• Does it work if you enclose the entire argument in braces: {...}? You have square brackets inside the argument and if not protected, they can get interpreted as the ending close bracket of the optional argument to the display environment. – Loop Space Aug 24 '18 at 13:09
• @LoopSpace Thanks, it works with {} but it's a bit unnatural to enclose optional argument in it. I'd prefer (and tried it before asking the question) to put curly braces inside environment defenition but it doesn't work. – Simon Aug 24 '18 at 17:01

OK, I solved it myself with \NewDocumentEnvironment from xparse to create environment.

And added starred version to show or not the grid.

\documentclass{article}

\usepackage{geometry}
\usepackage{float}
\usepackage{graphicx}
\usepackage{xparse}

\usepackage{tikz}
\usetikzlibrary{arrows.meta}
\usetikzlibrary{fit}

\usepackage{blindtext}
\usepackage{wrapfig}
\usepackage[babel=true]{microtype}

\newcommand{\fontsmall}{\fontsize{5pt}{6pt}\selectfont}
\newcommand{\fontnormal}{\fontsize{10pt}{12pt}\selectfont}

\floatstyle{boxed}
\newfloat{myfloat}{tbp}{extdisplay}
\NewDocumentEnvironment{display}{sO{}}{%
\setlength{\intextsep}{10pt}%
\SetTracking{encoding={*}}{150}%
\bfseries%
\fontnormal%
\wrapfloat{myfloat}{O}[0ex]{17\baselineskip}%
\begin{tikzpicture}[
numer/.style={draw, red, thick, circle, inner sep=0.2ex},
element/.style={draw, blue, thick, rectangle, rounded corners, inner sep=0},
strzala/.style={-stealth,red,thick},
linia/.style={red,thick},
]
\node[anchor=south west,inner sep=0] (image) at (0,0)
\bgroup
\begin{minipage}[][7.75\baselineskip][t]{12\baselineskip}%
\lsstyle%
}{%
\end{minipage}%
\egroup
\egroup;
\begin{scope}[x={(image.south east)},y={(image.north west)}]
% grid
\IfBooleanT {#1}{
\draw[help lines,ultra thin,xstep=.10,ystep=.10,lightgray] (0,0) grid (1,1);
\foreach \x in {1,...,9} { \node [red,anchor=north] at (\x/10,0) {\tiny 0.\x}; }
\foreach \y in {1,...,9} { \node [red,anchor=east] at (0,\y/10) {\tiny 0.\y}; }
}%
% argument
\noexpand{#2}   % without \noexpand first line of argument does not appear
% BEGIN OF ARGUMENT CONTENT
\node (text_num) at (0.2,0.3) [numer] {1};
\node (text) [element, fit={(0.4,0.6)(0.6,0.73)}] {};
\draw [strzala] (text_num) -- (text);
% END OF ARGUMENT CONTENT
\end{scope}
\end{tikzpicture}
\endwrapfloat%
\par%
}
\ExplSyntaxOn
\cs_new:cpn {display*} {\display*}
\cs_new_eq:cN {enddisplay*} \enddisplay
\ExplSyntaxOff

\begin{document}

\begin{display*}
~\par
~\par
\begin{center}
text
\end{center}\par
~\par
~\par
~\par
~\par
~\par
\end{display*}

\blindtext

\begin{display*}[
\node (text_num) at (0.8,0.7) [numer] {2};
\node (text) [element, fit={(0.4,0.22)(0.6,0.34)}] {};
\draw [strzala] (text_num) -- (text);
]
~\par
~\par
~\par
~\par
~\par
\begin{center}
text
\end{center}\par
~\par
~\par
\end{display*}%

\blindtext

\begin{display}[
\node (text_num) at (0.8,0.7) [numer] {2};
\node (text) [element, fit={(0.4,0.22)(0.6,0.34)}] {};
\draw [strzala] (text_num) -- (text);
]
~\par
~\par
~\par
~\par
~\par
\begin{center}
text
\end{center}\par
~\par
~\par
\end{display}

\blindtext

\end{document}


ps: I don't know exactly why it works but works for my purposes.

• @LoopSpace OK, thank you for explanation. I'm used to other languages that braces are always balanced and it simply works that way. LaTeX is great but weird ;) – Simon Aug 26 '18 at 10:48
• You have to remember that LaTeX is a typesetting system and there are many occasions where you might want to typeset unbalanced types of brackets. In maths, for example, we have half-open intervals written, eg, [0,1) – Loop Space Aug 26 '18 at 12:04
• @LoopSpace That's clear. I meant balanced braces in sense of coding ;) – Simon Aug 26 '18 at 19:58