3

This question is linked (but not the same) to this other one.

I am trying to make the color in circuitikz more reasonable to use. Now I am struggling with managing colors at a low level. In my shapes, I need to fill parts of them with the specified fill color, and others that should always be filled with the stroke (or draw) color. I naïvely tried this:

\documentclass[border=10pt]{standalone}
\usepackage{tikz}
\pgfdeclareshape{sline}{
    \anchor{center}{\pgfpointorigin}%
    \behindbackgroundpath{
        \pgfpathmoveto{\pgfpoint{-0.3cm}{0pt}}%
        \pgfpathlineto{\pgfpoint{0.3cm}{0pt}}%
        \pgfusepath{draw}%
        % lower rectangle
        \pgfpathrectanglecorners{\pgfpoint{-0.3cm}{-4pt}}{\pgfpoint{0.3cm}{-8pt}}
        \pgfusepath{fill, draw}
        % upper rectangle
        \pgfpathrectanglecorners{\pgfpoint{-0.3cm}{4pt}}{\pgfpoint{0.3cm}{8pt}}
        % \pgfsetfillcolor{cyan}% <- works, always cyan
        \pgfsetfillcolor{pgfstrokecolor}% I expected a red color...
        \pgfusepath{draw, fill}
    }
}
\begin{document}
\color{blue} Text
\begin{tikzpicture}[]
    \draw[] (0,1)  node [sline]{} (1,1) node{aaa};
    \draw[red, fill=green] (0,0)  node [sline]{} (1,0) node{bbb};
\end{tikzpicture}
\end{document}

Which fails as:

enter image description here

So I am here again: there is a way to say: ok, from now on make the fill color equal to the draw (stroke) color? That means that in the above example, the upper rectangle should be filled in red, or in whatever color is specified in the \draw -> like the "bbb" text is doing.

###update

Thanks to Ulrike Fischer, I have more data here. It seems that the simple red, which is the same as color=red, fills the \tikz@textcolor macro but not \tikz@strokecolor, which is empty. If you specify draw=red then you have the other way around. What is strange, is that if you say red, or color=red, the stroke color is red as the text color, so I expected it filled both.

\documentclass[border=10pt]{standalone}
\usepackage{tikz}
\makeatletter
\pgfdeclareshape{sline}{
    \anchor{center}{\pgfpointorigin}%
    \behindbackgroundpath{
        \pgfpathmoveto{\pgfpoint{-0.3cm}{0pt}}%
        \pgfpathlineto{\pgfpoint{0.3cm}{0pt}}%
        \pgfusepath{draw}%
        % lower rectangle
        \pgfpathrectanglecorners{\pgfpoint{-0.3cm}{-4pt}}{\pgfpoint{0.3cm}{-8pt}}
        \pgfusepath{fill, draw}
        % upper rectangle
        \pgfpathrectanglecorners{\pgfpoint{-0.3cm}{4pt}}{\pgfpoint{0.3cm}{8pt}}
        %
        % \pgfsetfillcolor{cyan}% <- works, always cyan
        % \pgfsetfillcolor{pgfstrokecolor}% I expected a red color...
        % \pgfsetfillcolor{\tikz@strokecolor}
        \pgfcircsetfillcolorifnotempty{\tikz@strokecolor}
        % \ifdefempty\tikz@strokecolor{}{\pgfsetfillcolor{\tikz@strokecolor}}
        \typeout{COLORstroke \tikz@strokecolor}
        \typeout{COLORtext \tikz@textcolor}
        \typeout{}
        \pgfusepath{draw, fill}
    }
}
\def\pgfcircsetfillcolorifnotempty#1{%
    \ifx#1\pgfutil@empty
    \else
        \pgfsetfillcolor{#1}%
    \fi
}

\makeatother \begin{document} \color{blue} Text \begin{tikzpicture}[] \draw[] (0,1) node [sline]{} ++(1,0) node[draw,fill]{aaa}; \draw[red, fill=green] (0,0) node [sline]{} ++(1,0) node[draw,fill]{bbb}; \draw[draw=red, fill=green] (0,-1) node [sline]{} ++(1,0) node[draw,fill]{bbb}; \draw[color=red, fill=green] (0,-2) node [sline]{} ++(1,0) node[draw,fill]{bbb}; \end{tikzpicture} \end{document}

enter image description here

and it says:

COLORstroke 
COLORtext

COLORstroke COLORtext red

COLORstroke red COLORtext

COLORstroke COLORtext red

so maybe I have a solution...

