1//////////////////////////////////////////////////////////////////////////////// 2// 3// ADOBE SYSTEMS INCORPORATED 4// Copyright 2003-2007 Adobe Systems Incorporated 5// All Rights Reserved. 6// 7// NOTICE: Adobe permits you to use, modify, and distribute this file 8// in accordance with the terms of the license agreement accompanying it. 9// 10//////////////////////////////////////////////////////////////////////////////// 11 12package mx.skins.halo 13{ 14 15import flash.display.GradientType; 16import flash.display.Graphics; 17import mx.core.IContainer; 18import mx.core.EdgeMetrics; 19import mx.core.FlexVersion; 20import mx.core.IUIComponent; 21import mx.core.mx_internal; 22import mx.graphics.RectangularDropShadow; 23import mx.skins.RectangularBorder; 24import mx.styles.IStyleClient; 25import mx.styles.StyleManager; 26import mx.utils.ColorUtil; 27import mx.graphics.GradientEntry; 28 29use namespace mx_internal; 30 31/** 32 * Defines the appearance of the default border for the Halo theme. 33 */ 34public class HaloBorder extends RectangularBorder 35{ 36 include "../../core/Version.as"; 37 38 //-------------------------------------------------------------------------- 39 // 40 // Class constants 41 // 42 //-------------------------------------------------------------------------- 43 44 /** 45 * @private 46 * A look up table for the offsets. 47 */ 48 private static var BORDER_WIDTHS:Object = 49 { 50 none: 0, 51 solid: 1, 52 inset: 2, 53 outset: 2, 54 alert: 3, 55 dropdown: 2, 56 menuBorder: 1, 57 comboNonEdit: 2 58 }; 59 60 //-------------------------------------------------------------------------- 61 // 62 // Constructor 63 // 64 //-------------------------------------------------------------------------- 65 66 /** 67 * Constructor. 68 */ 69 public function HaloBorder() 70 { 71 super(); 72 73 // 'default' is a keyword; setting it this way avoids a compiler error 74 BORDER_WIDTHS["default"] = 3; 75 } 76 77 //-------------------------------------------------------------------------- 78 // 79 // Fields 80 // 81 //-------------------------------------------------------------------------- 82 83 /** 84 * @private 85 * A reference to the object used to cast a drop shadow. 86 * See the drawDropShadow() method for details. 87 */ 88 private var dropShadow:RectangularDropShadow; 89 90 mx_internal var backgroundColor:Object; 91 mx_internal var backgroundAlphaName:String; 92 mx_internal var backgroundHole:Object; 93 mx_internal var bRoundedCorners:Boolean; 94 mx_internal var radius:Number; 95 mx_internal var radiusObj:Object; 96 97 //-------------------------------------------------------------------------- 98 // 99 // Overridden properties 100 // 101 //-------------------------------------------------------------------------- 102 103 //---------------------------------- 104 // borderMetrics 105 //---------------------------------- 106 107 /** 108 * @private 109 * Internal object that contains the thickness of each edge 110 * of the border 111 */ 112 protected var _borderMetrics:EdgeMetrics; 113 114 /** 115 * @private 116 * Return the thickness of the border edges. 117 * 118 * @return Object top, bottom, left, right thickness in pixels 119 */ 120 override public function get borderMetrics():EdgeMetrics 121 { 122 if (_borderMetrics) 123 return _borderMetrics; 124 125 var borderThickness:Number; 126 127 // Add support for "custom" style type here when we support it. 128 var borderStyle:String = getStyle("borderStyle"); 129 130 if (borderStyle == "default" || 131 borderStyle == "alert") 132 { 133 if (FlexVersion.compatibilityVersion < FlexVersion.VERSION_3_0) 134 _borderMetrics = new EdgeMetrics(0, 0, 0, 0); 135 else 136 return EdgeMetrics.EMPTY; 137 } 138 139 else if (borderStyle == "controlBar" || 140 borderStyle == "applicationControlBar") 141 { 142 _borderMetrics = new EdgeMetrics(1, 1, 1, 1); 143 } 144 145 else if (borderStyle == "solid") 146 { 147 borderThickness = getStyle("borderThickness"); 148 if (isNaN(borderThickness)) 149 borderThickness = 0; 150 151 _borderMetrics = new EdgeMetrics(borderThickness, 152 borderThickness, 153 borderThickness, 154 borderThickness); 155 156 var borderSides:String = getStyle("borderSides"); 157 if (borderSides != "left top right bottom") 158 { 159 // Adjust metrics based on which sides we have 160 if (borderSides.indexOf("left") == -1) 161 _borderMetrics.left = 0; 162 163 if (borderSides.indexOf("top") == -1) 164 _borderMetrics.top = 0; 165 166 if (borderSides.indexOf("right") == -1) 167 _borderMetrics.right = 0; 168 169 if (borderSides.indexOf("bottom") == -1) 170 _borderMetrics.bottom = 0; 171 } 172 } 173 174 else 175 { 176 borderThickness = BORDER_WIDTHS[borderStyle]; 177 if (isNaN(borderThickness)) 178 borderThickness = 0; 179 180 _borderMetrics = new EdgeMetrics(borderThickness, 181 borderThickness, 182 borderThickness, 183 borderThickness); 184 } 185 186 return _borderMetrics; 187 } 188 189 //-------------------------------------------------------------------------- 190 // 191 // Overridden methods 192 // 193 //-------------------------------------------------------------------------- 194 195 /** 196 * @private 197 * If borderStyle may have changed, clear the cached border metrics. 198 */ 199 override public function styleChanged(styleProp:String):void 200 { 201 if (styleProp == null || 202 styleProp == "styleName" || 203 styleProp == "borderStyle" || 204 styleProp == "borderThickness" || 205 styleProp == "borderSides") 206 { 207 _borderMetrics = null; 208 } 209 210 invalidateDisplayList(); 211 } 212 213 /** 214 * @private 215 * Draw the border, either 3D or 2D or nothing at all. 216 */ 217 override protected function updateDisplayList(w:Number, h:Number):void 218 { 219 if (isNaN(w) || isNaN(h)) 220 return; 221 222 super.updateDisplayList(w, h); 223 224 // Store background color in an object, 225 // so that null is distinct from black. 226 backgroundColor = getBackgroundColor(); 227 bRoundedCorners = false; 228 backgroundAlphaName = "backgroundAlpha"; 229 backgroundHole = null; 230 radius = 0; 231 radiusObj = null; 232 233 drawBorder(w,h); 234 drawBackground(w,h); 235 } 236 237 //-------------------------------------------------------------------------- 238 // 239 // Methods 240 // 241 //-------------------------------------------------------------------------- 242 243 /** 244 * @private 245 */ 246 mx_internal function drawBorder(w:Number, h:Number):void 247 { 248 var borderStyle:String = getStyle("borderStyle"); 249 250 // Other styles that we may fetch. 251 var highlightAlphas:Array = getStyle("highlightAlphas"); 252 253 var backgroundAlpha:Number; 254 255 var borderCapColor:uint; 256 var borderColor:uint; 257 var borderSides:String; 258 var borderThickness:Number; 259 var buttonColor:uint; 260 var docked:Boolean; 261 var dropdownBorderColor:uint; 262 var fillColors:Array; 263 var footerColors:Array; 264 var highlightColor:uint; 265 var shadowCapColor:uint; 266 var shadowColor:uint; 267 var themeColor:uint; 268 var translucent:Boolean; 269 270 var hole:Object; 271 var drawTopHighlight:Boolean = false; 272 273 var borderColorDrk1:Number 274 var borderColorDrk2:Number 275 var borderColorLt1:Number 276 277 var borderInnerColor:Object; 278 279 var g:Graphics = graphics; 280 g.clear(); 281 282 if (borderStyle) 283 { 284 switch (borderStyle) 285 { 286 case "none": 287 { 288 break; 289 } 290 291 case "inset": // used for text input & numeric stepper 292 { 293 borderColor = getStyle("borderColor"); 294 borderColorDrk1 = 295 ColorUtil.adjustBrightness2(borderColor, -40); 296 borderColorDrk2 = 297 ColorUtil.adjustBrightness2(borderColor, +25); 298 borderColorLt1 = 299 ColorUtil.adjustBrightness2(borderColor, +40); 300 301 borderInnerColor = backgroundColor; 302 if (borderInnerColor === null || 303 borderInnerColor === "") 304 { 305 borderInnerColor = borderColor; 306 } 307 308 draw3dBorder(borderColorDrk2, borderColorDrk1, borderColorLt1, 309 Number(borderInnerColor), 310 Number(borderInnerColor), 311 Number(borderInnerColor)); 312 break; 313 } 314 315 case "outset": 316 { 317 borderColor = getStyle("borderColor"); 318 borderColorDrk1 = 319 ColorUtil.adjustBrightness2(borderColor, -40); 320 borderColorDrk2 = 321 ColorUtil.adjustBrightness2(borderColor, -25); 322 borderColorLt1 = 323 ColorUtil.adjustBrightness2(borderColor, +40); 324 325 borderInnerColor = backgroundColor; 326 if (borderInnerColor === null || 327 borderInnerColor === "") 328 { 329 borderInnerColor = borderColor; 330 } 331 332 draw3dBorder(borderColorDrk2, borderColorLt1, borderColorDrk1, 333 Number(borderInnerColor), 334 Number(borderInnerColor), 335 Number(borderInnerColor)); 336 break; 337 } 338 339 case "alert": 340 case "default": 341 { 342 if (FlexVersion.compatibilityVersion < FlexVersion.VERSION_3_0) 343 { 344 // For Panel/Alert, "borderAlpha" is the alpha for the 345 // title/control/gutter area and "backgroundAlpha" 346 // is the alpha for the content area. 347 // We flip-flop the variables here so the "borderAlpha" 348 // is applied by the background drawing code at the bottom. 349 var contentAlpha:Number = getStyle("backgroundAlpha"); 350 backgroundAlpha = getStyle("borderAlpha"); 351 backgroundAlphaName = "borderAlpha"; 352 353 radius = getStyle("cornerRadius"); 354 bRoundedCorners = 355 getStyle("roundedBottomCorners").toString().toLowerCase() == "true"; 356 var br:Number = bRoundedCorners ? radius : 0; 357 358 drawDropShadow(0, 0, w, h, radius, radius, br, br); 359 360 // If we don't have rounded corners we need to initialize 361 // the complex radius object so the background fill code 362 // below works correctly. 363 if (!bRoundedCorners) 364 radiusObj = {}; 365 366 var parentContainer:IContainer = parent as IContainer; 367 368 if (parentContainer) 369 { 370 var vm:EdgeMetrics = parentContainer.viewMetrics; 371 372 // The backgroundHole is the content area 373 backgroundHole = {x:vm.left, y:vm.top, 374 w: Math.max(0, w - vm.left - vm.right), 375 h: Math.max(0, h - vm.top - vm.bottom), 376 r:0}; 377 378 if (backgroundHole.w > 0 && backgroundHole.h > 0) 379 { 380 // Draw a shadow around the content 381 // if the content and panel alpha are different. 382 // This could be a style property if needed 383 if (contentAlpha != backgroundAlpha) 384 { 385 drawDropShadow(backgroundHole.x, backgroundHole.y, 386 backgroundHole.w, backgroundHole.h, 387 0, 0, 0, 0); 388 } 389 390 // Fill in the content area 391 g.beginFill(Number(backgroundColor), contentAlpha); 392 g.drawRect(backgroundHole.x, backgroundHole.y, 393 backgroundHole.w, backgroundHole.h); 394 g.endFill(); 395 } 396 } 397 398 // When the content and panel alpha are different, the border 399 // of the panel is drawn using borderColor. We've already 400 // drawn the content background so we set backgroundColor to 401 // borderColor here so the drawing code below is done with the 402 // border color. 403 backgroundColor = getStyle("borderColor"); 404 } 405 406 break; 407 } 408 409 case "dropdown": // never used 410 { 411 // The dropdownBorderColor is currently only used 412 // when displaying an error state. 413 dropdownBorderColor = getStyle("dropdownBorderColor"); 414 415 drawDropShadow(0, 0, w, h, 4, 0, 0, 4); 416 417 // frame 418 drawRoundRect( 419 0, 0, w, h, 420 { tl: 4, tr: 0, br: 0, bl: 4 }, 421 0x4D555E, 1); 422 423 // gradient 424 drawRoundRect( 425 0, 0, w, h, 426 { tl: 4, tr: 0, br: 0, bl: 4}, 427 [ 0xFFFFFF, 0xFFFFFF ], [ 0.7, 0 ], 428 verticalGradientMatrix(0, 0, w, h)); 429 430 // button top higlight edge 431 drawRoundRect( 432 1, 1, w - 1, h - 2, 433 { tl: 3, tr: 0, br: 0, bl: 3 }, 434 0xFFFFFF, 1); 435 436 // button face 437 drawRoundRect( 438 1, 2, w - 1, h - 3, 439 { tl: 3, tr: 0, br: 0, bl: 3 }, 440 [ 0xEEEEEE, 0xFFFFFF ], 1, 441 verticalGradientMatrix(0, 0, w - 1, h - 3)); 442 443 if (!isNaN(dropdownBorderColor)) 444 { 445 // combo background in error state 446 drawRoundRect( 447 0, 0, w + 1, h, 448 { tl: 4, tr: 0, br: 0, bl: 4 }, 449 dropdownBorderColor, 0.5); 450 451 // button top higlight edge 452 drawRoundRect( 453 1, 1, w - 1, h - 2, 454 { tl: 3, tr: 0, br: 0, bl: 3 }, 455 0xFFFFFF, 1); 456 457 //button face 458 drawRoundRect( 459 1, 2, w - 1, h - 3, 460 { tl: 3, tr: 0, br: 0, bl: 3 }, 461 [ 0xEEEEEE, 0xFFFFFF ], 1, 462 verticalGradientMatrix(0, 0, w - 1, h - 3)); 463 } 464 465 // Make sure the border isn't filled in down below. 466 backgroundColor = null; 467 468 break; 469 } 470 471 case "menuBorder": 472 { 473 borderColor = getStyle("borderColor"); 474 drawRoundRect( 475 0, 0, w, h, 0, 476 borderColor, 1); 477 drawDropShadow(1, 1, w - 2, h - 2, 0, 0, 0, 0); 478 break; 479 } 480 481 case "comboNonEdit": 482 { 483 break; 484 } 485 486 case "controlBar": 487 { 488 if (w == 0 || h == 0) 489 { 490 // If the width or height is 0, don't draw anything. 491 backgroundColor = null; 492 break; 493 } 494 495 footerColors = getStyle("footerColors"); 496 var showChrome:Boolean = footerColors != null; 497 var borderAlpha:Number = getStyle("borderAlpha"); 498 499 if (showChrome) 500 { 501 g.lineStyle(0, footerColors.length > 0 ? 502 footerColors[1] : footerColors[0], borderAlpha); 503 g.moveTo(0, 0); 504 g.lineTo(w, 0); 505 g.lineStyle(0, 0, 0); 506 507 // cornerRadius is defined on our parent container. Reach up 508 // and grab it. Yes, this is cheating... 509 if (parent && parent.parent && parent.parent is IStyleClient) 510 { 511 radius = 512 IStyleClient(parent.parent).getStyle("cornerRadius"); 513 borderAlpha = 514 IStyleClient(parent.parent).getStyle("borderAlpha"); 515 } 516 517 if (isNaN(radius)) 518 radius = 0; 519 520 // If our parent has square bottom corners, 521 // use square corners. 522 if (IStyleClient(parent.parent). 523 getStyle("roundedBottomCorners").toString().toLowerCase() != "true") 524 { 525 radius = 0; 526 } 527 528 drawRoundRect( 529 0, 1, w, h - 1, 530 { tl: 0, tr: 0, bl:radius, br: radius }, 531 footerColors, borderAlpha, 532 verticalGradientMatrix(0, 0, w, h)); 533 534 if (footerColors.length > 1 && 535 footerColors[0] != footerColors[1]) 536 { 537 drawRoundRect( 538 0, 1, w, h - 1, 539 { tl: 0, tr: 0, bl: radius, br: radius }, 540 [ 0xFFFFFF, 0xFFFFFF ], highlightAlphas, 541 verticalGradientMatrix(0, 0, w, h)); 542 543 drawRoundRect( 544 1, 2, w - 2, h - 3, 545 { tl: 0, tr: 0, bl: radius - 1, br: radius - 1 }, 546 footerColors, borderAlpha, 547 verticalGradientMatrix(0, 0, w, h)); 548 } 549 } 550 551 // Don't draw the background color below. 552 // We've already handled it here. 553 backgroundColor = null; 554 break; 555 } 556 557 case "applicationControlBar": 558 { 559 fillColors = getStyle("fillColors"); 560 backgroundAlpha = getStyle("backgroundAlpha"); 561 highlightAlphas = getStyle("highlightAlphas"); 562 var fillAlphas:Array = getStyle("fillAlphas"); 563 docked = getStyle("docked"); 564 565 // background color of the bar 566 var backgroundColorNum:uint = uint(backgroundColor); 567 568 radius = getStyle("cornerRadius"); 569 if (!radius) 570 radius = 0; 571 572 drawDropShadow(0, 1, w, h - 1, 573 radius, radius, radius, radius); 574 575 if (backgroundColor !== null && StyleManager.isValidStyleValue(backgroundColor)) 576 { 577 drawRoundRect( 578 0, 1, w, h - 1, radius, 579 backgroundColorNum, backgroundAlpha, 580 verticalGradientMatrix(0, 0, w, h)); 581 } 582 583 // surface 584 drawRoundRect( 585 0, 1, w, h - 1, radius, 586 fillColors, fillAlphas, 587 verticalGradientMatrix(0, 0, w, h)); 588 589 // highlight 590 drawRoundRect( 591 0, 1, w, (h / 2) - 1, 592 { tl: radius, tr: radius, bl: 0, br: 0 }, 593 [ 0xFFFFFF, 0xFFFFFF ], highlightAlphas, 594 verticalGradientMatrix(0, 0, w, h / 2 - 1)); 595 596 // edge 597 drawRoundRect( 598 0, 1, w, h - 1, 599 { tl: radius, tr: radius, bl: 0, br: 0 }, 600 0xFFFFFF, 0.3, null, 601 GradientType.LINEAR, null, 602 { x: 0, y: 2, w: w, h: h - 2, 603 r: { tl: radius, tr: radius, bl: 0, br: 0 } }); 604 605 // Don't draw the background color below. 606 // We've already handled it here. 607 backgroundColor = null; 608 609 break; 610 } 611 612 default: // ((borderStyle == "solid") || (borderStyle == null)) 613 { 614 borderColor = getStyle("borderColor"); 615 borderThickness = getStyle("borderThickness"); 616 borderSides = getStyle("borderSides"); 617 var bHasAllSides:Boolean = true; 618 radius = getStyle("cornerRadius"); 619 620 bRoundedCorners = 621 getStyle("roundedBottomCorners").toString().toLowerCase() == "true"; 622 623 var holeRadius:Number = 624 Math.max(radius - borderThickness, 0); 625 626 hole = { x: borderThickness, 627 y: borderThickness, 628 w: w - borderThickness * 2, 629 h: h - borderThickness * 2, 630 r: holeRadius }; 631 632 if (!bRoundedCorners) 633 { 634 radiusObj = {tl:radius, tr:radius, bl:0, br:0}; 635 hole.r = {tl:holeRadius, tr:holeRadius, bl:0, br:0}; 636 } 637 638 if (borderSides != "left top right bottom") 639 { 640 // Convert the radius values from a scalar to an object 641 // because we need to adjust individual radius values 642 // if we are missing any sides. 643 hole.r = { tl: holeRadius, 644 tr: holeRadius, 645 bl: bRoundedCorners ? holeRadius : 0, 646 br: bRoundedCorners ? holeRadius : 0 }; 647 648 radiusObj = { tl: radius, 649 tr: radius, 650 bl: bRoundedCorners ? radius : 0, 651 br: bRoundedCorners ? radius : 0}; 652 653 borderSides = borderSides.toLowerCase(); 654 655 if (borderSides.indexOf("left") == -1) 656 { 657 hole.x = 0; 658 hole.w += borderThickness; 659 hole.r.tl = 0; 660 hole.r.bl = 0; 661 radiusObj.tl = 0; 662 radiusObj.bl = 0; 663 bHasAllSides = false; 664 } 665 666 if (borderSides.indexOf("top") == -1) 667 { 668 hole.y = 0; 669 hole.h += borderThickness; 670 hole.r.tl = 0; 671 hole.r.tr = 0; 672 radiusObj.tl = 0; 673 radiusObj.tr = 0; 674 bHasAllSides = false; 675 } 676 677 if (borderSides.indexOf("right") == -1) 678 { 679 hole.w += borderThickness; 680 hole.r.tr = 0; 681 hole.r.br = 0; 682 radiusObj.tr = 0; 683 radiusObj.br = 0; 684 bHasAllSides = false; 685 } 686 687 if (borderSides.indexOf("bottom") == -1) 688 { 689 hole.h += borderThickness; 690 hole.r.bl = 0; 691 hole.r.br = 0; 692 radiusObj.bl = 0; 693 radiusObj.br = 0; 694 bHasAllSides = false; 695 } 696 } 697 698 if (radius == 0 && bHasAllSides) 699 { 700 drawDropShadow(0, 0, w, h, 0, 0, 0, 0); 701 702 g.beginFill(borderColor); 703 g.drawRect(0, 0, w, h); 704 g.drawRect(borderThickness, borderThickness, 705 w - 2 * borderThickness, 706 h - 2 * borderThickness); 707 g.endFill(); 708 } 709 else if (radiusObj) 710 { 711 drawDropShadow(0, 0, w, h, 712 radiusObj.tl, radiusObj.tr, 713 radiusObj.br, radiusObj.bl); 714 715 drawRoundRect( 716 0, 0, w, h, radiusObj, 717 borderColor, 1, 718 null, null, null, hole); 719 720 // Reset radius here so background drawing 721 // below is correct. 722 radiusObj.tl = Math.max(radius - borderThickness, 0); 723 radiusObj.tr = Math.max(radius - borderThickness, 0); 724 radiusObj.bl = bRoundedCorners ? Math.max(radius - borderThickness, 0) : 0; 725 radiusObj.br = bRoundedCorners ? Math.max(radius - borderThickness, 0) : 0; 726 } 727 else 728 { 729 drawDropShadow(0, 0, w, h, 730 radius, radius, radius, radius); 731 732 drawRoundRect( 733 0, 0, w, h, radius, 734 borderColor, 1, 735 null, null, null, hole); 736 737 // Reset radius here so background drawing 738 // below is correct. 739 radius = Math.max(getStyle("cornerRadius") - 740 borderThickness, 0); 741 } 742 } 743 } // switch 744 } 745 } 746 747 748 /** 749 * @private 750 * Draw a 3D border. 751 */ 752 mx_internal function draw3dBorder(c1:Number, c2:Number, c3:Number, 753 c4:Number, c5:Number, c6:Number):void 754 { 755 var w:Number = width; 756 var h:Number = height; 757 758 /* 759 // temp color override to verify layout of lines 760 var c1:Number = 0x919999; 761 var c2:Number = 0x6F7777; 762 var c3:Number = 0xD5DDDD; 763 var c4:Number = 0xC4CCCC; 764 var c5:Number = 0xEEEEEE; 765 var c6:Number = 0xD5DDDD; 766 */ 767 768 drawDropShadow(0, 0, width, height, 0, 0, 0, 0); 769 770 var g:Graphics = graphics; 771 772 // outside sides 773 g.beginFill(c1); 774 g.drawRect(0, 0, w, h); 775 g.drawRect(1, 0, w - 2, h); 776 g.endFill(); 777 778 // outside top 779 g.beginFill(c2); 780 g.drawRect(1, 0, w - 2, 1); 781 g.endFill(); 782 783 // outside bottom 784 g.beginFill(c3); 785 g.drawRect(1, h - 1, w - 2, 1); 786 g.endFill(); 787 788 // inside top 789 g.beginFill(c4); 790 g.drawRect(1, 1, w - 2, 1); 791 g.endFill(); 792 793 // inside bottom 794 g.beginFill(c5); 795 g.drawRect(1, h - 2, w - 2, 1); 796 g.endFill(); 797 798 // inside sides 799 g.beginFill(c6); 800 g.drawRect(1, 2, w - 2, h - 4); 801 g.drawRect(2, 2, w - 4, h - 4); 802 g.endFill(); 803 } 804 805 /** 806 * @private 807 */ 808 mx_internal function drawBackground(w:Number, h:Number):void 809 { 810 // The behavior used to be that we always create a background 811 // regardless of whether we have a background color or not. 812 // Now we only create a background if we have a color 813 // or if the mouseShield or mouseShieldChildren styles are true. 814 // Look at Container.addEventListener and Container.isBorderNeeded 815 // for the mouseShield logic. JCS 6/24/05 816 if ((backgroundColor !== null && 817 backgroundColor !== "") || 818 getStyle("mouseShield") || 819 getStyle("mouseShieldChildren")) 820 { 821 var nd:Number = Number(backgroundColor); 822 var alpha:Number = 1.0; 823 var bm:EdgeMetrics = getBackgroundColorMetrics(); 824 var g:Graphics = graphics; 825 826 if (isNaN(nd) || 827 backgroundColor === "" || 828 backgroundColor === null) 829 { 830 alpha = 0; 831 nd = 0xFFFFFF; 832 } 833 else 834 { 835 alpha = getStyle(backgroundAlphaName); 836 } 837 838 // If we have a non-zero radius, use drawRoundRect() 839 // to fill in the background. 840 if (radius != 0 || backgroundHole) 841 { 842 var bottom:Number = bm.bottom; 843 844 if (radiusObj) 845 { 846 var topRadius:Number = 847 Math.max(radius - Math.max(bm.top, bm.left, bm.right), 0); 848 var bottomRadius:Number = bRoundedCorners ? 849 Math.max(radius - Math.max(bm.bottom, bm.left, bm.right), 0) : 0; 850 851 radiusObj = { tl: topRadius, 852 tr: topRadius, 853 bl: bottomRadius, 854 br: bottomRadius }; 855 856 drawRoundRect( 857 bm.left, bm.top, 858 width - (bm.left + bm.right), 859 height - (bm.top + bottom), 860 radiusObj, 861 nd, alpha, null, 862 GradientType.LINEAR, null, 863 backgroundHole); 864 } 865 else 866 { 867 drawRoundRect( 868 bm.left, bm.top, 869 width - (bm.left + bm.right), 870 height - (bm.top + bottom), 871 radius, 872 nd, alpha, null, 873 GradientType.LINEAR, null, 874 backgroundHole); 875 } 876 } 877 else 878 { 879 g.beginFill(nd, alpha); 880 g.drawRect(bm.left, bm.top, 881 w - bm.right - bm.left, h - bm.bottom - bm.top); 882 g.endFill(); 883 } 884 } 885 886 var borderStyle:String = getStyle("borderStyle"); 887 888 if (FlexVersion.compatibilityVersion < FlexVersion.VERSION_3_0 && (borderStyle == "alert" || borderStyle == "default") && getStyle("headerColors") == null) 889 { 890 var highlightAlphas:Array = getStyle("highlightAlphas"); 891 var highlightAlpha:Number = highlightAlphas ? highlightAlphas[0] : 0.3; 892 // edge 893 drawRoundRect( 894 0, 0, w, h, 895 { tl: radius, tr: radius, bl: 0, br: 0 }, 896 0xFFFFFF, highlightAlpha, null, 897 GradientType.LINEAR, null, 898 { x: 0, y: 1, w: w, h: h - 1, 899 r: { tl: radius, tr: radius, bl: 0, br: 0 } }); 900 } 901 } 902 903 /** 904 * @private 905 * Apply a drop shadow using a bitmap filter. 906 * 907 * Bitmap filters are slow, and their slowness is proportional 908 * to the number of pixels being filtered. 909 * For a large HaloBorder, it's wasteful to create a big shadow. 910 * Instead, we'll create the shadow offscreen 911 * and stretch it to fit the HaloBorder. 912 */ 913 mx_internal function drawDropShadow(x:Number, y:Number, 914 width:Number, height:Number, 915 tlRadius:Number, trRadius:Number, 916 brRadius:Number, blRadius:Number):void 917 { 918 // Do I need a drop shadow in the first place? If not, return 919 // immediately. 920 if (getStyle("dropShadowEnabled") == false || 921 getStyle("dropShadowEnabled") == "false" || 922 width == 0 || 923 height == 0) 924 { 925 return; 926 } 927 928 // Calculate the angle and distance for the shadow 929 var distance:Number = getStyle("shadowDistance"); 930 var direction:String = getStyle("shadowDirection"); 931 var angle:Number; 932 if (getStyle("borderStyle") == "applicationControlBar") 933 { 934 var docked:Boolean = getStyle("docked"); 935 angle = docked ? 90 : getDropShadowAngle(distance, direction); 936 distance = Math.abs(distance); 937 } 938 else 939 { 940 angle = getDropShadowAngle(distance, direction); 941 distance = Math.abs(distance) + 2; 942 } 943 944 // Create a RectangularDropShadow object, set its properties, 945 // and draw the shadow 946 if (!dropShadow) 947 dropShadow = new RectangularDropShadow(); 948 949 dropShadow.distance = distance; 950 dropShadow.angle = angle; 951 dropShadow.color = getStyle("dropShadowColor"); 952 dropShadow.alpha = 0.4; 953 954 dropShadow.tlRadius = tlRadius; 955 dropShadow.trRadius = trRadius; 956 dropShadow.blRadius = blRadius; 957 dropShadow.brRadius = brRadius; 958 959 dropShadow.drawShadow(graphics, x, y, width, height); 960 } 961 962 /** 963 * @private 964 * Convert the value of the shadowDirection property 965 * into a shadow angle. 966 */ 967 mx_internal function getDropShadowAngle(distance:Number, 968 direction:String):Number 969 { 970 if (direction == "left") 971 return distance >= 0 ? 135 : 225; 972 973 else if (direction == "right") 974 return distance >= 0 ? 45 : 315; 975 976 else // direction == "center" 977 return distance >= 0 ? 90 : 270; 978 } 979 980 /** 981 * @private 982 */ 983 mx_internal function getBackgroundColor():Object 984 { 985 var p:IUIComponent = parent as IUIComponent; 986 if (p && !p.enabled) 987 { 988 var color:Object = getStyle("backgroundDisabledColor"); 989 if (color !== null && StyleManager.isValidStyleValue(color)) 990 return color; 991 } 992 993 return getStyle("backgroundColor"); 994 } 995 996 /** 997 * @private 998 */ 999 mx_internal function getBackgroundColorMetrics():EdgeMetrics 1000 { 1001 return borderMetrics; 1002 } 1003} 1004 1005} 1006