12

I would like to be able to detect if a particular option has been provided via a \tikzset and issue a message based on that.

The MWE yields:

enter image description here

But once the conditional works (just a comment for now) it should yield:

enter image description here

Notes:

  • Even though I don't think that this case introduces any additional complexity, I am not concerned about the case where a \tikzset uses a style defined by another \tikzset.

Code:

\documentclass{article}
\usepackage{tikz}

\tikzset{Hollow/.style={red}} \tikzset{Solid/.style={green}}

\newcommand{\TikzPicture}{% \begin{tikzpicture} \draw [ultra thick, blue, ->, My Options] (0,0) -- (1,0) % If option Hollow is specified node [right] {Error: Option Hollow specified.} ; \end{tikzpicture}% }%

\begin{document}

\tikzset{My Options/.style={Hollow}} \TikzPicture

\tikzset{My Options/.style={}} \TikzPicture \end{document}

Peter Grill
  • 223,288
  • Hollow is defined as a style so it's a combination of certain key=value pairs, it doesn't set a distinctive switch per se when called. If it's a distinct option you can /.try it at the first instance then it's gonna stay there. – percusse Mar 05 '13 at 23:09
  • @percusse: Never heard of /.try, will have to look that up.. – Peter Grill Mar 05 '13 at 23:31

2 Answers2

13

Edit: Via the .forward to handler (only available with the CVS version of PGF) , you can attach a boolean to your Hollow style when you want to test if it is specified:

\documentclass{article}
\usepackage{tikz}
\usepackage{etoolbox}

\newbool{Hollow}

\tikzset{
  Hollow is used/.code=\booltrue{Hollow},
  Test Hollow/.code={\tikzset{Hollow/.forward to=/tikz/Hollow is used}},
  Hollow/.style={red},
  Solid/.style={green},
}

\newcommand{\TikzPicture}{%
    \begin{tikzpicture}
        \draw [Test Hollow,ultra thick, blue, ->, My Options] (0,0) -- (1,0)
        \ifbool{Hollow}{
          node [right] {Error: Option Hollow specified.}
        }{
          node [right] {Ok: Option Hollow is not specified.}
        }
        ;
    \end{tikzpicture}%
}%

\begin{document}

\tikzset{My Options/.style={Hollow}}
\TikzPicture

\tikzset{My Options/.style={}}
\TikzPicture

\tikzset{Hollow/.style={violet,dotted}}

\tikzset{My Options/.style={Hollow}}
\TikzPicture

\end{document}

enter image description here

First solution (with version 2.10 of PGF):

\documentclass{article}
\usepackage{tikz}
\usepackage{etoolbox}

\newbool{Hollow}

\tikzset{
  Hollow/.code={
    \booltrue{Hollow}
    \pgfkeysalso{red}
  },
  Solid/.style={green},
}

\newcommand{\TikzPicture}{%
    \begin{tikzpicture}
        \draw [ultra thick, blue, ->, My Options] (0,0) -- (1,0)
        \ifbool{Hollow}{node [right] {Error: Option Hollow specified.}}{}
        ;
    \end{tikzpicture}%
}%

\begin{document}

\tikzset{My Options/.style={Hollow}}
\TikzPicture

\tikzset{My Options/.style={}}
\TikzPicture

\end{document}
Paul Gaborit
  • 70,770
  • 10
  • 176
  • 283
3

This approach re-defined the .style handler by appending (in this case)

\expandafter\let\csname ifqrr@trace@pgfk@/tikz/Hollow\endcsname\iftrue

to it. Now, /tikz/Hollow is stored in the macro \pgfkeyscurrentpath, so we need to expand it once, because, of course, \pgfkeyscurrentpath will be different when the style is called.

This is the reason I used .ecode instead of .code for the redefinition of the .style handler:

\pgfkeys{
  /handlers/.style/.code=
    \pgfkeys{
      \pgfkeyscurrentpath/.ecode=
        \noexpand\expandafter\noexpand\let\noexpand
             \csname ifqrr@trace@pgfk@\pgfkeyscurrentpath\noexpand\endcsname\noexpand\iftrue
        \noexpand\pgfkeysalso{\unexpanded{#1}}%
    }
}

This has the following consequences:

  • Currently, it only works with .style, not with .estyle, .style args, .estyle args, .style 2 args or .style n args. It also does not work with the handler .append style (which is often used) with a previous undefined style, i.e. .append style without a previous .style.
  • It does not work with previous defined styles.

I also have defined a two-argument expecting .if handler that tests if the key is given, but sadly, it cannot be used inside a path. Therefore I have defined a very simple \iftikzstyle macro that only works for keys in the /tikz/ path but it can be used inside a path.

Further Improvements

  • Re-defining all other style handlers (its just expansion ;))
  • We need to go deeper:

    It would be better to add the \let sequence where the styles are called if one specifies it (for example with \tikzset or in the optional arguments of a \draw). This could make existing/pre-defined styles also available for /.if and \iftikzstyle.

Code

\documentclass{article}
\usepackage{tikz}

\pgfkeys{/handlers/.style/.code=\pgfkeys{\pgfkeyscurrentpath/.ecode=\noexpand\expandafter\noexpand\let\noexpand\csname ifqrr@trace@pgfk@\pgfkeyscurrentpath\noexpand\endcsname\noexpand\iftrue\noexpand\pgfkeysalso{\unexpanded{#1}}}}
\pgfkeys{
    /handlers/.if/.code 2 args={% works not in the middle of a path
        \expandafter\ifx\csname ifqrr@trace@pgfk@\pgfkeyscurrentpath\endcsname\iftrue#1\else#2\fi}}

\makeatletter
\newcommand*{\iftikzstyle}[1]{% only for /tikz/ styles
    \expandafter\ifx\csname ifqrr@trace@pgfk@/tikz/#1\endcsname\iftrue
        \expandafter\@firstoftwo
    \else
        \expandafter\@secondoftwo
    \fi
}
\makeatother

\tikzset{Hollow/.style={red}}
\tikzset{Solid/.style={green}}

\newcommand{\TikzPicture}{%
    \begin{tikzpicture}
        \draw [ultra thick, blue, ->, My Options] (0,0) -- (1,0)
          \iftikzstyle{Hollow}{node[right] {Error: Option Hollow specified.}}{node[opacity=.5,right] {Option Hollow not specified}}
        ;
    \end{tikzpicture}%
}%

\begin{document}
\tikzset{My Options/.style={Hollow}}
\TikzPicture

\tikzset{My Options/.style={}}
\TikzPicture

\tikzset{Hollow/.if={Hollow is specified.}{Hollow is not specified.}}

\tikzset{Hollow}
\tikzset{Hollow/.if={Hollow is specified.}{Hollow is not specified.}}
\end{document}

Output

enter image description here

Qrrbrbirlbel
  • 119,821