16

Context

In my document, I attach a tooltip to the middle part of a word. To demonstrate this behavior, try mousing over just the letter V in the word AVA.

Here is the implementation and usage of my \tooltip command.

%% This tooltip command
\newcommand\tooltip[2]{%
    \special{pdf:bann<</Type/Annot /Subtype/Widget /FT/Btn /Ff 65536 /H/N /TU(#2)>>}%
    #1%
    \special{pdf:eann}%
}

%% is used like so
A\tooltip{V}{Tooltip text here.}A

%% which expands like so.
A\special{…}V\special{…}A

The specifics of making the tooltips are not directly relevant the question, but I have included it for context.

Problem

Separating the parts of the word by interspersing \special{}, i.e. A\special{}V\special{}A causes the kerning between parts to no longer apply.¹ (Note: \special is not special — this behavior also occurs in A{V}A and A{}V{}A, unless one uses XeLaTeX or LuaLaTeX.²)

Partial solution

I was able to restore kerning in the latter two parts using the following command, adapted from this answer, which uses \futurelet to do the trick.

\newcommand\kernright[1]{\def\hltext{#1}\futurelet\hlnext\hldokern}
\def\hldokern{%
    \sbox0{\mbox\hltext\mbox\hlnext}\sbox2{\hltext\hlnext}\kern\dimexpr\wd2-\wd0\relax%
}

(Although that question specifically concerns kerning between different styles, the solution still works. Another more generic question has no satisfactory solution.)

Here are three wrapper commands for \tooltip.

\newcommand\tooltipA[2]{#1}
\newcommand\tooltipB[2]{\tooltip{#1}{#2}}
\newcommand\tooltipC[2]{\tooltip{#1}{#2}\kernright{#1}}

Below is a comparison table and the corresponding rendered image.

                        A\tooltipX{V}{}A expands to             AV kerned?   VA kerned?
                        ‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾             ‾‾‾‾‾‾‾‾‾‾   ‾‾‾‾‾‾‾‾‾‾
A. Normal kerned text   AVA                                     yes          yes
B. Interrupted text     A\special{}V\special{}A                 no           no
C. Partial solution     A\special{}V\special{}\kernright{V}A    no           yes

examples of kerning across empty groups

However, I have not been able to come up with a way to write a \tooltipD command that would also restore kerning between A and V, as there does not appear to be a command that does the “opposite” of \futurelet.

Question

How do I restore the kerning between A and V?

I would expect to insert an additional \kernleft command somewhere in the body of the \tooltipC command to yield an output equivalent to the top part of the image.

MWE

(Tooltips should work in XeLaTeX.³)

\documentclass[varwidth=true]{standalone}
\newcommand\tooltip[2]{%
\special{pdf:bann<</Type/Annot /Subtype/Widget /FT/Btn /Ff 65536 /H/N /TU(#2)>>}%
#1%
\special{pdf:eann}%
}
\newcommand\kernright[1]{\def\hltext{#1}\futurelet\hlnext\hldokern}
\def\hldokern{%
\sbox0{\mbox\hltext\mbox\hlnext}\sbox2{\hltext\hlnext}\kern\dimexpr\wd2-\wd0\relax%
}

% A-C are from original question; D is adapted from Steven's answer
\newcommand\tooltipA[2]{#1}
\newcommand\tooltipB[2]{\tooltip{#1}{#2}}
\newcommand\tooltipC[2]{\tooltip{#1}{#2}\kernright{#1}}
\newcommand\tooltipD[2]{%
    #1%
    \setbox0=\hbox{#1}\kern-\wd0%
    \tooltip{#1}{#2}%
    \kern-\wd0#1%
}

\begin{document}
\tooltip{Foo}{Bar}

A\tooltipA{V}{Tooltip text}A

A\tooltipB{V}{Tooltip text}A

A\tooltipC{V}{Tooltip text}A

A\tooltipD{V}{Tooltip text}A
\end{document}
hftf
  • 2,283
  • 1
    which tex engine and driver are those \special targeted for? – David Carlisle Mar 07 '14 at 08:34
  • Is it just kerns that you need or would you want f\special{}fi to use an ffi ligature. (Solutions involving typesetting the original string might be easier if you do ligatures as well as kerns) – David Carlisle Mar 07 '14 at 09:27
  • @DavidCarlisle I have been using XeLaTeX/xdvipdfmx, but ideally a solution should work in all cases. – hftf Mar 07 '14 at 11:39
  • I hadn't thought about ligatures not applying. (In my document, the A's are often punctuation marks.) Ideally ligatures should also still apply, but I'm not seeing how you would get a tooltip to only cover part of an ffi glyph, for example. – hftf Mar 07 '14 at 11:45
  • well because (apart from using lua) the only general way I can see to do this is to typeset the word without the tooltip and then back up and position the tooltip pdfmark over the word while not typesetting anything, so that you just need to estimate the visual extent of the active region. This only works for pdf style anotations where the anotation is separate from the text in the back end, if you have an html style back end where the annotation has to surround the text then you would have to break ligatures – David Carlisle Mar 07 '14 at 11:49
  • So I don't think there is a totally general solution, it all depends on what the code you are adding is supposed to do. I see Steven's posted an answer using overprinting as I suggest in the previous comment. (I'd better give him a vote:-) – David Carlisle Mar 07 '14 at 11:51

3 Answers3

6

Is an overstrike allowed? If so, this restores the kerning. I don't comprehend the tooltip code, but tried to show what I mean in this MWE. The key to restoring the proper kerning is to start the \tooltip macro on #1 and end it on #1.

I have EDITED to insert \relax after the \kerns, per the OP's warning.

I have re-EDITED, based on comments from the OP. Now that I fully understanding that the first argument to \tooltip isn't just a character, but could conceivably be a word or several words, I have revised my strategy as follows: the only kerning/overstrike that occurs is on the first and last letters of the argument. Thus, spaces and explicit hyphens in the middle of the argument can be used for a linebreak. The one case that still has difficulty is hyphenatable words. This method does not hyphenate, but I'm not quite sure why.

Below is a variant (made to compile in PDFLaTeX) on the file provided by the OP in his comments, to test the kerning of the various methods, A-D, when the methods were stressed with an imminent linebreak. The currently proposed solution is method D, which captures the kerns, but cannot auto-hyphenate.

\documentclass{article}
%\usepackage{fontspec}
\usepackage{xcolor}
%\setmainfont{Minion Pro}
%\setmonofont{Consolas}
\usepackage{stringstrings}

\newcommand\tooltip[2]{%
\special{pdf:bann<</Type/Annot /Subtype/Widget /FT/Btn /Ff 65536 /H/N /TU(#2)>>}%
#1%
\special{pdf:eann}%
}
\newcommand\kernright[1]{\def\hltext{#1}\futurelet\hlnext\hldokern}
\def\hldokern{%
\sbox0{\mbox\hltext\mbox\hlnext}\sbox2{\hltext\hlnext}\kern\dimexpr\wd2-\wd0\relax%
}

\newcommand\tooltipA[2]{#1}
\newcommand\tooltipB[2]{\tooltip{#1}{#2}}
\newcommand\tooltipC[2]{\tooltip{#1}{#2}\kernright{#1}}
\newcommand\tooltipD[2]{%
\firstof#1\relax%
\tooltip{#1}{#2}%
\substring[q]{#1}{$}{$}%
\setbox0=\hbox{\thestring}%
\kern-\wd0\relax\thestring%
}

\def\firstof#1#2\relax{#1\setbox0=\hbox{#1}\kern-\wd0\relax}

\begin{document}
\setlength\parindent{0pt}
\newcommand\lotsofxs{\textcolor{gray!20}{xxxxx xxxxx xxxxx xxxxx xxxxx xxxxx xxxxx xxxxx xxxxx xxxxx xx}}
\newcommand\trial[4]{\lotsofxs{} #2\csname tooltip#1\endcsname{#3}{Tooltip text}#4\par}
\newcommand\fourtrials[4]{
{\texttt{#2|#3|#4}\hfill\textbf{#1}}\par\hrule\par
\trial{A}{#2}{#3}{#4}
\trial{B}{#2}{#3}{#4}
\trial{C}{#2}{#3}{#4}
\trial{D}{#2}{#3}{#4}
\bigskip
}

Default behavior: VAVA\tooltipD{V}{text}AVAV\vspace{1em}

%\rule{\textwidth}{2pt}\par
\fourtrials{Unhyphenatable word (only situation with overflow)}{A}{VxxxxxxxxxxV}{A}
\fourtrials{Multiple words}{A}{Vxxxxx xxxxxV}{A}
\fourtrials{Explicit hyphen}{A}{Vxxxxx\-xxxxxV}{A}
\fourtrials{Hyphenatable word}{‘}{Automatically}{.}
\fourtrials{Multiple words}{‘}{Auto matically}{.}

\end{document}

enter image description here


Original solution:

Conversation with the OP in the comments leads to two points that should be made about this solution. One is that this method will break if a space is in the first argument to \tooltip. The reason is that a space has glue, and glue is not of fixed width. Thus, kerning cannot be used to undo a space.

The second point is that the tooltip in the middle of the word will prevent hyphenation for that word. While this doesn't make the method "broken", it does allow that long words that would otherwise hyphenate will not do so, with a tooltip in their middle. Thus, one could experience margin overruns, not because of the method directly, but because indirectly the normal hyphenation is prevented.

\documentclass{article}
%% This tooltip command
\newcommand\tooltip[2]{%
    #1%
    \setbox0=\hbox{#1}\kern-\wd0\relax%
    \special{pdf:bann<</Type/Annot /Subtype/Widget /FT/Btn /Ff 65536 /H/N /TU(#2)>>}%
    \phantom{#1}%
    \special{pdf:eann}%
    \kern-\wd0\relax#1%
}
\parskip 1ex
\begin{document}
\noindent\rule{\textwidth}{2pt}

The tooltipped word is ``crAVAt,'' with the tooltip on the ``V''.

\noindent$\bullet$ \textbf{As it is supposed to work}

ccvcvf adsakljfd kdfklj sdkljsdf kjsdkj ds fdsfdggfds dd dgfd fsf dsf ddd
crA\tooltip{V}{Tooltip text}At 
dfsf  sdf s sd fsdf sdfsd sd ds sd frsdr d sfsd fds

ccvcvf adsakljfd kdfklj sdkljsdf kjsdkj ds fdsfdggfds dd dgfd fsf dsf dd %d
crA\tooltip{V}{Tooltip text}At 
dfsf  sdf s sd fsdf sdfsd sd ds sd frsdr d sfsd fds

\noindent$\bullet$ \textbf{Tooltip prevents hyphenation, which can cause margin overruns}

ccvcvf adsakljfd kdfklj sdkljsdf kjsdkj ds fdsfdggfds dd dgfd fsf ds
crA\tooltip{V}{Tooltip text}Atinated
the prior word is tooltipped.

ccvcvf adsakljfd kdfklj sdkljsdf kjsdkj ds fdsfdggfds dd dgfd fsf ds
crAVAtinated
the prior word is not tooltipped.

\noindent$\bullet$ \textbf{Spaces (glue)  in tooltip's argument 1 can cause non-alignment of kern}

Here are spaces in the first argument iddsfxsxddgfdxffdxxfgsfdsfdd 
crA\tooltip{V V}{Tooltip text}At 
Here the tooltip was on the ``V V'' in the middle of ``crAV VAt.''


\end{document}

enter image description here

  • It defeats the purpose if the actual tooltip is gone!… It might work for me if I take out \phantom. – hftf Mar 07 '14 at 11:53
  • 1
    @hftf I would also add that it would help us help you if you post a complete MWE in your question; let's say, one that produces the desired tooltip, but doesn't capture the proper kerning. It might help us better understand the requirements, we who don't deal with tooltips. – Steven B. Segletes Mar 07 '14 at 11:58
  • 1
    @hftf I placed the \phantom thinking that all that was required was a horizontal space over which the tooltip would be active. Removing it would be OK, but would result in a triple rather than double strike, of the character. – Steven B. Segletes Mar 07 '14 at 12:02
  • @hftf Alternately, if one wanted to avoid the triple strike, one could change the \phantom{#1} to \color{white}#1\color{black} or perhaps \textcolor{white}{#1}, if one loaded the xcolor package. – Steven B. Segletes Mar 07 '14 at 12:08
  • I've tried this out in my document, and unfortunately it doesn't play nice with line breaks. I also had to insert \relaxes after the kern values to prevent stuff from being gobbled up after numerals and such. – hftf Mar 07 '14 at 13:00
  • @hftf Thanks for the tip regarding the \relaxes. But I have revised my MWE to show that I cannot recreate a problem with line breaks. – Steven B. Segletes Mar 07 '14 at 13:15
  • Can you try this MWE? http://pastebin.com/raw.php?i=zdQjsuqW Here is my output: http://i.imgur.com/viADOwa.png – hftf Mar 07 '14 at 13:27
  • @hftf I'm sorry, my site will not allow me to access the pastebin site. I will say I have noticed there are times where the margin overflows. But in all of those cases, it likewise overflowed with the null \tooltipA, indicating the problem wasn't with the current method, but with a difficult-to-align sentence. – Steven B. Segletes Mar 07 '14 at 13:35
  • 1
    @hftf One other thought. If the tooltip 1st argument includes a space, then this will break my method because a space has glue, which can stretch/compress during typesetting. Also, the other thought is that words that would otherwise hyphenate to break across a line will no longer hyphenate, because the tooltip code in the middle of the word will destroy its search in the dictionary. That could bring on margin overflows indirectly (not because the method is broken, but because a long word can no longer be hyphenated). – Steven B. Segletes Mar 07 '14 at 13:46
  • Sorry if I was unclear about "line breaking"; I meant having the tooltip first argument span two lines (such as by space or hyphenation). I improved my line breaking testcase and put it into a gist here (PDF included): https://gist.github.com/hftf/9413067 As you can see, in each of the five cases tested, the \tooltipD command doesn't have the same appearance as \tooltipA, although the first (unhyphenatable word) comes the closest. – hftf Mar 07 '14 at 15:07
  • (Quick note: I just used XeLaTeX and Minion Pro because I couldn't find an example of a punctuation-letter kern in Computer Modern. The last two examples in your image are missing the before Automatically that demonstrates whether restoring the kerning on the left side of the \tooltip was successful.) – hftf Mar 07 '14 at 16:39
  • @hftf Is that character just a grave accent, as in the left side of a quote? – Steven B. Segletes Mar 07 '14 at 16:42
  • 1
    Yes, but it is not kerned with A in Computer Modern, I believe. – hftf Mar 07 '14 at 16:46
  • Would it make more sense to use your \firstof trick on the left side, and use \kernright (which we know already works) for the right side, to limit the overstriking to just the first letter instead of both the first and last letters? – hftf Mar 07 '14 at 17:01
3

probably I'd just re-add the kerns explictly after measuring the text with and without the adjacent characters being separated by box boundaries.

\documentclass[varwidth=true]{standalone}
\newcommand\tooltip[2]{%
\special{pdf:bann<</Type/Annot /Subtype/Widget /FT/Btn /Ff 65536 /H/N /TU(#2)>>}%
#1%
\special{pdf:eann}%
}


\newcommand\tooltipZ[6]{%
#1%
\kerna{#1}{#2}%
\tooltip{#3}{#4}%
\kerna{#5}{#6}%
#6%
}

\newcommand\kerna[2]{%
\sbox0{#1}\sbox2{#2}\sbox4{#1#2}%
\kern\dimexpr\wd4-\wd0-\wd2\relax}

\begin{document}
\tooltip{Foo}{Bar}

AVA

% #1 pre-char
% #2 first active char
% #3 active text
% #4 tooltip
% #5 last active char
% #6 post-char
\tooltipZ{A}{V}
         {V}{Tooltip text}
         {V}{A}


\end{document}
David Carlisle
  • 757,742
  • Surely you don't even need to separate out the first and last characters? – hftf Aug 23 '15 at 18:05
  • The obvious disadvantage of this solution is that the user would need to pass the pre-char and post-char as arguments \tooltipZ{foo}...{bar} even though they are not part of the tooltip, instead of foo\tooltipZ...bar. – hftf Aug 23 '15 at 18:11
  • @hftf for comment 1, Oh I guess you are right you could drop arguments 2 and 5 and use the entire argument 3 for each measurement (so would just have 4 arguments). For comment 2 think of it as a different interface rather than a disadvantage. a disadvantage would be a loss of functionality:-) – David Carlisle Aug 23 '15 at 20:40
3

My suggestion is to slight re-design the \tooltip syntax. The first parameter of such macro is the whole word, but the highlighted text is surrounded into second braces pair, for example:

\tooltip{A{V}Atar}{avatar}

If there isn't the second brace pair then the whole text is highlighted:

\tooltip{tipped text}{tip}

This can be implemented simply without overlapping letters:

\def\tooltip#1{\tooltipA#1{}\end}
\def\tooltipA#1#{\def\tmpa{#1}\tooltipB}
\def\tooltipB#1#2\end#3{\ifx\end#1\end
   \tooltipC{}\tmpa{}{#3}\else \tooltipC\tmpa{#1}{#2}{#3}\fi
}
\def\tooltipC#1#2#3#4{% #1=pre-text, #2=tipped text, #3=post-text, #4=tip
   #1\kerncorr{#1}{#2}%
   \special{pdf:bann<</Type/Annot /Subtype/Widget /FT/Btn /Ff 65536 /H/N /TU(#4)>>}%
   #2%
   \special{pdf:eann}%
   \kerncorr{#2}{#3}#3%
}
\def\kerncorr#1#2{\setbox0=\hbox{#1\kern0pt #2}\setbox2=\hbox{#1#2}%
   \kern\wd2 \kern-\wd0
}

The hyphenation can be set directly by \- if needed, for example

\tooltip{A{V}A\-tar}{avatar}
wipet
  • 74,238