[system] / trunk / webwork / system / courseScripts / PGbasicmacros.pl Repository:
ViewVC logotype

Annotation of /trunk/webwork/system/courseScripts/PGbasicmacros.pl

Parent Directory Parent Directory | Revision Log Revision Log


Revision 27 - (view) (download) (as text)

1 : sam 11 #!/usr/local/bin/webwork-perl
2 : sam 2
3 :     ####################################################################
4 :     # Copyright @ 1995-1998 University of Rochester
5 :     # All Rights Reserved
6 :     ####################################################################
7 :    
8 :     =head1 NAME
9 :    
10 :     PGbasicmacros.pl --- located in the courseScripts directory
11 :    
12 :     =head1 SYNPOSIS
13 :    
14 :    
15 :    
16 :     =head1 DESCRIPTION
17 :    
18 :    
19 :    
20 :     =cut
21 :    
22 :     # this is equivalent to use strict, but can be used within the Safe compartment.
23 :     BEGIN{
24 :     be_strict;
25 :     }
26 : gage 27 sub _PGbasicmacros_export {
27 :     my @EXPORT = ( '&NAMED_ANS_RULE', '&NAMED_ANS_RULE_OPTION',
28 :     '&NAMED_ANS_RULE_EXTENSION', '&ANS_RULE', '&NAMED_ANS_BOX', '&ANS_BOX',
29 :     '&NAMED_ANS_RADIO', '&NAMED_ANS_RADIO_OPTION',
30 :     '&NAMED_ANS_RADIO_BUTTONS', '&ANS_RADIO', '&ANS_RADIO_OPTION',
31 :     '&ANS_RADIO_BUTTONS', '&NAMED_ANS_CHECKBOX',
32 :     '&NAMED_ANS_CHECKBOX_OPTION', '&NAMED_ANS_CHECKBOX_BUTTONS',
33 :     '&ANS_CHECKBOX', '&ANS_CHECKBOX_OPTION', '&ANS_CHECKBOX_BUTTONS',
34 :     '&ans_rule', '&ans_rule_extension', '&ans_radio_buttons',
35 :     '&ans_checkbox', '&tex_ans_rule', '&tex_ans_rule_extension', '&ans_box',
36 :     '&checkbox', '&NAMED_POP_UP_LIST', '&pop_up_list', '&solution',
37 :     '&SOLUTION', '&hint', '&HINT', '&random', '&non_zero_random', '&SRAND',
38 :     '&TEX', '&M3', '&MODES', '&_PGbasicmacros_export',
39 :     '&_PGbasicmacros_initialize', '&ALPHABET', '&PAR', '&BR', '&LQ', '&RQ',
40 :     '&BM', '&EM', '&BDM', '&EDM', '&LTS', '&GTS', '&LTE', '&GTE',
41 :     '&BEGIN_ONE_COLUMN', '&END_ONE_COLUMN', '&SOLUTION_HEADING',
42 :     '&HINT_HEADING', '&US', '&SPACE', '&BBOLD', '&EBOLD', '&HR', '&LBRACE',
43 :     '&RBRACE', '&LB', '&RB', '&DOLLAR', '&PERCENT', '&CARET', '&PI', '&E',
44 :     '&ev_substring', '&safe_ev', '&old_safe_ev', '&FEQ', '&math_ev3',
45 :     '&display_math_ev3', '&EV2', '&EV3', '&beginproblem',
46 :     '&protect_underbar', '&OL', '&htmlLink', '&appletLink', '&spf', '&sspf',
47 :     '&lex_sort', '&num_sort', '&begintable', '&endtable', '&row', '&image',
48 :     '&images', '&caption', '&captions', '&imageRow', '&display_options2',
49 :     '&_PGbasicmacros_init','&test'
50 :     );
51 :     @EXPORT;
52 :     }
53 :     my $displayMode=$main::displayMode;
54 : sam 2
55 : gage 27 my ($PAR,
56 :     $BR,
57 :     $LQ,
58 :     $RQ,
59 :     $BM,
60 :     $EM,
61 :     $BDM,
62 :     $EDM,
63 :     $LTS,
64 :     $GTS,
65 :     $LTE,
66 :     $GTE,
67 :     $BEGIN_ONE_COLUMN,
68 :     $END_ONE_COLUMN,
69 :     $SOL,
70 :     $HINT,
71 :     $US,
72 :     $SPACE,
73 :     $BBOLD,
74 :     $EBOLD,
75 :     $HR,
76 :     $LBRACE,
77 :     $RBRACE,
78 :     $LB,
79 :     $RB,
80 :     $DOLLAR,
81 :     $PERCENT,
82 :     $CARET,
83 :     $PI,
84 :     $E,
85 :     @ALPHABET,
86 :     );
87 :     _PGbasicmacros_init();
88 :     sub _PGbasicmacros_init {
89 :     PG_restricted_eval( <<'EOF');
90 :     $main::PAR = PAR();
91 :     $main::BR = BR();
92 :     $main::LQ = LQ();
93 :     $main::RQ = RQ();
94 :     $main::BM = BM();
95 :     $main::EM = EM();
96 :     $main::BDM = BDM();
97 :     $main::EDM = EDM();
98 :     $main::LTS = LTS();
99 :     $main::GTS = GTS();
100 :     $main::LTE = LTE();
101 :     $main::GTE = GTE();
102 :     $main::BEGIN_ONE_COLUMN = BEGIN_ONE_COLUMN();
103 :     $main::END_ONE_COLUMN = END_ONE_COLUMN();
104 :     $main::SOL = SOLUTION_HEADING();
105 :     $main::HINT = HINT_HEADING();
106 :     $main::US = US();
107 :     $main::SPACE = SPACE();
108 :     $main::BBOLD = BBOLD();
109 :     $main::EBOLD = EBOLD();
110 :     $main::HR = HR();
111 :     $main::LBRACE = LBRACE();
112 :     $main::RBRACE = RBRACE();
113 :     $main::LB = LB();
114 :     $main::RB = RB();
115 :     $main::DOLLAR = DOLLAR();
116 :     $main::PERCENT = PERCENT();
117 :     $main::CARET = CARET();
118 :     $main::PI = PI();
119 :     $main::E = E();
120 :     @main::ALPHABET = ('A'..'ZZ');
121 :    
122 :     $PAR = PAR();
123 :     $BR = BR();
124 :     $LQ = LQ();
125 :     $RQ = RQ();
126 :     $BM = BM();
127 :     $EM = EM();
128 :     $BDM = BDM();
129 :     $EDM = EDM();
130 :     $LTS = LTS();
131 :     $GTS = GTS();
132 :     $LTE = LTE();
133 :     $GTE = GTE();
134 :     $BEGIN_ONE_COLUMN = BEGIN_ONE_COLUMN();
135 :     $END_ONE_COLUMN = END_ONE_COLUMN();
136 :     $SOL = SOLUTION_HEADING();
137 :     $HINT = HINT_HEADING();
138 :     $US = US();
139 :     $SPACE = SPACE();
140 :     $BBOLD = BBOLD();
141 :     $EBOLD = EBOLD();
142 :     $HR = HR();
143 :     $LBRACE = LBRACE();
144 :     $RBRACE = RBRACE();
145 :     $LB = LB();
146 :     $RB = RB();
147 :     $DOLLAR = DOLLAR();
148 :     $PERCENT = PERCENT();
149 :     $CARET = CARET();
150 :     $PI = PI();
151 :     $E = E();
152 :     @ALPHABET = ('A'..'ZZ');
153 :    
154 :     $displayMode =$main::displayMode;
155 :     EOF
156 : sam 2
157 : gage 27 }
158 :     sub test {
159 :     "PI is $PI $BR displayMode is $displayMode";
160 :     }
161 :     #_PGbasicmacros_init(); # initialize constants
162 :    
163 : sam 2 =head2 Answer blank macros:
164 :    
165 :     These produce answer blanks of various sizes or pop up lists or radio answer buttons.
166 :     The names for the answer blanks are
167 :     generated implicitly.
168 :    
169 :     ans_rule( width )
170 :     tex_ans_rule( width )
171 :     ans_radio_buttons(value1=>label1, value2,label2 => value3,label3=>...)
172 :     pop_up_list(@list) # list consists of (value => label, PR => "Product rule",...)
173 :    
174 :     To indicate the checked position of radio buttons put a '%' in front of the value: C<ans_radio_buttons(1, 'Yes','%2','No')>
175 :     will have 'No' checked. C<tex_ans_rule> works inside math equations in C<HTML_tth> mode. It does not work in C<Latex2HTML> mode
176 :     since this mode produces gif pictures.
177 :    
178 :    
179 :     The following method is defined in F<PG.pl> for entering the answer evaluators corresponding
180 :     to answer rules with automatically generated names. The answer evaluators are matched with the
181 :     answer rules in the order in which they appear on the page.
182 :    
183 :     ANS(ans_evaluator1, ans_evaluator2,...);
184 :    
185 :     These are more primitive macros which produce answer blanks for specialized cases when complete
186 :     control over the matching of answers blanks and answer evaluators is desired.
187 :     The names of the answer blanks must be generated manually, and it is best if they do NOT begin
188 :     with the default answer prefix (currently AnSwEr).
189 :    
190 :    
191 :     NAMED_ANS_RULE(name, width)
192 :     NAMED_ANS_BOX(name, rows, cols)
193 :     NAMED_ANS_RADIO(name, value,label,)
194 :     NAMED_ANS_RADIO_OPTION(name, value,label)
195 :     NAMED_ANS_RADIO_BUTTONS(name,value1,label1,value2,label2,...)
196 :     check_box('-name' =>answer5,'-value' =>'statement3','-label' =>'I loved this course!' )
197 :     NAMED_POP_UP_LIST($name, @list) # list consists of (value => tag, PR => "Product rule",...)
198 :    
199 :     (Name is the name of the variable, value is the value given to the variable when this option is selected,
200 :     and label is the text printed next to the button or check box. Check box variables can have multiple values.)
201 :    
202 :     NAMED_ANS_RADIO_BUTTONS creates a sequence of NAMED_ANS_RADIO and NAMED_ANS_RADIO_OPTION items which
203 :     are output either as an array or, in scalar context, as the array glued together with spaces. It is
204 :     usually easier to use this than to manually construct the radio buttons by hand. However, sometimes
205 :     extra flexibility is desiredin which case:
206 :    
207 :     When entering radio buttons using the "NAMED" format, you should use NAMED_ANS_RADIO button for the first button
208 :     and then use NAMED_ANS_RADIO_OPTION for the remaining buttons. NAMED_ANS_RADIO requires a matching answer evalutor,
209 :     while NAMED_ANS_RADIO_OPTION does not. The name used for NAMED_ANS_RADIO_OPTION should match the name
210 :     used for NAMED_ANS_RADIO (and the associated answer evaluator).
211 :    
212 :    
213 :    
214 :     The following method is defined in in F<PG.pl> for entering the answer evaluators corresponding
215 :     to answer rules with automatically generated names. The answer evaluators are matched with the
216 :     answer rules in the order in which they appear on the page.
217 :    
218 :     NAMED_ANS(name1 => ans_evaluator1, name2 => ans_evaluator2,...);
219 :    
220 :     These auxiliary macros are defined in PG.pl
221 :    
222 :    
223 :     NEW_ANS_NAME( number ); # produces a new answer blank name from a number by adding a prefix (AnSwEr)
224 :     # and registers this name as an implicitly labeled answer
225 :     # Its use is paired with each answer evaluator being entered using ANS()
226 :    
227 :     ANS_NUM_TO_NAME(number); # adds the prefix (AnSwEr) to the number, but does nothing else.
228 :    
229 :     RECORD_ANS_NAME( name ); # records the order in which the answer blank is rendered
230 :     # This is called by all of the constructs above, but must
231 :     # be called explicitly if an input blank is constructed explictly
232 :     # using HTML code.
233 :    
234 :     These are legacy macros:
235 :    
236 :     ANS_RULE( number, width ); # equivalent to NAMED_ANS_RULE( NEW_ANS_NAME(number), width)
237 :     ANS_BOX( question_number,height, width ); # equivalent to NAMED_ANS_BOX( NEW_ANS_NAME(number), height, width)
238 :     ANS_RADIO( question_number, value,tag ); # equivalent to NAMED_ANS_RADIO( NEW_ANS_NAME(number), value,tag)
239 :     ANS_RADIO_OPTION( question_number, value,tag ); # equivalent to NAMED_ANS_RADIO_OPTION( ANS_NUM_TO_NAME(number), value,tag)
240 :    
241 :    
242 :     =cut
243 :    
244 :    
245 :     sub NAMED_ANS_RULE {
246 :     my($name,$col) = @_;
247 :     my $len = 0.07*$col;
248 :     my $answer_value = '';
249 :     $answer_value = ${$main::inputs_ref}{$name} if defined(${$main::inputs_ref}{$name});
250 :     if ($answer_value =~ /\0/ ) {
251 :     my @answers = split("\0", $answer_value);
252 :     $answer_value = shift(@answers); # use up the first answer
253 :     $main::rh_sticky_answers{$name}=\@answers; # store the rest
254 :     $answer_value= '' unless defined($answer_value);
255 :     }
256 :     $name = RECORD_ANS_NAME($name);
257 :     MODES(
258 :     TeX => "\\mbox{\\parbox[t]{10pt}{\\hrulefill}}\\hrulefill\\quad ",
259 :     Latex2HTML => qq!\\begin{rawhtml}\n<INPUT TYPE=TEXT SIZE=$col NAME=\"$name\" VALUE = \"\">\n\\end{rawhtml}\n!,
260 :     HTML => "<INPUT TYPE=TEXT SIZE=$col NAME=\"$name\" VALUE = \"$answer_value\">\n"
261 :     );
262 :     }
263 :    
264 :     sub NAMED_ANS_RULE_OPTION {
265 :     &NAMED_ANS_RULE_EXTENSION;
266 :     }
267 :    
268 :     sub NAMED_ANS_RULE_EXTENSION {
269 :     my($name,$col) = @_;
270 :     my $len = 0.07*$col;
271 :     my $answer_value = '';
272 :     $answer_value = ${$main::inputs_ref}{$name} if defined(${$main::inputs_ref}{$name});
273 :     if ( defined($main::rh_sticky_answers{$name}) ) {
274 :     $answer_value = shift( @{$main::rh_sticky_answers{$name}});
275 :     $answer_value = '' unless defined($answer_value);
276 :     }
277 :     MODES(
278 :     TeX => '\\hrulefill\\quad ',
279 :     Latex2HTML => qq!\\begin{rawhtml}\n<INPUT TYPE=TEXT SIZE=$col NAME=\"$name\" VALUE = \"\">\n\\end{rawhtml}\n!,
280 :     HTML => qq!<INPUT TYPE=TEXT SIZE=$col NAME = "$name" VALUE = "$answer_value">\n!
281 :     );
282 :     }
283 :    
284 :     sub ANS_RULE {
285 :     my($number,$col) = @_;
286 :     my $name = NEW_ANS_NAME($number);
287 :     NAMED_ANS_RULE($name,$col);
288 :     }
289 :    
290 :    
291 :     sub NAMED_ANS_BOX {
292 :     my($name,$row,$col) = @_;
293 :     $row = 10 unless defined($row);
294 :     $col = 80 unless defined($col);
295 :     $name = RECORD_ANS_NAME($name);
296 :     my $len = 0.07*$col;
297 :     my $height = .07*$row;
298 :     my $answer_value = '';
299 :     $answer_value = $main::inputs_ref->{$name} if defined( $main::inputs_ref->{$name} );
300 :     my $out = M3(
301 :     qq!\\vskip $height in \\hrulefill\\quad !,
302 :     qq!\\begin{rawhtml}<TEXTAREA NAME="$name" ROWS="$row" COLS="$col"
303 :     WRAP="VIRTUAL">$answer_value</TEXTAREA>\\end{rawhtml}!,
304 :     qq!<TEXTAREA NAME="$name" ROWS="$row" COLS="$col"
305 :     WRAP="VIRTUAL">$answer_value</TEXTAREA>!
306 :     );
307 :     $out;
308 :     }
309 :    
310 :     sub ANS_BOX {
311 :     my($number,$row,$col) = @_;
312 :     my $name = NEW_ANS_NAME($number);
313 :     NAMED_ANS_BOX($name,$row,$col);
314 :     }
315 :    
316 :     sub NAMED_ANS_RADIO {
317 :     my $name = shift;
318 :     my $value = shift;
319 :     my $tag =shift;
320 :     $name = RECORD_ANS_NAME($name);
321 :     my $checked = '';
322 :     if ($value =~/^\%/) {
323 :     $value =~ s/^\%//;
324 :     $checked = 'CHECKED'
325 :     }
326 :     if (defined($main::inputs_ref->{$name}) ) {
327 :     if ($main::inputs_ref->{$name} eq $value) {
328 :     $checked = 'CHECKED'
329 :     } else {
330 :     $checked = '';
331 :     }
332 :    
333 :     }
334 :    
335 :     MODES(
336 :     TeX => qq!\\item{$tag}\n!,
337 :     Latex2HTML => qq!\\begin{rawhtml}\n<INPUT TYPE=RADIO NAME="$name" VALUE="$value" $checked>\\end{rawhtml}$tag!,
338 :     HTML => qq!<INPUT TYPE=RADIO NAME="$name" VALUE="$value" $checked>$tag!
339 :     );
340 :    
341 :     }
342 :    
343 :     sub NAMED_ANS_RADIO_OPTION {
344 :     my $name = shift;
345 :     my $value = shift;
346 :     my $tag =shift;
347 :    
348 :    
349 :     my $checked = '';
350 :     if ($value =~/^\%/) {
351 :     $value =~ s/^\%//;
352 :     $checked = 'CHECKED'
353 :     }
354 :     if (defined($main::inputs_ref->{$name}) ) {
355 :     if ($main::inputs_ref->{$name} eq $value) {
356 :     $checked = 'CHECKED'
357 :     } else {
358 :     $checked = '';
359 :     }
360 :    
361 :     }
362 :    
363 :     MODES(
364 :     TeX => qq!\\item{$tag}\n!,
365 :     Latex2HTML => qq!\\begin{rawhtml}\n<INPUT TYPE=RADIO NAME="$name" VALUE="$value" $checked>\\end{rawhtml}$tag!,
366 :     HTML => qq!<INPUT TYPE=RADIO NAME="$name" VALUE="$value" $checked>$tag!
367 :     );
368 :    
369 :     }
370 :    
371 :     sub NAMED_ANS_RADIO_BUTTONS {
372 :     my $name =shift;
373 :     my $value = shift;
374 :     my $tag = shift;
375 :    
376 :    
377 :     my @out = ();
378 :     push(@out, NAMED_ANS_RADIO($name, $value,$tag));
379 :     my @buttons = @_;
380 :     while (@buttons) {
381 :     $value = shift @buttons; $tag = shift @buttons;
382 :     push(@out, NAMED_ANS_RADIO_OPTION($name, $value,$tag));
383 :     }
384 :     (wantarray) ? @out : join(" ",@out);
385 :     }
386 :     sub ANS_RADIO {
387 :     my $number = shift;
388 :     my $value = shift;
389 :     my $tag =shift;
390 :     my $name = NEW_ANS_NAME($number);
391 :     NAMED_ANS_RADIO($name,$value,$tag);
392 :     }
393 :    
394 :     sub ANS_RADIO_OPTION {
395 :     my $number = shift;
396 :     my $value = shift;
397 :     my $tag =shift;
398 :    
399 :    
400 :     my $name = ANS_NUM_TO_NAME($number);
401 :     NAMED_ANS_RADIO_OPTION($name,$value,$tag);
402 :     }
403 :     sub ANS_RADIO_BUTTONS {
404 :     my $number =shift;
405 :     my $value = shift;
406 :     my $tag = shift;
407 :    
408 :    
409 :     my @out = ();
410 :     push(@out, ANS_RADIO($number, $value,$tag));
411 :     my @buttons = @_;
412 :     while (@buttons) {
413 :     $value = shift @buttons; $tag = shift @buttons;
414 :     push(@out, ANS_RADIO_OPTION($number, $value,$tag));
415 :     }
416 :     (wantarray) ? @out : join(" ",@out);
417 :     }
418 :    
419 :     sub NAMED_ANS_CHECKBOX {
420 :     my $name = shift;
421 :     my $value = shift;
422 :     my $tag =shift;
423 :     $name = RECORD_ANS_NAME($name);
424 :    
425 :     my $checked = '';
426 :     if ($value =~/^\%/) {
427 :     $value =~ s/^\%//;
428 :     $checked = 'CHECKED'
429 :     }
430 :    
431 :     if (defined($main::inputs_ref->{$name}) ) {
432 :     if ($main::inputs_ref->{$name} eq $value) {
433 :     $checked = 'CHECKED'
434 :     }
435 :     else {
436 :     $checked = '';
437 :     }
438 :    
439 :     }
440 :    
441 :     MODES(
442 :     TeX => qq!\\item{$tag}\n!,
443 :     Latex2HTML => qq!\\begin{rawhtml}\n<INPUT TYPE=CHECKBOX NAME="$name" VALUE="$value" $checked>\\end{rawhtml}$tag!,
444 :     HTML => qq!<INPUT TYPE=CHECKBOX NAME="$name" VALUE="$value" $checked>$tag!
445 :     );
446 :    
447 :     }
448 :    
449 :     sub NAMED_ANS_CHECKBOX_OPTION {
450 :     my $name = shift;
451 :     my $value = shift;
452 :     my $tag =shift;
453 :    
454 :     my $checked = '';
455 :     if ($value =~/^\%/) {
456 :     $value =~ s/^\%//;
457 :     $checked = 'CHECKED'
458 :     }
459 :    
460 :     if (defined($main::inputs_ref->{$name}) ) {
461 :     if ($main::inputs_ref->{$name} eq $value) {
462 :     $checked = 'CHECKED'
463 :     }
464 :     else {
465 :     $checked = '';
466 :     }
467 :    
468 :     }
469 :    
470 :     MODES(
471 :     TeX => qq!\\item{$tag}\n!,
472 :     Latex2HTML => qq!\\begin{rawhtml}\n<INPUT TYPE=CHECKBOX NAME="$name" VALUE="$value" $checked>\\end{rawhtml}$tag!,
473 :     HTML => qq!<INPUT TYPE=CHECKBOX NAME="$name" VALUE="$value" $checked>$tag!
474 :     );
475 :    
476 :     }
477 :    
478 :     sub NAMED_ANS_CHECKBOX_BUTTONS {
479 :     my $name =shift;
480 :     my $value = shift;
481 :     my $tag = shift;
482 :    
483 :     my @out = ();
484 :     push(@out, NAMED_ANS_CHECKBOX($name, $value,$tag));
485 :    
486 :     my @buttons = @_;
487 :     while (@buttons) {
488 :     $value = shift @buttons; $tag = shift @buttons;
489 :     push(@out, NAMED_ANS_CHECKBOX_OPTION($name, $value,$tag));
490 :     }
491 :    
492 :     (wantarray) ? @out : join(" ",@out);
493 :     }
494 :    
495 :     sub ANS_CHECKBOX {
496 :     my $number = shift;
497 :     my $value = shift;
498 :     my $tag =shift;
499 :     my $name = NEW_ANS_NAME($number);
500 :    
501 :     NAMED_ANS_CHECKBOX($name,$value,$tag);
502 :     }
503 :    
504 :     sub ANS_CHECKBOX_OPTION {
505 :     my $number = shift;
506 :     my $value = shift;
507 :     my $tag =shift;
508 :     my $name = ANS_NUM_TO_NAME($number);
509 :    
510 :     NAMED_ANS_CHECKBOX_OPTION($name,$value,$tag);
511 :     }
512 :    
513 :     sub ANS_CHECKBOX_BUTTONS {
514 :     my $number =shift;
515 :     my $value = shift;
516 :     my $tag = shift;
517 :    
518 :     my @out = ();
519 :     push(@out, ANS_CHECKBOX($number, $value, $tag));
520 :    
521 :     my @buttons = @_;
522 :     while (@buttons) {
523 :     $value = shift @buttons; $tag = shift @buttons;
524 :     push(@out, ANS_CHECKBOX_OPTION($number, $value,$tag));
525 :     }
526 :    
527 :     (wantarray) ? @out : join(" ",@out);
528 :     }
529 :    
530 :     sub ans_rule {
531 :     my $len = shift; # gives the optional length of the answer blank
532 :     $len = 20 unless $len ;
533 :     my $name = NEW_ANS_NAME(++$main::ans_rule_count);
534 :     NAMED_ANS_RULE($name ,$len);
535 :     }
536 :     sub ans_rule_extension {
537 :     my $len = shift;
538 :     $len = 20 unless $len ;
539 :     my $name = NEW_ANS_NAME($main::ans_rule_count); # don't update the answer name
540 :     NAMED_ANS_RULE($name ,$len);
541 :     }
542 :     sub ans_radio_buttons {
543 :     my $name = NEW_ANS_NAME(++$main::ans_rule_count);
544 :     my @radio_buttons = NAMED_ANS_RADIO_BUTTONS($name, @_);
545 :    
546 : gage 27 if ($displayMode eq 'TeX') {
547 : sam 2 $radio_buttons[0] = "\n\\begin{itemize}\n" . $radio_buttons[0];
548 :     $radio_buttons[$#radio_buttons] .= "\n\\end{itemize}\n";
549 :     }
550 :    
551 :     (wantarray) ? @radio_buttons: join(" ", @radio_buttons);
552 :     }
553 :    
554 :     #added 6/14/2000 by David Etlinger
555 :     sub ans_checkbox {
556 :     my $name = NEW_ANS_NAME( ++$main::ans_rule_count );
557 :     my @checkboxes = NAMED_ANS_CHECKBOX_BUTTONS( $name, @_ );
558 :    
559 :     if ($main::displayMode eq 'TeX') {
560 :     $checkboxes[0] = "\n\\begin{itemize}\n" . $checkboxes[0];
561 :     $checkboxes[$#checkboxes] .= "\n\\end{itemize}\n";
562 :     }
563 :    
564 :     (wantarray) ? @checkboxes: join(" ", @checkboxes);
565 :     }
566 :    
567 :    
568 :     ## define a version of ans_rule which will work inside TeX math mode or display math mode -- at least for tth mode.
569 :     ## This is great for displayed fractions.
570 :     ## This will not work with latex2HTML mode since it creates gif equations.
571 :    
572 :     sub tex_ans_rule {
573 :     my $len = shift;
574 :     $len = 20 unless $len ;
575 :     my $name = NEW_ANS_NAME(++$main::ans_rule_count);
576 :     my $answer_rule = NAMED_ANS_RULE($name ,$len); # we don't want to create three answer rules in different modes.
577 :     my $out = MODES(
578 :     'TeX' => $answer_rule,
579 :     'Latex2HTML' => '\\fbox{Answer boxes cannot be placed inside typeset equations}',
580 :     'HTML_tth' => '\\begin{rawhtml} '. $answer_rule.'\\end{rawhtml}',
581 :     'HTML' => $answer_rule
582 :     );
583 :    
584 :     $out;
585 :     }
586 :     sub tex_ans_rule_extension {
587 :     my $len = shift;
588 :     $len = 20 unless $len ;
589 :     my $name = NEW_ANS_NAME($main::ans_rule_count);
590 :     my $answer_rule = NAMED_ANS_RULE($name ,$len); # we don't want to create three answer rules in different modes.
591 :     my $out = MODES(
592 :     'TeX' => $answer_rule,
593 :     'Latex2HTML' => '\fbox{Answer boxes cannot be placed inside typeset equations}',
594 :     'HTML_tth' => '\\begin{rawhtml} '. $answer_rule.'\\end{rawhtml}',
595 :     'HTML' => $answer_rule
596 :     );
597 :    
598 :     $out;
599 :     }
600 : gage 5 # still needs some cleanup.
601 :     sub NAMED_TEX_ANS_RULE {
602 :     my $name = shift;
603 :     my $len = shift;
604 :     $len = 20 unless $len ;
605 :     my $answer_rule = NAMED_ANS_RULE($name ,$len); # we don't want to create three answer rules in different modes.
606 :     my $out = MODES(
607 :     'TeX' => $answer_rule,
608 :     'Latex2HTML' => '\\fbox{Answer boxes cannot be placed inside typeset equations}',
609 :     'HTML_tth' => '\\begin{rawhtml} '. $answer_rule.'\\end{rawhtml}',
610 :     'HTML' => $answer_rule
611 :     );
612 :    
613 :     $out;
614 :     }
615 :     sub NAMED_TEX_ANS_RULE_EXTENSION {
616 :     my $name = shift;
617 :     my $len = shift;
618 :     $len = 20 unless $len ;
619 :     my $answer_rule = NAMED_ANS_RULE_EXTENSION($name ,$len); # we don't want to create three answer rules in different modes.
620 :     my $out = MODES(
621 :     'TeX' => $answer_rule,
622 :     'Latex2HTML' => '\fbox{Answer boxes cannot be placed inside typeset equations}',
623 :     'HTML_tth' => '\\begin{rawhtml} '. $answer_rule.'\\end{rawhtml}',
624 :     'HTML' => $answer_rule
625 :     );
626 :    
627 :     $out;
628 :     }
629 : sam 2 sub ans_box {
630 :     my $row = shift;
631 :     my $col =shift;
632 :     $row = 5 unless $row;
633 :     $col = 80 unless $col;
634 :     my $name = NEW_ANS_NAME(++$main::ans_rule_count);
635 :     NAMED_ANS_BOX($name ,$row,$col);
636 :     }
637 :    
638 :     #this is legacy code; use ans_checkbox instead
639 :     sub checkbox {
640 :     my %options = @_;
641 :     qq!<INPUT TYPE="checkbox" NAME="$options{'-name'}" VALUE="$options{'-value'}">$options{'-label'}!
642 :     }
643 :    
644 :    
645 :     sub NAMED_POP_UP_LIST {
646 :     my $name = shift;
647 :     my @list = @_;
648 :     $name = RECORD_ANS_NAME($name); # record answer name
649 :     my $answer_value = '';
650 :     $answer_value = ${$main::inputs_ref}{$name} if defined(${$main::inputs_ref}{$name});
651 :     my $out = "";
652 :     if ($main::displayMode eq "HTML" or $main::displayMode eq "HTML_tth") {
653 :     $out = qq!<SELECT NAME = "$name" SIZE=1> \n!;
654 :     my $i;
655 :     foreach ($i=0; $i< @list; $i=$i+2) {
656 :     my $select_flag = ($list[$i] eq $answer_value) ? "SELECTED" : "";
657 :     $out .= qq!<OPTION $select_flag VALUE ="$list[$i]" > $list[$i+1] </OPTION>\n!;
658 :     };
659 :     $out .= " </SELECT>\n";
660 :     } elsif ( $main::displayMode eq "Latex2HTML") {
661 :     $out = qq! \\begin{rawhtml}<SELECT NAME = "$name" SIZE=1> \\end{rawhtml} \n !;
662 :     my $i;
663 :     foreach ($i=0; $i< @list; $i=$i+2) {
664 :     my $select_flag = ($list[$i] eq $answer_value) ? "SELECTED" : "";
665 :     $out .= qq!\\begin{rawhtml}<OPTION $select_flag VALUE ="$list[$i]" > $list[$i+1] </OPTION>\\end{rawhtml}\n!;
666 :     };
667 :     $out .= " \\begin{rawhtml}</SELECT>\\end{rawhtml}\n";
668 :     } elsif ( $main::displayMode eq "TeX") {
669 :     $out .= "\\fbox{?}";
670 :     }
671 :    
672 :     }
673 :    
674 :     sub pop_up_list {
675 :     my @list = @_;
676 :     my $name = NEW_ANS_NAME(++$main::ans_rule_count); # get new answer name
677 :     NAMED_POP_UP_LIST($name, @list);
678 :     }
679 :    
680 :     # end answer blank macros
681 :    
682 :     =head2 Hints and solutions macros
683 :    
684 :     solution('text','text2',...);
685 :     SOLUTION('text','text2',...); # equivalent to TEXT(solution(...));
686 :    
687 :     hint('text', 'text2', ...);
688 :     HINT('text', 'text2',...); # equivalent to TEXT("$main::BR$main::HINT" . hint(@_) . "$main::BR") if hint(@_);
689 :    
690 :     Solution prints its concatenated input when the check box named 'ShowSol' is set and
691 :     the time is after the answer date. (The variable C<$envir{'inputs_ref'}->>C<{'ShowSol'}> is set.)
692 :    
693 :     PG_FLAGS{'solutionExists'} is set to 1 when a solution is available for viewing.
694 :    
695 :     Hints are shown only after the number of attempts is greater than $main::showHint.
696 :     ($main::showHint defaults to 1.)
697 :    
698 :     =cut
699 :    
700 :    
701 :    
702 :     # solution prints its input when $displaySolutionsQ is set.
703 :     # use as TEXT(solution("blah, blah");
704 :     # \$solutionExists
705 :     # is passed to processProblem which displays a "show Solution" button
706 :     # when a solution is available for viewing
707 :    
708 :    
709 :     sub solution {
710 :     my @in = @_;
711 :     my $out = '';
712 : gage 27 PG_restricted_eval('$main::solutionExists =1');
713 : sam 2 if ($envir{'inputs_ref'}->{'ShowSol'}) {
714 :     my %inlist;
715 :     grep($inlist{$_}++,@{ $envir{'PRINT_FILE_NAMES_FOR'} });
716 :     if ( defined($inlist{$main::studentLogin}) and ($inlist{$main::studentLogin} > 0) ) {
717 :     $out = join(' ',@in);
718 :     } elsif ($envir{'answerDate'} < time ){
719 :     $out = join(' ',@in);
720 :     }
721 :     }
722 :    
723 :     $out;
724 :     }
725 :    
726 :    
727 :    
728 :     sub SOLUTION {
729 :     TEXT( solution(@_)) ;
730 :     }
731 :    
732 :    
733 :    
734 :     sub hint {
735 :     my @in = @_;
736 :     my $out = '';
737 :    
738 :     $main::showHint = 1 unless defined($main::showHint);
739 :     $main::numOfAttempts = 0 unless defined($main::numOfAttempts);
740 :     if ($main::displayMode eq 'TeX') {
741 :     $out = ''; # do nothing since hints are not available for download
742 :    
743 :     } elsif ($main::numOfAttempts >= $main::showHint ) { #numOfAttempts is only defined in interactive mode
744 :     if ( ${$main::inputs_ref}{'ShowHint'} ) {
745 :     $out = join(' ',@in); # show hint
746 :     } elsif ($main::displayMode eq 'HTML' or $main::displayMode eq 'HTML_tth') {
747 :     $out = checkbox(-name=>'ShowHint',
748 :     -value=>1,
749 :     -label=>"Show Hint",
750 :     -override => 1
751 :     ) ;
752 :     } elsif ($main::displayMode eq 'Latex2HTML') {
753 :     $out = '\\begin{rawhtml}' . checkbox(-name=>'ShowHint',
754 :     -value=>1,
755 :     -label=>"Show Hint",
756 :     -override => 1
757 :     ) . '\\end{rawhtml}' ;
758 :     } else {
759 :     warn "Error: The subroutine hints doesn't know what to do in display mode $main::displayMode.";
760 :     $out = '';
761 :     }
762 :     } else {
763 :     # do nothing since the $numOf Attempts is not yet large enough.
764 :     $out = '';
765 :     }
766 :     $out ;
767 :     }
768 :    
769 :    
770 :    
771 :     sub HINT {
772 :     TEXT("$main::BR$main::HINT" . hint(@_) . "$main::BR") if hint(@_);
773 :     }
774 :    
775 :    
776 :    
777 :     # End hints and solutions macros
778 :     #################################
779 :    
780 :     # Produces a random number between $begin and $end with increment 1.
781 :     # You do not have to worry about integer or floating point types.
782 :    
783 :     =head2 Pseudo-random number generator
784 :    
785 :     Usage:
786 :     random(0,5,.1) # produces a random number between 0 and 5 in increments of .1
787 :     non_zero_random(0,5,.1) # gives a non-zero random number
788 :    
789 :     SRAND(seed) # resets the main random generator -- use very cautiously
790 :    
791 :    
792 :     SRAND(time) will create a different problem everytime it is called. This makes it difficult
793 :     to check the answers :-).
794 :    
795 :     SRAND($envir{'inputs_ref'}->{'key'} ) will create a different problem for each login session.
796 :     This is probably what is desired.
797 :    
798 :     =cut
799 :    
800 :    
801 :     sub random {
802 :     my ($begin, $end, $incr) = @_;
803 :     $main::PG_random_generator->random($begin,$end,$incr);
804 :     }
805 :    
806 :    
807 :     sub non_zero_random { ##gives a non-zero random number
808 :     my (@arguments)=@_;
809 :     my $a=0;
810 :     my $i=100; #safety counter
811 :     while ($a==0 && ( 0 < $i-- ) ) {
812 :     $a=random(@arguments);
813 :     }
814 :     $a;
815 :     }
816 :    
817 :     sub SRAND { # resets the main random generator -- use cautiously
818 :     my $seed = shift;
819 :     $main::PG_random_generator -> srand($seed);
820 :     }
821 :    
822 :     # display macros
823 :    
824 :     =head2 Display Macros
825 :    
826 :     These macros produce different output depending on the display mode being used to show
827 :     the problem on the screen, or whether the problem is being converted to TeX to produce
828 :     a hard copy output.
829 :    
830 :     MODES ( TeX => "Output this in TeX mode",
831 :     HTML => "output this in HTML mode",
832 :     HTML_tth => "output this in HTML_tth mode",
833 :     Latex2HTML => "output this in Latex2HTML mode",
834 :     )
835 :    
836 :     TEX (tex_version, html_version) #obsolete
837 :    
838 :     M3 (tex_version, latex2html_version, html_version) #obsolete
839 :    
840 :    
841 :    
842 :     =cut
843 :    
844 :    
845 :     sub TEX {
846 :     my ($tex, $html ) = @_;
847 :     MODES(TeX => $tex, HTML => $html, HTML_tth => $html);
848 :     }
849 :    
850 :    
851 :     sub M3 {
852 :     my($tex,$l2h,$html) = @_;
853 :     MODES(TeX => $tex, Latex2HTML => $l2h, HTML => $html, HTML_tth => $html);
854 :     }
855 :    
856 :     # This replaces M3. You can add new modes at will to this one.
857 :    
858 :     sub MODES {
859 :     my %options = @_;
860 :     return $options{$main::displayMode}
861 :     if defined( $options{$main::displayMode} );
862 :    
863 :     # default searches.
864 :     if ($main::displayMode eq "Latex2HTML") {
865 :     return $options{TeX}
866 :     if defined( $options{TeX} );
867 :     return $options{HTML}
868 :     if defined( $options{HTML} );
869 :     die " ERROR in using MODES: 'HTML' and 'TeX' options not defined for 'Latex2HTML'";
870 :     }
871 :    
872 :     if ($main::displayMode eq "HTML_tth") {
873 :     return $options{HTML}
874 :     if defined( $options{HTML} );
875 :     die " ERROR in using MODES: 'HTML' option not defined for HTML_tth";
876 :    
877 :     }
878 :    
879 :     # trap undefined errors
880 : gage 27 die "ERROR in defining MODES: Can't find |$displayMode| among
881 :     available options:" . join(" ", keys(%options) )
882 :     . " file " . __FILE__ ." line " . __LINE__."\n\n";
883 : sam 2
884 :     }
885 :    
886 :    
887 :     # end display macros
888 :    
889 :    
890 :     =head2 Display constants
891 :    
892 :     @ALPHABET ALPHABET() capital letter alphabet -- ALPHABET[0] = 'A'
893 :     $PAR PAR() paragraph character (\par or <p>)
894 :     $BR BR() line break character
895 :     $LQ LQ() left double quote
896 :     $RQ RQ() right double quote
897 :     $BM BM() begin math
898 :     $EM EM() end math
899 :     $BDM BDM() begin display math
900 :     $EDM EDM() end display math
901 :     $LTS LTS() strictly less than
902 :     $GTS GTS() strictly greater than
903 :     $LTE LTE() less than or equal
904 :     $GTE GTE() greater than or equal
905 :     $BEGIN_ONE_COLUMN BEGIN_ONE_COLUMN() begin one-column mode
906 :     $END_ONE_COLUMN END_ONE_COLUMN() end one-column mode
907 :     $SOL SOLUTION_HEADING() solution headline
908 :     $HINT HINT_HEADING() hint headline
909 :     $US US() underscore character
910 :     $SPACE SPACE() space character (tex and latex only)
911 :     $BBOLD BBOLD() begin bold typeface
912 :     $EBOLD EBOLD() end bold typeface
913 :     $HR HR() horizontal rule
914 :     $LBRACE LBRACE() left brace
915 :     $LB LB () left brace
916 :     $RBRACE RBRACE() right brace
917 :     $RB RB () right brace
918 :     $DOLLAR DOLLAR() a dollar sign
919 :     $PERCENT PERCENT() a percent sign
920 :     $CARET CARET() a caret sign
921 :     $PI PI() the number pi
922 :     $E E() the number e
923 :    
924 :     =cut
925 :    
926 :    
927 :    
928 :     # A utility variable. Notice that "B"=$ALPHABET[1] and
929 :     # "ABCD"=@ALPHABET[0..3].
930 :    
931 :     sub ALPHABET {
932 :     ('A'..'ZZ')[@_];
933 :     }
934 :    
935 :     ###############################################################
936 :     # Some constants which are different in tex and in HTML
937 :     # The order of arguments is TeX, Latex2HTML, HTML
938 :     sub PAR { MODES( TeX => '\\par ',Latex2HTML => '\\par ',HTML => '<P>' ); };
939 :     sub BR { MODES( TeX => '\\par\\noindent ',Latex2HTML => '\\par\\noindent ',HTML => '<BR>'); };
940 :     sub LQ { MODES( TeX => "``", Latex2HTML => '"', HTML => '&quot;' ); };
941 :     sub RQ { MODES( TeX => "''", Latex2HTML => '"', HTML => '&quot;' ); };
942 :     sub BM { MODES(TeX => '\\(', Latex2HTML => '\\(', HTML => ''); }; # begin math mode
943 :     sub EM { MODES(TeX => '\\)', Latex2HTML => '\\)', HTML => ''); }; # end math mode
944 :     sub BDM { MODES(TeX => '\\[', Latex2HTML => '\\[', HTML => '<P ALIGN=CENTER>'); }; #begin displayMath mode
945 :     sub EDM { MODES(TeX => '\\]', Latex2HTML => '\\]', HTML => '</P>'); }; #end displayMath mode
946 :     sub LTS { MODES(TeX => ' < ', Latex2HTML => ' \\lt ', HTML => '&lt;'); };
947 :     sub GTS {MODES(TeX => ' > ', Latex2HTML => ' \\gt ', HTML => '&gt;'); };
948 :     sub LTE { MODES(TeX => ' \\le ', Latex2HTML => ' \\le ', HTML => '&lt;=' ); };
949 :     sub GTE { MODES(TeX => ' \\ge ', Latex2HTML => ' \\ge ', HTML => '&gt;'); };
950 :     sub BEGIN_ONE_COLUMN { MODES(TeX => " \\end{multicols}\n", Latex2HTML => " ", HTML => " "); };
951 :     sub END_ONE_COLUMN { MODES(TeX =>
952 :     " \\begin{multicols}{2}\n\\columnwidth=\\linewidth\n",
953 :     Latex2HTML => ' ', HTML => ' ');
954 :    
955 :     };
956 :     sub SOLUTION_HEADING { MODES( TeX => '\\par {\\bf Solution:}',
957 :     Latex2HTML => '\\par {\\bf Solution:}',
958 :     HTML => '<P><B>Solution:</B>');
959 :     };
960 :     sub HINT_HEADING { MODES( TeX => "\\par {\\bf Hint:}", Latex2HTML => "\\par {\\bf Hint:}", HTML => "<P><B>Hint:</B>"); };
961 :     sub US { MODES(TeX => '\\_', Latex2HTML => '\\_', HTML => '_');}; # underscore, e.g. file${US}name
962 :     sub SPACE { MODES(TeX => '\\ ', Latex2HTML => '\\ ', HTML => '&nbsp;');}; # force a space in latex, doesn't force extra space in html
963 :     sub BBOLD { MODES(TeX => '{\\bf ', Latex2HTML => '{\\bf ', HTML => '<B>'); };
964 :     sub EBOLD { MODES( TeX => '}', Latex2HTML => '}',HTML => '</B>'); };
965 :     sub HR { MODES(TeX => '\\par\\hrulefill\\par ', Latex2HTML => '\\begin{rawhtml} <HR> \\end{rawhtml}', HTML => '<HR>'); };
966 :     sub LBRACE { MODES( TeX => '\{', Latex2HTML => '\\lbrace', HTML => '\{' , HTML_tth=> '\\lbrace' ); };
967 :     sub RBRACE { MODES( TeX => '\}', Latex2HTML => '\\rbrace', HTML => '\}' , HTML_tth=> '\\rbrace',); };
968 :     sub LB { MODES( TeX => '\{', Latex2HTML => '\\lbrace', HTML => '\{' , HTML_tth=> '\\lbrace' ); };
969 :     sub RB { MODES( TeX => '\}', Latex2HTML => '\\rbrace', HTML => '\}' , HTML_tth=> '\\rbrace',); };
970 :     sub DOLLAR { MODES( TeX => '\\$', Latex2HTML => '\\$', HTML => '$' ); };
971 :     sub PERCENT { MODES( TeX => '\\%', Latex2HTML => '\\%', HTML => '%' ); };
972 :     sub CARET { MODES( TeX => '\\^', Latex2HTML => '\\^', HTML => '^' ); };
973 :     sub PI {4*atan2(1,1);};
974 :     sub E {exp(1);};
975 :    
976 :     ###############################################################
977 :     ## Evaluation macros
978 :    
979 :    
980 :     =head2 TEXT macros
981 :    
982 :     Usage:
983 :     TEXT(@text);
984 :    
985 :     This is the simplest way to print text from a problem. The strings in the array C<@text> are concatenated
986 :     with spaces between them and printed out in the text of the problem. The text is not processed in any other way.
987 :     C<TEXT> is defined in PG.pl.
988 :    
989 :     Usage:
990 :     BEGIN_TEXT
991 :     text.....
992 :     END_TEXT
993 :    
994 :     This is the most common way to enter text into the problem. All of the text between BEGIN_TEXT and END_TEXT
995 :     is processed by the C<EV3> macro described below and then printed using the C<TEXT> command. The two key words
996 :     must appear on lines by themselves. The preprocessing that makes this construction work is done in F<PGtranslator.pm>.
997 :     See C<EV3> below for details on the processing.
998 :    
999 :    
1000 :     =cut
1001 :    
1002 :     =head2 Evaluation macros
1003 :    
1004 :     =head3 EV3
1005 :    
1006 :     TEXT(EV3("This is a formulat \( \int_0^5 x^2 \, dx \) ");
1007 :     TEXT(EV3(@text));
1008 :    
1009 :     TEXT(EV3(<<'END_TEXT'));
1010 :     text stuff...
1011 :     END_TEXT
1012 :    
1013 :    
1014 :     The BEGIN_TEXT/END_TEXT construction is translated into the construction above by PGtranslator.pm. END_TEXT must appear
1015 :     on a line by itself and be left justified. (The << construction is known as a "here document" in UNIX and in PERL.)
1016 :    
1017 :     The single quotes around END_TEXT mean that no automatic interpolation of variables takes place in the text.
1018 :     Using EV3 with strings which have been evaluated by double quotes may lead to unexpected results.
1019 :    
1020 :    
1021 :     The evaluation macro E3 first evaluates perl code inside the braces: C<\{ code \}>.
1022 :     Any perl statment can be put inside the braces. The
1023 :     result of the evaluation (i.e. the last statement evaluated) replaces the C<\{ code \}> construction.
1024 :    
1025 :     Next interpolation of all variables (e.g. C<$var or @array> ) is performed.
1026 :    
1027 :     Then mathematical formulas in TeX are evaluated within the
1028 :     C<\( tex math mode \)> and
1029 :     C<\[ tex display math mode \] >
1030 :     constructions, in that order:
1031 :    
1032 :     =head3 FEQ
1033 :    
1034 :     FEQ($string); # processes and outputs the string
1035 :    
1036 :    
1037 :     The mathematical formulas are run through the macro C<FEQ> (Format EQuations) which performs
1038 :     several substitutions (see below).
1039 :     In C<HTML_tth> mode the resulting code is processed by tth to obtain an HTML version
1040 :     of the formula. (In the future processing by WebEQ may be added here as another option.)
1041 :     The Latex2HTML mode does nothing
1042 :     at this stage; it creates the entire problem before running it through
1043 :     TeX and creating the GIF images of the equations.
1044 :    
1045 :     The resulting string is output (and usually fed into TEXT to be printed in the problem).
1046 :    
1047 :     Usage:
1048 :    
1049 :     $string2 = FEQ($string1);
1050 :    
1051 :     This is a filter which is used to format equations by C<EV2> and C<EV3>, but can also be used on its own. It is best
1052 :     understood with an example.
1053 :    
1054 :     $string1 = "${a}x^2 + ${b}x + {$c:%.1f}"; $a = 3;, $b = -2; $c = -7.345;
1055 :    
1056 :     when interpolated becomes:
1057 :    
1058 :     $string1 = '3x^2 + -2x + {-7.345:%0.1f}
1059 :    
1060 :     FEQ first changes the number of decimal places displayed, so that the last term becomes -7.3 Then it removes the
1061 :     extraneous plus and minus signs, so that the final result is what you want:
1062 :    
1063 :     $string2 = '3x^2 - 2x -7.3';
1064 :    
1065 :     (The %0.1f construction
1066 :     is the same formatting convention used by Perl and nearly identical to the one used by the C printf statement. Some common
1067 :     usage: %0.3f 3 decimal places, fixed notation; %0.3e 3 significant figures exponential notation; %0.3g uses either fixed
1068 :     or exponential notation depending on the size of the number.)
1069 :    
1070 :     Two additional legacy formatting constructions are also supported:
1071 :    
1072 :     C<?{$c:%0.3f} > will give a number with 3 decimal places and a negative
1073 :     sign if the number is negative, no sign if the number is positive.
1074 :    
1075 :     C<!{$c:%0.3f}> determines the sign and prints it
1076 :     whether the number is positive or negative.
1077 :    
1078 :     =head3 EV2
1079 :    
1080 :     TEXT(EV2(@text));
1081 :    
1082 :     TEXT(EV2(<<END_OF_TEXT));
1083 :     text stuff...
1084 :     END_OF_TEXT
1085 :    
1086 :     This is a precursor to EV3. In this case the constants are interpolated first, before the evaluation of the \{ ...code...\}
1087 :     construct. This can lead to unexpected results. For example C<\{ join(" ", @text) \}> with C<@text = ("Hello","World);> becomes,
1088 :     after interpolation, C<\{ join(" ",Hello World) \}> which then causes an error when evaluated because Hello is a bare word.
1089 :     C<EV2> can still be useful if you allow for this, and in particular it works on double quoted strings, which lead to
1090 :     unexpected results with C<EV3>. Using single quoted strings with C<EV2> may lead to unexpected results.
1091 :    
1092 :     The unexpected results have to do with the number of times backslashed constructions have to be escaped. It's quite messy. For
1093 :     more details get a good Perl book and then read the code. :-)
1094 :    
1095 :    
1096 :    
1097 :    
1098 :     =cut
1099 :    
1100 :    
1101 :     sub ev_substring {
1102 :     my $string = shift;
1103 :     my $start_delim = shift;
1104 :     my $end_delim = shift;
1105 :     my $actionRef = shift;
1106 :     my ($eval_out,$PG_eval_errors,$PG_full_error_report)=();
1107 :     my $out = "";
1108 :     while ($string) {
1109 :     if ($string =~ /\Q$start_delim\E/s) {
1110 :     #print "$start_delim $end_delim evaluating_substring=$string<BR>";
1111 :     $string =~ s/^(.*?)\Q$start_delim\E//s; # get string up to next \{ ---treats string as a single line, ignoring returns
1112 :     $out .= $1;
1113 :     #print "$start_delim $end_delim substring_out=$out<BR>";
1114 :     $string =~ s/^(.*?)\Q$end_delim\E//s; # get perl code up to \} ---treats string as a single line, ignoring returns
1115 :     #print "$start_delim $end_delim evaluate_string=$1<BR>";
1116 :     ($eval_out,$PG_eval_errors,$PG_full_error_report) = &$actionRef($1);
1117 :     $eval_out = "$start_delim $eval_out $end_delim" if $PG_full_error_report;
1118 :     $out = $out . $eval_out;
1119 :     #print "$start_delim $end_delim new substring_out=$out<BR><p><BR>";
1120 :     $out .="$main::PAR ERROR $0 in ev_substring, PGbasicmacros.pl:$main::PAR <PRE> $@ </PRE>$main::PAR" if $@;
1121 :     }
1122 :     else {
1123 :     $out .= $string; # flush the last part of the string
1124 :     last;
1125 :     }
1126 :    
1127 :     }
1128 :     $out;
1129 :     }
1130 :     sub safe_ev {
1131 :     my ($out,$PG_eval_errors,$PG_full_error_report) = &old_safe_ev; # process input by old_safe_ev first
1132 :     $out =~s/\\/\\\\/g; # protect any new backslashes introduced.
1133 :     ($out,$PG_eval_errors,$PG_full_error_report)
1134 :     }
1135 :    
1136 :     sub old_safe_ev {
1137 :     my $in = shift;
1138 :     my ($out,$PG_eval_errors,$PG_full_error_report) = PG_restricted_eval("$in;");
1139 :     # the addition of the ; seems to provide better error reporting
1140 :     if ($PG_eval_errors) {
1141 :     my @errorLines = split("\n",$PG_eval_errors);
1142 :     #$out = "<PRE>$main::PAR % ERROR in $0:old_safe_ev, PGbasicmacros.pl: $main::PAR % There is an error occuring inside evaluation brackets \\{ ...code... \\} $main::BR % somewhere in an EV2 or EV3 or BEGIN_TEXT block. $main::BR % Code evaluated:$main::BR $in $main::BR % $main::BR % $errorLines[0]\n % $errorLines[1]$main::BR % $main::BR % $main::BR </PRE> ";
1143 :     warn " ERROR in old_safe_ev, PGbasicmacros.pl: <PRE>
1144 :     ## There is an error occuring inside evaluation brackets \\{ ...code... \\}
1145 :     ## somewhere in an EV2 or EV3 or BEGIN_TEXT block.
1146 :     ## Code evaluated:
1147 :     ## $in
1148 :     ##" .join("\n ", @errorLines). "
1149 :     ##</PRE>$main::BR
1150 :     ";
1151 :     $out ="$main::PAR $main::BBOLD $in $main::EBOLD $main::PAR";
1152 :    
1153 :    
1154 :     }
1155 :    
1156 :     ($out,$PG_eval_errors,$PG_full_error_report);
1157 :     }
1158 :    
1159 :     sub FEQ { # Format EQuations
1160 :     my $in = shift;
1161 :     # formatting numbers -- the ?{} and !{} constructions
1162 :     $in =~s/\?\s*\{([.\-\$\w\d]+):?([%.\da-z]*)\}/${ \( &sspf($1,$2) )}/g;
1163 :     $in =~s/\!\s*\{([.\-\$\w\d]+):?([%.\da-z]*)\}/${ \( &spf($1,$2) )}/g;
1164 :    
1165 :     # more formatting numbers -- {number:format} constructions
1166 :     $in =~ s/\{(\s*[\+\-\d\.]+[eE]*[\+\-]*\d*):(\%\d*.\d*\w)}/${ \( &spf($1,$2) )}/g;
1167 :     $in =~ s/\+\s*\-/ - /g;
1168 :     $in =~ s/\-\s*\+/ - /g;
1169 :     $in =~ s/\+\s*\+/ + /g;
1170 :     $in =~ s/\-\s*\-/ + /g;
1171 :     $in;
1172 :     }
1173 :    
1174 :     sub math_ev3 {
1175 :     my $in = shift; #print "in=$in<BR>";
1176 :     my ($out,$PG_eval_errors,$PG_full_error_report);
1177 :     $in = FEQ($in);
1178 :     $in =~ s/%/\\%/g; # % causes trouble in TeX and HTML_tth it usually (always?) indicates an error, not comment
1179 :     return("$main::BM $in $main::EM") unless ($main::displayMode eq 'HTML_tth');
1180 :     $in = "\\(" . $in . "\\)";
1181 :     $out = tth($in);
1182 :     ($out,$PG_eval_errors,$PG_full_error_report);
1183 :    
1184 :     }
1185 :    
1186 :     sub display_math_ev3 {
1187 :     my $in = shift; #print "in=$in<BR>";
1188 :     my ($out,$PG_eval_errors,$PG_full_error_report);
1189 :     $in = FEQ($in);
1190 :     $in =~ s/%/\\%/g;
1191 :     return("$main::BDM $in $main::EDM") unless $main::displayMode eq 'HTML_tth' ;
1192 :     $in = "\\[" . $in . "\\]";
1193 :     $out =tth($in);
1194 :     ($out,$PG_eval_errors,$PG_full_error_report);
1195 :     }
1196 :    
1197 :     sub EV2 {
1198 :     my $string = join(" ",@_);
1199 :     # evaluate code inside of \{ \} (no nesting allowed)
1200 :     $string = ev_substring($string,"\\{","\\}",\&old_safe_ev);
1201 :     $string = ev_substring($string,"\\<","\\>",\&old_safe_ev);
1202 :     $string = ev_substring($string,"\\(","\\)",\&math_ev3);
1203 :     $string = ev_substring($string,"\\[","\\]",\&display_math_ev3);
1204 :     # macros for displaying math
1205 :     $string =~ s/\\\(/$main::BM/g;
1206 :     $string =~ s/\\\)/$main::EM/g;
1207 :     $string =~ s/\\\[/$main::BDM/g;
1208 :     $string =~ s/\\\]/$main::EDM/g;
1209 :     $string;
1210 :     }
1211 :    
1212 :     sub EV3{
1213 :     my $string = join(" ",@_);
1214 :     # evaluate code inside of \{ \} (no nesting allowed)
1215 :     $string = ev_substring($string,"\\\\{","\\\\}",\&safe_ev); # handles \{ \} in single quoted strings of PG files
1216 :     # interpolate variables
1217 :     my ($evaluated_string,$PG_eval_errors,$PG_full_errors) = PG_restricted_eval("<<END_OF_EVALUATION_STRING\n$string\nEND_OF_EVALUATION_STRING\n");
1218 :     if ($PG_eval_errors) {
1219 :     my @errorLines = split("\n",$PG_eval_errors);
1220 :     $string =~ s/</&lt;/g; $string =~ s/>/&gt;/g;
1221 :     $evaluated_string = "<PRE>$main::PAR % ERROR in $0:EV3, PGbasicmacros.pl: $main::PAR % There is an error occuring in the following code:$main::BR $string $main::BR % $main::BR % $errorLines[0]\n % $errorLines[1]$main::BR % $main::BR % $main::BR </PRE> ";
1222 :     $@="";
1223 :     }
1224 :     $string = $evaluated_string;
1225 :     $string = ev_substring($string,"\\(","\\)",\&math_ev3);
1226 :     $string = ev_substring($string,"\\[","\\]",\&display_math_ev3);
1227 :     $string;
1228 :     }
1229 :    
1230 :     =head2 Formatting macros
1231 :    
1232 :     beginproblem() # generates text listing number and the point value of
1233 :     # the problem. It will also print the file name containing
1234 :     # the problem for users listed in the PRINT_FILE_NAMES_FOR PG_environment
1235 :     # variable.
1236 :     OL(@array) # formats the array as an Ordered List ( <OL> </OL> ) enumerated by letters.
1237 :    
1238 :     htmlLink($url, $text)
1239 :     # Places a reference to the URL with the specified text in the problem.
1240 :     # A common usage is \{ htmlLink(alias('prob1_help.html') \}, 'for help')
1241 :     # where alias finds the full address of the prob1_help.html file in the same directory
1242 :     # as the problem file
1243 :     appletLink($url, $parameters)
1244 :     # For example
1245 : gage 5 # appletLink(q! archive="http: //webwork.math.rochester.edu/gage/xFunctions/xFunctions.zip"
1246 :     code="xFunctionsLauncher.class" width=100 height=14!,
1247 : sam 2 " parameter text goes here")
1248 :     # will link to xFunctions.
1249 :    
1250 :     low level:
1251 :    
1252 :     spf($number, $format) # prints the number with the given format
1253 :     sspf($number, $format) # prints the number with the given format, always including a sign.
1254 :     protect_underbar($string) # protects the underbar (class_name) in strings which may have to pass through TeX.
1255 :    
1256 :     =cut
1257 :    
1258 :     sub beginproblem {
1259 :     my $out = "";
1260 :     my $TeXFileName = protect_underbar($main::fileName);
1261 :     my $l2hFileName = protect_underbar($main::fileName);
1262 :     my %inlist;
1263 :     my $points ='pts';
1264 :     $points = 'pt' if $main::problemValue == 1;
1265 :     ## Prepare header for the problem
1266 :     grep($inlist{$_}++,@{ $envir{'PRINT_FILE_NAMES_FOR'} });
1267 :     if ( defined($inlist{$main::studentLogin}) and ($inlist{$main::studentLogin} > 0) ) {
1268 :     $out = &M3("\n\n\\medskip\\hrule\\smallskip\\par{\\bf ${main::probNum}.{\\footnotesize ($main::problemValue $points) $TeXFileName}}\\newline ",
1269 :     " \\begin{rawhtml} ($main::problemValue $points) <B>$l2hFileName</B><BR>\\end{rawhtml}",
1270 :     "($main::problemValue $points) <B>$main::fileName</B><BR>"
1271 :     );
1272 :     } else {
1273 :     $out = &M3("\n\n\\smallskip\\hrule\\smallskip\\par{\\bf ${main::probNum}.}($main::problemValue $points) ",
1274 :     "($main::problemValue $points) ",
1275 :     "($main::problemValue $points) "
1276 :     );
1277 :     }
1278 :     $out;
1279 :    
1280 :     }
1281 :    
1282 :     # kludge to clean up path names
1283 :     ## allow underscore character in set and section names and also allows line breaks at /
1284 :     sub protect_underbar {
1285 :     my $in = shift;
1286 :     if ($main::displayMode eq 'TeX') {
1287 :    
1288 :     $in =~ s|_|\\\_|g;
1289 :     $in =~ s|/|\\\-/|g; # allows an optional hyphenation of the path (in tex)
1290 :     }
1291 :     $in;
1292 :     }
1293 :    
1294 :    
1295 :     # An example of a macro which prints out a list (with letters)
1296 :     sub OL {
1297 :     my(@array) = @_;
1298 :     my $i = 0;
1299 :     my $out= &M3(
1300 :     "\\begin{enumerate}\n",
1301 :     " \\begin{rawhtml} <OL TYPE=\"A\" VALUE=\"1\"> \\end{rawhtml} ",
1302 :     "<OL TYPE=\"A\" VALUE=\"1\">\n"
1303 :     ) ;
1304 :     my $elem;
1305 :     foreach $elem (@array) {
1306 :     $out .= &M3(
1307 :     "\\item[$main::ALPHABET[$i].] $elem\n",
1308 :     " \\begin{rawhtml} <LI> \\end{rawhtml} $elem ",
1309 :     "<LI> $elem\n"
1310 :     ) ;
1311 :     $i++;
1312 :     }
1313 :     $out .= &M3(
1314 :     "\\end{enumerate}\n",
1315 :     " \\begin{rawhtml} </OL>\n \\end{rawhtml} ",
1316 :     "</OL>\n"
1317 :     ) ;
1318 :     }
1319 :    
1320 :     sub htmlLink {
1321 :     my $url = shift;
1322 :     my $text = shift;
1323 :     my $options = shift;
1324 :     $options = "" unless defined($options);
1325 :     M3( "{\\bf \\underline{$text} }",
1326 :     "\\begin{rawhtml} <A HREF=\"$url\" $options> $text </A>\\end{rawhtml}",
1327 :     "<A HREF=\"$url\" $options> $text </A>"
1328 :     );
1329 :     }
1330 :     sub appletLink {
1331 :     my $url = shift;
1332 :     my $options = shift;
1333 :     $options = "" unless defined($options);
1334 :     M3( "{\\bf \\underline{APPLET} }",
1335 :     "\\begin{rawhtml} <APPLET $url> $options </APPLET>\\end{rawhtml}",
1336 :     "<APPLET $url> $options </APPLET>"
1337 :     );
1338 :     }
1339 :     sub spf {
1340 :     my($number,$format) = @_; # attention, the order of format and number are reversed
1341 :     $format = "%4.3g" unless $format; # default value for format
1342 :     sprintf($format, $number);
1343 :     }
1344 :     sub sspf {
1345 :     my($number,$format) = @_; # attention, the order of format and number are reversed
1346 :     $format = "%4.3g" unless $format; # default value for format
1347 :     my $sign = $number>=0 ? " + " : " - ";
1348 :     $number = $number>=0 ? $number : -$number;
1349 :     $sign .sprintf($format, $number);
1350 :     }
1351 :    
1352 :     =head2 Sorting and other list macros
1353 :    
1354 :    
1355 :    
1356 :     Usage:
1357 :     lex_sort(@list); # outputs list in lexigraphic (alphabetical) order
1358 :     num_sort(@list); # outputs list in numerical order
1359 :     uniq( @list); # outputs a list with no duplicates. Order is unspecified.
1360 :    
1361 :     PGsort( \&sort_subroutine, @list);
1362 :     # &sort_subroutine defines order. It's output must be -1,0 or 1.
1363 :    
1364 :     =cut
1365 :    
1366 :     # uniq gives unique elements of a list:
1367 :     sub uniq {
1368 :     my (@in) =@_;
1369 :     my %temp = ();
1370 :     while (@in) {
1371 :     $temp{shift(@in)}++;
1372 :     }
1373 :     my @out = keys %temp; # sort is causing trouble with Safe.??
1374 :     @out;
1375 :     }
1376 :    
1377 :     sub lex_sort {
1378 :     PGsort sub {$_[0] cmp $_[1]}, @_;
1379 :     }
1380 :     sub num_sort {
1381 :     PGsort sub {$_[0] <=> $_[1]}, @_;
1382 :     }
1383 :    
1384 :    
1385 :     =head2 Macros for handling tables
1386 :    
1387 :     Usage:
1388 :     begintable( number_of_columns_in_table)
1389 :     row(@dataelements)
1390 :     endtable()
1391 :    
1392 :     Example of useage:
1393 :    
1394 :     BEGIN_TEXT
1395 :     This problem tests calculating new functions from old ones:$BR
1396 :     From the table below calculate the quantities asked for:$BR
1397 :     \{begintable(scalar(@firstrow)+1)\}
1398 :     \{row(" \(x\) ",@firstrow)\}
1399 :     \{row(" \(f(x)\) ", @secondrow)\}
1400 :     \{row(" \(g(x)\) ", @thirdrow)\}
1401 :     \{row(" \(f'(x)\) ", @fourthrow)\}
1402 :     \{row(" \(g'(x)\) ", @fifthrow)\}
1403 :     \{endtable()\}
1404 :    
1405 :     (The arrays contain numbers which are placed in the table.)
1406 :    
1407 :     END_TEXT
1408 :    
1409 :     =cut
1410 :    
1411 :     sub begintable {
1412 :     my ($number)=shift; #number of columns in table
1413 :     my %options = @_;
1414 :     warn "begintable(cols) requires a number indicating the number of columns" unless defined($number);
1415 :     my $out = "";
1416 :     if ($main::displayMode eq 'TeX') {
1417 :     $out .= "\n\\par\\smallskip\\begin{center}\\begin{tabular}{" . "|c" x $number . "|} \\hline\n";
1418 :     }
1419 :     elsif ($main::displayMode eq 'Latex2HTML') {
1420 :     $out .= "\n\\begin{rawhtml} <TABLE , BORDER=1>\n\\end{rawhtml}";
1421 :     }
1422 :     elsif ($main::displayMode eq 'HTML' || $main::displayMode eq 'HTML_tth') {
1423 :     $out .= "<TABLE BORDER=1>\n"
1424 :     }
1425 :     else {
1426 :     $out = "Error: PGchoicemacros: begintable: Unknown displayMode: $main::displayMode.\n";
1427 :     }
1428 :     $out;
1429 :     }
1430 :    
1431 :     sub endtable {
1432 :     my $out = "";
1433 :     if ($main::displayMode eq 'TeX') {
1434 :     $out .= "\n\\end {tabular}\\end{center}\\par\\smallskip\n";
1435 :     }
1436 :     elsif ($main::displayMode eq 'Latex2HTML') {
1437 :     $out .= "\n\\begin{rawhtml} </TABLE >\n\\end{rawhtml}";
1438 :     }
1439 :     elsif ($main::displayMode eq 'HTML' || $main::displayMode eq 'HTML_tth') {
1440 :     $out .= "</TABLE>\n";
1441 :     }
1442 :     else {
1443 :     $out = "Error: PGchoicemacros: endtable: Unknown displayMode: $main::displayMode.\n";
1444 :     }
1445 :     $out;
1446 :     }
1447 :    
1448 :    
1449 :     sub row {
1450 :     my @elements = @_;
1451 :     my $out = "";
1452 :     if ($main::displayMode eq 'TeX') {
1453 :     while (@elements) {
1454 :     $out .= shift(@elements) . " &";
1455 :     }
1456 :     chop($out); # remove last &
1457 :     $out .= "\\\\ \\hline \n";
1458 :     # carriage returns must be added manually for tex
1459 :     }
1460 :     elsif ($main::displayMode eq 'Latex2HTML') {
1461 :     $out .= "\n\\begin{rawhtml}\n<TR>\n\\end{rawhtml}\n";
1462 :     while (@elements) {
1463 :     $out .= " \n\\begin{rawhtml}\n<TD> \n\\end{rawhtml}\n" . shift(@elements) . " \n\\begin{rawhtml}\n</TD> \n\\end{rawhtml}\n";
1464 :     }
1465 :     $out .= " \n\\begin{rawhtml}\n</TR> \n\\end{rawhtml}\n";
1466 :     }
1467 :     elsif ($main::displayMode eq 'HTML' || $main::displayMode eq 'HTML_tth') {
1468 :     $out .= "<TR>\n";
1469 :     while (@elements) {
1470 :     $out .= "<TD>" . shift(@elements) . "</TD>";
1471 :     }
1472 :     $out .= "\n</TR>\n";
1473 :     }
1474 :     else {
1475 :     $out = "Error: PGchoicemacros: row: Unknown displayMode: $main::displayMode.\n";
1476 :     }
1477 :     $out;
1478 :     }
1479 :    
1480 :     =head2 Macros for displaying static images
1481 :    
1482 :     Usage:
1483 :     $string = image($image, width => 100, height => 100, tex_size => 800)
1484 :     $string = image([$image1, $image2], width => 100, height => 100, tex_size => 800)
1485 :     $string = caption($string);
1486 :     $string = imageRow([$image1, $image2 ], [$caption1, $caption2]);
1487 :     # produces a complete table with rows of pictures.
1488 :    
1489 :    
1490 :     =cut
1491 :    
1492 :     # More advanced macros
1493 :     sub image {
1494 :     my $image_ref = shift;
1495 :     my @opt = @_;
1496 :     unless (scalar(@opt) % 2 == 0 ) {
1497 :     warn "ERROR in image macro. A list of macros must be inclosed in square brackets.";
1498 :     }
1499 :     my %in_options = @opt;
1500 :     my %known_options = ( width => 100,
1501 :     height => 100,
1502 :     tex_size => 800
1503 :     );
1504 :     # # handle options
1505 :     my %out_options = %known_options;
1506 :     foreach my $opt_name (keys %in_options) {
1507 :     if ( exists( $known_options{$opt_name} ) ) {
1508 :     $out_options{$opt_name} = $in_options{$opt_name} if exists( $in_options{$opt_name} ) ;
1509 :     } else {
1510 :     die "Option $opt_name not defined for image. " .
1511 :     "Default options are:<BR> ", display_options2(%known_options);
1512 :    
1513 :     }
1514 :     }
1515 :     my $width = $out_options{width};
1516 :     my $height = $out_options{height};
1517 :     my $tex_size = $out_options{tex_size};
1518 :     my $width_ratio = $tex_size*(.001);
1519 :     my @image_list = ();
1520 :    
1521 :     if (ref($image_ref) =~ /ARRAY/ ) {
1522 :     @image_list = @{$image_ref};
1523 :     } else {
1524 :     push(@image_list,$image_ref);
1525 :     }
1526 :     my @output_list = ();
1527 :     while(@image_list) {
1528 :    
1529 :     my $imageURL = alias(shift @image_list);
1530 :     my $out="";
1531 :    
1532 :    
1533 :     if ($main::displayMode eq 'TeX') {
1534 :     $out = qq!\\includegraphics[width=$width_ratio\\linewidth]{$imageURL}\n !
1535 :     }
1536 :     elsif ($main::displayMode eq 'Latex2HTML') {
1537 :     $out = qq!\\begin{rawhtml}\n<A HREF= "$imageURL" TARGET="ZOOM"><IMG SRC="$imageURL" WIDTH="$width" HEIGHT="$height"></A>\n
1538 :     \\end{rawhtml}\n !
1539 :     }
1540 :     elsif ($main::displayMode eq 'HTML' || $main::displayMode eq 'HTML_tth') {
1541 :     $out = qq!<A HREF= "$imageURL" TARGET="ZOOM"><IMG SRC="$imageURL" WIDTH="$width" HEIGHT="$height"></A>
1542 :     !
1543 :     }
1544 :     else {
1545 :     $out = "Error: PGchoicemacros: image: Unknown displayMode: $main::displayMode.\n";
1546 :     }
1547 :     push(@output_list, $out);
1548 :     }
1549 :     wantarray ? @output_list : $output_list[0] ;
1550 :     }
1551 :    
1552 :     # This is legacy code.
1553 :     sub images {
1554 :     my @in = @_;
1555 :     my @outlist = ();
1556 :     while (@in) {
1557 :     push(@outlist,&image( shift(@in) ) );
1558 :     }
1559 :     @outlist;
1560 :     }
1561 :    
1562 :    
1563 :     sub caption {
1564 :     my ($out) = @_;
1565 :     $out = " $out \n" if $main::displayMode eq 'TeX';
1566 :     $out = " $out " if $main::displayMode eq 'HTML';
1567 :     $out = " $out " if $main::displayMode eq 'HTML_tth';
1568 :     $out = " $out " if $main::displayMode eq 'Latex2HTML';
1569 :     $out;
1570 :     }
1571 :    
1572 :     sub captions {
1573 :     my @in = @_;
1574 :     my @outlist = ();
1575 :     while (@in) {
1576 :     push(@outlist,&caption( shift(@in) ) );
1577 :     }
1578 :     @outlist;
1579 :     }
1580 :    
1581 :     sub imageRow {
1582 :    
1583 :     my $pImages = shift;
1584 :     my $pCaptions=shift;
1585 :     my $out = "";
1586 :     my @images = @$pImages;
1587 :     my @captions = @$pCaptions;
1588 :     my $number = @images;
1589 :     # standard options
1590 :     my %options = ( 'tex_size' => 200, # width for fitting 4 across
1591 :     'height' => 100,
1592 :     'width' => 100,
1593 :     @_ # overwrite any default options
1594 :     );
1595 :    
1596 :     if ($main::displayMode eq 'TeX') {
1597 :     $out .= "\n\\par\\smallskip\\begin{center}\\begin{tabular}{" . "|c" x $number . "|} \\hline\n";
1598 :     while (@images) {
1599 :     $out .= &image( shift(@images),%options ) . '&';
1600 :     }
1601 :     chop($out);
1602 :     $out .= "\\\\ \\hline \n";
1603 :     while (@captions) {
1604 :     $out .= &caption( shift(@captions) ) . '&';
1605 :     }
1606 :     chop($out);
1607 :     $out .= "\\\\ \\hline \n\\end {tabular}\\end{center}\\par\\smallskip\n";
1608 :     } elsif ($main::displayMode eq 'Latex2HTML'){
1609 :    
1610 :     $out .= "\n\\begin{rawhtml} <TABLE BORDER=1><TR>\n\\end{rawhtml}\n";
1611 :     while (@images) {
1612 :     $out .= "\n\\begin{rawhtml} <TD>\n\\end{rawhtml}\n" . &image( shift(@images),%options )
1613 :     . "\n\\begin{rawhtml} </TD>\n\\end{rawhtml}\n" ;
1614 :     }
1615 :    
1616 :     $out .= "\n\\begin{rawhtml}</TR><TR>\\end{rawhtml}\n";
1617 :     while (@captions) {
1618 :     $out .= "\n\\begin{rawhtml} <TH>\n\\end{rawhtml}\n".&caption( shift(@captions) )
1619 :     . "\n\\begin{rawhtml} </TH>\n\\end{rawhtml}\n" ;
1620 :     }
1621 :    
1622 :     $out .= "\n\\begin{rawhtml} </TR> </TABLE >\n\\end{rawhtml}";
1623 :     } elsif ($main::displayMode eq 'HTML' || $main::displayMode eq 'HTML_tth'){
1624 :     $out .= "<P>\n <TABLE BORDER=2 CELLPADDING=3 CELLSPACING=2 ><TR ALIGN=CENTER VALIGN=MIDDLE>\n";
1625 :     while (@images) {
1626 :     $out .= " \n<TD>". &image( shift(@images),%options ) ."</TD>";
1627 :     }
1628 :     $out .= "</TR>\n<TR>";
1629 :     while (@captions) {
1630 :     $out .= " <TH>". &caption( shift(@captions) ) ."</TH>";
1631 :     }
1632 :     $out .= "\n</TR></TABLE></P>\n"
1633 :     }
1634 :     else {
1635 :     $out = "Error: PGchoicemacros: imageRow: Unknown languageMode: $main::displayMode.\n";
1636 :     warn $out;
1637 :     }
1638 :     $out;
1639 :     }
1640 :    
1641 :    
1642 :     ###########
1643 :     # Auxiliary macros
1644 :    
1645 :     sub display_options2{
1646 :     my %options = @_;
1647 :     my $out_string = "";
1648 :     foreach my $key (keys %options) {
1649 :     $out_string .= " $key => $options{$key},<BR>";
1650 :     }
1651 :     $out_string;
1652 :     }
1653 :    
1654 :    
1655 :     1;

aubreyja at gmail dot com
ViewVC Help
Powered by ViewVC 1.0.9