2

there is a problem I have been trying to solve for a while but without success so far. As far as I know, TeX is very good at appropriately breaking text lines with respect to a fixed container width. What I am trying to achieve is different: I would like to be able to compute an "optimal" width for a given content.

By optimal, I mean that there is an underlying constraint. For instance, I would like to be able to write a command \settooptimalwidth#1#2#3 which takes:

  • #1 as a length to adjust
  • #2 as a maximum width
  • #3 as a content

If #3 is very short (shorter than #2), it would simply do the same as \settowidth. If #3 is longer than #2, it would break #3 into lines as if it was put in a minibox, and (that's the tricky part) return the length of the widest lines amongst those. I'm assuming here that the line breaking algorithm is not using the usual "justified" align, but instead raggedleft/right or centering (otherwise the problem is irrelevant).

Let me give a few examples where such a command would be useful: * auto-adjusting the width of an array column whose content is to be centered, with potential line breaking, * some kind of right-aligned verse environment with a fancy frame. If the verse is very short then the frame would be small. If the verse is very long, it would break the text to an "optimal" width.

I think that the way to go is with \unhbox, but I'm not sure how to use it. Any help would be appreciated.

  • 3
    I think you are describing the varwidth environment from the package of that name – David Carlisle Apr 18 '15 at 21:16
2

As David Carlisle wrote above, the package varwidth is the way to go. It provides the environment varwidth which does what I was asking for. Here is a minimal example to draw text on a gradient shaded background using beamer.

\documentclass{beamer}

\usepackage{calc,varwidth}

\colorlet{titleshadeA}{white!30!orange}
\colorlet{titleshadeB}{red!30!black}

\newlength\shadeboxwidth
\newlength\shadeboxheight
\newlength\shadeboxsep
\newcommand\shadebox[4]{%
  \setlength\shadeboxsep{#3}%
  \settowidth\shadeboxwidth{\begin{varwidth}{\textwidth}#4\end{varwidth}}%
  \advance\shadeboxwidth by 2\shadeboxsep%
  \settototalheight\shadeboxheight{\begin{varwidth}{\textwidth}#4\end{varwidth}}%
  \advance\shadeboxheight by 2\shadeboxsep%
  \pgfdeclarehorizontalshading{titleshade}{\shadeboxheight}{%
    color(0mm)=(#1);%
    color(\shadeboxwidth)=(#2)%
  }%
  \rlap{\pgfuseshading{titleshade}}%
  \begin{beamercolorbox}[sep=\shadeboxsep,wd=\shadeboxwidth,ht=\shadeboxheight,dp=0pt]{postit}%
    \color{white}\begin{varwidth}{\textwidth}\raggedleft#4\end{varwidth}%
  \end{beamercolorbox}%
}

\begin{document}
\begin{frame}
\strut\hfill\shadebox{titleshadeA}{titleshadeB}{1ex}{\raggedleft\LARGE Something short}\\
\strut\hfill\shadebox{titleshadeA}{titleshadeB}{1ex}{\raggedleft\LARGE Something very long which will be broken and aligned to the right}\bigskip
\hrule height 2pt\bigskip
Notice how it doesnt spawn the total text width (see the black rule above), but instead adjusts itself to the longest text line of the content.
\end{frame}
\end{document}
  • It would be more courteous to ask DC to write an answer rather than taking credit for his comment! (It would be different if you posted code demonstrating the solution - but there is nothing here not in that comment.) – cfr Apr 18 '15 at 21:57
  • 1
    @cfr i can probably survive without the rep:-) Vincent, to close the loop you should accept your own answer. – David Carlisle Apr 18 '15 at 22:17
  • Oops, my apologies, David. That was my very first post here and I did not realize one get credit for providing useful answers. If you want me to delete mine and provide your own, please tell me. – Vincent Forman Apr 18 '15 at 23:55

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.