0

One line can be justified as follows: \makebox[\textwidth][s]{<text>}. How can I justify only a part of a line when the width is not known? Of course I can adjust the width by trial and error, but don't want to do it.

The use case is described below.

I use exsheets package and wrapfig to embed figures into exercises.

Exercise 1 represents situation which I normally try to avoid, when there is no text above the figure.

Exercises 2, 3 represent usual situation with one or two lines above the figure. It sometimes looks OK, but always requires a lot of manual work. I need to find where to break the first line and need to make the second line justified with \makebox[][s]{}.

I have different types of exercises with different post-code (shown in square brackets).

Using \hfill after the exercise number post-code is needed to end the line where normal lines of the paragraph end, otherwise it could end too early. But in some cases \hfill produces too much space. Another option is to use \makebox[<width>][s]{<text>}, but since question number with a post-code have variable length, I need to adjust to every question.

If there are more suitable packages and approaches, I'd like to learn about them too.

\documentclass[a4paper,14pt]{extbook}

\usepackage[english,latin]{babel}
\usepackage{wrapfig}  \setlength{\intextsep}{0pt}
\usepackage{graphicx} \graphicspath{{plots/}}

\usepackage[auto-label,counter-within=chapter]{exsheets}

  \SetupExSheets{headings=runin}
  \DeclareInstance{exsheets-heading}{runin}{default}{
    runin = true,
    number-pre-code = \hspace{1em},
    number-post-code =~,
    join = { main[hc,vc]number[l,vc](0em,0pt) }
  }

\begin{document}

~

\begin{wrapfigure}[]{r}{0.39\textwidth}
  \includegraphics[width=0.94\linewidth]{3_1_13}
\end{wrapfigure}
\begin{question}[ID=1]
\texttt{[some text here]}
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.

\end{question}

\noindent\parbox{\linewidth}{
  \begin{question}[ID=2]
  \texttt{[another text]}
  %Lorem ipsum dolor sit amet, consectetur % is not justified
  %\hfill Lorem ipsum dolor sit amet, consectetur % too much space before "Lorem"
  \makebox[0.675\textwidth][s]{ Lorem ipsum dolor sit amet, consectetur} %need to guess the multiplier of the \textwidth

    \begin{wrapfigure}[]{r}{0.39\textwidth}
      \includegraphics[width=0.94\linewidth]{3_1_13}
    \end{wrapfigure}
  \noindent \mbox{adipiscing} elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.

  \end{question}
}

\noindent\parbox{\linewidth}{
  \begin{question}[ID=3]
  \texttt{[something else]}
  \hfill Lorem ipsum dolor sit amet, consectetur adi- % this particular case looks OK, but I'd prefer to use \makebox[<width>][s]{<text>}.

  \makebox[\textwidth][s]{piscing, sed do eiusmod tempor incididunt ut labore et magna. Ut enim}

    \begin{wrapfigure}[]{r}{0.39\textwidth}
      \includegraphics[width=0.94\linewidth]{3_1_13}
    \end{wrapfigure}
  \noindent Ut enim ad enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.

  \end{question}
}

\end{document}

enter image description here

2
  • 1
    I'm not really sure I understand the issue. Just \texttt{[something else]} Lorem ipsum dolor sit amet, consectetur adipiscing, sed do eiusmod tempor incididunt ut labore et magna. Ut enim \begin{wrapfigure}[]{r}{0.39\textwidth} \includegraphics[width=0.94\linewidth, height=1cm]{example-image} \end{wrapfigure} ad enim ad minim veniam looks ok for me, no \hfill, no \makebox, no \noindent. Just make sure there are no empty lines anywhere that start a new paragraph, then place the wrapfigure somewhere in the text (manual adjustment of the break is still needed).
    – Marijn
    Commented Apr 6, 2020 at 13:02
  • Most of the complexity of wrapfig comes from handling multiple paragraphs. If your questions are a single paragraph each, you could do it all using \parshape and tikz[overlay]. Commented Apr 6, 2020 at 15:23

1 Answer 1

2

This solution creates environment myformat to place savebox \illustration a specified number of lines into the text.

The value 2.2em is approximately the indentation due to the question. I really didn't want to dig into exsheets or exbook to determine the precise width.

\documentclass[a4paper,14pt]{extbook}

\usepackage[english,latin]{babel}
\usepackage{graphicx} \graphicspath{{plots/}}
\usepackage{tikz}
\usepackage{lipsum}% MWE only
\usepackage{showframe}% MWE only

\usepackage[auto-label,counter-within=chapter]{exsheets}

  \SetupExSheets{headings=runin}
  \DeclareInstance{exsheets-heading}{runin}{default}{
    runin = true,
    number-pre-code = \hspace{1em},
    number-post-code =~,
    join = { main[hc,vc]number[l,vc](0em,0pt) }
  }

\newsavebox{\illustration}% used to pass image
\newenvironment{myformat}[1]{% #1=line number for start of illustration (1=first)
  \begin{minipage}[t]{\dimexpr \linewidth-2.2em}% kludge
  \setlength{\dimen0}{\dimexpr \textwidth-\wd\illustration-\columnsep}% reduced line width
  \setlength{\dimen1}{\dimexpr \ht\illustration + \dp\illustration}% total height
  \count1=\numexpr \dimen1/\baselineskip\relax
  \ifdim \dimen1>\the\count1\baselineskip\relax
    \advance\count1 by 1
  \fi
  \count2=0% construct \parshape arguments
  \ifnum #1<2\relax
    \edef\shape{\the\numexpr \count1+1}%
  \else
    \edef\shape{\the\numexpr \count1+#1}%
    \loop\advance\count2 by 1
    \ifnum\count2<#1\relax
      \edef\shape{\shape\space 0pt \the\linewidth}%
    \repeat
    \count2=0
  \fi
  \loop\ifnum\count2<\count1
    \edef\shape{\shape\space 0pt \the\dimen0}%
    \advance\count2 by 1
  \repeat
  \edef\shape{\shape\space 0pt \the\linewidth}%
  \parshape=\shape
  \tikz[overlay]{\path ({\textwidth-\wd\illustration},{\ht\strutbox+\baselineskip-#1\baselineskip})
    node[below right, inner sep=0pt]{\usebox\illustration};}%
  \ignorespaces}{\end{minipage}}

\begin{document}

\savebox{\illustration}{\includegraphics[width=0.2\textwidth]{example-image}}%
\begin{question}[ID=1] \begin{myformat}{1}
\texttt{[some text here]}
\LipsumPar{1}
\end{myformat}
\end{question}

\begin{question}[ID=2] \begin{myformat}{2}
  \texttt{[another text]}
  \LipsumPar{1}
  \end{myformat}
  \end{question}

  \begin{question}[ID=3] \begin{myformat}{3}
  \texttt{[something else]}
  \LipsumPar{1}
  \end{myformat}
  \end{question}

\end{document}

Instead of TikZ one can use

  \leavevmode\rlap{\hspace{\dimexpr \textwidth-\wd\illustration}%
    \raisebox{\dimexpr \ht\strutbox+\baselineskip-#1\baselineskip-\ht\illustration}[0pt][0pt]%
      {\usebox\illustration}}%

I developed these as completely separate environments, then figured out how to merge most of the code.

The tricky bit is that question contains a \par and \parshape has to come after the \par but before anything else. So like wrapfig I used \everypar.

This version no longer needs the indentation for question, but instead needs the additional vertical spacing it uses (approximated).

\documentclass[oneside,12pt,a4paper]{book}

\usepackage[english,latin]{babel}
\usepackage{graphicx} \graphicspath{{plots/}}
\usepackage{lipsum}% MWE only
\usepackage{showframe}% MWE only
\usepackage{hyperref}

\usepackage[auto-label,counter-within=chapter]{exsheets}

  \SetupExSheets{headings=runin}
  \DeclareInstance{exsheets-heading}{runin}{default}{
    runin = true,
    number-pre-code = \hspace{1em},
    number-post-code =~,
    join = { main[hc,vc]number[l,vc](0em,0pt) }
  }

\newsavebox{\illustration}% used to pass image
\newenvironment{leftfigure}[1]{% #1=line number for start of illustration (1=first)
  \setlength{\dimen2}{\dimexpr \wd\illustration+\columnsep}% indentation
  \setlength{\dimen0}{\dimexpr \linewidth-\dimen2}% reduced line width
  \setlength{\dimen1}{\dimexpr \ht\illustration + \dp\illustration}% total height
  \setlength{\dimen3}{0pt}% image offset
  \commonfigure{#1}}{}

\newenvironment{rightfigure}[1]{% #1=line number for start of illustration (1=first)
  \setlength{\dimen3}{\dimexpr \linewidth-\wd\illustration}% offset to image
  \setlength{\dimen0}{\dimexpr \dimen3-\columnsep}% reduced line width
  \setlength{\dimen1}{\dimexpr \ht\illustration + \dp\illustration}% total height
  \setlength{\dimen2}{0pt}% indentation
  \commonfigure{#1}}{}

\newcommand{\commonfigure}[1]{% combine environments
  \count1=\numexpr \dimen1/\baselineskip\relax
  \ifdim \dimen1>\the\count1\baselineskip\relax
    \advance\count1 by 1
  \fi
  \count2=0% construct \parshape arguments
  \ifnum #1<2\relax
    \edef\shape{\the\numexpr \count1+1}%
  \else
    \edef\shape{\the\numexpr \count1+#1}%
    \loop\advance\count2 by 1
    \ifnum\count2<#1\relax
      \edef\shape{\shape\space 0pt \the\linewidth}%
    \repeat
    \count2=0
  \fi
  \loop\ifnum\count2<\count1
    \edef\shape{\shape\space \the\dimen2\space \the\dimen0}%
    \advance\count2 by 1
  \repeat
  \edef\shape{\shape\space 0pt \the\linewidth}%
  \par\noindent\rlap{\hspace{\dimen3}% overlap illustration
    \raisebox{\dimexpr \ht\strutbox+\baselineskip-#1\baselineskip-\ht\illustration-0.8ex}% 0.8ex fudge
      [0pt][0pt]{\usebox\illustration}}%
  \strut\vspace{-\baselineskip}% approximate the vertical spacing for question
  \everypar{\parshape=\shape\everypar{}}%
}

\begin{document}

\savebox{\illustration}{\includegraphics[width=0.2\textwidth]{example-image}}%

\begin{rightfigure}{1}
\begin{question}[ID=1]
\texttt{[some text here]}
\LipsumPar{1}
\end{question}
\end{rightfigure}

\begin{rightfigure}{2}
\begin{question}[ID=2]
  \texttt{[another text]}
  \LipsumPar{1}
\end{question}
\end{rightfigure}

\begin{rightfigure}{3}
\begin{question}[ID=3]
  \texttt{[something else]}
  \LipsumPar{1}
\end{question}
\end{rightfigure}

\begin{leftfigure}{1}
\begin{question}[ID=4]
\texttt{[some text here]}
\LipsumPar{1}
\end{question}
\end{leftfigure}

\begin{leftfigure}{2}
\begin{question}[ID=5]
  \texttt{[another text]}
  \LipsumPar{1}
\end{question}
\end{leftfigure}

\begin{leftfigure}{3}
\begin{question}[ID=6]
  \texttt{[something else]}
  \LipsumPar{1}
\end{question}
\end{leftfigure}

\end{document}
14
  • That's cool! I like the way it counts n lines above the figure and justify them. Simple and clear. My exercises are mostly single paragraph each, indeed. However, with wrapfig I can set offset between the image and the text (I'm sure it can be done with tikz as well). Also, the new environment myformat sets its own indents and the question with myformat inside look different (see 1.3 from i.imgur.com/WpeHNoA.png). Also, sometimes I want to place the figure in the left part of the question. Otherwise, this approach is much better than with the wrapfig.
    – pozitron57
    Commented Apr 6, 2020 at 20:31
  • You can add more paragraphs so long as the image is entirely contained within the first. \parshape can be used to adjust the left side as well, I just didn't want to add extra complications. Commented Apr 7, 2020 at 12:56
  • could you please modify your answer to tell how: 1. Reserve white space for the figure. 2. Choose to place it left or right. 3. Not to change the formatting of the questions. Then your answer would be a better alternative to wrapfig.
    – pozitron57
    Commented Apr 8, 2020 at 9:04
  • By "reserve white space" are you talking about \intextsep? Commented Apr 8, 2020 at 16:46
  • I meant to add a white space border to the figure. I realized that it could be done, for example, with clip and trim (negative values) options from graphicx.
    – pozitron57
    Commented Apr 8, 2020 at 17:05

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .