rjw | 6c1fd8f | 2022-11-30 14:33:01 +0800 | [diff] [blame^] | 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 | use Exporter; |
| 16 | use strict; |
| 17 | use Carp; |
| 18 | |
| 19 | |
| 20 | |
| 21 | |
| 22 | |
| 23 | |
| 24 | use vars qw($AUTOLOAD $VERSION @ISA); |
| 25 | @ISA = qw(Exporter); |
| 26 | |
| 27 | $VERSION = '2.37'; |
| 28 | |
| 29 | ############################################################################### |
| 30 | # |
| 31 | # new() |
| 32 | # |
| 33 | # Constructor |
| 34 | # |
| 35 | sub new { |
| 36 | |
| 37 | my $class = shift; |
| 38 | |
| 39 | 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 | bless $self, $class; |
| 102 | |
| 103 | # Set properties passed to Workbook::add_format() |
| 104 | $self->set_format_properties(@_) if @_; |
| 105 | |
| 106 | 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 | my $self = shift; |
| 118 | my $other = $_[0]; |
| 119 | |
| 120 | return unless defined $other; |
| 121 | return unless (ref($self) eq ref($other)); |
| 122 | |
| 123 | # Store the properties that we don't want overwritten. |
| 124 | my $xf = $self->{_xf_index}; |
| 125 | my $merge_range = $self->{_merge_range}; |
| 126 | my $used_merge = $self->{_used_merge}; |
| 127 | |
| 128 | %$self = %$other; # Copy properties |
| 129 | |
| 130 | # Restore saved properties. |
| 131 | $self->{_xf_index} = $xf; |
| 132 | $self->{_merge_range} = $merge_range; |
| 133 | $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 | use integer; # Avoid << shift bug in Perl 5.6.0 on HP-UX |
| 146 | |
| 147 | my $self = shift; |
| 148 | |
| 149 | my $record; # Record identifier |
| 150 | my $length; # Number of bytes to follow |
| 151 | |
| 152 | my $ifnt; # Index to FONT record |
| 153 | my $ifmt; # Index to FORMAT record |
| 154 | my $style; # Style and other options |
| 155 | my $align; # Alignment |
| 156 | my $indent; # |
| 157 | my $icv; # fg and bg pattern colors |
| 158 | my $border1; # Border line options |
| 159 | my $border2; # Border line options |
| 160 | my $border3; # Border line options |
| 161 | |
| 162 | |
| 163 | # Set the type of the XF record and some of the attributes. |
| 164 | if ($self->{_type} == 0xFFF5) { |
| 165 | $style = 0xFFF5; |
| 166 | } |
| 167 | else { |
| 168 | $style = $self->{_locked}; |
| 169 | $style |= $self->{_hidden} << 1; |
| 170 | } |
| 171 | |
| 172 | |
| 173 | # Flags to indicate if attributes have been set. |
| 174 | my $atr_num = ($self->{_num_format} != 0); |
| 175 | |
| 176 | my $atr_fnt = ($self->{_font_index} != 0); |
| 177 | |
| 178 | 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 | 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 | my $atr_pat = ($self->{_fg_color} != 0x40 || |
| 192 | $self->{_bg_color} != 0x41 || |
| 193 | $self->{_pattern} != 0x00) ? 1 : 0; |
| 194 | |
| 195 | my $atr_prot = ($self->{_hidden} != 0 || |
| 196 | $self->{_locked} != 1) ? 1 : 0; |
| 197 | |
| 198 | |
| 199 | # Set attribute changed flags for the style formats. |
| 200 | if ($self->{_xf_index} != 0 and $self->{_type} == 0xFFF5) { |
| 201 | |
| 202 | if ($self->{_xf_index} >= 16) { |
| 203 | $atr_num = 0; |
| 204 | $atr_fnt = 1; |
| 205 | } |
| 206 | else { |
| 207 | $atr_num = 1; |
| 208 | $atr_fnt = 0; |
| 209 | } |
| 210 | |
| 211 | $atr_alc = 1; |
| 212 | $atr_bdr = 1; |
| 213 | $atr_pat = 1; |
| 214 | $atr_prot = 1; |
| 215 | } |
| 216 | |
| 217 | |
| 218 | # Set a default diagonal border style if none was specified. |
| 219 | $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 | $self->{_fg_color} = 0x40 if $self->{_fg_color} == 0x7FFF; |
| 224 | $self->{_bg_color} = 0x41 if $self->{_bg_color} == 0x7FFF; |
| 225 | $self->{_bottom_color} = 0x40 if $self->{_bottom_color} == 0x7FFF; |
| 226 | $self->{_top_color} = 0x40 if $self->{_top_color} == 0x7FFF; |
| 227 | $self->{_left_color} = 0x40 if $self->{_left_color} == 0x7FFF; |
| 228 | $self->{_right_color} = 0x40 if $self->{_right_color} == 0x7FFF; |
| 229 | $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 | $self->{_bottom_color} = 0 if $self->{_bottom} == 0; |
| 234 | $self->{_top_color} = 0 if $self->{_top} == 0; |
| 235 | $self->{_right_color} = 0 if $self->{_right} == 0; |
| 236 | $self->{_left_color} = 0 if $self->{_left} == 0; |
| 237 | $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 | if ($self->{_pattern} <= 0x01 and |
| 248 | $self->{_bg_color} != 0x41 and |
| 249 | $self->{_fg_color} == 0x40 ) |
| 250 | { |
| 251 | $self->{_fg_color} = $self->{_bg_color}; |
| 252 | $self->{_bg_color} = 0x40; |
| 253 | $self->{_pattern} = 1; |
| 254 | } |
| 255 | |
| 256 | if ($self->{_pattern} <= 0x01 and |
| 257 | $self->{_bg_color} == 0x41 and |
| 258 | $self->{_fg_color} != 0x40 ) |
| 259 | { |
| 260 | $self->{_bg_color} = 0x40; |
| 261 | $self->{_pattern} = 1; |
| 262 | } |
| 263 | |
| 264 | |
| 265 | # Set default alignment if indent is set. |
| 266 | $self->{_text_h_align} = 1 if $self->{_indent} and |
| 267 | $self->{_text_h_align} == 0; |
| 268 | |
| 269 | |
| 270 | $record = 0x00E0; |
| 271 | $length = 0x0014; |
| 272 | |
| 273 | $ifnt = $self->{_font_index}; |
| 274 | $ifmt = $self->{_num_format}; |
| 275 | |
| 276 | |
| 277 | $align = $self->{_text_h_align}; |
| 278 | $align |= $self->{_text_wrap} << 3; |
| 279 | $align |= $self->{_text_v_align} << 4; |
| 280 | $align |= $self->{_text_justlast} << 7; |
| 281 | $align |= $self->{_rotation} << 8; |
| 282 | |
| 283 | |
| 284 | |
| 285 | $indent = $self->{_indent}; |
| 286 | $indent |= $self->{_shrink} << 4; |
| 287 | $indent |= $self->{_merge_range} << 5; |
| 288 | $indent |= $self->{_reading_order} << 6; |
| 289 | $indent |= $atr_num << 10; |
| 290 | $indent |= $atr_fnt << 11; |
| 291 | $indent |= $atr_alc << 12; |
| 292 | $indent |= $atr_bdr << 13; |
| 293 | $indent |= $atr_pat << 14; |
| 294 | $indent |= $atr_prot << 15; |
| 295 | |
| 296 | |
| 297 | $border1 = $self->{_left}; |
| 298 | $border1 |= $self->{_right} << 4; |
| 299 | $border1 |= $self->{_top} << 8; |
| 300 | $border1 |= $self->{_bottom} << 12; |
| 301 | |
| 302 | $border2 = $self->{_left_color}; |
| 303 | $border2 |= $self->{_right_color} << 7; |
| 304 | $border2 |= $self->{_diag_type} << 14; |
| 305 | |
| 306 | |
| 307 | $border3 = $self->{_top_color}; |
| 308 | $border3 |= $self->{_bottom_color} << 7; |
| 309 | $border3 |= $self->{_diag_color} << 14; |
| 310 | $border3 |= $self->{_diag_border} << 21; |
| 311 | $border3 |= $self->{_pattern} << 26; |
| 312 | |
| 313 | $icv = $self->{_fg_color}; |
| 314 | $icv |= $self->{_bg_color} << 7; |
| 315 | |
| 316 | |
| 317 | |
| 318 | my $header = pack("vv", $record, $length); |
| 319 | my $data = pack("vvvvvvvVv", $ifnt, $ifmt, $style, |
| 320 | $align, $indent, |
| 321 | $border1, $border2, $border3, |
| 322 | $icv); |
| 323 | |
| 324 | 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 | my $self = shift; |
| 345 | |
| 346 | my $record; # Record identifier |
| 347 | my $length; # Record length |
| 348 | |
| 349 | my $dyHeight; # Height of font (1/20 of a point) |
| 350 | my $grbit; # Font attributes |
| 351 | my $icv; # Index to color palette |
| 352 | my $bls; # Bold style |
| 353 | my $sss; # Superscript/subscript |
| 354 | my $uls; # Underline |
| 355 | my $bFamily; # Font family |
| 356 | my $bCharSet; # Character set |
| 357 | my $reserved; # Reserved |
| 358 | my $cch; # Length of font name |
| 359 | my $rgch; # Font name |
| 360 | my $encoding; # Font name character encoding |
| 361 | |
| 362 | |
| 363 | $dyHeight = $self->{_size} * 20; |
| 364 | $icv = $self->{_color}; |
| 365 | $bls = $self->{_bold}; |
| 366 | $sss = $self->{_font_script}; |
| 367 | $uls = $self->{_underline}; |
| 368 | $bFamily = $self->{_font_family}; |
| 369 | $bCharSet = $self->{_font_charset}; |
| 370 | $rgch = $self->{_font}; |
| 371 | $encoding = $self->{_font_encoding}; |
| 372 | |
| 373 | # Handle utf8 strings in perl 5.8. |
| 374 | if ($] >= 5.008) { |
| 375 | require Encode; |
| 376 | |
| 377 | if (Encode::is_utf8($rgch)) { |
| 378 | $rgch = Encode::encode("UTF-16BE", $rgch); |
| 379 | $encoding = 1; |
| 380 | } |
| 381 | } |
| 382 | |
| 383 | $cch = length $rgch; |
| 384 | |
| 385 | # Handle Unicode font names. |
| 386 | if ($encoding == 1) { |
| 387 | croak "Uneven number of bytes in Unicode font name" if $cch % 2; |
| 388 | $cch /= 2 if $encoding; |
| 389 | $rgch = pack 'v*', unpack 'n*', $rgch; |
| 390 | } |
| 391 | |
| 392 | $record = 0x31; |
| 393 | $length = 0x10 + length $rgch; |
| 394 | $reserved = 0x00; |
| 395 | |
| 396 | $grbit = 0x00; |
| 397 | $grbit |= 0x02 if $self->{_italic}; |
| 398 | $grbit |= 0x08 if $self->{_font_strikeout}; |
| 399 | $grbit |= 0x10 if $self->{_font_outline}; |
| 400 | $grbit |= 0x20 if $self->{_font_shadow}; |
| 401 | |
| 402 | |
| 403 | my $header = pack("vv", $record, $length); |
| 404 | my $data = pack("vvvvvCCCCCC", $dyHeight, $grbit, $icv, $bls, |
| 405 | $sss, $uls, $bFamily, |
| 406 | $bCharSet, $reserved, $cch, $encoding); |
| 407 | |
| 408 | 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 | 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 | my $key = "$self->{_font}$self->{_size}"; |
| 426 | $key .= "$self->{_font_script}$self->{_underline}"; |
| 427 | $key .= "$self->{_font_strikeout}$self->{_bold}$self->{_font_outline}"; |
| 428 | $key .= "$self->{_font_family}$self->{_font_charset}"; |
| 429 | $key .= "$self->{_font_shadow}$self->{_color}$self->{_italic}"; |
| 430 | $key .= "$self->{_font_encoding}"; |
| 431 | $key =~ s/ /_/g; # Convert the key to a single word |
| 432 | |
| 433 | return $key; |
| 434 | } |
| 435 | |
| 436 | |
| 437 | ############################################################################### |
| 438 | # |
| 439 | # get_xf_index() |
| 440 | # |
| 441 | # Returns the used by Worksheet->_XF() |
| 442 | # |
| 443 | sub get_xf_index { |
| 444 | my $self = shift; |
| 445 | |
| 446 | 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 | 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 | return 0x7FFF unless defined $_[0]; |
| 484 | |
| 485 | # or the color string converted to an integer, |
| 486 | return $colors{lc($_[0])} if exists $colors{lc($_[0])}; |
| 487 | |
| 488 | # or the default color if string is unrecognised, |
| 489 | return 0x7FFF if ($_[0] =~ m/\D/); |
| 490 | |
| 491 | # or an index < 8 mapped into the correct range, |
| 492 | return $_[0] + 8 if $_[0] < 8; |
| 493 | |
| 494 | # or the default color if arg is outside range, |
| 495 | return 0x7FFF if $_[0] > 63; |
| 496 | |
| 497 | # or an integer in the valid range |
| 498 | 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 | my $self = shift; |
| 511 | my $type = $_[0]; |
| 512 | |
| 513 | if (defined $_[0] and $_[0] eq 0) { |
| 514 | $self->{_type} = 0x0000; |
| 515 | } |
| 516 | else { |
| 517 | $self->{_type} = 0xFFF5; |
| 518 | } |
| 519 | } |
| 520 | |
| 521 | |
| 522 | ############################################################################### |
| 523 | # |
| 524 | # set_align() |
| 525 | # |
| 526 | # Set cell alignment. |
| 527 | # |
| 528 | sub set_align { |
| 529 | |
| 530 | my $self = shift; |
| 531 | my $location = $_[0]; |
| 532 | |
| 533 | return if not defined $location; # No default |
| 534 | return if $location =~ m/\d/; # Ignore numbers |
| 535 | |
| 536 | $location = lc($location); |
| 537 | |
| 538 | $self->set_text_h_align(1) if ($location eq 'left'); |
| 539 | $self->set_text_h_align(2) if ($location eq 'centre'); |
| 540 | $self->set_text_h_align(2) if ($location eq 'center'); |
| 541 | $self->set_text_h_align(3) if ($location eq 'right'); |
| 542 | $self->set_text_h_align(4) if ($location eq 'fill'); |
| 543 | $self->set_text_h_align(5) if ($location eq 'justify'); |
| 544 | $self->set_text_h_align(6) if ($location eq 'center_across'); |
| 545 | $self->set_text_h_align(6) if ($location eq 'centre_across'); |
| 546 | $self->set_text_h_align(6) if ($location eq 'merge'); # S:WE name |
| 547 | $self->set_text_h_align(7) if ($location eq 'distributed'); |
| 548 | $self->set_text_h_align(7) if ($location eq 'equal_space'); # ParseExcel |
| 549 | |
| 550 | |
| 551 | $self->set_text_v_align(0) if ($location eq 'top'); |
| 552 | $self->set_text_v_align(1) if ($location eq 'vcentre'); |
| 553 | $self->set_text_v_align(1) if ($location eq 'vcenter'); |
| 554 | $self->set_text_v_align(2) if ($location eq 'bottom'); |
| 555 | $self->set_text_v_align(3) if ($location eq 'vjustify'); |
| 556 | $self->set_text_v_align(4) if ($location eq 'vdistributed'); |
| 557 | $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 | my $self = shift; |
| 571 | $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 | my $self = shift; |
| 584 | |
| 585 | $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 | my $self = shift; |
| 601 | |
| 602 | $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 | my $self = shift; |
| 616 | my $weight = $_[0]; |
| 617 | |
| 618 | $weight = 0x2BC if not defined $weight; # Bold text |
| 619 | $weight = 0x2BC if $weight == 1; # Bold text |
| 620 | $weight = 0x190 if $weight == 0; # Normal text |
| 621 | $weight = 0x190 if $weight < 0x064; # Lower bound |
| 622 | $weight = 0x190 if $weight > 0x3E8; # Upper bound |
| 623 | |
| 624 | $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 | my $self = shift; |
| 637 | my $style = $_[0]; |
| 638 | |
| 639 | $self->set_bottom($style); |
| 640 | $self->set_top($style); |
| 641 | $self->set_left($style); |
| 642 | $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 | my $self = shift; |
| 655 | my $color = $_[0]; |
| 656 | |
| 657 | $self->set_bottom_color($color); |
| 658 | $self->set_top_color($color); |
| 659 | $self->set_left_color($color); |
| 660 | $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 | my $self = shift; |
| 673 | my $rotation = $_[0]; |
| 674 | |
| 675 | # Argument should be a number |
| 676 | 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 | $rotation = int $rotation; |
| 680 | |
| 681 | if ($rotation == 270) { |
| 682 | $rotation = 255; |
| 683 | } |
| 684 | elsif ($rotation >= -90 or $rotation <= 90) { |
| 685 | $rotation = -$rotation +90 if $rotation < 0; |
| 686 | } |
| 687 | else { |
| 688 | carp "Rotation $rotation outside range: -90 <= angle <= 90"; |
| 689 | $rotation = 0; |
| 690 | } |
| 691 | |
| 692 | $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 | my $self = shift; |
| 705 | |
| 706 | my %properties = @_; # Merge multiple hashes into one |
| 707 | |
| 708 | while (my($key, $value) = each(%properties)) { |
| 709 | |
| 710 | # Strip leading "-" from Tk style properties e.g. -color => 'red'. |
| 711 | $key =~ s/^-//; |
| 712 | |
| 713 | # Create a sub to set the property. |
| 714 | my $sub = \&{"set_$key"}; |
| 715 | $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 | my $self = shift; |
| 734 | |
| 735 | # Ignore calls to DESTROY |
| 736 | return if $AUTOLOAD =~ /::DESTROY$/; |
| 737 | |
| 738 | # Check for a valid method names, i.e. "set_xxx_yyy". |
| 739 | $AUTOLOAD =~ /.*::set(\w+)/ or die "Unknown method: $AUTOLOAD\n"; |
| 740 | |
| 741 | # Match the attribute, i.e. "_xxx_yyy". |
| 742 | my $attribute = $1; |
| 743 | |
| 744 | # Check that the attribute exists |
| 745 | exists $self->{$attribute} or die "Unknown method: $AUTOLOAD\n"; |
| 746 | |
| 747 | # The attribute value |
| 748 | 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 | no strict 'refs'; # To allow symbol table hackery |
| 757 | |
| 758 | if ($AUTOLOAD =~ /.*::set\w+color$/) { |
| 759 | # For "set_property_color" methods |
| 760 | $value = _get_color($_[0]); |
| 761 | |
| 762 | *{$AUTOLOAD} = sub { |
| 763 | my $self = shift; |
| 764 | |
| 765 | $self->{$attribute} = _get_color($_[0]); |
| 766 | }; |
| 767 | } |
| 768 | else { |
| 769 | |
| 770 | $value = $_[0]; |
| 771 | $value = 1 if not defined $value; # The default value is always 1 |
| 772 | |
| 773 | *{$AUTOLOAD} = sub { |
| 774 | my $self = shift; |
| 775 | my $value = shift; |
| 776 | |
| 777 | $value = 1 if not defined $value; |
| 778 | $self->{$attribute} = $value; |
| 779 | }; |
| 780 | } |
| 781 | |
| 782 | |
| 783 | $self->{$attribute} = $value; |
| 784 | } |
| 785 | |
| 786 | |
| 787 | 1; |
| 788 | |
| 789 | |
| 790 | __END__ |
| 791 | |
| 792 | |
| 793 | =head1 NAME |
| 794 | |
| 795 | Format - A class for defining Excel formatting. |
| 796 | |
| 797 | =head1 SYNOPSIS |
| 798 | |
| 799 | See the documentation for Spreadsheet::WriteExcel |
| 800 | |
| 801 | =head1 DESCRIPTION |
| 802 | |
| 803 | This module is used in conjunction with Spreadsheet::WriteExcel. |
| 804 | |
| 805 | =head1 AUTHOR |
| 806 | |
| 807 | John McNamara jmcnamara@cpan.org |
| 808 | |
| 809 | =head1 COPYRIGHT |
| 810 | |
| 811 | © MM-MMX, John McNamara. |
| 812 | |
| 813 | All Rights Reserved. This module is free software. It may be used, redistributed and/or modified under the same terms as Perl itself. |