File Coverage

blib/lib/Spreadsheet/WriteExcel/Format.pm
Criterion Covered Total %
statement 178 276 64.4
branch 54 152 35.5
condition 17 41 41.4
subroutine 18 26 69.2
pod 0 16 0.0
total 267 511 52.2


line stmt bran cond sub pod time code
1             package Spreadsheet::WriteExcel::Format;
2              
3             ###############################################################################
4             #
5             # Format - A class for defining Excel formatting.
6             #
7             #
8             # Used in conjunction with Spreadsheet::WriteExcel
9             #
10             # Copyright 2000-2010, John McNamara, jmcnamara@cpan.org
11             #
12             # Documentation after __END__
13             #
14              
15 33     33   878 use Exporter;
  33         70  
  33         1340  
16 33     33   193 use strict;
  33         57  
  33         922  
17 33     33   191 use Carp;
  33         63  
  33         2366  
18              
19              
20              
21              
22              
23              
24 33     33   194 use vars qw($AUTOLOAD $VERSION @ISA);
  33         65  
  33         14658  
25             @ISA = qw(Exporter);
26              
27             $VERSION = '2.40';
28              
29             ###############################################################################
30             #
31             # new()
32             #
33             # Constructor
34             #
35             sub new {
36              
37 1653     1653 0 3105 my $class = shift;
38              
39 1653   100     42788 my $self = {
40             _xf_index => shift || 0,
41              
42             _type => 0,
43             _font_index => 0,
44             _font => 'Arial',
45             _size => 10,
46             _bold => 0x0190,
47             _italic => 0,
48             _color => 0x7FFF,
49             _underline => 0,
50             _font_strikeout => 0,
51             _font_outline => 0,
52             _font_shadow => 0,
53             _font_script => 0,
54             _font_family => 0,
55             _font_charset => 0,
56             _font_encoding => 0,
57              
58             _num_format => 0,
59             _num_format_enc => 0,
60              
61             _hidden => 0,
62             _locked => 1,
63              
64             _text_h_align => 0,
65             _text_wrap => 0,
66             _text_v_align => 2,
67             _text_justlast => 0,
68             _rotation => 0,
69              
70             _fg_color => 0x40,
71             _bg_color => 0x41,
72              
73             _pattern => 0,
74              
75             _bottom => 0,
76             _top => 0,
77             _left => 0,
78             _right => 0,
79              
80             _bottom_color => 0x40,
81             _top_color => 0x40,
82             _left_color => 0x40,
83             _right_color => 0x40,
84              
85             _indent => 0,
86             _shrink => 0,
87             _merge_range => 0,
88             _reading_order => 0,
89              
90             _diag_type => 0,
91             _diag_color => 0x40,
92             _diag_border => 0,
93              
94             _font_only => 0,
95              
96             # Temp code to prevent merged formats in non-merged cells.
97             _used_merge => 0,
98              
99             };
100              
101 1653         9649 bless $self, $class;
102              
103             # Set properties passed to Workbook::add_format()
104 1653 100       5679 $self->set_format_properties(@_) if @_;
105              
106 1653         5019 return $self;
107             }
108              
109              
110             ###############################################################################
111             #
112             # copy($format)
113             #
114             # Copy the attributes of another Spreadsheet::WriteExcel::Format object.
115             #
116             sub copy {
117 0     0 0 0 my $self = shift;
118 0         0 my $other = $_[0];
119              
120 0 0       0 return unless defined $other;
121 0 0       0 return unless (ref($self) eq ref($other));
122              
123             # Store the properties that we don't want overwritten.
124 0         0 my $xf = $self->{_xf_index};
125 0         0 my $merge_range = $self->{_merge_range};
126 0         0 my $used_merge = $self->{_used_merge};
127              
128 0         0 %$self = %$other; # Copy properties
129              
130             # Restore saved properties.
131 0         0 $self->{_xf_index} = $xf;
132 0         0 $self->{_merge_range} = $merge_range;
133 0         0 $self->{_used_merge} = $used_merge;
134             }
135              
136              
137             ###############################################################################
138             #
139             # get_xf($style)
140             #
141             # Generate an Excel BIFF XF record.
142             #
143             sub get_xf {
144              
145 33     33   41658 use integer; # Avoid << shift bug in Perl 5.6.0 on HP-UX
  33         390  
  33         275  
146              
147 1346     1346 0 1720 my $self = shift;
148              
149 1346         1572 my $record; # Record identifier
150             my $length; # Number of bytes to follow
151              
152 0         0 my $ifnt; # Index to FONT record
153 0         0 my $ifmt; # Index to FORMAT record
154 0         0 my $style; # Style and other options
155 0         0 my $align; # Alignment
156 0         0 my $indent; #
157 0         0 my $icv; # fg and bg pattern colors
158 0         0 my $border1; # Border line options
159 0         0 my $border2; # Border line options
160 0         0 my $border3; # Border line options
161              
162              
163             # Set the type of the XF record and some of the attributes.
164 1346 100       3369 if ($self->{_type} == 0xFFF5) {
165 1220         1648 $style = 0xFFF5;
166             }
167             else {
168 126         248 $style = $self->{_locked};
169 126         299 $style |= $self->{_hidden} << 1;
170             }
171              
172              
173             # Flags to indicate if attributes have been set.
174 1346         2240 my $atr_num = ($self->{_num_format} != 0);
175              
176 1346         1827 my $atr_fnt = ($self->{_font_index} != 0);
177              
178 1346 100 66     19374 my $atr_alc = ($self->{_text_h_align} != 0 ||
179             $self->{_text_v_align} != 2 ||
180             $self->{_shrink} != 0 ||
181             $self->{_merge_range} != 0 ||
182             $self->{_text_wrap} != 0 ||
183             $self->{_indent} != 0) ? 1 : 0;
184              
185 1346 50 33     14084 my $atr_bdr = ($self->{_bottom} != 0 ||
186             $self->{_top} != 0 ||
187             $self->{_left} != 0 ||
188             $self->{_right} != 0 ||
189             $self->{_diag_type} != 0) ? 1: 0;
190              
191 1346 50 33     8332 my $atr_pat = ($self->{_fg_color} != 0x40 ||
192             $self->{_bg_color} != 0x41 ||
193             $self->{_pattern} != 0x00) ? 1 : 0;
194              
195 1346 50 33     5330 my $atr_prot = ($self->{_hidden} != 0 ||
196             $self->{_locked} != 1) ? 1 : 0;
197              
198              
199             # Set attribute changed flags for the style formats.
200 1346 100 100     6009 if ($self->{_xf_index} != 0 and $self->{_type} == 0xFFF5) {
201              
202 1159 100       2296 if ($self->{_xf_index} >= 16) {
203 305         372 $atr_num = 0;
204 305         373 $atr_fnt = 1;
205             }
206             else {
207 854         2122 $atr_num = 1;
208 854         974 $atr_fnt = 0;
209             }
210              
211 1159         1352 $atr_alc = 1;
212 1159         7038 $atr_bdr = 1;
213 1159         1092 $atr_pat = 1;
214 1159         1285 $atr_prot = 1;
215             }
216              
217              
218             # Set a default diagonal border style if none was specified.
219 1346 50 33     6307 $self->{_diag_border} = 1 if !$self->{_diag_border} and $self->{_diag_type};
220              
221              
222             # Reset the default colours for the non-font properties
223 1346 50       2859 $self->{_fg_color} = 0x40 if $self->{_fg_color} == 0x7FFF;
224 1346 50       2673 $self->{_bg_color} = 0x41 if $self->{_bg_color} == 0x7FFF;
225 1346 50       2649 $self->{_bottom_color} = 0x40 if $self->{_bottom_color} == 0x7FFF;
226 1346 50       2757 $self->{_top_color} = 0x40 if $self->{_top_color} == 0x7FFF;
227 1346 50       2763 $self->{_left_color} = 0x40 if $self->{_left_color} == 0x7FFF;
228 1346 50       2734 $self->{_right_color} = 0x40 if $self->{_right_color} == 0x7FFF;
229 1346 50       2700 $self->{_diag_color} = 0x40 if $self->{_diag_color} == 0x7FFF;
230              
231              
232             # Zero the default border colour if the border has not been set.
233 1346 50       3256 $self->{_bottom_color} = 0 if $self->{_bottom} == 0;
234 1346 50       3058 $self->{_top_color} = 0 if $self->{_top} == 0;
235 1346 50       4004 $self->{_right_color} = 0 if $self->{_right} == 0;
236 1346 50       3329 $self->{_left_color} = 0 if $self->{_left} == 0;
237 1346 50       2705 $self->{_diag_color} = 0 if $self->{_diag_type} == 0;
238              
239              
240             # The following 2 logical statements take care of special cases in relation
241             # to cell colours and patterns:
242             # 1. For a solid fill (_pattern == 1) Excel reverses the role of foreground
243             # and background colours.
244             # 2. If the user specifies a foreground or background colour without a
245             # pattern they probably wanted a solid fill, so we fill in the defaults.
246             #
247 1346 50 33     6222 if ($self->{_pattern} <= 0x01 and
      33        
248             $self->{_bg_color} != 0x41 and
249             $self->{_fg_color} == 0x40 )
250             {
251 0         0 $self->{_fg_color} = $self->{_bg_color};
252 0         0 $self->{_bg_color} = 0x40;
253 0         0 $self->{_pattern} = 1;
254             }
255              
256 1346 50 33     8516 if ($self->{_pattern} <= 0x01 and
      33        
257             $self->{_bg_color} == 0x41 and
258             $self->{_fg_color} != 0x40 )
259             {
260 0         0 $self->{_bg_color} = 0x40;
261 0         0 $self->{_pattern} = 1;
262             }
263              
264              
265             # Set default alignment if indent is set.
266 1346 50 33     3690 $self->{_text_h_align} = 1 if $self->{_indent} and
267             $self->{_text_h_align} == 0;
268              
269              
270 1346         1936 $record = 0x00E0;
271 1346         1445 $length = 0x0014;
272              
273 1346         1645 $ifnt = $self->{_font_index};
274 1346         1762 $ifmt = $self->{_num_format};
275              
276              
277 1346         1751 $align = $self->{_text_h_align};
278 1346         1826 $align |= $self->{_text_wrap} << 3;
279 1346         1606 $align |= $self->{_text_v_align} << 4;
280 1346         1619 $align |= $self->{_text_justlast} << 7;
281 1346         1625 $align |= $self->{_rotation} << 8;
282              
283              
284              
285 1346         1578 $indent = $self->{_indent};
286 1346         1633 $indent |= $self->{_shrink} << 4;
287 1346         1602 $indent |= $self->{_merge_range} << 5;
288 1346         1721 $indent |= $self->{_reading_order} << 6;
289 1346         1551 $indent |= $atr_num << 10;
290 1346         1399 $indent |= $atr_fnt << 11;
291 1346         1405 $indent |= $atr_alc << 12;
292 1346         1479 $indent |= $atr_bdr << 13;
293 1346         1466 $indent |= $atr_pat << 14;
294 1346         1548 $indent |= $atr_prot << 15;
295              
296              
297 1346         1641 $border1 = $self->{_left};
298 1346         1864 $border1 |= $self->{_right} << 4;
299 1346         1590 $border1 |= $self->{_top} << 8;
300 1346         1536 $border1 |= $self->{_bottom} << 12;
301              
302 1346         1828 $border2 = $self->{_left_color};
303 1346         1740 $border2 |= $self->{_right_color} << 7;
304 1346         1586 $border2 |= $self->{_diag_type} << 14;
305              
306              
307 1346         1573 $border3 = $self->{_top_color};
308 1346         1631 $border3 |= $self->{_bottom_color} << 7;
309 1346         1628 $border3 |= $self->{_diag_color} << 14;
310 1346         1674 $border3 |= $self->{_diag_border} << 21;
311 1346         1648 $border3 |= $self->{_pattern} << 26;
312              
313 1346         1551 $icv = $self->{_fg_color};
314 1346         1797 $icv |= $self->{_bg_color} << 7;
315              
316              
317              
318 1346         2923 my $header = pack("vv", $record, $length);
319 1346         2941 my $data = pack("vvvvvvvVv", $ifnt, $ifmt, $style,
320             $align, $indent,
321             $border1, $border2, $border3,
322             $icv);
323              
324 1346         13569 return($header . $data);
325             }
326              
327              
328             ###############################################################################
329             #
330             # Note to porters. The majority of the set_property() methods are created
331             # dynamically via Perl' AUTOLOAD sub, see below. You may prefer/have to specify
332             # them explicitly in other implementation languages.
333             #
334              
335              
336             ###############################################################################
337             #
338             # get_font()
339             #
340             # Generate an Excel BIFF FONT record.
341             #
342             sub get_font {
343              
344 428     428 0 662 my $self = shift;
345              
346 428         551 my $record; # Record identifier
347             my $length; # Record length
348              
349 0         0 my $dyHeight; # Height of font (1/20 of a point)
350 0         0 my $grbit; # Font attributes
351 0         0 my $icv; # Index to color palette
352 0         0 my $bls; # Bold style
353 0         0 my $sss; # Superscript/subscript
354 0         0 my $uls; # Underline
355 0         0 my $bFamily; # Font family
356 0         0 my $bCharSet; # Character set
357 0         0 my $reserved; # Reserved
358 0         0 my $cch; # Length of font name
359 0         0 my $rgch; # Font name
360 0         0 my $encoding; # Font name character encoding
361              
362              
363 428         8244 $dyHeight = $self->{_size} * 20;
364 428         748 $icv = $self->{_color};
365 428         624 $bls = $self->{_bold};
366 428         594 $sss = $self->{_font_script};
367 428         578 $uls = $self->{_underline};
368 428         557 $bFamily = $self->{_font_family};
369 428         585 $bCharSet = $self->{_font_charset};
370 428         652 $rgch = $self->{_font};
371 428         572 $encoding = $self->{_font_encoding};
372              
373             # Handle utf8 strings in perl 5.8.
374 428 50       1101 if ($] >= 5.008) {
375 428         2384 require Encode;
376              
377 428 50       1538 if (Encode::is_utf8($rgch)) {
378 0         0 $rgch = Encode::encode("UTF-16BE", $rgch);
379 0         0 $encoding = 1;
380             }
381             }
382              
383 428         524 $cch = length $rgch;
384              
385             # Handle Unicode font names.
386 428 50       916 if ($encoding == 1) {
387 0 0       0 croak "Uneven number of bytes in Unicode font name" if $cch % 2;
388 0 0       0 $cch /= 2 if $encoding;
389 0         0 $rgch = pack 'v*', unpack 'n*', $rgch;
390             }
391              
392 428         514 $record = 0x31;
393 428         559 $length = 0x10 + length $rgch;
394 428         604 $reserved = 0x00;
395              
396 428         457 $grbit = 0x00;
397 428 50       991 $grbit |= 0x02 if $self->{_italic};
398 428 50       1027 $grbit |= 0x08 if $self->{_font_strikeout};
399 428 50       850 $grbit |= 0x10 if $self->{_font_outline};
400 428 50       918 $grbit |= 0x20 if $self->{_font_shadow};
401              
402              
403 428         931 my $header = pack("vv", $record, $length);
404 428         1168 my $data = pack("vvvvvCCCCCC", $dyHeight, $grbit, $icv, $bls,
405             $sss, $uls, $bFamily,
406             $bCharSet, $reserved, $cch, $encoding);
407              
408 428         2160 return($header . $data . $rgch);
409             }
410              
411             ###############################################################################
412             #
413             # get_font_key()
414             #
415             # Returns a unique hash key for a font. Used by Workbook->_store_all_fonts()
416             #
417             sub get_font_key {
418              
419 1407     1407 0 1753 my $self = shift;
420              
421             # The following elements are arranged to increase the probability of
422             # generating a unique key. Elements that hold a large range of numbers
423             # e.g. _color are placed between two binary elements such as _italic
424             #
425 1407         4004 my $key = "$self->{_font}$self->{_size}";
426 1407         4611 $key .= "$self->{_font_script}$self->{_underline}";
427 1407         4443 $key .= "$self->{_font_strikeout}$self->{_bold}$self->{_font_outline}";
428 1407         3300 $key .= "$self->{_font_family}$self->{_font_charset}";
429 1407         4396 $key .= "$self->{_font_shadow}$self->{_color}$self->{_italic}";
430 1407         2390 $key .= "$self->{_font_encoding}";
431 1407         2262 $key =~ s/ /_/g; # Convert the key to a single word
432              
433 1407         3786 return $key;
434             }
435              
436              
437             ###############################################################################
438             #
439             # get_xf_index()
440             #
441             # Returns the index used by Worksheet->_XF()
442             #
443             sub get_xf_index {
444 23     23 0 32 my $self = shift;
445              
446 23         78 return $self->{_xf_index};
447             }
448              
449              
450             ###############################################################################
451             #
452             # _get_color()
453             #
454             # Used in conjunction with the set_xxx_color methods to convert a color
455             # string into a number. Color range is 0..63 but we will restrict it
456             # to 8..63 to comply with Gnumeric. Colors 0..7 are repeated in 8..15.
457             #
458             sub _get_color {
459              
460 22623     22623   233392 my %colors = (
461             aqua => 0x0F,
462             cyan => 0x0F,
463             black => 0x08,
464             blue => 0x0C,
465             brown => 0x10,
466             magenta => 0x0E,
467             fuchsia => 0x0E,
468             gray => 0x17,
469             grey => 0x17,
470             green => 0x11,
471             lime => 0x0B,
472             navy => 0x12,
473             orange => 0x35,
474             pink => 0x21,
475             purple => 0x14,
476             red => 0x0A,
477             silver => 0x16,
478             white => 0x09,
479             yellow => 0x0D,
480             );
481              
482             # Return the default color, 0x7FFF, if undef,
483 22623 100       167981 return 0x7FFF unless defined $_[0];
484              
485             # or the color string converted to an integer,
486 61 50       722 return $colors{lc($_[0])} if exists $colors{lc($_[0])};
487              
488             # or the default color if string is unrecognised,
489 0 0       0 return 0x7FFF if ($_[0] =~ m/\D/);
490              
491             # or an index < 8 mapped into the correct range,
492 0 0       0 return $_[0] + 8 if $_[0] < 8;
493              
494             # or the default color if arg is outside range,
495 0 0       0 return 0x7FFF if $_[0] > 63;
496              
497             # or an integer in the valid range
498 0         0 return $_[0];
499             }
500              
501              
502             ###############################################################################
503             #
504             # set_type()
505             #
506             # Set the XF object type as 0 = cell XF or 0xFFF5 = style XF.
507             #
508             sub set_type {
509              
510 1220     1220 0 1451 my $self = shift;
511 1220         1507 my $type = $_[0];
512              
513 1220 50 33     5515 if (defined $_[0] and $_[0] eq 0) {
514 0         0 $self->{_type} = 0x0000;
515             }
516             else {
517 1220         6160 $self->{_type} = 0xFFF5;
518             }
519             }
520              
521              
522             ###############################################################################
523             #
524             # set_align()
525             #
526             # Set cell alignment.
527             #
528             sub set_align {
529              
530 0     0 0 0 my $self = shift;
531 0         0 my $location = $_[0];
532              
533 0 0       0 return if not defined $location; # No default
534 0 0       0 return if $location =~ m/\d/; # Ignore numbers
535              
536 0         0 $location = lc($location);
537              
538 0 0       0 $self->set_text_h_align(1) if ($location eq 'left');
539 0 0       0 $self->set_text_h_align(2) if ($location eq 'centre');
540 0 0       0 $self->set_text_h_align(2) if ($location eq 'center');
541 0 0       0 $self->set_text_h_align(3) if ($location eq 'right');
542 0 0       0 $self->set_text_h_align(4) if ($location eq 'fill');
543 0 0       0 $self->set_text_h_align(5) if ($location eq 'justify');
544 0 0       0 $self->set_text_h_align(6) if ($location eq 'center_across');
545 0 0       0 $self->set_text_h_align(6) if ($location eq 'centre_across');
546 0 0       0 $self->set_text_h_align(6) if ($location eq 'merge'); # S:WE name
547 0 0       0 $self->set_text_h_align(7) if ($location eq 'distributed');
548 0 0       0 $self->set_text_h_align(7) if ($location eq 'equal_space'); # ParseExcel
549              
550              
551 0 0       0 $self->set_text_v_align(0) if ($location eq 'top');
552 0 0       0 $self->set_text_v_align(1) if ($location eq 'vcentre');
553 0 0       0 $self->set_text_v_align(1) if ($location eq 'vcenter');
554 0 0       0 $self->set_text_v_align(2) if ($location eq 'bottom');
555 0 0       0 $self->set_text_v_align(3) if ($location eq 'vjustify');
556 0 0       0 $self->set_text_v_align(4) if ($location eq 'vdistributed');
557 0 0       0 $self->set_text_v_align(4) if ($location eq 'vequal_space'); # ParseExcel
558             }
559              
560              
561             ###############################################################################
562             #
563             # set_valign()
564             #
565             # Set vertical cell alignment. This is required by the set_format_properties()
566             # method to differentiate between the vertical and horizontal properties.
567             #
568             sub set_valign {
569              
570 0     0 0 0 my $self = shift;
571 0         0 $self->set_align(@_);
572             }
573              
574              
575             ###############################################################################
576             #
577             # set_center_across()
578             #
579             # Implements the Excel5 style "merge".
580             #
581             sub set_center_across {
582              
583 0     0 0 0 my $self = shift;
584              
585 0         0 $self->set_text_h_align(6);
586             }
587              
588              
589             ###############################################################################
590             #
591             # set_merge()
592             #
593             # This was the way to implement a merge in Excel5. However it should have been
594             # called "center_across" and not "merge".
595             # This is now deprecated. Use set_center_across() or better merge_range().
596             #
597             #
598             sub set_merge {
599              
600 0     0 0 0 my $self = shift;
601              
602 0         0 $self->set_text_h_align(6);
603             }
604              
605              
606             ###############################################################################
607             #
608             # set_bold()
609             #
610             # Bold has a range 0x64..0x3E8.
611             # 0x190 is normal. 0x2BC is bold. So is an excessive use of AUTOLOAD.
612             #
613             sub set_bold {
614              
615 124     124 0 222 my $self = shift;
616 124         199 my $weight = $_[0];
617              
618 124 50       460 $weight = 0x2BC if not defined $weight; # Bold text
619 124 50       353 $weight = 0x2BC if $weight == 1; # Bold text
620 124 50       433 $weight = 0x190 if $weight == 0; # Normal text
621 124 50       500 $weight = 0x190 if $weight < 0x064; # Lower bound
622 124 50       341 $weight = 0x190 if $weight > 0x3E8; # Upper bound
623              
624 124         653 $self->{_bold} = $weight;
625             }
626              
627              
628             ###############################################################################
629             #
630             # set_border($style)
631             #
632             # Set cells borders to the same style
633             #
634             sub set_border {
635              
636 0     0 0 0 my $self = shift;
637 0         0 my $style = $_[0];
638              
639 0         0 $self->set_bottom($style);
640 0         0 $self->set_top($style);
641 0         0 $self->set_left($style);
642 0         0 $self->set_right($style);
643             }
644              
645              
646             ###############################################################################
647             #
648             # set_border_color($color)
649             #
650             # Set cells border to the same color
651             #
652             sub set_border_color {
653              
654 0     0 0 0 my $self = shift;
655 0         0 my $color = $_[0];
656              
657 0         0 $self->set_bottom_color($color);
658 0         0 $self->set_top_color($color);
659 0         0 $self->set_left_color($color);
660 0         0 $self->set_right_color($color);
661             }
662              
663              
664             ###############################################################################
665             #
666             # set_rotation($angle)
667             #
668             # Set the rotation angle of the text. An alignment property.
669             #
670             sub set_rotation {
671              
672 0     0 0 0 my $self = shift;
673 0         0 my $rotation = $_[0];
674              
675             # Argument should be a number
676 0 0       0 return if $rotation !~ /^([+-]?)(?=\d|\.\d)\d*(\.\d*)?([Ee]([+-]?\d+))?$/;
677              
678             # The arg type can be a double but the Excel dialog only allows integers.
679 0         0 $rotation = int $rotation;
680              
681 0 0 0     0 if ($rotation == 270) {
    0          
682 0         0 $rotation = 255;
683             }
684             elsif ($rotation >= -90 or $rotation <= 90) {
685 0 0       0 $rotation = -$rotation +90 if $rotation < 0;
686             }
687             else {
688 0         0 carp "Rotation $rotation outside range: -90 <= angle <= 90";
689 0         0 $rotation = 0;
690             }
691              
692 0         0 $self->{_rotation} = $rotation;
693             }
694              
695              
696             ###############################################################################
697             #
698             # set_format_properties()
699             #
700             # Convert hashes of properties to method calls.
701             #
702             sub set_format_properties {
703              
704 1590     1590 0 2463 my $self = shift;
705              
706 1590         4118 my %properties = @_; # Merge multiple hashes into one
707              
708 1590         4949 while (my($key, $value) = each(%properties)) {
709              
710             # Strip leading "-" from Tk style properties e.g. -color => 'red'.
711 2200         3063 $key =~ s/^-//;
712              
713             # Create a sub to set the property.
714 2200         2553 my $sub = \&{"set_$key"};
  2200         6108  
715 2200         9735 $sub->($self, $value);
716             }
717             }
718              
719             # Renamed rarely used set_properties() to set_format_properties() to avoid
720             # confusion with Workbook method of the same name. The following acts as an
721             # alias for any code that uses the old name.
722             *set_properties = *set_format_properties;
723              
724              
725             ###############################################################################
726             #
727             # AUTOLOAD. Deus ex machina.
728             #
729             # Dynamically create set methods that aren't already defined.
730             #
731             sub AUTOLOAD {
732              
733 172     172   294 my $self = shift;
734              
735             # Ignore calls to DESTROY
736 172 50       615 return if $AUTOLOAD =~ /::DESTROY$/;
737              
738             # Check for a valid method names, i.e. "set_xxx_yyy".
739 172 50       1186 $AUTOLOAD =~ /.*::set(\w+)/ or die "Unknown method: $AUTOLOAD\n";
740              
741             # Match the attribute, i.e. "_xxx_yyy".
742 172         487 my $attribute = $1;
743              
744             # Check that the attribute exists
745 172 50       1246 exists $self->{$attribute} or die "Unknown method: $AUTOLOAD\n";
746              
747             # The attribute value
748 172         233 my $value;
749              
750              
751             # There are two types of set methods: set_property() and
752             # set_property_color(). When a method is AUTOLOADED we store a new anonymous
753             # sub in the appropriate slot in the symbol table. The speeds up subsequent
754             # calls to the same method.
755             #
756 33     33   103530 no strict 'refs'; # To allow symbol table hackery
  33         75  
  33         8334  
757              
758 172 100       574 if ($AUTOLOAD =~ /.*::set\w+color$/) {
759             # For "set_property_color" methods
760 28         146 $value = _get_color($_[0]);
761              
762 28         122 *{$AUTOLOAD} = sub {
763 33     33   71 my $self = shift;
764              
765 33         133 $self->{$attribute} = _get_color($_[0]);
766 28         153 };
767             }
768             else {
769              
770 144         235 $value = $_[0];
771 144 100       359 $value = 1 if not defined $value; # The default value is always 1
772              
773 144         597 *{$AUTOLOAD} = sub {
774 654     654   973 my $self = shift;
775 654         856 my $value = shift;
776              
777 654 100       1445 $value = 1 if not defined $value;
778 654         3448 $self->{$attribute} = $value;
779 144         976 };
780             }
781              
782              
783 172         1875 $self->{$attribute} = $value;
784             }
785              
786              
787             1;
788              
789              
790             __END__