Rmano
  • 40,848
  • 3
  • 64
  • 125
  • not quite sure that I understand what you want (and colors in pgf are quite difficult), but perhaps \ifdefempty\tikz@strokecolor{}{\pgfsetfillcolor{\tikz@strokecolor}} – Ulrike Fischer Feb 23 '22 at 17:25
  • @UlrikeFischer thanks, tried, but \tikz@strokecolor is not defined at that point (nor \ifdefempty, really...) – Rmano Feb 24 '22 at 08:35
  • hm, I tested with draw=red, and that it works, but tikz seems not to store the color if only red is used. Perhaps you can find here something https://tex.stackexchange.com/questions/320819/how-to-retrieve-current-stroke-and-fill-color-in-pgf-tikz – Ulrike Fischer Feb 24 '22 at 08:42
  • @UlrikeFischer it seems that I could use \tikz@textcolor, which is filled with the draw color is there is no explicit text= key. I will study Steven's answer you pointed to, but it needs to actively store the color in the draw, it seems, and I'd like to have it transparently work. Yes, I noticed that using draw=red explicitly works... which is strange, red should be equivalent... – Rmano Feb 24 '22 at 08:50
  • Looks like there's no way to retrieve “current” stroke and fill colors in node path, when color is explicitly set by one or more of options draw, fill, and color as path options. The reason is, code for these options are appended to \tikz@options and the latter is not executed until a tikz path ends (in \tikz@finish). But the code for node path is used (and saved in a box) when a node is encountered on a tikz path. The overall order is like \def\tikz@options{\pgfsetcolor{...}} \setbox\nodebox{<node path and text>} \tikz@options \box\nodebox. – muzimuzhi Z Feb 25 '22 at 03:53
  • \path[<color>] is special because a \pgfutil@color{<color>} is executed immediately. Also value of \tikz@strokecolor is not reliable when another draw=<color> is encountered on the same path and after the node. In \draw[draw=red] node[sline] {} [draw=cyan]; the draw=cyan wins but at the time node[sline] {} is saved in a box, it has no info about the following path options. Since a rectangle is simple enough it's possible to do calculations and draw it as a thick line. Otherwise providing a new color option is easier. – muzimuzhi Z Feb 25 '22 at 03:56
  • I think I can use it in the end. What I need is that the upper rectangle is filled with the same color of the draw color used in the shape, for consistency. Anyway, wouldn't be nice to have \tikz@strokecolor (and maybe fill) set in color=red and red. – Rmano Feb 25 '22 at 08:49

1 Answers1

2

Thanks to the help by users in the comments — Ulrike Fischer for providing a tool to explore things, and muzimuzhi Z for this answer and for showing me the internals of TikZ colors, I managed to find a (partial, but still) solution.

That will fail if the user change draw color mid-path, but I think it's the best option for now. Moreover, if the color is changed mid-path it will fail, as shown in the last example --- which is a bit of a pity; if the sline where all red (in the sense that the color was the one at the moment of the building of the behindbackgroundpath I'd be happier, but...).

\documentclass[border=10pt]{standalone}
\usepackage{tikz}
\usepackage{circuitikz}
\usepackage{regexpatch} % for the starred-form of \xpatchcmd
\makeatletter
\let\ctikz@strokecolor\pgfutil@empty
\pgfkeys{/tikz/color/.add code={}{\edef\ctikz@strokecolor{#1}}}
% 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}
    {\edef\ctikz@strokecolor{\tikz@key}%
    \expandafter\tikz@addoption\expandafter}
  {}{%
  \pgfutil@packagewarning{circuitikz}{%
    Color patch failed, expect strange colors (see manual)}}
\pgfkeyslet{/tikz/.unknown/.@cmd}{\my@temp}
%
\pgfdeclareshape{sline}{
    \anchor{center}{\pgfpointorigin}%
    \behindbackgroundpath{
        \pgfpathmoveto{\pgfpoint{-0.3cm}{0pt}}%
        \pgfpathlineto{\pgfpoint{0.3cm}{0pt}}%
        \pgfusepath{draw}%
        % lower rectangle
        \pgfpathrectanglecorners{\pgfpoint{-0.3cm}{-4pt}}{\pgfpoint{0.3cm}{-8pt}}
        \pgfusepath{fill, draw}
        % upper rectangle
        \pgfpathrectanglecorners{\pgfpoint{-0.3cm}{4pt}}{\pgfpoint{0.3cm}{8pt}}
        %
        % \pgfsetfillcolor{cyan}% <- works, always cyan
        \pgf@circ@setfillcolorasdraw
        \pgfusepath{draw, fill}
        \pgfsetcolor{black}
        \pgftext[y=10pt]{\tiny S:\tikz@strokecolor~T:\tikz@textcolor~F:\tikz@fillcolor}
        \pgftext[y=16pt]{\tiny CS:\ctikz@strokecolor}
    }
}
\def\pgf@circ@setfillcolorasdraw{%
    \ifx\tikz@strokecolor\pgfutil@empty
        \ifx\ctikz@strokecolor\pgfutil@empty
            \pgfsetfillcolor{.}
        \else
            \pgfsetfillcolor{\ctikz@strokecolor}
        \fi
    \else
        % we have strokecolor, yay!
        \pgfsetfillcolor{\tikz@strokecolor}
    \fi
}
\makeatother
\begin{document}

\color{blue} Text default is blue \begin{tikzpicture}[baseline=2cm] \draw[] (0,2) node [sline]{} ++(1,0) node[draw,fill]{A} ++(1,0) node[right]{no options}; \draw[red] (0,1) node [sline]{} ++(1,0) node[draw,fill]{B} ++(1,0) node[right]{red}; \draw[red, fill=green] (0,0) node [sline]{} ++(1,0) node[draw,fill]{C} ++(1,0) node[right]{red, fill=green}; \draw[color=red, fill=green] (0,-1) node [sline]{} ++(1,0) node[draw,fill]{D} ++(1,0) node[right]{color=red, fill=green}; \draw[draw=red, fill=green] (0,-2) node [sline]{} ++(1,0) node[draw,fill]{E} ++(1,0) node[right]{draw=red, fill=green}; \draw[text=red, fill=green] (0,-3) node [sline]{} ++(1,0) node[draw,fill]{F} ++(1,0) node[right]{text=red, fill=green}; \draw[red] (0,-4) node [sline]{} ++(1,0) [black] node[draw,fill]{F} ++(1,0) node[right]{red, then black}; \end{tikzpicture}

\end{document}

enter image description here

Now my problem is that I am not sure if this is an enhancement from the previous state of circuitikz... I'll think a bit about it.

Rmano
  • 40,848
  • 3
  • 64
  • 125