3

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{adjustbox}
\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
            \adjustbox{scale={1.25}{1.00}}\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}

enter image description here

  • 3
    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
1

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{adjustbox}
\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
            \adjustbox{scale={1.25}{1.00}}\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.

  • The closing delimiter of a \newcommand optional argument is the first closing square bracket that the parser encounters that is at the same level wrt TeX groups. Since your argument contains several closed brackets, with \newcommand then the first is taken as that delimiter. Putting it in braces shifts the group level and stops this. With \NewDocumentCommand, the delimiters have to be balanced, meaning that as all your brackets occur in pairs, the correct one is used as the closing delimiter. Lastly, putting an argument in braces is a fairly standard thing in TeX. – Loop Space Aug 26 '18 at 8:10
  • @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

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.