4

Trying to solve pgf basic layer: struggling (again) with colors, I had an idea for a workaround (saving a state for circuitikz...).

But although I know how to add a hook to the color= key, TikZ let you use just the color as a synonym, and I can't find how to make it work in that case:

\documentclass[border=10pt]{standalone}
\usepackage{tikz}
\tikzset{mykey/.initial=(none)}
\pgfkeys{/tikz/color/.add code={}{\tikzset{mykey={#1}}}}
\begin{document}
\begin{tikzpicture}[]
    \draw[color=red] (0,1) node{I see \pgfkeysvalueof{/tikz/mykey}};
    \draw[red] (0,0) node{I see \pgfkeysvalueof{/tikz/mykey}};
\end{tikzpicture}
\end{document}

enter image description here

Is it possible to "attach" the hook also to the second line?

BTW: I tried this:

\documentclass[border=10pt]{standalone}
\usepackage{tikz}
\usepackage{etoolbox}
\tikzset{mykey/.initial=(none)}
\pgfkeys{/tikz/color/.add code={}{\tikzset{mykey={#1}}}}
\makeatletter
\apptocmd{\tikz@compat@color@set}{\tikzset{mykey={#1}}}%
    {\typeout{color patching ok}}{\typeout{color patching failed}}
\makeatletter
\begin{document}
\begin{tikzpicture}[]
    \draw[color=red] (0,1) node{I see \pgfkeysvalueof{/tikz/mykey}};
    \draw[blue] (0,0) node{I see \pgfkeysvalueof{/tikz/mykey}};
\end{tikzpicture}
\end{document}

which is not giving error, the \tikzset is called, by it still fails (probably a scoping problem).

Rmano
  • 40,848
  • 3
  • 64
  • 125
  • If somebody can point me where the code that manages the "use an unknown option as a color" is... ;-) – Rmano Feb 24 '22 at 12:02
  • 1
    the code is in tikz.code.tex. But imho that here can't work. The core problem is that tikz takes shortcuts, and so all variants (color=red / red / draw=red,fill=red) sets a different set of commands and color. I would suggest a feature request ... – Ulrike Fischer Feb 24 '22 at 12:28

2 Answers2

2

Not an answer but a bit long for a comment. I wrote a command to output various color commands of tikz. Be aware that I don't test every location, colors could e.g. be different in nodes or scopes. But it looks as if you could at least try to use the two global commands \pgf@strokecolor@global and \pgf@fillcolor@global

\documentclass{article}
\usepackage{tikz}

\begin{document} \makeatletter \newcommand\showcolors[1]{% \typeout{^^J#1:^^J========} \typeout{fill: \tikz@fillcolor} \typeout{fill: \csname\string\color@pgffillcolor\endcsname} \typeout{fill (global): \pgf@fillcolor@global} \typeout{stroke:\tikz@strokecolor} \typeout{stroke: \csname\string\color@pgfstrokecolor\endcsname} \typeout{stroke (global): \pgf@strokecolor@global} \typeout{text:\tikz@textcolor} \typeout{text:\csname\string\color@tikzcolor\endcsname} \typeout{current color: \current@color} } \tikzset{showcolors/.code={\showcolors{#1}}}

\color{blue} Text \begin{tikzpicture}[] \tikz\draw[showcolors=nocolors] (0,0);
\tikz[draw=red, fill=green] \draw[showcolors=draw/fill] (0,0);
\tikz[color=yellow] \draw[showcolors=color] (0,0);
\tikz[brown] \draw[showcolors=no key] (0,0);
\end{tikzpicture}

\end{document}

nocolors:
========
fill: 
fill: \\color@pgffillcolor 
fill (global): 0 0 1 rg 0 0 1 RG
stroke:
stroke: 0 0 1 rg 0 0 1 RG
stroke (global): 0 0 1 rg 0 0 1 RG
text:
text:\\color@tikzcolor 
current color: 0 0 1 rg 0 0 1 RG

draw/fill:
========
fill: green
fill: 0 1 0 rg 0 1 0 RG
fill (global): 0 1 0 rg 0 1 0 RG
stroke:red
stroke: 1 0 0 rg 1 0 0 RG
stroke (global): 1 0 0 rg 1 0 0 RG
text:
text:\\color@tikzcolor 
current color: 0 0 1 rg 0 0 1 RG

color:
========
fill: 
fill: \\color@pgffillcolor 
fill (global): 0 0 1 0 k 0 0 1 0 K
stroke:
stroke: 0 0 1 0 k 0 0 1 0 K
stroke (global): 0 0 1 0 k 0 0 1 0 K
text:yellow
text:\\color@tikzcolor 
current color: 0 0 1 rg 0 0 1 RG

no key:
========
fill: 
fill: 0.75 0.5 0.25 rg 0.75 0.5 0.25 RG
fill (global): 0.75 0.5 0.25 rg 0.75 0.5 0.25 RG
stroke:
stroke: 0 0 1 rg 0 0 1 RG
stroke (global): 0.75 0.5 0.25 rg 0.75 0.5 0.25 RG
text:brown
text:\\color@tikzcolor 
current color: 0.75 0.5 0.25 rg 0.75 0.5 0.25 RG

Ulrike Fischer
  • 327,261
  • Thanks, this is useful. The problem is that I do not know how to use the "global" color, they seem to have some internal format... \pgfsetfillcolor does not work, I think. I will mumble a bit more... – Rmano Feb 24 '22 at 15:32
  • @Rmano yes, that is the backend format. And to make life even more complicated it differ between the engines, and if l3color comes into play it gets different again. On the whole it would much nicer if tikz would store the colors by name. – Ulrike Fischer Feb 24 '22 at 15:35
1

In \pgfkeys{/tikz/.unknown/.code=...}, \tikz@compat@color@set is used inside \tikz@addoption{...} which just appends its argument to \tikz@options. Hence \tikz@compat@color@set is not executed until \tikz@options is used at the very end of the current path, by \tikz@finish.

%% run latexdef -p tikz -s tikz@addoption
% tikz.code.tex, line 47:
\def\tikz@addoption#1{%
  \expandafter\def\expandafter\tikz@options\expandafter{\tikz@options#1}}%

To make \tikzset{mykey={#1}} executed immediately, I'm afraid you have to patch the code for key /tikz/.unknown:

\documentclass[border=10pt]{standalone}
\usepackage{tikz}
\usepackage{regexpatch} % for the starred-form of \xpatchcmd

\tikzset{ mykey/.initial=(none), color/.append code={\tikzset{mykey={#1}}} }

\makeatletter % note /tikz/.unknown/.@body is not updated \pgfkeysgetvalue{/tikz/.unknown/.@cmd}{\my@temp} \xpatchcmd*\my@temp % use starred-form to replace all (two places actually) {\expandafter\tikz@addoption\expandafter} {\tikzset{mykey/.expand once=\tikz@key}% \expandafter\tikz@addoption\expandafter} {}{\PatchFailed} \pgfkeyslet{/tikz/.unknown/.@cmd}{\my@temp} \makeatletter

\begin{document} \begin{tikzpicture}[] \draw[color=red] (0,1) node {I see \pgfkeysvalueof{/tikz/mykey}}; \draw[blue] (0,0) node {I see \pgfkeysvalueof{/tikz/mykey}}; \end{tikzpicture} \end{document}

enter image description here

muzimuzhi Z
  • 26,474