2

I'm using the following code (taken from this site for putting nice underlines under my text.

\usepackage{ulem}
\usepackage{contour}

\renewcommand{\ULdepth}{1.8pt}
\contourlength{0.8pt}

\newcommand{\ul}[1]{%
  \uline{\phantom{#1}}%
  \llap{\contour{white}{#1}}
}

However, when underlining within shaded environments (from the framed package), the whiteness persists around the letters. To fix this, I thought I would add this underneath the code above:

\makeatletter

\def\ifenv#1{
   \def\@tempa{#1}%
   \ifx\@tempa\@currenvir
      \expandafter\@firstoftwo
    \else
      \expandafter\@secondoftwo
   \fi
}

\makeatother

\usepackage{xparse}

\ExplSyntaxOn
\NewDocumentCommand{\newenvcommand}{ m m } % #1 = env name, #2 = command name
{
    \tl_if_exist:cF { g_envc_#1_list_tl } { \tl_new:c { g_envc_#1_list_tl } }
    \tl_gput_right:cn { g_envc_#1_list_tl } { #2 }
    \exp_args:Nc \newcommand { w envc_#1_\cs_to_str:N #2 }
}
\NewDocumentCommand{\checkenvcommands}{ }
{
    \tl_if_exist:cT { g_envc_\use:c {@currenvir} _list_tl }
    {
        \tl_map_inline:cn { g_envc_\use:c {@currenvir} _list_tl }
        {
            \cs_set_eq:Nc ##1 { envc_\use:c {@currenvir} _\cs_to_str:N ##1 }
        }
    }
}
\ExplSyntaxOff

%--Taking the bit below out restores normal underlining
\newenvcommand{shaded}{\ul}[1]{%
  \uline{\phantom{#1}}%
  \llap{\contour{shadedcolor}{#1}}
}

Turns out it didn't work – it even made the normal underline outside the shaded environments stop working entirely.

How can I have two different colour values for \contour without them being in conflict with each other?

MWE:

\documentclass[a4paper,12pt]{report}

%-- Underline:

\usepackage{ulem}
\usepackage{contour}

\renewcommand{\ULdepth}{1.8pt}
\contourlength{0.8pt}

\newcommand{\ul}[1]{%
  \uline{\phantom{#1}}%
  \llap{\contour{white}{#1}}
}

%-- Shaded environment:

\usepackage{framed,color}

\definecolor{shadecolor}{rgb}{.827451,.827451,.827451}

%-- Local commands:

\usepackage{xparse}

\ExplSyntaxOn
\NewDocumentCommand{\newenvcommand}{ m m } % #1 = env name, #2 = command name
{
    \tl_if_exist:cF { g_envc_#1_list_tl } { \tl_new:c { g_envc_#1_list_tl } }
    \tl_gput_right:cn { g_envc_#1_list_tl } { #2 }
    \exp_args:Nc \newcommand { w envc_#1_\cs_to_str:N #2 }
}
\NewDocumentCommand{\checkenvcommands}{ }
{
    \tl_if_exist:cT { g_envc_\use:c {@currenvir} _list_tl }
    {
        \tl_map_inline:cn { g_envc_\use:c {@currenvir} _list_tl }
        {
            \cs_set_eq:Nc ##1 { envc_\use:c {@currenvir} _\cs_to_str:N ##1 }
        }
    }
}
\ExplSyntaxOff

%--Taking the bit below out restores normal underlining
\newenvcommand{shaded}{\ul}[1]{%
  \uline{\phantom{#1}}%
  \llap{\contour{shadedcolor}{#1}}
}

\begin{document}

\ul{Test outside shaded.} %--Works if I take out the \newenvcommand{shaded}{\ul}[1]{…} bit, fails when I put it back.

\begin{shaded}
    \ul{Test inside shaded.} %--Displays white edge if I take out the \newenvcommand{shaded}{\ul}[1]{…} bit, fails when I put it back.
\end{shaded}

\end{document}

I am aware of what the command is doing. On a white background, I create a white edge around letters so that the underline won't cut the letters. That works fine. But on a shadedcolor background I want to change that edge to match that shadedcolor. It's all about getting rid of ugly cuts in letters that go under the underline.

It's just that when I modify that command for a specific environment using \newenvcommand{shaded}{\ul}[1], everything stops working.


EDIT: Forgot to include some code

  1. So apparently I forgot to mention how far down/up I want that underline:
\renewcommand{\ULdepth}{1.8pt}
\contourlength{0.8pt}
  1. And I forgot to mention that I'm using the framed and color packages as well:
\usepackage{framed,color}

\definecolor{shadecolor}{rgb}{.827451,.827451,.827451}
  1. Perhaps this is also worth mentioning:
\makeatletter

\def\ifenv#1{
   \def\@tempa{#1}%
   \ifx\@tempa\@currenvir
      \expandafter\@firstoftwo
    \else
      \expandafter\@secondoftwo
   \fi
}

\makeatother

All these edits have now been added to the code above. Sorry for the inconvenience.

5
  • An MWE would be useful, otherwise there is too much guessing. Contour puts a halo around the letters, following the contours of the glyphs, exactly for the purpose of making the text more legible when placed over an image, graph or shaded background. There is an illustration in the documentation. Default is 16 contours. Why not just do \uline{some text}? Unrelated: your code snippet is missing a }.
    – Cicada
    Nov 28 '19 at 9:36
  • contour places copies of the text underneath (with \rlap) when the outline package option is not being used, using sin and cos to position them with a small circular motion offset, to get the halo effect. For multiple colours, you could perhaps insert code into its loop, making the colour a variable, dependent on (a modulo of) the iteration.
    – Cicada
    Nov 28 '19 at 10:02
  • Literally just do \begin{document} \ul{Test outside shaded.} \begin{shaded} \ul{Test inside shaded.} \end{shaded} \end{document}. I didn't think I'd have to do that to give you context.
    – Matt
    Nov 28 '19 at 12:41
  • Missing } was a mis-paste when I copied it over to StackExchange. Thanks for pointing that out.
    – Matt
    Nov 28 '19 at 12:43
  • 3
    (1) The code doesn't compile as is. You defined an environment command shaded, but not also an environment shaded: add \newenvironment{shaded}{\checkenvcommands}{} to your code. : see tex.stackexchange.com/questions/48073/… (2) Doing a \show\ul inside shaded environment puts >\ul\=relax into the log, so the \ul expands to nothing and the rest prints as normal. (3) Unrelated: when I use \uline{}, it goes underneath the descenders, and nothing is cut off anywhere.
    – Cicada
    Nov 29 '19 at 10:33
2

Not an answer, more a comment with a picture:

The locally defined \ul is no longer \relaxed when copy-pasting @egreg's expl3 code from Defining commands that are scoped to a particular environment exactly, which gives this result (outside the environment = red; inside the environment = blue):

test underline with contour

MWE

\documentclass[a4paper,12pt]{report}
\newcommand\textdescenders{pqrgym}
\usepackage{ulem}
\usepackage{contour}

\newcommand{\ul}[1]{%
  \uline{\phantom{#1}}%
  \llap{\contour{red}{#1}}
}

%%\usepackage{xparse}
%%
%%\ExplSyntaxOn
%%\NewDocumentCommand{\newenvcommand}{ m m } % #1 = env name, #2 = command name
%%{
%%    \tl_if_exist:cF { g_envc_#1_list_tl } { \tl_new:c { g_envc_#1_list_tl } }
%%    \tl_gput_right:cn { g_envc_#1_list_tl } { #2 }
%%    \exp_args:Nc \newcommand { w envc_#1_\cs_to_str:N #2 }
%%}
%%\NewDocumentCommand{\checkenvcommands}{ }
%%{
%%    \tl_if_exist:cT { g_envc_\use:c {@currenvir} _list_tl }
%%    {
%%        \tl_map_inline:cn { g_envc_\use:c {@currenvir} _list_tl }
%%        {
%%            \cs_set_eq:Nc ##1 { envc_\use:c {@currenvir} _\cs_to_str:N ##1 }
%%        }
%%    }
%%}
%%\ExplSyntaxOff

\usepackage{xparse}
\ExplSyntaxOn
\NewDocumentCommand{\newenvcommand}{ m m } % #1 = env name, #2 = command name
  {
   \cs_if_exist:cF { g_envc_#1_list_tl } { \tl_new:c { g_envc_#1_list_tl } }
   \tl_gput_right:cn { g_envc_#1_list_tl } { #2 }
   \exp_after:wN \newcommand \cs:w envc_#1_\cs_to_str:N #2 \cs_end:
  }
\NewDocumentCommand{\checkenvcommands}{ }
  {
   \cs_if_exist:cT { g_envc_\use:c {@currenvir} _list_tl }
     {
      \tl_map_inline:cn { g_envc_\use:c {@currenvir} _list_tl }
        { \cs_set_eq:Nc ##1 { envc_\use:c {@currenvir} _\cs_to_str:N ##1 } }
     }
  }
\ExplSyntaxOff

%--Taking the bit below out restores normal underlining
\newenvcommand{shaded}{\ul}[1]{%
  \uline{\phantom{#1}}%
  \llap{\contour{blue}{#1}
%  \uline{#1}\\
%  \contour{blue}{#1}
  }
}

\newenvironment{shaded}{\checkenvcommands}{}

%\input{the-above-code.tex}
\contourlength{0.6pt}

\begin{document}
\Huge
{\normalsize  \textbackslash uline as is: }

\uline{Test outside shaded. \textdescenders}
\vspace{2ex}

{\normalsize  \textbackslash ul with \texttt{contour:}} 

\ul{Test outside shaded. \textdescenders}

{\normalsize  environment \texttt{shaded} with local \textbackslash ul:} 

\begin{shaded}
%\show\ul
    \ul{Test inside shaded. \textdescenders } %--Displays white edge if I take out the \newenvcommand{shaded}{\ul}[1]{…} bit, fails when I put it back.
\end{shaded}

\end{document}

I still don't see why contour would be needed, or how it could have an effect, since the contour halo is not even reaching far enough to affect the line. But that is unrelated.

egreg's code is always interesting.


Edited to add:

Ah, I think I've worked out why the background circumstances of the question sound so bizarre to me: it's because the ulem package by default does this (which is perfectly OK):

ulem default

And there are two parameters controlling the line -- thickness, via \ULthickness:

ulem uline thickness

and depth, via \ULdepth:

ulem uline depth

The documentation says that default value for \ULdepth is \maxdimen, which changes with the font. So if something is (re)setting \maxdimen to a small or zero value (or no value), and/or setting \ULdepth is not an available action to push the underline back down again (for example, the command is being \relaxed by something more important (and, as yet, unspecified)), then the underline will go through the descenders, as described in the comments. Then, in turn, if a non-ulem workaround is being sought, we arrive at how contour might enter into the picture (indeed, there are old questions/answers on point).

Simple (if that is what's happened).

I thought that perhaps I might have had a different version of ulem, but, since the last update was 2011, that seems unlikely.

As a logistics choice, my inclination would be to start with ulem first, rather than begin with co-opting (an)other package(s), simply because of the implied dependencies being embedded into the maintenance of the solution by that second method. However, that is a different question, and unrelated.


Edit 2:

Contour and ulem work perfectly fine with the different colours:

without the environments

If you want to use egreg's code for scoping commands inside environments, there are three things to do: (1) check for any typing errors that may have crept in when copying from 'over', wherever 'over' is - e.g. how many ds are there in the names?; (2) use egreg's code, as per the linked question is a good source; and (3) actually use the code - defining something is just the first step.

The way you have coded shows that the \ul you are using in the shaded environment is:

not the one

not the one you are intending.

Hint: identify the environment that is actually using the \checkenvcommands command.

The easiest way is to copy egreg's code from the linked question, define your environment that uses that code, and then the \ul is scoped to that environment. Once you do all those changes, the result is:

egreg code environment

MWE:

\documentclass[a4paper,12pt]{report}

\newcommand\testdescenders{pqgrym}

\usepackage{ulem}
\usepackage{contour}

\renewcommand{\ULdepth}{1.8pt}
\contourlength{0.8pt}

\newcommand{\ul}[1]{%
  \uline{\phantom{#1}}%
  \llap{\contour{white}{#1}}
}

%-- Shaded environment:

\usepackage{framed,xcolor}

\usepackage{xparse}
\ExplSyntaxOn
\NewDocumentCommand{\newenvcommand}{ m m } % #1 = env name, #2 = command name
  {
   \cs_if_exist:cF { g_envc_#1_list_tl } { \tl_new:c { g_envc_#1_list_tl } }
   \tl_gput_right:cn { g_envc_#1_list_tl } { #2 }
   \exp_after:wN \newcommand \cs:w envc_#1_\cs_to_str:N #2 \cs_end:
  }
\NewDocumentCommand{\checkenvcommands}{ }
  {
   \cs_if_exist:cT { g_envc_\use:c {@currenvir} _list_tl }
     {
      \tl_map_inline:cn { g_envc_\use:c {@currenvir} _list_tl }
        { \cs_set_eq:Nc ##1 { envc_\use:c {@currenvir} _\cs_to_str:N ##1 } }
     }
  }
\ExplSyntaxOff


\definecolor{shadecolor}{rgb}{.6,.8,.9}

\newenvcommand{xshaded}{\ul}[1]{%
  \uline{\phantom{#1}}%
  \llap{\contour{shadecolor}{#1}}
}


\newenvironment{xshaded}{\checkenvcommands\begin{shaded}}{\end{shaded}}


\begin{document}

\ul{Test outside shaded \testdescenders .}
\begin{xshaded}
    \ul{Test inside shaded \testdescenders .} 
\end{xshaded}


\end{document}

If you want to redefine framed package's shaded environment, that should be a separate question.

=====

Edit

For reference, etoolbox package provides a way to patch existing environments, so the code simplifies to:

MWE

\documentclass[a4paper,12pt]{report}

\newcommand\testdescenders{pqgrym}

\usepackage{ulem}
\usepackage{contour}%default: copies mode; default # copies = 16

%bring the underline nearer to the baseline
\renewcommand{\ULdepth}{1.8pt}
%set a small width of the halo around the text
\contourlength{0.8pt}

%underline is drawn first, then the overlapping text
%white: assumes page colour is white
\newcommand{\ul}[1]{%
  \uline{\phantom{#1}}%
  \llap{\contour{white}{#1}}
}

% framed provides shaded environment:
\usepackage{framed}
\usepackage{xcolor}
\definecolor{shadecolor}{rgb}{.85,.9,.95}


%define command to define local-scope command and repoint environment to local token-list
\usepackage{xparse}
\ExplSyntaxOn
\NewDocumentCommand{\newenvcommand}{ m m } % #1 = env name, #2 = command name
  {
   \cs_if_exist:cF { g_envc_#1_list_tl } { \tl_new:c { g_envc_#1_list_tl } }
   \tl_gput_right:cn { g_envc_#1_list_tl } { #2 }
   \exp_after:wN \newcommand \cs:w envc_#1_\cs_to_str:N #2 \cs_end:
  }
\NewDocumentCommand{\checkenvcommands}{ }
  {
   \cs_if_exist:cT { g_envc_\use:c {@currenvir} _list_tl }
     {
      \tl_map_inline:cn { g_envc_\use:c {@currenvir} _list_tl }
        { \cs_set_eq:Nc ##1 { envc_\use:c {@currenvir} _\cs_to_str:N ##1 } }
     }
  }
\ExplSyntaxOff


%define a local command \ul for framed's shaded environment
\newenvcommand{shaded}{\ul}[1]{%
  \uline{\phantom{#1}}%
  \llap{\contour{shadecolor}{#1}}
}


%patch framed's shaded environment to check for local commands
\usepackage{etoolbox}
\AtBeginEnvironment{shaded}{\checkenvcommands}




\begin{document}

\ul{Test outside shaded \testdescenders .}
\begin{shaded}
    \ul{Test inside shaded \testdescenders .} 
\end{shaded}


\end{document}

Unrelated: If time is a consideration, then compilable code illustrating the problem (an MWE) will more likely generate an answer sooner, in the 6 min - 6 hr range (P > 0.90), rather than the 6 day - 6 week range (P < 0.10) - or never - that a buggy set of random code snippets ever would.

However, since I had earlier (slowly) worked out how to patch contour to run in outline mode under xelatex (in effect, passing pdf literals to the output via xdvipdfmx's \special command), interest in how contour was being applied here has led to a great deal of learning and knowledge, precisely because of "a buggy set of random code snippets".

4
  • Since the actual answer to the question is "fix the typing errors", other questions with similar answers have been voted closed as off-topic (because the solution does not involve Tex). Moreover, since the code which is the basis of the question is a mangled version of egreg's proper code at the linked question, this question can be viewed as a(n indirect) duplicate of that one and, again, a votable candidate for closure. Sidenote: the character used for the wavy underline is char58 in the lasy font from the AMS, being the tail of a photon trail. That font is fixed size, alas.
    – Cicada
    Dec 1 '19 at 9:19
  • Ah, it's because I forgot to copy over all of my code. See my updated MWE. I forgot to mention that I have set my line to purposely intersect with the letters, because then it's close to the actual invisible line the letters sit on. Add \renewcommand{\ULdepth}{1.8pt} and \contourlength{0.8pt} to see what I'm talking about.
    – Matt
    Dec 2 '19 at 17:22
  • Also @egreg told me his original version was outdated, so he gave me a new version in an answer to one of my other questions. I'm not entirely sure what he changed, functionwise, but I see that it is different.
    – Matt
    Dec 2 '19 at 17:24
  • I'm basically doing this alexwlchan.net/2017/10/latex-underlines but want to change my halo to match 1. the document background, and 2. the shaded background.
    – Matt
    Dec 2 '19 at 17:35

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.