I'm trying to create a command to show the distributive property of multiplication (for school effects) using tikzmarks and xparse. So far so good, the code is a bit long and I would like to know if I can accomplish this in a more summarized way (the right way ...my code is not very neat).
The subject is like this, I have defined a command \tikzmkpd[...]{...}{...} which receives an optional argument [key=val] and two mandatory arguments separated by commas. With the mandatory arguments it works perfect, the problem I have when trying to implement [key=val]. My idea is that [key=val]works like this:
config-A={yshift={#1},end-yshift={#1,#2,#3},color={#1,#2,#3},distance={#1,#2,#3}},
config-B={yshift={#1},end-yshift={#1,#2,#3},color={#1,#2,#3},distance={#1,#2,#3}}
For now of config-A I only have written the yshift and end-yshift keys that control the spaces of the beginning and end of the arrows that I am drawing with tikz.
My problem is with the key end-yshift={#1,#2,#3} which calls the command auxiliary \endyshift{...}. By using the command \endyshift{...} directly it accepts:
\endyshift{#1}
\endyshift{#1,#2}
\endyshift{#1,#2,#3}
but if I use it in [key=val] it becomes obligatory to pass the three parameters:
end-yshift={#1} % error
end-yshift={#1,#2} % error
end-yshift={#1,#2,#3} % correct
I've tried {} or ,, ` as "empty" arguments, but it doesn't work, besides, I think the code is pretty long and maybe it can be achieved using another strategy.
Here's my question then, can you pass key={v,a,l} where v, a and l execute different code?
This is my example document:
\documentclass{article}
\usepackage{xparse,tikz,etoolbox}
\usetikzlibrary{arrows.meta,bending,calc,tikzmark}
\setlength{\parindent}{0pt} % just for the example
\pagestyle{empty}
% short :)
\newcommand*{\TkM}[2]{\tikzmarknode{#1}{#2}}
% active : for expl3
\makeatletter
\def\@colon{:}
\ExplSyntaxOn
\keys_define:nn { tikzmkpd }
{
config-A .code:n = { \keys_set:nn { tikzmkpd / config-A } { #1 } },
}
% config-A={yshift={#1},end-yshift={#1,#2,#3},color={#1,#2,#3},distance={#1,#2,#3}}
\keys_define:nn { tikzmkpd / config-A }
{
yshift .dim_set:N = \l_yshift_A_dim,
yshift .initial:n = 1.7ex,
yshift-AC .dim_set:N = \l_yshift_AC_dim,
yshift-AC .initial:n = 1.7ex,
yshift-AD .dim_set:N = \l_yshift_AD_dim,
yshift-AD .initial:n = 1.7ex,
yshift-AE .dim_set:N = \l_yshift_AE_dim,
yshift-AE .initial:n = 1.7ex,
distan-AC .dim_set:N = \l_distance_AC_dim,
distan-AC .initial:n = 1.00ex,
distan-AD .dim_set:N = \l_distance_AD_dim,
distan-AD .initial:n = 2.00ex,
distan-AE .dim_set:N = \l_distance_AE_dim,
distan-AE .initial:n = 3.00ex,
colour-AC .tl_set:N = \l_color_AC_tl,
colour-AC .initial:n = red,
colour-AD .tl_set:N = \l_color_AD_tl,
colour-AD .initial:n = green,
colour-AE .tl_set:N = \l_color_AE_tl,
colour-AE .initial:n = blue,
end-yshift .code:n = \endyshift{#1},
% yshiftall .meta:n = {end-yshift={#1}, yshift = #1,}, % not work
}
\NewDocumentCommand { \endyshift } { m }
{
\int_case:nnF { \clist_count:n { #1 } }
{
{1}{\EndACshift {#1}} %
{2}{\EndADshift {#1}} %
{3}{\EndAEshift {#1}} %
}{}
}
\NewDocumentCommand{ \EndACshift }{m}
{
\EndAC#1
}
\cs_new_protected:Npn \EndAC #1
{
\keys_set:nn { tikzmkpd / config-A }
{
yshift-AC = #1,
}
}
\NewDocumentCommand{ \EndADshift }{>{\SplitArgument{1}{,}}m}
{
\EndAD#1
}
\cs_new_protected:Npn \EndAD #1 #2
{
\keys_set:nn { tikzmkpd / config-A }
{
yshift-AC = #1,
yshift-AD = #2,
}
}
\NewDocumentCommand{\EndAEshift}{>{\SplitArgument{2}{,}}m}
{
\EndAE#1
}
\cs_new_protected:Npn \EndAE #1 #2 #3
{
\keys_set:nn { tikzmkpd / config-A }
{
yshift-AC = #1,
yshift-AD = #2,
yshift-AE = #3,
}
}
% case 1: a(c+d) A1(B1+B2)
\cs_new_protected:Npn \_case_one:n
{
\draw[->,color=\l_color_AC_tl] ([yshift=\l_yshift_A_dim]$(pic ~ cs\@colon\csuse{A1})$)
to[out=60,in=120,distance=\l_distance_AC_dim]
([yshift=\l_yshift_AC_dim]$(pic ~ cs\@colon\csuse{B1})$);
\draw[->,,color=\l_color_AD_tl] ([yshift=\l_yshift_A_dim]$(pic ~ cs\@colon\csuse{A1})$)
to[out=60,in=120,distance=\l_distance_AD_dim]
([yshift=\l_yshift_AD_dim]$(pic ~ cs\@colon\csuse{B2})$);
}
% case 2: a(c+d+e) A1(B1+B2+B3)
\cs_new_protected:Npn \_case_two:n
{
\_case_one:n
\draw[->,color=\l_color_AE_tl] ([yshift=\l_yshift_A_dim]$(pic ~ cs\@colon\csuse{A1})$)
to[out=60,in=120,distance=\l_distance_AE_dim]
([yshift=\l_yshift_AE_dim]$(pic ~ cs\@colon\csuse{B3})$);
}
% case 3: (a+b)(c+d) (A1+A2)(B1+B2)
\cs_new_protected:Npn \_case_tree:n
{
\_case_one:n
\draw[->] ([yshift=-0.5ex]$(pic ~ cs\@colon\csuse{A2})$)
to[out=-60,in=-120,distance=1ex] ([yshift=-0.5ex]$(pic ~ cs\@colon\csuse{B1})$);
\draw[->] ([yshift=-0.5ex]$(pic ~ cs\@colon\csuse{A2})$)
to[out=-60,in=-120,distance=2ex] ([yshift=-0.5ex]$(pic ~ cs\@colon\csuse{B2})$);
}
% case 4: (a+b)(c+d+e) (A1+A2)(B1+B2+B3)
\cs_new_protected:Npn \_case_fourth:n
{
\_case_tree:n
\draw[->,color=\l_color_AE_tl] ([yshift=1.7ex]$(pic ~ cs\@colon\csuse{A1})$)
to[out=60,in=120,distance=3.0ex] ([yshift=1.7ex]$(pic ~ cs\@colon\csuse{B3})$);
\draw[->] ([yshift=-0.5ex]$(pic ~ cs\@colon\csuse{A2})$)
to[out=-60,in=-120,distance=3ex] ([yshift=-0.5ex]$(pic ~ cs\@colon\csuse{B3})$);
}
% user command
\NewDocumentCommand{\tikzmkpd}{O{} m m}
{
\group_begin:
\IfNoValueF { #1 } { \keys_set:nn { tikzmkpd }{ #1 } }
\foreach \x [count=\n] in {#2} { \csxdef{A\n}{\x} }% save in A<n>
\foreach \y [count=\m] in {#3} { \csxdef{B\m}{\y} }% save in B<m>
\tikzset{>={Straight ~ Barb[length=1.5pt,round,bend]}}%
\begin{tikzpicture}[overlay,remember ~ picture]%
\bool_if:nTF { \int_compare_p:n { \clist_count:n { #2 } = 1 } &&
\int_compare_p:n { \clist_count:n { #3 } = 2 } } { \_case_one:n }{ }
\bool_if:nTF { \int_compare_p:n { \clist_count:n { #2 } = 1 } &&
\int_compare_p:n { \clist_count:n { #3 } = 3 } } { \_case_two:n }{ }
\bool_if:nTF { \int_compare_p:n { \clist_count:n { #2 } = 2 } &&
\int_compare_p:n { \clist_count:n { #3 } = 2 } } { \_case_tree:n }{ }
\bool_if:nTF { \int_compare_p:n { \clist_count:n { #2 } = 2 } &&
\int_compare_p:n { \clist_count:n { #3 } = 3 } } { \_case_fourth:n }{ }
\end{tikzpicture}
\group_end:
}
\ExplSyntaxOff
\makeatother
\begin{document}
\section{case 1}
$\TkM{A}{2a^2}(\TkM{B}{b}+\TkM{D}{3q})$%
\tikzmkpd[config-A={end-yshift={2ex,2ex,2ex}}]{A}{B,D}
\section{case 2}
$\TkM{a1}{2p}\left(\TkM{b1}{3q}+\TkM{c1}{4r}+\TkM{d1}{1}\right)$
\tikzmkpd{a1}{b1, c1, d1}
\section{case 3}
$(\TkM{X1}{2a^2}+\TkM{X2}{n})(\TkM{Y1}{b}+\TkM{Y2}{3q})$%
\tikzmkpd{X1,X2}{Y1,Y2}
\section{case 4}
$(\TkM{a}{x}-\TkM{b}{2})(\TkM{c}{x^2}+\TkM{d}{2x}+\TkM{e}{4})$
\tikzmkpd{a,b}{c, d, e}
\end{document}
And an example of the output that produces:
Any help is appreciated.
PS: The idea of the command is NOT to write the tikzpicture environment directly into the document.

key={some,thing}by definingkeywithl3keys'.code:nor.tl_set:N, but then for the passed-in contents, you'll have to do the parsing work yourself (unless you delegate tol3keysagain...). Wouldn't it be more natural to use hierarchical keys in the stylemykey/mysubkey=...(see Sub-dividing keys in thel3keysdocumentation)? – frougon Jun 08 '19 at 10:33xparseandetoolbox. That way you avoid mixing pgf keys with other keys. Of course, I do not fully understand what's going on here but the splitting of the arguments can be achieved with the/.listkey handler. – Jun 08 '19 at 16:01expl3is always extensive). Going straight topgfkeysis not an option for me, I don't know it well and it would cause me more problems (I'm new totikz), subdividing the keys seems a good idea to me, I'll try. – Pablo González L Jun 08 '19 at 18:18