Adding the opposite of `open` to arrow tips definitions
Discussed in https://github.com/pgf-tikz/pgf/discussions/1347
Originally posted by Rmano July 9, 2024 Good morning!
If I define a new arrow tip that by default is open, like this (which is still somehow buggy, I can't see exactly why)
%% Jack Tap, see
%% https://github.com/circuitikz/circuitikz/issues/806
\pgfdeclarearrow{name=Jack Tap,
parameters = {%
\the\pgfarrowlength,%
\the\pgfarrowwidth,%
\ifpgfarrowswap s\fi%
\ifpgfarrowopen o\fi%
},
setup code = {
\pgfarrowssettipend{.5\pgfarrowlength}
\pgfarrowssetlineend{-.6\pgfarrowlength}
\pgfarrowssetvisualbackend{-.6\pgfarrowlength}
\pgfarrowssetbackend{-.6\pgfarrowlength}
% hull
\pgfarrowshullpoint{.5\pgfarrowlength}{0pt}
\pgfarrowshullpoint{0pt}{\pgfarrowwidth}
\pgfarrowshullpoint{-.6\pgfarrowlength}{0pt}
% Saves: Only the length:
\pgfarrowssavethe\pgfarrowlength
\pgfarrowssavethe\pgfarrowwidth
},
drawing code = {
\pgfpathmoveto{\pgfqpoint{.5\pgfarrowlength}{0pt}}
\pgfpathlineto{\pgfqpoint{0pt}{\pgfarrowwidth}}
\pgfpathlineto{\pgfqpoint{-.5\pgfarrowlength}{0pt}}
\pgfpathlineto{\pgfqpoint{-.6\pgfarrowlength}{0pt}}
\ifpgfarrowopen
\pgfusepathqstroke
\else
\pgfpathclose\pgfusepathqfillstroke
\fi
},
defaults = {length = 0.3cm, width=0.15cm,open},
% cache=false, % breaks everything
}
\tikzset{v/.tip={Jack Tap[swap]}, ^/.tip={Jack Tap}}
then I can't switch to the not-open (closed, filled?) version without knowing the color, i.e., using Jack Barb[fill=black]. Wouldn't it be useful to add a "complementary" switch for open, like, for example:
\pgfkeys{/pgf/arrow keys/filled/.code=\pgfarrowsaddtooptions{\pgfarrowopenfalse}}
Or maybe closed, to convey the not-open thing?
I tried to search for a complementary flag without success, but if it's already there, please tell me ;-)
Notice that the code of the arrow has been fixed; you can see it here: https://github.com/circuitikz/circuitikz/pull/810/files
I am not posting it because it really isn't that relevant --- the matter is adding a "not open" flag argument. I am using filled for circuitikz, but I'll happily adapt to what is felt to be better.
I think Jack Tap[fill=.] does what you want.
I think
Jack Tap[fill=.]does what you want.
Ah, yes, probably it does. Hmmm... I still like more of a "flag" type, but yes, that's a good solution.
Nope generally one needs Jack Tap[fill=pgfstrokecolor], in which pgfstrokecolor color name is never mentioned in the pgfmanual. But its corresponding pgffillcolor is mentioned in the doc of /pgf/arrow keys/fill.
\documentclass{article}
\usepackage{tikz}
\usetikzlibrary{arrows.meta}
\begin{document}
\pgfkeys{/pgf/arrow keys/filled/.code=\pgfarrowsaddtooptions{\pgfarrowopenfalse}}
\begin{tikzpicture}[nodes={anchor=west}, arrows={[scale=2]}]
\draw[draw=red, fill=gray, -{Stealth}]
(0, 0) -- (1, 0) -- (2,.5) node {default};
\draw[draw=red, fill=gray, yshift=-0.5cm, -{Stealth[cyan]}]
(0, 0) -- (1, 0) -- (2,.5) node {+ cyan};
\draw[draw=red, fill=gray, yshift=-1.0cm, -{Stealth[open, cyan]}]
(0, 0) -- (1, 0) -- (2,.5) node {+ open};
\draw[draw=red, fill=gray, yshift=-1.5cm, -{Stealth[open, cyan, fill=.]}]
(0, 0) -- (1, 0) -- (2,.5) node {current color ``.''};
\draw[draw=red, fill=gray, yshift=-2.0cm, -{Stealth[open, cyan, fill=pgffillcolor]}]
(0, 0) -- (1, 0) -- (2,.5) node {pgffillcolor};
\draw[draw=red, fill=gray, yshift=-2.5cm, -{Stealth[open, cyan, fill=pgfstrokecolor]}]
(0, 0) -- (1, 0) -- (2,.5) node {pgfstrokecolor};
\draw[draw=red, fill=gray, yshift=-3.0cm, -{Stealth[open, cyan, filled]}]
(0, 0) -- (1, 0) -- (2,.5) node {filled};
\end{tikzpicture}
\end{document}
Well, the behavior is not really the same. Look at this (contrived) example:
\documentclass[]{article}
\usepackage[T1]{fontenc}
\usepackage{tikz}
\usetikzlibrary{arrows.meta}
%% Jack Tap, see
%% https://github.com/circuitikz/circuitikz/issues/806
\pgfdeclarearrow{name=Jack Tap,
parameters = {%
\the\pgfarrowlength,%
\the\pgfarrowwidth,%
\ifpgfarrowswap s\fi%
\ifpgfarrowopen o\fi%
\ifpgfarrowroundjoin j\fi
\ifpgfarrowroundcap c\fi%
},
setup code = {
\pgfarrowssettipend{.5\pgfarrowlength}
\pgfarrowssetlineend{-.6\pgfarrowlength}
\pgfarrowssetvisualbackend{-.6\pgfarrowlength}
\pgfarrowssetbackend{-.6\pgfarrowlength}
% hull
\pgfarrowshullpoint{.5\pgfarrowlength}{0pt}
\pgfarrowshullpoint{0pt}{\pgfarrowwidth}
\pgfarrowshullpoint{-.6\pgfarrowlength}{0pt}
% Saves: Only the length:
\pgfarrowssavethe\pgfarrowlength
\pgfarrowssavethe\pgfarrowwidth
},
drawing code = {
\pgfsetdash{}{+0pt}
\pgfarrowlinewidth=\pgflinewidth
\ifpgfarrowroundjoin\pgfsetroundjoin\else\pgfsetmiterjoin\fi
\ifpgfarrowroundcap\pgfsetroundcap\else\pgfsetbuttcap\fi
\pgfpathmoveto{\pgfqpoint{-.6\pgfarrowlength}{0pt}}
\pgfpathlineto{\pgfqpoint{-.5\pgfarrowlength}{0pt}}
\pgfpathlineto{\pgfqpoint{0pt}{\pgfarrowwidth}}
\pgfpathlineto{\pgfqpoint{.5\pgfarrowlength}{0pt}}
\ifpgfarrowopen
\pgfusepathqstroke
\else
\pgfpathclose
\ifdim\pgfarrowlinewidth>0pt\pgfusepathqfillstroke\else\pgfusepathqfill\fi
\fi
},
defaults = {length = 0.3cm, width=0.15cm,open},
% cache=false, % breaks everything
}
\pgfkeys{/pgf/arrow keys/filled/.code=\pgfarrowsaddtooptions{\pgfarrowopenfalse}}
\tikzset{v/.tip={Jack Tap[swap]}, ^/.tip={Jack Tap},
vf/.tip={Jack Tap[swap,filled]}, ^f/.tip={Jack Tap[filled]}}
\begin{document}
\begin{tikzpicture}[color=blue]
\draw[-{Jack Tap}] (0,2) edge ++(2,0) -- ++(0,1);
\draw[red, -{Jack Tap[filled]}] (0,0) edge ++(2,0) -- ++(0,1);
\draw[red, -{Jack Tap[fill=.]}] (0,-2) edge ++(2,0) -- ++(0,1);
\end{tikzpicture}
\end{document}
I would like to avoid adding new keys. Currently Jack Tap[fill] (without argument) gives an error. We could make that work and make it behave like your proposed filled.
Yes, that would be possible too --- although I think that having on/off for binary switch is also a clean interface.
My feeling would be to let fill as it is and add the possibility for open (and probably, for symmetry, swap) to take a boolean, like open=false (default to true).
...thinking about it a bit more, probably the filled flag would be the easiest to add and document. It's just a sentence in the description of open ;-). I know it's a key more, but it's quite buried in the arrow tip hierarchy...
Nice @hmenke, thank you. One little thing: I was trying to provide the fill with no argument for circuitikz now, and I was thinking something like checking for the version of tikz, and then if it's older than 3.1.11 install the code. But (apart from finding how to check the version, which I'll do ;-) later), there is a little problem: is it possible to "undo" the ...fill/.value required?
@Rmano To undo /.value required, currently one has to make use of implementation details of pgfkeys: \cs_undefine:c {pgfk@/pgf/arrow~keys/fill/.@def} does the trick.
https://github.com/pgf-tikz/pgf/blob/44f8137449b34f62bc6371bd442ae5cc98f60f18/tex/generic/pgf/utilities/pgfkeys.code.tex#L853
Example undoing /.value required
\documentclass{article}
\usepackage{tikz}
\usetikzlibrary{arrows.meta}
\begin{document}
\tikzset{/pgf/arrow keys/fill} % errors
\ExplSyntaxOn
\cs_undefine:c {pgfk@/pgf/arrow~keys/fill/.@def}
\ExplSyntaxOff
\tikzset{/pgf/arrow keys/fill} % passes
\end{document}
Thanks @muzimuzhi ! I had managed to arrive at \pgfkeyssetvalue{/pgf/arrow keys/fill/.@def}{}% --- is that equivalent? It seems to work, and should work also for older formats without expl3...
Also, I think that \expandafter\let\csname pgfk@/pgf/arrow keys/fill/.@def\endcsname\@undefined is doing the same thing as the \cs_undefine:c; am I correct?
Also, I think that
\expandafter\let\csname pgfk@/pgf/arrow keys/fill/.@def\endcsname\@undefinedis doing the same thing as the\cs_undefine:c; am I correct?
Yes, that's correct.
@Rmano
I had managed to arrive at
\pgfkeyssetvalue{/pgf/arrow keys/fill/.@def}{}%--- is that equivalent?
From the point of view of pgfkeys, \pgfkeyssetvalue{/pgf/arrow keys/fill/.@def}{} is equivalent to setting /pgf/arrow keys/fill/.default={}, hence slightly different than just undoing effect of /.value required. But it might be the right final form, depending on how #1352 will be modified, see my review https://github.com/pgf-tikz/pgf/pull/1352/files#r1678191162.
Possible final form of workaround for tikz v3.1.10 or older
\IfPackageAtLeastTF{tikz}{2023/01/16}{}{% one day after v3.1.10 (2023-01-15)
\pgfkeys{
/pgf/arrow keys/fill/.code={...}, % new code in v3.1.11 pasted here
/pgf/arrow keys/fill/.default={}
}%
}
@muzimuzhi Thanks - I suppose that the code in your last answer needs LaTeX, am I right? I mean, it would not work in ConTeXt for example...
@Rmano Yes, \IfPackageAtLeastTF needs LaTeX (sorry). For a portable solution, it seems you have to parse the date or version stored in pgf.revision.tex yourself.
$ cat `kpsewhich pgf.revision.tex`
\def\pgfrevision{3.1.10}
\def\pgfversion{3.1.10}
\def\pgfrevisiondate{2023-01-15}
\def\pgfversiondate{2023-01-15}
Thanks @muzimuzhi. Unfortunately, I found that the format of the date changed between 2021 and 2022 --- it was separated by / before... :-(
Maybe I could just check if /pgf/arrow keys/fill/.@def is defined, and if yes, apply the change. Or surrender and just add the filled key and be done...
@Rmano Here is a parser that parses three numbers separated by a single arbitrary non-digit token (or group). It assumes YYYY<sep>MM<sep>dd (optionally followed by another <sep>, <sep> doesn't have to be uniform, it's just gobbled).
\newcount\pdYear
\newcount\pdMonth
\newcount\pdDay
\begingroup
\catcode`\@=11
\unexpanded{\endgroup
% pgfutil replacement code >>>
\let\pgfutil@protected\protected
% <<<
\pgfutil@protected\def\parsedate#1%
{%
\afterassignment\parsedate@month
\pdYear=#1\relax
}
\pgfutil@protected\def\parsedate@month#1%
{%
\afterassignment\parsedate@day
\pdMonth=%
}
\pgfutil@protected\def\parsedate@day#1%
{%
\afterassignment\parsedate@cleanup
\pdDay=%
}
\def\parsedate@cleanup#1\relax{}
}
\def\test#1{\parsedate{#1}\the\pdYear-\the\pdMonth-\the\pdDay\par}
\test{2024-02-01}
\test{2024/02/01}
\test{2024.02.01}
\bye
Keep in mind that you don't have to alter the category code, so don't need the \unexpanded (and if you did, you'd want to use \pgfutil@unexpanded instead for Context support).
@Skillmon thanks again. I was not sure about the \unexpanded thing and grouping there, but it seems that it works ok:
https://github.com/circuitikz/circuitikz/blob/5537c8f2420f43e49fb23887e8d417b96e4313bd/tex/pgfcirc.defines.tex#L269-L319
@Rmano Your code looks good. The \begingroup\catcode`\@=11 \unravel{\endgroup...} is just a scoped \makeatletter...\makeatother and not necessary in package code (since your setup for your code level should already deal with @ being a letter).