Take the 2-minute tour ×
TeX - LaTeX Stack Exchange is a question and answer site for users of TeX, LaTeX, ConTeXt, and related typesetting systems. It's 100% free, no registration required.

mystyle/.style= {...} is perhaps used ?

I would like to know how to verify if the style is really defined and in this case, I would like to know if the style is empty ?

Is it possible to use \pgfkeysifdefined to get the first result ?

share|improve this question
    

3 Answers 3

up vote 4 down vote accepted
\documentclass{standalone}
\usepackage{tikz}
\makeatletter
\def\pgfkeysifstyledefined#1#2#3{%
  \pgfkeys@ifcsname pgfk@#1/.@cmd\endcsname#2\else#3\fi}

\def\pgfkeysifstyleempty#1{%
  \expandafter\expandafter\expandafter\pgfkeysifstyleempty@i
  \csname pgfk@#1/.@cmd\endcsname\pgfeov}

\def\pgfkeysifstyleempty@i\pgfkeysalso#1#2#3{%
  \if\relax\detokenize{#1}\relax
    #2%
  \else
    #3%
  \fi}
\makeatother

\begin{document}

\pgfkeysifstyledefined{/tikz/my style}{Defined}{Undefined}

\tikzset{my style/.style = {}}
\pgfkeysifstyledefined{/tikz/my style}{Defined}{Undefined}

\pgfkeysifstyleempty{/tikz/my style}{Empty}{Non empty}

\tikzset{my style/.style = {Test}}
\pgfkeysifstyleempty{/tikz/my style}{Empty}{Non empty}

\end{document}
share|improve this answer
    
Thanks It was exactly what I needed. I made another test with \begin{tikzpicture}[other style/.style={thick}] and the result is fine ! –  Alain Matthes Feb 28 '12 at 16:03
    
Be careful with this code -- if I understand the pgf manual correctly (p485), there are several ways .@cmd can be defined, not merely as a side-effect of setting .style. So \pgfkeysifstyledefined may return false positives (and ...empty may return false negatives). A more robust solution, I think (but have not attempted), would redefine /handlers/.style/.@cmd to record the key names it defines somewhere in a parallel key tree (similar to how trace-pgfkeys works, I think) and then checks that. But that's complicated and probably more work than you need for the common case here... –  Ben Lerner Feb 28 '12 at 16:45
    
@BenLerner: trace-pgfkeys does not use a parallel tree, unless you mean that it redefines the internals of pgfkeys, which is true. Though I did write an answer, also dealing with styles in a different way (tex.stackexchange.com/a/43150/575) that does use a parallel tree for a similar purpose. –  Ryan Reich Feb 28 '12 at 19:57
    
@RyanReich, I guess I was thinking of that :) –  Ben Lerner Feb 28 '12 at 20:07

It appears not -- .style is a handler that sets .code, which in turn is a handler that sets the internal .@cmd attribute. Using Ryan Reich's incredibly cool trace-pgfkeys package (from this question), the following code

\documentclass{article}
\usepackage{pgfkeys}
\usepackage[tracemacros]{trace-pgfkeys}
\pgfkeystracelevel{verbose}
\begin{document}
\makeatletter

\typeout{Setting /test1/.style}
\pgfkeys{/test1/.style={shape=rectangle}}
\typeout{Checking ifdefine /test1/.style}
\pgfkeysifdefined{/test1/.style}{True}{False}
\typeout{Checking ifdefine /test1/.code}
\pgfkeysifdefined{/test1/.code}{True}{False}
\typeout{Checking ifdefine /test1/.@cmd}
\pgfkeysifdefined{/test1/.@cmd}{True}{False}


\typeout{Checking ifdefine /test-missing/.style}
\pgfkeysifdefined{/test-missing/.style}{True}{False}
\typeout{Checking ifdefine /test-missing/.code}
\pgfkeysifdefined{/test-missing/.code}{True}{False}
\typeout{Checking ifdefine /test-missing/.@cmd}
\pgfkeysifdefined{/test-missing/.@cmd}{True}{False}

\typeout{Setting /test2/.style to nothing}
\pgfkeys{/test2/.style=}

\pgfkeysgetvalue{/test2/.@cmd}{\test}
\ifx\test\relax Empty \else Not empty \fi
\end{document}

produces the following document:

False False True
False False False
Not empty

