From 8186542aa5c83c77e3aabe6d3cea54f249423472 Mon Sep 17 00:00:00 2001 From: Karl Berry Date: Mon, 23 May 2011 22:02:31 +0000 Subject: exam 2.4 (23may11) git-svn-id: svn://tug.org/texlive/trunk@22585 c570f23f-e606-0410-a88d-b1316a301751 --- Master/texmf-dist/tex/latex/exam/exam.cls | 2682 +++++++++++++++++++---------- 1 file changed, 1770 insertions(+), 912 deletions(-) (limited to 'Master/texmf-dist/tex/latex/exam/exam.cls') diff --git a/Master/texmf-dist/tex/latex/exam/exam.cls b/Master/texmf-dist/tex/latex/exam/exam.cls index ea3516cbb46..1f4fc6358fc 100644 --- a/Master/texmf-dist/tex/latex/exam/exam.cls +++ b/Master/texmf-dist/tex/latex/exam/exam.cls @@ -18,7 +18,7 @@ % This work consists of the files exam.cls and examdoc.tex. -% The user documentation for exam.cls is in the file examdoc.tex. +% The user's guide for exam.cls is in the file examdoc.tex. %%% Philip Hirschhorn @@ -31,8 +31,8 @@ % from my web page: http://www-math.mit.edu/~psh/ -\def\fileversion{2.3} -\def\filedate{2008/07/19} +\def\fileversion{2.4} +\def\filedate{2011/05/22} %--------------------------------------------------------------------- %--------------------------------------------------------------------- % @@ -82,681 +82,460 @@ % %-------------------------------------------------------------------- %-------------------------------------------------------------------- -% Changelog since version 2.2: +% Changelog since version 2.3: %-------------------------------------------------------------------- -% Version 2.3, 2008/07/16: +% Version 2.4, 2011/05/22: % -% Minor typographic corrections to comments. +% No longer betatest. % %-------------------------------------------------------------------- -% Version 2.222$\beta$, 2008/07/13: +% Version 2.321$\beta$, 2011/05/15: % -% Corrected a typo in the error message displayed when -% \shadedsolutions is used without having said \usepackage{color}. +% New environments: EnvUplevel and EnvFullwidth % -%-------------------------------------------------------------------- -% Version 2.221$\beta$, 2008/07/03: +% The EnvUplevel environment is similar to the command \uplevel, +% except that \uplevel is a command taking one argument. The +% EnvUplevel environment has the advantage that you can include +% verbatim material (using, e.g., the \verb command) in the +% environment. (You can't include verbatim material in the argument +% of an \uplevel command.) % -% \themarginpoints used to expand to -% \@points \@marginpointname -% whether the points were bonus or non-bonus. We fixed that, so that -% it expands to either -% \@points \@marginbonuspointname -% or -% \@points \@marginpointname -% depending on whether or not the points are bonus points. +% The EnvFullwidth environment is similar to the command \fullwidth, +% except that \fullwidth is a command taking one argument. The +% EnvFullwidth environment has the advantage that you can include +% verbatim material (using, e.g., the \verb command) in the +% environment. (You can't include verbatim material in the argument +% of a \fullwidth command.) % %-------------------------------------------------------------------- -% Version 2.220$\beta$, 2008/05/24: +% Version 2.320$\beta$, 2011/04/16: % -% New command: \fillwithdottedlines -% New environment: solutionordottedlines +% New document class options: cancelspace +% nocancelspace +% New commands: \cancelspace +% \nocancelspace % +% Using the document class option cancelspace is equivalent to giving +% the command \cancelspace at the beginning of the file. The default is +% \nocancelspace. Thus, the document class option nocancelspace has no +% effect, but is there to avoid errors if a user is confused. % -% \fillwithdottedlines is similar to \fillwithlines except that it -% inserts dotted lines (created by \dotfill) instead of solid lines. +% If the user uses the document class option cancelspace and if +% solutions are not being printed, then any space that would be added by +% an optional argument to the solution, solutionorbox, solutionorlines, +% or solutionordottedlines environments will not be added. % -% \fillwithdottedlines takes one argument, which is either a length or -% \fill, and it fills that much vertical space with dotted horizontal -% lines that run the length of the current line. That is, they extend -% from the current left margin (which depends on whether we're in a -% question, part, subpart, or subsubpart) to the right margin. +% If solutions are being printed (because the user used the document +% class option answers or gave the command \printanswers), then the +% option cancelspace (and the command \cancelspace) will have no +% effect. % -% The distance between the lines is \dottedlinefillheight, whose -% default value is set with the command +%-------------------------------------------------------------------- +% Version 2.319$\beta$, 2011/04/11: % -% \setlength\dottedlinefillheight{.25in} +% We fixed an obscure bug, in which if the user gives a \qformat +% command, in which case they shouldn't want to give a \droppoints +% command, but they *do* give a \droppoints command, there is an +% error (\padded@point@block undefined). % -% This value can be changed by giving a new \setlength command. +%-------------------------------------------------------------------- +% Version 2.318$\beta$, 2011/04/05: % -% The solutionordottedlines environment is almost identical to the -% solutionorlines environment, except that when solutions are not -% being printed and an optional argument appears specifying an amount -% of space to be left for answers, that space is filled with dotted -% lines (created by \dotfill), rather than filled with solid lines (as -% it is by the solutionorlines environment). +% \qformat and \bonusqformat are now totally independent. +% That is: \qformat doesn't affect bonus questions, and \noqformat +% no longer cancels \bonusqformat. % -%-------------------------------------------------------------------- -% Version 2.219$\beta$, 2007/11/24: -% -% There can now be partial grade tables and point tables, either bonus -% or non-bonus. -% -% New commands: -% -% \partialgradetable -% \partialbonusgradetable -% \partialpointtable -% \partialbonuspointtable -% \begingradingrange -% \endgradingrange -% -% The user defines a grading range by saying -% -% \begingradingrange{whatever} -% -% to start the range and -% -% \endgradingrange{whatever} -% -% to end the range (where ``whatever'' is a name chosen by the user). -% To create the table, the user says, e.g., -% -% \partialgradetable{whatever}[v][questions] -% -% That is, each of \partialgradetable, \partialbonusgradetable, -% \partialpointtable, and \partialbonuspointtable takes -% -% one required argument (the name of the grading range) and -% -% two optional arguments, the first being either ``[v]'' or ``[h]'', -% the second being either ``[questions]'' or ``[pages]''. -% -% If either or both of the optional arguments are omitted, [questions] -% and [v] will be used. -% -% If the table is indexed by questions, then it will include all -% questions following the \begingradingrange{whatever} and preceding the -% \endgradingrange{whatever}. -% -% If the table is indexed by pages, then it will include all pages with -% points starting with the page containing the -% \begingradingrange{whatever} and ending with the page containing the -% \endgradingrange{whatever}. -% -% Otherwise, -% -% \partialgradetable is similar to \gradetable -% \partialbonsugradetable is similar to \bonusgradetable -% \partialpointtable is similar to \pointtable -% \partialbonuspointtable is similar to \bonuspointtable -% -%-------------------------------------------------------------------- -% Version 2.218$\beta$, 2007/10/31: -% -% Instead of appending -% \the \pageinfo@commands \the \point@toks -% to \everypar, we insert them into the box \@labels. This corrects the -% problem that arose when a question (or part, etc.) begins with a list -% environment (including verbatim, flushleft, center, flushright, and -% possibly others that are implemented as trivlist environments). The -% \item command in those environments throws away the previous contents -% of \everypar, and so the tokens -% \the \pageinfo@commands \the \point@toks -% didn't get inserted where we expected. List environments *do* -% preserve the contents of the box \@labels, though. - -% This version of exam.cls is not completely backward compatible with -% older versions. The changes only affect documents in which the user -% was doing something that probably should not have been done with the -% older versions, though. This new version does something useful in -% situations in which older versions did something not very useful: - -% This change introduces a change in behavior for documents in which a -% question with points begins with a parts environment, so that the -% points for the first part (if any) would appear on the same line as -% the points for the question. In earlier versions of exam.cls, the -% points for the question would not be printed if there are points for -% the part that begins on the same line. In this version of exam.cls, -% all points will be printed. If they're both printed in the left -% margin, or both in the right margin, then they'll be printed directly -% on top of one another, which is not what you want. (You can use -% \pointsinmargin, \pointsinrightmargin, and \nopointsinmargin to print -% them in different places.) If points are being printed right in the -% text (i.e., \nopointsinmargin), then the points for the question will -% be printed *before* the label (a) for the first part is printed. - -% The behavior of this new version of exam.cls seems clearly preferable -% to the old behavior, but it is a change! +% New command: \nobonusqformat +% \nobonusqformat does for \bonusqformat what \noqformat does for +% \qformat. % %-------------------------------------------------------------------- -% Version 2.217$\beta$, 2007/10/22: -% -% We changed things so that we're now compatible with calc.sty +% Version 2.317$\beta$, 2011/04/02: % -% calc.sty redefines \setcounter and \addtocounter in a way that -% conflicts with a trick we were using to deal with \half points. +% We changed the definition of \numcoverpages so that on the first run +% of latex (when \exam@lastcoverpage isn't yet defined), \numcoverpages +% will expand to +% 0\mbox{\normalfont\bf ??} +% instead of +% \mbox{\normalfont\bf ??} +% so that the construction \romannumeral\numcoverpages will not generate +% an error on the first run of latex. % -% We replaced one \setcounter command with +% We also made changes and corrections to comments. % -% \global\csname c@#1\endcsname 0#2\relax -% -% and one \addtocounter command with +%-------------------------------------------------------------------- +% Version 2.316$\beta$, 2010/12/22: % -% \global\advance\csname c@#1\endcsname 0#2\relax % -%-------------------------------------------------------------------- -% Version 2.216$\beta$, 2007/08/27: -% -% The command \answerline now takes an optional argument. If the -% optional argument appears, then when \printanswers is true the -% argument will be printed on the answer line. When \printanswers is -% false, the optional argument is ignored. -% -% When the argument is printed, it is printed with -% \CorrectChoiceEmphasis and it is a distance of \answerclearance above -% the line. The default value of \answerclearance is set with the -% command -% -% \setlength\answerclearance{0.2ex} -% -% and it can be changed with a \setlength command. -% -% The optional argument is centered on the answer line unless it is too -% long, in which case it extends to the right of the answer line. -% -%-------------------------------------------------------------------- -% Version 2.215$\beta$, 2007/08/24: -% % New commands: -% -% \pointtable -% \bonuspointtable -% -% Both of these take up to two optional arguments: -% -% The first can be either [v] or [h]. -% The second can be either [questions] or [pages]. -% -% These commands are similar to the commands -% -% \gradetable -% \bonusgradetable -% -% except that the new commands print only two columns (or rows), -% omitting the column (or row) for the score. -% +% +% \pointsinrange{rangename} +% \bonuspointsinrange{rangename} +% +% If `rangename' is the name of a grading range defined using +% \begingradingrange{rangename} and \endgradingrange{rangename}, then +% \pointsinrange{rangename} expands to the number of points in that +% grading range and \bonuspointsinrange{rangename} expands to the number +% of bonus points in that grading range. + +% We also changed the checkboxes and oneparcheckboxes environments so +% that, when solutions are being printed, a \CorrectChoice will be +% printed with \CorrectChoiceEmphasis (along with the \checkedchar +% that marks the \CorrectChoice). This brings the behavior in line +% with that of the choices and oneparchoices environments. +% %-------------------------------------------------------------------- -% Version 2.214$\beta$, 2007/07/19: +% Version 2.315$\beta$, 2010/12/21: % % New commands: % -% \questionshook -% \partshook -% \subpartshook -% \subsubpartshook -% \choiceshook +% \settabletotalpoints +% \settabletotalbonuspoints % -% These are for advanced users who want to customize the list -% parameters (\topsep, \partopsep, \itemsep, \parsep, etc.) for the -% lists that these environments create. They are all defined to be -% empty, but the user can change them using \renewcommand. +% Each of those takes one argument. After giving the command +% \settabletotalpoints{numpoints}, any grade or point table (partial +% or full) will list the total points as numpoints instead of the +% actual total number of points in the table. % -%-------------------------------------------------------------------- -% Version 2.213$\beta$, 2006/11/27: -% -% New documentclass option: addpoints -% Using this option is equivalent to giving the command -% \addpoints -% at the beginning of the document. -% -% New commands: -% -% \bonusquestion -% \bonustitledquestion -% \bonuspart -% \bonussubpart -% \bonussubsubpart -% -% \bonuspointsofquestion -% \bonuspointsonpage -% -% \numbonuspoints -% -% \bonuspointpoints -% \bonuspointformat -% \thebonuspoints -% \bonuspoints -% \bonuspointname -% \marginbonuspointname -% -% \bonusgradetable -% -% \bhqword -% \bhpword -% \bhsword -% \bhtword -% \bvqword -% \bvpword -% \bvsword -% \bvtword -% -% \bvpgword -% \bhpgword -% -% -% The commands -% -% \bonusquestion -% \bonustitledquestion -% \bonuspart -% \bonussubpart -% \bonussubsubpart -% -% are the same as the commands -% -% \question -% \titledquestion -% \part -% \subpart -% \subsubpart -% -% except that any points assigned become ``bonus points'', which by -% default are typeset in the form -% -% 1. (1 point (bonus)) -% -% or -% -% 1. (2 points (bonus)) -% -% If no points are assigned, then these ``bonus'' versions of the -% commands are equivalent to the non-bonus versions. -% -% The command -% -% \bonusgradetable -% -% is analogous to the command \gradetable; it can be used in any of the -% four forms -% -% \bonusgradetable[v][questions] -% \bonusgradetable[h][questions] -% \bonusgradetable[v][pages] -% \bonusgradetable[h][pages] -% -% and it counts only bonus points, while \gradetable counts only -% non-bonus points. -% -% The commands -% -% \bonuspointsofquestion -% \bonuspointsonpage -% \numbonuspoints -% -% are analogous to the commands -% -% \pointsofquestion -% \pointsonpage -% \numpoints -% -% The remaining new commands are for customizing the appearance of bonus -% points and bonusgradetable. The command -% -% \bonuspointpoints -% -% is analogous to the command \pointpoints; it takes two arguments, the -% first of which will appear after 1 or \half points the second to -% appear after any other number of points. The default was created by -% the equivalent of the command -% -% \bonuspointpoints{point (bonus)}{points (bonus)} -% -% If, for example, you give the command -% -% \bonuspointpoints{bonus point}{bonus points} -% -% then bonus points will look like -% -% 1. (1 bonus point) -% -% or -% -% 1. (2 bonus points) -% -% (The commands \bracketedpoints, \boxedpoints, and \nobracketedpoints -% have the same effect on bonus points that they have on non-bonus -% points, and the command \marksnotpionts replaces ``point'' with -% ``mark'' in all of these cases.) -% -% \bonuspointname is analogous to \pointname, and the defaults were -% created by the commands -% -% \pointname{ \points} -% \bonuspointname{ \bonuspoints} -% -% (Note the intentional space in each of those commands.) -% -% \marginbonuspointname is analogous to \marginpointname, and the -% default was created by the command -% -% \marginbonuspointname{ (bonus)} -% -% \bonuspointformat is analogous to \pointformat. -% -% -% The commands for customizing the words used in \bonusgradetable are -% analogous to those used for customizing the words used in \gradetable, -% except that they begin with a ``b'': -% -% \bhqword is analogous to \hqword -% \bhpword is analogous to \hpword -% \bhsword is analogous to \hsword -% \bhtword is analogous to \htword -% \bvqword is analogous to \vqword -% \bvpword is analogous to \vpword -% \bvsword is analogous to \vsword -% \bvtword is analogous to \vtword -% is analogous to -% \bvpgword is analogous to \vpgword -% \bhpgword is analogous to \hpgword -% +% After giving the command \settabletotalbonuspoints{numbonuspoints}, +% any grade or point table will list the total bonus points as +% numbonuspoints instead of the actual total number of bonus points in +% the table. % -%-------------------------------------------------------------------- -% Version 2.212$\beta$, 2006/11/13: +% These commands are intended for exams in which students are asked to +% do some subset of the problems, but not all of them, and so the +% total number of points possible is less than the sum of the points +% for all of the questions. % -% Made \useslantedhalf and \usehorizontalhalf global. % -%-------------------------------------------------------------------- -% Version 2.211$\beta$, 2006/10/29: +% To have one of these commands affect only a single table, confine the +% command and the \gradetable command inside of a group, as in % -% New commands: +% \begingroup +% \settabletotalpoints{100} +% \gradetable[v][questions] +% \endgroup % -% \pointformat -% \themarginpoints +% or even just % -% An old command that's also useful here is +% \begin{center} +% \settabletotalpoints{100} +% \gradetable[v][questions] +% \end{center} % -% \thepoints +%-------------------------------------------------------------------- +% Version 2.314$\beta$, 2010/12/01: % -% \pointformat: The \pointformat command allows you to change the -% format used to print the points. It takes one argument, and that -% argument becomes the command to print the points, whether the points -% are being printed at the beginning of the question, in the left -% margin (because of \pointsinmargin), in the right margin (because of -% \pointsinrightmargin), or dropped in the right margin at the end of -% the question (because of \pointsdroppedatright). +% New user command: % -% The argument to \pointformat should contain either the command +% \addquestionobject % -% \thepoints +% This is for when some of a question spills onto the next page, but +% that page doesn't have any parts, subparts, subsubparts, or choices +% beginning on theat page (which means that the \ifincomplete command +% won't know that any of that question is on that page). If you say +% \addquestionobject at the very end of the question, it will write a +% questionobject to the .aux file so that \ifincomplete will work +% correctly. % -% which expands to the number of points followed by the argument to -% the last \pointname command, or the command +% New commands used only internally: % -% \themarginpoints +% \first@questionobject +% \questionobject@pluspagecheck % -% which expands to the number of points followed by the argument to -% the last \marginpointname command. +% These were just to clean up some of the internal code. % -% For example, the command \bracketedpoints is equivalent to +%-------------------------------------------------------------------- +% Version 2.313$\beta$, 2010/02/18: % -% \pointformat{[\thepoints]} +% Bug fix: When solutions are not being printed, the solution, +% solutionorlines, and solutionordottedlines environments disallow +% pagebreaks before the environment, which can pull the last line of +% the question (or part, or etc.) preceding the environment onto the +% next page, even when leaving a rather large space before the +% pagebreak. We insert % -% if points are not being printed in the margin and to +% \penalty 0 % -% \pointformat{[\themarginpoints]} +% to allow a pagebreak before the environment. We make no change to +% the solutionorbox environment, since it didn't have this problem. % -% if points are being printed in the margin. +%-------------------------------------------------------------------- +% Version 2.312$\beta$, 2010/01/17: % -% For another example, the command \boxedpoints is equivalent to +% New commands: +% +% \combinedgradetable +% \combinedpointtable +% \partialcombinedgradetable +% \partialcombinedpointtable +% +% These are similar to \gradetable, \pointable, \bonusgradetable, +% \bonuspointtable, \partialgradetable, \partialpointtable, +% \partialbonusgradetable, and \partialbonuspointtable except that +% these new commands list both the points and the bonus points. +% +% \partialcombinedgradetable and \partialcombinedpointtable take one +% required argument, which is the name of the grading range. All four +% of these commands take two optional arguments, the first being either +% ``v'' or ``h'' and the second being either ``questions'' or +% ``pages''. The possibilities are thus +% +% \combinedgradetable[v][questions] +% \combinedgradetable[v][pages] +% \combinedgradetable[h][questions] +% \combinedgradetable[h][pages] +% \partialcombinedgradetable{rangename}[v][questions] +% \partialcombinedgradetable{rangename}[v][pages] +% \partialcombinedgradetable{rangename}[h][questions] +% \partialcombinedgradetable{rangename}[h][pages] +% +% The defaults are ``v'' and ``questions''. +% +% The horizontal tables have separate rows for the points and bonus +% points. The vertical tables have separate columns for the points and +% bonus points. +% +% The default values for the words that appear in the tables are set by +% the commands +% +% \chqword{Question:} +% \chpgword{Page:} +% \chpword{Points:} +% \chbpword{Bonus Points:} +% \chsword{Score:} +% \chtword{Total} +% \cvqword{Question} +% \cvpgword{Page} +% \cvpword{Points} +% \cvbpword{Bonus Points} +% \cvsword{Score} +% \cvtword{Total:} +% +% The words in the table can be changed by giving any of these +% commands with the desired word as argument. % -% \pointformat{\fbox{\thepoints}} +%-------------------------------------------------------------------- +% Version 2.311$\beta$, 2010/01/10: % -% if points are not being printed in the margin and to +% New environment: oneparcheckboxes % -% \pointformat{\fbox{\themarginpoints}} +% The oneparcheckboxes environment is to the checkboxes environment as +% the oneparchoices environment is to the choices environment. That is, +% each choice is begun with either a \choice or a \correctchoice +% command, and these will all be printed as a single paragraph. When +% answers are not being printed, each choice will have a label +% consisting of a box that the student can check, created by the +% argument to the last \checkboxchar command. The default value is +% created by the command % -% if points are being printed in the margin. +% \checkboxchar{$\bigcirc$} % -% For another example, if you give the commands +% (Note the dollar signs, since \bigcirc can appear only in math +% mode.) When answers are being printed, then any choice created +% using the \correctchoice command will be labelled by the argument to +% the last \checkedchar command, the default value of which is created +% by the command % -% \pointsinmargin -% \marginpointname{\%} -% \pointformat{\slshape (\themarginpoints)} +% \checkedchar{$\surd$} % -% then the points will be printed in the left margin, followed by the -% symbol `%', surrounded by parentheses, all in slanted type. +%-------------------------------------------------------------------- +% Version 2.310$\beta$, 2010/01/09: % -% For another example, if you give the commands +% New command: \bonusqformat % -% \pointsinrightmargin -% \marginpointname{\%} -% \pointformat{\fbox{\bfseries \boldmath \themarginpoints}} +% The \bonusqformat command takes one argument, with the same +% description as for the argument of the \qformat command. % -% then the points will be printed in the right margin, followed by the -% symbol `%', all in bold and surrounded by a box. (Note: The commands -% \bfseries and \boldmath are needed here because the ``one half'' -% printed when you use half points is printed in math mode while the -% rest of the points are printed in text mode.) +% Note added 2011/04/05: Version 2.318$\beta$ changes the behavior so +% that \qformat and \bonusqformat are now completely independent! % -%-------------------------------------------------------------------- -% Version 2.210$\beta$, 2006/09/28: +% If the user gives a \qformat command, then the argument of that +% command is used to format both questions and bonusquestions. If, +% after giving the \qformat command, the user gives a \bonusqformat +% command, then the argument of the \bonusqformat command will be used +% to format bonus questions. % -% Fixed the bug that prevented having two consecutive \correctchoice's -% in a choices or oneparchoices environment. +% Note: The \bonusqformat command must be given *after* the \qformat +% command, or else the \bonusqformat command will have no effect. % -%-------------------------------------------------------------------- -% Version 2.209$\beta$, 2006/05/26: +% Note: If the user hasn't given a \qformat command, then a +% \bonusqformat command will have no effect. % -% We corrected the problem that \ifcontinuation and \ifincomplete paid -% attention only to parts, subparts, and subsubparts when deciding on -% which page a question ended, but ignored choices. We corrected this, -% so that a question is now thought to end on the page on which its last -% part, subpart, subsubpart, or choice begins. +% Note: If the user gives a \qformat command and a \bonusqformat +% command, and then later says \noqformat, then the arguments of both +% the \qformat and \bonusqformat commands are no longer usable. That +% is, if the user later on once again says \qformat, and wants the bonus +% questions to have a different format from the questions, then another +% \bonusqformat command must be given. % -%-------------------------------------------------------------------- -% Version 2.208$\beta$, 2006/01/30: -% -% We corrected the description of the usage of \ifthenelse in the -% comments describing what's new in version 2.207beta. +% Note added 2011/04/05:: The above is changed in version 2.318$\beta$. +% \qformat and \bonusqformat are now completely independent. +% \noqformat cancels only \qformat, and the new command +% \nobonusqformat cancels \bonusqformat. % %-------------------------------------------------------------------- -% Version 2.207$\beta$, 2006/01/29: -% -% New feature: It's possible to say -% -% \ifprintanswers -% Some stuff -% \fi -% -% to insert ``Some stuff'' only when answers are being printed. It's -% also possible to say -% -% \ifprintanswers -% Some stuff -% \else -% Other stuff -% \fi -% -% to insert ``Some stuff'' when answers are being printed and ``Other -% stuff'' when answers aren't being printed. -% -% Alternatively, it's possible to accomplish the same thing by saying -% -% \ifthenelse{\boolean{printanswers}}{Some stuff}{Other stuff} -% -% If you want to ``Stuff'' only when answers aren't being printed, you -% can say either -% -% \ifprintanswers -% \else -% Stuff -% \fi -% -% or -% -% \ifthenelse{\boolean{printanswers}}{}{Stuff} -% -% We accomplished this by changing all uses of \if@printanswers, -% \@printanswerstrue, and \@printanswersfalse to \ifprintanswers, -% \printanswerstrue, and \printanswersfalse. -% +% Version 2.309$\beta$, 2009/11/30: +% +% New environment: checkboxes +% New commands: \checkboxeshook +% \checkboxchar +% \checkedchar +% +% The checkboxes environment is similar to the choices environment, +% except that choices are not numbered. Instead of numbers, each +% choice has a label consisting of a box that the student can check, +% created by the argument to the last \checkboxchar command. The +% default value is created by the command +% +% \checkboxchar{$\bigcirc$} +% +% (Note the dollar signs, since \bigcirc can appear only in math +% mode.) When answers are being printed, then any choice created +% using the \correctchoice command will be labelled by the argument to +% the last \checkedchar command, the default value of which is created +% by the command +% +% \checkedchar{$\surd$} +% +% The list parameters used in the checkboxes environment can be +% customized by redefining \checkboxeshook, the default value of which +% is empty. (This is similar to using \choiceshook to alter the +% choices environment.) +% %-------------------------------------------------------------------- -% Version 2.206$\beta$, 2005/08/24: -% -% New feature: When using a grading table indexed by questions, it's -% possible to replace the question numbers in the table with titles -% for the questions. +% Version 2.308$\beta$, 2009/11/26: % -% -% There are two new commands: \titledquestion and \thequestiontitle. -% -% -% \titledquestion is a replacement for \question; it has one required -% argument (the title) and one optional argument (the point value), as -% in -% -% \titledquestion{Question \thequestion: Concepts} -% -% which sets the question title to ``Question 2: Concepts'' (if this -% is the second question) and doesn't set any pointvalues, or -% -% \titledquestion{Design}[10] -% -% which sets the question title to ``Design'' and sets the pointvalue -% to ``10''. (Note that the question title doesn't include the number -% of the question unless you put it there using the \thequestion -% command.) -% -% The title of the question then automatically replaces the question -% number in a grading table indexed by question numbers. -% -% -% +% We fixed a bug that caused \bonussubpart to act like \subpart and +% \bonussubsubpart to act like \subsubpart. % -% -% \thequestiontitle: This command expands to the question title. This -% is for use in the argument of a \qformat command, so that you can make -% the question title appear in the actual question. -% -% If a question is begun with \question (instead of \titledquestion), -% then the value of \thequestiontitle will automatically be set to the -% number of the question. -% -% Note: The contents of \thequestiontitle don't appear anywhere in the -% actual question unless you do something to make it appear. For -% example, the command -% -% \qformat{\textbf{Question \thequestion: \thequestiontitle}\dotfill\thepoints} -% -% would insert the number of the question along with the title of the -% question and the point value at the beginning of the question. -% -% -% Note: If you use a grading table indexed by questions and you use the -% \titledquestion command, then the number of the question won't appear -% in the grading table unless you include \thequestion in the title of -% the question. -% +%-------------------------------------------------------------------- +% Version 2.307$\beta$, 2009/06/11: % -% Note: If \thequestion appears in both the argument to \qformat and the -% title of the question, then the question number will be printed -% twice. -% -% -% If the command \thequestiontitle is never used, then the only effect -% of using the command \titledquestion is that in a grading table -% indexed by question number, this question will be indexed by the -% number of the question, rather than by the argument to -% \titledquestion, and the title of the question would never appear -% except in the grading table. +% We fixed a bug that arose only when there were cover pages and the +% first page of the cover pages used a different extraheadheight or +% extrafootheight from that used on the first page of the regular pages. +% The bug caused the first page of the regular pages to use the +% extraheadheight and extrafootheight intended only for the first cover +% page. % -% %-------------------------------------------------------------------- +% Version 2.306$\beta$, 2009/03/28: % -% Version 2.205$\beta$, 2005/08/22: +% We fixed a bug that arose only when the user used a figure or +% table environment that floated to the top of a page. If that +% happened, then a full page's worth of text was placed below +% the figure or table, makeing the text run over the footline and off +% the bottom of the page. % -% Bug fix: If a question began with a parts environment (i.e., if the -% parts environment began before we entered horizontal mode in the -% question), then a grading table indexed by questions would get the -% part number instead of the question number. That's fixed now. +% We fixed this by commenting out several lines at the end of +% \@setheadheight and @setfootheight. % %-------------------------------------------------------------------- +% Version 2.305$\beta$, 2009/01/30: % -% Version 2.204$\beta$, 2005/08/21: +% We fixed a bug to keep page breaks from occurring inside of +% \makeemptybox. We also added \begingroup \endgroup for the off +% chance that someone was using box0 and didn't want us to change it. % -% Bug fix: Hyperlinks didn't work on page numbers for horizontal -% grading tables indexed by page numbers. They do now. +% We also fixed a bug in the solutionorbox environment that showed +% itself when the user used \stretch in the optional argument. % %-------------------------------------------------------------------- +% Version 2.304$\beta$, 2009/01/22: % -% Version 2.203$\beta$, 2005/08/20: +% We rewrote the definition of \makeemptybox and the solutionorbox +% environment (created in version 2.303). % -% Eliminated \do@int@lbl, and replaced it with labels for each -% question, part, subpart, and subsubpart the names of which -% tell you what they're labelling. +% The argument to \makeemptybox can now be either a length, or \fill, or +% \stretch{number}. % -% That allowed us to rewrite the grade table stuff so that, for tables -% indexed by question numbers, the question numbers are inserted with a -% \ref, so that if \usepackage{hyperref} and pdflatex are used, those -% question numbers will be clickable links that take you to the relevant -% question. +% The optional argument to the solutionorbox environment can also be +% either a length, or \fill, or \stretch{number}. If the optional +% argument is omitted, then no box is printed when printanswers is +% false. +% +% The minimum box height is \minboxheight, whose value is set by the +% command % -% We also added a label for the first points to appear on each page, and -% rewrote the grade table stuff for tables indexed by page number so -% that the page numbers are inserted with a \pageref, so that if -% \usepackage{hyperref} and pdflatex are used, those page numbers will -% be clickable links that take you to the relevant page. +% \setlength\minboxheight{.1in} +% +% This can be changed by giving a new setlength command, but it's not +% likely that anyone actually wants a box of height less than .1 inch. % %-------------------------------------------------------------------- +% Version 2.303$\beta$, 2009/01/21: +% +% New command: \makeemptybox +% New environment: solutionorbox % -% Version 2.202$\beta$, 2005/08/10: +% \makeemptybox takes one argument, which is a length, and it creates +% an empty box of width the length of the current line and of height +% equal to the argument. That is, the box extends from the current +% left margin (which depends on whether we're in a question, part, +% subpart, or subsubpart) to the right margin. % -% Created \correctchoice as a synonym for \CorrectChoice +% The solutionorbox environment is similar to the solution +% environment, except that if printanswers is false and an optional +% argument is specified, then instead of leaving that much blank space +% we print an empty box of that height. The optional argument must be +% a dimension; it can not be \fill. If the optional argument is +% missing or equal to 0pt, then when printanswers is false we print +% nothing at all. % -% Changed \CorrectChoiceDeclarations to \CorrectChoiceEmphasis, -% and created \correctchoiceemphasis as a synonym for that. +% Note: This is changed in version 2.304. As of that version, the +% argument can be a length, or \fill, or \stretch{number}. % %-------------------------------------------------------------------- +% Version 2.302$\beta$, 2008/10/18: +% +% New commands: \numcoverpages and \totalnumpages +% +% \numcoverpages inserts the number of pages occupied by the +% coverpages environment. If there is no coverpages environment, +% it inserts 0. % -% Version 2.201$\beta$, 2005/08/09: +% \totalnumpages inserts the sum of \numcoverpages and \numpages. +% Note that if there are pages preceding a coverpages environment, then +% those pages will not be counted by \totalnumpages. % -% We created a \CorrectChoice command for use in the choices and -% oneparchoices environments. +% We also added \relax after some \ifnum comparisons and commented +% out some line endings to remove, e.g., an unwanted space inserted +% by \ifcontinuation when the page is a continuation. % -% When solutions are not being printed, \CorrectChoice is equivalent to -% \choice. +%-------------------------------------------------------------------- +% Version 2.301$\beta$, 2008/09/22: % -% When solutions *are* being printed, the choice that was created with -% \CorrectChoice (rather than with \choice) will be printed subject to -% the declarations in the argument of the +% All solution, solutionorlines, and solutionordotteslines +% environments are now enclosed in a group which is begun +% with the argument of the command % -% \CorrectChoiceDeclarations +% \SolutionEmphasis % -% command. The default is +% the default value of which is determined by the command % -% \CorrectChoiceDeclarations{\bfseries} +% \SolutionEmphasis{} % -% and so, when solutions are being printed, the correct choice is -% printed in boldface by default. If, e.g., you give the command +% That is, the default is that nothing is inserted. +% For example, if the command % -% \usepackage{color} +% \SolutionEmphasis{\itshape\small} % -% after the \documentclass command and then give the command +% is used, the solutions will be set in italics, in small type. % -% \CorrectChoiceDeclarations{\color{red}} % -% then the correct choice will be printed in red. If, e.g., you give -% the command +% New command: \unframedsolutions % -% \CorrectChoiceDeclarations{\color{red}\bfseries} +% This causes solutions to be printed as normal text, without any +% framing or shading. Anyone using this command should use the +% \SolutionEmphasis command so that the solutions will be +% distinguishable from the rest of the exam. % -% then the correct choice will be printed in red and in boldface. +%-------------------------------------------------------------------- +% Version 2.3, 2008/07/16: % -% Note added later: \CorrectChoiceDeclarations was changed -% to \CorrectChoiceEmphasis in version 2.202$\beta$. +% Minor typographic corrections to comments. % %-------------------------------------------------------------------- %-------------------------------------------------------------------- @@ -774,6 +553,11 @@ \DeclareOption{answers}{\printanswerstrue} \DeclareOption{noanswers}{\printanswersfalse} +\newif\ifcancelspace +\cancelspacefalse +\DeclareOption{cancelspace}{\cancelspacetrue} +\DeclareOption{nocancelspace}{\cancelspacefalse} + % The following keeps track of whether the user has requested that we % add up the points on the exam. We make the default false so that % users who put other than numbers into the points argument of a @@ -902,7 +686,7 @@ \newcommand*\adj@hdht@ftht{% \if@coverpages - \ifnum\value{page}=1 + \ifnum\value{page}=1\relax \@setheadheight{\covfp@exhd}% \@setfootheight{\covfp@exft}% \else @@ -910,7 +694,7 @@ \@setfootheight{\covrun@exft}% \fi \else - \ifnum\value{page}=1 + \ifnum\value{page}=1\relax \@setheadheight{\fp@exhd}% \@setfootheight{\fp@exft}% \else @@ -991,7 +775,7 @@ \@appendoutput{\adj@hdht@ftht} %-------------------------------------------------------------------- -% \setheadheight and \setfootheight: +% \@setheadheight and \@setfootheight: \def\@setheadheight#1{% \begingroup % Avoid trouble from using \@temp and \@spaces @@ -1018,11 +802,22 @@ % executed only in the preamble or as we return from the output % routine, but we're leaving it in so that this will still work if % we use this at some random point in the middle of composing a - % page). + % page). + % Bugfix, Version 2.306beta, 2009/03/28: + % We don't do this!! + % If the user had a figure environment that floated to the + % top of a page, then this would cause that page to run + % over the footer and off the bottom of the page, because + % this somehow caused a full page's worth of stuff to be + % placed after the figure, as if the figure wasn't taking + % up space on the page. + % We *do* need to put \@colht at the correct new value, though, + % apparently because \@colht is set near the end of the + % output routine. \global\@colht=\textheight - \global\@colroom=\textheight - \global\vsize=\textheight - \global\pagegoal=\textheight +% \global\@colroom=\textheight +% \global\vsize=\textheight +% \global\pagegoal=\textheight \endgroup } @@ -1050,10 +845,21 @@ % routine, but we're leaving it in so that this will still work if % we use this at some random point in the middle of composing a % page). + % Bugfix, Version 2.306beta, 2009/03/28: + % We don't do this!! + % If the user had a figure environment that floated to the + % top of a page, then this would cause that page to run + % over the footer and off the bottom of the page, because + % this somehow caused a full page's worth of stuff to be + % placed after the figure, as if the figure wasn't taking + % up space on the page. + % We *do* need to put \@colht at the correct new value, though, + % apparently because \@colht is set near the end of the + % output routine. \global\@colht=\textheight - \global\@colroom=\textheight - \global\vsize=\textheight - \global\pagegoal=\textheight +% \global\@colroom=\textheight +% \global\vsize=\textheight +% \global\pagegoal=\textheight \endgroup } @@ -1100,8 +906,12 @@ \newif\if@coverpages \@coverpagesfalse +\newcounter{num@coverpages} +% We'll set this to zero in case there is no coverpages environment: +\setcounter{num@coverpages}{0} + \newenvironment{coverpages}{% - \ifnum \value{numquestions}>0 + \ifnum \value{numquestions}>0\relax \ClassError{exam}{% Coverpages cannot be used after questions have begun.\MessageBreak }{% @@ -1115,7 +925,16 @@ \adj@hdht@ftht }{% \clearpage + \setcounter{num@coverpages}{\value{page}}% + \addtocounter{num@coverpages}{-1}% \pagenumbering{arabic}% + % Bugfix, Version 2.307\beta, 2009/06/11: + % We have to say \@coverpagesfalse before \adj@hdht@ftht + % because we're still inside the group created by the + % coverpages environment and we want to set the + % extraheadheight and extrafootheight to the values correct + % for the first non-cover page: + \@coverpagesfalse \adj@hdht@ftht } @@ -1132,13 +951,13 @@ \newcommand*\@dohead{% \def\@oddhead{% \if@coverpages - \ifnum\value{page}=1 + \ifnum\value{page}=1\relax \cov@fullhead \else \covrun@fullhead \fi \else - \ifnum\value{page}=1 + \ifnum\value{page}=1\relax \@fullhead \else \run@fullhead @@ -1151,13 +970,13 @@ \newcommand*\@dofoot{% \def\@oddfoot{% \if@coverpages - \ifnum\value{page}=1 + \ifnum\value{page}=1\relax \cov@fullfoot \else \covrun@fullfoot \fi \else - \ifnum\value{page}=1 + \ifnum\value{page}=1\relax \@fullfoot \else \run@fullfoot @@ -1629,6 +1448,7 @@ % \numpages, \iflastpage, and \oddeven % Also: \numpoints, \numquestions, \numparts, and \numsubparts % Also also: \pointsofquestion +% Also: \numcoverpages and \totalnumpages % Make the number of pages available as the macro \numpages, % the number of points as \numpoints, @@ -1660,6 +1480,20 @@ \exam@lastpage }% numpages +% Change 2011/04/01: We added a ``0'' in front of the +% mbox when \exam@lastcoverpage isn't defined. This is +% so that the construction \romannumeral\numcoverpages +% won't generate an error on the first run of latex. +\def\numcoverpages{\@ifundefined{exam@lastcoverpage}% + {0\mbox{\normalfont\bf ??}}% + \exam@lastcoverpage +}% numpages + +\def\totalnumpages{\@ifundefined{exam@totalpages}% + {\mbox{\normalfont\bf ??}}% + \exam@totalpages +}% numpages + \def\numpoints{\@ifundefined{exam@numpoints}% {\mbox{\normalfont\bf ??}}% \exam@numpoints @@ -1698,12 +1532,30 @@ {\csname bonuspointsofq@\romannumeral #1\endcsname}% }% bonuspointsofquestion +% For use in \combinedgradetable and \combinedpointtable, we're +% changing the defintions of \pointsonpage and \bonuspointsonpage +% so that when, e.g., pointsonpage@ii is undefined, we just produce +% 0. This comes up because the final page of the exam may have either +% points with no bonus point or bonus points with no points, in which +% case the combined table will try to list both points and bonus points +% for that last page, and one of those will be undefined. +% +% \def\pointsonpage#1{\@ifundefined{pointsonpage@\romannumeral #1}% +% {\mbox{\normalfont\bf ??}}% +% {\csname pointsonpage@\romannumeral #1\endcsname}% +% }% pointsonpage +% \def\bonuspointsonpage#1{\@ifundefined{bonuspointsonpage@\romannumeral #1}% +% {\mbox{\normalfont\bf ??}}% +% {\csname bonuspointsonpage@\romannumeral #1\endcsname}% +% }% bonuspointsonpage +% +% spanish.ldf redefines \@roman, so we'll avoid using \roman: \def\pointsonpage#1{\@ifundefined{pointsonpage@\romannumeral #1}% - {\mbox{\normalfont\bf ??}}% + {0}% {\csname pointsonpage@\romannumeral #1\endcsname}% }% pointsonpage \def\bonuspointsonpage#1{\@ifundefined{bonuspointsonpage@\romannumeral #1}% - {\mbox{\normalfont\bf ??}}% + {0}% {\csname bonuspointsonpage@\romannumeral #1\endcsname}% }% bonuspointsonpage @@ -1750,7 +1602,14 @@ \advance\c@page-1 \immediate\write\@mainaux {\string\gdef\string\exam@lastpage{\arabic{page}}}% + \immediate\write\@mainaux + {\string\gdef\string\exam@lastcoverpage{\arabic{num@coverpages}}}% + % We can now trash the value of num@coverpages: + \addtocounter{num@coverpages}{\value{page}}% + \immediate\write\@mainaux + {\string\gdef\string\exam@totalpages{\arabic{num@coverpages}}}% \advance\c@page+1 % In case some other package looks at \c@page + % \immediate\write\@mainaux {\string\gdef\string\exam@numpoints{% \prtaux@hlfcntr{numpoints}}}% @@ -1869,9 +1728,9 @@ % argument. \def\oddeven#1#2{% \ifodd\value{page}% - #1 + #1% \else - #2 + #2% \fi }% oddeven @@ -2018,10 +1877,10 @@ {#1}% {\ifnum \thepage > \PgInfo@get{@endquestions}\relax % We're after a \nomorequestions: - #2 + #2% \else % We actually are incomplete: - #1 + #1% \fi }% \fi @@ -2129,7 +1988,7 @@ % \find@quesend, which is why it has to find the last question % begun on or before the current page, rather than just before % the current page. - \ifnum 1 > \arabic{question}\relax + \ifnum 1 > \value{question}\relax % Oops; probably because we're before the first question % Just set latest@ques to -1: \setcounter{latest@ques}{-1}% @@ -2152,7 +2011,7 @@ % then call \decr@latest@ques to recursively decrement % latest@ques as needed to find a question that begins on % or before the current page: - \setcounter{latest@ques}{\arabic{question}}% + \setcounter{latest@ques}{\value{question}}% \decr@latest@ques \fi \fi @@ -2277,7 +2136,7 @@ \else \@ifundefined{Pg@@endquestions}% {\incomp@first}% - {\ifnum \thepage < \PgInfo@get{@endquestions}% + {\ifnum \thepage < \PgInfo@get{@endquestions}\relax \incomp@first \else \incomp@second @@ -2415,7 +2274,7 @@ \csname if#1@half\endcsname \addtocounter{ifpos@cntr}{1}% \fi - \ifnum \value{ifpos@cntr} > 0 + \ifnum \value{ifpos@cntr} > 0\relax }% ifhlfnctr@pos % \prtaux@hlfcntr is used inside the argument of a \write command for @@ -2614,27 +2473,38 @@ % determine if there were points specified for this question.) % The argument to the \qformat command *must* contain some % stretch, i.e., at least one \hfil or \dotfill or ... +% +% The command \noqformat cancels the effect of \qformat and returns us +% to the default situation. +% +% The commands \bonusqformat and \nobonusformat are analogous. \newif\if@qformat \@qformatfalse +\newif\if@bonusqformat +\@bonusqformatfalse \def\qformat#1{% \global\@qformattrue \gdef\@questionformat{#1}% }% qformat +\def\bonusqformat#1{% + \global\@bonusqformattrue + \gdef\@bonusquestionformat{#1}% +}% bonusqformat \newcommand\noqformat{% \global\@qformatfalse }% noqformat +\newcommand\nobonusqformat{% + \global\@bonusqformatfalse +}% nobonusqformat + % \thepoints is for use in either a \qformat command -% or a \pointformat command. It needs to have the +% or a \pointformat command (or a \bonusqformat command). +% It needs to have the % \if@placepoints so that if it's used in a \qformat command % it won't print anything if there are no points: -%\newcommand\thepoints{% -% \if@placepoints -% \@points \@pointname -% \fi -%} \newcommand\thepoints{% \if@placepoints \if@bonus @@ -2647,9 +2517,6 @@ % \themarginpoints is for use only in a \pointformat command, % and so it doesn't need the \if@placepoints bit in \thepoints: -%\newcommand\themarginpoints{% -% \@points \@marginpointname -%}% themarginpoints \newcommand\themarginpoints{% \if@bonus \@points \@marginbonuspointname @@ -2673,10 +2540,54 @@ % begun on or before the current page: \newcounter{ques@object} +% \first@questionobject will be used by the \question command. +% That is, it will be used only once, but we want to keep its +% definition here, near the definitions of \addquestionobject and +% \questionobject@pluspagecheck. +\newcommand{\first@questionobject}{% + \setcounter{ques@object}{1}% + \edef\q@object@label{% + question\arabic{question}@object\arabic{ques@object}}% + \PgInfo@write{\q@object@label}% +}% first@questionobject + +% \addquestionobject will be used by each part, subpart, and +% subsubpart, and can also be used by the user to mark the end of a +% question that spills over onto the next page without any part, +% subpart, etc. starting on that page: +\newcommand{\addquestionobject}{% + \addtocounter{ques@object}{1}% + \edef\q@object@label{% + question\arabic{question}@object\arabic{ques@object}}% + \PgInfo@write{\q@object@label}% +}% addquestionobject + +% \questionobject@pluspagecheck will be used by each choice. It uses +% the questionobject to check if we're the first one on the current +% page, since choices don't have labels the way that questions, parts, +% subparts, and subsubparts do (those things use the label to check if +% they're the first thing on the page). +\newcommand{\questionobject@pluspagecheck}{% + \addtocounter{ques@object}{1}% + \edef\q@object@label{% + question\arabic{question}@object\arabic{ques@object}}% + \PgInfo@write{\q@object@label}% + \set@counter@to@pageof{Curr@Page}{\q@object@label}% + \expandafter\ifx\csname Contin@\theCurr@Page\endcsname\relax + % We're the first \question, \part, \subpart, \subsubpart, + % or choice on this page: + \global\expandafter\edef\csname + Contin@\theCurr@Page\endcsname{\arabic{question}}% + \fi +}% questionobject@pluspagecheck + + + % if@bonus will be true when we're doing a bonusquestion or bonuspart % or etc., and it will also be used also to distinguish between % \gradetable and \bonusgradetable (and between \pointtable and -% \bonuspointtable, etc.): +% \bonuspointtable, etc.), and also to distinguish between +% \pointsinrange and \bonuspointsinrange: \newif\if@bonus \@bonusfalse @@ -2689,6 +2600,7 @@ \newcommand\subpartshook{} \newcommand\subsubpartshook{} \newcommand\choiceshook{} +\newcommand\checkboxeshook{} \newenvironment{questions}{% @@ -2731,10 +2643,10 @@ \addtocounter{numquestions}{1}% % Write the sum of points of the previous question (if any) % to the .aux file. (At this point, the question counter - % has not yet been incremented, so \arabic{question} has the + % has not yet been incremented, so \value{question} is the % number of the question that was just completed.) \if@filesw - \ifnum \arabic{question} > 0\relax + \ifnum \value{question} > 0\relax % First do regular points: \immediate\write\@mainaux {\string\gdef\string\pointsofq@ @@ -2779,10 +2691,7 @@ \pageinfo@commands={% \edef\@queslabel{question@\arabic{question}}% \PgInfo@write{\@queslabel}% - \setcounter{ques@object}{1}% - \edef\q@object@label{% - question\arabic{question}@object\arabic{ques@object}}% - \PgInfo@write{\q@object@label}% + \first@questionobject % In addition to the \PgInfo@write we use an actual \label % command. We do this in order to make the question numbers in % the grade tables into \ref's, so that if the user says @@ -2842,7 +2751,6 @@ \process@subpart }% \def\process@subpart{% - \@bonusfalse \if@coverpages \cover@question@error \fi @@ -2856,10 +2764,7 @@ \edef\@subpartlabel{subpart@\arabic{question}% @\arabic{partno}@\arabic{subpart}}% \PgInfo@write{\@subpartlabel}% - \addtocounter{ques@object}{1}% - \edef\q@object@label{% - question\arabic{question}@object\arabic{ques@object}}% - \PgInfo@write{\q@object@label}% + \addquestionobject % In addition to the \PgInfo@write we use an actual \label % command. We do this in order to make the question numbers in % the grade tables into \ref's, so that if the user says @@ -2908,7 +2813,6 @@ \process@subsubpart }% \def\process@subsubpart{% - \@bonusfalse \if@coverpages \cover@question@error \fi @@ -2922,10 +2826,7 @@ \edef\@subsubpartlabel{subsubpart@\arabic{question}% @\arabic{partno}@\arabic{subpart}@\arabic{subsubpart}}% \PgInfo@write{\@subsubpartlabel}% - \addtocounter{ques@object}{1}% - \edef\q@object@label{% - question\arabic{question}@object\arabic{ques@object}}% - \PgInfo@write{\q@object@label}% + \addquestionobject % In addition to the \PgInfo@write we use an actual \label % command. We do this in order to make the question numbers in % the grade tables into \ref's, so that if the user says @@ -2981,7 +2882,7 @@ % Write the number of points of the final question % to the .aux file: \if@filesw - \ifnum \arabic{question} > 0\relax + \ifnum \value{question} > 0\relax % First do the regular points: \immediate\write\@mainaux {\string\gdef\string\pointsofq@\romannumeral @@ -3007,11 +2908,20 @@ % \question@number is used as the label in the question list (instead % of \questionlabel) so that if the user uses a \qformat command, % we'll use the \@questionformat specified by the \qformat command: + \def\question@number{% - \if@qformat - \makebox[\hsize][s]{\@questionformat}\hskip-\labelsep + \if@bonus + \if@bonusqformat + \makebox[\hsize][s]{\@bonusquestionformat}\hskip-\labelsep + \else + \questionlabel + \fi \else - \questionlabel + \if@qformat + \makebox[\hsize][s]{\@questionformat}\hskip-\labelsep + \else + \questionlabel + \fi \fi } \newcommand\questionlabel{\thequestion.} @@ -3030,19 +2940,36 @@ % possible points) to be combined with the label of the first % part. (\if@inlabel tells us if we are still waiting to enter % horizontal mode after seeing a \question command.) - \if@qformat - \if@inlabel - \leavevmode - \@inlabelfalse + \if@bonus + \if@bonusqformat + \if@inlabel + \leavevmode + \@inlabelfalse + \fi + % The following is just in case the question had points, + % in which case @placepoints will still be true. + % (We used to do this inside of the \thepoints macro, + % but that allowed for an error if the user specified points for + % a question but had a \qformat that didn't mention \thepoints.) + % We also set @placepoints to be false in the \question command, + % in case one queation follows a previous one that had no parts. + \global \@placepointsfalse + \fi + \else + \if@qformat + \if@inlabel + \leavevmode + \@inlabelfalse + \fi + % The following is just in case the question had points, + % in which case @placepoints will still be true. + % (We used to do this inside of the \thepoints macro, + % but that allowed for an error if the user specified points for + % a question but had a \qformat that didn't mention \thepoints.) + % We also set @placepoints to be false in the \question command, + % in case one queation follows a previous one that had no parts. + \global \@placepointsfalse \fi - % The following is just in case the question had points, - % in which case @placepoints will still be true. - % (We used to do this inside of the \thepoints macro, - % but that allowed for an error if the user specified points for - % a question but had a \qformat that didn't mention \thepoints.) - % We also set @placepoints to be false in the \question command, - % in case one queation follows a previous one that had no parts. - \global \@placepointsfalse \fi \def\part{% \@bonusfalse @@ -3065,10 +2992,7 @@ \temp@toks={% \edef\@partlabel{part@\arabic{question}@\arabic{partno}}% \PgInfo@write{\@partlabel}% - \addtocounter{ques@object}{1}% - \edef\q@object@label{% - question\arabic{question}@object\arabic{ques@object}}% - \PgInfo@write{\q@object@label}% + \addquestionobject % In addition to the \PgInfo@write we use an actual \label % command. We do this in order to make the question numbers in % the grade tables into \ref's, so that if the user says @@ -3378,12 +3302,6 @@ \def\item@points@pageinfo{% \item - % If @qformat is true, and if we're currently doing a question - % (rather than a part, subpart, or subsubpart), then we don't want - % to set the points (if any), since the points of a question will - % appear only if the user chooses to cause that by putting a - % \thepoints in the argument of the \qformat command. - % % Also: We need to do this here, *after* the \item command, rather % than inside the macro \@readpoints, because the \item command % puts the result of the \qformat command into an \hbox (with the @@ -3393,11 +3311,12 @@ % user put a \thepoints command inside that argument it will % correctly expand to the number of points. (When @placepoints is % false, \thepoints expands to nothing at all). - \if@qformat - \ifx\ques@ref\@queslevel - \global \@placepointsfalse - \fi - \fi + % + % We also want to define \padded@point@block when @placepoints is + % true even if qformat and bonusqformat are true just in case the + % user, for some deranged reason, says \droppoints immediately + % following a \question. + % \if@placepoints % Since we want the user to be able to say \thepoints in the % argument to a \pointformat command, we need \@placepointstrue @@ -3435,24 +3354,60 @@ % \setup@point@toks puts commands into \point@toks to place % \padded@point@block at the correct spot. It doesn't append % anything to \everypar (we do that in this macro, below). + % + % If @qformat is true, and if we're currently doing a question (or + % if @bonusqformat is true and we're doing a bonusquestion) + % (rather than a part, subpart, or subsubpart), then we don't want + % to set the points (if any), since the points of a question will + % appear only if the user chooses to cause that by putting a + % \thepoints in the argument of the \qformat command. \if@pointsdropped % Do nothing! \else - \setup@point@toks + \if@bonus + \if@bonusqformat + \ifx\ques@ref\@queslevel + % Do nothing + \else + \setup@point@toks + \fi + \else + \setup@point@toks + \fi + \else + \if@qformat + \ifx\ques@ref\@queslevel + % Do nothing + \else + \setup@point@toks + \fi + \else + \setup@point@toks + \fi + \fi \fi \global \@placepointsfalse \fi - % We *don't* use \append@toklist; see Bug fix note above + % We *don't* use \append@toklist; see the Bug fixnote above + % (Bug fix, 5 April 2004). % We can append the tokens ``\the\point@toks'' whether or not we're % setting any points because if we're not setting them, \point@toks % will be empty. % Also: It's important to do this *after* the \item command above, % since the \item command discards the previous contents of % \everypar. - % Version 2.217-beta changes: - % Instead of appending stuff to \everypar, we insert - % \the \pageinfo@commands and \the \point@toks - % into the box \@labels: + % Version 2.218$\beta$, 2007/10/31 changes: + % Instead of appending + % \the \pageinfo@commands \the \point@toks + % to \everypar, we insert them into the box \@labels. This corrects + % the problem that arose when a question (or part, etc.) begins with + % a list environment (including verbatim, flushleft, center, + % flushright, and possibly others that are implemented as trivlist + % environments). The \item command in those environments throws + % away the previous contents of \everypar, and so the tokens \the + % \pageinfo@commands \the \point@toks didn't get inserted where we + % expected. List environments *do* preserve the contents of the box + % \@labels, though. \global\setbox\@labels\hbox{\unhbox\@labels \the \pageinfo@commands \the \point@toks}% @@ -3776,7 +3731,7 @@ %-------------------------------------------------------------------- -% choices (for multiple choice) +% choices (for multiple choice) and checkboxes \renewcommand\thechoice{\Alph{choice}} @@ -3798,21 +3753,12 @@ \CorrectChoiceEmphasis{\bfseries} \let\correctchoiceemphasis\CorrectChoiceEmphasis - +% Note: \do@choice@pageinfo is used in both the choices and +% the checkboxes environments. \newtoks\choice@toks \def\do@choice@pageinfo{% \choice@toks={% - \addtocounter{ques@object}{1}% - \edef\q@object@label{% - question\arabic{question}@object\arabic{ques@object}}% - \PgInfo@write{\q@object@label}% - \set@counter@to@pageof{Curr@Page}{\q@object@label}% - \expandafter\ifx\csname Contin@\theCurr@Page\endcsname\relax - % We're the first \question, \part, \subpart, \subsubpart, - % or choice on this page: - \global\expandafter\edef\csname - Contin@\theCurr@Page\endcsname{\arabic{question}}% - \fi + \questionobject@pluspagecheck \choice@toks={}% }% % Version 2.217-beta changes: @@ -3869,25 +3815,15 @@ \def\choice{% \if@correctchoice \endgroup \fi \refstepcounter{choice}% - \ifnum\value{choice}>1 + \ifnum\value{choice}>1\relax \penalty -50\hskip 1em plus 1em\relax \fi \choicelabel % No need to put the following into a token string; we just put % the choicelabel onto the page, so we're at the spot whose page % number we want to record: - \addtocounter{ques@object}{1}% - \edef\q@object@label{% - question\arabic{question}@object\arabic{ques@object}}% - \PgInfo@write{\q@object@label}% - \set@counter@to@pageof{Curr@Page}{\q@object@label}% - \expandafter\ifx\csname Contin@\theCurr@Page\endcsname\relax - % We're the first \question, \part, \subpart, \subsubpart, - % or choice on this page: - \global\expandafter\edef\csname - Contin@\theCurr@Page\endcsname{\arabic{question}}% - \fi - \nobreak\enskip + \questionobject@pluspagecheck + \nobreak\enskip }% choice \def\CorrectChoice{% \if@correctchoice \endgroup \fi @@ -3896,25 +3832,15 @@ \begingroup \@correctchoicetrue \CorrectChoice@Emphasis \fi - \ifnum\value{choice}>1 + \ifnum\value{choice}>1\relax \penalty -50\hskip 1em plus 1em\relax \fi \choicelabel % No need to put the following into a token string; we just put % the choicelabel onto the page, so we're at the spot whose page % number we want to record: - \addtocounter{ques@object}{1}% - \edef\q@object@label{% - question\arabic{question}@object\arabic{ques@object}}% - \PgInfo@write{\q@object@label}% - \set@counter@to@pageof{Curr@Page}{\q@object@label}% - \expandafter\ifx\csname Contin@\theCurr@Page\endcsname\relax - % We're the first \question, \part, \subpart, \subsubpart, - % or choice on this page: - \global\expandafter\edef\csname - Contin@\theCurr@Page\endcsname{\arabic{question}}% - \fi - \nobreak\enskip + \questionobject@pluspagecheck + \nobreak\enskip }% CorrectChoice \let\correctchoice\CorrectChoice \let\par\@empty @@ -3925,11 +3851,101 @@ }% {\if@correctchoice \endgroup \fi} +\newcommand{\checkboxchar}[1]{\def\checkbox@char{#1}} +\newcommand{\checkedchar}[1]{\def\checked@char{#1}} +\checkboxchar{$\bigcirc$} +\checkedchar{$\surd$} + +\newenvironment{checkboxes}% + {\list{\checkbox@char}% + {% + \settowidth{\leftmargin}{W.\hskip\labelsep\hskip 2.5em}% + \def\choice{% + \if@correctchoice + \endgroup + \fi + \item + \do@choice@pageinfo + } % choice + \def\CorrectChoice{% + \if@correctchoice + \endgroup + \fi + \ifprintanswers + % We can't say \choice here, because that would + % insert an \endgroup: + \begingroup \@correctchoicetrue + \CorrectChoice@Emphasis + \item[\checked@char] + \else + \item + \fi + \do@choice@pageinfo + } % CorrectChoice + \let\correctchoice\CorrectChoice + \labelwidth\leftmargin\advance\labelwidth-\labelsep + \topsep=0pt + \partopsep=0pt + \checkboxeshook + }% + }% + {\if@correctchoice \endgroup \fi \endlist} + +\newenvironment{oneparcheckboxes}% + {% + % Although we're not printing numbers for the choices, we use the + % choice counter to keep track of whether a choice is the first + % one (in which case we don't leave any additional space) or a + % later one (in which case we do leave additional space): + \setcounter{choice}{0}% + \def\choice{% + \if@correctchoice \endgroup \fi + \stepcounter{choice}% + \ifnum\value{choice}>1\relax + \penalty -50\hskip 1em plus 1em\relax + \fi + \checkbox@char + % No need to put the following into a token string; we just put + % \checkbox@char onto the page, so we're at the spot whose page + % number we want to record: + \questionobject@pluspagecheck + \nobreak\enskip + }% choice + \def\CorrectChoice{% + \if@correctchoice \endgroup \fi + \stepcounter{choice}% + \ifprintanswers + \begingroup \@correctchoicetrue + \CorrectChoice@Emphasis + \fi + \ifnum\value{choice}>1\relax + \penalty -50\hskip 1em plus 1em\relax + \fi + \ifprintanswers + \checked@char + \else + \checkbox@char + \fi + % No need to put the following into a token string; we just put + % the choicelabel onto the page, so we're at the spot whose page + % number we want to record: + \questionobject@pluspagecheck + \nobreak\enskip + }% CorrectChoice + \let\correctchoice\CorrectChoice + \let\par\@empty + % If we're continuing the paragraph containing the question, + % then leave a bit of space before the first choice: + \ifvmode\else\enskip\fi + \ignorespaces + }% + {\if@correctchoice \endgroup \fi} -%-------------------------------------------------------------------- -% Answer Lines (for short answer questions) - -% Note: \ques@ref is also used in \item@points@pageinfo + +%-------------------------------------------------------------------- +% Answer Lines (for short answer questions) + +% Note: \ques@ref is also used in \item@points@pageinfo \def\ques@ref{question} \def\part@ref{part} @@ -4070,7 +4086,58 @@ } %-------------------------------------------------------------------- -% \uplevel and \fullwidth: +% \makeemptybox + +% \makeemptybox takes one argument, which is a length, and it creates +% an empty box of width the length of the current line and of height +% equal to the argument. That is, the box extends from the current +% left margin (which depends on whether we're in a question, part, +% subpart, or subsubpart) to the right margin. + +% As of version 2.304, the argument of \makeemptybox can be either +% a length, or \fill, or \stretch{number}. + +% \newcommand\makeemptybox[1]{ +% \par +% \begingroup +% \setlength{\fboxsep}{0pt}% +% \framebox[\linewidth]{% +% \vrule height 0pt depth #1 width 0pt +% }% +% \endgroup +% } + +\newlength\minboxheight +\setlength\minboxheight{.1in} + +\newcommand\makeemptybox[1]{% + \par + \hbox to \hsize{\hskip\@totalleftmargin \leaders\hrule\hfill}% + \nointerlineskip + \begingroup + \setbox0=\hbox to \hsize{\hskip\@totalleftmargin + \vrule height\minboxheight \hfill \vrule}% + % The vertical size desired may not be an exact multiple of + % \minboxheight, and so \cleaders might leave a gap between the + % vertical lines and the horizontal lines above and below it. + % Thus, we put a single copy of \box0 immediately below the + % horizontal line above and we'll also put a single copy of \box0 + % immediately above the horizontal line below. + \copy0 + \nobreak + \vskip -\minboxheight + \cleaders \copy0 \vskip #1 + \vskip -\minboxheight + \nointerlineskip + \copy0 + \endgroup + \nointerlineskip + \hbox to \hsize{\hskip\@totalleftmargin \leaders\hrule\hfill}% +} + +%-------------------------------------------------------------------- +% \uplevel and \fullwidth +% and the EnvUplevel and EnvFullwidth environments: % \uplevel is used to print text at the indentation level of the % enclosing environment. For example, to precede a question with @@ -4079,14 +4146,26 @@ % % \fullwidth is similar, but uses the full page of text on the page. +% The EnvUplevel environment is similar to the \uplevel command, but it +% has the advantage that you can include verbatim material (using, e.g., +% the \verb command) in the environment. (You can't include verbatim +% material in the argument of an \uplevel command.) + +% The EnvFullwidth environment is similar to the \fullwidth command, but +% it has the advantage that you can include verbatim material (using, +% e.g., the \verb command) in the environment. (You can't include +% verbatim material in the argument of an \fullwidth command.) + + \long\def\uplevel#1{% \par\bigskip \vbox{% + % We entered internal vertical mode, and so we get \parshape=0. % We set \leftskip to provide the correct left margin for whatever - % text is in the argument of the \uplevel command: + % is in the argument of the \uplevel command: \leftskip=\@totalleftmargin \advance\leftskip-\leftmargin - % We adjust \@totalleftmargin (and linewidth?) in case there's a + % We adjust \@totalleftmargin and linewidth in case there's a % solution environment inside of the argument to the \uplevel: \advance\@totalleftmargin-\leftmargin \advance\linewidth\leftmargin @@ -4095,9 +4174,24 @@ \nobreak } +\newenvironment{EnvUplevel} + {\par\bigskip\vbox\bgroup + % We set \leftskip to provide the correct left margin for whatever + % is inside of the environment: + \leftskip=\@totalleftmargin + \advance\leftskip-\leftmargin + % We adjust \@totalleftmargin (and linewidth?) in case there's a + % solution environment inside of the environment: + \advance\@totalleftmargin-\leftmargin + \advance\linewidth\leftmargin + } + {\egroup\nobreak} + + \long\def\fullwidth#1{% \par\bigskip \vbox{% + % We entered internal vertical mode, and so we get \parshape=0. \leftskip=0pt \rightskip=0pt \advance\linewidth\@totalleftmargin \@totalleftmargin=0pt @@ -4106,6 +4200,17 @@ \nobreak } +\newenvironment{EnvFullwidth} + {\par\bigskip\vbox\bgroup + % We entered internal vertical mode, and so we get \parshape=0. + \leftskip=0pt \rightskip=0pt + % We adjust \@totalleftmargin (and linewidth?) in case there's a + % solution environment inside of the environment: + \advance\linewidth\@totalleftmargin + \@totalleftmargin=0pt + } + {\egroup\nobreak} + %-------------------------------------------------------------------- %-------------------------------------------------------------------- @@ -4122,69 +4227,112 @@ \def\cellwidth#1{\@cellwidth=#1} \def\gradetablestretch#1{\def\@gtblstretch{#1}} +% \settabletotalpoints allows the user to specify a total +% number of points to appear in a table that may be different +% from the sum of the points in the table: +\newcommand\prt@tablepoints{\prt@hlfcntr{tbl@points}} +\newcommand\settabletotalpoints[1]{% + \def\prt@tablepoints{#1}% +}% \settabletotalpoints + +% \settabletotalbonuspoints is similar to \settabletotalpoints: +\newcommand\prt@tablebonuspoints{\prt@hlfcntr{tbl@bonuspoints}} +\newcommand\settabletotalbonuspoints[1]{% + \def\prt@tablebonuspoints{#1}% +}% \settabletotalbonuspoints + % All of the following that begin with `h' are for horizontal tables, % and all of them that begin with `v' are for vertical tables: \def\hqword#1{\def\@hqword{#1}} \def\hpword#1{\def\@hpword{#1}} \def\hsword#1{\def\@hsword{#1}} \def\htword#1{\def\@htword{#1}} +\def\hpgword#1{\def\@hpgword{#1}} + \def\vqword#1{\def\@vqword{#1}} \def\vpword#1{\def\@vpword{#1}} \def\vsword#1{\def\@vsword{#1}} \def\vtword#1{\def\@vtword{#1}} - \def\vpgword#1{\def\@vpgword{#1}} -\def\hpgword#1{\def\@hpgword{#1}} + % The following are the versions for bonusgradetable: \def\bhqword#1{\def\@bhqword{#1}} \def\bhpword#1{\def\@bhpword{#1}} \def\bhsword#1{\def\@bhsword{#1}} \def\bhtword#1{\def\@bhtword{#1}} +\def\bhpgword#1{\def\@bhpgword{#1}} + \def\bvqword#1{\def\@bvqword{#1}} \def\bvpword#1{\def\@bvpword{#1}} \def\bvsword#1{\def\@bvsword{#1}} \def\bvtword#1{\def\@bvtword{#1}} - \def\bvpgword#1{\def\@bvpgword{#1}} -\def\bhpgword#1{\def\@bhpgword{#1}} + +% The following are the versions for combinedgradetable: +\def\chqword#1{\def\@chqword{#1}} +\def\chpword#1{\def\@chpword{#1}} +\def\chbpword#1{\def\@chbpword{#1}} +\def\chsword#1{\def\@chsword{#1}} +\def\chtword#1{\def\@chtword{#1}} +\def\chpgword#1{\def\@chpgword{#1}} + +\def\cvqword#1{\def\@cvqword{#1}} +\def\cvpword#1{\def\@cvpword{#1}} +\def\cvbpword#1{\def\@cvbpword{#1}} +\def\cvsword#1{\def\@cvsword{#1}} +\def\cvtword#1{\def\@cvtword{#1}} +\def\cvpgword#1{\def\@cvpgword{#1}} + % Initialize: \cellwidth{2em} \gradetablestretch{1.5} + +\hqword{Question:} +\hpgword{Page:} \hpword{Points:} \hsword{Score:} \htword{Total} \vpword{Points} \vsword{Score} \vtword{Total:} +\vqword{Question} +\vpgword{Page} +\bhqword{Question:} +\bhpgword{Page:} \bhpword{Bonus Points:} \bhsword{Score:} \bhtword{Total} +\bvqword{Question} +\bvpgword{Page} \bvpword{Bonus Points} \bvsword{Score} \bvtword{Total:} -% For tables indexed by question number: -\vqword{Question} -\hqword{Question:} -\bvqword{Question} -\bhqword{Question:} - -% For tables indexed by page number: -\vpgword{Page} -\hpgword{Page:} -\bvpgword{Page} -\bhpgword{Page:} - +\chqword{Question:} +\chpgword{Page:} +\chpword{Points:} +\chbpword{Bonus Points:} +\chsword{Score:} +\chtword{Total} +\cvqword{Question} +\cvpgword{Page} +\cvpword{Points} +\cvbpword{Bonus Points} +\cvsword{Score} +\cvtword{Total:} % The only commands here accessible to the user are \gradetable, -% \bonusgradetable, \pointtable, \bonuspointtable, \partialgradetable, -% \partialbonusgradetable, \partialpointtable, -% \partialbonuspointtable, \begingradingrange, and \endgradingrange. +% \bonusgradetable, \combinedgradetable, \pointtable, +% \bonuspointtable, \combinedpointtable, \partialgradetable, +% \partialbonusgradetable, \partialcombinedtable, \partialpointtable, +% \partialbonuspointtable, \partialcombinedpointtable, +% \begingradingrange, \endgradingrange, \pointsinrange, and +% \bonuspointsinrange. % The possibilities are @@ -4198,6 +4346,11 @@ % \bonusgradetable[h][questions] % \bonusgradetable[h][pages] +% \combinedgradetable[v][questions] +% \combinedgradetable[v][pages] +% \combinedgradetable[h][questions] +% \combinedgradetable[h][pages] + % \pointtable[v][questions] % \pointtable[v][pages] % \pointtable[h][questions] @@ -4208,6 +4361,11 @@ % \bonuspointtable[h][questions] % \bonuspointtable[h][pages] +% \combinedpointtable[v][questions] +% \combinedpointtable[v][pages] +% \combinedpointtable[h][questions] +% \combinedpointtable[h][pages] + % \partialgradetable{whatever}[v][questions] % \partialgradetable{whatever}[v][pages] % \partialgradetable{whatever}[h][questions] @@ -4218,6 +4376,11 @@ % \partialbonusgradetable{whatever}[h][questions] % \partialbonusgradetable{whatever}[h][pages] +% \partialcombinedgradetable{whatever}[v][questions] +% \partialcombinedgradetable{whatever}[v][pages] +% \partialcombinedgradetable{whatever}[h][questions] +% \partialcombinedgradetable{whatever}[h][pages] + % \partialpointtable{whatever}[v][questions] % \partialpointtable{whatever}[v][pages] % \partialpointtable{whatever}[h][questions] @@ -4228,9 +4391,17 @@ % \partialbonuspointtable{whatever}[h][questions] % \partialbonuspointtable{whatever}[h][pages] +% \partialcombinedpointtable{whatever}[v][questions] +% \partialcombinedpointtable{whatever}[v][pages] +% \partialcombinedpointtable{whatever}[h][questions] +% \partialcombinedpointtable{whatever}[h][pages] + % \begingradingrange{whatever} % \endgradingrange{whatever} % +% \pointsinrange{whatever} +% \bonuspointsinrange{whatever} +% % where ``whatever'' is a label chosen by the user. % If one or both optional arguments are omitted, the defaults are @@ -4241,10 +4412,14 @@ \newif\if@scores % \@partialtrue means we're doing \partialgradetable, -% \partialbonusgradetable, \partialpointtable, or -% \partialbonuspointtable: +% \partialbonusgradetable, \partialcombinedgradetable, +% \partialpointtable, \partialbonuspointtable, or +% \partialcombinedpointtable: \newif\if@partial +% \@combinedtrue means we're doing \combinedgradetable +% or \combinedpointtable: +\newif\if@combined % It's OK to use the counter num@cols as a scratch counter % in \begingradingrange and \endgradingrange because @@ -4282,11 +4457,16 @@ % for the questions (or pages) that appear on the table: \new@hlfcntr{tbl@points} +% We'll use the counter tbl@bonuspoints to add up the total bonus +% points for the questions (or pages) that appear on the table: +\new@hlfcntr{tbl@bonuspoints} + \def\partialgradetable#1{% \@scorestrue \@bonusfalse \@partialtrue + \@combinedfalse \def\tbl@range{#1}% % If the user doesn't include the optional argument % choosing between vertical and horizontal, @@ -4298,6 +4478,7 @@ \@scorestrue \@bonustrue \@partialtrue + \@combinedfalse \def\tbl@range{#1}% % If the user doesn't include the optional argument % choosing between vertical and horizontal, @@ -4305,10 +4486,23 @@ \@ifnextchar[{\i@gtable}{\i@gtable[v]}% }% partialbonusgradetable +\def\partialcombinedgradetable#1{% + \@scorestrue + \@bonusfalse + \@partialtrue + \@combinedtrue + \def\tbl@range{#1}% + % If the user doesn't include the optional argument + % choosing between vertical and horizontal, + % we give them vertical: + \@ifnextchar[{\i@gtable}{\i@gtable[v]}% +}% partialcombinedgradetable + \def\partialpointtable#1{% \@scoresfalse \@bonusfalse \@partialtrue + \@combinedfalse \def\tbl@range{#1}% % If the user doesn't include the optional argument % choosing between vertical and horizontal, @@ -4320,6 +4514,7 @@ \@scoresfalse \@bonustrue \@partialtrue + \@combinedfalse \def\tbl@range{#1}% % If the user doesn't include the optional argument % choosing between vertical and horizontal, @@ -4327,12 +4522,25 @@ \@ifnextchar[{\i@gtable}{\i@gtable[v]}% }% partialbonuspointtable +\def\partialcombinedpointtable#1{% + \@scoresfalse + \@bonusfalse + \@partialtrue + \@combinedtrue + \def\tbl@range{#1}% + % If the user doesn't include the optional argument + % choosing between vertical and horizontal, + % we give them vertical: + \@ifnextchar[{\i@gtable}{\i@gtable[v]}% +}% partialcombinedpointtable + %-------------------------------------------------------------------- \def\gradetable{% \@scorestrue \@bonusfalse \@partialfalse + \@combinedfalse % If the user doesn't include the optional argument % choosing between vertical and horizontal, % we give them vertical: @@ -4343,6 +4551,18 @@ \@scorestrue \@bonustrue \@partialfalse + \@combinedfalse + % If the user doesn't include the optional argument + % choosing between vertical and horizontal, + % we give them vertical: + \@ifnextchar[{\i@gtable}{\i@gtable[v]}% +}% bonusgradetable + +\def\combinedgradetable{% + \@scorestrue + \@bonusfalse + \@partialfalse + \@combinedtrue % If the user doesn't include the optional argument % choosing between vertical and horizontal, % we give them vertical: @@ -4353,6 +4573,7 @@ \@scoresfalse \@bonusfalse \@partialfalse + \@combinedfalse % If the user doesn't include the optional argument % choosing between vertical and horizontal, % we give them vertical: @@ -4363,6 +4584,18 @@ \@scoresfalse \@bonustrue \@partialfalse + \@combinedfalse + % If the user doesn't include the optional argument + % choosing between vertical and horizontal, + % we give them vertical: + \@ifnextchar[{\i@gtable}{\i@gtable[v]}% +}% bonuspointtable + +\def\combinedpointtable{% + \@scoresfalse + \@bonusfalse + \@partialfalse + \@combinedtrue % If the user doesn't include the optional argument % choosing between vertical and horizontal, % we give them vertical: @@ -4416,6 +4649,8 @@ \def\@questionsref{questions} \def\@pagesref{pages} \def\do@table#1#2{% + % The first argument is ``v'' or ``h''; + % the second argument is ``questions'' or ``pages''. % See whether we're doing a table indexed by % questions or by pages: \begingroup % avoid trouble from using \@temp @@ -4459,10 +4694,14 @@ %-------------------------------------------------------------------- % Grade and point tables indexed by question numbers: +% We get to \find@qrange if we know we're doing a table indexed +% by question numbers. The argument is either ``v'' or ``h''. +% If we're not doing a partial table, then \find@qrange sets +% \tbl@firstq to 1 and \tbl@lastq to \numquestions. Otherwise, % \find@qrange makes sure the grading range is defined and that % its last question isn't before its first question. -% \@tblquestions branches, depending on whether the user -% selected [v] or [h]. +% \find@qrange then calls \@tblquestions, passing along the argument +% that is either ``v'' or ``h''. \def\find@qrange#1{% % We're doing a table indexed by question numbers. @@ -4480,7 +4719,7 @@ \edef\tbl@firstq{\csname tbl@\tbl@range @firstq\endcsname}% \edef\tbl@lastq{\csname tbl@\tbl@range @lastq\endcsname}% % Check that firstq precedes or equals lastq: - \ifnum \tbl@firstq > \tbl@lastq + \ifnum \tbl@firstq > \tbl@lastq\relax \fbox{Error: Grading Range `\tbl@range ': Last question precedes first question.}% \ClassError{exam}{% @@ -4509,6 +4748,8 @@ }% find@qrange \def\@tblquestions#1{% + % \tbl@firstq and \tbl@lastq have already been set. + % The argument is either ``v'' or ``h', and we branch accordingly. \if v#1% \@vtblquestions \else @@ -4552,8 +4793,9 @@ \def\@vtblquestions{% % The table is vertical and indexed by question numbers. - % See whether it's bonus or non-bonus, and - % gradetable or pointtable: + % The question range has already been determined. + % Branch according to whether it's bonus, non-bonus, or combined, + % and gradetable or pointtable: \begingroup % Save the current value of question in @iterator, so that % we can restore it after doing the table: @@ -4566,10 +4808,18 @@ \@bvpttblquestions \fi \else - \if@scores - \@vgrdtblquestions + \if@combined + \if@scores + \@cvgrdtblquestions + \else + \@cvpttblquestions + \fi \else - \@vpttblquestions + \if@scores + \@vgrdtblquestions + \else + \@vpttblquestions + \fi \fi \fi % Restore the saved value of question: @@ -4577,16 +4827,95 @@ \endgroup }% @vtblquestions +\def\@cvgrdtblquestions{% + % Vertical combined gradetable, indexed by questions + \set@hlfcntr{tbl@points}{0}% + \set@hlfcntr{tbl@bonuspoints}{0}% + \begin{tabular}{|c|c|c|c|} + \hline + {\@cvqword}& {\@cvpword}& {\@cvbpword}& {\@cvsword}\\ + \hline + \setcounter{question}{\tbl@firstq}% + \addtocounter{question}{-1}\do@cvloop + {\@cvtword}& \prt@tablepoints& + \prt@tablebonuspoints& + \hbox to \@cellwidth{\hfill}\\ + \hline + \end{tabular}% +} +\def\do@cvloop{% + % \do@cvloop is used by \@cvgrdtblquestions + \addtocounter{question}{1}% + \ref{question@\arabic{question}} & + \pointsofquestion{\arabic{question}}& + \bonuspointsofquestion{\arabic{question}}&\\ + \hline + \@ifundefined{pointsofq@\romannumeral \c@question}% + {}% + {\addto@hlfcntr{tbl@points} + {\csname pointsofq@\romannumeral \c@question\endcsname}}% + \@ifundefined{bonuspointsofq@\romannumeral \c@question}% + {}% + {\addto@hlfcntr{tbl@bonuspoints} + {\csname bonuspointsofq@\romannumeral \c@question\endcsname}}% + \ifnum \value{question} < \tbl@lastq\relax + \let\next@cvloop=\do@cvloop + \else + \let\next@cvloop=\relax + \fi + \next@cvloop +}% do@cvloop + + +\def\@cvpttblquestions{% + % Vertical combined pointtable, indexed by questions + \set@hlfcntr{tbl@points}{0}% + \set@hlfcntr{tbl@bonuspoints}{0}% + \begin{tabular}{|c|c|c|} + \hline + {\@cvqword}& {\@cvpword}& {\@cvbpword}\\ + \hline + \setcounter{question}{\tbl@firstq}% + \addtocounter{question}{-1}\do@cvptloop + {\@cvtword}& \prt@tablepoints& + \prt@tablebonuspoints\\ + \hline + \end{tabular}% +} +\def\do@cvptloop{% + % \do@cvptloop is used by \@cvpttblquestions + \addtocounter{question}{1}% + \ref{question@\arabic{question}} & + \pointsofquestion{\arabic{question}}& + \bonuspointsofquestion{\arabic{question}}\\ + \hline + \@ifundefined{pointsofq@\romannumeral \c@question}% + {}% + {\addto@hlfcntr{tbl@points} + {\csname pointsofq@\romannumeral \c@question\endcsname}}% + \@ifundefined{bonuspointsofq@\romannumeral \c@question}% + {}% + {\addto@hlfcntr{tbl@bonuspoints} + {\csname bonuspointsofq@\romannumeral \c@question\endcsname}}% + \ifnum \value{question} < \tbl@lastq\relax + \let\next@cvptloop=\do@cvptloop + \else + \let\next@cvptloop=\relax + \fi + \next@cvptloop +}% do@cvptloop + + \def\@bvgrdtblquestions{% % Vertical bonus gradetable, indexed by questions: - \set@hlfcntr{tbl@points}{0}% + \set@hlfcntr{tbl@bonuspoints}{0}% \begin{tabular}{|c|c|c|} \hline {\@bvqword}& {\@bvpword}& {\@bvsword}\\ \hline \setcounter{question}{\tbl@firstq}% \addtocounter{question}{-1}\do@bvloop - {\@bvtword}& \prt@hlfcntr{tbl@points}&\hbox to \@cellwidth{\hfill}\\ + {\@bvtword}& \prt@tablebonuspoints&\hbox to \@cellwidth{\hfill}\\ \hline \end{tabular}% }% @bvgrdtblquestions @@ -4598,7 +4927,7 @@ \hline \@ifundefined{bonuspointsofq@\romannumeral \c@question}% {}% - {\addto@hlfcntr{tbl@points} + {\addto@hlfcntr{tbl@bonuspoints} {\csname bonuspointsofq@\romannumeral \c@question\endcsname}}% \ifnum \value{question} < \tbl@lastq\relax \let\next@bvloop=\do@bvloop @@ -4608,16 +4937,17 @@ \next@bvloop }% do@bvloop + \def\@bvpttblquestions{% % Vertical bonus point table, indexed by questions: - \set@hlfcntr{tbl@points}{0}% + \set@hlfcntr{tbl@bonuspoints}{0}% \begin{tabular}{|c|c|} \hline {\@bvqword}& {\@bvpword}\\ \hline \setcounter{question}{\tbl@firstq}% \addtocounter{question}{-1}\do@bvptloop - {\@bvtword}& \prt@hlfcntr{tbl@points}\\ + {\@bvtword}& \prt@tablebonuspoints\\ \hline \end{tabular}% }% @bvpttblquestions @@ -4629,7 +4959,7 @@ \hline \@ifundefined{bonuspointsofq@\romannumeral \c@question}% {}% - {\addto@hlfcntr{tbl@points} + {\addto@hlfcntr{tbl@bonuspoints} {\csname bonuspointsofq@\romannumeral \c@question\endcsname}}% \ifnum \value{question} < \tbl@lastq\relax \let\next@bvptloop=\do@bvptloop @@ -4648,7 +4978,7 @@ \hline \setcounter{question}{\tbl@firstq}% \addtocounter{question}{-1}\do@vloop - {\@vtword}& \prt@hlfcntr{tbl@points}&\hbox to \@cellwidth{\hfill}\\ + {\@vtword}& \prt@tablepoints&\hbox to \@cellwidth{\hfill}\\ \hline \end{tabular}% }% @vgrdtblquestions @@ -4670,6 +5000,7 @@ \next@vloop }% do@vloop + \def\@vpttblquestions{% % Vertical non-bonus point table, indexed by questions: \set@hlfcntr{tbl@points}{0}% @@ -4679,7 +5010,7 @@ \hline \setcounter{question}{\tbl@firstq}% \addtocounter{question}{-1}\do@vptloop - {\@vtword}& \prt@hlfcntr{tbl@points}\\ + {\@vtword}& \prt@tablepoints\\ \hline \end{tabular}% }% @vpttblquestions @@ -4706,7 +5037,12 @@ % Horizontal, indexed by question numbers: \def\@htblquestions{% + % We get here from \@tblquestions. % The table is horizontal and indexed by question numbers. + % The question range has already been determined. + % Set num@cols equal to the number of questions on the table, and + % do either bonus, combined, or non-bonus table, in each case + % putting in a line for scores only if it's a gradetable: \@ifundefined{exam@numquestions}% {}% {% @@ -4714,24 +5050,25 @@ \addtocounter{num@cols}{-\tbl@firstq}% \addtocounter{num@cols}{1}% }% - % See whether it's bonus or non-bonus, and - % gradetable or pointtable: + % Do either bonus, combined, or non-bonus table. In each case, put + % in a line for scores if it's a gradetable: \begingroup % Save the current value of question in @iterator, so that % we can restore it after doing the table: \setcounter{@iterator}{\value{question}}% \renewcommand\arraystretch{\@gtblstretch}% \if@bonus - \set@hlfcntr{tbl@points}{0}% + % It's a horizontal bonus table, by questions: \begin{tabular}{|l|*{\thenum@cols}{c|}c|} \hline {\@bhqword}& \setcounter{question}{\tbl@firstq}% \addtocounter{question}{-1}\do@qnumloop {\@bhtword}\\ \hline + \set@hlfcntr{tbl@bonuspoints}{0}% {\@bhpword}& \setcounter{question}{\tbl@firstq}% \addtocounter{question}{-1}\do@bptloop - \prt@hlfcntr{tbl@points}\\ + \prt@tablebonuspoints\\ \hline % If it's a grade table, add in the score line: \if@scores @@ -4742,25 +5079,54 @@ \fi \end{tabular}% \else - \set@hlfcntr{tbl@points}{0}% - \begin{tabular}{|l|*{\thenum@cols}{c|}c|} - \hline - {\@hqword}& \setcounter{question}{\tbl@firstq}% - \addtocounter{question}{-1}\do@qnumloop - {\@htword}\\ - \hline - {\@hpword}& \setcounter{question}{\tbl@firstq}% - \addtocounter{question}{-1}\do@ptloop - \prt@hlfcntr{tbl@points}\\ - \hline - % If it's a grade table, add in the score line: - \if@scores - {\@hsword}& \setcounter{question}{\tbl@firstq}% - \addtocounter{question}{-1}\do@sloop - \\ + \if@combined + % It's a horizontal combined table, by questions: + \begin{tabular}{|l|*{\thenum@cols}{c|}c|} \hline - \fi - \end{tabular}% + {\@chqword}& \setcounter{question}{\tbl@firstq}% + \addtocounter{question}{-1}\do@qnumloop + {\@chtword}\\ + \hline + \set@hlfcntr{tbl@points}{0}% + {\@chpword}& \setcounter{question}{\tbl@firstq}% + \addtocounter{question}{-1}\do@ptloop + \prt@tablepoints\\ + \hline + \set@hlfcntr{tbl@bonuspoints}{0}% + {\@chbpword}& \setcounter{question}{\tbl@firstq}% + \addtocounter{question}{-1}\do@bptloop + \prt@tablebonuspoints\\ + \hline + % If it's a grade table, add in the score line: + \if@scores + {\@chsword}& \setcounter{question}{\tbl@firstq}% + \addtocounter{question}{-1}\do@sloop + \\ + \hline + \fi + \end{tabular}% + \else + % Horizontal non-bonus table, indexed by question number: + \set@hlfcntr{tbl@points}{0}% + \begin{tabular}{|l|*{\thenum@cols}{c|}c|} + \hline + {\@hqword}& \setcounter{question}{\tbl@firstq}% + \addtocounter{question}{-1}\do@qnumloop + {\@htword}\\ + \hline + {\@hpword}& \setcounter{question}{\tbl@firstq}% + \addtocounter{question}{-1}\do@ptloop + \prt@tablepoints\\ + \hline + % If it's a grade table, add in the score line: + \if@scores + {\@hsword}& \setcounter{question}{\tbl@firstq}% + \addtocounter{question}{-1}\do@sloop + \\ + \hline + \fi + \end{tabular}% + \fi \fi % Restore the saved value of question: \setcounter{question}{\value{@iterator}}% @@ -4768,11 +5134,11 @@ }% @htblquestions -% \do@qnumloop and \do@sloop are used both by non-bonus gradetable and -% by bonusgradetable: +% \do@qnumloop and \do@sloop are used by non-bonus, +% combined, and bonus tables: \def\do@qnumloop{% \addtocounter{question}{1}% - \ref{question@\arabic{question}} & + \ref{question@\arabic{question}}& \ifnum \value{question} < \tbl@lastq\relax \let\next@qnloop=\do@qnumloop \else @@ -4791,7 +5157,7 @@ \next@sloop }% do@sloop -% \do@ptloop is used only by non-bonus gradetable: +% \do@ptloop is used by combined and non-bonus tables: \def\do@ptloop{% \addtocounter{question}{1}% \pointsofquestion{\arabic{question}}& @@ -4807,13 +5173,13 @@ \next@ptloop }% do@ptloop -% \do@bptloop is used only by bonusgradetable: +% \do@bptloop is used by bonus and combined tables: \def\do@bptloop{% \addtocounter{question}{1}% \bonuspointsofquestion{\arabic{question}}& \@ifundefined{bonuspointsofq@\romannumeral \c@question}% {}% - {\addto@hlfcntr{tbl@points} + {\addto@hlfcntr{tbl@bonuspoints} {\csname bonuspointsofq@\romannumeral \c@question\endcsname}}% \ifnum \value{question} < \tbl@lastq\relax \let\next@bptloop=\do@bptloop @@ -4829,7 +5195,7 @@ % Grade and point tables indexed by page numbers: -% The only pages listed are those on which there is a nonzero number +% The only pages listed are those on which there are a nonzero number % of points. We check pages \tbl@firstp through \tbl@lastp % Once we've checked that, e.g., \lastpage@withpoints and % \pointsonpage@\romannumeral{\lastpage@withpoints} are defined, we @@ -4849,13 +5215,21 @@ % isn't defined, tmp@hlfcntr gets the value zero (because of the way % that \set@hlfcntr is written). - -% \find@prange makes sure the grading range is defined and that -% its last page isn't before its first page. - +% \find@prange makes sure the grading range is defined and that its +% last page isn't before its first page (if it's a partial table). In +% any case, it then sets \tbl@firstp and \tbl@lastp, and calls +% \@tblpages. \def\find@prange#1{% % We're doing a table indexed by pages. + % The argument is either ``v'' or ``h''. + % After determining the first and last page of the range, we + % call \@tblpages, passing it that argument (i.e., we say + % \@tblpages{#1}). + % If not a partial table, we set \tbl@firstp to 1 and \tbl@lastp to + % the last page with the appropriate points (and so if it's a + % combined table, it's the last page to have either bonus or + % non-bonus points). \if@partial \@ifundefined{tbl@\tbl@range @firstp}% {% @@ -4870,7 +5244,7 @@ \edef\tbl@firstp{\csname tbl@\tbl@range @firstp\endcsname}% \edef\tbl@lastp{\csname tbl@\tbl@range @lastp\endcsname}% % Check that firstp precedes or equals lastp: - \ifnum \tbl@firstp > \tbl@lastp + \ifnum \tbl@firstp > \tbl@lastp\relax \fbox{Error: Grading Range `\tbl@range ': Last page precedes first page.}% \ClassError{exam}{% @@ -4889,20 +5263,25 @@ \def\tbl@firstp{1}% % \tbl@lastp isn't used on the first run of LaTeX, and % \lastpage@withbonuspoints is defined on the second and later runs. + \def\tbl@lastp{\lastpage@withpoints}% \if@bonus \def\tbl@lastp{\lastpage@withbonuspoints}% - \else - \def\tbl@lastp{\lastpage@withpoints}% + \fi + \if@combined + \ifnum \lastpage@withbonuspoints > \lastpage@withpoints\relax + \def\tbl@lastp{\lastpage@withbonuspoints}% + \fi \fi \@tblpages{#1}% \fi }% find@prange - -% Check that there's enough info from the .aux file to do a page -% indexed grade table: \def\@tblpages#1{% + % We get here from \find@prange; the argument is either ``v'' or + % ``h''. + % Check that there's enough info from the .aux file to do a page + % indexed grade table. If so, call \@whichtblpgs{#1}: \@ifundefined{lastpage@withpoints}% {\ClassWarning{exam}{% You must run LaTeX twice more\MessageBreak @@ -4927,6 +5306,7 @@ % At this point, we know the table is indexed by pages. % It can be vertical or horizontal, % grade or point, and bonus or non-bonus. + % The argument is either ``v'' or ``h''; test it, and branch: \if v#1% \@vtblpages \else @@ -4971,12 +5351,14 @@ % Vertical, indexed by pages: \def\@vtblpages{% + % We get here from \@whchtblpgs. % At this point, we know it's a vertical table indexed by pages. - % It can be grade or point, and bonus or non-bonus. + % It can be grade or point, and bonus, non-bonus, or combined. \begingroup \renewcommand\arraystretch{\@gtblstretch}% - \set@hlfcntr{tbl@points}{0}% \if@bonus + % It's vertical, bonus, by pages, either point or grade: + \set@hlfcntr{tbl@bonuspoints}{0}% \if@scores \begin{tabular}{|c|c|c|} \hline @@ -4984,7 +5366,8 @@ \hline \setcounter{@iterator}{\tbl@firstp}% \addtocounter{@iterator}{-1}\pg@bvloop - {\@bvtword}& \prt@hlfcntr{tbl@points}&\hbox to \@cellwidth{\hfill}\\ + {\@bvtword}& \prt@tablebonuspoints& + \hbox to \@cellwidth{\hfill}\\ \hline \end{tabular}% \else @@ -4994,31 +5377,65 @@ \hline \setcounter{@iterator}{\tbl@firstp}% \addtocounter{@iterator}{-1}\pg@ptbvloop - {\@bvtword}& \prt@hlfcntr{tbl@points}\\ + {\@bvtword}& \prt@tablebonuspoints\\ \hline \end{tabular}% \fi \else - \if@scores - \begin{tabular}{|c|c|c|} - \hline - {\@vpgword}& {\@vpword}& {\@vsword}\\ - \hline - \setcounter{@iterator}{\tbl@firstp}% - \addtocounter{@iterator}{-1}\pg@vloop - {\@vtword}& \prt@hlfcntr{tbl@points}&\hbox to \@cellwidth{\hfill}\\ - \hline - \end{tabular}% + \if@combined + % It's vertical, combined, by pages, either point or grade: + \set@hlfcntr{tbl@points}{0}% + \set@hlfcntr{tbl@bonuspoints}{0}% + \if@scores + % Combined gradetable, vertical, by pages: + \begin{tabular}{|c|c|c|c|} + \hline + {\@cvpgword}& {\@cvpword}& {\@cvbpword}& {\@cvsword}\\ + \hline + \setcounter{@iterator}{\tbl@firstp}% + \addtocounter{@iterator}{-1}\pg@cvloop + {\@cvtword}& \prt@tablepoints& + \prt@tablebonuspoints& + \hbox to \@cellwidth{\hfill}\\ + \hline + \end{tabular}% + \else + % Combined pointtable, vertical, by pages: + \begin{tabular}{|c|c|c|} + \hline + {\@cvpgword}& {\@cvpword}& {\@cvbpword}\\ + \hline + \setcounter{@iterator}{\tbl@firstp}% + \addtocounter{@iterator}{-1}\pg@ptcvloop + {\@cvtword}& \prt@tablepoints& + \prt@tablebonuspoints\\ + \hline + \end{tabular}% + \fi \else - \begin{tabular}{|c|c|} - \hline - {\@vpgword}& {\@vpword}\\ - \hline - \setcounter{@iterator}{\tbl@firstp}% - \addtocounter{@iterator}{-1}\pg@ptvloop - {\@vtword}& \prt@hlfcntr{tbl@points}\\ - \hline - \end{tabular}% + % It's non-bonus, either point or grade: + \set@hlfcntr{tbl@points}{0}% + \if@scores + \begin{tabular}{|c|c|c|} + \hline + {\@vpgword}& {\@vpword}& {\@vsword}\\ + \hline + \setcounter{@iterator}{\tbl@firstp}% + \addtocounter{@iterator}{-1}\pg@vloop + {\@vtword}& \prt@tablepoints&\hbox to \@cellwidth{\hfill}\\ + \hline + \end{tabular}% + \else + \begin{tabular}{|c|c|} + \hline + {\@vpgword}& {\@vpword}\\ + \hline + \setcounter{@iterator}{\tbl@firstp}% + \addtocounter{@iterator}{-1}\pg@ptvloop + {\@vtword}& \prt@tablepoints\\ + \hline + \end{tabular}% + \fi \fi \fi \endgroup @@ -5028,9 +5445,7 @@ % \pg@ptvloop and \pg@ptvloopline are used only by non-bonus pointtable: \def\pg@ptvloop{% \addtocounter{@iterator}{1}% - % spanish.ldf redefines \@roman, so we'll avoid using \roman: - \set@hlfcntr{tmp@hlfcntr}{\csname pointsonpage@\romannumeral - \csname c@@iterator\endcsname\endcsname}% + \set@hlfcntr{tmp@hlfcntr}{\pointsonpage{\the@iterator}}% \ifhlfcntr@pos{tmp@hlfcntr}% \add@hlfcntrtohlfcntr{tbl@points}{tmp@hlfcntr}% \pg@ptvloopline @@ -5055,9 +5470,7 @@ % \pg@vloop and \pg@vloopline are used only by non-bonus gradetable: \def\pg@vloop{% \addtocounter{@iterator}{1}% - % spanish.ldf redefines \@roman, so we'll avoid using \roman: - \set@hlfcntr{tmp@hlfcntr}{\csname pointsonpage@\romannumeral - \csname c@@iterator\endcsname\endcsname}% + \set@hlfcntr{tmp@hlfcntr}{\pointsonpage{\the@iterator}}% \ifhlfcntr@pos{tmp@hlfcntr}% \add@hlfcntrtohlfcntr{tbl@points}{tmp@hlfcntr}% \pg@vloopline @@ -5079,14 +5492,123 @@ \hline }% pg@vloopline +% \pg@cvloop, \pg@noncvloopline, \check@bnspts, and +% \pg@cvloopline are used only by combined gradetable: +\def\pg@cvloop{% + \addtocounter{@iterator}{1}% + % Add the bonus points: + \set@hlfcntr{tmp@hlfcntr}{\bonuspointsonpage{\the@iterator}}% + \add@hlfcntrtohlfcntr{tbl@bonuspoints}{tmp@hlfcntr}% + % Add the regular points: + \set@hlfcntr{tmp@hlfcntr}{\csname pointsonpage@\romannumeral + \csname c@@iterator\endcsname\endcsname}% + \add@hlfcntrtohlfcntr{tbl@points}{tmp@hlfcntr}% + % Print a line of the table, if there are points on this page: + \ifhlfcntr@pos{tmp@hlfcntr}% + \pg@noncvloopline + \else + \check@bnspts + \fi + % Do the tail recursion bit: + \ifnum \the@iterator < \tbl@lastp\relax + \let\next@pg@cvloop=\pg@cvloop + \else + \let\next@pg@cvloop=\relax + \fi + \next@pg@cvloop +}% pg@cvloop +\def\pg@noncvloopline{% + % We still don't understand why we need to hide this inside of a + % macro; there's some weird interaction with the \ifnum checking to + % see if something is ``>0''; checking that something is ``=0'' + % doesn't cause the ``\ifnum incomplete'' (or whatever) error. + \pageref{firstpoints@onpage@\arabic{@iterator}}& + \pointsonpage{\the@iterator}& + \bonuspointsonpage{\the@iterator}&\\ + \hline +}% pg@noncvloopline +\def\check@bnspts{% + % We still don't understand why we need to hide this inside of a + % macro; there's some weird interaction with the \ifnum checking to + % see if something is ``>0''; checking that something is ``=0'' + % doesn't cause the ``\ifnum incomplete'' (or whatever) error. + \set@hlfcntr{tmp@hlfcntr}{\bonuspointsonpage{\the@iterator}}% + \ifhlfcntr@pos{tmp@hlfcntr}% + \pg@cvloopline + \fi +}% check@bnspts +\def\pg@cvloopline{% + % We still don't understand why we need to hide this inside of a + % macro; there's some weird interaction with the \ifnum checking to + % see if something is ``>0''; checking that something is ``=0'' + % doesn't cause the ``\ifnum incomplete'' (or whatever) error. + \pageref{firstbonuspoints@onpage@\arabic{@iterator}}& + \pointsonpage{\the@iterator}& + \bonuspointsonpage{\the@iterator}&\\ + \hline +}% pg@cvloopline + +% \pg@ptcvloop, \pg@ptnoncvloopline, \check@ptbnspts, and +% \pg@ptcvloopline are used only by combined pointtable: +\def\pg@ptcvloop{% + \addtocounter{@iterator}{1}% + % Add the bonus points: + \set@hlfcntr{tmp@hlfcntr}{\bonuspointsonpage{\the@iterator}}% + \add@hlfcntrtohlfcntr{tbl@bonuspoints}{tmp@hlfcntr}% + % Add the regular points: + \set@hlfcntr{tmp@hlfcntr}{\pointsonpage{\the@iterator}}% + \add@hlfcntrtohlfcntr{tbl@points}{tmp@hlfcntr}% + % Print a line of the table, if there are points on this page: + \ifhlfcntr@pos{tmp@hlfcntr}% + \pg@ptnoncvloopline + \else + \check@ptbnspts + \fi + % Do the tail recursion bit: + \ifnum \the@iterator < \tbl@lastp\relax + \let\next@pg@ptcvloop=\pg@ptcvloop + \else + \let\next@pg@ptcvloop=\relax + \fi + \next@pg@ptcvloop +}% pg@ptcvloop +\def\pg@ptnoncvloopline{% + % We still don't understand why we need to hide this inside of a + % macro; there's some weird interaction with the \ifnum checking to + % see if something is ``>0''; checking that something is ``=0'' + % doesn't cause the ``\ifnum incomplete'' (or whatever) error. + \pageref{firstpoints@onpage@\arabic{@iterator}}& + \pointsonpage{\the@iterator}& + \bonuspointsonpage{\the@iterator}\\ + \hline +}% pg@ptnoncvloopline +\def\check@ptbnspts{% + % We still don't understand why we need to hide this inside of a + % macro; there's some weird interaction with the \ifnum checking to + % see if something is ``>0''; checking that something is ``=0'' + % doesn't cause the ``\ifnum incomplete'' (or whatever) error. + \set@hlfcntr{tmp@hlfcntr}{\bonuspointsonpage{\the@iterator}}% + \ifhlfcntr@pos{tmp@hlfcntr}% + \pg@ptcvloopline + \fi +}% check@ptbnspts +\def\pg@ptcvloopline{% + % We still don't understand why we need to hide this inside of a + % macro; there's some weird interaction with the \ifnum checking to + % see if something is ``>0''; checking that something is ``=0'' + % doesn't cause the ``\ifnum incomplete'' (or whatever) error. + \pageref{firstbonuspoints@onpage@\arabic{@iterator}}& + \pointsonpage{\the@iterator}& + \bonuspointsonpage{\the@iterator}\\ + \hline +}% pg@ptcvloopline + % \pg@bvloop and \pg@bvloopline are used only by bonus gradetable: \def\pg@bvloop{% \addtocounter{@iterator}{1}% - % spanish.ldf redefines \@roman, so we'll avoid using \roman: - \set@hlfcntr{tmp@hlfcntr}{\csname bonuspointsonpage@\romannumeral - \csname c@@iterator\endcsname\endcsname}% + \set@hlfcntr{tmp@hlfcntr}{\bonuspointsonpage{\the@iterator}}% \ifhlfcntr@pos{tmp@hlfcntr}% - \add@hlfcntrtohlfcntr{tbl@points}{tmp@hlfcntr}% + \add@hlfcntrtohlfcntr{tbl@bonuspoints}{tmp@hlfcntr}% \pg@bvloopline \fi \ifnum \the@iterator < \tbl@lastp\relax @@ -5109,11 +5631,9 @@ % \pg@ptbvloop and \pg@ptbvloopline are used only by bonus pointtable: \def\pg@ptbvloop{% \addtocounter{@iterator}{1}% - % spanish.ldf redefines \@roman, so we'll avoid using \roman: - \set@hlfcntr{tmp@hlfcntr}{\csname bonuspointsonpage@\romannumeral - \csname c@@iterator\endcsname\endcsname}% + \set@hlfcntr{tmp@hlfcntr}{\bonuspointsonpage{\the@iterator}}% \ifhlfcntr@pos{tmp@hlfcntr}% - \add@hlfcntrtohlfcntr{tbl@points}{tmp@hlfcntr}% + \add@hlfcntrtohlfcntr{tbl@bonuspoints}{tmp@hlfcntr}% \pg@ptbvloopline \fi \ifnum \the@iterator < \tbl@lastp\relax @@ -5140,25 +5660,56 @@ % pages there are with points on them: \newcounter{num@cols} \def\count@pgswpts{% + % We're called by \@htblpages. % \count@pgswpts is used for horizontal - % grade tables and point tables, both - % bonus and non-bonus. + % grade tables and point tables, + % bonus, non-bonus, and combined. \setcounter{num@cols}{0}% \setcounter{@iterator}{\tbl@firstp}% \addtocounter{@iterator}{-1}% \if@bonus \docount@pgswbpts \else - \docount@pgswpts + \if@combined + \docount@pgswcpts + \else + \docount@pgswpts + \fi \fi }% count@pgswpts -% \docount@pgswpts is used for non-bonus gradetable: +\def\docount@pgswcpts{% + % Called by \count@pgswpts + % \docount@pgswcpts is used for combined gradetable. + % Count the number of pages in range with any kind of point (bonus + % or non-bonus): + \addtocounter{@iterator}{1}% + \set@hlfcntr{tmp@hlfcntr}{\pointsonpage{\the@iterator}}% + \ifhlfcntr@pos{tmp@hlfcntr}% + \addtocounter{num@cols}{1}% + \else + \check@bnsptpage + \fi + \ifnum \the@iterator < \tbl@lastp\relax + \let\next@docount=\docount@pgswcpts + \else + \let\next@docount=\relax + \fi + \next@docount +}% docount@pgswcpts +\def\check@bnsptpage{% + % We don't understand why we need to hide this inside of a macro: + \set@hlfcntr{tmp@hlfcntr}{\bonuspointsonpage{\the@iterator}}% + \ifhlfcntr@pos{tmp@hlfcntr}% + \addtocounter{num@cols}{1}% + \fi +}% check@bnsptpage + \def\docount@pgswpts{% + % Called by \count@pgswpts + % \docount@pgswpts is used for non-bonus gradetable: \addtocounter{@iterator}{1}% - % spanish.ldf redefines \@roman, so we'll avoid using \roman: - \set@hlfcntr{tmp@hlfcntr}{\csname pointsonpage@\romannumeral - \csname c@@iterator\endcsname\endcsname}% + \set@hlfcntr{tmp@hlfcntr}{\pointsonpage{\the@iterator}}% \ifhlfcntr@pos{tmp@hlfcntr}% \addtocounter{num@cols}{1}% \fi @@ -5170,12 +5721,11 @@ \next@docount }% docount@pgswpts -% \docount@pgswbpts is used for bonusgradetable: \def\docount@pgswbpts{% + % Called by \count@pgswpts + % \docount@pgswbpts is used for bonusgradetable: \addtocounter{@iterator}{1}% - % spanish.ldf redefines \@roman, so we'll avoid using \roman: - \set@hlfcntr{tmp@hlfcntr}{\csname bonuspointsonpage@\romannumeral - \csname c@@iterator\endcsname\endcsname}% + \set@hlfcntr{tmp@hlfcntr}{\bonuspointsonpage{\the@iterator}}% \ifhlfcntr@pos{tmp@hlfcntr}% \addtocounter{num@cols}{1}% \fi @@ -5190,15 +5740,21 @@ %-------------------------------------------------------------------- \def\@htblpages{% + % We get here from \@whchtblpgs. + % Horizontal grade or point table, by pages: \begingroup \renewcommand\arraystretch{\@gtblstretch}% + % Set num@cols equal to the number of pages with points (of + % correct type): \count@pgswpts % Suppress ``extra alignment tab'' errors if \thenum@cols = 0: - \ifnum \thenum@cols = 0 + \ifnum \thenum@cols = 0\relax \setcounter{num@cols}{1}% \fi \set@hlfcntr{tbl@points}{0}% + \set@hlfcntr{tbl@bonuspoints}{0}% \if@bonus + % Horizontal bonus grade or point table, by pages: \begin{tabular}{|l|*{\thenum@cols}{c|}c|} \hline {\@bhpgword}& \setcounter{@iterator}{\tbl@firstp}% @@ -5207,7 +5763,7 @@ \hline {\@bhpword}& \setcounter{@iterator}{\tbl@firstp}% \addtocounter{@iterator}{-1}\do@bpgptloop - \prt@hlfcntr{tbl@points}\\ + \prt@tablebonuspoints\\ \hline % If it's a grade table, do the line for scores: \if@scores @@ -5218,35 +5774,62 @@ \fi \end{tabular}% \else - \begin{tabular}{|l|*{\thenum@cols}{c|}c|} - \hline - {\@hpgword}& \setcounter{@iterator}{\tbl@firstp}% - \addtocounter{@iterator}{-1}\do@pgnumloop - {\@htword}\\ - \hline - {\@hpword}& \setcounter{@iterator}{\tbl@firstp}% - \addtocounter{@iterator}{-1}\do@pgptloop - \prt@hlfcntr{tbl@points}\\ - \hline - % If it's a grade table, do the line for scores: - \if@scores - {\@hsword}& \setcounter{@iterator}{\tbl@firstp}% - \addtocounter{@iterator}{-1}\do@pgsloop - \\ + \if@combined + % Horizontal combined grade or point table, by pages: + \begin{tabular}{|l|*{\thenum@cols}{c|}c|} \hline - \fi - \end{tabular}% + {\@chpgword}& \setcounter{@iterator}{\tbl@firstp}% + \addtocounter{@iterator}{-1}\do@cpgnumloop + {\@chtword}\\ + \hline + {\@chpword}& \setcounter{@iterator}{\tbl@firstp}% + \addtocounter{@iterator}{-1}\do@cpgptloop + \prt@tablepoints\\ + \hline + {\@chbpword}& \setcounter{@iterator}{\tbl@firstp}% + \addtocounter{@iterator}{-1}\do@cbpgptloop + \prt@tablebonuspoints\\ + \hline + % If it's a grade table, do the line for scores: + \if@scores + {\@chsword}& \setcounter{@iterator}{\tbl@firstp}% + \addtocounter{@iterator}{-1}\do@cpgsloop + \\ + \hline + \fi + \end{tabular}% + \else + % Horizontal non-bonus grade or point table, by pages: + \begin{tabular}{|l|*{\thenum@cols}{c|}c|} + \hline + {\@hpgword}& \setcounter{@iterator}{\tbl@firstp}% + \addtocounter{@iterator}{-1}\do@pgnumloop + {\@htword}\\ + \hline + {\@hpword}& \setcounter{@iterator}{\tbl@firstp}% + \addtocounter{@iterator}{-1}\do@pgptloop + \prt@tablepoints\\ + \hline + % If it's a grade table, do the line for scores: + \if@scores + {\@hsword}& \setcounter{@iterator}{\tbl@firstp}% + \addtocounter{@iterator}{-1}\do@pgsloop + \\ + \hline + \fi + \end{tabular}% + \fi \fi \endgroup }% @htblpages -% \do@pgnumloop, \pg@line, \do@pgptloop, \pgpt@line, \do@pgsloop, and -% \pg@sline are only for non-bonus gradetable: +%-------------------------------------------------------------------- +% \do@pgnumloop, \do@pgptloop, and \do@pgsloop +% are only for non-bonus gradetable. +% \pg@line is also for combinedgradetable. \def\do@pgnumloop{% \addtocounter{@iterator}{1}% - % spanish.ldf redefines \@roman, so we'll avoid using \roman: - \set@hlfcntr{tmp@hlfcntr}{\csname pointsonpage@\romannumeral - \csname c@@iterator\endcsname\endcsname}% + \set@hlfcntr{tmp@hlfcntr}{\pointsonpage{\the@iterator}}% \ifhlfcntr@pos{tmp@hlfcntr}% \pg@line \fi @@ -5258,17 +5841,16 @@ \next@pgnumloop }% \do@pgnumloop \def\pg@line{% + % We still don't know why we need to hide this inside of a macro: \pageref{firstpoints@onpage@\arabic{@iterator}}& }% \pg@line \def\do@pgptloop{% \addtocounter{@iterator}{1}% - % spanish.ldf redefines \@roman, so we'll avoid using \roman: - \set@hlfcntr{tmp@hlfcntr}{\csname pointsonpage@\romannumeral - \csname c@@iterator\endcsname\endcsname}% + \set@hlfcntr{tmp@hlfcntr}{\pointsonpage{\the@iterator}}% \ifhlfcntr@pos{tmp@hlfcntr}% \add@hlfcntrtohlfcntr{tbl@points}{tmp@hlfcntr}% - \pgpt@line + \pgpt@entry \fi \ifnum \the@iterator < \tbl@lastp\relax \let\next@pgptloop=\do@pgptloop @@ -5277,20 +5859,17 @@ \fi \next@pgptloop }% \do@pgptloop -\def\pgpt@line{% - % spanish.ldf redefines \@roman, so we'll avoid using \roman: - \csname pointsonpage@\romannumeral - \csname c@@iterator\endcsname\endcsname & -}% \pgpt@line +% \pgpt@entry is used by different macros: +\def\pgpt@entry{% + % We still don't know why we need to hide this inside of a macro: + \pointsonpage{\the@iterator}& +}% \pgpt@entry \def\do@pgsloop{% \addtocounter{@iterator}{1}% - % spanish.ldf redefines \@roman, so we'll avoid using \roman: - \set@hlfcntr{tmp@hlfcntr}{\csname pointsonpage@\romannumeral - \csname c@@iterator\endcsname\endcsname}% + \set@hlfcntr{tmp@hlfcntr}{\pointsonpage{\the@iterator}}% \ifhlfcntr@pos{tmp@hlfcntr}% - \add@hlfcntrtohlfcntr{tbl@points}{tmp@hlfcntr}% - \pg@sline + \pg@sentry \fi \ifnum \the@iterator < \tbl@lastp\relax \let\next@pgsloop=\do@pgsloop @@ -5299,20 +5878,22 @@ \fi \next@pgsloop }% \do@pgsloop -\def\pg@sline{% +% \pg@sentry is called by several different macros, +% to create different tables: +\def\pg@sentry{% + % We still don't know why we need to hide this inside of a macro: \hbox to \@cellwidth{\hfill}& -}% \pg@sline +}% \pg@sentry %-------------------------------------------------------------------- % These things are for bonusgradetable: -% \do@bpgnumloop, \bpg@line, \do@bpgptloop, \bpgpt@line, \do@bpgsloop, -% and \bpg@sline are only for bonusgradetable: +% \do@bpgnumloop, \do@bpgptloop, \do@bpgsloop, +% and \bpg@sline are only for bonusgradetable. +% \bpg@line is also used for combinedgradetable. \def\do@bpgnumloop{% \addtocounter{@iterator}{1}% - % spanish.ldf redefines \@roman, so we'll avoid using \roman: - \set@hlfcntr{tmp@hlfcntr}{\csname bonuspointsonpage@\romannumeral - \csname c@@iterator\endcsname\endcsname}% + \set@hlfcntr{tmp@hlfcntr}{\bonuspointsonpage{\the@iterator}}% \ifhlfcntr@pos{tmp@hlfcntr}% \bpg@line \fi @@ -5324,16 +5905,15 @@ \next@bpgnumloop }% do@bpgnumloop \def\bpg@line{% + % We still don't know why we need to hide this inside of a macro: \pageref{firstbonuspoints@onpage@\arabic{@iterator}}& }% bpg@line \def\do@bpgptloop{% \addtocounter{@iterator}{1}% - % spanish.ldf redefines \@roman, so we'll avoid using \roman: - \set@hlfcntr{tmp@hlfcntr}{\csname bonuspointsonpage@\romannumeral - \csname c@@iterator\endcsname\endcsname}% + \set@hlfcntr{tmp@hlfcntr}{\bonuspointsonpage{\the@iterator}}% \ifhlfcntr@pos{tmp@hlfcntr}% - \add@hlfcntrtohlfcntr{tbl@points}{tmp@hlfcntr}% + \add@hlfcntrtohlfcntr{tbl@bonuspoints}{tmp@hlfcntr}% \bpgpt@line \fi \ifnum \the@iterator < \tbl@lastp\relax @@ -5343,20 +5923,17 @@ \fi \next@bpgptloop }% do@bpgptloop +% \bpgpt@line is called by several macros: \def\bpgpt@line{% - % spanish.ldf redefines \@roman, so we'll avoid using \roman: - \csname bonuspointsonpage@\romannumeral - \csname c@@iterator\endcsname\endcsname & + % We still don't know why we need to hide this inside of a macro: + \bonuspointsonpage{\the@iterator}& }% bpgpt@line \def\do@bpgsloop{% \addtocounter{@iterator}{1}% - % spanish.ldf redefines \@roman, so we'll avoid using \roman: - \set@hlfcntr{tmp@hlfcntr}{\csname bonuspointsonpage@\romannumeral - \csname c@@iterator\endcsname\endcsname}% + \set@hlfcntr{tmp@hlfcntr}{\bonuspointsonpage{\the@iterator}}% \ifhlfcntr@pos{tmp@hlfcntr}% - \add@hlfcntrtohlfcntr{tbl@points}{tmp@hlfcntr}% - \bpg@sline + \pg@sentry \fi \ifnum \the@iterator < \tbl@lastp\relax \let\next@bpgsloop=\do@bpgsloop @@ -5365,9 +5942,193 @@ \fi \next@bpgsloop }% do@bpgsloop -\def\bpg@sline{% - \hbox to \@cellwidth{\hfill}& -}% bpg@sline + +%-------------------------------------------------------------------- +% These things are for combinedgradetable: + +% \do@cpgnumloop, \cpg@line, \cbpg@line, \do@cpgptloop, \bpgpt@line, +% \do@cpgsloop, \bpg@sline, and \do@cbpgptloop are only for +% combinedgradetable: +\def\do@cpgnumloop{% + \addtocounter{@iterator}{1}% + \set@hlfcntr{tmp@hlfcntr}{\pointsonpage{\the@iterator}}% + \ifhlfcntr@pos{tmp@hlfcntr}% + \pg@line + \else + \check@bpgpts + \fi + \ifnum \the@iterator < \tbl@lastp\relax + \let\next@cpgnumloop=\do@cpgnumloop + \else + \let\next@cpgnumloop=\relax + \fi + \next@cpgnumloop +}% do@bpgnumloop +\def\check@bpgpts{% + \set@hlfcntr{tmp@hlfcntr}{\bonuspointsonpage{\the@iterator}}% + \ifhlfcntr@pos{tmp@hlfcntr}% + \bpg@line + \fi +}% check@bpgpts + +\def\do@cpgptloop{% + \addtocounter{@iterator}{1}% + \set@hlfcntr{tmp@hlfcntr}{\pointsonpage{\the@iterator}}% + \ifhlfcntr@pos{tmp@hlfcntr}% + \add@hlfcntrtohlfcntr{tbl@points}{tmp@hlfcntr}% + \pgpt@entry + \else + \check@cbpts + \fi + \ifnum \the@iterator < \tbl@lastp\relax + \let\next@cpgptloop=\do@cpgptloop + \else + \let\next@cpgptloop=\relax + \fi + \next@cpgptloop +}% do@cpgptloop +\def\check@cbpts{% + \set@hlfcntr{tmp@hlfcntr}{\bonuspointsonpage{\the@iterator}}% + \ifhlfcntr@pos{tmp@hlfcntr}% + \pgpt@entry + \fi +}% check@cbpts + +\def\do@cbpgptloop{% + \addtocounter{@iterator}{1}% + \set@hlfcntr{tmp@hlfcntr}{\bonuspointsonpage{\the@iterator}}% + \ifhlfcntr@pos{tmp@hlfcntr}% + \add@hlfcntrtohlfcntr{tbl@bonuspoints}{tmp@hlfcntr}% + \bpgpt@line + \else + \check@cnonpts + \fi + \ifnum \the@iterator < \tbl@lastp\relax + \let\next@cbpgptloop=\do@cbpgptloop + \else + \let\next@cbpgptloop=\relax + \fi + \next@cbpgptloop +}% do@cbpgptloop +\def\check@cnonpts{% + \set@hlfcntr{tmp@hlfcntr}{\pointsonpage{\the@iterator}}% + \ifhlfcntr@pos{tmp@hlfcntr}% + \bpgpt@line + \fi +}% check@cnonpts + +\def\do@cpgsloop{% + \addtocounter{@iterator}{1}% + \set@hlfcntr{tmp@hlfcntr}{\pointsonpage{\the@iterator}}% + \ifhlfcntr@pos{tmp@hlfcntr}% + \pg@sentry + \else + \check@bnsline + \fi + \ifnum \the@iterator < \tbl@lastp\relax + \let\next@cpgsloop=\do@cpgsloop + \else + \let\next@cpgsloop=\relax + \fi + \next@cpgsloop +}% do@cpgsloop +\def\check@bnsline{% + \set@hlfcntr{tmp@hlfcntr}{\bonuspointsonpage{\the@iterator}}% + \ifhlfcntr@pos{tmp@hlfcntr}% + \pg@sentry + \fi +}% check@bnsline + +%-------------------------------------------------------------------- +% \pointsinrange and \bonuspointsinrange: +% We say either \@bonusfalse or \@bonustrue, and then we check it only +% in \do@countloop: +\def\pointsinrange#1{% + \@bonusfalse + \def\tbl@range{#1}% + \@ifundefined{exam@numpoints}% + {\mbox{\normalfont\bf ??}}% + {\read@range}% +}% pointsinrange + +\def\bonuspointsinrange#1{% + \@bonustrue + \def\tbl@range{#1}% + \@ifundefined{exam@numpoints}% + {\mbox{\normalfont\bf ??}}% + {\read@range}% +}% bonuspointsinrange + +\def\bad@range{% + {\mbox{\normalfont\bf ??}}% + \ClassWarning{exam}{% + Grading range `\tbl@range ' not defined.\MessageBreak + \space\space Run LaTeX again.\MessageBreak + }% +}% bad@range + +\def\read@range{% + \@ifundefined{tbl@\tbl@range @firstq}% + {% + \bad@range + }% + {% + \@ifundefined{tbl@\tbl@range @lastq}% + {% + \bad@range + }% + {% + \edef\tbl@firstq{\csname tbl@\tbl@range @firstq\endcsname}% + \edef\tbl@lastq{\csname tbl@\tbl@range @lastq\endcsname}% + % Check that firstq precedes or equals lastq: + \ifnum \tbl@firstq > \tbl@lastq\relax + \fbox{Error: Grading Range `\tbl@range ': + Last question precedes first question.}% + \ClassError{exam}{% + In grading range `\tbl@range ', + the last question\MessageBreak + \space\space comes before the first question.\MessageBreak + }{% + \string\begingradingrange \space must precede + \string\endgradingrange \space by at + least one question.\MessageBreak + }% + \else + \count@pointsinrange + \fi + }% + }% +}% read@range + +\def\count@pointsinrange{% + % Used for both \pointsinrange and \bonuspointsinrange: + \set@hlfcntr{tbl@points}{0}% + \setcounter{@iterator}{\tbl@firstq}% + \addtocounter{@iterator}{-1}\do@countloop + \prt@hlfcntr{tbl@points}% +}% count@pointsinrange +\def\do@countloop{% + % We check \if@bonus here when needed: + \addtocounter{@iterator}{1}% + \if@bonus + \@ifundefined{bonuspointsofq@\romannumeral \c@@iterator}% + {}% + {\addto@hlfcntr{tbl@points} + {\csname bonuspointsofq@\romannumeral \c@@iterator\endcsname}}% + \else + \@ifundefined{pointsofq@\romannumeral \c@@iterator}% + {}% + {\addto@hlfcntr{tbl@points} + {\csname pointsofq@\romannumeral \c@@iterator\endcsname}}% + \fi + \ifnum \value{@iterator} < \tbl@lastq\relax + \let\next@countloop=\do@countloop + \else + \let\next@countloop=\relax + \fi + \next@countloop +}% do@countloop + %-------------------------------------------------------------------- @@ -5388,80 +6149,164 @@ \def\printanswers{\printanswerstrue} \def\noprintanswers{\printanswersfalse} +% If the documentclass options include ``cancelspace'', then the +% command \cancelspacetrue is given at the beginning of the run. + +% If the documentclass options include ``nocancelspace'', then the +% command \cancelspacefalse is given at the beginning of the run. + +\def\cancelspace{\cancelspacetrue} +\def\nocancelspace{\cancelspacefalse} + +\newcommand\SolutionEmphasis[1]{% + \def\Solution@Emphasis{#1}% +} +\SolutionEmphasis{} % If printanswers is true, we print the solution using a TheSolution -% environment. If printanswers is false, we insert blank vertical -% space equal to the optional argument (the default value of which is -% 0pt). +% environment. If printanswers is false and cancelspace is false, we +% insert blank vertical space equal to the optional argument (the +% default value of which is 0pt). \newenvironment{solution}[1][0pt]% {% \ifprintanswers + \begingroup + \Solution@Emphasis \begin{TheSolution}% \else - \par - \vspace*{#1}% + \ifcancelspace + % Do nothing + \else + \par + \penalty 0 + \vspace*{#1}% + \fi \setbox\z@\vbox\bgroup \fi }{% \ifprintanswers \end{TheSolution}% + \endgroup \else \egroup \fi }% % If printanswers is true, we print the solution using a TheSolution -% environment. If printanswers is false, we insert lined vertical -% space equal to the optional argument (the default value of which is -% 0pt). +% environment. If printanswers is false and cancelspace is false, +% we insert an empty box of width the current line width and of +% height equal to the optional argument, which can be a length, or +% \fill, or \stretch{number}. If the optional argument is omitted, +% then the box is entirely omitted when printanswers is false. +\newenvironment{solutionorbox}[1][-1pt]% + {% + \ifprintanswers + \begingroup + \Solution@Emphasis + \begin{TheSolution}% + \else + \ifcancelspace + % Do nothing + \else + \par + % Note: It's important that the following test be + % ``\ifdim 0pt > #1'' rather than ``\ifdim #1 < 0pt'' + % That's because if the user says + % ``\begin{solutionorbox}{\stretch{1}}'' + % (or \stretch{anythingelse}), then this will expand to + % ``\ifdim 0pt > \z@ plus 1fill\relax''. + % The \ifdim will be ``\ifdim 0pt > \z@'', and we'll have + % ``plus 1fill\relax'' left over. This is OK because if the + % \ifdim is false, that leftover stuff will be ignored, + % and it will only be true if the user omitted the optional + % argument, in which case there's no \stretch and thus no + % left over part. + % If we said ``\ifdim #1 < 0pt'', then we'd get an error + % when the user used \stretch, since the leftover stuff + % would appear when TeX was looking for <, =, or >. + \ifdim 0pt > #1 + % do nothing + \else + \makeemptybox{#1}% + \fi + \fi + \setbox\z@\vbox\bgroup + \fi + }{% + \ifprintanswers + \end{TheSolution}% + \endgroup + \else + \egroup + \fi + }% + +% If printanswers is true, we print the solution using a TheSolution +% environment. If printanswers is false and cancelspace is false, +% we insert lined vertical space equal to the optional argument (the +% default value of which is 0pt). \newenvironment{solutionorlines}[1][0pt]% {% \ifprintanswers + \begingroup + \Solution@Emphasis \begin{TheSolution}% \else - \par - \fillwithlines{#1}% + \ifcancelspace + % Do nothing + \else + \par + \penalty 0 + \fillwithlines{#1}% + \fi \setbox\z@\vbox\bgroup \fi }{% \ifprintanswers \end{TheSolution}% + \endgroup \else \egroup \fi }% - % If printanswers is true, we print the solution using a TheSolution -% environment. If printanswers is false, we insert dotted lined -% vertical space equal to the optional argument (the default value of -% which is 0pt). +% environment. If printanswers is false and cancelspace is false, +% we insert dotted lined vertical space equal to the optional +% argument (the default value of which is 0pt). \newenvironment{solutionordottedlines}[1][0pt]% {% \ifprintanswers + \begingroup + \Solution@Emphasis \begin{TheSolution}% \else - \par - \fillwithdottedlines{#1}% + \ifcancelspace + % Do nothing + \else + \par + \penalty 0 + \fillwithdottedlines{#1}% + \fi \setbox\z@\vbox\bgroup \fi }{% \ifprintanswers \end{TheSolution}% + \endgroup \else \egroup \fi }% - % The environment TheSolution is called from the solution, -% solutionorlines, and solutionordottedlines environments -% when printanswers is true. It uses Donald Arseneau's -% framed.sty macros (included at the end if this file) to allow the +% solutionorbox, solutionorlines, and solutionordottedlines +% environments when printanswers is true. It uses Donald Arseneau's +% framed.sty macros (included at the end of this file) to allow the % solution to be broken across pages and have each piece enclosed in % an fbox (or a colorbox, if the user has given the command -% \shadedsolutions). -% +% \shadedsolutions), (or no box at all, if the user has given the +% command \unframedsolutions). % Of course, the user can change TheSolution with a \renewenvironment % command. \newcommand{\solutiontitle}{\noindent\textbf{Solution:}\enspace} @@ -5473,10 +6318,17 @@ % inside of the solution box: \leftskip=0pt \rightskip=0pt + % If the user said \unframedsolutions, then both + % \if@framedsolutions and \if@shadedsolutions are false: \if@framedsolutions - % Do nothing; we'll use the default \FrameCommand + % We'll use the default \FrameCommand \else - \def\FrameCommand{\colorbox{SolutionColor}}% + \if@shadedsolutions + \def\FrameCommand{\colorbox{SolutionColor}}% + \else + % It's \unframedsolutions: + \def\FrameCommand{}% + \fi \fi \MakeFramed{\advance\hsize-\width}% \solutiontitle @@ -5489,8 +6341,12 @@ \newif\if@framedsolutions \@framedsolutionstrue +\newif\if@shadedsolutions +\@shadedsolutionsfalse +% If the user said \unframedsolutions, then both +% \if@framedsolutions and \if@shadedsolutions are false. -\def\framedsolutions{\@framedsolutionstrue} +\def\framedsolutions{\@framedsolutionstrue\@shadedsolutionsfalse} \def\shadedsolutions{% \@ifundefined{definecolor} {% @@ -5507,9 +6363,11 @@ }% {% \definecolor{SolutionColor}{gray}{0.8} + \@shadedsolutionstrue \@framedsolutionsfalse }% } +\def\unframedsolutions{\@framedsolutionsfalse\@shadedsolutionsfalse} %-------------------------------------------------------------------- %-------------------------------------------------------------------- -- cgit v1.2.3