# pgfdeclareshape with variable dimensions using pgfkeys

I am trying to define some shapes for TikZ using \pgfdeclareshape. I would like to use options to make their size adjustable, however I do not get it to work. This example compiles, but the size of the circle is not set properly (or at all). What am I doing wrong :?

\documentclass[oneside,12pt]{scrartcl}
\usepackage{tikz}
\usetikzlibrary{shapes}

\makeatletter
\pgfkeys{/tikz/mycirclesize/.code={\pgf@x = #1}}
\pgfkeys{/tikz/mycirclesize/.default = 0.75cm}
\pgfkeysgetvalue{/tikz/mycirclesize}{\macro}

\pgfdeclareshape{mycircle}
{
\savedanchor\centerpoint{
\pgf@x = .5\wd\pgfnodeparttextbox
\pgf@y = .5\ht\pgfnodeparttextbox
}
\anchor{center}{\centerpoint}

\saveddimen\circsize{ \macro }

\backgroundpath{
\centerpoint

\pgfkeys{/pgf/minimum size = \circsize}
\pgfset{inner sep=1pt}
\pgfnode{circle}{center}{}{}{\pgfusepath{draw}}
}

}

\makeatother

\begin{document}

\begin{tikzpicture}

\draw (0,0) node[mycircle, mycirclesize=2cm] {};
\end{tikzpicture}

\end{document}

-

The problem is due to what mycirclesize does and when it does it.

You declare it with:

\pgfkeys{/tikz/mycirclesize/.code={\pgf@x = #1}}
\pgfkeys{/tikz/mycirclesize/.default = 0.75cm}
\pgfkeysgetvalue{/tikz/mycirclesize}{\macro}


This says three things:

1. When \pgfkeys{/tikz/mycirclesize=<something>} is called, execuite \pgf@x=<something> at that moment.
2. Set the default of /tikz/mycirclesize to 0.75cm so that if \pgfkeys{/tikz/mycirclsize} is called, ie without an argument, we assume it to be 0.75cm.
3. Get the current value of /tikz/mycirclesize and store it in \macro.

This third is crucial. At this point, /tikz/mycirclesize has no value and what is returned is simply \relax (it hasn't even been initialised). So \macro is let to be \relax and its value is frozen at this time.

Later, you call:

\draw (0,0) node[mycircle, mycirclesize=2cm] {};


which executes the key /tikz/mycirclesize with a value of 2cm and this sets \pgf@x to 2cm at that moment. It then gets wiped out pretty soon as \pgf@x tends to get battered about from one thing to the next without so much as a by-your-leave.

What you probably want to do is store the argument to mycirclesize as its value and then in the \savedimen call inside the shape get this value (and assign it to \pgf@x as that's how \savedimen works). The following is some code that will do that with minimal changes to your code.

\documentclass[oneside,12pt]{scrartcl}
%\url{http://tex.stackexchange.com/q/73877/86}
\usepackage{tikz}
\usetikzlibrary{shapes}

\makeatletter
\pgfkeys{/tikz/mycirclesize/.initial = 0.75cm}

\pgfdeclareshape{mycircle}
{
\savedanchor\centerpoint{
\pgf@x = .5\wd\pgfnodeparttextbox
\pgf@y = .5\ht\pgfnodeparttextbox
}
\anchor{center}{\centerpoint}

\saveddimen\circsize{\pgf@x=\pgfkeysvalueof{/tikz/mycirclesize}}

\backgroundpath{
\centerpoint
\pgfkeys{/pgf/minimum size = \circsize}
\pgfset{inner sep=1pt}
\pgfnode{circle}{center}{}{}{\pgfusepath{draw}}
}

}

\makeatother

\begin{document}

\begin{tikzpicture}

\draw (0,0) node[mycircle, mycirclesize=2cm] {};
\end{tikzpicture}

\end{document}

-
Wow, thanks for the fast reply. This works, and it works exactly as I want it to work =D Anyway, I do not yet quite understand the difference in your and my implementation (or rather, why the difference leads to different behaviour), but I will try to figure that out.. Your explanation is extremely helpful. – Theo Sep 24 '12 at 13:11