下面的 MWE 通过\TypsetInBlueOnlyIfCurrentColorIsBlack
宏完全实现了我想要的功能:
\TypsetInBlueOnlyIfCurrentColorIsBlack
旨在将其参数的颜色更改为蓝色,仅有的如果当前颜色是黑色。否则,将使用当前颜色。
问题:
- 我期望
xcolor
会提供一个宏来执行此操作,但找不到它。因此,想知道这种方法是否存在任何明显的问题,或者是否提供了官方接口。
参考:
- 此解决方案改编自如何获取当前颜色的文本表示? 。
代码:
\documentclass{article}
\usepackage{xcolor}
\usepackage{xstring}
%% At this point the default color is black so save that.
\edef\BlackColor{\csname\string\color@.\endcsname}
\makeatletter
\newcommand{\@CurrentColor}{}% Make sure we are not using an existing macro
\newcommand*{\TypsetInBlueOnlyIfCurrentColorIsBlack}[1]{%
\edef\@CurrentColor{\csname\string\color@.\endcsname}% Get current color
\IfStrEq{\@CurrentColor}{\BlackColor}{%
{\bfseries\ttfamily\textcolor{blue}{#1}}% current color IS black
}{%
{\bfseries\ttfamily#1}% current color is NOT black
}%
}
\makeatother
\begin{document}
Following should be in blue:
\TypsetInBlueOnlyIfCurrentColorIsBlack{blue}.
\color{red}
Following should be in red:
\TypsetInBlueOnlyIfCurrentColorIsBlack{red}.
\color{blue}
Following should also be in blue:
\TypsetInBlueOnlyIfCurrentColorIsBlack{blue}.
\end{document}
答案1
接口?expl3
当然是使用!
您\storecolor
可以存储需要进行比较的颜色表示。
我定义了一个通用的比较命令,并且也定义了你的命令作为特例。
在开始文档时,传递给的列表中的每种颜色\storecolors
也会black
在内部表示中进行转换并存储在属性列表中。这是为了提高效率,但实际上并非必要:它节省了评估中的几个步骤。
主命令转换内部表示中的当前颜色,并将其与作为第一个参数给出的颜色进行比较(仅限命名的颜色,但可以概括)。如果测试返回 true,则使用作为第二个参数指定的颜色来打印第三个参数;否则不执行任何颜色更改。
\documentclass{article}
\usepackage{xcolor}
\usepackage{xparse}
\ExplSyntaxOn
\NewDocumentCommand{\perhapschangecolor}{mmm}
{% #1 = color to compare with current
% #2 = color to use if match
% #3 = text
\peter_color_change:nnn { #1 } { #2 } { #3 }
}
% the same but with black and blue preset
\NewDocumentCommand{\TypsetInBlueOnlyIfCurrentColorIsBlack}{m}
{
\perhapschangecolor{black}{blue}{#1}
}
\NewDocumentCommand{\storecolors}{m}
{% black is always stored
\AtBeginDocument { \peter_color_store:n { black,#1 } }
}
\prop_new:N \g_peter_color_stored_prop
\tl_new:N \l__peter_color_current_tl
\cs_new:Nn \peter_color_store:n
{
\hbox_set:Nn \l_tmpa_box
{
\clist_map_inline:nn { #1 }
{
\color{##1}
\driver_color_pickup:N \l_tmpa_tl
\prop_gput:NnV \g_peter_color_stored_prop { ##1 } \l_tmpa_tl
}
}
}
\cs_new_protected:Nn \peter_color_change:nnn
{
\driver_color_pickup:N \l__peter_color_current_tl
\prop_if_in:NnTF \g_peter_color_stored_prop { #1 }
{% more efficient test
\str_if_eq:eeTF
{ \l__peter_color_current_tl }
{ \prop_item:Nn \g_peter_color_stored_prop { #1 } }
{ \textcolor{#2}{#3} }
{ #3 }
}
{
\hbox_set:Nn \l_tmpa_box
{
\color{#1}
\driver_color_pickup:N \l_tmpa_tl
\tl_gset_eq:NN \g_tmpa_tl \l_tmpa_tl
}
\driver_color_pickup:N \l_tmpa_tl
\str_if_eq:eeTF { \g_tmpa_tl } { \l_tmpa_tl }
{ \textcolor{#2}{#3} }
{ #3 }
}
}
\ExplSyntaxOff
\storecolors{red!60}
\begin{document}
Following should be in blue:
\TypsetInBlueOnlyIfCurrentColorIsBlack{blue}
\color{red}
Following should be in red:
\TypsetInBlueOnlyIfCurrentColorIsBlack{red}
\color{blue}
Following should be in blue:
\TypsetInBlueOnlyIfCurrentColorIsBlack{blue}
\color{black}
Following should be in pale red:
\perhapschangecolor{black}{red!60}{red!60}
\color{red!60}
Following should be in pale red:
\perhapschangecolor{black}{red!60}{red!60}
\color{blue}
Following should be in blue:
\perhapschangecolor{black}{red!60}{blue}
% blue has not been stored, but the test succeeds as well
Following should be in pale red:
\perhapschangecolor{blue}{red!60}{red!60}
\end{document}