line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package PostScript::Graph::Key; |
2
|
|
|
|
|
|
|
our $VERSION = 1.03; |
3
|
13
|
|
|
13
|
|
1042
|
use strict; |
|
13
|
|
|
|
|
30
|
|
|
13
|
|
|
|
|
672
|
|
4
|
13
|
|
|
13
|
|
79
|
use warnings; |
|
13
|
|
|
|
|
29
|
|
|
13
|
|
|
|
|
439
|
|
5
|
13
|
|
|
13
|
|
71
|
use Exporter; |
|
13
|
|
|
|
|
27
|
|
|
13
|
|
|
|
|
549
|
|
6
|
13
|
|
|
13
|
|
74
|
use Carp; |
|
13
|
|
|
|
|
28
|
|
|
13
|
|
|
|
|
1503
|
|
7
|
13
|
|
|
13
|
|
71
|
use PostScript::File 1.00 qw(str); |
|
13
|
|
|
|
|
266
|
|
|
13
|
|
|
|
|
685
|
|
8
|
13
|
|
|
13
|
|
11023
|
use PostScript::Graph::Paper 1.00; |
|
13
|
|
|
|
|
473
|
|
|
13
|
|
|
|
|
27970
|
|
9
|
|
|
|
|
|
|
|
10
|
|
|
|
|
|
|
our @ISA = qw(Exporter); |
11
|
|
|
|
|
|
|
|
12
|
|
|
|
|
|
|
=head1 NAME |
13
|
|
|
|
|
|
|
|
14
|
|
|
|
|
|
|
PostScript::Graph::Key - a Key area for PostScript::Graph::Paper |
15
|
|
|
|
|
|
|
|
16
|
|
|
|
|
|
|
=head1 SYNOPSIS |
17
|
|
|
|
|
|
|
|
18
|
|
|
|
|
|
|
use PostScript::File; |
19
|
|
|
|
|
|
|
use PostScript::Graph::Key; |
20
|
|
|
|
|
|
|
use PostScript::Graph::Paper; |
21
|
|
|
|
|
|
|
|
22
|
|
|
|
|
|
|
=head2 Typical |
23
|
|
|
|
|
|
|
|
24
|
|
|
|
|
|
|
A Key panel is drawn to the right of its associated graph. The area needed for the Key panel must be calculated |
25
|
|
|
|
|
|
|
before the graph Paper can be drawn in the remaining space. |
26
|
|
|
|
|
|
|
|
27
|
|
|
|
|
|
|
my $ps = new PostScript::File; |
28
|
|
|
|
|
|
|
my @bbox = $psf->get_page_bounding_box(); |
29
|
|
|
|
|
|
|
|
30
|
|
|
|
|
|
|
# Calculate variables from the graph data |
31
|
|
|
|
|
|
|
# planned layout and available space ... |
32
|
|
|
|
|
|
|
|
33
|
|
|
|
|
|
|
my $gk = new PostScript::Graph::Key( |
34
|
|
|
|
|
|
|
num_items => ... , |
35
|
|
|
|
|
|
|
max_height => ... , |
36
|
|
|
|
|
|
|
text_width => ... , |
37
|
|
|
|
|
|
|
icon_width => ... , |
38
|
|
|
|
|
|
|
icon_height => ... , |
39
|
|
|
|
|
|
|
); |
40
|
|
|
|
|
|
|
|
41
|
|
|
|
|
|
|
# Need to pass this to GraphPaper |
42
|
|
|
|
|
|
|
my $width = $pgk->width(); |
43
|
|
|
|
|
|
|
|
44
|
|
|
|
|
|
|
my $gp = new PostScript::Graph::Paper( |
45
|
|
|
|
|
|
|
file => $ps, |
46
|
|
|
|
|
|
|
chart => { |
47
|
|
|
|
|
|
|
key_width => $width, |
48
|
|
|
|
|
|
|
}, |
49
|
|
|
|
|
|
|
); |
50
|
|
|
|
|
|
|
|
51
|
|
|
|
|
|
|
# Now we can link the two |
52
|
|
|
|
|
|
|
$gk->build_key( $gp ); |
53
|
|
|
|
|
|
|
|
54
|
|
|
|
|
|
|
foreach $line (@lines) { |
55
|
|
|
|
|
|
|
... draw line on graph_paper ... |
56
|
|
|
|
|
|
|
|
57
|
|
|
|
|
|
|
$gk->add_key_item( $title, <
|
58
|
|
|
|
|
|
|
... postscript code |
59
|
|
|
|
|
|
|
... drawing icon |
60
|
|
|
|
|
|
|
END |
61
|
|
|
|
|
|
|
} |
62
|
|
|
|
|
|
|
|
63
|
|
|
|
|
|
|
=head2 All options |
64
|
|
|
|
|
|
|
|
65
|
|
|
|
|
|
|
my $gp = new PostScript::Graph::Key( |
66
|
|
|
|
|
|
|
file => $ps_file, |
67
|
|
|
|
|
|
|
graph_paper => $ps_gpaper, |
68
|
|
|
|
|
|
|
max_height => 500, |
69
|
|
|
|
|
|
|
num_items => 5, |
70
|
|
|
|
|
|
|
background => 0.9, |
71
|
|
|
|
|
|
|
outline_color => [0.5, 0.5, 0.2], |
72
|
|
|
|
|
|
|
outline_wdith => 0.8, |
73
|
|
|
|
|
|
|
spacing => 4, |
74
|
|
|
|
|
|
|
horz_spacing => 4, |
75
|
|
|
|
|
|
|
vert_spacing => 6, |
76
|
|
|
|
|
|
|
icon_height => 12, |
77
|
|
|
|
|
|
|
icon_width => 40, |
78
|
|
|
|
|
|
|
text_width => 72, |
79
|
|
|
|
|
|
|
text_font => { |
80
|
|
|
|
|
|
|
size => 10, |
81
|
|
|
|
|
|
|
color => 0, |
82
|
|
|
|
|
|
|
font => 'Courier', |
83
|
|
|
|
|
|
|
}, |
84
|
|
|
|
|
|
|
title => 'My Key', |
85
|
|
|
|
|
|
|
title_font => { |
86
|
|
|
|
|
|
|
color => [1, 0, 0], |
87
|
|
|
|
|
|
|
font => 'Times-Bold', |
88
|
|
|
|
|
|
|
size => 14, |
89
|
|
|
|
|
|
|
}, |
90
|
|
|
|
|
|
|
}; |
91
|
|
|
|
|
|
|
|
92
|
|
|
|
|
|
|
=head1 DESCRIPTION |
93
|
|
|
|
|
|
|
|
94
|
|
|
|
|
|
|
This module is designed as a supporting part of the PostScript::Graph suite. For top level modules that output |
95
|
|
|
|
|
|
|
something useful, see |
96
|
|
|
|
|
|
|
|
97
|
|
|
|
|
|
|
PostScript::Graph::Bar |
98
|
|
|
|
|
|
|
PostScript::Graph::Stock |
99
|
|
|
|
|
|
|
PostScript::Graph::XY |
100
|
|
|
|
|
|
|
|
101
|
|
|
|
|
|
|
A companion object to PostScript::Graph::Paper, this is used by any module that requies a Key for a graph. The |
102
|
|
|
|
|
|
|
size and shape is automatically adjusted to accomodate the number of items in the space available, adding more |
103
|
|
|
|
|
|
|
columns if there is not enough vertical space. The textual description now wraps onto multiple lines if needed. |
104
|
|
|
|
|
|
|
|
105
|
|
|
|
|
|
|
The opportunity is provided to draw an icon with each key item using the same code and style as is used on the |
106
|
|
|
|
|
|
|
graph. This is accomplished in distinct phases. |
107
|
|
|
|
|
|
|
|
108
|
|
|
|
|
|
|
=over 4 |
109
|
|
|
|
|
|
|
|
110
|
|
|
|
|
|
|
=item * |
111
|
|
|
|
|
|
|
|
112
|
|
|
|
|
|
|
The total space available is typically obtained from PostScript::File, but must be known so that |
113
|
|
|
|
|
|
|
PostScript::Graph::Key and PostScript::Graph::Paper can divide it between them. |
114
|
|
|
|
|
|
|
|
115
|
|
|
|
|
|
|
=item * |
116
|
|
|
|
|
|
|
|
117
|
|
|
|
|
|
|
All the graph lines must exist before the graph is drawn. PostScript::Graph::Paper needs to calculate the axes |
118
|
|
|
|
|
|
|
and suggest the height available for the Key which will be placed to the right of the graph. |
119
|
|
|
|
|
|
|
|
120
|
|
|
|
|
|
|
=item * |
121
|
|
|
|
|
|
|
|
122
|
|
|
|
|
|
|
The PostScript::Graph::Key constructor calculates the outer box dimensions from the items required and the space |
123
|
|
|
|
|
|
|
available. In particular the number of text rows per item must be worked out and how many columns will be needed. |
124
|
|
|
|
|
|
|
|
125
|
|
|
|
|
|
|
=item * |
126
|
|
|
|
|
|
|
|
127
|
|
|
|
|
|
|
The key width can then be passed to the PostScript::Graph::Paper constructor, which works out the space available |
128
|
|
|
|
|
|
|
for the graph and usually draws the background grid. |
129
|
|
|
|
|
|
|
|
130
|
|
|
|
|
|
|
=item * |
131
|
|
|
|
|
|
|
|
132
|
|
|
|
|
|
|
B can then be called to draw the outer box and heading next to the grid. |
133
|
|
|
|
|
|
|
|
134
|
|
|
|
|
|
|
=item * |
135
|
|
|
|
|
|
|
|
136
|
|
|
|
|
|
|
For each graph line, the line can be drawn on the paper and its icons drawn in the key box at the same time, using |
137
|
|
|
|
|
|
|
the same PostScript::Graph::Style settings. |
138
|
|
|
|
|
|
|
|
139
|
|
|
|
|
|
|
=back |
140
|
|
|
|
|
|
|
|
141
|
|
|
|
|
|
|
|
142
|
|
|
|
|
|
|
=head1 CONSTRUCTOR |
143
|
|
|
|
|
|
|
|
144
|
|
|
|
|
|
|
=cut |
145
|
|
|
|
|
|
|
|
146
|
|
|
|
|
|
|
sub new { |
147
|
13
|
|
|
13
|
1
|
1460
|
my $class = shift; |
148
|
13
|
|
|
|
|
50
|
my $opt = {}; |
149
|
13
|
100
|
33
|
|
|
62
|
if (@_ == 1) { |
|
|
50
|
|
|
|
|
|
150
|
12
|
|
|
|
|
29
|
$opt = $_[0]; |
151
|
|
|
|
|
|
|
} elsif (@_ == 2 and $_[0]+0 > 0) { |
152
|
0
|
|
|
|
|
0
|
($opt->{max_height}, $opt->{num_items}) = @_; |
153
|
|
|
|
|
|
|
} else { |
154
|
1
|
|
|
|
|
6
|
%$opt = @_; |
155
|
|
|
|
|
|
|
} |
156
|
|
|
|
|
|
|
|
157
|
13
|
|
|
|
|
40
|
my $o = {}; |
158
|
13
|
|
|
|
|
46
|
bless( $o, $class ); |
159
|
|
|
|
|
|
|
|
160
|
13
|
50
|
|
|
|
160
|
$o->{gp} = defined($opt->{graph_paper}) ? $opt->{graph_paper} : undef; |
161
|
13
|
50
|
|
|
|
78
|
my $ps = defined($o->{gp}) ? $o->{gp}->file() : undef; |
162
|
13
|
50
|
|
|
|
61
|
$o->{ps} = defined($opt->{file}) ? $opt->{file} : $ps; |
163
|
|
|
|
|
|
|
|
164
|
13
|
50
|
|
|
|
61
|
$o->{title} = defined($opt->{title}) ? $opt->{title} : "Key"; |
165
|
13
|
50
|
|
|
|
109
|
$o->{hcolor} = defined($opt->{title_font}{color}) ? $opt->{title_font}{color} : 0; |
166
|
13
|
50
|
|
|
|
64
|
$o->{hfont} = defined($opt->{title_font}{font}) ? $opt->{title_font}{font} : 'Helvetica-Bold'; |
167
|
13
|
50
|
|
|
|
89
|
$o->{hsize} = defined($opt->{title_font}{size}) ? $opt->{title_font}{size} : 12; |
168
|
13
|
50
|
|
|
|
97
|
$o->{tcolor} = defined($opt->{text_font}{color}) ? $opt->{text_font}{color} : 0; |
169
|
13
|
50
|
|
|
|
83
|
$o->{tfont} = defined($opt->{text_font}{font}) ? $opt->{text_font}{font} : 'Helvetica'; |
170
|
13
|
50
|
|
|
|
66
|
$o->{tsize} = defined($opt->{text_font}{size}) ? $opt->{text_font}{size} : 10; |
171
|
13
|
50
|
|
|
|
72
|
$o->{ratio} = defined($opt->{glyph_ratio}) ? $opt->{glyph_ratio} : 0.44; |
172
|
13
|
100
|
|
|
|
80
|
$o->{twidth} = defined($opt->{text_width}) ? $opt->{text_width} : $o->{tsize} * 4; |
173
|
13
|
100
|
|
|
|
74
|
$o->{fcolor} = defined($opt->{background}) ? $opt->{background} : 1; |
174
|
13
|
50
|
|
|
|
61
|
$o->{ocolor} = defined($opt->{outline_color}) ? $opt->{outline_color} : 0; |
175
|
13
|
50
|
|
|
|
77
|
$o->{owidth} = defined($opt->{outline_width}) ? $opt->{outline_width} : 0.75; |
176
|
|
|
|
|
|
|
|
177
|
13
|
|
|
|
|
61
|
$o->{items} = $opt->{item_labels}; # used by wrapped_items() |
178
|
13
|
|
|
|
|
75
|
$o->{wrapchrs} = $o->{twidth}/($o->{tsize}*$o->{ratio}); # used by wrapped_items() |
179
|
13
|
50
|
|
|
|
70
|
if (defined $o->{items}) { |
180
|
0
|
|
|
|
|
0
|
$o->{nlines} = $o->wrapped_items; |
181
|
|
|
|
|
|
|
} else { |
182
|
13
|
50
|
|
|
|
1027
|
croak "Option 'num_items' must be given\nStopped" unless $opt->{num_items}; |
183
|
13
|
|
|
|
|
94
|
$o->{nlines} = [ (1) x $opt->{num_items} ]; |
184
|
|
|
|
|
|
|
} |
185
|
|
|
|
|
|
|
|
186
|
13
|
100
|
|
|
|
72
|
$o->{spc} = defined($opt->{spacing}) ? $opt->{spacing} : 4; |
187
|
13
|
50
|
|
|
|
63
|
$o->{vspc} = defined($opt->{vert_spacing}) ? $opt->{vert_spacing} : $o->{spc}; |
188
|
13
|
50
|
|
|
|
69
|
$o->{hspc} = defined($opt->{horz_spacing}) ? $opt->{horz_spacing} : $o->{spc} * 2; |
189
|
13
|
100
|
|
|
|
85
|
$o->{dxicon} = defined($opt->{icon_width}) ? $opt->{icon_width} : $o->{tsize}; |
190
|
13
|
100
|
|
|
|
67
|
$o->{dyicon} = defined($opt->{icon_height}) ? $opt->{icon_height} : $o->{tsize}; |
191
|
|
|
|
|
|
|
|
192
|
13
|
|
|
|
|
98
|
$o->{dx} = $o->{hspc} + $o->{dxicon} + $o->{hspc} + $o->{twidth} + $o->{hspc}; |
193
|
13
|
100
|
|
|
|
83
|
$o->{dyicon} = ($o->{dyicon} > $o->{tsize} ? $o->{dyicon} : $o->{tsize}); # dyicon always >= tsize |
194
|
13
|
|
|
|
|
37
|
my $isize = $o->{dyicon} + 2 * $o->{vspc}; |
195
|
|
|
|
|
|
|
|
196
|
13
|
50
|
|
|
|
58
|
croak "Option 'max_height' must be given\nStopped" unless defined $opt->{max_height}; |
197
|
13
|
|
|
|
|
34
|
$o->{height} = $opt->{max_height}; |
198
|
13
|
|
|
|
|
61
|
$o->{tmargin} = $o->{hsize} + 3 * $o->{vspc}; |
199
|
13
|
|
|
|
|
34
|
my $margins = $o->{tmargin} + 2 * $o->{vspc}; |
200
|
13
|
|
|
|
|
41
|
my $height = $o->{height} - $margins; |
201
|
13
|
50
|
|
|
|
54
|
$height = 1 unless $height > 0; |
202
|
|
|
|
|
|
|
|
203
|
|
|
|
|
|
|
# distribute items amongst columns |
204
|
13
|
|
|
|
|
24
|
my $sofar = 0; |
205
|
13
|
|
|
|
|
23
|
my $column = 0; |
206
|
13
|
|
|
|
|
20
|
my $max = 0; |
207
|
13
|
|
|
|
|
25
|
my (@cols, @rowp, @rowh); |
208
|
13
|
|
|
|
|
30
|
for (my $i = 0; $i <= $#{$o->{nlines}}; $i++) { |
|
238
|
|
|
|
|
594
|
|
209
|
225
|
|
|
|
|
360
|
$rowp[$i] = $sofar; |
210
|
225
|
|
|
|
|
502
|
my $itemh = 2* $o->{vspc} + $o->{nlines}[$i] * ($o->{tsize} + $o->{vspc}); |
211
|
|
|
|
|
|
|
#warn "$i nlines=",$o->{nlines}[$i],", itemh=$itemh, rowp=",$rowp[$i],"\n"; |
212
|
225
|
|
|
|
|
251
|
$sofar += $itemh; |
213
|
225
|
100
|
|
|
|
1432
|
if ($sofar >= $height) { |
214
|
6
|
|
|
|
|
10
|
$sofar -= $itemh; |
215
|
6
|
50
|
|
|
|
694
|
$max = $sofar if $sofar > $max; |
216
|
6
|
|
|
|
|
10
|
$column++; |
217
|
6
|
|
|
|
|
10
|
$rowp[$i] = 0; |
218
|
6
|
|
|
|
|
10
|
$sofar = $itemh; |
219
|
|
|
|
|
|
|
} |
220
|
225
|
|
|
|
|
314
|
$cols[$i] = $column; |
221
|
225
|
100
|
|
|
|
380
|
if ($isize > $itemh) { |
222
|
3
|
|
|
|
|
9
|
$rowh[$i] = $isize; |
223
|
3
|
|
|
|
|
5
|
$sofar += ($isize - $itemh); |
224
|
|
|
|
|
|
|
} else { |
225
|
222
|
|
|
|
|
360
|
$rowh[$i] = $itemh; |
226
|
|
|
|
|
|
|
} |
227
|
225
|
100
|
|
|
|
640
|
$max = $sofar if $sofar > $max; |
228
|
|
|
|
|
|
|
#warn "$i column=$column, diff=$diff ($isize - $itemh), sofar=$sofar, max=$max\n" |
229
|
|
|
|
|
|
|
} |
230
|
|
|
|
|
|
|
|
231
|
|
|
|
|
|
|
#warn "max=$max, column=$column\n"; |
232
|
13
|
|
|
|
|
46
|
$o->{height} = $margins + $max; |
233
|
13
|
|
|
|
|
54
|
$o->{start} = $o->{height} - $o->{tmargin} - 4 * $o->{vspc}; |
234
|
13
|
|
|
|
|
43
|
$o->{width} = $o->{hspc} + ($column+1) * $o->{dx}; |
235
|
|
|
|
|
|
|
|
236
|
|
|
|
|
|
|
# for add_key_item() |
237
|
13
|
|
|
|
|
38
|
$o->{cols} = \@cols; # the column number for each item |
238
|
13
|
|
|
|
|
74
|
$o->{rowp} = \@rowp; # offset from top of column to top of item |
239
|
13
|
|
|
|
|
36
|
$o->{current} = 0; # item to be shown |
240
|
|
|
|
|
|
|
|
241
|
13
|
|
|
|
|
92
|
return $o; |
242
|
|
|
|
|
|
|
} |
243
|
|
|
|
|
|
|
|
244
|
|
|
|
|
|
|
=head2 new( [options] ) |
245
|
|
|
|
|
|
|
|
246
|
|
|
|
|
|
|
C should be either a list of hash keys and values or a hash reference. Unlike other objects in this |
247
|
|
|
|
|
|
|
series, a couple of these (C and C) are required. Another difference is that all options |
248
|
|
|
|
|
|
|
occur within a flat space - there are no sub-groups. This is because it is expected that this module will only be |
249
|
|
|
|
|
|
|
used as part of another Chart object, with these options passed as a group through that constructor. |
250
|
|
|
|
|
|
|
|
251
|
|
|
|
|
|
|
All values are in PostScript native units (1/72 inch). |
252
|
|
|
|
|
|
|
|
253
|
|
|
|
|
|
|
If C is an integer, the textual description will have one line per item. Where long descriptions are |
254
|
|
|
|
|
|
|
needed, C can be given instead. It should refer to a list of the strings to be placed next to each |
255
|
|
|
|
|
|
|
key icon. The constructor calculates the number of rows needed when this text is wrapped within C. |
256
|
|
|
|
|
|
|
The text is only actually wrapped when B is called. |
257
|
|
|
|
|
|
|
|
258
|
|
|
|
|
|
|
=head3 background |
259
|
|
|
|
|
|
|
|
260
|
|
|
|
|
|
|
Background colour for the key rectangle. (Default: 1) |
261
|
|
|
|
|
|
|
|
262
|
|
|
|
|
|
|
=head3 file |
263
|
|
|
|
|
|
|
|
264
|
|
|
|
|
|
|
If C is not given, this probably should be. It is the PostScript::File object that holds the graph |
265
|
|
|
|
|
|
|
being constructed. It is possible to specify this later, when calling B. (No default) |
266
|
|
|
|
|
|
|
|
267
|
|
|
|
|
|
|
=head3 glyph_ratio |
268
|
|
|
|
|
|
|
|
269
|
|
|
|
|
|
|
A kludge provided to fine-tune how well the text labels fit into the box. It is not possible to get the actual |
270
|
|
|
|
|
|
|
width of proportional font strings from PostScript, so this gives the opportunity to guess an 'average width' for |
271
|
|
|
|
|
|
|
particular fonts. (Default: 0.5) |
272
|
|
|
|
|
|
|
|
273
|
|
|
|
|
|
|
=head3 graph_paper |
274
|
|
|
|
|
|
|
|
275
|
|
|
|
|
|
|
If given, this should be a PostScript::Graph::Paper object. A GraphKey needs to know which GraphPaper |
276
|
|
|
|
|
|
|
has allocated space for it. But the GraphPaper need the GraphKey to have already worked out how much space it |
277
|
|
|
|
|
|
|
needs. The best solution is to create the GraphKey before the GraphPaper, then pass the latter to B. |
278
|
|
|
|
|
|
|
(No default) |
279
|
|
|
|
|
|
|
|
280
|
|
|
|
|
|
|
=head3 horizontal_spacing |
281
|
|
|
|
|
|
|
|
282
|
|
|
|
|
|
|
The gaps between edges, icon and text. (Defaults to C) |
283
|
|
|
|
|
|
|
|
284
|
|
|
|
|
|
|
=head3 icon_height |
285
|
|
|
|
|
|
|
|
286
|
|
|
|
|
|
|
Vertical space for each icon. This will never be smaller than the height of the text. (Defaults to C) |
287
|
|
|
|
|
|
|
|
288
|
|
|
|
|
|
|
=head3 icon_width |
289
|
|
|
|
|
|
|
|
290
|
|
|
|
|
|
|
Amount of horizontal space to allow for the icon to the left of each label. (Defaults to C) |
291
|
|
|
|
|
|
|
|
292
|
|
|
|
|
|
|
=head3 item_labels |
293
|
|
|
|
|
|
|
|
294
|
|
|
|
|
|
|
As an alternative to specifying the number of items (which must be single lines of text), this takes an array ref |
295
|
|
|
|
|
|
|
pointing to a list of all the key labels that will later be added. The same wrapping algorithm is applied to |
296
|
|
|
|
|
|
|
both. The box dimensions are calculated from these, but the actual text printed should be passed seperately to |
297
|
|
|
|
|
|
|
B. |
298
|
|
|
|
|
|
|
|
299
|
|
|
|
|
|
|
=head3 max_height |
300
|
|
|
|
|
|
|
|
301
|
|
|
|
|
|
|
The vertical space available for the key rectangle. GraphKey tries to fit as many items as possible within this |
302
|
|
|
|
|
|
|
before adding another column. Required - there is no default. |
303
|
|
|
|
|
|
|
|
304
|
|
|
|
|
|
|
=head3 num_items |
305
|
|
|
|
|
|
|
|
306
|
|
|
|
|
|
|
The number of items that will be placed in the key. Required unless C is given. |
307
|
|
|
|
|
|
|
|
308
|
|
|
|
|
|
|
=head3 outline_color |
309
|
|
|
|
|
|
|
|
310
|
|
|
|
|
|
|
Colour of the box's outline. (Default: 0) |
311
|
|
|
|
|
|
|
|
312
|
|
|
|
|
|
|
=head3 outline_width |
313
|
|
|
|
|
|
|
|
314
|
|
|
|
|
|
|
Width of the box's outline. (Default: 0.75) |
315
|
|
|
|
|
|
|
|
316
|
|
|
|
|
|
|
=head3 spacing |
317
|
|
|
|
|
|
|
|
318
|
|
|
|
|
|
|
A larger value gives a less crowded feel, reduce it if you are short of space. Think printing leading. (Default: 4) |
319
|
|
|
|
|
|
|
|
320
|
|
|
|
|
|
|
=head3 text_color |
321
|
|
|
|
|
|
|
|
322
|
|
|
|
|
|
|
Colour of the text used in the body of the key. (Default: 0) |
323
|
|
|
|
|
|
|
|
324
|
|
|
|
|
|
|
=head3 text_font |
325
|
|
|
|
|
|
|
|
326
|
|
|
|
|
|
|
Font used for the key body text. (Default: "Helvetica") |
327
|
|
|
|
|
|
|
|
328
|
|
|
|
|
|
|
=head3 text_size |
329
|
|
|
|
|
|
|
|
330
|
|
|
|
|
|
|
Size of the font used for the key body text. (Default: 10) |
331
|
|
|
|
|
|
|
|
332
|
|
|
|
|
|
|
=head3 text_width |
333
|
|
|
|
|
|
|
|
334
|
|
|
|
|
|
|
Amount of room allowed for the text label on each key item. (Defaults to four times the font size) |
335
|
|
|
|
|
|
|
|
336
|
|
|
|
|
|
|
=head3 title |
337
|
|
|
|
|
|
|
|
338
|
|
|
|
|
|
|
The heading at the top of the key rectangle. (Default: "Key") |
339
|
|
|
|
|
|
|
|
340
|
|
|
|
|
|
|
=head3 title_color |
341
|
|
|
|
|
|
|
|
342
|
|
|
|
|
|
|
Colour of the key heading. (Default: 0) |
343
|
|
|
|
|
|
|
|
344
|
|
|
|
|
|
|
=head3 title_font |
345
|
|
|
|
|
|
|
|
346
|
|
|
|
|
|
|
The font used for the heading. (Default: "Helvetica-Bold") |
347
|
|
|
|
|
|
|
|
348
|
|
|
|
|
|
|
=head3 title_size |
349
|
|
|
|
|
|
|
|
350
|
|
|
|
|
|
|
Size of the font used for the heading. (Default: 12) |
351
|
|
|
|
|
|
|
|
352
|
|
|
|
|
|
|
=head3 vertical_spacing |
353
|
|
|
|
|
|
|
|
354
|
|
|
|
|
|
|
The gap between key items. (Defaults to C) |
355
|
|
|
|
|
|
|
|
356
|
|
|
|
|
|
|
=head1 OBJECT METHODS |
357
|
|
|
|
|
|
|
|
358
|
|
|
|
|
|
|
=cut |
359
|
|
|
|
|
|
|
|
360
|
|
|
|
|
|
|
sub width { |
361
|
13
|
|
|
13
|
1
|
303
|
return shift()->{width}; |
362
|
|
|
|
|
|
|
} |
363
|
|
|
|
|
|
|
|
364
|
|
|
|
|
|
|
=head2 width() |
365
|
|
|
|
|
|
|
|
366
|
|
|
|
|
|
|
Return the width required for the key rectangle. |
367
|
|
|
|
|
|
|
|
368
|
|
|
|
|
|
|
=cut |
369
|
|
|
|
|
|
|
|
370
|
|
|
|
|
|
|
sub height { |
371
|
0
|
|
|
0
|
1
|
0
|
return shift()->{height}; |
372
|
|
|
|
|
|
|
} |
373
|
|
|
|
|
|
|
|
374
|
|
|
|
|
|
|
=head2 height() |
375
|
|
|
|
|
|
|
|
376
|
|
|
|
|
|
|
Return the height required for the key rectangle. |
377
|
|
|
|
|
|
|
|
378
|
|
|
|
|
|
|
=cut |
379
|
|
|
|
|
|
|
|
380
|
|
|
|
|
|
|
sub build_key { |
381
|
13
|
|
|
13
|
1
|
330
|
my ($o, $gp) = @_; |
382
|
13
|
50
|
|
|
|
90
|
if (defined $gp) { |
383
|
13
|
|
|
|
|
45
|
$o->{gp} = $gp; |
384
|
13
|
|
|
|
|
97
|
$o->{ps} = $gp->file(); |
385
|
|
|
|
|
|
|
} |
386
|
13
|
50
|
|
|
|
100
|
die "No PostScript::Graph::Paper object\nStopped" unless (ref($o->{gp}) eq "PostScript::Graph::Paper"); |
387
|
|
|
|
|
|
|
|
388
|
13
|
|
|
|
|
97
|
my ($kx0, $ky0, $kx1, $ky1) = $o->{gp}->key_area(); |
389
|
13
|
|
|
|
|
70
|
my $offset = ($ky1 - $ky0 - $o->{height})/2; |
390
|
13
|
|
|
|
|
40
|
$ky0 += $offset; |
391
|
13
|
|
|
|
|
33
|
$ky1 = $ky0 + $o->{height}; |
392
|
13
|
|
|
|
|
87
|
my $textc = str($o->{tcolor}); |
393
|
13
|
|
|
|
|
131
|
my $headc = str($o->{hcolor}); |
394
|
13
|
|
|
|
|
111
|
my $outlinec = str($o->{ocolor}); |
395
|
13
|
|
|
|
|
108
|
my $fillc = str($o->{fcolor}); |
396
|
|
|
|
|
|
|
|
397
|
13
|
|
|
|
|
581
|
$o->{ps}->add_to_page( <
|
398
|
|
|
|
|
|
|
graphkeydict begin |
399
|
|
|
|
|
|
|
/kx0 $kx0 def |
400
|
|
|
|
|
|
|
/ky0 $ky0 def |
401
|
|
|
|
|
|
|
/kx1 $kx1 def |
402
|
|
|
|
|
|
|
/ky1 $ky1 def |
403
|
|
|
|
|
|
|
/kvspc $o->{vspc} def |
404
|
|
|
|
|
|
|
/khspc $o->{hspc} def |
405
|
|
|
|
|
|
|
/kdxicon $o->{dxicon} def |
406
|
|
|
|
|
|
|
/kdyicon $o->{dyicon} def |
407
|
|
|
|
|
|
|
/kdxtext $o->{twidth} def |
408
|
|
|
|
|
|
|
/kdytext $o->{tsize} def |
409
|
|
|
|
|
|
|
/kfont /$o->{tfont} def |
410
|
|
|
|
|
|
|
/ksize $o->{tsize} def |
411
|
|
|
|
|
|
|
/kcol $textc def |
412
|
|
|
|
|
|
|
($o->{title}) /$o->{hfont} $o->{hsize} $headc $o->{owidth} $outlinec $fillc keybox |
413
|
|
|
|
|
|
|
end |
414
|
|
|
|
|
|
|
END_CODE |
415
|
|
|
|
|
|
|
|
416
|
13
|
|
|
|
|
9575
|
PostScript::Graph::Key->ps_functions($o->{ps}); |
417
|
|
|
|
|
|
|
} |
418
|
|
|
|
|
|
|
|
419
|
|
|
|
|
|
|
=head2 build_key( [graph_paper] ) |
420
|
|
|
|
|
|
|
|
421
|
|
|
|
|
|
|
This is where the position of the key area is fixed and the outline and heading are drawn. It must be called |
422
|
|
|
|
|
|
|
before B. |
423
|
|
|
|
|
|
|
|
424
|
|
|
|
|
|
|
=cut |
425
|
|
|
|
|
|
|
|
426
|
|
|
|
|
|
|
sub add_key_item { |
427
|
220
|
|
|
220
|
1
|
486
|
my ($o, $label, $code, $ps) = @_; |
428
|
|
|
|
|
|
|
#warn "add_key_item($label)\n"; |
429
|
220
|
50
|
|
|
|
570
|
$label = "" unless (defined $label); |
430
|
220
|
50
|
|
|
|
446
|
$code = "" unless (defined $code); |
431
|
220
|
50
|
|
|
|
473
|
$o->{ps} = $ps if (defined $ps); |
432
|
220
|
50
|
|
|
|
702
|
die "No PostScript::File object to write to\nStopped" unless (ref($o->{ps}) eq "PostScript::File"); |
433
|
|
|
|
|
|
|
|
434
|
220
|
50
|
|
|
|
885
|
my @lines = $o->{items} ? $o->split_lines(ucfirst $label) : ucfirst($label); |
435
|
220
|
|
|
|
|
564
|
my $tsize = $o->{tsize} + $o->{vspc}; |
436
|
|
|
|
|
|
|
|
437
|
220
|
|
|
|
|
423
|
my $n = $o->{current}; |
438
|
220
|
|
100
|
|
|
868
|
my $col = $o->{cols}[$n] || 0; |
439
|
220
|
|
100
|
|
|
685
|
my $row = $o->{rowp}[$n] || 0; |
440
|
220
|
|
|
|
|
392
|
my $kdx = $col * $o->{dx}; |
441
|
220
|
|
|
|
|
412
|
my $kdy = $o->{start} - $row; |
442
|
|
|
|
|
|
|
# |
443
|
|
|
|
|
|
|
# TODO Centre the icon box within the text entry. |
444
|
|
|
|
|
|
|
# $o->{rowh} holds the necessary height, but it needs putting into PostScript |
445
|
|
|
|
|
|
|
# |
446
|
|
|
|
|
|
|
|
447
|
|
|
|
|
|
|
# The gstyledict kludge involving tppdy/tppdx is to ensure the point is shown centrally in the icon. |
448
|
|
|
|
|
|
|
# This may not be what is always wanted, but was put in to accomodate arrows (without lines) |
449
|
220
|
|
|
|
|
1692
|
$o->{ps}->add_to_page( <
|
450
|
|
|
|
|
|
|
graphkeydict begin |
451
|
|
|
|
|
|
|
/kdx $kdx def |
452
|
|
|
|
|
|
|
/kdy $kdy def |
453
|
|
|
|
|
|
|
newpath |
454
|
|
|
|
|
|
|
movetoicon |
455
|
|
|
|
|
|
|
gstyledict begin |
456
|
|
|
|
|
|
|
/tppdy ppdy def /ppdy 0 def |
457
|
|
|
|
|
|
|
/tppdx ppdx def /ppdx 0 def |
458
|
|
|
|
|
|
|
$code |
459
|
|
|
|
|
|
|
stroke |
460
|
|
|
|
|
|
|
/ppdy tppdy def |
461
|
|
|
|
|
|
|
/ppdx tppdx def |
462
|
|
|
|
|
|
|
end |
463
|
|
|
|
|
|
|
movetotext |
464
|
|
|
|
|
|
|
END_ITEM |
465
|
220
|
|
|
|
|
249336
|
foreach my $line (@lines) { |
466
|
220
|
|
|
|
|
514
|
$line =~ s/[(]/\\\(/g; |
467
|
220
|
|
|
|
|
330
|
$line =~ s/[)]/\\\)/g; |
468
|
220
|
|
|
|
|
1184
|
$o->{ps}->add_to_page("($line) show $tsize movedown\n"); |
469
|
|
|
|
|
|
|
} |
470
|
220
|
|
|
|
|
14315
|
$o->{current}++; |
471
|
220
|
|
|
|
|
764
|
$o->{ps}->add_to_page("end\n"); |
472
|
|
|
|
|
|
|
} |
473
|
|
|
|
|
|
|
|
474
|
|
|
|
|
|
|
=head2 add_key_item( label, code [, psfile] ) |
475
|
|
|
|
|
|
|
|
476
|
|
|
|
|
|
|
=over 8 |
477
|
|
|
|
|
|
|
|
478
|
|
|
|
|
|
|
=item label |
479
|
|
|
|
|
|
|
|
480
|
|
|
|
|
|
|
The text for this key item |
481
|
|
|
|
|
|
|
|
482
|
|
|
|
|
|
|
=item code |
483
|
|
|
|
|
|
|
|
484
|
|
|
|
|
|
|
Postscript code which draws the icon. |
485
|
|
|
|
|
|
|
|
486
|
|
|
|
|
|
|
=item psfile |
487
|
|
|
|
|
|
|
|
488
|
|
|
|
|
|
|
The PostScript::File object the code will be written to. If it was not given to B as either C or |
489
|
|
|
|
|
|
|
C, it must be given here. |
490
|
|
|
|
|
|
|
|
491
|
|
|
|
|
|
|
=back |
492
|
|
|
|
|
|
|
|
493
|
|
|
|
|
|
|
A number of postscript variables are provided to help with the drawing. See for the full list. |
494
|
|
|
|
|
|
|
|
495
|
|
|
|
|
|
|
kix0 left edge of icon area |
496
|
|
|
|
|
|
|
kiy0 bottom edge |
497
|
|
|
|
|
|
|
kix1 right edge |
498
|
|
|
|
|
|
|
kiy1 top edge |
499
|
|
|
|
|
|
|
|
500
|
|
|
|
|
|
|
Your code should use its own dictionary and can refer to dictionaries you have begun but not yet ended at this |
501
|
|
|
|
|
|
|
point. For example, here is the code used by PostScript::Graph::XY. It calculates the mid point of a diagonal line |
502
|
|
|
|
|
|
|
and draws it using the same functions used for the main chart. C etc. are provided by |
503
|
|
|
|
|
|
|
PostScript::Graph::Style to change style settings, C just expects 'x y' and C expects an |
504
|
|
|
|
|
|
|
array of coordinates followed by the greatest index allowed. |
505
|
|
|
|
|
|
|
|
506
|
|
|
|
|
|
|
|
507
|
|
|
|
|
|
|
$graphkey->add_key_item( $line->{ytitle}, |
508
|
|
|
|
|
|
|
<
|
509
|
|
|
|
|
|
|
2 dict begin |
510
|
|
|
|
|
|
|
/kpx kix0 kix1 add 2 div def |
511
|
|
|
|
|
|
|
/kpy kiy0 kiy1 add 2 div def |
512
|
|
|
|
|
|
|
point_outer |
513
|
|
|
|
|
|
|
kpx kpy draw1point |
514
|
|
|
|
|
|
|
[ kix0 kiy0 kix1 kiy1 ] 3 |
515
|
|
|
|
|
|
|
2 copy |
516
|
|
|
|
|
|
|
line_outer drawxyline |
517
|
|
|
|
|
|
|
line_inner drawxyline |
518
|
|
|
|
|
|
|
point_inner |
519
|
|
|
|
|
|
|
kpx kpy draw1point |
520
|
|
|
|
|
|
|
end |
521
|
|
|
|
|
|
|
END_KEY_ITEM |
522
|
|
|
|
|
|
|
|
523
|
|
|
|
|
|
|
=cut |
524
|
|
|
|
|
|
|
|
525
|
|
|
|
|
|
|
sub wrapped_items { |
526
|
0
|
|
|
0
|
0
|
0
|
my $o = shift; |
527
|
0
|
0
|
|
|
|
0
|
my @items = @_ ? @_ : @{$o->{items}}; |
|
0
|
|
|
|
|
0
|
|
528
|
0
|
|
|
|
|
0
|
my @split; |
529
|
0
|
|
|
|
|
0
|
my $nchars = $o->{twidth}/($o->{tsize}*$o->{ratio}); |
530
|
0
|
|
|
|
|
0
|
foreach my $text (@items) { |
531
|
0
|
|
|
|
|
0
|
push @split, scalar $o->split_lines($text, $nchars); |
532
|
|
|
|
|
|
|
} |
533
|
0
|
|
|
|
|
0
|
return \@split; |
534
|
|
|
|
|
|
|
} |
535
|
|
|
|
|
|
|
# Fit labels in $o->{items} array so they fit within $o->{twidth} |
536
|
|
|
|
|
|
|
# Returning number of lines required in total. |
537
|
|
|
|
|
|
|
|
538
|
|
|
|
|
|
|
|
539
|
|
|
|
|
|
|
sub split_lines { |
540
|
0
|
|
|
0
|
0
|
0
|
my ($o, $text, $nchars) = @_; |
541
|
0
|
0
|
|
|
|
0
|
$nchars = $o->{wrapchrs} unless defined $nchars; |
542
|
0
|
|
|
|
|
0
|
my @split_text; |
543
|
0
|
|
|
|
|
0
|
while ($text) { |
544
|
0
|
|
|
|
|
0
|
my ($left, $right); |
545
|
0
|
0
|
|
|
|
0
|
if (length $text <= $nchars) { |
546
|
0
|
|
|
|
|
0
|
$left = $text; |
547
|
0
|
|
|
|
|
0
|
$right = ''; |
548
|
|
|
|
|
|
|
} else { |
549
|
0
|
|
|
|
|
0
|
$left = substr $text, 0, $nchars; |
550
|
0
|
|
|
|
|
0
|
$right = substr $text, $nchars; |
551
|
0
|
|
|
|
|
0
|
$left =~ s/\s+(\S*)$//; |
552
|
0
|
0
|
|
|
|
0
|
$right = $1 . $right if $1; |
553
|
|
|
|
|
|
|
} |
554
|
0
|
|
|
|
|
0
|
push @split_text, $left; |
555
|
0
|
|
|
|
|
0
|
$text = $right; |
556
|
|
|
|
|
|
|
} |
557
|
0
|
|
|
|
|
0
|
return @split_text; |
558
|
|
|
|
|
|
|
} |
559
|
|
|
|
|
|
|
|
560
|
|
|
|
|
|
|
sub sum { |
561
|
0
|
|
|
0
|
0
|
0
|
my $total = 0; |
562
|
0
|
|
|
|
|
0
|
foreach my $item (@_) { |
563
|
0
|
|
|
|
|
0
|
$total += $item; |
564
|
|
|
|
|
|
|
} |
565
|
0
|
|
|
|
|
0
|
return $total; |
566
|
|
|
|
|
|
|
} |
567
|
|
|
|
|
|
|
|
568
|
|
|
|
|
|
|
sub ps_functions { |
569
|
13
|
|
|
13
|
1
|
43
|
my ($class, $ps) = @_; |
570
|
13
|
|
|
|
|
37
|
my $name = "GraphKey"; |
571
|
13
|
50
|
|
|
|
83
|
$ps->add_function( $name, <has_function($name)); |
572
|
|
|
|
|
|
|
/graphkeydict 20 dict def |
573
|
|
|
|
|
|
|
graphkeydict begin |
574
|
|
|
|
|
|
|
% _ title tfont tsize tcol boxw boxc fillc => _ |
575
|
|
|
|
|
|
|
/keybox { |
576
|
|
|
|
|
|
|
gpaperdict begin |
577
|
|
|
|
|
|
|
graphkeydict begin |
578
|
|
|
|
|
|
|
newpath |
579
|
|
|
|
|
|
|
kx0 ky0 moveto |
580
|
|
|
|
|
|
|
kx1 ky0 lineto |
581
|
|
|
|
|
|
|
kx1 ky1 lineto |
582
|
|
|
|
|
|
|
kx0 ky1 lineto |
583
|
|
|
|
|
|
|
closepath |
584
|
|
|
|
|
|
|
gsave gpapercolor fill grestore |
585
|
|
|
|
|
|
|
gpapercolor |
586
|
|
|
|
|
|
|
setlinewidth |
587
|
|
|
|
|
|
|
[ ] 0 setdash |
588
|
|
|
|
|
|
|
stroke |
589
|
|
|
|
|
|
|
/tcol exch def |
590
|
|
|
|
|
|
|
/tsize exch def |
591
|
|
|
|
|
|
|
/tfont exch def |
592
|
|
|
|
|
|
|
tfont tsize tcol gpaperfont |
593
|
|
|
|
|
|
|
kx0 kx1 add 2 div |
594
|
|
|
|
|
|
|
ky1 tsize 1.2 mul sub |
595
|
|
|
|
|
|
|
centered |
596
|
|
|
|
|
|
|
end end |
597
|
|
|
|
|
|
|
} bind def |
598
|
|
|
|
|
|
|
|
599
|
|
|
|
|
|
|
% _ => _ |
600
|
|
|
|
|
|
|
/movetoicon { |
601
|
|
|
|
|
|
|
graphkeydict begin |
602
|
|
|
|
|
|
|
/kix0 kx0 kdx add khspc add def |
603
|
|
|
|
|
|
|
/kiy0 ky0 kdy add def |
604
|
|
|
|
|
|
|
/kix1 kix0 kdxicon add def |
605
|
|
|
|
|
|
|
/kiy1 kiy0 kdyicon add def |
606
|
|
|
|
|
|
|
kix0 kiy0 moveto |
607
|
|
|
|
|
|
|
end |
608
|
|
|
|
|
|
|
} bind def |
609
|
|
|
|
|
|
|
|
610
|
|
|
|
|
|
|
% _ => _ |
611
|
|
|
|
|
|
|
/movetotext { |
612
|
|
|
|
|
|
|
graphkeydict begin |
613
|
|
|
|
|
|
|
gpaperdict begin |
614
|
|
|
|
|
|
|
kfont ksize kcol gpaperfont |
615
|
|
|
|
|
|
|
end |
616
|
|
|
|
|
|
|
/ktx0 kx0 kdx add khspc add kdxicon add khspc add def |
617
|
|
|
|
|
|
|
/kty0 ky0 kdy add def |
618
|
|
|
|
|
|
|
/ktx1 ktx0 kdxtext add def |
619
|
|
|
|
|
|
|
/kty1 kty0 kdyicon add def |
620
|
|
|
|
|
|
|
ktx0 kty0 kty1 add 2 div ksize 2 div sub kvspc 2 div add moveto |
621
|
|
|
|
|
|
|
end |
622
|
|
|
|
|
|
|
} bind def |
623
|
|
|
|
|
|
|
|
624
|
|
|
|
|
|
|
% tsize => _ |
625
|
|
|
|
|
|
|
/movedown { |
626
|
|
|
|
|
|
|
graphkeydict begin |
627
|
|
|
|
|
|
|
/kty0 1 index kty0 exch sub def |
628
|
|
|
|
|
|
|
/kty0 exch kty0 exch sub def |
629
|
|
|
|
|
|
|
ktx0 kty0 kty1 add 2 div ksize 2 div sub kvspc 2 div add moveto |
630
|
|
|
|
|
|
|
end |
631
|
|
|
|
|
|
|
} bind def |
632
|
|
|
|
|
|
|
end |
633
|
|
|
|
|
|
|
END_FUNCTIONS |
634
|
|
|
|
|
|
|
} |
635
|
|
|
|
|
|
|
|
636
|
|
|
|
|
|
|
=head3 ps_functions( ps ) |
637
|
|
|
|
|
|
|
|
638
|
|
|
|
|
|
|
Normally, this is called in B, but is provided as a class function so the dictionary may be still |
639
|
|
|
|
|
|
|
available even when a Key object is not required. |
640
|
|
|
|
|
|
|
|
641
|
|
|
|
|
|
|
=cut |
642
|
|
|
|
|
|
|
|
643
|
|
|
|
|
|
|
=head1 POSTSCRIPT CODE |
644
|
|
|
|
|
|
|
|
645
|
|
|
|
|
|
|
None of the postscript functions defined in this module would have application outside it. However, the following |
646
|
|
|
|
|
|
|
variables are defined within the C dictionary and may be of some use. |
647
|
|
|
|
|
|
|
|
648
|
|
|
|
|
|
|
kix0 left edge of icon area |
649
|
|
|
|
|
|
|
kiy0 bottom edge |
650
|
|
|
|
|
|
|
kix1 right edge |
651
|
|
|
|
|
|
|
kiy1 top edge |
652
|
|
|
|
|
|
|
kvspc vertical spacing |
653
|
|
|
|
|
|
|
khspc horizontal spacing |
654
|
|
|
|
|
|
|
kdxicon width of icon area |
655
|
|
|
|
|
|
|
kdyicon height of icon area |
656
|
|
|
|
|
|
|
kdxtext width of text area |
657
|
|
|
|
|
|
|
kdytext height of text area |
658
|
|
|
|
|
|
|
kfont font used for text |
659
|
|
|
|
|
|
|
ksize font size used |
660
|
|
|
|
|
|
|
kcol colour of font used |
661
|
|
|
|
|
|
|
|
662
|
|
|
|
|
|
|
=cut |
663
|
|
|
|
|
|
|
|
664
|
|
|
|
|
|
|
=head1 BUGS |
665
|
|
|
|
|
|
|
|
666
|
|
|
|
|
|
|
Too much space is allocated to wrapped text if accompanied by a large icon. |
667
|
|
|
|
|
|
|
|
668
|
|
|
|
|
|
|
=head1 AUTHOR |
669
|
|
|
|
|
|
|
|
670
|
|
|
|
|
|
|
Chris Willmot, chris@willmot.org.uk |
671
|
|
|
|
|
|
|
|
672
|
|
|
|
|
|
|
=head1 SEE ALSO |
673
|
|
|
|
|
|
|
|
674
|
|
|
|
|
|
|
L, L and L for the other modules in this suite. |
675
|
|
|
|
|
|
|
|
676
|
|
|
|
|
|
|
L, L and L for modules that use this one. |
677
|
|
|
|
|
|
|
|
678
|
|
|
|
|
|
|
=cut |
679
|
|
|
|
|
|
|
|
680
|
|
|
|
|
|
|
|
681
|
|
|
|
|
|
|
1; |