1 /**************************************************************************** 2 Copyright (c) 2011-2012 cocos2d-x.org 3 Copyright (c) 2013-2014 Chukong Technologies Inc. 4 5 http://www.cocos2d-x.org 6 7 Permission is hereby granted, free of charge, to any person obtaining a copy 8 of this software and associated documentation files (the "Software"), to deal 9 in the Software without restriction, including without limitation the rights 10 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 copies of the Software, and to permit persons to whom the Software is 12 furnished to do so, subject to the following conditions: 13 14 The above copyright notice and this permission notice shall be included in 15 all copies or substantial portions of the Software. 16 17 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23 THE SOFTWARE. 24 ****************************************************************************/ 25 26 ccui._FocusNavigationController = cc.Class.extend({ 27 _keyboardListener: null, 28 _firstFocusedWidget: null, 29 _enableFocusNavigation: false, 30 _keyboardEventPriority: 1, 31 32 enableFocusNavigation: function(flag){ 33 if (this._enableFocusNavigation === flag) 34 return; 35 36 this._enableFocusNavigation = flag; 37 if (flag) 38 this._addKeyboardEventListener(); 39 else 40 this._removeKeyboardEventListener(); 41 }, 42 43 _setFirstFocsuedWidget: function(widget){ 44 this._firstFocusedWidget = widget; 45 }, 46 47 _onKeyPressed: function(keyCode, event){ 48 if (this._enableFocusNavigation && this._firstFocusedWidget) { 49 if (keyCode === cc.KEY.dpadDown) { 50 this._firstFocusedWidget = this._firstFocusedWidget.findNextFocusedWidget(ccui.Widget.DOWN, this._firstFocusedWidget); 51 } 52 if (keyCode === cc.KEY.dpadUp){ 53 this._firstFocusedWidget = this._firstFocusedWidget.findNextFocusedWidget(ccui.Widget.UP, this._firstFocusedWidget); 54 } 55 if (keyCode === cc.KEY.dpadLeft) { 56 this._firstFocusedWidget = this._firstFocusedWidget.findNextFocusedWidget(ccui.Widget.LEFT, this._firstFocusedWidget); 57 } 58 if (keyCode === cc.KEY.dpadRight) { 59 this._firstFocusedWidget = this._firstFocusedWidget.findNextFocusedWidget(ccui.Widget.RIGHT, this._firstFocusedWidget); 60 } 61 } 62 }, 63 64 _addKeyboardEventListener: function(){ 65 if (!this._keyboardListener) { 66 this._keyboardListener = cc.EventListener.create({ 67 event: cc.EventListener.KEYBOARD, 68 onKeyReleased: this._onKeyPressed.bind(this) 69 }); 70 cc.eventManager.addListener(this._keyboardListener, this._keyboardEventPriority); 71 } 72 }, 73 74 _removeKeyboardEventListener: function(){ 75 if (this._keyboardListener) { 76 cc.eventManager.removeEventListener(this._keyboardListener); 77 this._keyboardListener = null; 78 } 79 } 80 }); 81 82 ccui.__LAYOUT_COMPONENT_NAME = "__ui_layout"; 83 84 /** 85 * The base class for ccui controls and layout 86 * @sample 87 * var uiWidget = new ccui.Widget(); 88 * this.addChild(uiWidget); 89 * @class 90 * @extends ccui.ProtectedNode 91 * 92 * @property {Number} xPercent - Position x in percentage of width 93 * @property {Number} yPercent - Position y in percentage of height 94 * @property {Number} widthPercent - Width in percentage of parent width 95 * @property {Number} heightPercent - Height in percentage of parent height 96 * @property {ccui.Widget} widgetParent - <@readonly> The direct parent when it's a widget also, otherwise equals null 97 * @property {Boolean} enabled - Indicate whether the widget is enabled 98 * @property {Boolean} focused - Indicate whether the widget is focused 99 * @property {ccui.Widget.SIZE_ABSOLUTE|ccui.Widget.SIZE_PERCENT} sizeType - The size type of the widget 100 * @property {ccui.Widget.TYPE_WIDGET|ccui.Widget.TYPE_CONTAINER} widgetType - <@readonly> The type of the widget 101 * @property {Boolean} touchEnabled - Indicate whether touch events are enabled 102 * @property {Boolean} updateEnabled - Indicate whether the update function is scheduled 103 * @property {Boolean} bright - Indicate whether the widget is bright 104 * @property {String} name - The name of the widget 105 * @property {Number} actionTag - The action tag of the widget 106 */ 107 ccui.Widget = ccui.ProtectedNode.extend(/** @lends ccui.Widget# */{ 108 _enabled: true, ///< Highest control of widget 109 _bright: true, ///< is this widget bright 110 _touchEnabled: false, ///< is this widget touch endabled 111 112 _brightStyle: null, ///< bright style 113 114 _touchBeganPosition: null, ///< touch began point 115 _touchMovePosition: null, ///< touch moved point 116 _touchEndPosition: null, ///< touch ended point 117 118 _touchEventListener: null, 119 _touchEventSelector: null, 120 121 _name: "default", 122 _widgetType: null, 123 _actionTag: 0, 124 _customSize: null, 125 _layoutParameterDictionary: null, 126 _layoutParameterType:0, 127 128 _focused: false, 129 _focusEnabled: true, 130 131 _ignoreSize: false, 132 _affectByClipping: false, 133 134 _sizeType: null, 135 _sizePercent: null, 136 _positionType: null, 137 _positionPercent: null, 138 _hit: false, 139 _nodes: null, 140 _touchListener: null, 141 _className: "Widget", 142 _flippedX: false, 143 _flippedY: false, 144 _opacity: 255, 145 _highlight: false, 146 147 _touchEventCallback: null, 148 _clickEventListener: null, 149 150 _propagateTouchEvents: true, 151 _unifySize: false, 152 153 _callbackName: null, 154 _callbackType: null, 155 _usingLayoutComponent: false, 156 _inViewRect: true, 157 158 /** 159 * Constructor function, override it to extend the construction behavior, remember to call "this._super()" in the extended "ctor" function. 160 * @function 161 */ 162 ctor: function () { 163 cc.ProtectedNode.prototype.ctor.call(this); 164 this._brightStyle = ccui.Widget.BRIGHT_STYLE_NONE; 165 this._touchBeganPosition = cc.p(0, 0); 166 this._touchMovePosition = cc.p(0, 0); 167 this._touchEndPosition = cc.p(0, 0); 168 this._widgetType = ccui.Widget.TYPE_WIDGET; 169 this._customSize = cc.size(0, 0); 170 this._layoutParameterDictionary = {}; 171 this._sizeType = ccui.Widget.SIZE_ABSOLUTE; 172 this._sizePercent = cc.p(0, 0); 173 this._positionType = ccui.Widget.POSITION_ABSOLUTE; 174 this._positionPercent = cc.p(0, 0); 175 this._nodes = []; 176 this._layoutParameterType = ccui.LayoutParameter.NONE; 177 this.init(); //TODO 178 }, 179 180 /** 181 * initializes state of widget. please do not call this function by yourself, you should pass the parameters to constructor to initialize it
. 182 * @returns {boolean} 183 */ 184 init: function () { 185 if (cc.ProtectedNode.prototype.init.call(this)) { 186 this._layoutParameterDictionary = {}; 187 this._initRenderer(); 188 this.setBright(true); 189 190 this.onFocusChanged = this.onFocusChange.bind(this); 191 this.onNextFocusedWidget = null; 192 this.setAnchorPoint(cc.p(0.5, 0.5)); 193 194 this.ignoreContentAdaptWithSize(true); 195 return true; 196 } 197 return false; 198 }, 199 200 /** 201 * Calls updateSizeAndPosition and its parent's onEnter 202 * @override 203 */ 204 onEnter: function () { 205 var locListener = this._touchListener; 206 if (locListener && !locListener._isRegistered() && this._touchEnabled) 207 cc.eventManager.addListener(locListener, this); 208 if(!this._usingLayoutComponent) 209 this.updateSizeAndPosition(); 210 cc.ProtectedNode.prototype.onEnter.call(this); 211 }, 212 213 /** 214 * Calls unscheduleUpdate and its parent's onExit 215 * @override 216 */ 217 onExit: function(){ 218 this.unscheduleUpdate(); 219 cc.ProtectedNode.prototype.onExit.call(this); 220 }, 221 222 _getOrCreateLayoutComponent: function(){ 223 var layoutComponent = this.getComponent(ccui.__LAYOUT_COMPONENT_NAME); 224 if (null == layoutComponent){ 225 layoutComponent = new ccui.LayoutComponent(); 226 this.addComponent(layoutComponent); 227 } 228 return layoutComponent; 229 }, 230 231 /** 232 * The direct parent when it's a widget also, otherwise equals null 233 * @returns {ccui.Widget|null} 234 */ 235 getWidgetParent: function () { 236 var widget = this.getParent(); 237 if (widget instanceof ccui.Widget) 238 return widget; 239 return null; 240 }, 241 242 _updateContentSizeWithTextureSize: function(size){ 243 if(this._unifySize){ 244 this.setContentSize(size); 245 return; 246 } 247 this.setContentSize(this._ignoreSize ? size : this._customSize); 248 }, 249 250 _isAncestorsEnabled: function(){ 251 var parentWidget = this._getAncensterWidget(this); 252 if (parentWidget == null) 253 return true; 254 if (parentWidget && !parentWidget.isEnabled()) 255 return false; 256 257 return parentWidget._isAncestorsEnabled(); 258 }, 259 260 /** 261 * Allow widget touch events to propagate to its parents. Set false will disable propagation 262 * @since v3.2 263 * @param {Boolean} isPropagate 264 */ 265 setPropagateTouchEvents: function(isPropagate){ 266 this._propagateTouchEvents = isPropagate; 267 }, 268 269 /** 270 * Return whether the widget is propagate touch events to its parents or not 271 * @since v3.2 272 * @returns {boolean} 273 */ 274 isPropagateTouchEvents: function(){ 275 return this._propagateTouchEvents; 276 }, 277 278 /** 279 * Specify widget to swallow touches or not 280 * @since v3.2 281 * @param {Boolean} swallow 282 */ 283 setSwallowTouches: function(swallow){ 284 if (this._touchListener) 285 this._touchListener.setSwallowTouches(swallow); 286 }, 287 288 /** 289 * Return whether the widget is swallowing touch or not 290 * @since v3.2 291 * @returns {boolean} 292 */ 293 isSwallowTouches: function(){ 294 if (this._touchListener){ 295 //return true; //todo need test 296 return this._touchListener.isSwallowTouches(); 297 } 298 return false; 299 }, 300 301 _getAncensterWidget: function(node){ 302 if (null == node) 303 return null; 304 305 var parent = node.getParent(); 306 if (null == parent) 307 return null; 308 309 if (parent instanceof ccui.Widget) 310 return parent; 311 else 312 return this._getAncensterWidget(parent.getParent()); 313 }, 314 315 _isAncestorsVisible: function(node){ 316 if (null == node) 317 return true; 318 319 var parent = node.getParent(); 320 321 if (parent && !parent.isVisible()) 322 return false; 323 return this._isAncestorsVisible(parent); 324 }, 325 326 _cleanupWidget: function(){ 327 //clean up _touchListener 328 this._eventDispatcher.removeEventListener(this._touchListener); 329 this._touchEnabled = false; 330 this._touchListener = null; 331 332 //cleanup focused widget and focus navigation controller 333 if (ccui.Widget._focusedWidget === this){ 334 ccui.Widget._focusedWidget = null; 335 ccui.Widget._focusNavigationController = null; 336 } 337 }, 338 339 /** 340 * <p> 341 * Sets whether the widget is enabled <br/> 342 * true if the widget is enabled, widget may be touched , false if the widget is disabled, widget cannot be touched. <br/> 343 * The default value is true, a widget is default to enabled 344 * </p> 345 * @param {Boolean} enabled 346 */ 347 setEnabled: function (enabled) { 348 this._enabled = enabled; 349 }, 350 351 /** 352 * initializes renderer of widget. 353 */ 354 _initRenderer: function () {}, 355 356 /** 357 * Sets _customSize of ccui.Widget, if ignoreSize is true, the content size is its renderer's contentSize, otherwise the content size is parameter. 358 * and updates size percent by parent content size. At last, updates its children's size and position. 359 * @param {cc.Size|Number} contentSize content size or width of content size 360 * @param {Number} [height] 361 * @override 362 */ 363 setContentSize: function(contentSize, height){ 364 var locWidth = (height === undefined) ? contentSize.width : contentSize; 365 var locHeight = (height === undefined) ? contentSize.height : height; 366 cc.Node.prototype.setContentSize.call(this, locWidth, locHeight); 367 368 this._customSize.width = locWidth; 369 this._customSize.height = locHeight; 370 if(this._unifySize){ 371 //unify size logic 372 } else if (this._ignoreSize){ 373 this._contentSize = this.getVirtualRendererSize(); 374 } 375 if (!this._usingLayoutComponent && this._running) { 376 var widgetParent = this.getWidgetParent(); 377 var pSize = widgetParent ? widgetParent.getContentSize() : this._parent.getContentSize(); 378 this._sizePercent.x = (pSize.width > 0.0) ? locWidth / pSize.width : 0.0; 379 this._sizePercent.y = (pSize.height > 0.0) ? locHeight / pSize.height : 0.0; 380 } 381 this._onSizeChanged(); 382 }, 383 384 _setWidth: function (w) { 385 cc.Node.prototype._setWidth.call(this, w); 386 this._customSize.width = w; 387 if(this._unifySize){ 388 //unify size logic 389 } else if (this._ignoreSize){ 390 this._contentSize = this.getVirtualRendererSize(); 391 } 392 393 if (!this._usingLayoutComponent && this._running) { 394 var widgetParent = this.getWidgetParent(); 395 var locWidth = widgetParent ? widgetParent.width : this._parent.width; 396 this._sizePercent.x = locWidth > 0 ? this._customSize.width / locWidth : 0; 397 } 398 this._onSizeChanged(); 399 }, 400 _setHeight: function (h) { 401 cc.Node.prototype._setHeight.call(this, h); 402 this._customSize.height = h; 403 if(this._unifySize){ 404 //unify size logic 405 } else if (this._ignoreSize){ 406 this._contentSize = this.getVirtualRendererSize(); 407 } 408 409 if (!this._usingLayoutComponent && this._running) { 410 var widgetParent = this.getWidgetParent(); 411 var locH = widgetParent ? widgetParent.height : this._parent.height; 412 this._sizePercent.y = locH > 0 ? this._customSize.height / locH : 0; 413 } 414 this._onSizeChanged(); 415 }, 416 417 /** 418 * Changes the percent that is widget's percent size 419 * @param {cc.Point} percent that is widget's percent size, width and height value from 0 to 1. 420 */ 421 setSizePercent: function (percent) { 422 if(this._usingLayoutComponent){ 423 var component = this._getOrCreateLayoutComponent(); 424 component.setUsingPercentContentSize(true); 425 component.setPercentContentSize(percent); 426 component.refreshLayout(); 427 return; 428 } 429 430 this._sizePercent.x = percent.x; 431 this._sizePercent.y = percent.y; 432 var width = this._customSize.width, height = this._customSize.height; 433 if (this._running) { 434 var widgetParent = this.getWidgetParent(); 435 if (widgetParent) { 436 width = widgetParent.width * percent.x; 437 height = widgetParent.height * percent.y; 438 } else { 439 width = this._parent.width * percent.x; 440 height = this._parent.height * percent.y; 441 } 442 } 443 if (this._ignoreSize) 444 this.setContentSize(this.getVirtualRendererSize()); 445 else 446 this.setContentSize(width, height); 447 448 this._customSize.width = width; 449 this._customSize.height = height; 450 }, 451 452 _setWidthPercent: function (percent) { 453 this._sizePercent.x = percent; 454 var width = this._customSize.width; 455 if (this._running) { 456 var widgetParent = this.getWidgetParent(); 457 width = (widgetParent ? widgetParent.width : this._parent.width) * percent; 458 } 459 if (this._ignoreSize) 460 this._setWidth(this.getVirtualRendererSize().width); 461 else 462 this._setWidth(width); 463 this._customSize.width = width; 464 }, 465 _setHeightPercent: function (percent) { 466 this._sizePercent.y = percent; 467 var height = this._customSize.height; 468 if (this._running) { 469 var widgetParent = this.getWidgetParent(); 470 height = (widgetParent ? widgetParent.height : this._parent.height) * percent; 471 } 472 if (this._ignoreSize) 473 this._setHeight(this.getVirtualRendererSize().height); 474 else 475 this._setHeight(height); 476 this._customSize.height = height; 477 }, 478 479 /** 480 * updates its size by size type and its position by position type. 481 * @param {cc.Size} [parentSize] parent size 482 */ 483 updateSizeAndPosition: function (parentSize) { 484 if(!parentSize){ 485 var widgetParent = this.getWidgetParent(); 486 if(widgetParent) 487 parentSize = widgetParent.getLayoutSize(); 488 else 489 parentSize = this._parent.getContentSize(); 490 } 491 492 switch (this._sizeType) { 493 case ccui.Widget.SIZE_ABSOLUTE: 494 if(this._ignoreSize) 495 this.setContentSize(this.getVirtualRendererSize()); 496 else 497 this.setContentSize(this._customSize); 498 this._sizePercent.x = (parentSize.width > 0) ? this._customSize.width / parentSize.width : 0; 499 this._sizePercent.y = (parentSize.height > 0) ? this._customSize.height / parentSize.height : 0; 500 break; 501 case ccui.Widget.SIZE_PERCENT: 502 var cSize = cc.size(parentSize.width * this._sizePercent.x , parentSize.height * this._sizePercent.y); 503 if(this._ignoreSize) 504 this.setContentSize(this.getVirtualRendererSize()); 505 else 506 this.setContentSize(cSize); 507 this._customSize.width = cSize.width; 508 this._customSize.height = cSize.height; 509 break; 510 default: 511 break; 512 } 513 this._onSizeChanged(); 514 var absPos = this.getPosition(); 515 switch (this._positionType) { 516 case ccui.Widget.POSITION_ABSOLUTE: 517 if (parentSize.width <= 0 || parentSize.height <= 0) { 518 this._positionPercent.x = this._positionPercent.y = 0; 519 } else { 520 this._positionPercent.x = absPos.x / parentSize.width; 521 this._positionPercent.y = absPos.y / parentSize.height; 522 } 523 break; 524 case ccui.Widget.POSITION_PERCENT: 525 absPos = cc.p(parentSize.width * this._positionPercent.x, parentSize.height * this._positionPercent.y); 526 break; 527 default: 528 break; 529 } 530 if(this._parent instanceof ccui.ImageView){ 531 var renderer = this._parent._imageRenderer; 532 if(renderer && !renderer._textureLoaded) 533 return; 534 } 535 this.setPosition(absPos); 536 }, 537 538 /**TEXTURE_RES_TYPE 539 * Changes the size type of widget. 540 * @param {ccui.Widget.SIZE_ABSOLUTE|ccui.Widget.SIZE_PERCENT} type that is widget's size type 541 */ 542 setSizeType: function (type) { 543 this._sizeType = type; 544 if (this._usingLayoutComponent) { 545 var component = this._getOrCreateLayoutComponent(); 546 component.setUsingPercentContentSize(this._sizeType === ccui.SIZE_PERCENT); 547 } 548 }, 549 550 /** 551 * Gets the size type of widget. 552 * @returns {ccui.Widget.SIZE_ABSOLUTE|ccui.Widget.SIZE_PERCENT} that is widget's size type 553 */ 554 getSizeType: function () { 555 return this._sizeType; 556 }, 557 558 /** 559 * Ignore the widget size 560 * @param {Boolean} ignore true that widget will ignore it's size, use texture size, false otherwise. Default value is true. 561 */ 562 ignoreContentAdaptWithSize: function (ignore) { 563 if(this._unifySize){ 564 this.setContentSize(this._customSize); 565 return; 566 } 567 568 if(this._ignoreSize === ignore) 569 return; 570 571 this._ignoreSize = ignore; 572 this.setContentSize( ignore ? this.getVirtualRendererSize() : this._customSize ); 573 //this._onSizeChanged(); 574 }, 575 576 /** 577 * Gets whether ignore the content size (custom size) 578 * @returns {boolean} true that widget will ignore it's size, use texture size, false otherwise. 579 */ 580 isIgnoreContentAdaptWithSize: function () { 581 return this._ignoreSize; 582 }, 583 584 /** 585 * Get custom size of ccui.Widget 586 * @returns {cc.Size} 587 */ 588 getCustomSize: function () { 589 return cc.size(this._customSize); 590 }, 591 592 /** 593 * Gets layout size of ccui.Widget. 594 * @returns {cc.Size} 595 */ 596 getLayoutSize: function(){ 597 return cc.size(this._contentSize); 598 }, 599 600 /** 601 * Returns size percent of ccui.Widget 602 * @returns {cc.Point} 603 */ 604 getSizePercent: function () { 605 if(this._usingLayoutComponent){ 606 var component = this._getOrCreateLayoutComponent(); 607 this._sizePercent = component.getPercentContentSize(); 608 } 609 return this._sizePercent; 610 }, 611 _getWidthPercent: function () { 612 return this._sizePercent.x; 613 }, 614 _getHeightPercent: function () { 615 return this._sizePercent.y; 616 }, 617 618 /** 619 * Gets world position of ccui.Widget. 620 * @returns {cc.Point} world position of ccui.Widget. 621 */ 622 getWorldPosition: function () { 623 return this.convertToWorldSpace(cc.p(this._anchorPoint.x * this._contentSize.width, this._anchorPoint.y * this._contentSize.height)); 624 }, 625 626 /** 627 * Gets the Virtual Renderer of widget. 628 * @returns {ccui.Widget} 629 */ 630 getVirtualRenderer: function () { 631 return this; 632 }, 633 634 /** 635 * Gets the content size of widget. Content size is widget's texture size. 636 */ 637 getVirtualRendererSize:function(){ 638 return cc.size(this._contentSize); 639 }, 640 641 /** 642 * call back function called when size changed. 643 */ 644 _onSizeChanged: function () { 645 if(!this._usingLayoutComponent){ 646 var locChildren = this.getChildren(); 647 for (var i = 0, len = locChildren.length; i < len; i++) { 648 var child = locChildren[i]; 649 if(child instanceof ccui.Widget) 650 child.updateSizeAndPosition(); 651 } 652 } 653 }, 654 655 /** 656 * Sets whether the widget is touch enabled. The default value is false, a widget is default to touch disabled 657 * @param {Boolean} enable true if the widget is touch enabled, false if the widget is touch disabled. 658 */ 659 setTouchEnabled: function (enable) { 660 if (this._touchEnabled === enable) 661 return; 662 663 this._touchEnabled = enable; //TODO need consider remove and re-add. 664 if (this._touchEnabled) { 665 if(!this._touchListener) 666 this._touchListener = cc.EventListener.create({ 667 event: cc.EventListener.TOUCH_ONE_BY_ONE, 668 swallowTouches: true, 669 onTouchBegan: this.onTouchBegan.bind(this), 670 onTouchMoved: this.onTouchMoved.bind(this), 671 onTouchEnded: this.onTouchEnded.bind(this) 672 }); 673 cc.eventManager.addListener(this._touchListener, this); 674 } else { 675 cc.eventManager.removeListener(this._touchListener); 676 } 677 }, 678 679 /** 680 * Returns whether or not touch is enabled. 681 * @returns {boolean} true if the widget is touch enabled, false if the widget is touch disabled. 682 */ 683 isTouchEnabled: function () { 684 return this._touchEnabled; 685 }, 686 687 /** 688 * Determines if the widget is highlighted 689 * @returns {boolean} true if the widget is highlighted, false if the widget is not highlighted . 690 */ 691 isHighlighted: function(){ 692 return this._highlight; 693 }, 694 695 /** 696 * Sets whether the widget is highlighted. The default value is false, a widget is default to not highlighted 697 * @param highlight true if the widget is highlighted, false if the widget is not highlighted. 698 */ 699 setHighlighted:function(highlight){ 700 if (highlight === this._highlight) 701 return; 702 this._highlight = highlight; 703 if (this._bright) { 704 if (this._highlight) 705 this.setBrightStyle(ccui.Widget.BRIGHT_STYLE_HIGH_LIGHT); 706 else 707 this.setBrightStyle(ccui.Widget.BRIGHT_STYLE_NORMAL); 708 } else 709 this._onPressStateChangedToDisabled(); 710 }, 711 712 /** 713 * Determines if the widget is on focused 714 * @returns {boolean} whether the widget is focused or not 715 */ 716 isFocused: function () { 717 return this._focused; 718 }, 719 720 /** 721 * Sets whether the widget is on focused 722 * The default value is false, a widget is default to not on focused 723 * @param {boolean} focus pass true to let the widget get focus or pass false to let the widget lose focus 724 */ 725 setFocused: function (focus) { 726 this._focused = focus; 727 //make sure there is only one focusedWidget 728 if (focus){ 729 ccui.Widget._focusedWidget = this; 730 if(ccui.Widget._focusNavigationController) 731 ccui.Widget._focusNavigationController._setFirstFocsuedWidget(this); 732 } 733 }, 734 735 /** 736 * returns whether the widget could accept focus. 737 * @returns {boolean} true represent the widget could accept focus, false represent the widget couldn't accept focus 738 */ 739 isFocusEnabled: function(){ 740 return this._focusEnabled; 741 }, 742 743 /** 744 * sets whether the widget could accept focus. 745 * @param {Boolean} enable true represent the widget could accept focus, false represent the widget couldn't accept focus 746 */ 747 setFocusEnabled: function(enable){ 748 this._focusEnabled = enable; 749 }, 750 751 /** 752 * <p> 753 * When a widget is in a layout, you could call this method to get the next focused widget within a specified direction. <br/> 754 * If the widget is not in a layout, it will return itself 755 * </p> 756 * @param direction the direction to look for the next focused widget in a layout 757 * @param current the current focused widget 758 * @return the next focused widget in a layout 759 */ 760 findNextFocusedWidget: function( direction, current){ 761 if (null === this.onNextFocusedWidget || null == this.onNextFocusedWidget(direction) ) { 762 var isLayout = current instanceof ccui.Layout; 763 if (this.isFocused() || isLayout) { 764 var layout = this.getParent(); 765 if (null === layout || !(layout instanceof ccui.Layout)){ 766 //the outer layout's default behaviour is : loop focus 767 if (isLayout) 768 return current.findNextFocusedWidget(direction, current); 769 return current; 770 } else 771 return layout.findNextFocusedWidget(direction, current); 772 } else 773 return current; 774 } else { 775 var getFocusWidget = this.onNextFocusedWidget(direction); 776 this.dispatchFocusEvent(this, getFocusWidget); 777 return getFocusWidget; 778 } 779 }, 780 781 /** 782 * when a widget calls this method, it will get focus immediately. 783 */ 784 requestFocus: function(){ 785 if (this === ccui.Widget._focusedWidget) 786 return; 787 this.dispatchFocusEvent(ccui.Widget._focusedWidget, this); 788 }, 789 790 /** 791 * no matter what widget object you call this method on , it will return you the exact one focused widget 792 */ 793 getCurrentFocusedWidget: function(){ 794 return ccui.Widget._focusedWidget; 795 }, 796 797 /** 798 * <p> 799 * When a widget lose/get focus, this method will be called. Be Caution when you provide your own version, <br/> 800 * you must call widget.setFocused(true/false) to change the focus state of the current focused widget; 801 * </p> 802 */ 803 onFocusChanged: null, 804 805 /** 806 * use this function to manually specify the next focused widget regards to each direction 807 */ 808 onNextFocusedWidget: null, 809 810 /** 811 * Sends the touch event to widget's parent, its subclass will override it, e.g. ccui.ScrollView, ccui.PageView 812 * @param {Number} eventType 813 * @param {ccui.Widget} sender 814 * @param {cc.Touch} touch 815 */ 816 interceptTouchEvent: function(eventType, sender, touch){ 817 var widgetParent = this.getWidgetParent(); 818 if (widgetParent) 819 widgetParent.interceptTouchEvent(eventType,sender,touch); 820 }, 821 822 /** 823 * This method is called when a focus change event happens 824 * @param {ccui.Widget} widgetLostFocus 825 * @param {ccui.Widget} widgetGetFocus 826 */ 827 onFocusChange: function(widgetLostFocus, widgetGetFocus){ 828 //only change focus when there is indeed a get&lose happens 829 if (widgetLostFocus) 830 widgetLostFocus.setFocused(false); 831 if (widgetGetFocus) 832 widgetGetFocus.setFocused(true); 833 }, 834 835 /** 836 * Dispatch a EventFocus through a EventDispatcher 837 * @param {ccui.Widget} widgetLostFocus 838 * @param {ccui.Widget} widgetGetFocus 839 */ 840 dispatchFocusEvent: function(widgetLostFocus, widgetGetFocus){ 841 //if the widgetLoseFocus doesn't get focus, it will use the previous focused widget instead 842 if (widgetLostFocus && !widgetLostFocus.isFocused()) 843 widgetLostFocus = ccui.Widget._focusedWidget; 844 845 if (widgetGetFocus !== widgetLostFocus){ 846 if (widgetGetFocus && widgetGetFocus.onFocusChanged) 847 widgetGetFocus.onFocusChanged(widgetLostFocus, widgetGetFocus); 848 if (widgetLostFocus && widgetGetFocus.onFocusChanged) 849 widgetLostFocus.onFocusChanged(widgetLostFocus, widgetGetFocus); 850 cc.eventManager.dispatchEvent(new cc.EventFocus(widgetLostFocus, widgetGetFocus)); 851 } 852 }, 853 854 /** 855 * Sets whether the widget is bright. The default value is true, a widget is default to bright 856 * @param {Boolean} bright true if the widget is bright, false if the widget is dark. 857 */ 858 setBright: function (bright) { 859 this._bright = bright; 860 if (this._bright) { 861 this._brightStyle = ccui.Widget.BRIGHT_STYLE_NONE; 862 this.setBrightStyle(ccui.Widget.BRIGHT_STYLE_NORMAL); 863 } else 864 this._onPressStateChangedToDisabled(); 865 }, 866 867 /** 868 * To set the bright style of ccui.Widget. 869 * @param {Number} style BRIGHT_NORMAL the widget is normal state, BRIGHT_HIGHLIGHT the widget is height light state. 870 */ 871 setBrightStyle: function (style) { 872 if (this._brightStyle === style) 873 return; 874 875 style = style || ccui.Widget.BRIGHT_STYLE_NORMAL; 876 this._brightStyle = style; 877 switch (this._brightStyle) { 878 case ccui.Widget.BRIGHT_STYLE_NORMAL: 879 this._onPressStateChangedToNormal(); 880 break; 881 case ccui.Widget.BRIGHT_STYLE_HIGH_LIGHT: 882 this._onPressStateChangedToPressed(); 883 break; 884 default: 885 break; 886 } 887 }, 888 889 _onPressStateChangedToNormal: function () {}, 890 891 _onPressStateChangedToPressed: function () {}, 892 893 _onPressStateChangedToDisabled: function () {}, 894 895 _updateChildrenDisplayedRGBA: function(){ 896 this.setColor(this.getColor()); 897 this.setOpacity(this.getOpacity()); 898 }, 899 900 /** 901 * A call back function when widget lost of focus. 902 */ 903 didNotSelectSelf: function () {}, 904 905 /** 906 * <p> 907 * The callback of touch began event. <br/> 908 * If the bounding box of ccui.Widget contains the touch point, it will do the following things: <br/> 909 * 1. sets highlight state, <br/> 910 * 2. sends event to parent widget by interceptTouchEvent <br/> 911 * 3. calls the callback of touch began event. <br/> 912 * 4. returns true, <br/> 913 * otherwise returns false directly. <br/> 914 * </p> 915 * @override 916 * @param {cc.Touch} touch 917 * @param {cc.Event} event 918 * @returns {boolean} 919 */ 920 onTouchBegan: function (touch, event) { 921 this._hit = false; 922 if (this.isVisible() && this.isEnabled() && this._isAncestorsEnabled() && this._isAncestorsVisible(this) ){ 923 var touchPoint = touch.getLocation(); 924 this._touchBeganPosition.x = touchPoint.x; 925 this._touchBeganPosition.y = touchPoint.y; 926 if(this.hitTest(this._touchBeganPosition) && this.isClippingParentContainsPoint(this._touchBeganPosition)) 927 this._hit = true; 928 } 929 if (!this._hit) { 930 return false; 931 } 932 this.setHighlighted(true); 933 934 /* 935 * Propagate touch events to its parents 936 */ 937 if (this._propagateTouchEvents) { 938 this.propagateTouchEvent(ccui.Widget.TOUCH_BEGAN, this, touch); 939 } 940 941 this._pushDownEvent(); 942 return true; 943 }, 944 945 propagateTouchEvent: function(event, sender, touch){ 946 var widgetParent = this.getWidgetParent(); 947 if (widgetParent){ 948 widgetParent.interceptTouchEvent(event, sender, touch); 949 } 950 }, 951 952 /** 953 * <p> 954 * The callback of touch moved event. <br/> 955 * It sets the highlight state by touch, sends event to parent widget by interceptTouchEvent and calls the callback of touch moved event. 956 * </p> 957 * @param {cc.Touch} touch 958 * @param {cc.Event} event 959 */ 960 onTouchMoved: function (touch, event) { 961 var touchPoint = touch.getLocation(); 962 this._touchMovePosition.x = touchPoint.x; 963 this._touchMovePosition.y = touchPoint.y; 964 this.setHighlighted(this.hitTest(touchPoint)); 965 /* 966 * Propagate touch events to its parents 967 */ 968 if (this._propagateTouchEvents) 969 this.propagateTouchEvent(ccui.Widget.TOUCH_MOVED, this, touch); 970 this._moveEvent(); 971 }, 972 973 /** 974 * <p> 975 * The callback of touch end event 976 * It sends event to parent widget by interceptTouchEvent, 977 * calls the callback of touch end event (highlight= true) or touch canceled event (highlight= false). 978 * sets the highlight state to false , 979 * </p> 980 * @param touch 981 * @param event 982 */ 983 onTouchEnded: function (touch, event) { 984 var touchPoint = touch.getLocation(); 985 this._touchEndPosition.x = touchPoint.x; 986 this._touchEndPosition.y = touchPoint.y; 987 /* 988 * Propagate touch events to its parents 989 */ 990 if (this._propagateTouchEvents) 991 this.propagateTouchEvent(ccui.Widget.TOUCH_ENDED, this, touch); 992 993 var highlight = this._highlight; 994 this.setHighlighted(false); 995 if (highlight) 996 this._releaseUpEvent(); 997 else 998 this._cancelUpEvent(); 999 }, 1000 1001 /** 1002 * A call back function called when widget is selected, and on touch canceled. 1003 * @param {cc.Point} touchPoint 1004 */ 1005 onTouchCancelled: function (touchPoint) { 1006 this.setHighlighted(false); 1007 this._cancelUpEvent(); 1008 }, 1009 1010 /** 1011 * A call back function called when widget is selected, and on touch long clicked. 1012 * @param {cc.Point} touchPoint 1013 */ 1014 onTouchLongClicked: function (touchPoint) { 1015 this.longClickEvent(); 1016 }, 1017 1018 //call back function called widget's state changed to dark. 1019 _pushDownEvent: function () { 1020 if (this._touchEventCallback) 1021 this._touchEventCallback(this, ccui.Widget.TOUCH_BEGAN); 1022 if (this._touchEventListener && this._touchEventSelector) 1023 this._touchEventSelector.call(this._touchEventListener, this, ccui.Widget.TOUCH_BEGAN); 1024 }, 1025 1026 _moveEvent: function () { 1027 if (this._touchEventCallback) 1028 this._touchEventCallback(this, ccui.Widget.TOUCH_MOVED); 1029 if (this._touchEventListener && this._touchEventSelector) 1030 this._touchEventSelector.call(this._touchEventListener, this, ccui.Widget.TOUCH_MOVED); 1031 }, 1032 1033 _releaseUpEvent: function () { 1034 if (this._touchEventCallback) 1035 this._touchEventCallback(this, ccui.Widget.TOUCH_ENDED); 1036 if (this._touchEventListener && this._touchEventSelector) 1037 this._touchEventSelector.call(this._touchEventListener, this, ccui.Widget.TOUCH_ENDED); 1038 if (this._clickEventListener) 1039 this._clickEventListener(this); 1040 }, 1041 1042 _cancelUpEvent: function () { 1043 if (this._touchEventCallback) 1044 this._touchEventCallback(this, ccui.Widget.TOUCH_CANCELED); 1045 if (this._touchEventListener && this._touchEventSelector) 1046 this._touchEventSelector.call(this._touchEventListener, this, ccui.Widget.TOUCH_CANCELED); 1047 }, 1048 1049 longClickEvent: function () { 1050 //TODO it will implement in v3.1 1051 }, 1052 1053 /** 1054 * Sets the touch event target/selector of the ccui.Widget 1055 * @param {Function} selector 1056 * @param {Object} target 1057 */ 1058 addTouchEventListener: function (selector, target) { 1059 if(target === undefined) 1060 this._touchEventCallback = selector; 1061 else { 1062 this._touchEventSelector = selector; 1063 this._touchEventListener = target; 1064 } 1065 }, 1066 1067 addClickEventListener: function(callback){ 1068 this._clickEventListener = callback; 1069 }, 1070 1071 /** 1072 * Checks a point if is in widget's space 1073 * @param {cc.Point} pt 1074 * @returns {boolean} true if the point is in widget's space, false otherwise. 1075 */ 1076 hitTest: function (pt) { 1077 var bb = cc.rect(0,0, this._contentSize.width, this._contentSize.height); 1078 return cc.rectContainsPoint(bb, this.convertToNodeSpace(pt)); 1079 }, 1080 1081 /** 1082 * returns whether clipping parent widget contains point. 1083 * @param {cc.Point} pt location point 1084 * @returns {Boolean} 1085 */ 1086 isClippingParentContainsPoint: function(pt){ 1087 this._affectByClipping = false; 1088 var parent = this.getParent(); 1089 var clippingParent = null; 1090 while (parent) { 1091 if (parent instanceof ccui.Layout) { 1092 if (parent.isClippingEnabled()) { 1093 this._affectByClipping = true; 1094 clippingParent = parent; 1095 break; 1096 } 1097 } 1098 parent = parent.getParent(); 1099 } 1100 1101 if (!this._affectByClipping) 1102 return true; 1103 1104 if (clippingParent) { 1105 if (clippingParent.hitTest(pt)) 1106 return clippingParent.isClippingParentContainsPoint(pt); 1107 return false; 1108 } 1109 return true; 1110 }, 1111 1112 /** 1113 * Calls the checkChildInfo of widget's parent, its subclass will override it. 1114 * @param {number} handleState 1115 * @param {ccui.Widget} sender 1116 * @param {cc.Point} touchPoint 1117 */ 1118 checkChildInfo: function (handleState, sender, touchPoint) { 1119 var widgetParent = this.getWidgetParent(); 1120 if (widgetParent) 1121 widgetParent.checkChildInfo(handleState, sender, touchPoint); 1122 }, 1123 1124 /** 1125 * Changes the position (x,y) of the widget . 1126 * The original point (0,0) is at the left-bottom corner of screen. 1127 * @override 1128 * @param {cc.Point|Number} pos 1129 * @param {Number} [posY] 1130 */ 1131 setPosition: function (pos, posY) { 1132 if (!this._usingLayoutComponent && this._running) { 1133 var widgetParent = this.getWidgetParent(); 1134 if (widgetParent) { 1135 var pSize = widgetParent.getContentSize(); 1136 if (pSize.width <= 0 || pSize.height <= 0) { 1137 this._positionPercent.x = 0; 1138 this._positionPercent.y = 0; 1139 } else { 1140 if (posY === undefined) { 1141 this._positionPercent.x = pos.x / pSize.width; 1142 this._positionPercent.y = pos.y / pSize.height; 1143 } else { 1144 this._positionPercent.x = pos / pSize.width; 1145 this._positionPercent.y = posY / pSize.height; 1146 } 1147 } 1148 } 1149 } 1150 1151 cc.Node.prototype.setPosition.call(this, pos, posY); 1152 //this._positionType = ccui.Widget.POSITION_ABSOLUTE; 1153 }, 1154 1155 setPositionX: function (x) { 1156 if (this._running) { 1157 var widgetParent = this.getWidgetParent(); 1158 if (widgetParent) { 1159 var pw = widgetParent.width; 1160 if (pw <= 0) 1161 this._positionPercent.x = 0; 1162 else 1163 this._positionPercent.x = x / pw; 1164 } 1165 } 1166 1167 cc.Node.prototype.setPositionX.call(this, x); 1168 }, 1169 setPositionY: function (y) { 1170 if (this._running) { 1171 var widgetParent = this.getWidgetParent(); 1172 if (widgetParent) { 1173 var ph = widgetParent.height; 1174 if (ph <= 0) 1175 this._positionPercent.y = 0; 1176 else 1177 this._positionPercent.y = y / ph; 1178 } 1179 } 1180 1181 cc.Node.prototype.setPositionY.call(this, y); 1182 }, 1183 1184 /** 1185 * Changes the position (x,y) of the widget 1186 * @param {cc.Point} percent 1187 */ 1188 setPositionPercent: function (percent) { 1189 if (this._usingLayoutComponent){ 1190 var component = this._getOrCreateLayoutComponent(); 1191 component.setPositionPercentX(percent.x); 1192 component.setPositionPercentY(percent.y); 1193 component.refreshLayout(); 1194 return; 1195 }else{ 1196 this._setXPercent(percent.x); 1197 this._setYPercent(percent.y); 1198 } 1199 this._renderCmd.setDirtyFlag(cc.Node._dirtyFlags.transformDirty); 1200 }, 1201 _setXPercent: function (percent) { 1202 if (this._usingLayoutComponent){ 1203 var component = this._getOrCreateLayoutComponent(); 1204 component.setPositionPercentX(percent.x); 1205 component.refreshLayout(); 1206 return; 1207 } 1208 this._positionPercent.x = percent; 1209 }, 1210 _setYPercent: function (percent) { 1211 if (this._usingLayoutComponent){ 1212 var component = this._getOrCreateLayoutComponent(); 1213 component.setPositionPercentY(percent.x); 1214 component.refreshLayout(); 1215 return; 1216 } 1217 this._positionPercent.y = percent; 1218 }, 1219 1220 /** 1221 * Gets the percent (x,y) of the widget 1222 * @returns {cc.Point} The percent (x,y) of the widget in OpenGL coordinates 1223 */ 1224 getPositionPercent: function () { 1225 if (this._usingLayoutComponent) { 1226 var component = this._getOrCreateLayoutComponent(); 1227 this._positionPercent.x = component.getPositionPercentX(); 1228 this._positionPercent.y = component.getPositionPercentY(); 1229 } 1230 return cc.p(this._positionPercent); 1231 }, 1232 1233 _getXPercent: function () { 1234 if (this._usingLayoutComponent) { 1235 var component = this._getOrCreateLayoutComponent(); 1236 this._positionPercent.x = component.getPositionPercentX(); 1237 this._positionPercent.y = component.getPositionPercentY(); 1238 } 1239 return this._positionPercent.x; 1240 }, 1241 _getYPercent: function () { 1242 if (this._usingLayoutComponent) { 1243 var component = this._getOrCreateLayoutComponent(); 1244 this._positionPercent.x = component.getPositionPercentX(); 1245 this._positionPercent.y = component.getPositionPercentY(); 1246 } 1247 return this._positionPercent.y; 1248 }, 1249 1250 /** 1251 * Changes the position type of the widget 1252 * @param {Number} type the position type of widget 1253 */ 1254 setPositionType: function (type) { 1255 this._positionType = type; 1256 if(this._usingLayoutComponent){ 1257 var component = this._getOrCreateLayoutComponent(); 1258 if (type === ccui.POSITION_ABSOLUTE){ 1259 component.setPositionPercentXEnabled(false); 1260 component.setPositionPercentYEnabled(false); 1261 } else { 1262 component.setPositionPercentXEnabled(true); 1263 component.setPositionPercentYEnabled(true); 1264 } 1265 } 1266 this._renderCmd.setDirtyFlag(cc.Node._dirtyFlags.transformDirty); 1267 }, 1268 1269 /** 1270 * Gets the position type of the widget 1271 * @returns {Number} the position type of widget 1272 */ 1273 getPositionType: function () { 1274 return this._positionType; 1275 }, 1276 1277 /** 1278 * Sets whether the widget should be flipped horizontally or not. 1279 * @param {Boolean} flipX true if the widget should be flipped horizontally, false otherwise. 1280 */ 1281 setFlippedX: function (flipX) { 1282 var realScale = this.getScaleX(); 1283 this._flippedX = flipX; 1284 this.setScaleX(realScale); 1285 }, 1286 1287 /** 1288 * <p> 1289 * Returns the flag which indicates whether the widget is flipped horizontally or not. <br/> 1290 * It only flips the texture of the widget, and not the texture of the widget's children. <br/> 1291 * Also, flipping the texture doesn't alter the anchorPoint. <br/> 1292 * If you want to flip the anchorPoint too, and/or to flip the children too use: <br/> 1293 * widget.setScaleX(sprite.getScaleX() * -1); 1294 * </p> 1295 * @returns {Boolean} true if the widget is flipped horizontally, false otherwise. 1296 */ 1297 isFlippedX: function () { 1298 return this._flippedX; 1299 }, 1300 1301 /** 1302 * Sets whether the widget should be flipped vertically or not. 1303 * @param {Boolean} flipY true if the widget should be flipped vertically, false otherwise. 1304 */ 1305 setFlippedY: function (flipY) { 1306 var realScale = this.getScaleY(); 1307 this._flippedY = flipY; 1308 this.setScaleY(realScale); 1309 }, 1310 1311 /** 1312 * <p> 1313 * Return the flag which indicates whether the widget is flipped vertically or not. <br/> 1314 * It only flips the texture of the widget, and not the texture of the widget's children. <br/> 1315 * Also, flipping the texture doesn't alter the anchorPoint. <br/> 1316 * If you want to flip the anchorPoint too, and/or to flip the children too use: <br/> 1317 * widget.setScaleY(widget.getScaleY() * -1); 1318 * </p> 1319 * @returns {Boolean} true if the widget is flipped vertically, false otherwise. 1320 */ 1321 isFlippedY: function () { 1322 return this._flippedY; 1323 }, 1324 1325 _adaptRenderers: function(){}, 1326 1327 /** 1328 * Determines if the widget is bright 1329 * @returns {boolean} true if the widget is bright, false if the widget is dark. 1330 */ 1331 isBright: function () { 1332 return this._bright; 1333 }, 1334 1335 /** 1336 * Determines if the widget is enabled 1337 * @returns {boolean} 1338 */ 1339 isEnabled: function () { 1340 return this._enabled; 1341 }, 1342 1343 /** 1344 * Gets the left boundary position of this widget. 1345 * @returns {number} 1346 */ 1347 getLeftBoundary: function () { 1348 return this.getPositionX() - this._getAnchorX() * this._contentSize.width; 1349 }, 1350 1351 /** 1352 * Gets the bottom boundary position of this widget. 1353 * @returns {number} 1354 */ 1355 getBottomBoundary: function () { 1356 return this.getPositionY() - this._getAnchorY() * this._contentSize.height; 1357 }, 1358 1359 /** 1360 * Gets the right boundary position of this widget. 1361 * @returns {number} 1362 */ 1363 getRightBoundary: function () { 1364 return this.getLeftBoundary() + this._contentSize.width; 1365 }, 1366 1367 /** 1368 * Gets the top boundary position of this widget. 1369 * @returns {number} 1370 */ 1371 getTopBoundary: function () { 1372 return this.getBottomBoundary() + this._contentSize.height; 1373 }, 1374 1375 /** 1376 * Gets the position of touch began event. 1377 * @returns {cc.Point} 1378 */ 1379 getTouchBeganPosition: function(){ 1380 return cc.p(this._touchBeganPosition); 1381 }, 1382 1383 /** 1384 * Gets the position of touch moved event 1385 * @returns {cc.Point} 1386 */ 1387 getTouchMovePosition: function(){ 1388 return cc.p(this._touchMovePosition); 1389 }, 1390 1391 /** 1392 * Gets the position of touch end event 1393 * @returns {cc.Point} 1394 */ 1395 getTouchEndPosition:function(){ 1396 return cc.p(this._touchEndPosition); 1397 }, 1398 1399 /** 1400 * get widget type 1401 * @returns {ccui.Widget.TYPE_WIDGET|ccui.Widget.TYPE_CONTAINER} 1402 */ 1403 getWidgetType: function () { 1404 return this._widgetType; 1405 }, 1406 1407 /** 1408 * Gets LayoutParameter of widget. 1409 * @param {ccui.LayoutParameter} parameter 1410 */ 1411 setLayoutParameter: function (parameter) { 1412 if(!parameter) 1413 return; 1414 this._layoutParameterDictionary[parameter.getLayoutType()] = parameter; 1415 this._layoutParameterType = parameter.getLayoutType(); 1416 }, 1417 1418 /** 1419 * Gets layout parameter 1420 * @param {ccui.LayoutParameter.NONE|ccui.LayoutParameter.LINEAR|ccui.LayoutParameter.RELATIVE} type 1421 * @returns {ccui.LayoutParameter} 1422 */ 1423 getLayoutParameter: function (type) { 1424 type = type || this._layoutParameterType; 1425 return this._layoutParameterDictionary[type]; 1426 }, 1427 1428 /** 1429 * Returns the "class name" of widget. 1430 * @returns {string} 1431 */ 1432 getDescription: function () { 1433 return "Widget"; 1434 }, 1435 1436 /** 1437 * Clones a new widget. 1438 * @returns {ccui.Widget} 1439 */ 1440 clone: function () { 1441 var clonedWidget = this._createCloneInstance(); 1442 clonedWidget._copyProperties(this); 1443 clonedWidget._copyClonedWidgetChildren(this); 1444 return clonedWidget; 1445 }, 1446 1447 _createCloneInstance: function () { 1448 return new ccui.Widget(); 1449 }, 1450 1451 _copyClonedWidgetChildren: function (model) { 1452 var widgetChildren = model.getChildren(); 1453 for (var i = 0; i < widgetChildren.length; i++) { 1454 var locChild = widgetChildren[i]; 1455 if (locChild instanceof ccui.Widget) 1456 this.addChild(locChild.clone()); 1457 } 1458 }, 1459 1460 _copySpecialProperties: function (model) {}, 1461 1462 _copyProperties: function (widget) { 1463 this.setEnabled(widget.isEnabled()); 1464 this.setVisible(widget.isVisible()); 1465 this.setBright(widget.isBright()); 1466 this.setTouchEnabled(widget.isTouchEnabled()); 1467 this.setLocalZOrder(widget.getLocalZOrder()); 1468 this.setTag(widget.getTag()); 1469 this.setName(widget.getName()); 1470 this.setActionTag(widget.getActionTag()); 1471 1472 this._ignoreSize = widget._ignoreSize; 1473 1474 this.setContentSize(widget._contentSize); 1475 this._customSize.width = widget._customSize.width; 1476 this._customSize.height = widget._customSize.height; 1477 1478 this._copySpecialProperties(widget); 1479 this._sizeType = widget.getSizeType(); 1480 this._sizePercent.x = widget._sizePercent.x; 1481 this._sizePercent.y = widget._sizePercent.y; 1482 1483 this._positionType = widget._positionType; 1484 this._positionPercent.x = widget._positionPercent.x; 1485 this._positionPercent.y = widget._positionPercent.y; 1486 1487 this.setPosition(widget.getPosition()); 1488 this.setAnchorPoint(widget.getAnchorPoint()); 1489 this.setScaleX(widget.getScaleX()); 1490 this.setScaleY(widget.getScaleY()); 1491 this.setRotation(widget.getRotation()); 1492 this.setRotationX(widget.getRotationX()); 1493 this.setRotationY(widget.getRotationY()); 1494 this.setFlippedX(widget.isFlippedX()); 1495 this.setFlippedY(widget.isFlippedY()); 1496 this.setColor(widget.getColor()); 1497 this.setOpacity(widget.getOpacity()); 1498 1499 this._touchEventCallback = widget._touchEventCallback; 1500 this._touchEventListener = widget._touchEventListener; 1501 this._touchEventSelector = widget._touchEventSelector; 1502 this._clickEventListener = widget._clickEventListener; 1503 this._focused = widget._focused; 1504 this._focusEnabled = widget._focusEnabled; 1505 this._propagateTouchEvents = widget._propagateTouchEvents; 1506 1507 for (var key in widget._layoutParameterDictionary) { 1508 var parameter = widget._layoutParameterDictionary[key]; 1509 if (parameter) 1510 this.setLayoutParameter(parameter.clone()); 1511 } 1512 this._onSizeChanged(); 1513 }, 1514 1515 /*temp action*/ 1516 setActionTag: function (tag) { 1517 this._actionTag = tag; 1518 }, 1519 1520 getActionTag: function () { 1521 return this._actionTag; 1522 }, 1523 1524 /** 1525 * Gets the left boundary position of this widget. 1526 * @deprecated since v3.0, please use getLeftBoundary instead. 1527 * @returns {number} 1528 */ 1529 getLeftInParent: function(){ 1530 cc.log("getLeftInParent is deprecated. Please use getLeftBoundary instead."); 1531 return this.getLeftBoundary(); 1532 }, 1533 1534 /** 1535 * Gets the bottom boundary position of this widget. 1536 * @deprecated since v3.0, please use getBottomBoundary instead. 1537 * @returns {number} 1538 */ 1539 getBottomInParent: function(){ 1540 cc.log("getBottomInParent is deprecated. Please use getBottomBoundary instead."); 1541 return this.getBottomBoundary(); 1542 }, 1543 1544 /** 1545 * Gets the right boundary position of this widget. 1546 * @deprecated since v3.0, please use getRightBoundary instead. 1547 * @returns {number} 1548 */ 1549 getRightInParent: function(){ 1550 cc.log("getRightInParent is deprecated. Please use getRightBoundary instead."); 1551 return this.getRightBoundary(); 1552 }, 1553 1554 /** 1555 * Gets the top boundary position of this widget. 1556 * @deprecated since v3.0, please use getTopBoundary instead. 1557 * @returns {number} 1558 */ 1559 getTopInParent: function(){ 1560 cc.log("getTopInParent is deprecated. Please use getTopBoundary instead."); 1561 return this.getTopBoundary(); 1562 }, 1563 1564 /** 1565 * Gets the touch end point of widget when widget is selected. 1566 * @deprecated since v3.0, please use getTouchEndPosition instead. 1567 * @returns {cc.Point} the touch end point. 1568 */ 1569 getTouchEndPos: function () { 1570 cc.log("getTouchEndPos is deprecated. Please use getTouchEndPosition instead."); 1571 return this.getTouchEndPosition(); 1572 }, 1573 1574 /** 1575 *Gets the touch move point of widget when widget is selected. 1576 * @deprecated since v3.0, please use getTouchMovePosition instead. 1577 * @returns {cc.Point} the touch move point. 1578 */ 1579 getTouchMovePos: function () { 1580 cc.log("getTouchMovePos is deprecated. Please use getTouchMovePosition instead."); 1581 return this.getTouchMovePosition(); 1582 }, 1583 1584 /** 1585 * Checks a point if in parent's area. 1586 * @deprecated since v3.0, please use isClippingParentContainsPoint instead. 1587 * @param {cc.Point} pt 1588 * @returns {Boolean} 1589 */ 1590 clippingParentAreaContainPoint: function (pt) { 1591 cc.log("clippingParentAreaContainPoint is deprecated. Please use isClippingParentContainsPoint instead."); 1592 this.isClippingParentContainsPoint(pt); 1593 }, 1594 1595 /** 1596 * Gets the touch began point of widget when widget is selected. 1597 * @deprecated since v3.0, please use getTouchBeganPosition instead. 1598 * @returns {cc.Point} the touch began point. 1599 */ 1600 getTouchStartPos: function () { 1601 cc.log("getTouchStartPos is deprecated. Please use getTouchBeganPosition instead."); 1602 return this.getTouchBeganPosition(); 1603 }, 1604 1605 /** 1606 * Changes the size that is widget's size 1607 * @deprecated since v3.0, please use setContentSize instead. 1608 * @param {cc.Size} size that is widget's size 1609 */ 1610 setSize: function (size) { 1611 this.setContentSize(size); 1612 }, 1613 1614 /** 1615 * Returns size of widget 1616 * @deprecated since v3.0, please use getContentSize instead. 1617 * @returns {cc.Size} 1618 */ 1619 getSize: function () { 1620 return this.getContentSize(); 1621 }, 1622 1623 /** 1624 * Adds a node for widget (this function is deleted in -x) 1625 * @param {cc.Node} node 1626 * @param {Number} zOrder 1627 * @param {Number} tag 1628 * @deprecated since v3.0, please use addChild instead. 1629 */ 1630 addNode: function (node, zOrder, tag) { 1631 if (node instanceof ccui.Widget) { 1632 cc.log("Please use addChild to add a Widget."); 1633 return; 1634 } 1635 cc.Node.prototype.addChild.call(this, node, zOrder, tag); 1636 this._nodes.push(node); 1637 }, 1638 1639 /** 1640 * Gets node by tag 1641 * @deprecated since v3.0, please use getChildByTag instead. 1642 * @param {Number} tag 1643 * @returns {cc.Node} 1644 */ 1645 getNodeByTag: function (tag) { 1646 var _nodes = this._nodes; 1647 for (var i = 0; i < _nodes.length; i++) { 1648 var node = _nodes[i]; 1649 if (node && node.getTag() === tag) { 1650 return node; 1651 } 1652 } 1653 return null; 1654 }, 1655 1656 /** 1657 * Returns all children. 1658 * @deprecated since v3.0, please use getChildren instead. 1659 * @returns {Array} 1660 */ 1661 getNodes: function () { 1662 return this._nodes; 1663 }, 1664 1665 /** 1666 * Removes a node from ccui.Widget 1667 * @deprecated since v3.0, please use removeChild instead. 1668 * @param {cc.Node} node 1669 * @param {Boolean} cleanup 1670 */ 1671 removeNode: function (node, cleanup) { 1672 cc.Node.prototype.removeChild.call(this, node, cleanup); 1673 cc.arrayRemoveObject(this._nodes, node); 1674 }, 1675 1676 /** 1677 * Removes node by tag 1678 * @deprecated since v3.0, please use removeChildByTag instead. 1679 * @param {Number} tag 1680 * @param {Boolean} [cleanup] 1681 */ 1682 removeNodeByTag: function (tag, cleanup) { 1683 var node = this.getChildByTag(tag); 1684 if (!node) 1685 cc.log("cocos2d: removeNodeByTag(tag = %d): child not found!", tag); 1686 else 1687 this.removeChild(node, cleanup); 1688 }, 1689 1690 /** 1691 * Removes all node 1692 * @deprecated since v3.0, please use removeAllChildren instead. 1693 */ 1694 removeAllNodes: function () { 1695 for (var i = 0; i < this._nodes.length; i++) { 1696 var node = this._nodes[i]; 1697 cc.Node.prototype.removeChild.call(this, node); 1698 } 1699 this._nodes.length = 0; 1700 }, 1701 1702 _findLayout: function(){ 1703 cc.renderer.childrenOrderDirty = true; 1704 var layout = this._parent; 1705 while(layout){ 1706 if(layout._doLayout){ 1707 layout._doLayoutDirty = true; 1708 break; 1709 }else 1710 layout = layout._parent; 1711 } 1712 }, 1713 1714 /** 1715 * @since v3.2 1716 * @returns {boolean} true represent the widget use Unify Size, false represent the widget couldn't use Unify Size 1717 */ 1718 isUnifySizeEnabled: function(){ 1719 return this._unifySize; 1720 }, 1721 1722 /** 1723 * @since v3.2 1724 * @param {Boolean} enable enable Unify Size of a widget 1725 */ 1726 setUnifySizeEnabled: function(enable){ 1727 this._unifySize = enable; 1728 }, 1729 1730 //v3.3 1731 _ccEventCallback: null, 1732 /** 1733 * Set a event handler to the widget in order to use cocostudio editor and framework 1734 * @since v3.3 1735 * @param {function} callback 1736 */ 1737 addCCSEventListener: function(callback){ 1738 this._ccEventCallback = callback; 1739 }, 1740 1741 //override the scale functions. 1742 setScaleX: function(scaleX){ 1743 if (this._flippedX) 1744 scaleX = scaleX * -1; 1745 cc.Node.prototype.setScaleX.call(this, scaleX); 1746 }, 1747 setScaleY: function(scaleY){ 1748 if (this._flippedY) 1749 scaleY = scaleY * -1; 1750 cc.Node.prototype.setScaleY.call(this, scaleY); 1751 }, 1752 setScale: function(scaleX, scaleY){ 1753 if(scaleY === undefined) 1754 scaleY = scaleX; 1755 this.setScaleX(scaleX); 1756 this.setScaleY(scaleY); 1757 }, 1758 1759 getScaleX: function(){ 1760 var originalScale = cc.Node.prototype.getScaleX.call(this); 1761 if (this._flippedX) 1762 originalScale = originalScale * -1.0; 1763 return originalScale; 1764 }, 1765 getScaleY: function(){ 1766 var originalScale = cc.Node.prototype.getScaleY.call(this); 1767 if (this._flippedY) 1768 originalScale = originalScale * -1.0; 1769 return originalScale; 1770 }, 1771 getScale: function(){ 1772 if(this.getScaleX() !== this.getScaleY()) 1773 cc.log("Widget#scale. ScaleX != ScaleY. Don't know which one to return"); 1774 return this.getScaleX(); 1775 }, 1776 1777 /** 1778 * Sets callback name to widget. 1779 * @since v3.3 1780 * @param {String} callbackName 1781 */ 1782 setCallbackName: function(callbackName){ 1783 this._callbackName = callbackName; 1784 }, 1785 1786 /** 1787 * Gets callback name of widget 1788 * @since v3.3 1789 * @returns {String|Null} 1790 */ 1791 getCallbackName: function(){ 1792 return this._callbackName; 1793 }, 1794 1795 /** 1796 * Sets callback type to widget 1797 * @since v3.3 1798 * @param {String} callbackType 1799 */ 1800 setCallbackType: function(callbackType){ 1801 this._callbackType = callbackType; 1802 }, 1803 1804 /** 1805 * Gets callback type of widget 1806 * @since v3.3 1807 * @returns {String|null} 1808 */ 1809 getCallbackType: function(){ 1810 return this._callbackType; 1811 }, 1812 1813 /** 1814 * Whether enable layout component of a widget 1815 * @since v3.3 1816 * @param {Boolean} enable enable layout Component of a widget 1817 */ 1818 setLayoutComponentEnabled: function(enable){ 1819 this._usingLayoutComponent = enable; 1820 }, 1821 1822 /** 1823 * Returns whether enable layout component of a widget 1824 * @return {Boolean} true represent the widget use Layout Component, false represent the widget couldn't use Layout Component. 1825 */ 1826 isLayoutComponentEnabled: function(){ 1827 return this._usingLayoutComponent; 1828 }, 1829 1830 1831 _createRenderCmd: function(){ 1832 if(cc._renderType === cc.game.RENDER_TYPE_WEBGL) 1833 return new ccui.Widget.WebGLRenderCmd(this); 1834 else 1835 return new ccui.Widget.CanvasRenderCmd(this); 1836 } 1837 }); 1838 1839 var _p = ccui.Widget.prototype; 1840 1841 // Extended properties 1842 /** @expose */ 1843 _p.xPercent; 1844 cc.defineGetterSetter(_p, "xPercent", _p._getXPercent, _p._setXPercent); 1845 /** @expose */ 1846 _p.yPercent; 1847 cc.defineGetterSetter(_p, "yPercent", _p._getYPercent, _p._setYPercent); 1848 /** @expose */ 1849 _p.widthPercent; 1850 cc.defineGetterSetter(_p, "widthPercent", _p._getWidthPercent, _p._setWidthPercent); 1851 /** @expose */ 1852 _p.heightPercent; 1853 cc.defineGetterSetter(_p, "heightPercent", _p._getHeightPercent, _p._setHeightPercent); 1854 /** @expose */ 1855 _p.widgetParent; 1856 cc.defineGetterSetter(_p, "widgetParent", _p.getWidgetParent); 1857 /** @expose */ 1858 _p.enabled; 1859 cc.defineGetterSetter(_p, "enabled", _p.isEnabled, _p.setEnabled); 1860 /** @expose */ 1861 _p.focused; 1862 cc.defineGetterSetter(_p, "focused", _p.isFocused, _p.setFocused); 1863 /** @expose */ 1864 _p.sizeType; 1865 cc.defineGetterSetter(_p, "sizeType", _p.getSizeType, _p.setSizeType); 1866 /** @expose */ 1867 _p.widgetType; 1868 cc.defineGetterSetter(_p, "widgetType", _p.getWidgetType); 1869 /** @expose */ 1870 _p.touchEnabled; 1871 cc.defineGetterSetter(_p, "touchEnabled", _p.isTouchEnabled, _p.setTouchEnabled); 1872 /** @expose */ 1873 _p.updateEnabled; 1874 cc.defineGetterSetter(_p, "updateEnabled", _p.isUpdateEnabled, _p.setUpdateEnabled); 1875 /** @expose */ 1876 _p.bright; 1877 cc.defineGetterSetter(_p, "bright", _p.isBright, _p.setBright); 1878 /** @expose */ 1879 _p.name; 1880 cc.defineGetterSetter(_p, "name", _p.getName, _p.setName); 1881 /** @expose */ 1882 _p.actionTag; 1883 cc.defineGetterSetter(_p, "actionTag", _p.getActionTag, _p.setActionTag); 1884 /** @expose */ 1885 _p.opacity; 1886 cc.defineGetterSetter(_p, "opacity", _p.getOpacity, _p.setOpacity); 1887 1888 _p = null; 1889 1890 /** 1891 * allocates and initializes a UIWidget. 1892 * @deprecated 1893 * @return {ccui.Widget} 1894 */ 1895 ccui.Widget.create = function () { 1896 return new ccui.Widget(); 1897 }; 1898 1899 ccui.Widget._focusedWidget = null; //both layout & widget will be stored in this variable 1900 ccui.Widget._focusNavigationController = null; 1901 1902 /** 1903 * call this method with parameter true to enable the Android Dpad focus navigation feature 1904 * @note it doesn't implemented on Web 1905 * @param {Boolean} enable set true to enable dpad focus navigation, otherwise disable dpad focus navigation 1906 */ 1907 ccui.Widget.enableDpadNavigation = function(enable){ 1908 if (enable){ 1909 if (null == ccui.Widget._focusNavigationController) { 1910 ccui.Widget._focusNavigationController = new ccui._FocusNavigationController(); 1911 if (ccui.Widget._focusedWidget) { 1912 ccui.Widget._focusNavigationController._setFirstFocsuedWidget(ccui.Widget._focusedWidget); 1913 } 1914 } 1915 ccui.Widget._focusNavigationController.enableFocusNavigation(true); 1916 } else { 1917 if(ccui.Widget._focusNavigationController){ 1918 ccui.Widget._focusNavigationController.enableFocusNavigation(false); 1919 ccui.Widget._focusNavigationController = null; 1920 } 1921 } 1922 }; 1923 1924 /** 1925 * Gets the focused widget of current stage. 1926 * @function 1927 * @returns {null|ccui.Widget} 1928 */ 1929 ccui.Widget.getCurrentFocusedWidget = function(){ 1930 return ccui.Widget._focusedWidget; 1931 }; 1932 1933 // Constants 1934 //bright style 1935 /** 1936 * None bright style of ccui.Widget. 1937 * @constant 1938 * @type {number} 1939 */ 1940 ccui.Widget.BRIGHT_STYLE_NONE = -1; 1941 /** 1942 * Normal bright style of ccui.Widget. 1943 * @constant 1944 * @type {number} 1945 */ 1946 ccui.Widget.BRIGHT_STYLE_NORMAL = 0; 1947 /** 1948 * Light bright style of ccui.Widget. 1949 * @constant 1950 * @type {number} 1951 */ 1952 ccui.Widget.BRIGHT_STYLE_HIGH_LIGHT = 1; 1953 1954 //widget type 1955 /** 1956 * The type code of Widget for ccui controls. 1957 * @constant 1958 * @type {number} 1959 */ 1960 ccui.Widget.TYPE_WIDGET = 0; 1961 /** 1962 * The type code of Container for ccui controls. 1963 * @constant 1964 * @type {number} 1965 */ 1966 ccui.Widget.TYPE_CONTAINER = 1; 1967 1968 //Focus Direction 1969 /** 1970 * The left of Focus direction for ccui.Widget 1971 * @constant 1972 * @type {number} 1973 */ 1974 ccui.Widget.LEFT = 0; 1975 /** 1976 * The right of Focus direction for ccui.Widget 1977 * @constant 1978 * @type {number} 1979 */ 1980 ccui.Widget.RIGHT = 1; 1981 /** 1982 * The up of Focus direction for ccui.Widget 1983 * @constant 1984 * @type {number} 1985 */ 1986 ccui.Widget.UP = 2; 1987 /** 1988 * The down of Focus direction for ccui.Widget 1989 * @constant 1990 * @type {number} 1991 */ 1992 ccui.Widget.DOWN = 3; 1993 1994 //texture resource type 1995 /** 1996 * The image file texture type of ccui.Widget loads. 1997 * @constant 1998 * @type {number} 1999 */ 2000 ccui.Widget.LOCAL_TEXTURE = 0; 2001 /** 2002 * The sprite frame texture type of ccui.Widget loads. 2003 * @constant 2004 * @type {number} 2005 */ 2006 ccui.Widget.PLIST_TEXTURE = 1; 2007 2008 //touch event type 2009 /** 2010 * The touch began type of ccui.Widget's touch event 2011 * @constant 2012 * @type {number} 2013 */ 2014 ccui.Widget.TOUCH_BEGAN = 0; 2015 /** 2016 * The touch moved type of ccui.Widget's touch event 2017 * @constant 2018 * @type {number} 2019 */ 2020 ccui.Widget.TOUCH_MOVED = 1; 2021 /** 2022 * The touch end type of ccui.Widget's touch event 2023 * @constant 2024 * @type {number} 2025 */ 2026 ccui.Widget.TOUCH_ENDED = 2; 2027 /** 2028 * The touch canceled type of ccui.Widget's touch event 2029 * @constant 2030 * @type {number} 2031 */ 2032 ccui.Widget.TOUCH_CANCELED = 3; 2033 2034 //size type 2035 /** 2036 * The absolute of ccui.Widget's size type. 2037 * @constant 2038 * @type {number} 2039 */ 2040 ccui.Widget.SIZE_ABSOLUTE = 0; 2041 /** 2042 * The percent of ccui.Widget's size type. 2043 * @constant 2044 * @type {number} 2045 */ 2046 ccui.Widget.SIZE_PERCENT = 1; 2047 2048 //position type 2049 /** 2050 * The absolute of ccui.Widget's position type. 2051 * @constant 2052 * @type {number} 2053 */ 2054 ccui.Widget.POSITION_ABSOLUTE = 0; 2055 /** 2056 * The percent of ccui.Widget's position type. 2057 * @constant 2058 * @type {number} 2059 */ 2060 ccui.Widget.POSITION_PERCENT = 1; 2061