# TikZ: Override fill of shape based on one pgfkey with another in command

I'm creating a package that generates a tikz picture based on a command with pgf key/value parameters. I want to have two parameters, one that specifies a base shape with a particular fill colour, and another that turns that fill "on" when false (to the specified colour), and "off" (to white) when true. I've created a simplified example below:

\documentclass[border=5pt]{standalone}
\usepackage{xifthen}
\usepackage{tikz}
\newboolean{shapecolour}
\pgfkeys{/tikz/.cd,
circle/.style={fill=red},
square/.style={fill=green},
triangle/.style={fill=yellow},
blank/.style={fill=white},
colourshape/.store in=\colourshape,
colourshape=circle,
nocolour/.store in=\nocolour,
nocolour=false,
circle/.pic={\draw [fill] circle(0.5); },
square/.pic={\draw [fill] (0,0) -- (0,1) -- (1,1) -- (1,0) -- cycle;},
triangle/.pic={\draw [fill] (0,0) -- (1,0) -- (0.5, 1) -- cycle;},
}

\begin{document}

\newcommand{\TestCommand}[1][]{
\tikzset{colourshape=circle, nocolour=false, #1}
\setboolean{shapecolour}{\nocolour}
\pic[\ifthenelse{\boolean{shapecolour}}{blank}{\colourshape}]{\colourshape};
}

\begin{tikzpicture}
\TestCommand[colourshape=triangle, nocolour=true]
\end{tikzpicture}

\end{document}


This is the desired outcome of my code, based on the pgfkeys arguments put into TestCommand:

So the code above should produce a triangle with a white fill. Instead I get the error ! Argument of \boolean has an extra }. I know I can achieve the same result in a more verbose way by specifying a separate pic for each variant of the shape, but I would like to have a more compact solution, especially as there will be more style options to follow.

• Ouch, you are overriding a lot of default TikZ keys. – percusse Sep 14 '16 at 19:15
• @percusse I know, the real thing doesn't do this. It's a quick and dirty example. It works if I type in the style parameters manually rather than using the conditional, so it's OK. – Crazymoomin Sep 14 '16 at 19:21

## 1 Answer

It is hard to be certain without more information about the overall project. However, from your example, I would not use a conditional here at all. If you do use a conditional, I would look into PGF's .is if handler, which will make things much easier.

First some keys:

\tikzset{%


We can afford to use verbose names here because the user interface won't require them at all.

  Crazymoomin circle/.pic={\draw [fill=Crazymoomin@fill] (.5,.5) circle (0.5);},
Crazymoomin square/.pic={\draw [fill=Crazymoomin@fill] (0,0) -- (0,1) -- (1,1) -- (1,0) -- cycle;},
Crazymoomin triangle/.pic={\draw [fill=Crazymoomin@fill] (0,0) -- (1,0) -- (0.5, 1) -- cycle;},


So that we can use simple key names in the user interface, we'll put them on a custom path, but we'll make sure that standard TikZ keys work here, too.

  /Crazymoomin/.search also={/tikz},


Switch paths.

  /Crazymoomin/.cd,


Now we can use simple names without overwriting the defaults.

  fill/.code={%


This will hold a custom colour.

    \colorlet{Crazymoomin@fill}{#1}%
},


And a shape.

  shape/.store in=\Crazymoomin@shape,


To handle the colour/shape combo neatly, let's make colour shape a choice key.

  colour shape/.is choice,


Now for the options, which each switch to our path and set the pic shape and fill.

  colour shape/triangle/.style={/Crazymoomin/.cd, shape=triangle, fill=yellow},
colour shape/circle/.style={/Crazymoomin/.cd, shape=circle, fill=red},
colour shape/square/.style={/Crazymoomin/.cd, shape=square, fill=green},


no colour can just set the fill to white.

  no colour/.style={/Crazymoomin/fill=white},


Make sure we have a default for everything.

  fill=gray,
shape=circle,
}


Now the command.

\newcommand{\TestCommand}[1][]{%
\tikzset{%


Switch to our path.

   /Crazymoomin/.cd,


Default setting. This sets the filling colour anyway, so no colour is effectively false by default.

   colour shape=circle,


User options.

   #1,
}%


And the pic.

 \pic {Crazymoomin \Crazymoomin@shape};
}


Then we can write, for example,

\begin{tikzpicture}
\TestCommand[colour shape=triangle, no colour]
\scoped[xshift=12.5mm]{\TestCommand[colour shape=circle, no colour]}
\scoped[xshift=25mm]{\TestCommand[colour shape=square, no colour]}
\scoped[yshift=12.5mm]{\TestCommand[colour shape=triangle]}
\scoped[xshift=12.5mm, yshift=12.5mm]{\TestCommand[colour shape=circle]}
\scoped[xshift=25mm, yshift=12.5mm]{\TestCommand[colour shape=square]}
\end{tikzpicture}


to produce

Obviously this is awkward because I didn't want to mess around too much with \TextCommand which doesn't have any positioning information (eek!?).

Complete code:

\documentclass[border=10pt,multi,tikz]{standalone}
\makeatletter
\tikzset{%
Crazymoomin circle/.pic={\draw [fill=Crazymoomin@fill] (.5,.5) circle (0.5);},
Crazymoomin square/.pic={\draw [fill=Crazymoomin@fill] (0,0) -- (0,1) -- (1,1) -- (1,0) -- cycle;},
Crazymoomin triangle/.pic={\draw [fill=Crazymoomin@fill] (0,0) -- (1,0) -- (0.5, 1) -- cycle;},
/Crazymoomin/.search also={/tikz},
/Crazymoomin/.cd,
fill/.code={%
\colorlet{Crazymoomin@fill}{#1}%
},
shape/.store in=\Crazymoomin@shape,
colour shape/.is choice,
colour shape/triangle/.style={/Crazymoomin/.cd, shape=triangle, fill=yellow},
colour shape/circle/.style={/Crazymoomin/.cd, shape=circle, fill=red},
colour shape/square/.style={/Crazymoomin/.cd, shape=square, fill=green},
no colour/.style={/Crazymoomin/fill=white},
fill=gray,
shape=circle,
}
\newcommand{\TestCommand}[1][]{%
\tikzset{%
/Crazymoomin/.cd,
colour shape=circle,
#1,
}%
\pic {Crazymoomin \Crazymoomin@shape};
}
\makeatother
\begin{document}
\begin{tikzpicture}
\TestCommand[colour shape=triangle, no colour]
\scoped[xshift=12.5mm]{\TestCommand[colour shape=circle, no colour]}
\scoped[xshift=25mm]{\TestCommand[colour shape=square, no colour]}
\scoped[yshift=12.5mm]{\TestCommand[colour shape=triangle]}
\scoped[xshift=12.5mm, yshift=12.5mm]{\TestCommand[colour shape=circle]}
\scoped[xshift=25mm, yshift=12.5mm]{\TestCommand[colour shape=square]}
\end{tikzpicture}
\end{document}

• Thankyou for the answer, very helpful. I do change the outline pattern and colour using keys as well, but I have managed to get this to work because I'm changing separate style attributes. However, your method looks a lot more attractive so i'll see if I can do something similar for those. I wasn't planning on adding positioning information as they will probably either be drawn on their own or as part of a larger Tikz picture where I would expect positioning would be controlled out of scope of the command. I haven't decided yet if I'm going to include it. – Crazymoomin Sep 15 '16 at 8:16