Precisa-se de especialista em TeX: como \setto(optimal)width?

Precisa-se de especialista em TeX: como \setto(optimal)width?

há um problema que venho tentando resolver há algum tempo, mas sem sucesso até agora. Até onde eu sei, o TeX é muito bom em quebrar linhas de texto de maneira adequada em relação a uma largura fixa de contêiner. O que estou tentando alcançar é diferente: gostaria de poder calcular uma largura "ideal" para um determinado conteúdo.

Por ótimo, quero dizer que existe uma restrição subjacente. Por exemplo, eu gostaria de poder escrever um comando \settooptimalwidth#1#2#3que levasse:

  • #1 como comprimento para ajustar
  • #2 como largura máxima
  • #3 como conteúdo

Se #3 for muito curto (menor que #2), simplesmente faria o mesmo que \settowidth. Se o número 3 for maior que o número 2, ele quebrará o número 3 em linhas como se tivesse sido colocado em uma minicaixa e (essa é a parte complicada) retornaria o comprimento das linhas mais largas entre elas. Estou assumindo aqui que o algoritmo de quebra de linha não está usando o alinhamento "justificado" usual, mas sim irregular à esquerda/direita ou centralização (caso contrário, o problema é irrelevante).

Deixe-me dar alguns exemplos onde tal comando seria útil: * ajuste automático da largura de uma coluna de array cujo conteúdo deve ser centralizado, com potencial quebra de linha, * algum tipo de ambiente de verso alinhado à direita com uma moldura sofisticada. Se o versículo for muito curto, o quadro será pequeno. Se o versículo for muito longo, o texto ficará com uma largura "ideal".

Acho que o caminho a seguir é \unhbox, mas não tenho certeza de como usá-lo. Qualquer ajuda seria apreciada.

Responder1

Como David Carlisle escreveu acima, o pacote varwidthé o caminho a percorrer. Ele fornece o ambiente varwidthque faz o que eu estava pedindo. Aqui está um exemplo mínimo para desenhar texto em um fundo sombreado gradiente usando o 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}

informação relacionada