and a lot of useful debugging output, the following trace for setting /test1/.style:

Setting /test1/.style
[trace-pgfkeys]-: Tracing \pgfkeys call.
[trace-pgfkeys]-+ Key/value list: (/test1/.style={shape=rectangle})
[trace-pgfkeys]-+ Current key-value: (/test1/.style={shape=rectangle})
[trace-pgfkeys]-+ \pgfkeyscurrentkey (given): /test1/.style
[trace-pgfkeys]-: Full key; no path added.
[trace-pgfkeys]-> \pgfkeyscurrentkey : /test1/.style
[trace-pgfkeys]-+ \pgfkeyscurrentvalue : (shape=rectangle)
[trace-pgfkeys]-: Case one: key code?
[trace-pgfkeys]-: Case two: key value?
[trace-pgfkeys]-: Case three: key unknown. Splitting the path.
[trace-pgfkeys]-+ \pgfkeyscurrentpath (/test1)
[trace-pgfkeys]-+ \pgfkeyscurrentname (.style)
[trace-pgfkeys]-: Checking whether a handler is defined.
[trace-pgfkeys]-+ Executing all handlers.
[trace-pgfkeys]-: Tracing \pgfkeysgetvalue .
[trace-pgfkeys]-: Value: (\long macro:#1\pgfeov ->\pgfkeys {\pgfkeyscurrentpath /.code=\pgfkeysalso {#1}})
[trace-pgfkeys]--+ Storing key value in \pgfkeys@code 
[trace-pgfkeys]--> Storing: /handlers/.style/.@cmd 
[trace-pgfkeys]--+ Done storing.
[trace-pgfkeys]-: Handler code:
[trace-pgfkeys]-: \long macro:#1\pgfeov ->\pgfkeys {\pgfkeyscurrentpath /.code=\pgfkeysalso {#1}}
[trace-pgfkeys]--+ Executing handler.
[trace-pgfkeys]--> Handler: /handlers/.style
[trace-pgfkeys]---: Tracing \pgfkeys call.
[trace-pgfkeys]---+ Key/value list: (\pgfkeyscurrentpath /.code=\pgfkeysalso {shape=rectangle})
[trace-pgfkeys]---+ Current key-value: (\pgfkeyscurrentpath /.code=\pgfkeysalso {shape=rectangle})
[trace-pgfkeys]---+ \pgfkeyscurrentkey (given): /test1/.code
[trace-pgfkeys]---: Full key; no path added.
[trace-pgfkeys]---> \pgfkeyscurrentkey : /test1/.code
[trace-pgfkeys]---+ \pgfkeyscurrentvalue : (\pgfkeysalso {shape=rectangle})
[trace-pgfkeys]---: Case one: key code?
[trace-pgfkeys]---: Case two: key value?
[trace-pgfkeys]---: Case three: key unknown. Splitting the path.
[trace-pgfkeys]---+ \pgfkeyscurrentpath (/test1)
[trace-pgfkeys]---+ \pgfkeyscurrentname (.code)
[trace-pgfkeys]---: Checking whether a handler is defined.
[trace-pgfkeys]---+ Executing all handlers.
[trace-pgfkeys]---: Tracing \pgfkeysgetvalue .
[trace-pgfkeys]---: Value: (\long macro:#1\pgfeov ->\pgfkeysdef {\pgfkeyscurrentpath }{#1})
[trace-pgfkeys]----+ Storing key value in \pgfkeys@code 
[trace-pgfkeys]----> Storing: /handlers/.code/.@cmd 
[trace-pgfkeys]----+ Done storing.
[trace-pgfkeys]---: Handler code:
[trace-pgfkeys]---: \long macro:#1\pgfeov ->\pgfkeysdef {\pgfkeyscurrentpath }{#1}
[trace-pgfkeys]----+ Executing handler.
[trace-pgfkeys]----> Handler: /handlers/.code
[trace-pgfkeys]----: Tracing \pgfkeysdef .
[trace-pgfkeys]----: Code: (\pgfkeysalso {shape=rectangle})
[trace-pgfkeys]-----+ Defining key code.
[trace-pgfkeys]-----> New code: /test1
[trace-pgfkeys]-----: Tracing \pgfkeyslet .
[trace-pgfkeys]------+ Assigning key from \pgfkeys@temp 
[trace-pgfkeys]------> Assigning: /test1/.@cmd
[trace-pgfkeys]------+ Done assigning.
[trace-pgfkeys]-----+ Done defining.
[trace-pgfkeys]----+ Done defining.
[trace-pgfkeys]---+ Execution finished.
[trace-pgfkeys]--+ Last key processed.
[trace-pgfkeys]-+ Execution finished.
[trace-pgfkeys]+ Last key processed.

Note that /.style has a /.@cmd that in turn sets /.code, which itself has a /.@cmd that finally sets the /test1/.@cmd attribute directly. Hope that helps!

share|improve this answer
    
+1 for the investigation and the use of the trace-pgfkeys package. –  cjorssen Feb 28 '12 at 15:09
    
+1 very interesting to see how to use the trace-pgfkeys package and +1 for Ryan too ! –  Alain Matthes Feb 28 '12 at 16:02
    
+1 for making my morning! –  Ryan Reich Feb 28 '12 at 17:54

Here is my take on this answer. Basically, setting a .style has the effect of setting .@cmd to exactly the code \pgfkeysalso{<keys>}. I take this to be the definition of "is a style", since there is no way to check that this kind of code wasn't produced by setting .code directly, but then, if it quacks like a duck...

I provide three user commands:

  • \pgfkeysifstyle{<full key>}{<true>}{<false>}, which acts based on whether the key is a style in the sense above.

  • \lastpgfkeysstyle, which stores the contents of the style if the key is a style. If it's not, don't use this.

  • \pgfkeysifstyleempty (same args), which acts based on whether that style is empty. If it's not a style, I go with "true" since otherwise you might want to use \lastpgfkeysstyle.

The code:

\documentclass{article}
\usepackage{filecontents}

\begin{filecontents*}{pgfkeys-ifstyle.sty}
 \RequirePackage{etoolbox}% for \ifstrequal, \ifdefempty

 \def\lastpgfkeysstyle{}
 % Checks if #1 = \pgfkeysalso{...} and, if so, puts the argument
 % in \lastpgfkeysstyle
 \def\@ifgetpgfkeysalso#1\pgfkeysalso#2#3\@nil{%
  \ifstrequal{#1.#3}{.\pgfkeysalso{}}% \pgfkeysalso{#2} is the only thing there
   {\def\lastpgfkeysstyle{#2}\@firstoftwo}
   {\@secondoftwo}%
 }

 % So I don't need to write this again
 \def\expandaftertwice{\expandafter\expandafter\expandafter}

 \def\pgfkeysifstyle#1{%
  % "Expand" the key's .@cmd until its code shows
  % Even if there is no .@cmd, we get #1\pgfeov, which will not screw us up.
  \toks0=\expandaftertwice{\csname pgfk@#1/.@cmd\endcsname##1\pgfeov}%
  \expandafter\@ifgetpgfkeysalso\the\toks0 \pgfkeysalso{}\@nil% That space is very important!
 }
 \def\pgfkeysifstyleempty#1{%
  \pgfkeysifstyle{#1}
   {\ifdefempty{\lastpgfkeysstyle}}
   {% We count a non-style as empty, since otherwise you might use \lastpgfkeysstyle
    \PackageWarning{pgfkeys-ifstyle}
     {In \noexpand\pgfkeysifstyleempty\MessageBreak
      The key #1 is not defined as a style!\MessageBreak}
    \@firstoftwo
   }%
 }
\end{filecontents*}

\usepackage{pgfkeys-ifstyle}
\usepackage{pgfkeys,pgffor}

\begin{document}
 \pgfkeys{
  /key 1/.style = {x, y, z},
  /key 2/.code = {Not a style #1},
  /key 3/.initial = {Not even a code},
  /key 4/.style = {},% Empty style
  /key 5/.code = {\pgfkeysalso{a, b, c} and other stuff},
  /key 6/.code = {\pgfkeysalso{a, b, c}},
 }

 \newcommand*\teststyle[1]{%
  \par\medskip\noindent
  \pgfkeysifstyle{#1}{#1 has a style: \lastpgfkeysstyle}{#1 is not a style}\\
  \pgfkeysifstyleempty{#1}{#1 has an empty style}{#1 does not have an empty style}
 }

 \foreach \n in {1,...,6} {\teststyle{/key \n}}
\end{document}
share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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