0

I am trying to implement command — let's name it fn — aimed to behave like overset command and underline the lower word with some curve. Doing this using TikZ. The lower word is made as node text, and the upper one — as node's label option. And because of that some additional padding is appearing like in MWE below.

\documentclass{article}

\usepackage{tikz}
\usetikzlibrary{calc}
\usepackage{xparse}
\newcommand{\tmpText}{}

\NewDocumentCommand{\fn}{ > { \SplitArgument { 1 } { : } } m }{%
    {%
        \NewDocumentCommand{\tmpSubject}{mm}{%
            \IfValueT{##2}{\renewcommand{\tmpText}{##2}}
            \tikz[baseline=(Root.base)]{%
                \node[inner sep=0pt,
                      outer sep=0pt,
                      label={[yshift=-2,
                              font=\tiny\itshape] \tmpText}] (Root) {##1};
                \draw[line width=0.75]
                    let
                        \p1 = (Root.south west),
                        \p2 = (Root.south east)
                    in
                        (\x1, \y1 - 2) -- (\x2, \y2 - 2);
            }%
        }%
        \tmpSubject#1%
    }%
}


\begin{document}
{\setlength{\fboxsep}{0pt}
    \fbox{\fn{Hello:world}}
    \fbox{\fn{Hello}}
    \fbox{Hello}
}
\end{document}

Which is producing the following output:enter image description here

So, the main question is whether it is possible to correct paddings so that the output would be as follow (color is only for indicating desired area)?enter image description here And of course, if the upper text is wider than lower one, width as well should be corrected to the wider text. Alas, could not find the answer myself neither on forum nor in TikZ.

And the additional question is it a good way to define temporary commands inside another command in terms of performance? Like I defined fn in MWE? My main motivation of such nested macros is not to define function I do not directly need in main document.

Thanks in advance.

1 Answer 1

4

You correctly set the inner sep to 0 for the node but forgot to do so for the label, which is also a node. Once you set it to 0 (or 0.5pt for the optics) there, you no longer need the negative yshift. I also added a %, and marked the position with <-.

\documentclass{article}

\usepackage{tikz}
\usetikzlibrary{calc}
\usepackage{xparse}
\newcommand{\tmpText}{}

\NewDocumentCommand{\fn}{ > { \SplitArgument { 1 } { : } } m }{%
    {%
        \NewDocumentCommand{\tmpSubject}{mm}{%
            \IfValueT{##2}{\renewcommand{\tmpText}{##2}}% <-
            \tikz[baseline=(Root.base)]{%
                \node[inner sep=0pt,
                      outer sep=0pt,
                      label={[inner sep=0.5pt,
                              font=\tiny\itshape] \tmpText}] (Root) {##1};
                \draw[line width=0.75]
                    let
                        \p1 = (Root.south west),
                        \p2 = (Root.south east)
                    in
                        (\x1, \y1 - 2) -- (\x2, \y2 - 2);
            }%
        }%
        \tmpSubject#1%
    }%
}


\begin{document}
{\setlength{\fboxsep}{0pt}
    \fbox{\fn{Hello:world}}
    \fbox{\fn{Hello}}
    \fbox{Hello}
}
\end{document}

enter image description here

Or without calc but with line cap=rect.

\documentclass{article}

\usepackage{tikz}
\usepackage{xparse}
\newcommand{\tmpText}{}

\NewDocumentCommand{\fn}{ > { \SplitArgument { 1 } { : } } m }{%
    {%
        \NewDocumentCommand{\tmpSubject}{mm}{%
            \IfValueT{##2}{\renewcommand{\tmpText}{##2}}%
            \tikz[baseline=(Root.base)]{%
                \node[inner sep=0pt,
                      outer sep=0pt,
                      label={[inner sep=0.5pt,
                              font=\tiny\itshape] \tmpText}] (Root) {##1};
                \draw[line width=0.75,line cap=rect]
                        ([yshift=-2pt]Root.south west)--
                        ([yshift=-2pt]Root.south east);
            }%
        }%
        \tmpSubject#1%
    }%
}


\begin{document}
{\setlength{\fboxsep}{0pt}
    \fbox{\fn{Hello:world}}
    \fbox{\fn{Hello}}
    \fbox{Hello}
}
\end{document}

enter image description here

Or, a third version where we do not allow TikZ to choose the bounding box according to a path that has line cap=rect. To this end, I only insert a coordinate at the bottom and draw the line overlay, i.e. exclude it from the bounding box. This version comes with a comparison with plain \fboxes.

\documentclass{article}

\usepackage{tikz}
\usepackage{xparse}
\newcommand{\tmpText}{}

\NewDocumentCommand{\fn}{ > { \SplitArgument { 1 } { : } } m }{%
    {%
        \NewDocumentCommand{\tmpSubject}{mm}{%
            \IfValueT{##2}{\renewcommand{\tmpText}{##2}}%
            \tikz[baseline=(Root.base)]{%
                \node[inner sep=0pt,
                      outer sep=0pt,
                      label={[inner sep=0.5pt,
                              font=\tiny\itshape] \tmpText}] (Root) {##1};
                \path ([yshift=-2.375pt]Root.south west);             
                \draw[line width=0.75,overlay]
                        ([yshift=-2pt]Root.south west)--
                        ([yshift=-2pt]Root.south east);
            }%
        }%
        \tmpSubject#1%
    }%
}

\newcommand{\cmd}[1]{\texttt{\textbackslash #1}}
\begin{document}
{\setlength{\fboxsep}{0pt}
\begin{tabular}{|@{\,}l@{\,}|c|@{}l@{}|}
\fbox{\fn{Hello:world}} & \cmd{fd} with label & \fbox{\fn{Hello:world}}\\
\fbox{Hello}  & just \cmd{fbox} for comparison & \fbox{Hello}\\
\fbox{\fn{Hello}}  & \cmd{fd} without label & \fbox{\fn{Hello}} \\
\fbox{Hello}  & just \cmd{fbox} for comparison & \fbox{Hello}\\
\end{tabular}}
\end{document}

enter image description here

Let me also draw your attention to the tikzmark library, which comes with the command \tikzmarknode, which detect its ambient text (math mode vs. text mode etc.), which may be of use here.

6
  • Oh, this is great! @marmot, but what to do about the additional spaces on the left? I found out that one space comes from not putting % sign in the end on each line in command declaration, but still there is another inter-word space. Any thoughts why it might happen?
    – Vezzp
    Commented Jul 7, 2019 at 11:43
  • @robur Good catch! You need to add a % after \IfValueT{##2}{\renewcommand{\tmpText}{##2}} since otherwise a space gets inserted.
    – user121799
    Commented Jul 7, 2019 at 11:46
  • @mormot, but after adding % there is still one more space on the left, which I cannot explain. Could you give it a try, please?
    – Vezzp
    Commented Jul 7, 2019 at 12:03
  • @robur I added a third version. What you are (probably) referring to is the fact that TikZ computes the bounding box for lines with line cap=rect. One can switch this off.
    – user121799
    Commented Jul 7, 2019 at 13:48
  • @mormot, I cannot understand why, but I could not reproduce none of your output, alas with your exact codes — still some perceptible spacing! Why else could it be? I can remove it directly with hspace, but it seems there is still a slight difference.
    – Vezzp
    Commented Jul 7, 2019 at 16:31

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .