1 /* 2 Copyright aswing.org, see the LICENCE.txt. 3 */ 4 5 import org.aswing.ASColor; 6 import org.aswing.ASFont; 7 import org.aswing.border.Border; 8 import org.aswing.ComponentDecorator; 9 import org.aswing.Container; 10 import org.aswing.ElementCreater; 11 import org.aswing.Event; 12 import org.aswing.EventDispatcher; 13 import org.aswing.geom.Dimension; 14 import org.aswing.geom.Point; 15 import org.aswing.geom.Rectangle; 16 import org.aswing.graphices.Graphics; 17 import org.aswing.graphices.SolidBrush; 18 import org.aswing.Icon; 19 import org.aswing.Insets; 20 import org.aswing.JToolTip; 21 import org.aswing.plaf.ASColorUIResource; 22 import org.aswing.plaf.ASFontUIResource; 23 import org.aswing.plaf.ComponentUI; 24 import org.aswing.RepaintManager; 25 import org.aswing.utils.Delegate; 26 import org.aswing.utils.DepthManager; 27 import org.aswing.utils.MathUtils; 28 29 /** 30 * The super class for all UIs. 31 * 32 * <p>The maximumSize and minimumSize are the component's represent max or min size. 33 * 34 * <p>You can set a Component's size max than its maximumSize, but when it was drawed, 35 * it will not max than its maximumSize.Just as its maximumSize and posited itself 36 * in that size dimension you just setted. The position is relative to <code>getAlignmentX</code> 37 * and <code>getAlignmentY<code>. 38 * 39 * @see #setSize() 40 * @see #setMaximuzedSize() 41 * @see #getAlignmentX() 42 * @see #setActive() 43 * 44 * @author iiley 45 */ 46 class org.aswing.Component extends EventDispatcher{ 47 48 /** 49 * When the component was created due to displayable 50 *<br> 51 * onCreated Event{source:Component} 52 */ 53 public static var ON_CREATED:String = "onCreated"; 54 /** 55 * When the component was removed due to undisplayable 56 *<br> 57 * onDestroy Event{source:Component} 58 */ 59 public static var ON_DESTROY:String = "onDestroy"; 60 61 /** 62 * When the component painting. 63 * onPaint Event{source:Component} 64 */ 65 public static var ON_PAINT:String = "onPaint"; 66 67 /** 68 * onShown Event{source:Component} 69 */ 70 public static var ON_SHOWN:String = "onShown"; 71 72 /** 73 * onHidden Event{source:Component} 74 */ 75 public static var ON_HIDDEN:String = "onHidden"; 76 77 /** 78 * onMoved Event{source:Component, oldPos:Point, newPos:Point} 79 */ 80 public static var ON_MOVED:String = "onMoved"; 81 82 /** 83 * onResized Event{source:Component, oldSize:Dimension, newSize:Dimension} 84 */ 85 public static var ON_RESIZED:String = "onResized"; 86 87 88 //--------------------------------------------------- 89 90 91 92 /** 93 * When the component's state changed. 94 * This is not implemented by every components. 95 * If a component implemented to fire this event, it should 96 * declare this property again. 97 *<br> 98 * onStateChanged Event{source:Component} 99 * @see org.aswing.AbstractButton#ON_STATE_CHANGED 100 * @see org.aswing.ButtonModel#addChangeListener() 101 * @see org.aswing.BoundedRangeModel#addChangeListener() 102 */ 103 public static var ON_STATE_CHANGED:String = "onStateChanged"; 104 /** 105 * just actived component has this event. 106 * onPress Event{source:Component} 107 */ 108 public static var ON_PRESS:String = "onPress"; 109 /** 110 * just actived component has this event. 111 * onRelease Event{source:Component} 112 */ 113 public static var ON_RELEASE:String = "onRelease"; 114 115 /** 116 * just actived component has this event. 117 * onReleaseOutSide Event{source:Component} 118 */ 119 public static var ON_RELEASEOUTSIDE:String = "onReleaseOutSide"; 120 /** 121 * just actived component has this event. 122 * onRollOver Event{source:Component} 123 */ 124 public static var ON_ROLLOVER:String = "onRollOver"; 125 /** 126 * just actived component has this event. 127 * onRollOut Event{source:Component} 128 */ 129 public static var ON_ROLLOUT:String = "onRollOut"; 130 131 /** 132 * just actived component has this event. 133 * onClicked Event{source:Component, clickCount:Number} 134 */ 135 public static var ON_CLICKED:String = "onClicked"; 136 137 public static var ON_SETFOCUS:String = "onSetFocus"; 138 139 public static var ON_KILLFOCUS:String = "onKillFocus"; 140 141 public static var MAX_CLICK_INTERVAL:Number = 200; 142 //------------------------------------------------------ 143 144 private static var idCounter:Number = 0; 145 //NOTE REMOVE THIS 146 //private var tabCounter:Number = 0; 147 148 public static function get creater():ElementCreater{ 149 return ElementCreater.getInstance(); 150 } 151 152 private var ui:ComponentUI; 153 private var uiProperties:Object; //a map contains ui properties 154 //ui properties 155 private var border:Border; 156 private var font:ASFont; 157 private var bgColor:ASColor; 158 private var fgColor:ASColor; 159 private var opaque:Boolean; 160 private var focusable:Boolean; 161 //------------- 162 163 private var root_mc:MovieClip; //the component mc's root 164 private var clip_mc:MovieClip; //the component's clip(mask rect) mc 165 private var trigger_mc:MovieClip; //the trigger for the press/roll... events 166 private var target_mc:MovieClip; //the component's content primary mc 167 168 private var lastClickTime:Number; 169 private var clickCount:Number; 170 171 172 private var name:String; 173 private var id:Object; 174 private var bounds:Rectangle; 175 private var enabled:Boolean; 176 private var visible:Boolean; 177 private var displayable:Boolean; 178 private var valid:Boolean; 179 private var clipMasked:Boolean; 180 private var focused:Boolean; 181 private var useHandCursor:Boolean; 182 private var triggerEnabled:Boolean; 183 184 private var alignmentX:Number; 185 private var alignmentY:Number; 186 187 private var preferredSize:Dimension; 188 private var maximumSize:Dimension; 189 private var minimumSize:Dimension; 190 191 private var parent:Container; 192 private var toolTip:JToolTip; 193 194 /** 195 * It is Abstract, you must call <code>updateUI</code> if your component 196 * has a UI, at then end of your construction. 197 */ 198 private function Component(){ 199 super(); 200 setName("Component"); 201 bounds = new Rectangle(0, 0, 0, 0); 202 enabled = true; 203 visible = true; 204 clipMasked = true; 205 displayable = false; 206 valid = false; 207 focused = false; 208 useHandCursor = false; 209 triggerEnabled = true; 210 alignmentX = 0; 211 alignmentY = 0; 212 lastClickTime = 0; 213 clickCount = 0; 214 215 if(idCounter < MathUtils.STRING_REPRESENTABLE_MAX){ 216 id = idCounter + ""; 217 idCounter++; 218 }else{ 219 id = new Object(); 220 } 221 222 //init for ui properties 223 uiProperties = new Object(); 224 uiProperties["opaque"] = false; 225 uiProperties["focusable"] = true; 226 opaque = undefined; //undefined means not defined, so will use property get from UI 227 focusable = undefined; //... 228 229 //default value is a UIResource means as same as got from UI 230 border = undefined; 231 font = ASFontUIResource.createResourceFont(ASFont.getASFont()); 232 bgColor = ASColorUIResource.createResourceColor(ASColor.WHITE); 233 fgColor = ASColorUIResource.createResourceColor(ASColor.BLACK); 234 } 235 236 237 /** 238 * Returns the component's id.(Type Object(usually a string)) 239 * Each component have their owner different id. This id is generated by Component constructor, 240 * you should not to modify its value. 241 */ 242 public function getID():Object{ 243 return id; 244 } 245 246 /** 247 * Returns the <code>UIDefaults</code> key used to 248 * look up the name of the <code>org.aswing.plaf.ComponentUI</code> 249 * class that defines the look and feel 250 * for this component. Most applications will never need to 251 * call this method. Subclasses of <code>Component</code> that support 252 * pluggable look and feel should override this method to 253 * return a <code>UIDefaults</code> key that maps to the 254 * <code>ComponentUI</code> subclass that defines their look and feel. 255 * 256 * @return the <code>UIDefaults</code> key for a 257 * <code>ComponentUI</code> subclass 258 * @see org.aswing.UIDefaults#getUI() 259 */ 260 public function getUIClassID():String{ 261 return "ComponentUI"; 262 } 263 264 /** 265 * This just for test, every component's root_mc name start with the name set here. 266 * Different Component can have same name, suggest every type of component have a name same to his class name, 267 * or you want to test, you can set any name to any component, but besure that you'd better set the same before it added to a container. 268 * @see #addTo() 269 */ 270 public function setName(name:String):Void{ 271 this.name = name; 272 } 273 274 /** 275 * @see #setName() 276 */ 277 public function getName():String{ 278 return name; 279 } 280 281 /** 282 * Resets the UI property to a value from the current look and feel. 283 * <code>Component</code> subclasses must override this method 284 * like this: 285 * <pre> 286 * public void updateUI() { 287 * setUI((SliderUI)UIManager.getUI(this); 288 * } 289 * </pre> 290 * 291 * @see #setUI() 292 * @see org.aswing.UIManager#getLookAndFeel() 293 * @see org.aswing.UIManager#getUI() 294 */ 295 public function updateUI():Void{} 296 297 298 /** 299 * Sets the look and feel delegate for this component. 300 * <code>Component</code> subclasses generally override this method 301 * to narrow the argument type. For example, in <code>JSlider</code>: 302 * <pre> 303 * public void setUI(SliderUI newUI) { 304 * super.setUI(newUI); 305 * } 306 * </pre> 307 * <p> 308 * Additionally <code>Component</code> subclasses must provide a 309 * <code>getUI</code> method that returns the correct type. For example: 310 * <pre> 311 * public SliderUI getUI() { 312 * return (SliderUI)ui; 313 * } 314 * </pre> 315 * 316 * @param newUI the new UI delegate 317 * @see #updateUI() 318 * @see UIManager#getLookAndFeel() 319 * @see UIManager#getUI() 320 */ 321 private function setUI(newUI:ComponentUI):Void{ 322 /* We do not check that the UI instance is different 323 * before allowing the switch in order to enable the 324 * same UI instance *with different default settings* 325 * to be installed. 326 */ 327 if (ui != null) { 328 ui.uninstallUI(this); 329 } 330 ui = newUI; 331 if (ui != null) { 332 ui.installUI(this); 333 if(isDisplayable()){ 334 ui.create(this); 335 } 336 } 337 revalidate(); 338 repaint(); 339 } 340 341 /** 342 * Sets the UI delegated property value.<br> 343 * If the property value in component is undefined, then the delegated value 344 * will be used. 345 * @param name the property name 346 * @param value the value 347 */ 348 public function setUIProperty(name:String, value):Void{ 349 uiProperties[name] = value; 350 } 351 352 /** 353 * Returns the UI delegated property value. 354 * @param name the property name 355 * @return the value 356 */ 357 public function getUIProperty(name:String){ 358 return uiProperties[name]; 359 } 360 361 /** 362 * Create and add this component to a Container. 363 * the method must only can call in a Container's method, 364 * else the Container's layout maybe wrong and Container event will not be called 365 * 366 * If component was added to a displayable container it could be diplayable. 367 * else it could be not diplayable. 368 * @see #isDiplayable() 369 */ 370 public function addTo(parent:Container):Void{ 371 this.parent = parent; 372 root_mc = parent.createChildMC(name); 373 if(root_mc != undefined){ 374 root_mc._x = bounds.x; 375 root_mc._y = bounds.y; 376 create(); 377 initialize(); 378 displayable = true; 379 repaint(); 380 revalidate(); 381 dispatchEvent(ON_CREATED, createEventObj(ON_CREATED)); 382 } 383 } 384 385 /** 386 * Destroy and remove this component from its parent(Container). 387 * If it has not parent, call the destroy method to remove it. 388 * @see #destroy() 389 */ 390 public function removeFromContainer():Void{ 391 if(parent != null){ 392 parent.remove(this); 393 parent = null; 394 }else{ 395 destroy(); 396 } 397 } 398 399 /** 400 * Destroy(Remove) the component's source movie clips. 401 * After this, this component was undisplayable, has no parent, has no child...<br> 402 * When a displayable component be destroied, the event onDestroy will be generated. 403 * <b> 404 * Note:You'd better not call this method directly, if you want to remove a compoent, call 405 * its method removeFromContainer, it will notify its parent to remove and then destroy it. 406 * </b> 407 * @see #removeFromContainer() 408 * @see #ON_DESTROY 409 */ 410 public function destroy():Void{ 411 if(root_mc != null){ 412 root_mc.unloadMovie(); 413 root_mc.removeMovieClip(); 414 root_mc = null; 415 displayable = false; 416 dispatchEvent(ON_DESTROY, createEventObj(ON_DESTROY)); 417 } 418 } 419 420 public function getParent():Container{ 421 return parent; 422 } 423 424 /** 425 * Set this component to have press/releaseXXx/rollXXx...event functions. 426 */ 427 private function initActive():Void{ 428 var detect_mc:MovieClip = this.trigger_mc; 429 if(detect_mc != null){ 430 detect_mc.onRollOver = Delegate.create(this, ____onRollOver); 431 detect_mc.onRollOut = Delegate.create(this, ____onRollOut); 432 detect_mc.onPress = Delegate.create(this, ____onPress); 433 detect_mc.onRelease = Delegate.create(this, ____onRelease); 434 detect_mc.onReleaseOutside = Delegate.create(this, ____onReleaseOutside); 435 detect_mc.enabled = enabled; 436 } 437 detect_mc._visible = triggerEnabled; 438 detect_mc.useHandCursor = useHandCursor; 439 } 440 441 public function setBorder(b:Border):Void{ 442 if(border != b){ 443 uninstallBorderWhenNextPaint(border); 444 border = b; 445 repaint(); 446 revalidate(); 447 } 448 } 449 450 public function getBorder():Border{ 451 return border; 452 } 453 454 public function getInsets():Insets{ 455 if(border == null){ 456 return new Insets(); 457 }else{ 458 return border.getBorderInsets(this, getSize().getBounds()); 459 } 460 } 461 462 463 /////// 464 /** 465 * create others after target_mc created. 466 */ 467 private function create():Void{ 468 trigger_mc = creater.createMC(root_mc, "trigger_mc"); 469 target_mc = creater.createMC(root_mc, "target_mc"); 470 clip_mc = creater.createMC(root_mc, "clip_mc"); 471 //focus_mc = creater.createMC(target_mc, "focus_mc"); 472 ui.create(this); 473 } 474 475 /////////// 476 /** 477 * initialize after create 478 */ 479 private function initialize():Void{ 480 //paint the clip rect content 481 var g:Graphics = new Graphics(trigger_mc); 482 g.fillRectangle(new SolidBrush(0, 0), 0, 0, 1, 1); 483 g = new Graphics(clip_mc); 484 g.fillRectangle(new SolidBrush(0, 100), 0, 0, 1, 1); 485 target_mc.setMask(clip_mc); 486 487 initActive(); 488 setEnabled(enabled); 489 setClipMasked(clipMasked); 490 root_mc._visible = this.visible; 491 } 492 493 ///////// 494 /** 495 * draw the component interface in specified bounds. 496 * Sub class should override this method if you want to draw your component's face. 497 * @param b this paiting bounds, it is opposite on the component's target_mc, 498 * that mean the bounds.x mean in target_mc's x, not the root_mc's or component's parent's x. 499 */ 500 private function paint(b:Rectangle):Void{ 501 target_mc.clear(); 502 var g:Graphics = new Graphics(target_mc); 503 504 ui.paint(this, g, b); 505 //paint border at last to make it at the top depth 506 if(border != null){ 507 // not that border is not painted in b, is painted in component's full size bounds 508 // because border are the rounds, others will painted in the border's bounds. 509 border.paintBorder(this, g, getInsets().getRoundBounds(b)); 510 } 511 dispatchEvent(ON_PAINT, createEventObj(ON_PAINT)); 512 513 } 514 515 /** 516 * Returns a graphics of the Component. 517 */ 518 public function getGraphics():Graphics{ 519 return new Graphics(target_mc); 520 } 521 522 /** 523 * Redraws the component face next frame.This method can 524 * be called often, so it needs to execute quickly. 525 * @see org.aswing.RepaintManager 526 */ 527 public function repaint():Void{ 528 RepaintManager.getInstance().addRepaintComponent(this); 529 } 530 531 /** 532 * Returns the bounds that component should paint in. 533 * <p> 534 * This is same to some paint method param b:Rectangle. 535 * So if you want to paint outside those method, you can get the 536 * rectangle from here. 537 * 538 * If this component has a little maximum size, and then current 539 * size is larger, the bounds return from this method will be related 540 * to <code>getAlignmentX<code>, <code>getAlignmentY<code> and <code>getMaximumSize<code>. 541 * @return return the rectangle that component should paint in. 542 * @see #getAlignmentX() 543 * @see #getAlignmentY() 544 * @see #getMaximumSize() 545 */ 546 public function getPaintBounds():Rectangle{ 547 return getInsets().getInsideBounds(getPaintBoundsInRoot()); 548 } 549 550 /** 551 * Redraw the component face immediately. 552 * @see #repaint() 553 */ 554 public function paintImmediately():Void{ 555 if(displayable && isVisible()){ 556 var paintBounds:Rectangle = getPaintBoundsInRoot(); 557 //locate and scale the clip mask 558 clip_mc._x = paintBounds.x; 559 clip_mc._y = paintBounds.y; 560 //paint size maybe larger than component size, if that just mask component size 561 clip_mc._width = Math.min(getWidth(), paintBounds.width); 562 clip_mc._height = Math.min(getHeight(), paintBounds.height); 563 564 trigger_mc._x = paintBounds.x; 565 trigger_mc._y = paintBounds.y; 566 trigger_mc._width = clip_mc._width; 567 trigger_mc._height = clip_mc._height; 568 569 paint(getInsets().getInsideBounds(paintBounds)); 570 } 571 } 572 573 /** 574 * get the simon-pure component paint bounds. 575 * This is include insets range. 576 * @see #getPaintBounds() 577 */ 578 private function getPaintBoundsInRoot():Rectangle{ 579 var minSize:Dimension = getMinimumSize(); 580 var maxSize:Dimension = getMaximumSize(); 581 var size:Dimension = getSize(); 582 var paintBounds:Rectangle = new Rectangle(0, 0, size.width, size.height); 583 //if it size max than maxsize, draw it as maxsize and then locate it in it size(the size max than maxsize) 584 if(size.width > maxSize.width){ 585 paintBounds.width = maxSize.width; 586 paintBounds.x = (size.width-paintBounds.width)*getAlignmentX(); 587 } 588 if(size.height > maxSize.height){ 589 paintBounds.height = maxSize.height; 590 paintBounds.y = (size.height-paintBounds.height)*getAlignmentY(); 591 } 592 //cannot paint its min than minsize 593 if(paintBounds.width < minSize.width) paintBounds.width = minSize.width; 594 if(paintBounds.height < minSize.height) paintBounds.height = minSize.height; 595 return paintBounds; 596 } 597 598 ///////// 599 /** 600 * the Component changed size. 601 * <br>default operation here is : if current size not min than getMinimumSize 602 * call repaint else set target_mc to hide. 603 */ 604 private function size():Void{ 605 repaint(); 606 invalidate(); 607 } 608 609 /** 610 * Supports deferred automatic layout. 611 * <p> 612 * Calls <code>invalidate</code> and then adds this component's 613 * <code>validateRoot</code> to a list of components that need to be 614 * validated. Validation will occur after all currently pending 615 * events have been dispatched. In other words after this method 616 * is called, the first validateRoot (if any) found when walking 617 * up the containment hierarchy of this component will be validated. 618 * By default, <code>JWindow</code>, <code>JScrollPane</code>, 619 * and <code>JTextField</code> return true 620 * from <code>isValidateRoot</code>. 621 * <p> 622 * This method will or will not automatically be called on this component 623 * when a property value changes such that size, location, or 624 * internal layout of this component has been affected.But invalidate 625 * will do called after thats method, so you want to get the contents of 626 * the GUI to update you should call this method. 627 * <p> 628 * 629 * @see #invalidate() 630 * @see #validate() 631 * @see #isValidateRoot() 632 * @see RepaintManager#addInvalidComponent() 633 */ 634 public function revalidate():Void { 635 invalidate(); 636 RepaintManager.getInstance().addInvalidComponent(this); 637 } 638 639 public function revalidateIfNecessary():Void{ 640 RepaintManager.getInstance().addInvalidComponent(this); 641 } 642 643 /** 644 * Invalidates this component. This component and all parents 645 * above it are marked as needing to be laid out. This method can 646 * be called often, so it needs to execute quickly. 647 * @see #validate() 648 * @see #doLayout() 649 * @see org.aswing.LayoutManager 650 */ 651 public function invalidate():Void { 652 valid = false; 653 if(parent != null && parent.isValid()){ 654 parent.invalidate(); 655 } 656 } 657 658 /** 659 * Ensures that this component has a valid layout. This method is 660 * primarily intended to operate on instances of <code>Container</code>. 661 * @see #invalidate() 662 * @see #doLayout() 663 * @see org.aswing.LayoutManager 664 * @see org.aswing.Container#validate() 665 */ 666 public function validate():Void { 667 if(!valid){ 668 doLayout(); 669 valid = true; 670 } 671 } 672 673 /** 674 * If this method returns true, revalidate calls by descendants of this 675 * component will cause the entire tree beginning with this root to be validated. 676 * Returns false by default. 677 * JScrollPane overrides this method and returns true. 678 * @return always returns false 679 */ 680 public function isValidateRoot():Boolean{ 681 return false; 682 } 683 684 /** 685 * Determines whether this component is valid. A component is valid 686 * when it is correctly sized and positioned within its parent 687 * container and all its children are also valid. 688 * In order to account for peers' size requirements, components are invalidated 689 * before they are first shown on the screen. By the time the parent container 690 * is fully realized, all its components will be valid. 691 * @return <code>true</code> if the component is valid, <code>false</code> 692 * otherwise 693 * @see #validate() 694 * @see #invalidate() 695 */ 696 public function isValid():Boolean{ 697 return valid; 698 } 699 700 /** 701 * layout this component. Locate this component to its location and visible its visible. 702 */ 703 public function doLayout():Void{ 704 if(displayable){ 705 root_mc._x = bounds.x; 706 root_mc._y = bounds.y; 707 root_mc._visible = visible; 708 } 709 } 710 711 /** 712 * Sets whether the component clip should be masked by its bounds. By default it is true. 713 * @param m whether the component clip should be masked. 714 * @see #isClipMasked() 715 */ 716 public function setClipMasked(m:Boolean):Void{ 717 clipMasked = m; 718 clip_mc._visible = clipMasked; 719 if(clipMasked){ 720 target_mc.setMask(clip_mc); 721 }else{ 722 target_mc.setMask(null); 723 } 724 } 725 726 /** 727 * Returns whether the component clip should be masked by its bounds. By default it is true. 728 * @return whether the component clip should be masked. 729 * @see #setClipMasked() 730 */ 731 public function isClipMasked():Boolean{ 732 return clipMasked; 733 } 734 735 /** 736 * Set a component to be hide or shown. 737 * If a component was hide, some laterly operation may not be done, 738 * they will be done when next shown, ex: repaint, doLayout .... 739 * So suggest you dont changed a component's visible frequently. 740 */ 741 public function setVisible(v:Boolean):Void{ 742 if(v != visible){ 743 visible = v; 744 if(v){ 745 dispatchEvent(ON_SHOWN, createEventObj(ON_SHOWN)); 746 }else{ 747 dispatchEvent(ON_HIDDEN, createEventObj(ON_HIDDEN)); 748 } 749 //because the repaint and some other operating only do when visible 750 //so when change to visible, must call repaint to do the operatings they had not done when invisible 751 if(visible){ 752 repaint(); 753 } 754 revalidate(); 755 } 756 } 757 758 public function isVisible():Boolean{ 759 return visible; 760 } 761 762 /** 763 * Determines whether this component is displayable. 764 * <br> 765 * A component is displayable when it is connected to a native screen resource. 766 * 767 * <br> 768 * A component is made displayable either when it is added to a displayable containment hierarchy or when its containment hierarchy is made displayable. 769 * A component is made undisplayable either when it is removed from a displayable containment hierarchy or when its containment hierarchy is made undisplayable. 770 */ 771 public function isDisplayable():Boolean{ 772 return displayable; 773 } 774 775 /** 776 * set the text format for this component.<br> 777 * this method will cause a repaint method call.<br> 778 * If you change to a larger or smaller size format, you may need to call 779 * this component's parent to doLayout to make this layout well. 780 */ 781 public function setFont(newFont:ASFont):Void{ 782 if(font != newFont){ 783 font = newFont; 784 repaint(); 785 revalidate(); 786 } 787 } 788 789 public function getFont():ASFont{ 790 return font; 791 } 792 793 public function setBackground(c:ASColor):Void{ 794 bgColor = c; 795 } 796 797 public function getBackground():ASColor{ 798 return bgColor; 799 } 800 801 public function setForeground(c:ASColor):Void{ 802 fgColor = c; 803 } 804 805 public function getForeground():ASColor{ 806 return fgColor; 807 } 808 809 /** 810 * If true the component paints every pixel within its bounds. 811 * Otherwise, the component may not paint some or all of its 812 * pixels, allowing the underlying pixels to show through. 813 * <p> 814 * The default value of this property is false for <code>JComponent</code>. 815 * However, the default value for this property on most standard 816 * <code>Component</code> subclasses (such as <code>JButton</code> and 817 * <code>JTree</code>) is look-and-feel dependent. 818 * 819 * @param b true if this component should be opaque 820 * @see #isOpaque() 821 */ 822 public function setOpaque(b:Boolean):Void { 823 if(opaque != b){ 824 opaque = b; 825 repaint(); 826 } 827 } 828 829 /** 830 * Returns true if this component is completely opaque. 831 * <p> 832 * An opaque component paints every pixel within its 833 * rectangular bounds. A non-opaque component paints only a subset of 834 * its pixels or none at all, allowing the pixels underneath it to 835 * "show through". Therefore, a component that does not fully paint 836 * its pixels provides a degree of transparency. 837 * <p> 838 * Subclasses that guarantee to always completely paint their contents 839 * should override this method and return true. 840 * 841 * @return true if this component is completely opaque 842 * @see #setOpaque() 843 */ 844 public function isOpaque():Boolean{ 845 if(opaque === undefined){ 846 return (uiProperties["opaque"] == true); 847 }else{ 848 return opaque; 849 } 850 } 851 852 /** 853 * setBounds(bounds:Rectangle)<br> 854 * setBounds(x:Number, y:Number, width:Number, height:Number) 855 * <p> 856 */ 857 public function setBounds():Void{ 858 var newBounds:Rectangle = new Rectangle(arguments[0], arguments[1], arguments[2], arguments[3]); 859 setLocation(newBounds.x, newBounds.y); 860 setSize(newBounds.width, newBounds.height); 861 } 862 863 /** 864 * Moves and resizes this component. The new location of the top-left corner is specified by x and y, and the new size is specified by width and height. 865 * 866 * <p>Stores the bounds value of this component into "return value" b and returns b. 867 * If b is null or undefined a new Rectangle object is allocated. 868 * 869 * @param b the return value, modified to the component's bounds. 870 * 871 * @see #setSize() 872 * @see #setLocation() 873 */ 874 public function getBounds(b:Rectangle):Rectangle{ 875 if(b != undefined){ 876 b.setRect(bounds); 877 return b; 878 }else{ 879 return new Rectangle(bounds.x, bounds.y, bounds.width, bounds.height); 880 } 881 } 882 883 /** 884 * setLocation(x:Number, y:Number)<br> 885 * setLocation(p:Point) 886 * <p> 887 * Set the component's location, if it is diffs from old location, invalidate it to wait validate. 888 * The top-left corner of the new location is specified by the x and y parameters 889 * in the coordinate space of this component's parent. 890 */ 891 public function setLocation():Void{ 892 var newPos:Point = new Point(arguments[0], arguments[1]); 893 var event:Event = createEventObj(ON_MOVED); 894 event.oldPos = new Point(bounds.x, bounds.y); 895 event.newPos = newPos; 896 if(!newPos.equals(event.oldPos)){ 897 bounds.setLocation(newPos); 898 dispatchEvent(ON_MOVED, event); 899 invalidate(); 900 } 901 } 902 903 /** 904 * setGlobalLocation(x:Number, y:Number)<br> 905 * setGlobalLocation(p:Point) 906 * <p> 907 * Set the component's location in global coordinate. 908 * @see setLocation() 909 * @see MovieClip.localToGlobal() 910 * @see MovieClip.globalToLocal() 911 */ 912 public function setGlobalLocation():Void{ 913 var newGlobalPos:Point = new Point(arguments[0], arguments[1]); 914 root_mc._parent.globalToLocal(newGlobalPos); 915 setLocation(newGlobalPos); 916 } 917 918 /** 919 * getLocation(p:Point)<br> 920 * getLocation() 921 * <p> 922 * Stores the location value of this component into "return value" p and returns p. 923 * If p is null or undefined a new Point object is allocated. 924 * @param p the return value, modified to the component's location. 925 */ 926 public function getLocation(p:Point):Point{ 927 if(p != undefined){ 928 p.setLocation(bounds.x, bounds.y); 929 return p; 930 }else{ 931 return new Point(bounds.x, bounds.y); 932 } 933 } 934 935 /** 936 * getGlobalLocation(p:Point)<br> 937 * getGlobalLocation() 938 * <p> 939 * Stores the global location value of this component into "return value" p and returns p. 940 * If p is null or undefined a new Point object is allocated. 941 * @param p the return value, modified to the component's global location. 942 * @see #getLocation() 943 * @see MovieClip.localToGlobal() 944 * @see MovieClip.globalToLocal() 945 */ 946 public function getGlobalLocation(p:Point):Point{ 947 var gp:Point = new Point(bounds.x, bounds.y); 948 root_mc._parent.localToGlobal(gp); 949 if(p != undefined){ 950 p.setLocation(gp); 951 return p; 952 }else{ 953 return gp; 954 } 955 } 956 957 /** 958 * setSize(width:Number, height:Number)<br> 959 * setSize(dim:Dimension) 960 * <p> 961 * Set the component's size, the width and height all will be setted to not less than zero, 962 * then set the size. 963 * You can set a Component's size max than its maximumSize, but when it was drawed, 964 * it will not max than its maximumSize.Just as its maximumSize and posited itself 965 * in that size dimension you just setted. The position is relative to <code>getAlignmentX</code> 966 * @see #getAlignmentX() 967 * @see #getAlignmentY() 968 * @see #getMinimumSize() 969 * @see #countMaximumSize() 970 * @see #getPreferredSize() 971 */ 972 public function setSize():Void{ 973 var newSize:Dimension = new Dimension(arguments[0], arguments[1]); 974 newSize.width = Math.max(0, newSize.width); 975 newSize.height = Math.max(0, newSize.height); 976 var oldSize:Dimension = new Dimension(bounds.width, bounds.height); 977 if(!newSize.equals(oldSize)){ 978 var event:Event = createEventObj(ON_RESIZED); 979 event.oldSize = oldSize; 980 event.newSize = newSize; 981 bounds.setSize(newSize); 982 size(); 983 dispatchEvent(ON_RESIZED, event); 984 } 985 } 986 987 /** 988 * getSize(s:Dimension)<br> 989 * getSize() 990 * <p> 991 * Stores the size value of this component into "return value" s and returns s. 992 * If s is null or undefined a new Dimension object is allocated. 993 * @param p the return value, modified to the component's size. 994 */ 995 public function getSize(s:Dimension):Dimension{ 996 if(s != undefined){ 997 s.setSize(bounds.width, bounds.height); 998 return s; 999 }else{ 1000 return new Dimension(bounds.width, bounds.height); 1001 } 1002 } 1003 1004 /** 1005 * Registers the text to display in a tool tip. 1006 * The text displays when the cursor lingers over the component. 1007 * @param t the string to display; if the text is null, 1008 * the tool tip is turned off for this component 1009 */ 1010 public function setToolTipText(t:String):Void{ 1011 if(t == null){ 1012 toolTip.removeFromContainer(); 1013 }else{ 1014 if(toolTip == null){ 1015 toolTip = new JToolTip(); 1016 toolTip.setTipText(t); 1017 toolTip.setComponent(this); 1018 }else{ 1019 toolTip.setTipText(t); 1020 } 1021 } 1022 } 1023 1024 /** 1025 * Returns the tooltip string that has been set with setToolTipText. 1026 * @return the text of the tool tip 1027 * @see #setToolTipText() 1028 */ 1029 public function getToolTipText():String{ 1030 if(toolTip == null){ 1031 return null; 1032 }else{ 1033 return toolTip.getTipText(); 1034 } 1035 } 1036 1037 /** 1038 * @param ax 1039 * @see #getAlignmentX() 1040 */ 1041 public function setAlignmentX(ax:Number):Void{ 1042 if(alignmentX != ax){ 1043 alignmentX = ax; 1044 repaint(); 1045 } 1046 } 1047 1048 /** 1049 * @param ay 1050 * @see #getAlignmentY() 1051 */ 1052 public function setAlignmentY(ay:Number):Void{ 1053 if(alignmentY != ay){ 1054 alignmentY = ay; 1055 repaint(); 1056 } 1057 } 1058 1059 /** 1060 * Returns the alignment along the x axis. 1061 * This specifies how the component would like to be aligned relative 1062 * to its size when its size is maxer than its maximumSize. 1063 * The value should be a number between 0 and 1 where 0 1064 * represents alignment start from left, 1 is aligned the furthest 1065 * away from the left, 0.5 is centered, etc. 1066 * @return the alignment along the x axis, 0 by default 1067 */ 1068 public function getAlignmentX():Number{ 1069 return alignmentX; 1070 } 1071 1072 /** 1073 * Returns the alignment along the y axis. 1074 * This specifies how the component would like to be aligned relative 1075 * to its size when its size is maxer than its maximumSize. 1076 * The value should be a number between 0 and 1 where 0 1077 * represents alignment start from top, 1 is aligned the furthest 1078 * away from the top, 0.5 is centered, etc. 1079 * @return the alignment along the y axis, 0 by default 1080 */ 1081 public function getAlignmentY():Number{ 1082 return alignmentY; 1083 } 1084 1085 /** 1086 * get the minimumSize from ui, if ui is null then Returns getInsets().roundsSize(new Dimension(0, 0)). 1087 */ 1088 private function countMinimumSize():Dimension{ 1089 if(ui != null){ 1090 return ui.getMinimumSize(this); 1091 }else{ 1092 return getInsets().roundsSize(new Dimension(0, 0)); 1093 } 1094 } 1095 1096 /** 1097 * get the maximumSize from ui, if ui is null then new Dimension(Number.MAX_VALUE, Number.MAX_VALUE); 1098 */ 1099 private function countMaximumSize():Dimension{ 1100 if(ui != null){ 1101 return ui.getMaximumSize(this); 1102 }else{ 1103 return new Dimension(Number.MAX_VALUE, Number.MAX_VALUE); 1104 } 1105 } 1106 1107 /** 1108 * get the preferredSize from ui, if ui is null then just return the current size 1109 */ 1110 private function countPreferredSize():Dimension{ 1111 if(ui != null){ 1112 return ui.getPreferredSize(this); 1113 }else{ 1114 return getSize(); 1115 } 1116 } 1117 1118 /** 1119 * @see #setMinimumSize() 1120 */ 1121 public function getMinimumSize():Dimension{ 1122 if(minimumSize != null){ 1123 return new Dimension(minimumSize); 1124 }else{ 1125 return countMinimumSize(); 1126 } 1127 } 1128 1129 /** 1130 * @see #setMaximumSize() 1131 */ 1132 public function getMaximumSize():Dimension{ 1133 if(maximumSize != null){ 1134 return new Dimension(maximumSize); 1135 }else{ 1136 return countMaximumSize(); 1137 } 1138 } 1139 1140 /** 1141 * @see #setPreferredSize() 1142 */ 1143 public function getPreferredSize():Dimension{ 1144 if(preferredSize != null){ 1145 return new Dimension(preferredSize); 1146 }else{ 1147 return countPreferredSize(); 1148 } 1149 } 1150 1151 /** 1152 * setMinimumSize(d:Dimension)<br> 1153 * setMinimumSize(width:Number, height:Number) 1154 * <p> 1155 * Set the minimumSize, then the component's minimumSize is 1156 * specified. otherwish getMinimumSize will can the count method. 1157 * @param arguments null to set minimumSize null then getMinimumSize will can the layout. 1158 * others set the minimumSize to be a specified size. 1159 * @see #getMinimumSize() 1160 */ 1161 public function setMinimumSize():Void{ 1162 if(arguments[0] == null){ 1163 minimumSize = null; 1164 } 1165 else if(arguments[1]!=null){ 1166 minimumSize = new Dimension(arguments[0], arguments[1]); 1167 } 1168 else{ 1169 minimumSize=new Dimension(arguments[0].width, arguments[0].height); 1170 } 1171 } 1172 1173 /** 1174 * setMaximumSize(d:Dimension)<br> 1175 * setMaximumSize(width:Number, height:Number)<br> 1176 * <p> 1177 * Set the maximumSize, then the component's maximumSize is 1178 * specified. otherwish getMaximumSize will can count method. 1179 * 1180 * @param arguments null to set maximumSize null to make getMaximumSize will can the layout. 1181 * others set the maximumSize to be a specified size. 1182 * @see #getMaximumSize() 1183 * @see #MaximumSize() 1184 */ 1185 public function setMaximumSize():Void{ 1186 if(arguments[0] == null){ 1187 maximumSize = null; 1188 } 1189 else if(arguments[1]!=null){ 1190 maximumSize = new Dimension(arguments[0], arguments[1]); 1191 } 1192 else{ 1193 maximumSize=new Dimension(arguments[0].width,arguments[0].height); 1194 } 1195 } 1196 1197 /** 1198 * setPreferredSize(d:Dimension)<br> 1199 * setPreferredSize(width:Number, height:Number)<br> 1200 * <p> 1201 * Set the preferredSize, then the component's preferredSize is 1202 * specified. otherwish getPreferredSize will count method. 1203 * 1204 * @param arguments null to set preferredSize null to make getPreferredSize will can the layout, 1205 * others set the preferredSize to be a specified size. 1206 * @see #getPreferredSize() 1207 */ 1208 public function setPreferredSize():Void{ 1209 if(arguments[0] == null){ 1210 preferredSize = null; 1211 } 1212 else if(arguments[1]!=null){ 1213 preferredSize = new Dimension(arguments[0], arguments[1]); 1214 } 1215 else{ 1216 preferredSize=new Dimension(arguments[0].width,arguments[0].height); 1217 } 1218 } 1219 1220 public function getWidth():Number{ 1221 return bounds.width; 1222 } 1223 1224 public function getHeight():Number{ 1225 return bounds.height; 1226 } 1227 1228 public function getX():Number{ 1229 return bounds.x; 1230 } 1231 1232 public function getY():Number{ 1233 return bounds.y; 1234 } 1235 1236 /** 1237 * Enable or disable the component. 1238 * <p> 1239 * If a component is disabled, it will not fire mouse events. 1240 * And some component will has different interface when enabled or disabled. 1241 * But it will also eat mouse clicks when disable even it will not fire mouse events. 1242 * @param b true to enable the component, false to disable it. 1243 * @see #setTriggerEnabled() 1244 * @see #ON_ROLLOVER 1245 * @see #ON_ROLLOUT 1246 * @see #ON_PRESS 1247 * @see #ON_RELEASE 1248 * @see #ON_RELEASEOUTSIDE 1249 */ 1250 public function setEnabled(b:Boolean):Void{ 1251 trigger_mc.enabled = b; 1252 enabled = b; 1253 } 1254 1255 /** 1256 * Returns whether the component is enabled. 1257 * @see #setEnabled() 1258 */ 1259 public function isEnabled():Boolean{ 1260 return enabled; 1261 } 1262 1263 /** 1264 * Sets whether the component trigger be enabled. 1265 * <P> 1266 * If it is enabled, it will fire events when mouse roll, press on the component, of course 1267 * it eats the mouse clicks so its container may not got clicks. 1268 * If it is disabled, it will not fire events when mouse roll press on, 1269 * And the importance is that it will not eat the mouse clicks. 1270 * <P> 1271 * Default value is true. 1272 * @param b true to enable trigger, false to disable it. 1273 * @see #ON_ROLLOVER 1274 * @see #ON_ROLLOUT 1275 * @see #ON_PRESS 1276 * @see #ON_RELEASE 1277 * @see #ON_RELEASEOUTSIDE 1278 */ 1279 public function setTriggerEnabled(b:Boolean):Void{ 1280 triggerEnabled = b; 1281 trigger_mc._visible = b; 1282 } 1283 1284 /** 1285 * Returns is trigger enabled. 1286 * @see #setTriggerEnabled() 1287 */ 1288 public function isTriggerEnabled():Boolean{ 1289 return triggerEnabled; 1290 } 1291 1292 /** 1293 * Sets whether use hand cursor when mouse move on this component. 1294 * Default is false. 1295 * @param b true to use hand cursor when mouse move on this component, false not. 1296 */ 1297 public function setUseHandCursor(b:Boolean):Void{ 1298 useHandCursor = b; 1299 trigger_mc.useHandCursor = b; 1300 } 1301 1302 /** 1303 * @return whether use hand cursor when mouse move on this component. 1304 * @see #setUseHandCursor() 1305 */ 1306 public function isUseHandCursor():Boolean{ 1307 return useHandCursor; 1308 } 1309 1310 /** 1311 * Creates and returns an empty MovieClip from the Component's target MovieClip. 1312 * <p> 1313 * Note that if you create an new MC for a border or icon you should remove them in your 1314 * uninstallXXx method of them. 1315 * @param nameStart the prefix of the created MovieClip's name. 1316 * @param depth the depth of the created MovieClip. 1317 */ 1318 public function createMovieClip(nameStart:String, depth:Number):MovieClip{ 1319 return creater.createMC(target_mc, nameStart, depth); 1320 } 1321 1322 /** 1323 * Attaches and returns a MovieClip from the Component's target MovieClip. 1324 * <p> 1325 * Note that if you attach an new MC for a border or icon you should remove them in your 1326 * uninstallXXx method of them. 1327 * @param linkage the linkage id of the MovieClip in your Symbol Library. 1328 * @param nameStart the prefix of the attached MovieClip's name. 1329 * @param depth the depth of the attached MovieClip. 1330 */ 1331 public function attachMovieClip(linkage:String, nameStart:String, depth:Number):MovieClip{ 1332 return creater.attachMC(target_mc, linkage, nameStart, depth); 1333 } 1334 1335 /** 1336 * Creates and returns an textfiled from the Component's target MovieClip. 1337 * <p> 1338 * Note that if you create an new textfiled for a border or icon you should remove them in your 1339 * uninstallXXx method of them. 1340 * @param nameStart the prefix of the created textfiled's name. 1341 * @param depth the depth of the created textfiled. 1342 */ 1343 public function createTextField(nameStart:String, depth:Number):TextField{ 1344 return creater.createTF(target_mc, nameStart, depth); 1345 } 1346 1347 /** 1348 * Returns the component's mc's depth. 1349 * It will return undefined when this component is displayable. 1350 */ 1351 public function getDepth():Number{ 1352 return root_mc.getDepth(); 1353 } 1354 1355 /** 1356 * Swap the component's mc's depth. This is only effective when this component is displayable. 1357 */ 1358 public function swapDepths(target):Void{ 1359 root_mc.swapDepths(target); 1360 } 1361 1362 /** 1363 * Brings this component at top depth of all brothers. 1364 * This is only effective when this component is displayable. 1365 */ 1366 public function bringToTopDepth():Void{ 1367 DepthManager.bringToTop(root_mc); 1368 } 1369 1370 /** 1371 * Brings this component at bottom depth of all brothers. 1372 * This is only effective when this component is displayable. 1373 */ 1374 public function bringToBottomDepth():Void{ 1375 DepthManager.bringToBottom(root_mc); 1376 } 1377 1378 /** 1379 * Returns the component's clip mc hitTest() 1380 */ 1381 public function hitTest(x, y, shapeFlag):Boolean{ 1382 return clip_mc.hitTest(x, y, shapeFlag); 1383 } 1384 1385 /** 1386 * Returns the position of the mouse in the Component area. 1387 * (0, 0) is the top left of the component bounds. 1388 * @return the position of the mouse in the Component area. 1389 */ 1390 public function getMousePosition():Point{ 1391 return new Point(root_mc._xmouse, root_mc._ymouse); 1392 } 1393 1394 public function globalToComponent(p:Point):Point{ 1395 var np:Point = new Point(p.x, p.y); 1396 root_mc.globalToLocal(np); 1397 return np; 1398 } 1399 1400 public function componentToGlobal(p:Point):Point{ 1401 var np:Point = new Point(p.x, p.y); 1402 root_mc.localToGlobal(np); 1403 return np; 1404 } 1405 1406 public function toString():String{ 1407 return "Component - " + name + " mc:" + root_mc; 1408 } 1409 1410 public function isFocusable(Void):Boolean{ 1411 if(focusable === undefined){ 1412 return (uiProperties["focusable"] == true); 1413 }else{ 1414 return focusable; 1415 } 1416 } 1417 1418 public function setFocusable(val:Boolean):Void{ 1419 focusable=val; 1420 } 1421 1422 public function isFocused(Void):Boolean{ 1423 return focused; 1424 } 1425 1426 public function setFocus(val:Boolean):Void{ 1427 if(val){ 1428 focused=val; 1429 __onSetFocus(); 1430 } 1431 else{ 1432 focused=val; 1433 __onKillFocus(); 1434 } 1435 } 1436 /* 1437 public function getFocusClip(Void):MovieClip{ 1438 return focus_mc; 1439 } 1440 */ 1441 /** 1442 * @see ComponentDecorator#removeBorderWhenNextPaint() 1443 */ 1444 private function uninstallBorderWhenNextPaint(border:Border):Void{ 1445 ComponentDecorator.removeBorderWhenNextPaint(this, border); 1446 } 1447 /** 1448 * @see ComponentDecorator#removeIconWhenNextPaint() 1449 */ 1450 private function uninstallIconWhenNextPaint(icon:Icon):Void{ 1451 ComponentDecorator.removeIconWhenNextPaint(this, icon); 1452 } 1453 1454 /** 1455 * Notifies all listeners that have registered interest for 1456 * notification on this event type. 1457 */ 1458 private function fireStateChanged():Void{ 1459 dispatchEvent(ON_STATE_CHANGED, createEventObj(ON_STATE_CHANGED)); 1460 } 1461 1462 1463 //-----------------------component's event method------------- 1464 private function __onPress():Void{ 1465 parent.__onChildPressed(this); 1466 dispatchEvent(ON_PRESS, createEventObj(ON_PRESS)); 1467 1468 //FocusManager.getCurrentManager().resetFocusManager(); 1469 } 1470 private function __onRelease():Void{ 1471 dispatchEvent(ON_RELEASE, createEventObj(ON_RELEASE)); 1472 } 1473 private function __onReleaseOutside():Void{ 1474 dispatchEvent(ON_RELEASEOUTSIDE, createEventObj(ON_RELEASEOUTSIDE)); 1475 } 1476 private function __onRollOver():Void{ 1477 dispatchEvent(ON_ROLLOVER, createEventObj(ON_ROLLOVER)); 1478 } 1479 private function __onRollOut():Void{ 1480 dispatchEvent(ON_ROLLOUT, createEventObj(ON_ROLLOUT)); 1481 } 1482 private function __onClick():Void{ 1483 var time:Number = getTimer(); 1484 if(time - lastClickTime < MAX_CLICK_INTERVAL){ 1485 clickCount++; 1486 }else{ 1487 clickCount = 1; 1488 } 1489 lastClickTime = time; 1490 var obj:Event = createEventObj(ON_CLICKED); 1491 obj.clickCount = clickCount; 1492 dispatchEvent(ON_CLICKED, obj); 1493 } 1494 private function __onSetFocus():Void{ 1495 dispatchEvent(ON_SETFOCUS, createEventObj(ON_SETFOCUS)); 1496 } 1497 private function __onKillFocus():Void{ 1498 dispatchEvent(ON_KILLFOCUS, createEventObj(ON_KILLFOCUS)); 1499 } 1500 1501 //-----------------------mc events deletage, can't override these method------------- 1502 private function ____onPress():Void{ 1503 __onPress(); 1504 } 1505 1506 private function ____onRelease():Void{ 1507 __onRelease(); 1508 __onClick(); 1509 } 1510 1511 private function ____onReleaseOutside():Void{ 1512 __onReleaseOutside(); 1513 } 1514 1515 private function ____onRollOver():Void{ 1516 __onRollOver(); 1517 } 1518 1519 private function ____onRollOut():Void{ 1520 __onRollOut(); 1521 } 1522 1523 } 1524