8

The following minimal working example shows the problem. The mainmacro is an example of what I need; here I want to use my keys and keys from tikz (like draw,color,shape). The result is fine only if I use shape = circle. circle is not enough. Idem if I want the color red. color = red is obligatory. What is wrong in my code ? Do you know a better way to achieve what I want ?

\documentclass[a4paper]{article}
\usepackage{tikz}
\usetikzlibrary{calc}

\makeatletter
\pgfkeys{/mykeys/.cd,
d/.code                     = {\def\macro@d{#1}},   
a/.code                     = {\def\macro@a{#1}},
/mykeys/.unknown/.code      = {\let\searchname=\pgfkeyscurrentname
                                               \pgfkeysalso{\searchname/.try=#1,
                                                    /tikz/\searchname/.retry=#1}
                              }    
        }  
\def\mainmacro{\pgfutil@ifnextchar[{\main@macro}{\main@macro[]}}
\def\main@macro[#1](#2)#3{%
\begingroup
  \pgfkeys{mykeys/.cd,
           d = 1,
           a = 45}
  \pgfqkeys{/mykeys}{#1}
  \path (#2) --+(\macro@a:\macro@d) node[/mykeys/.cd,#1] {#3};
\endgroup
}
\makeatother

\begin{document} 

    \begin{tikzpicture}
        \draw (0,0) --( 1,1) coordinate (a) ;
        \mainmacro[a=0,d=12pt,draw,shape=circle](a){label 1}    
        \mainmacro[d=2cm,draw,circle](a){label 2}       
    \end{tikzpicture}

\end{document}

enter image description here

Update

\documentclass[a4paper]{article}
\usepackage{tikz}
\usetikzlibrary{calc}

\makeatletter
\pgfkeys{/mykeys/.cd,
d/.store in                 = {\macro@d},   
a/.store in                 = {\macro@a},
/mykeys/.unknown/.code      = {\let\searchname=\pgfkeyscurrentname
                                               \pgfkeysalso{\searchname/.try=#1,
                                                    /tikz/\searchname/.retry=#1,
                                                    /tikz/.cd,#1}}}  

\def\mainmacro{\pgfutil@ifnextchar[{\main@macro}{\main@macro[]}}
\def\main@macro[#1](#2){%
\begingroup
\pgfkeys{mykeys/.cd,
           d = 1,
           a = 1}
\pgfqkeys{/mykeys}{#1}

\draw[/mykeys/.cd,#1] (\macro@a,\macro@a) circle (\macro@d) --++(1,1) node[#1] {label};% 
\endgroup
}
\makeatother

\begin{document} 
    \begin{tikzpicture}
        \draw (0,0) -- (5,0) ;
        \mainmacro[red,ultra thick](a)       
    \end{tikzpicture}

\end{document}

enter image description here

The trick works for the node but not with \draw perhaps I'm wrong somewhere in my code

  • I think /.store in handler is better here. – percusse Mar 16 '16 at 9:36
  • @percusse why do you think it's better ? there is a document about this ? I have some difficulties with the pgfmanual about this ... a complete example would be better – Alain Matthes Mar 16 '16 at 13:05
  • I guess it handles the current scope better but I don't have any rigorous argument. It might be just a pschological preference. – percusse Mar 16 '16 at 13:07
  • @percusse no psch. because with your code 1. I get an error if I use .code instead of .store in and I am not happy not understand why ! Perhaps it's a new question interesting ? – Alain Matthes Mar 16 '16 at 14:06
  • I think I know why the order matters. I'll check at home. – percusse Mar 30 '16 at 14:54
5

This happens because shape, color names (and some other stuff) are not keys. In other words, when you write red or diamond it doesn't have a dedicated key for such things. Hence, it goes through the TikZ machinery of searchname/.retry but because no such key is there it fails. Instead /tikz/.unknown/.code is much more comprehensive and sophisticated. For example

{%
        % Ok, second chance: This might be an arrow specification:
        \expandafter\pgfutil@in@\expandafter-\expandafter{\tikz@key}%
        \ifpgfutil@in@%
          % Ah, an arrow spec!
          \expandafter\tikz@processarrows\expandafter{\tikz@key}%
        \else%
          % Ok, third chance: A shape!
          \expandafter\ifx\csname pgf@sh@s@\tikz@key\endcsname\relax%
            \pgfkeys{/errors/unknown key/.expand
            once=\expandafter{\expandafter/\expandafter t\expandafter
            i\expandafter k\expandafter z\expandafter/\tikz@key}{##1}}%
          \else%
            \edef\tikz@shape{\tikz@key}%
          \fi%
        \fi%
      }%

I can think of two ways to do this:

  1. You can in the end of the key trial, pass to TikZ explicitly and let it decide what to do. Hence you add the following

    \pgfkeys{/mykeys/.cd,
    d/.store in            = {\macro@d},   
    a/.store in            = {\macro@a},
    /mykeys/.unknown/.code = {\let\searchname=\pgfkeyscurrentname%
                              \pgfkeysalso{\searchname/.try=#1,
                              /tikz/\searchname/.retry=#1,
                              /tikz/.cd,#1}% <--- Now invoked under TikZ
                             }
    }  
    

    Here, we explicitly trigger TikZ unknown machinery since the family is TikZ now. Hence goes through all the shape name checks and so on.

  2. Write your own /.unknown/.code handler to account for known names. For example in Make a PGFkeys path take precedence over another path for a whole scope there are a few examples.

  • I need to study your answer but I agree with you for the diagnostic about the keys. The two ways proposed are interesting. – Alain Matthes Mar 16 '16 at 12:23
  • Your code works with a node but with my new code \draw ... – Alain Matthes Mar 30 '16 at 15:08
4

Here is two simple solutions.

First solution (the better ?)

You may use the /.search also handler (see p.891 of pgfmanual, v3.0.1a):

\documentclass[a4paper]{article}
\usepackage{tikz}
\usetikzlibrary{calc}

\makeatletter
\pgfkeys{
  /mykeys/.cd,
  d/.code                     = {\def\macro@d{#1}},   
  a/.code                     = {\def\macro@a{#1}},
  /mykeys/.search also={/tikz},
}  
\def\mainmacro{\pgfutil@ifnextchar[{\main@macro}{\main@macro[]}}
\def\main@macro[#1](#2)#3{%
\begingroup
  \pgfkeys{mykeys/.cd,
           d = 1,
           a = 45}
  \pgfqkeys{/mykeys}{#1}
  \path (#2) --+(\macro@a:\macro@d) node[/mykeys/.cd,#1] {#3};
\endgroup
}
\makeatother

\begin{document} 

    \begin{tikzpicture}
        \draw (0,0) --( 1,1) coordinate (a) ;
        \mainmacro[a=0,d=12pt,draw,red,shape=circle](a){label 1}    
        \mainmacro[d=2cm,draw,circle](a){label 2}       
    \end{tikzpicture}

\end{document}

Second solution

You may use the /.forward to handler (see p.890 of pgfmanual, v3.0.1a):

\documentclass[a4paper]{article}
\usepackage{tikz}
\usetikzlibrary{calc}

\makeatletter
\pgfkeys{
  /mykeys/.cd,
  d/.code                     = {\def\macro@d{#1}},   
  a/.code                     = {\def\macro@a{#1}},
  /mykeys/.unknown/.forward to=/tikz/\pgfkeyscurrentname,
}  
\def\mainmacro{\pgfutil@ifnextchar[{\main@macro}{\main@macro[]}}
\def\main@macro[#1](#2)#3{%
\begingroup
  \pgfkeys{mykeys/.cd,
           d = 1,
           a = 45}
  \pgfqkeys{/mykeys}{#1}
  \path (#2) --+(\macro@a:\macro@d) node[/mykeys/.cd,#1] {#3};
\endgroup
}
\makeatother

\begin{document} 
    \begin{tikzpicture}
        \draw (0,0) --( 1,1) coordinate (a) ;
        \mainmacro[a=0,d=12pt,draw,red,shape=circle](a){label 1}    
        \mainmacro[d=2cm,draw,circle](a){label 2}       
    \end{tikzpicture}
\end{document}
  • Thanks for the information but I update my question. Nothing works with the new code. – Alain Matthes Mar 30 '16 at 14:50
  • @AlainMatthes /.search also works with your new example... – Paul Gaborit Mar 30 '16 at 14:56
  • Yes great but do you have an explanation because now I'm lost ... – Alain Matthes Mar 30 '16 at 14:57
  • The .search also handler more or less wraps/redirects/aliases the .unknown/.code handler. Paul's code is effectively the same at Percusse's. More strictly I think .search also will intercept arguments passed to a key first, if it is specified. if it doesn't catch the arguments pgf will degrade to .unkown/.code, if that exists (is specified), else pgf will error out. I'm not sure how .search also differs from .forward to. – Carel Jul 1 '16 at 23:18

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.