3

I have trouble understanding how to properly use tikz keys and pass them. Let's say I want to code two tikz pics with both a "fill" argument. I sometimes end up writing things like the example below. But rather than using \ifmyfillA I would like to "pass" the boolean value to cmdB, is there a simple one-line way to do that? This code seems messy but I can't figure out the proper way to do it.

[edit] Changing to true MWE. Now cmdB is drawing a rectangle that can be filled or not. cmdA is just a wrapper calling cmdB. The goal is to get rid of the \if … \else … \fi block, and just replace it with one line.

\documentclass[]{article}
\usepackage{tikz}
\newif\ifmyfillA
\newif\ifmyfillB
\tikzset{
    cmdA/args/fill/.is if=myfillA,
    cmdA/args/fill=false,
    cmdA/.pic={
        \pgfqkeys{/tikz/cmdA/args}{#1}
        \ifmyfillA
            \pic[] at (0,0) {cmdB={fill}};
        \else
            \pic at (0,0) {cmdB={}};
        \fi
    },
    cmdB/args/fill/.is if=myfillB,
    cmdB/args/fill=false,
    cmdB/.pic={
        \pgfqkeys{/tikz/cmdB/args}{#1}
        \ifmyfillB
            \draw[fill] (-1,-1) rectangle (1,1);
        \else
            \draw[] (-1,-1) rectangle (1,1);
        \fi
    }
}
\begin{document}
\begin{tikzpicture}
    \pic[red] at (0,0) {cmdA};
    \pic[blue] at (3,0) {cmdA={fill}};
\end{tikzpicture}
\end{document}

It gives: enter image description here

Zooky
  • 451
  • 1
    I am sorry your question is not very clear to me! I don't understand what are cmdA and cmdB and how they should be related together?

    However see the example in page 889 of the tikz-pgf manual!

    – Hafid Boukhoulda Jan 06 '19 at 17:08
  • They are just 2 pics, that can do anything, the important point is that cmdA is calling cmdB, and cmdB should be called with the "fill" option set to true if and only if cmdA has been called itself with "fill" set to true. – Zooky Jan 06 '19 at 17:12
  • 1
    There is a is if key which is described in a very nice example on p. 889 of the pgfmanual. (But please don not abuse it, otherwise the earth may become flat! ;-) –  Jan 06 '19 at 17:12
  • @ChristianHupfer And the black forest is black. I know. ;-) –  Jan 06 '19 at 17:14
  • I guess your question is rather interesting (+1) but I am not sure I understand what the purpose of cmdB and cmdA is. Isn't cmdA/.pic={ \ifmyfillA \pic at (0,0) {cmdB={fill}} \else \pic at (0,0) {cmdB={}} \fi } a recursion? A pic is a code. And then you tell TikZ to set the pic to be code to call a pic. Please make an MWE that works without is if and then it will be straightforward to add the is if. –  Jan 06 '19 at 17:21
  • Please help us to help you by providing example of such pics into a so called minimal working example MWE that starts with \documentclass and ends with \end{document} – Hafid Boukhoulda Jan 06 '19 at 17:22
  • @mamot @hafid-boukhdoulda Sorry I thought the example would be sufficient. I updated with a full MWE. The question is now, how to avoid the \if… \else… \fi and just directly pass the boolean value. Maybe something like fill=/tikz/cmdA/args/fill… but obviously that's not the way to do it. – Zooky Jan 06 '19 at 17:50
  • Have you tried `\tikzset{cmdB/args/fill./link=cmdA/args/fill,} – Hafid Boukhoulda Jan 06 '19 at 18:54

1 Answers1

2

get rid of the \if… \else… \fi block

  1. With cmdB/args/fill/.is choice we restrain the key to take only one value from a set of predefined values (in our case : true or false).

  2. With cmdB/args/fill/true/.code={<some code>} "some code" is executed whenever the key cmdB/args/fill takes the value true

  3. With cmdB/args/fill/false/.code={<some code>} "some code" is executed whenever the key cmdB/args/fill takes the value false

  4. Depending on the argument #1 ("fill=true" or "fill=false") passed to the pic cmdB, with cmdB/.pic={ \pgfqkeys{/tikz/cmdB/args}{#1}} one of the "some code" stored in (2.) or (.3) will execute.

?

\documentclass[]{article}
\usepackage{tikz}
\tikzset{
    cmdA/.pic={
        \pgfkeyssetvalue{/tikz/cmdA/args}{#1} % /tikz/cdmA /args/fill=true if fill=true is passed as argument
            \pic[] at (0,0) {cmdB={#1}}; 
    },
    cmdB/args/fill/.is choice, %
    cmdB/args/fill/true/.code={\draw[fill] (-1,-1)rectangle(1,1);},
    cmdB/args/fill/false/.code={\draw[](-1,-1)rectangle(1,1);},
    cmdB/.pic={ \pgfqkeys{/tikz/cmdB/args}{#1}} 
}
\begin{document}
\begin{tikzpicture}
    \pic[red] at (0,0) {cmdA={fill=false}};
    \pic[blue] at (3,0) {cmdA={fill=true}};
\end{tikzpicture}
\end{document}

enter image description here

  • What I'm trying to do is not necessarily to get rid of \ifmyfillA and \ifmyfillB (I guess we do need to store the boolean somehow), but to get rid of the \if… \else… \fi block. There should be a way to pass the boolean value of \ifmyfillA as an argument to cmdB ? The solution you are proposing works for this specific case but is not generic enough I think. – Zooky Jan 06 '19 at 21:28
  • @Zooky your question is not clear : you said The goal is to get rid of the \if … \else … \fi block, but it looks that you want to get rid of \pgfqkeys{/tikz/cmdA/args}{#1}. If you pass a boolean value, what will you do without \if ? You should probably give some "meta code" of what you want to be able to do. – Kpym Jan 07 '19 at 07:10
  • @Kpym No, the pgfqkeys is fine. What I'm trying to do is just to access the value stored in \myfillA, without using \ifmyfillA: as far as I'm aware, with boolean values in TeX, you can use such a block \ifmyfillA … \else … \fi, or change the value with e.g. \myfillAtrue, but how do you "read" the value? Think of a scripting language like python, where you could define a function with a keyword argument such as def cmdB(fill=true): \n print(fill) and then, if myfillA is a boolean value, you could just call it using cmdB(fill=myfillA), without having to write a if… else … fi block. – Zooky Jan 07 '19 at 07:44
  • 1
    @Zooky The value stored in \myfillA is the same value stored in the key cmdA/args/fill . You can access the value stored in cmdA/args/fill by \pgfkeysvalueof{cmdA/args/fill} – Hafid Boukhoulda Jan 07 '19 at 07:53
  • @HafidBoukhoulda I think we are getting closer, thanks. Now, I tried to replace the \ifmyfillA … block by \pic at (0,0) {cmdB={fill=\pgfkeysvalueof{/tikz/cmdA/args/fill}}};, and I get a Missing \endcsname inserted. Does it need to be escaped somehow? I find many examples with other kinds of variables, but I have trouble finding examples with booleans (not sure if it's different, from the way it is stored). Well, at least I think the idea of what I'm trying to do is clear now. – Zooky Jan 07 '19 at 08:11
  • @Zooky Answer updated with some explanation – Hafid Boukhoulda Jan 08 '19 at 07:17
  • @HafidBoukhoulda This is indeed much cleaner, thank you! However, even with this solution, you still have one line of code for fill/true and one for fill/false. Which means that if you have 5 different booleans arguments that you want to pass to cmdB… you need to distinguish manually between 2^5 cases? I liked the idea of using \pgfkeysvalueof, isn't there a way to do something like cmdB={bool1=\pgfkeysvalueof{/…/bool1},bool2=\pgfkeysvalueof{/…/bool2},bool3=…} ? I actually have to try again, but maybe now that the value is not stored as a boolean bus in a "is choice", it will work. – Zooky Jan 09 '19 at 13:16
  • @zooky in cmdB={bool1=pgfkeysvalueof{/.../bool1}} what will you do with the first bool1 value except use it in an ifelse statement ? – Hafid Boukhoulda Jan 09 '19 at 18:15