我正在制作一个文档,希望词汇表中条目的定义能够作为工具提示出现。
工具提示代码本身来自答案: 无法在工具提示中嵌入超链接引用
我的函数接受 3 个参数,第一个参数是定义工具提示函数的名称,第二个参数是出现在词汇表中的名称 - 可能超过 1 个单词,第三个参数是定义。
\newcommand{\defTerm}[3]{%
\expandafter\newcommand\csname #1\endcsname[1]{%
{\textbf{\tooltip{##1}{\begin{varwidth}{10cm}#3\end{varwidth}}}}%
}%
\newglossaryentry{#1}{name=#2,description={#3}}%
}
理想情况下,带有定义的工具提示也适用于词汇表本身的术语。这意味着在某些情况下,在正文中,第三个参数将包含创建工具提示的命令。
例如:
\defTerm{GP}{GP}{The ground plane.}
\defTerm{Transverse}{Transverse}{This is orthogonal to the \GP{GP}.}
然后在文本中
The \Transverse{transverse} plane is ...
尝试创建包含内容的工具提示时失败
这与 \GP{GP} 正交。
但是\GP{GP}
尝试在其中制作工具提示。
我想要实现的是修改\defTerm
命令,以便在使用工具提示命令时,正则表达式将定义(参数#3
)内的任何命令替换为\textbf
。在普通正则表达式中搜索:(\\[A-Z]\w+{)([a-zA-Z\s]*)(})
并替换为\textbf{$2}
这里我有两个问题。我在测试环境中使用正则表达式,但我不知道如何搜索反斜杠字符。这可能与编译顺序有关。我的第二个问题与如何使用\ExplSyntaxOn
和有关\ExplSyntaxOff
。我工作的不工作的命令是
% Command to add items to glossary and create the command for using tooltips
\newcommand{\defTerm}[3]{%
\expandafter\newcommand\csname #1\endcsname[1]{%
\ExplSyntaxOn
\tl_set:Nn \l_tmpa_tl { #3 }
\regex_replace_all:nnN {([A-Z]\w+{)([a-zA-Z\s]*)(})} {textbf{\2}} \l_tmpa_tl %Also should have backslash
\tl_use:N \l_tmpa_tl
\ExplSyntaxOff
{\textbf{\tooltip{##1}{\begin{varwidth}{10cm}#3\end{varwidth}}}}%
}%
\newglossaryentry{#1}{name=#2,description={#3}}%
}
以下是完整的工作代码。我已将想要进行的更改注释掉。
\documentclass{article}
\usepackage{varwidth} % To allow maximum width boxes in tooltips
\usepackage{tooltips}
\begin{document}
\defTerm{GP}{GP}{The ground plane.}
\defTerm{Transverse}{Transverse}{This is orthogonal to the GP.}
%\defTerm{Transverse}{Transverse}{This is orthogonal to the \GP{GP}.} % What I would like to use instead of the line above
The \Transverse{transverse} plane is ...
\end{document}
下面是 tooltips.sty。说实话,我对 \tootip 命令了解不多。我只需要不带星号的选项,不需要更改字体颜色,因此任何简化都会受到赞赏。
% https://tex.stackexchange.com/questions/397639/cant-embed-hyperlink-references-in-a-tooltip
\ProvidesPackage{tooltips}
% Command to add items to glossary and create the command for using tooltips
\newcommand{\defTerm}[3]{%
\expandafter\newcommand\csname #1\endcsname[1]{%
% \ExplSyntaxOn
% \tl_set:Nn \l_tmpa_tl { #3 }
% \regex_replace_all:nnN {([A-Z]\w+{)([a-zA-Z\s]*)(})} {textbf{\2}} \l_tmpa_tl %Also should have backslash
% \tl_use:N \l_tmpa_tl
% \ExplSyntaxOff
{\textbf{\tooltip{##1}{\begin{varwidth}{10cm}#3\end{varwidth}}}}%
}%
%\newglossaryentry{#1}{name=#2,description={#3}}%
}
\usepackage{pdfbase}[2017/03/16]
\usepackage{xparse,ocgbase}
\usepackage{xcolor,calc}
\usepackage{tikzpagenodes,linegoal}
\usetikzlibrary{calc}
\ExplSyntaxOn
\let\tpPdfLink\pbs_pdflink:nn
\let\tpPdfAnnot\pbs_pdfannot:nnnn\let\tpPdfLastAnn\pbs_pdflastann:
\let\tpAppendToFields\pbs_appendtofields:n
\def\tpPdfXform{\pbs_pdfxform:nnnnn{1}{1}{}{}}
\let\tpPdfLastXform\pbs_pdflastxform:
\let\cListSet\clist_set:Nn\let\cListItem\clist_item:Nn
\ExplSyntaxOff
\makeatletter
\NewDocumentCommand{\tooltip}{%
ssssO{\ifdefined\@linkcolor\@linkcolor\else black\fi}mO{yellow!20}mO{0pt,0pt}%
}{{%
\leavevmode%
\IfBooleanT{#2}{%
%for variants with two and more stars, put tip box on a PDF Layer (OCG)
\ocgbase@new@ocg{tipOCG.\thetcnt}{%
/Print<</PrintState/OFF>>/Export<</ExportState/OFF>>%
}{false}%
\xdef\tpTipOcg{\ocgbase@last@ocg}%
%prevent simultaneous visibility of multiple non-draggable tooltips
\ocgbase@add@ocg@to@radiobtn@grp{tool@tips}{\ocgbase@last@ocg}%
}%
\tpPdfLink{%
\IfBooleanTF{#4}{%
/Subtype/Link/Border[0 0 0]/A <</S/SetOCGState/State [/Toggle \tpTipOcg]>>
}{%
/Subtype/Screen%
/AA<<%
\IfBooleanTF{#3}{%
/E<</S/SetOCGState/State [/Toggle \tpTipOcg]>>%
}{%
\IfBooleanTF{#2}{%
/E<</S/SetOCGState/State [/ON \tpTipOcg]>>%
/X<</S/SetOCGState/State [/OFF \tpTipOcg]>>%
}{
\IfBooleanTF{#1}{%
/E<</S/JavaScript/JS(%
var fd=this.getField('tip.\thetcnt');%
if(typeof(click\thetcnt)=='undefined'){%
var click\thetcnt=false;%
var fdor\thetcnt=fd.rect;var dragging\thetcnt=false;%
}%
if(fd.display==display.hidden){%
fd.delay=true;fd.display=display.visible;fd.delay=false;%
}else{%
if(!click\thetcnt&&!dragging\thetcnt)
{fd.display=display.hidden;}%
if(!dragging\thetcnt){click\thetcnt=false;}%
}%
this.dirty=false;%
)>>%
}{%
/E<</S/JavaScript/JS(%
var fd=this.getField('tip.\thetcnt');%
if(typeof(click\thetcnt)=='undefined'){%
var click\thetcnt=false;%
var fdor\thetcnt=fd.rect;var dragging\thetcnt=false;%
}%
if(fd.display==display.hidden){%
fd.delay=true;fd.display=display.visible;fd.delay=false;%
}%
this.dirty=false;%
)>>%
/X<</S/JavaScript/JS(%
if(!click\thetcnt&&!dragging\thetcnt){fd.display=display.hidden;}%
if(!dragging\thetcnt){click\thetcnt=false;}%
this.dirty=false;%
)>>%
}%
/U<</S/JavaScript/JS(click\thetcnt=true;this.dirty=false;)>>%
/PC<</S/JavaScript/JS (%
var fd=this.getField('tip.\thetcnt');%
try{fd.rect=fdor\thetcnt;}catch(e){}%
fd.display=display.hidden;this.dirty=false;%
)>>%
/PO<</S/JavaScript/JS(this.dirty=false;)>>%
}%
}%
>>%
}%
}{{\color{#5}#6}}%
\sbox\tiptext{%
\IfBooleanT{#2}{%
\ocgbase@oc@bdc{\tpTipOcg}\ocgbase@open@stack@push{\tpTipOcg}}%
\fcolorbox{black}{#7}{#8}%
\IfBooleanT{#2}{\ocgbase@oc@emc\ocgbase@open@stack@pop\tpNull}%
}%
\cListSet\tpOffsets{#9}%
\edef\twd{\the\wd\tiptext}%
\edef\tht{\the\ht\tiptext}%
\edef\tdp{\the\dp\tiptext}%
\tipshift=0pt%
\IfBooleanTF{#2}{%
%OCG-based (that is, all non-draggable) boxes should not extend beyond the
%current column as they may get overlaid by text in the neighbouring column
\setlength\whatsleft{\linegoal}%
}{%
\measureremainder{\whatsleft}%
}%
\ifdim\whatsleft<\dimexpr\twd+\cListItem\tpOffsets{1}\relax%
\setlength\tipshift{\whatsleft-\twd-\cListItem\tpOffsets{1}}\fi%
\IfBooleanF{#2}{\tpPdfXform{\tiptext}}%
\raisebox{\heightof{#6}+\tdp+\cListItem\tpOffsets{2}}[0pt][0pt]{%
\makebox[0pt][l]{\hspace{\dimexpr\tipshift+\cListItem\tpOffsets{1}\relax}%
\IfBooleanTF{#2}{\usebox{\tiptext}}{%
\tpPdfAnnot{\twd}{\tht}{\tdp}{%
/Subtype/Widget/FT/Btn/T (tip.\thetcnt)%
/AP<</N \tpPdfLastXform>>%
/MK<</TP 1/I \tpPdfLastXform/IF<</S/A/FB true/A [0.0 0.0]>>>>%
/Ff 65536/F 3%
/AA <<%
/U <<%
/S/JavaScript/JS(%
var fd=event.target;%
var mX=this.mouseX;var mY=this.mouseY;%
var drag=function(){%
var nX=this.mouseX;var nY=this.mouseY;%
var dX=nX-mX;var dY=nY-mY;%
var fdr=fd.rect;%
fdr[0]+=dX;fdr[1]+=dY;fdr[2]+=dX;fdr[3]+=dY;%
fd.rect=fdr;mX=nX;mY=nY;%
};%
if(!dragging\thetcnt){%
dragging\thetcnt=true;Int=app.setInterval("drag()",1);%
}%
else{app.clearInterval(Int);dragging\thetcnt=false;}%
this.dirty=false;%
)%
>>%
>>%
}%
\tpAppendToFields{\tpPdfLastAnn}%
}%
}}%
\stepcounter{tcnt}%
}}
\makeatother
\newsavebox\tiptext\newcounter{tcnt}
\newlength{\whatsleft}\newlength{\tipshift}
\newcommand{\measureremainder}[1]{%
\begin{tikzpicture}[overlay,remember picture]
\path let \p0 = (0,0), \p1 = (current page.east) in
[/utils/exec={\pgfmathsetlength#1{\x1-\x0}\global#1=#1}];
\end{tikzpicture}%
}
答案1
我建议如下:
\newcommand\tooltip@textbf[9]{\textbf{#6}}
\DeclareExpandableDocumentCommand{\tooltip}{%
ssssO{\ifdefined\@linkcolor\@linkcolor\else black\fi}mO{yellow!20}O{0pt,0pt}m%
}{{%
\expandafter\let\csname tooltip code\endcsname\tooltip@textbf
% ... rest of macro definition here
%
}
这使得\tooltip
将自身定义为\textbf
。请注意\DeclareExpandableDocumentCommand
-- 的参数文本中使用的命令\tooltip
必须是可扩展的(这是嵌套工具提示中发生的错误,因为\tooltip
命令本身不可扩展)。另请注意,我交换了 的参数 8 和 9 的顺序\tooltip
。这是因为可扩展命令不能以可选参数结尾。这避免了对任何花哨的正则表达式的需求。
对于您的\defTerm
命令,我建议您在定义的命令中添加一个特殊前缀和一个特殊的“访问器”命令。这样您就可以拥有一个名称与通用命令相同的术语,并且更容易看出哪些宏是术语。此更改与工具提示问题的解决方案无关。
\newcommand\useTerm[1]{\csname term-#1\endcsname}
\newcommand{\defTerm}[3]{%
\expandafter\newcommand\csname term-#1\endcsname[1]{%
{\tooltip{\textbf{##1}}{\begin{varwidth}{10cm}#3\end{varwidth}}}%
}%
\newglossaryentry{#1}{name=#2,description={#3}}%
}
最后,如果您要使用 expl3 解决方案,请注意,、、\makeatletter
和所有通常都应在命令之外发生。例如:\makeatletter
\ExplSyntaxOn
\ExplSyntaxOff
% Wrong, leads to "Undefined control sequence \tl"
\newcommand\mycommand{%
\ExplSyntaxOn
\tl_set:Nn \l_tmpa_tl { something }
% ... more stuff
\ExplSyntaxOff
}
% Right (or at least it will work)
\ExplSyntaxOn
\newcommand\mycommand{
\tl_set:Nn \l_tmpa_tl { something }
% ... more stuff
}
\ExplSyntaxOff
% Right:
\makeatletter
\newcommand\mycommand{\@firstofone}
\makeatother
好的,这是完整的代码。请注意,我删除了包glossaries
,所以我注释掉了该\newglossaryentry
行。这是因为该glossaries
包与你的问题的任何部分都无关。如果你使用它,你可以放回去\usepackage{glossaries}
并取消注释\newglossaryentry
。
\documentclass{article}
\usepackage{varwidth} % To allow maximum width boxes in tooltips
\usepackage{tooltips}
\begin{document}
\defTerm{GP}{GP}{The ground plane.}
\defTerm{Transverse}{Transverse}{This is orthogonal to the \useTerm{GP}{GP}.} % What I would like to use instead of the line above
The \useTerm{Transverse}{transverse} plane is ...
\end{document}
和tooltips.sty
:
\ProvidesPackage{tooltips}
% Command to add items to glossary and create the command for using tooltips
\newcommand\useTerm[1]{\csname term-#1\endcsname}
\newcommand{\defTerm}[3]{%
\expandafter\newcommand\csname term-#1\endcsname[1]{%
{\tooltip{\textbf{##1}}{\begin{varwidth}{10cm}#3\end{varwidth}}}%
}%
%\newglossaryentry{#1}{name=#2,description={#3}}%
}
\usepackage{pdfbase}[2017/03/16]
\usepackage{xparse,ocgbase}
\usepackage{xcolor,calc}
\usepackage{tikzpagenodes,linegoal}
\usetikzlibrary{calc}
\ExplSyntaxOn
\let\tpPdfLink\pbs_pdflink:nn
\let\tpPdfAnnot\pbs_pdfannot:nnnn\let\tpPdfLastAnn\pbs_pdflastann:
\let\tpAppendToFields\pbs_appendtofields:n
\def\tpPdfXform{\pbs_pdfxform:nnnnn{1}{1}{}{}}
\let\tpPdfLastXform\pbs_pdflastxform:
\let\cListSet\clist_set:Nn\let\cListItem\clist_item:Nn
\ExplSyntaxOff
\makeatletter
\newcommand\tooltip@textbf[9]{{#6}}
\DeclareExpandableDocumentCommand{\tooltip}{%
ssssO{\ifdefined\@linkcolor\@linkcolor\else black\fi}mO{yellow!20}O{0pt,0pt}m%
}{{%
\expandafter\let\csname tooltip code\endcsname\tooltip@textbf
\leavevmode%
\IfBooleanT{#2}{%
%for variants with two and more stars, put tip box on a PDF Layer (OCG)
\ocgbase@new@ocg{tipOCG.\thetcnt}{%
/Print<</PrintState/OFF>>/Export<</ExportState/OFF>>%
}{false}%
\xdef\tpTipOcg{\ocgbase@last@ocg}%
%prevent simultaneous visibility of multiple non-draggable tooltips
\ocgbase@add@ocg@to@radiobtn@grp{tool@tips}{\ocgbase@last@ocg}%
}%
\tpPdfLink{%
\IfBooleanTF{#4}{%
/Subtype/Link/Border[0 0 0]/A <</S/SetOCGState/State [/Toggle \tpTipOcg]>>
}{%
/Subtype/Screen%
/AA<<%
\IfBooleanTF{#3}{%
/E<</S/SetOCGState/State [/Toggle \tpTipOcg]>>%
}{%
\IfBooleanTF{#2}{%
/E<</S/SetOCGState/State [/ON \tpTipOcg]>>%
/X<</S/SetOCGState/State [/OFF \tpTipOcg]>>%
}{
\IfBooleanTF{#1}{%
/E<</S/JavaScript/JS(%
var fd=this.getField('tip.\thetcnt');%
if(typeof(click\thetcnt)=='undefined'){%
var click\thetcnt=false;%
var fdor\thetcnt=fd.rect;var dragging\thetcnt=false;%
}%
if(fd.display==display.hidden){%
fd.delay=true;fd.display=display.visible;fd.delay=false;%
}else{%
if(!click\thetcnt&&!dragging\thetcnt)
{fd.display=display.hidden;}%
if(!dragging\thetcnt){click\thetcnt=false;}%
}%
this.dirty=false;%
)>>%
}{%
/E<</S/JavaScript/JS(%
var fd=this.getField('tip.\thetcnt');%
if(typeof(click\thetcnt)=='undefined'){%
var click\thetcnt=false;%
var fdor\thetcnt=fd.rect;var dragging\thetcnt=false;%
}%
if(fd.display==display.hidden){%
fd.delay=true;fd.display=display.visible;fd.delay=false;%
}%
this.dirty=false;%
)>>%
/X<</S/JavaScript/JS(%
if(!click\thetcnt&&!dragging\thetcnt){fd.display=display.hidden;}%
if(!dragging\thetcnt){click\thetcnt=false;}%
this.dirty=false;%
)>>%
}%
/U<</S/JavaScript/JS(click\thetcnt=true;this.dirty=false;)>>%
/PC<</S/JavaScript/JS (%
var fd=this.getField('tip.\thetcnt');%
try{fd.rect=fdor\thetcnt;}catch(e){}%
fd.display=display.hidden;this.dirty=false;%
)>>%
/PO<</S/JavaScript/JS(this.dirty=false;)>>%
}%
}%
>>%
}%
}{{\color{#5}#6}}%
\sbox\tiptext{%
\IfBooleanT{#2}{%
\ocgbase@oc@bdc{\tpTipOcg}\ocgbase@open@stack@push{\tpTipOcg}}%
\fcolorbox{black}{#7}{#9}%
\IfBooleanT{#2}{\ocgbase@oc@emc\ocgbase@open@stack@pop\tpNull}%
}%
\cListSet\tpOffsets{#8}%
\edef\twd{\the\wd\tiptext}%
\edef\tht{\the\ht\tiptext}%
\edef\tdp{\the\dp\tiptext}%
\tipshift=0pt%
\IfBooleanTF{#2}{%
%OCG-based (that is, all non-draggable) boxes should not extend beyond the
%current column as they may get overlaid by text in the neighbouring column
\setlength\whatsleft{\linegoal}%
}{%
\measureremainder{\whatsleft}%
}%
\ifdim\whatsleft<\dimexpr\twd+\cListItem\tpOffsets{1}\relax%
\setlength\tipshift{\whatsleft-\twd-\cListItem\tpOffsets{1}}\fi%
\IfBooleanF{#2}{\tpPdfXform{\tiptext}}%
\raisebox{\heightof{#6}+\tdp+\cListItem\tpOffsets{2}}[0pt][0pt]{%
\makebox[0pt][l]{\hspace{\dimexpr\tipshift+\cListItem\tpOffsets{1}\relax}%
\IfBooleanTF{#2}{\usebox{\tiptext}}{%
\tpPdfAnnot{\twd}{\tht}{\tdp}{%
/Subtype/Widget/FT/Btn/T (tip.\thetcnt)%
/AP<</N \tpPdfLastXform>>%
/MK<</TP 1/I \tpPdfLastXform/IF<</S/A/FB true/A [0.0 0.0]>>>>%
/Ff 65536/F 3%
/AA <<%
/U <<%
/S/JavaScript/JS(%
var fd=event.target;%
var mX=this.mouseX;var mY=this.mouseY;%
var drag=function(){%
var nX=this.mouseX;var nY=this.mouseY;%
var dX=nX-mX;var dY=nY-mY;%
var fdr=fd.rect;%
fdr[0]+=dX;fdr[1]+=dY;fdr[2]+=dX;fdr[3]+=dY;%
fd.rect=fdr;mX=nX;mY=nY;%
};%
if(!dragging\thetcnt){%
dragging\thetcnt=true;Int=app.setInterval("drag()",1);%
}%
else{app.clearInterval(Int);dragging\thetcnt=false;}%
this.dirty=false;%
)%
>>%
>>%
}%
\tpAppendToFields{\tpPdfLastAnn}%
}%
}}%
\stepcounter{tcnt}%
}}
\makeatother
\newsavebox\tiptext\newcounter{tcnt}
\newlength{\whatsleft}\newlength{\tipshift}
\newcommand{\measureremainder}[1]{%
\begin{tikzpicture}[overlay,remember picture]
\path let \p0 = (0,0), \p1 = (current page.east) in
[/utils/exec={\pgfmathsetlength#1{\x1-\x0}\global#1=#1}];
\end{tikzpicture}%
}