3

Inspired by this answer, I would like to have a customized solution environment which accepts an optional argument. This argument can be either numeric or alphabetic, and its value corresponds to the question level whose width is desired to be set to the solution environment.

For example, suppose the question levels have some indices to be: 1 for questions, 2 for parts, 3 for subparts, and 4 for subsubparts. Then the new solution environment might be something like \begin{solution}[2] if I want the solution to span the whole line width of the part environment regardless of where I print this solution.

Finally, if I don't type the optional argument, I would like the width to be set by the parent question level.

\documentclass[answers]{exam}
\usepackage{lipsum}
\usepackage{mdframed}

\renewenvironment{solution}
{\begingroup\par\parshape0%
\begin{mdframed}[skipabove=\baselineskip,
                 innertopmargin=\baselineskip,
                 innerbottommargin=\baselineskip,
                 userdefinedwidth=\textwidth]
\textbf{Solution:}\enspace\ignorespaces}
{\end{mdframed}\par\endgroup}

\begin{document}
    \begin{questions}
        \question A question.
        \begin{parts}
            \part part
            \begin{solution}
                The long solution continues onto another page: \lipsum[1-8]
            \end{solution}
        \end{parts}
    \end{questions}

    \lipsum[1]
\end{document}
frougon
  • 24,283
  • 1
  • 32
  • 55
Diaa
  • 9,599

1 Answers1

4

What you want has been implemented as a package for clean reuse among several documents: the package is called examwsolns and can be found here. Documentation is there too.

Sample usage

Here is an example.tex file that shows how to use this package:

\documentclass[answers]{exam}
\usepackage[framemethod=tikz]{mdframed}
%\usepackage[replace-solution-env]{examwsolns}
\usepackage{examwsolns}
\usepackage{xcolor}
\usepackage{lipsum}
\usepackage{tikz}

% Also possible in the preamble:
% \examwsolnsSetup{replace-solution-env}
% \examwsolnsSetup{replace-solution-env=true}

% Default additional arguments to pass to the 'mdframed' environment
\examwsolnsSetMdFramedDefaultArgs{
  skipabove = \baselineskip,
  innertopmargin = \baselineskip,
  innerbottommargin = \baselineskip,
  userdefinedwidth = \linewidth
}

\begin{document}
Here is a full line:
\par\noindent\hrulefill

\begin{wsolution}
  Autodetected outer level.
\end{wsolution}

\begin{questions}
  \question A question.

    \begin{wsolution}
      Autodetected question level.
    \end{wsolution}

    \begin{parts}
       \part A part
         \begin{wsolution}[][innertopmargin = 2\baselineskip,
                             innerbottommargin = 2\baselineskip,
                             backgroundcolor=gray!40,
                             roundcorner=8pt]
           Autodetected part level.
         \end{wsolution}

         \begin{subparts}
            \subpart A subpart
              \begin{wsolution}
                Autodetected subpart level.
              \end{wsolution}

             \subpart
               \begin{subsubparts}
                 \subsubpart A subsubpart
                   \begin{wsolution}
                     Autodetected subsubpart level.
                   \end{wsolution}

                 \subsubpart Another subsubpart
                   \begin{wsolution}
                     Autodetected subsubpart level.
                   \end{wsolution}
               \end{subsubparts}
          \end{subparts}

       \part Other part
         \begin{wsolution}
           Autodetected part level.
         \end{wsolution}
    \end{parts}

  \question Other question
    \begin{wsolution}
      Autodetected question level.
    \end{wsolution}

    \begin{parts}
      \part A part
        \begin{wsolution}[1]
          Forced at level 1.
        \end{wsolution}

        \begin{wsolution}[2]
          Forced at level 2.
        \end{wsolution}

        \begin{wsolution}[3]
          Forced at level 3. \lipsum[2-8]
        \end{wsolution}

        \begin{wsolution}[4]
          Forced at level 4.

          \lipsum[9]\lipsum[10][1-2]
        \end{wsolution}

        {% \examwsolnsSetMdFramedPreText and \examwsolnsSetMdFramedPostText
         % respect TeX's grouping rules.
          \examwsolnsSetMdFramedPreText{\emph{Sample pre-text} $\langle$}%
          \examwsolnsSetMdFramedPostText{$\rangle$ \emph{Sample post-text}}%
        \begin{wsolution}[3]
          Forced at level 3.
        \end{wsolution}
        }

        \begin{wsolution}[2]
          Forced at level 2.
        \end{wsolution}
    \end{parts}

  \question Last question
    \begin{wsolution}[1]
      Forced at level 1.
    \end{wsolution}

    \begin{wsolution}[0]
      Forced at level 0.
    \end{wsolution}
\end{questions}

Here is a full line for comparison:
\par\noindent\hrulefill
\end{document}

Output for the example.tex file given above

Page 1:

Screenshot for page 1


Page 2:

Screenshot for page 2


Page 3:

Screenshot for page 3

frougon
  • 24,283
  • 1
  • 32
  • 55
  • Many thanks. Your answer is really impressive and exhausting to just read. If you don't mind I would like one final tweak: could you please make the input of the optional argument of zero (i.e. \begin{solution}[0]) results in the width of \textwidth spanning all the space between the left and right margins as done by the MWE in my question? – Diaa May 07 '19 at 00:13
  • 1
    Glad that you liked it (sometimes, people here ask questions, obtain responses that required a lot of work but no one reads them, not even the person who asked...). I've added handling of level 0 (“outer”). If you're still here, I may turn this into a package for clean reuse when you have several documents (probably the environment should have a different name [proposal?], with possibly an option to replace the existing solution environment; also, the optional arguments to mdframed should be parametrizable). – frougon May 07 '19 at 08:15
  • I always have to appreciate the time and effort anyone put in answering my questions with nothing in return. – Diaa May 07 '19 at 08:26
  • For the environment name, it might be something like widesolution as suggested by this answer. – Diaa May 07 '19 at 08:34
  • Additionally, if you would like to check my other unanswered question that might need some sort of programming as well, you can find it here. – Diaa May 07 '19 at 08:37
  • I've updated my answer: 1) What I wrote here is implemented. 2) The package is now hosted externally (see the answer). 3) The environment is called wsolution, where the w suggests this has something to do with width without being too precise. 4) It respects the answers option of the exam class (i.e., the \ifprintanswers conditional). 5) Pre-text and post-text inside the mdframed environment are customizable. – frougon May 11 '19 at 08:48
  • It would be great if you upload it to miktex/texlive to avoid manually downloading every update of it. – Diaa May 11 '19 at 14:56
  • I believe it would be better to contact the maintainer of the exam class (ditto for your other question, by the way). – frougon May 11 '19 at 17:02
  • When trying to create an empty solution box with dots inside as instructed here, the following \begin{solution}[1] \centering \repeatit[3]{\myrepeat{130}{.}\\} \vspace*{\baselineskip} \end{solution} doesn't have an escape vspace (i.e. \vspace*{\baselineskip}) as shown here knowing that I loaded the package with replace-solution-env option. – Diaa Aug 31 '19 at 23:09
  • 1
    I tried to reproduce it but got this: no problem. You could try doing {\centering ... \par}\vspace*{whatever}, possibly followed by \null in case this doesn't work. I'd also suggest doing the dots with \dotfill and replacing the custom loop macros with something standard like \pgffor. No need for \centering, BTW. The following is much simpler and looks good to me: \begin{wsolution}[1] \foreach \i in {1,...,3} {\noindent\dotfill\par} \end{wsolution}result. \foreach is defined in the pgffor package. – frougon Sep 01 '19 at 12:51
  • Thanks for your comment, but I am away from keyboard at the moment to try it. However, I would be highly grateful if you could make your comment as an answer to my previous question. – Diaa Sep 01 '19 at 16:27
  • Sorry, but too many things are unclear. In the other question, the dots have too appear in a question (from the exam point of view), but here, your screenshot shows answer and there is “Answer:” in the box. This has influence on where and how the dots can/should be placed. In my screenshot, the dots starts on the same line as “Solution”. I like it this way, but this is not the case in the aforementioned link. – frougon Sep 01 '19 at 18:26
  • I have no idea if you want them my way or starting on the next line. It's important to know, especially considering the left and right margin requirements in your other question that you linked to here. Besides, you can't expect to control at the same time left & right margin plus length of dotted line: these 3 parameters are linked by a relation, they are not independent. So, things are a bit too unclear for me to answer. Hint: \leftskip and \rightskip could help for the margins. – frougon Sep 01 '19 at 18:29
  • I couldn't get the escape vertical space by \vspace*, but I got it by \par\null\par (is it because you wrote in the package \tl_set:Nn \l_examwsolns_mdframed_post_text_tl { \unskip }?). For the title Answer, I tweaked your package file by adding \underline{\textbf { Answer \tl_to_str:n { : } }} \par\null\par. – Diaa Sep 01 '19 at 21:10
  • For the way the dots are printed, I hope to have control of their density/number in my way of printing the title individually on a single line. – Diaa Sep 01 '19 at 21:31
  • Yes, \unskip is a likely culprit for eating your vertical skip (it doesn't distinguish between vertical and horizontal skips). You can get away with \null or \kern 0pt, but the normal way when you don't want the \unskip would be to do \examwsolnsSetMdFramedPostText{} before the wsolution env that needs the change. Use \begingroup or { before \examwsolnsSetMdFramedPostText{}, and \endgroup or } after the wsolution env(s) in order to limit the scope of the change. You don't need to modify my .sty to use the word “Answer”, ... – frougon Sep 02 '19 at 06:17
  • ... just do something like \examwsolnsSetMdFramedPreText{\textbf{Answer:}\enspace \ignorespaces}, with grouping as explained before if you want to limit the scope. Underlining is ugly. To control the dots, you can use zrefs \zdotfill (probably the easiest way) or directly one of TeX's \leaders, \cleaders and \xleaders commands. For the latter, you can look at LaTeX's definition of \dotfill: \leavevmode \cleaders \hb@xt@ .44em{\hss .\hss }\hfill \kern \z@ and write your own command with similar code but different values (don't forget \makeatletter ... \makeatother). – frougon Sep 02 '19 at 06:27
  • One more comment on the \vspace* problem you encountered: in order to counteract the \unskip, another easy way should be to use (for instance) \par\kern 1cm instead of the \vspace*. This should work because a \kern is not a skip. (Also, contrary to skips, kerns don't get discarded at beginning and end of {lines [for horizontal kerns]} {pages [for vertical kerns]}, but this should matter here unless mdframed is considering breaking the box across two pages). – frougon Sep 02 '19 at 06:30
  • I could push a change so that the pre-text and post-text can be set this way too: \examwsolnsSetup{mdframed-pre-text={\textbf{Answer:}\enspace \ignorespaces}, mdframed-post-text={}} (probably I should have done that from the beginning, as this would have removed the need for \examwsolnsSetMdFramedPreText and \examwsolnsSetMdFramedPostText) . – frougon Sep 02 '19 at 06:41
  • Hello :). I would like to know if it is possible to edit the package by providing a key for default level width. For example, is possible to have something like \usepackage[default-width = outer]{examwsolns}? – Diaa Jul 29 '20 at 17:52
  • 1
    Hello. With examwsolns version 0.4, you can use the new default-level package option: default-level=current|outer|question|part|subpart|subsubpart (the initial value is current, which corresponds to the usual behavior). – frougon Jul 31 '20 at 13:20
  • Thanks for not giving up on this package :). I think you may find it useful to check my relevant last question. Thanks again for the response. – Diaa Jul 31 '20 at 13:41