--- loncom/homework/optionresponse.pm	2011/10/08 23:03:42	1.173.2.1
+++ loncom/homework/optionresponse.pm	2011/09/30 16:47:08	1.180
@@ -1,7 +1,7 @@
 # LearningOnline Network with CAPA
 # option list style responses
 #
-# $Id: optionresponse.pm,v 1.173.2.1 2011/10/08 23:03:42 raeburn Exp $
+# $Id: optionresponse.pm,v 1.180 2011/09/30 16:47:08 raeburn Exp $
 #
 # Copyright Michigan State University Board of Trustees
 #
@@ -221,7 +221,26 @@ sub end_foilgroup {
 	my $part_id="$Apache::inputtags::part.$Apache::inputtags::response[-1]";
 	push (@{ $Apache::lonhomework::analyze{"$part_id.options"} },@opt);
     } elsif ( $target eq 'grade') {
+
+      my $nonlenient=0;
+      my $part=$Apache::inputtags::part;
+      my $lenientparm=&Apache::lonnet::EXT("resource.$part.lenient");
+
+      if ($Apache::lonhomework::scantronmode) {
+         $nonlenient=0;
+# Grading an exam: we are grading lenient unless told not to
+         if ($lenientparm=~/^0|off|no$/i) {
+            $nonlenient=1;
+         }
+      } else {
+# Web mode: we are non-lenient unless told to
+         $nonlenient=1;
+         if ($lenientparm=~/^1|on|yes$/i) {
+            $nonlenient=0;
+         }
+      }
       if ( &Apache::response::submitted()) {
+
 	my @whichopt = &whichfoils($max,$randomize);
 	my $temp=1;my $name;
 	my %responsehash;
@@ -229,11 +248,43 @@ sub end_foilgroup {
 	my $right=0;
 	my $wrong=0;
 	my $ignored=0;
+        my ($numrows,$bubbles_per_row);
+        if ($Apache::lonhomework::scantronmode) {
+            my $numitems = scalar(@opt);
+            ($numrows,$bubbles_per_row) =
+                &Apache::optionresponse::getnumrows($numitems);
+        }
+        if ($numrows < 1) {
+            $numrows = 1;
+        }
 	foreach $name (@whichopt) {
-	  my $response=&Apache::response::getresponse($temp);
-	  if ($env{'form.submitted'} eq 'scantron' && $response=~/\S/) {
-	      $response = $opt[$response];
-	  }
+	  my $response;
+          if ($env{'form.submitted'} eq 'scantron') {
+              if ($numrows > 1) {
+                  my $num = $temp;
+                  my $totalnum;
+                  for (my $i=0; $i<$numrows; $i++) {
+                      my $item = &Apache::response::getresponse($num);
+                      if ($item =~ /^\d+$/) {
+                          $totalnum = $i*$bubbles_per_row + $item;
+                      }
+                      $num ++;
+                  }
+                  if ($totalnum =~ /^\d+$/) {
+                      $response = $opt[$totalnum];
+                  }
+                  $temp += $numrows;
+              } else {
+                  $response=&Apache::response::getresponse($temp);
+                  if ($response=~/\S/) {
+                      $response = $opt[$response];
+                  }
+                  $temp ++;
+              }
+	  } else {
+              $response=&Apache::response::getresponse($temp);
+              $temp ++;
+          }
 	  if ( $response =~ /[^\s]/) {
 	    $responsehash{$name}=$response;
 	    my $value=$Apache::response::foilgroup{$name.'.value'};
@@ -246,7 +297,6 @@ sub end_foilgroup {
 	  } else {
 	    $ignored++;
 	  }
-	  $temp++;
 	}
 	my $part=$Apache::inputtags::part;
 	my $id = $Apache::inputtags::response['-1'];
@@ -282,7 +332,10 @@ sub end_foilgroup {
 		my $ad=$Apache::lonhomework::results{"resource.$part.$id.awarddetail"}='MISSING_ANSWER';
 		&Apache::response::handle_previous(\%previous,$ad);
 	    }
-	} elsif (!$Apache::lonhomework::scantronmode) {
+	} elsif ($nonlenient) {
+#
+# Non-lenient mode. All right or all wrong
+#
 	    my $ad;
 	    if ($wrong==0 && $ignored==0) {
 		$ad='EXACT_ANS';
@@ -298,6 +351,9 @@ sub end_foilgroup {
 	    $Apache::lonhomework::results{"resource.$part.$id.awarddetail"}=$ad;
 	    &Apache::response::handle_previous(\%previous,$ad);
 	} else {
+#
+# This is lenient mode
+#
 	    my $ad;
 	    if ($wrong==0 && $right==0) {
 		#nothing submitted only assign a score if we 
@@ -318,8 +374,16 @@ sub end_foilgroup {
     }
     my $part_id     = $Apache::inputtags::part;
     my $response_id = $Apache::inputtags::response[-1];
-    &Apache::lonxml::increment_counter(&getfoilcounts($max),
-				       "$part_id.$response_id");
+    my ($numrows,$bubbles_per_row);
+    if (($target eq 'tex') && ($Apache::lonhomework::type eq 'exam')) {
+        ($numrows,$bubbles_per_row) =
+            &Apache::optionresponse::getnumrows(scalar(@opt));
+    }
+    if ($numrows < 1) {
+        $numrows = 1;
+    }
+    my $increment = &getfoilcounts($max) * $numrows;
+    &Apache::lonxml::increment_counter($increment,"$part_id.$response_id");
     if ($target eq 'analyze') {
 	&Apache::lonhomework::set_bubble_lines();
     }
@@ -431,7 +495,6 @@ sub displayfoils {
   my $part=$Apache::inputtags::part;
   my $id=$Apache::inputtags::response[-1];
   my $break;
-  my $solved=$Apache::lonhomework::history{"resource.$part.solved"};
   if ( ($target ne 'tex') &&
        &Apache::response::show_answer() ) {
     my $temp=1;
@@ -603,9 +666,24 @@ sub displayfoils {
 	  }
 	  if ($Apache::lonhomework::type eq 'exam') {
 	      $result.='\vskip -1 mm\noindent';
-              $result.= '\textbf{'. $internal_counter.'}. \vskip -3mm'.&bubbles(\@alphabet,\@opt).
-		                 ' \strut ';
-	      $internal_counter++;
+              my ($numrows,$bubbles_per_row) = &getnumrows(scalar(@opt)); 
+              if ($numrows == 1) {  
+                  $result .= '\textbf{'.$internal_counter.'}. \vskip -3mm';
+              } else {
+                  my $linetext;
+                  for (my $i=0; $i<$numrows; $i++) {
+                      $linetext .= $internal_counter+$i.', ';
+                  }
+                  $linetext =~ s/,\s$//;
+                  $result .= '\small {\textbf{'.$linetext.'}} '.
+                             '\hskip 2 mm {\footnotesize '.
+                             &mt('(Bubble once in [_1] lines)',$numrows).
+                             '} \vskip 1 mm';
+              }
+              $result.= &bubbles(\@alphabet,\@opt,undef,undef,$numrows,
+                                 $bubbles_per_row,$internal_counter).
+                        ' \strut ';
+	      $internal_counter += $numrows;
 	  }
           if ($target eq 'tex' && $env{'form.pdfFormFields'} eq 'yes'
               && $Apache::inputtags::status[-1] eq 'CAN_ANSWER'
@@ -686,7 +764,8 @@ sub webbubbles {
 
 
 sub bubbles {
-    my ($ralphabet,$ropt,$response, $max_width) = @_;
+    my ($ralphabet,$ropt,$response,$max_width,$numrows,$bubbles_per_row,
+        $internal_counter) = @_;
     my @alphabet = @$ralphabet;
     my @opt = @$ropt;
     my ($result,$head,$line) =('','','');
@@ -707,28 +786,37 @@ sub bubbles {
     }
     &Apache::lonxml::debug("Final maxwidth: $textwidth");
     for (my $ind=0;$ind<=$number_of_bubbles;$ind++) {
+        my $item;
+        if ($numrows > 1) {
+            my $num = $internal_counter+int($ind/$bubbles_per_row);
+            my $idx = int($ind % $bubbles_per_row);
+            $item = $num.$alphabet[$idx];
+        } else {
+            $item = $alphabet[$ind];
+        }
 	my $leftmargin;
 	$opt[$ind]=&Apache::lonxml::latex_special_symbols($opt[$ind]);
 	if ($response eq 'rankresponse') {$opt[$ind]='Rank '.$opt[$ind];}
 	if ($ind==0) {$leftmargin=6;} else {$leftmargin=10;}
 
-	$current_length += (length($opt[$ind])+length($alphabet[$ind])+4)*2;
+	$current_length += (length($opt[$ind])+length($item)+4)*2;
+        
 	if ($current_length<($textwidth-$leftmargin) and $ind!=$number_of_bubbles) {
-	    $line.='\hskip 4 mm {\small \textbf{'.$alphabet[$ind].'}}$\bigcirc$\hskip -1 mm & \hskip -3 mm {\small '.$opt[$ind].'} & ';
+            
+	    $line.='\hskip 4 mm {\small \textbf{'.$item.'}}$\bigcirc$\hskip -1 mm & \hskip -3 mm {\small '.$opt[$ind].'} & ';
 	    $head.='lr';
 	} else {
 	    $line=~s/\&\s*$//;
 	    $result.='\vskip -1 mm\noindent\setlength{\tabcolsep}{2 mm}\renewcommand{\arraystretch}{1.25}\begin{tabular}{'.$head.'}'.$line.'\\\\\end{tabular}\vskip 0 mm';
-	    $line = '\hskip 4 mm {\small \textbf{'.$alphabet[$ind].'}}$\bigcirc$\hskip -1 mm & \hskip -3 mm {\small '.$opt[$ind].'} & ';;
+	    $line = '\hskip 4 mm {\small \textbf{'.$item.'}}$\bigcirc$\hskip -1 mm & \hskip -3 mm {\small '.$opt[$ind].'} & ';
 	    $head ='lr';
-	    $current_length = (length($opt[$ind])+length($alphabet[$ind]))*2;
+	    $current_length = (length($opt[$ind])+length($item))*2;
 	}
 
     }
     return $result;
 }
 
-
 sub start_conceptgroup {
   my ($target,$token,$tagstack,$parstack,$parser,$safeeval,$style)=@_;
   $Apache::optionresponse::conceptgroup=1;
@@ -873,6 +961,24 @@ sub insert_foil {
 sub insert_drawoptionlist {
     return '<drawoptionlist />';
 }
+
+sub getnumrows {
+    my ($numitems) = @_;
+    my $bubbles_per_row;
+    my $default_numbubbles = 10;
+    if (($env{'form.bubbles_per_row'} =~ /^\d+$/) &&
+        ($env{'form.bubbles_per_row'} > 0)) {
+        $bubbles_per_row = $env{'form.bubbles_per_row'};
+    } else {
+        $bubbles_per_row = $default_numbubbles;
+    }
+    my $numrows = int ($numitems/$bubbles_per_row);
+    if (($numitems % $bubbles_per_row) != 0) {
+        $numrows ++;
+    }
+    return ($numrows,$bubbles_per_row);
+}
+
 1;
 __END__