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 /** 27 * Base class for ccui.Widget 28 * @sample 29 * var uiWidget = ccui.Widget.create(); 30 * this.addChild(uiWidget); 31 * @class 32 * @extends ccui.Node 33 * 34 * @property {Number} xPercent - Position x in percentage of width 35 * @property {Number} yPercent - Position y in percentage of height 36 * @property {Number} widthPercent - Width in percentage of parent width 37 * @property {Number} heightPercent - Height in percentage of parent height 38 * @property {ccui.Widget} widgetParent - <@readonly> The direct parent when it's a widget also, otherwise equals null 39 * @property {Boolean} enabled - Indicate whether the widget is enabled 40 * @property {Boolean} focused - Indicate whether the widget is focused 41 * @property {ccui.Widget.SIZE_ABSOLUTE|ccui.Widget.SIZE_PERCENT} sizeType - The size type of the widget 42 * @property {ccui.Widget.TYPE_WIDGET|ccui.Widget.TYPE_CONTAINER} widgetType - <@readonly> The type of the widget 43 * @property {Boolean} touchEnabled - Indicate whether touch events are enabled 44 * @property {Boolean} updateEnabled - Indicate whether the update function is scheduled 45 * @property {Boolean} bright - Indicate whether the widget is bright 46 * @property {String} name - The name of the widget 47 * @property {Number} actionTag - The action tag of the widget 48 */ 49 ccui.Widget = ccui.Node.extend(/** @lends ccui.Widget# */{ 50 51 RGBAProtocol: true, 52 _enabled: true, ///< Highest control of widget 53 _bright: true, ///< is this widget bright 54 _touchEnabled: false, ///< is this widget touch endabled 55 _touchPassedEnabled: false, ///< is the touch event should be passed 56 _focus: false, ///< is the widget on focus 57 _brightStyle: null, ///< bright style 58 _updateEnabled: false, ///< is "update" method scheduled 59 _touchStartPos: null, ///< touch began point 60 _touchMovePos: null, ///< touch moved point 61 _touchEndPos: null, ///< touch ended point 62 63 _touchEventListener: null, 64 _touchEventSelector: null, 65 66 _name: "default", 67 _widgetType: null, 68 _actionTag: 0, 69 _size: cc.size(0, 0), 70 _customSize: null, 71 _layoutParameterDictionary: null, 72 _ignoreSize: false, 73 _widgetChildren: null, 74 _affectByClipping: false, 75 76 _sizeType: null, 77 _sizePercent: null, 78 positionType: null, 79 _positionPercent: null, 80 _reorderWidgetChildDirty: false, 81 _hitted: false, 82 _nodes: null, 83 _touchListener: null, 84 _color: null, 85 _className: "Widget", 86 _flippedX: false, 87 _flippedY: false, 88 ctor: function () { 89 cc.Node.prototype.ctor.call(this); 90 this._brightStyle = ccui.Widget.BRIGHT_STYLE_NONE; 91 this._touchStartPos = cc.p(0, 0); 92 this._touchMovePos = cc.p(0, 0); 93 this._touchEndPos = cc.p(0, 0); 94 this._widgetType = ccui.Widget.TYPE_WIDGET; 95 this._size = cc.size(0, 0); 96 this._customSize = cc.size(0, 0); 97 this._layoutParameterDictionary = {}; 98 this._widgetChildren = []; 99 this._sizeType = ccui.Widget.SIZE_ABSOLUTE; 100 this._sizePercent = cc.p(0, 0); 101 this.positionType = ccui.Widget.POSITION_ABSOLUTE; 102 this._positionPercent = cc.p(0, 0); 103 this._nodes = []; 104 this._color = cc.color(255, 255, 255, 255); 105 this.init(); 106 }, 107 108 /** 109 * initializes state of widget. 110 * @returns {boolean} 111 */ 112 init: function () { 113 if (cc.Node.prototype.init.call(this)) { 114 this._layoutParameterDictionary = {}; 115 this._widgetChildren = []; 116 this.initRenderer(); 117 this.setBright(true); 118 this.ignoreContentAdaptWithSize(true); 119 this.setAnchorPoint(cc.p(0.5, 0.5)); 120 } 121 return true; 122 }, 123 124 onEnter: function () { 125 this.updateSizeAndPosition(); 126 cc.Node.prototype.onEnter.call(this); 127 }, 128 129 visit: function (ctx) { 130 if (this._enabled) { 131 cc.Node.prototype.visit.call(this, ctx); 132 } 133 }, 134 135 sortAllChildren: function () { 136 this._reorderWidgetChildDirty = this._reorderChildDirty; 137 cc.Node.prototype.sortAllChildren.call(this); 138 if (this._reorderWidgetChildDirty) { 139 var _children = this._widgetChildren; 140 var i, j, length = _children.length, tempChild; 141 142 // insertion sort 143 for (i = 0; i < length; i++) { 144 var tempItem = _children[i]; 145 j = i - 1; 146 tempChild = _children[j]; 147 148 //continue moving element downwards while zOrder is smaller or when zOrder is the same but mutatedIndex is smaller 149 while (j >= 0 && ( tempItem._localZOrder < tempChild._localZOrder || 150 ( tempItem._localZOrder == tempChild._localZOrder && tempItem.arrivalOrder < tempChild.arrivalOrder ))) { 151 _children[j + 1] = tempChild; 152 j = j - 1; 153 tempChild = _children[j]; 154 } 155 _children[j + 1] = tempItem; 156 } 157 158 //don't need to check children recursively, that's done in visit of each child 159 160 this._reorderWidgetChildDirty = false; 161 } 162 }, 163 164 /** 165 * Adds a child to the container. 166 * @param {ccui.Widget} widget 167 * @param {Number} zOrder 168 * @param {Number} tag 169 */ 170 addChild: function (widget, zOrder, tag) { 171 if (widget instanceof ccui.Widget) { 172 cc.Node.prototype.addChild.call(this, widget, zOrder, tag); 173 this._widgetChildren.push(widget); 174 return; 175 } 176 if (widget instanceof cc.Node) { 177 cc.log("Please use addNode to add a CCNode."); 178 return; 179 } 180 }, 181 182 /** 183 * 184 * @param tag 185 * @returns {ccui.Widget} 186 */ 187 getChildByTag: function (tag) { 188 var __children = this._widgetChildren; 189 if (__children != null) { 190 for (var i = 0; i < __children.length; i++) { 191 var node = __children[i]; 192 if (node && node.tag == tag) 193 return node; 194 } 195 } 196 return null; 197 }, 198 199 /** 200 * Return an array of children 201 * @returns {Array} 202 */ 203 getChildren: function () { 204 return this._widgetChildren; 205 }, 206 207 /** 208 * get the count of children 209 * @returns {Number} 210 */ 211 getChildrenCount: function () { 212 return this._widgetChildren.length; 213 }, 214 215 getWidgetParent: function () { 216 var widget = this.getParent(); 217 if (widget instanceof ccui.Widget) { 218 return widget; 219 } 220 return null; 221 }, 222 223 /** 224 * remove child 225 * @param {ccui.Widget} widget 226 * @param {Boolean} cleanup 227 */ 228 removeChild: function (widget, cleanup) { 229 if (!(widget instanceof ccui.Widget)) { 230 cc.log("child must a type of ccui.Widget"); 231 return; 232 } 233 cc.Node.prototype.removeChild.call(this, widget, cleanup); 234 cc.arrayRemoveObject(this._widgetChildren, widget); 235 }, 236 237 removeChildByTag: function (tag, cleanup) { 238 var child = this.getChildByTag(tag); 239 240 if (child == null) { 241 cc.log("cocos2d: removeChildByTag(tag = " + tag + "): child not found!"); 242 } 243 else { 244 this.removeChild(child, cleanup); 245 } 246 }, 247 248 /** 249 * Removes all children from the container, and do a cleanup to all running actions depending on the cleanup parameter. 250 */ 251 removeAllChildren: function (cleanup) { 252 for (var i = 0; i < this._widgetChildren.length; i++) { 253 var widget = this._widgetChildren[i]; 254 cc.Node.prototype.removeChild.call(this, widget, cleanup); 255 } 256 this._widgetChildren.length = 0; 257 }, 258 259 /** 260 * Set enabled renderer 261 * @param {Boolean} enabled 262 */ 263 setEnabled: function (enabled) { 264 this._enabled = enabled; 265 var arrayChildren = this._widgetChildren; 266 var childrenCount = arrayChildren.length; 267 for (var i = 0; i < childrenCount; i++) { 268 var child = arrayChildren[i]; 269 child.setEnabled(enabled); 270 } 271 }, 272 273 /** 274 * Gets a child from the container with its name 275 * @param {string} name 276 * @returns {ccui.Widget} 277 */ 278 getChildByName: function (name) { 279 var arrayChildren = this._widgetChildren; 280 var childrenCount = arrayChildren.length; 281 for (var i = 0; i < childrenCount; i++) { 282 var child = arrayChildren[i]; 283 if (child.getName() == name) { 284 return child; 285 } 286 } 287 }, 288 289 /** 290 * initializes renderer of widget. 291 */ 292 initRenderer: function () { 293 }, 294 295 /** 296 * add node for widget 297 * @param {cc.Node} node 298 * @param {Number} zOrder 299 * @param {Number} tag 300 */ 301 addNode: function (node, zOrder, tag) { 302 if (node instanceof ccui.Widget) { 303 cc.log("Please use addChild to add a Widget."); 304 return; 305 } 306 cc.Node.prototype.addChild.call(this, node, zOrder, tag); 307 this._nodes.push(node); 308 }, 309 310 /** 311 * get node by tag 312 * @param {Number} tag 313 * @returns {cc.Node} 314 */ 315 getNodeByTag: function (tag) { 316 var _nodes = this._nodes; 317 for (var i = 0; i < _nodes.length; i++) { 318 var node = _nodes[i]; 319 if (node && node.getTag() == tag) { 320 return node; 321 } 322 } 323 return null; 324 }, 325 326 /** 327 * get all node 328 * @returns {Array} 329 */ 330 getNodes: function () { 331 return this._nodes; 332 }, 333 334 /** 335 * remove node 336 * @param {cc.Node} node 337 * @param {Boolean} cleanup 338 */ 339 removeNode: function (node, cleanup) { 340 cc.Node.prototype.removeChild.call(this, node); 341 cc.arrayRemoveObject(this._nodes, node); 342 }, 343 344 /** 345 * remove node by tag 346 * @param {Number} tag 347 * @param {Boolean} cleanup 348 */ 349 removeNodeByTag: function (tag, cleanup) { 350 var node = this.getNodeByTag(tag); 351 if (!node) { 352 cc.log("cocos2d: removeNodeByTag(tag = %d): child not found!", tag); 353 } 354 else { 355 this.removeNode(node); 356 } 357 }, 358 359 /** 360 * remove all node 361 */ 362 removeAllNodes: function () { 363 for (var i = 0; i < this._nodes.length; i++) { 364 var node = this._nodes[i]; 365 cc.Node.prototype.removeChild.call(this, node); 366 } 367 this._nodes.length = 0; 368 }, 369 370 /** 371 * Changes the size that is widget's size 372 * @param {cc.Size} size 373 */ 374 setSize: function (size) { 375 var locW = this._customSize.width = size.width; 376 var locH = this._customSize.height = size.height; 377 if (this._ignoreSize) { 378 locW = this.width; 379 locH = this.height; 380 } 381 this._size.width = locW; 382 this._size.height = locH; 383 384 if (this._running) { 385 var widgetParent = this.getWidgetParent(); 386 if (widgetParent) { 387 locW = widgetParent.width; 388 locH = widgetParent.height; 389 } else { 390 locW = this._parent.width; 391 locH = this._parent.height; 392 } 393 this._sizePercent.x = locW > 0 ? this._customSize.width / locW : 0; 394 this._sizePercent.y = locH > 0 ? this._customSize.height / locH : 0; 395 } 396 this.onSizeChanged(); 397 }, 398 _setWidth: function (w) { 399 var locW = this._customSize.width = w; 400 this._ignoreSize && (locW = this.width); 401 this._size.width = locW; 402 403 if (this._running) { 404 var widgetParent = this.getWidgetParent(); 405 locW = widgetParent ? widgetParent.width : this._parent.width; 406 this._sizePercent.x = locW > 0 ? this._customSize.width / locW : 0; 407 } 408 this.onSizeChanged(); 409 }, 410 _setHeight: function (h) { 411 var locH = this._customSize.height = h; 412 this._ignoreSize && (locH = this.height); 413 this._size.height = locH; 414 415 if (this._running) { 416 var widgetParent = this.getWidgetParent(); 417 locH = widgetParent ? widgetParent.height : this._parent.height; 418 this._sizePercent.y = locH > 0 ? this._customSize.height / locH : 0; 419 } 420 this.onSizeChanged(); 421 }, 422 423 /** 424 * Changes the percent that is widget's percent size 425 * @param {cc.Point} percent 426 */ 427 setSizePercent: function (percent) { 428 this._sizePercent.x = percent.x; 429 this._sizePercent.y = percent.y; 430 var width = this._customSize.width, height = this._customSize.height; 431 if (this._running) { 432 var widgetParent = this.getWidgetParent(); 433 if (widgetParent) { 434 width = widgetParent.width * percent.x; 435 height = widgetParent.height * percent.y; 436 } 437 else { 438 width = this._parent.width * percent.x; 439 height = this._parent.height * percent.y; 440 } 441 } 442 if (!this._ignoreSize) { 443 this._size.width = width; 444 this._size.height = height; 445 } 446 this._customSize.width = width; 447 this._customSize.height = height; 448 this.onSizeChanged(); 449 }, 450 _setWidthPercent: function (percent) { 451 this._sizePercent.x = percent; 452 var width = this._customSize.width; 453 if (this._running) { 454 var widgetParent = this.getWidgetParent(); 455 width = (widgetParent ? widgetParent.width : this._parent.width) * percent; 456 } 457 this._ignoreSize || (this._size.width = width); 458 this._customSize.width = width; 459 this.onSizeChanged(); 460 }, 461 _setHeightPercent: function (percent) { 462 this._sizePercent.y = percent; 463 var height = this._customSize.height; 464 if (this._running) { 465 var widgetParent = this.getWidgetParent(); 466 height = (widgetParent ? widgetParent.height : this._parent.height) * percent; 467 } 468 this._ignoreSize || (this._size.height = height); 469 this._customSize.height = height; 470 this.onSizeChanged(); 471 }, 472 473 /** 474 * update size and position 475 */ 476 updateSizeAndPosition: function () { 477 switch (this._sizeType) { 478 case ccui.Widget.SIZE_ABSOLUTE: 479 var locSize; 480 if (this._ignoreSize) { 481 locSize = this.getContentSize(); 482 } 483 else { 484 locSize = this._customSize; 485 } 486 this._size.width = locSize.width; 487 this._size.height = locSize.height; 488 489 var pSize, spx = 0, spy = 0; 490 var widgetParent = this.getWidgetParent(); 491 if (widgetParent) { 492 pSize = widgetParent.getSize(); 493 } else { 494 pSize = this._parent.getContentSize(); 495 } 496 if (pSize.width > 0) { 497 spx = this._customSize.width / pSize.width; 498 } 499 if (pSize.height > 0) { 500 spy = this._customSize.height / pSize.height; 501 } 502 this._sizePercent.x = spx; 503 this._sizePercent.y = spy; 504 break; 505 case ccui.Widget.SIZE_PERCENT: 506 var widgetParent = this.getWidgetParent(); 507 var cSize = cc.size(0, 0); 508 if (widgetParent) { 509 cSize.width = widgetParent.getSize().width * this._sizePercent.x; 510 cSize.height = widgetParent.getSize().height * this._sizePercent.y; 511 } else { 512 cSize.width = this._parent.getContentSize().width * this._sizePercent.x; 513 cSize.height = this._parent.getContentSize().height * this._sizePercent.y; 514 } 515 var locSize; 516 if (this._ignoreSize) { 517 locSize = this.getContentSize(); 518 } 519 else { 520 locSize = cSize; 521 } 522 this._size.width = locSize.width; 523 this._size.height = locSize.height; 524 this._customSize.width = cSize.width; 525 this._customSize.height = cSize.height; 526 break; 527 default: 528 break; 529 } 530 this.onSizeChanged(); 531 var absPos = this.getPosition(); 532 switch (this.positionType) { 533 case ccui.Widget.POSITION_ABSOLUTE: 534 var widgetParent = this.getWidgetParent(); 535 var pSize; 536 if (widgetParent) { 537 pSize = widgetParent.getSize(); 538 } else { 539 pSize = this._parent.getContentSize(); 540 } 541 if (pSize.width <= 0 || pSize.height <= 0) { 542 this._positionPercent.x = 0; 543 this._positionPercent.y = 0; 544 } else { 545 this._positionPercent.x = absPos.x / pSize.width; 546 this._positionPercent.y = absPos.y / pSize.height; 547 } 548 break; 549 case ccui.Widget.POSITION_PERCENT: 550 var widgetParent = this.getWidgetParent(); 551 var pSize; 552 if (widgetParent) { 553 pSize = widgetParent.getSize(); 554 } else { 555 pSize = this._parent.getContentSize(); 556 } 557 absPos = cc.p(pSize.width * this._positionPercent.x, pSize.height * this._positionPercent.y); 558 break; 559 default: 560 break; 561 } 562 this.setPosition(absPos); 563 }, 564 565 /**TEXTURE_RES_TYPE 566 * Changes the size type of widget. 567 * @param {ccui.Widget.SIZE_ABSOLUTE|ccui.Widget.SIZE_PERCENT} type 568 */ 569 setSizeType: function (type) { 570 this._sizeType = type; 571 }, 572 573 /** 574 * Gets the size type of widget. 575 * @returns {ccui.Widget.SIZE_ABSOLUTE|ccui.Widget.SIZE_PERCENT} 576 */ 577 getSizeType: function () { 578 return this._sizeType; 579 }, 580 581 /** 582 * Ignore the widget size 583 * @param {Boolean} ignore 584 */ 585 ignoreContentAdaptWithSize: function (ignore) { 586 this._ignoreSize = ignore; 587 var locSize; 588 if (this._ignoreSize) { 589 locSize = this.getContentSize(); 590 } 591 else { 592 locSize = this._customSize; 593 } 594 this._size.width = locSize.width; 595 this._size.height = locSize.height; 596 this.onSizeChanged(); 597 }, 598 599 /** 600 * Gets the widget if is ignore it's size. 601 * @returns {boolean} 602 */ 603 isIgnoreContentAdaptWithSize: function () { 604 return this._ignoreSize; 605 }, 606 607 /** 608 * Returns size of widget 609 * @returns {cc.Size} 610 */ 611 getSize: function () { 612 return this._size; 613 }, 614 615 /** 616 * Get custom size 617 * @returns {cc.Size} 618 */ 619 getCustomSize: function () { 620 return this._customSize 621 }, 622 623 /** 624 * Returns size percent of widget 625 * @returns {cc.Point} 626 */ 627 getSizePercent: function () { 628 return this._sizePercent; 629 }, 630 _getWidthPercent: function () { 631 return this._sizePercent.x; 632 }, 633 _getHeightPercent: function () { 634 return this._sizePercent.y; 635 }, 636 637 /** 638 * Gets world position of widget. 639 * @returns {cc.Point} 640 */ 641 getWorldPosition: function () { 642 return this.convertToWorldSpace(cc.p(0, 0)); 643 }, 644 645 /** 646 * Gets the Virtual Renderer of widget. 647 * @returns {cc.Node} 648 */ 649 getVirtualRenderer: function () { 650 return this; 651 }, 652 653 /** 654 * call back function called when size changed. 655 */ 656 onSizeChanged: function () { 657 for (var i = 0; i < this._widgetChildren.length; i++) { 658 var child = this._widgetChildren[i]; 659 child.updateSizeAndPosition(); 660 } 661 }, 662 663 /** 664 * Gets the content size of widget. 665 * @returns {cc.Size} 666 */ 667 getContentSize: function () { 668 return this._size; 669 }, 670 _getWidth: function () { 671 return this._size.width; 672 }, 673 _getHeight: function () { 674 return this._size.height; 675 }, 676 677 /** 678 * Sets whether the widget is touch enabled 679 * @param enable 680 */ 681 setTouchEnabled: function (enable) { 682 if (this._touchEnabled === enable) { 683 return; 684 } 685 this._touchEnabled = enable; 686 if (this._touchEnabled) { 687 this._touchListener = cc.EventListener.create({ 688 event: cc.EventListener.TOUCH_ONE_BY_ONE, 689 swallowTouches: true, 690 onTouchBegan: this.onTouchBegan.bind(this), 691 onTouchMoved: this.onTouchMoved.bind(this), 692 onTouchEnded: this.onTouchEnded.bind(this) 693 }); 694 cc.eventManager.addListener(this._touchListener, this); 695 } else { 696 cc.eventManager.removeListener(this._touchListener); 697 } 698 }, 699 700 /** 701 * To set the bright style of widget. 702 * @returns {boolean} 703 */ 704 isTouchEnabled: function () { 705 return this._touchEnabled; 706 }, 707 708 /** 709 * Schedules the "update" method. 710 * @param enable 711 */ 712 setUpdateEnabled: function (enable) { 713 if (this._updateEnabled == enable) { 714 return; 715 } 716 this._updateEnabled = enable; 717 if (enable) { 718 this.scheduleUpdate(); 719 } 720 else { 721 this.unscheduleUpdate(); 722 } 723 }, 724 725 /** 726 * is the "update" method scheduled. 727 * @returns {boolean} 728 */ 729 isUpdateEnabled: function () { 730 return this._updateEnabled; 731 }, 732 733 /** 734 * Determines if the widget is on focused 735 * @returns {boolean} 736 */ 737 isFocused: function () { 738 return this._focus; 739 }, 740 741 /** 742 * Sets whether the widget is on focused 743 * The default value is false, a widget is default to not on focused 744 * @param {boolean} fucos 745 */ 746 setFocused: function (fucos) { 747 if (fucos == this._focus) { 748 return; 749 } 750 this._focus = fucos; 751 if (this._bright) { 752 if (this._focus) { 753 this.setBrightStyle(ccui.Widget.BRIGHT_STYLE_HIGH_LIGHT); 754 } 755 else { 756 this.setBrightStyle(ccui.Widget.BRIGHT_STYLE_NORMAL); 757 } 758 } 759 else { 760 this.onPressStateChangedToDisabled(); 761 } 762 }, 763 764 setBright: function (bright, containChild) { 765 this._bright = bright; 766 if (this._bright) { 767 this._brightStyle = ccui.Widget.BRIGHT_STYLE_NONE; 768 this.setBrightStyle(ccui.Widget.BRIGHT_STYLE_NORMAL); 769 } 770 else { 771 this.onPressStateChangedToDisabled(); 772 } 773 }, 774 775 /** 776 * To set the bright style of widget. 777 * @param {ccui.Widget.BRIGHT_STYLE_NONE|ccui.Widget.BRIGHT_STYLE_NORMAL|ccui.Widget.BRIGHT_STYLE_HIGH_LIGHT} style 778 */ 779 setBrightStyle: function (style) { 780 if (this._brightStyle == style) { 781 return; 782 } 783 style = style || ccui.Widget.BRIGHT_STYLE_NORMAL; 784 this._brightStyle = style; 785 switch (this._brightStyle) { 786 case ccui.Widget.BRIGHT_STYLE_NORMAL: 787 this.onPressStateChangedToNormal(); 788 break; 789 case ccui.Widget.BRIGHT_STYLE_HIGH_LIGHT: 790 this.onPressStateChangedToPressed(); 791 break; 792 default: 793 break; 794 } 795 }, 796 797 /** 798 * call back function called widget's state changed to normal. 799 */ 800 onPressStateChangedToNormal: function () { 801 802 }, 803 804 /** 805 * call back function called widget's state changed to selected. 806 */ 807 onPressStateChangedToPressed: function () { 808 809 }, 810 811 /** 812 * call back function called widget's state changed to dark. 813 */ 814 onPressStateChangedToDisabled: function () { 815 816 }, 817 818 /** 819 * A call back function when widget lost of focus. 820 */ 821 didNotSelectSelf: function () { 822 823 }, 824 825 onTouchBegan: function (touch, event) { 826 var touchPoint = touch.getLocation(); 827 this._touchStartPos.x = touchPoint.x; 828 this._touchStartPos.y = touchPoint.y; 829 this._hitted = this.isEnabled() && this.isTouchEnabled() && this.hitTest(touchPoint) && this.clippingParentAreaContainPoint(touchPoint); 830 if (!this._hitted) { 831 return false; 832 } 833 this.setFocused(true); 834 var widgetParent = this.getWidgetParent(); 835 if (widgetParent) { 836 widgetParent.checkChildInfo(0, this, touchPoint); 837 } 838 this.pushDownEvent(); 839 return !this._touchPassedEnabled; 840 }, 841 842 onTouchMoved: function (touch, event) { 843 var touchPoint = touch.getLocation(); 844 this._touchMovePos.x = touchPoint.x; 845 this._touchMovePos.y = touchPoint.y; 846 this.setFocused(this.hitTest(touchPoint)); 847 var widgetParent = this.getWidgetParent(); 848 if (widgetParent) { 849 widgetParent.checkChildInfo(1, this, touchPoint); 850 } 851 this.moveEvent(); 852 }, 853 854 855 onTouchEnded: function (touch, event) { 856 var touchPoint = touch.getLocation(); 857 this._touchEndPos.x = touchPoint.x; 858 this._touchEndPos.y = touchPoint.y; 859 var focus = this._focus; 860 this.setFocused(false); 861 var widgetParent = this.getWidgetParent(); 862 if (widgetParent) { 863 widgetParent.checkChildInfo(2, this, touchPoint); 864 } 865 if (focus) { 866 this.releaseUpEvent(); 867 } 868 else { 869 this.cancelUpEvent(); 870 } 871 }, 872 873 /** 874 * A call back function called when widget is selected, and on touch canceled. 875 * @param {cc.Point} touchPoint 876 */ 877 onTouchCancelled: function (touchPoint) { 878 this.setFocused(false); 879 this.cancelUpEvent(); 880 }, 881 882 /** 883 * A call back function called when widget is selected, and on touch long clicked. 884 * @param {cc.Point} touchPoint 885 */ 886 onTouchLongClicked: function (touchPoint) { 887 this.longClickEvent(); 888 }, 889 890 //call back function called widget's state changed to dark. 891 892 pushDownEvent: function () { 893 if (this._touchEventListener && this._touchEventSelector) { 894 if (this._touchEventSelector) { 895 this._touchEventSelector.call(this._touchEventListener, this, ccui.Widget.TOUCH_BEGAN); 896 } 897 } 898 }, 899 900 moveEvent: function () { 901 if (this._touchEventListener && this._touchEventSelector) { 902 if (this._touchEventSelector) { 903 this._touchEventSelector.call(this._touchEventListener, this, ccui.Widget.TOUCH_MOVED); 904 } 905 } 906 }, 907 908 releaseUpEvent: function () { 909 if (this._touchEventListener && this._touchEventSelector) { 910 if (this._touchEventSelector) { 911 this._touchEventSelector.call(this._touchEventListener, this, ccui.Widget.TOUCH_ENDED); 912 } 913 } 914 }, 915 916 cancelUpEvent: function () { 917 if (this._touchEventSelector) { 918 this._touchEventSelector.call(this._touchEventListener, this, ccui.Widget.TOUCH_CANCELED); 919 } 920 }, 921 922 longClickEvent: function () { 923 924 }, 925 926 /** 927 * Sets the touch event target/selector of the menu item 928 * @param {Function} selector 929 * @param {Object} target 930 */ 931 addTouchEventListener: function (selector, target) { 932 this._touchEventSelector = selector; 933 this._touchEventListener = target; 934 }, 935 936 /** 937 * Checks a point if is in widget's space 938 * @param {cc.Point} pt 939 * @returns {boolean} 940 */ 941 hitTest: function (pt) { 942 var nsp = this.convertToNodeSpace(pt); 943 var bb = cc.rect(-this._size.width * this._anchorPoint.x, -this._size.height * this._anchorPoint.y, this._size.width, this._size.height); 944 if (nsp.x >= bb.x && nsp.x <= bb.x + bb.width && nsp.y >= bb.y && nsp.y <= bb.y + bb.height) { 945 return true; 946 } 947 return false; 948 }, 949 950 /** 951 * Checks a point if in parent's area. 952 * @param {cc.Point} pt 953 * @returns {Boolean} 954 */ 955 clippingParentAreaContainPoint: function (pt) { 956 this._affectByClipping = false; 957 var parent = this.getParent(); 958 var clippingParent = null; 959 while (parent) { 960 if (parent instanceof ccui.Layout) { 961 if (parent.isClippingEnabled()) { 962 this._affectByClipping = true; 963 clippingParent = parent; 964 break; 965 } 966 } 967 parent = parent.getParent(); 968 } 969 970 if (!this._affectByClipping) { 971 return true; 972 } 973 974 975 if (clippingParent) { 976 var bRet = false; 977 if (clippingParent.hitTest(pt)) { 978 bRet = true; 979 } 980 if (bRet) { 981 return clippingParent.clippingParentAreaContainPoint(pt); 982 } 983 return false; 984 } 985 return true; 986 }, 987 988 /** 989 * Sends the touch event to widget's parent 990 * @param {number} handleState 991 * @param {ccui.Widget} sender 992 * @param {cc.Point} touchPoint 993 */ 994 checkChildInfo: function (handleState, sender, touchPoint) { 995 var widgetParent = this.getWidgetParent(); 996 if (widgetParent) { 997 widgetParent.checkChildInfo(handleState, sender, touchPoint); 998 } 999 }, 1000 1001 /** 1002 * Changes the position (x,y) of the widget . 1003 * @param {cc.Point||Number} pos 1004 * @param {Number} posY 1005 */ 1006 setPosition: function (pos, posY) { 1007 if (this._running) { 1008 var widgetParent = this.getWidgetParent(); 1009 if (widgetParent) { 1010 var pSize = widgetParent.getSize(); 1011 if (pSize.width <= 0 || pSize.height <= 0) { 1012 this._positionPercent.x = 0; 1013 this._positionPercent.y = 0; 1014 } 1015 else { 1016 if (posY) { 1017 this._positionPercent.x = pos / pSize.width; 1018 this._positionPercent.y = posY / pSize.height; 1019 } else { 1020 this._positionPercent.x = pos.x / pSize.width; 1021 this._positionPercent.y = pos.y / pSize.height; 1022 } 1023 } 1024 } 1025 } 1026 1027 cc.Node.prototype.setPosition.apply(this, arguments); 1028 }, 1029 1030 setPositionX: function (x) { 1031 if (this._running) { 1032 var widgetParent = this.getWidgetParent(); 1033 if (widgetParent) { 1034 var pw = widgetParent.width; 1035 if (pw <= 0) 1036 this._positionPercent.x = 0; 1037 else 1038 this._positionPercent.x = x / pw; 1039 } 1040 } 1041 1042 cc.Node.prototype.setPositionX.call(this, x); 1043 }, 1044 setPositionY: function (y) { 1045 if (this._running) { 1046 var widgetParent = this.getWidgetParent(); 1047 if (widgetParent) { 1048 var ph = widgetParent.height; 1049 if (ph <= 0) 1050 this._positionPercent.y = 0; 1051 else 1052 this._positionPercent.y = y / ph; 1053 } 1054 } 1055 1056 cc.Node.prototype.setPositionY.call(this, y); 1057 }, 1058 1059 /** 1060 * Changes the position (x,y) of the widget 1061 * @param {cc.Point} percent 1062 */ 1063 setPositionPercent: function (percent) { 1064 this._positionPercent = percent; 1065 if (this._running) { 1066 var widgetParent = this.getWidgetParent(); 1067 if (widgetParent) { 1068 var parentSize = widgetParent.getSize(); 1069 this.setPosition(parentSize.width * this._positionPercent.x, parentSize.height * this._positionPercent.y); 1070 } 1071 } 1072 }, 1073 _setXPercent: function (percent) { 1074 this._positionPercent.x = percent; 1075 if (this._running) { 1076 var widgetParent = this.getWidgetParent(); 1077 if (widgetParent) { 1078 var absX = widgetParent.width * percent; 1079 this.setPositionX(absX); 1080 } 1081 } 1082 }, 1083 _setYPercent: function (percent) { 1084 this._positionPercent.y = percent; 1085 if (this._running) { 1086 var widgetParent = this.getWidgetParent(); 1087 if (widgetParent) { 1088 var absY = widgetParent.height * percent; 1089 this.setPositionY(absY); 1090 } 1091 } 1092 }, 1093 1094 updateAnchorPoint: function () { 1095 this.setAnchorPoint(this.getAnchorPoint()); 1096 }, 1097 1098 /** 1099 * Gets the percent (x,y) of the widget 1100 * @returns {cc.Point} 1101 */ 1102 getPositionPercent: function () { 1103 return this._positionPercent; 1104 }, 1105 _getXPercent: function () { 1106 return this._positionPercent.x; 1107 }, 1108 _getYPercent: function () { 1109 return this._positionPercent.y; 1110 }, 1111 1112 /** 1113 * Changes the position type of the widget 1114 * @param {ccui.Widget.POSITION_ABSOLUTE|ccui.Widget.POSITION_PERCENT} type 1115 */ 1116 setPositionType: function (type) { 1117 this.positionType = type; 1118 }, 1119 1120 /** 1121 * Gets the position type of the widget 1122 * @returns {cc.pPositionType} 1123 */ 1124 getPositionType: function () { 1125 return this.positionType; 1126 }, 1127 1128 /** 1129 * Set flipped x 1130 * @param {Boolean} flipX 1131 */ 1132 setFlippedX: function (flipX) { 1133 this._flippedX = flipX; 1134 this.updateFlippedX(); 1135 }, 1136 1137 /** 1138 * Get flipped x 1139 * @returns {Boolean} 1140 */ 1141 isFlippedX: function () { 1142 return this._flippedX; 1143 }, 1144 1145 /** 1146 * Set flipped y 1147 * @param {Boolean} flipY 1148 */ 1149 setFlippedY: function (flipY) { 1150 this._flippedY = flipY; 1151 this.updateFlippedY(); 1152 }, 1153 1154 /** 1155 * Get flipped y 1156 * @returns {Boolean} 1157 */ 1158 isFlippedY: function () { 1159 return this._flippedY; 1160 }, 1161 1162 updateFlippedX: function () { 1163 1164 }, 1165 1166 updateFlippedY: function () { 1167 1168 }, 1169 1170 /** 1171 * Determines if the widget is bright 1172 * @returns {boolean} 1173 */ 1174 isBright: function () { 1175 return this._bright; 1176 }, 1177 1178 /** 1179 * Determines if the widget is enabled 1180 * @returns {boolean} 1181 */ 1182 isEnabled: function () { 1183 return this._enabled; 1184 }, 1185 1186 /** 1187 * Gets the left boundary position of this widget. 1188 * @returns {number} 1189 */ 1190 getLeftInParent: function () { 1191 return this.getPositionX() - this._getAnchorX() * this._size.width; 1192 }, 1193 1194 /** 1195 * Gets the bottom boundary position of this widget. 1196 * @returns {number} 1197 */ 1198 getBottomInParent: function () { 1199 return this.getPositionY() - this._getAnchorY() * this._size.height; 1200 }, 1201 1202 /** 1203 * Gets the right boundary position of this widget. 1204 * @returns {number} 1205 */ 1206 getRightInParent: function () { 1207 return this.getLeftInParent() + this._size.width; 1208 }, 1209 1210 /** 1211 * Gets the top boundary position of this widget. 1212 * @returns {number} 1213 */ 1214 getTopInParent: function () { 1215 return this.getBottomInParent() + this._size.height; 1216 }, 1217 1218 /** 1219 * Gets touch start position 1220 * @returns {cc.Point} 1221 */ 1222 getTouchStartPos: function () { 1223 return this._touchStartPos; 1224 }, 1225 1226 /** 1227 * Gets touch move position 1228 * @returns {cc.Point} 1229 */ 1230 getTouchMovePos: function () { 1231 return this._touchMovePos; 1232 }, 1233 1234 /** 1235 * Gets touch end position 1236 * @returns {cc.Point} 1237 */ 1238 getTouchEndPos: function () { 1239 return this._touchEndPos; 1240 }, 1241 1242 /** 1243 * Sets the name of widget 1244 * @param {String} name 1245 */ 1246 setName: function (name) { 1247 this._name = name; 1248 }, 1249 1250 /** 1251 * Gets the name of widget 1252 * @returns {string} 1253 */ 1254 getName: function () { 1255 return this._name; 1256 }, 1257 1258 /** 1259 * get widget type 1260 * @returns {ccui.Widget.TYPE_WIDGET|ccui.Widget.TYPE_CONTAINER} 1261 */ 1262 getWidgetType: function () { 1263 return this._widgetType; 1264 }, 1265 1266 /** 1267 * Sets layout parameter 1268 * @param {ccui.LayoutParameter} parameter 1269 */ 1270 setLayoutParameter: function (parameter) { 1271 this._layoutParameterDictionary[parameter.getLayoutType()] = parameter; 1272 }, 1273 1274 /** 1275 * Gets layout parameter 1276 * @param {ccui.LayoutParameter.NONE|ccui.LayoutParameter.LINEAR|ccui.LayoutParameter.RELATIVE} type 1277 * @returns {ccui.LayoutParameter} 1278 */ 1279 getLayoutParameter: function (type) { 1280 return this._layoutParameterDictionary[type]; 1281 }, 1282 1283 /** 1284 * Returns the "class name" of widget. 1285 * @returns {string} 1286 */ 1287 getDescription: function () { 1288 return "Widget"; 1289 }, 1290 1291 clone: function () { 1292 var clonedWidget = this.createCloneInstance(); 1293 clonedWidget.copyProperties(this); 1294 clonedWidget.copyClonedWidgetChildren(this); 1295 return clonedWidget; 1296 }, 1297 1298 createCloneInstance: function () { 1299 return ccui.Widget.create(); 1300 }, 1301 1302 copyClonedWidgetChildren: function (model) { 1303 var widgetChildren = model.getChildren(); 1304 for (var i = 0; i < widgetChildren.length; i++) { 1305 var locChild = widgetChildren[i]; 1306 if (locChild instanceof ccui.Widget) { 1307 this.addChild(locChild.clone()); 1308 } 1309 } 1310 }, 1311 1312 copySpecialProperties: function (model) { 1313 1314 }, 1315 1316 copyProperties: function (widget) { 1317 this.setEnabled(widget.isEnabled()); 1318 this.setVisible(widget.isVisible()); 1319 this.setBright(widget.isBright()); 1320 this.setTouchEnabled(widget.isTouchEnabled()); 1321 this._touchPassedEnabled = false; 1322 this.setLocalZOrder(widget.getLocalZOrder()); 1323 this.setUpdateEnabled(widget.isUpdateEnabled()); 1324 this.setTag(widget.getTag()); 1325 this.setName(widget.getName()); 1326 this.setActionTag(widget.getActionTag()); 1327 this._ignoreSize = widget._ignoreSize; 1328 this._size = cc.size(widget._size.width, widget._size.height); 1329 this._customSize = cc.size(widget._customSize.width, widget._customSize.height); 1330 this.copySpecialProperties(widget); 1331 this._sizeType = widget.getSizeType(); 1332 this._sizePercent = cc.p(widget._sizePercent.x, widget._sizePercent.y); 1333 this.positionType = widget.positionType; 1334 this._positionPercent = cc.p(widget._positionPercent.x, widget._positionPercent.y); 1335 this.setPosition(widget.getPosition()); 1336 this.setAnchorPoint(widget.getAnchorPoint()); 1337 this.setScaleX(widget.getScaleX()); 1338 this.setScaleY(widget.getScaleY()); 1339 this.setRotation(widget.getRotation()); 1340 this.setRotationX(widget.getRotationX()); 1341 this.setRotationY(widget.getRotationY()); 1342 this.setFlippedX(widget.isFlippedX()); 1343 this.setFlippedY(widget.isFlippedY()); 1344 this.setColor(widget.getColor()); 1345 this.setOpacity(widget.getOpacity()); 1346 for (var key in widget._layoutParameterDictionary) { 1347 var parameter = widget._layoutParameterDictionary[key]; 1348 if (parameter) 1349 this.setLayoutParameter(parameter.clone()); 1350 } 1351 this.onSizeChanged(); 1352 }, 1353 1354 /*temp action*/ 1355 setActionTag: function (tag) { 1356 this._actionTag = tag; 1357 }, 1358 1359 getActionTag: function () { 1360 return this._actionTag; 1361 }, 1362 /** 1363 * Set color 1364 * @param {cc.Color} color 1365 */ 1366 setColor: function (color) { 1367 this._color.r = color.r; 1368 this._color.g = color.g; 1369 this._color.b = color.b; 1370 this.updateTextureColor(); 1371 if (color.a !== undefined && !color.a_undefined) { 1372 this.setOpacity(color.a); 1373 } 1374 }, 1375 1376 /** 1377 * Get color 1378 * @returns {cc.Color} 1379 */ 1380 getColor: function () { 1381 return cc.color(this._color.r, this._color.g, this._color.b, this._color.a); 1382 }, 1383 1384 /** 1385 * Set opacity 1386 * @param {Number} opacity 1387 */ 1388 setOpacity: function (opacity) { 1389 if(opacity === this._color.a) return; 1390 this._color.a = opacity; 1391 this.updateTextureOpacity(opacity); 1392 }, 1393 1394 /** 1395 * Get opacity 1396 * @returns {Number} 1397 */ 1398 getOpacity: function () { 1399 return this._color.a; 1400 }, 1401 1402 updateTextureColor: function () { 1403 1404 }, 1405 1406 updateTextureOpacity: function (opacity) { 1407 for(var p in this._children){ 1408 var item = this._children[p]; 1409 if(item && item.RGBAProtocol){ 1410 item.setOpacity(opacity); 1411 } 1412 1413 } 1414 }, 1415 1416 1417 updateColorToRenderer: function (renderer) { 1418 if (renderer.RGBAProtocol) { 1419 renderer.setColor(this._color); 1420 } 1421 }, 1422 1423 updateOpacityToRenderer: function (renderer) { 1424 if (renderer.RGBAProtocol) { 1425 renderer.setOpacity(this._color.a); 1426 } 1427 } 1428 }); 1429 1430 var _p = ccui.Widget.prototype; 1431 1432 // Extended properties 1433 /** @expose */ 1434 _p.xPercent; 1435 cc.defineGetterSetter(_p, "xPercent", _p._getXPercent, _p._setXPercent); 1436 /** @expose */ 1437 _p.yPercent; 1438 cc.defineGetterSetter(_p, "yPercent", _p._getYPercent, _p._setYPercent); 1439 /** @expose */ 1440 _p.widthPercent; 1441 cc.defineGetterSetter(_p, "widthPercent", _p._getWidthPercent, _p._setWidthPercent); 1442 /** @expose */ 1443 _p.heightPercent; 1444 cc.defineGetterSetter(_p, "heightPercent", _p._getHeightPercent, _p._setHeightPercent); 1445 /** @expose */ 1446 _p.widgetParent; 1447 cc.defineGetterSetter(_p, "widgetParent", _p.getWidgetParent); 1448 /** @expose */ 1449 _p.enabled; 1450 cc.defineGetterSetter(_p, "enabled", _p.isEnabled, _p.setEnabled); 1451 /** @expose */ 1452 _p.focused; 1453 cc.defineGetterSetter(_p, "focused", _p.isFocused, _p.setFocused); 1454 /** @expose */ 1455 _p.sizeType; 1456 cc.defineGetterSetter(_p, "sizeType", _p.getSizeType, _p.setSizeType); 1457 /** @expose */ 1458 _p.widgetType; 1459 cc.defineGetterSetter(_p, "widgetType", _p.getWidgetType); 1460 /** @expose */ 1461 _p.touchEnabled; 1462 cc.defineGetterSetter(_p, "touchEnabled", _p.isTouchEnabled, _p.setTouchEnabled); 1463 /** @expose */ 1464 _p.updateEnabled; 1465 cc.defineGetterSetter(_p, "updateEnabled", _p.isUpdateEnabled, _p.setUpdateEnabled); 1466 /** @expose */ 1467 _p.bright; 1468 cc.defineGetterSetter(_p, "bright", _p.isBright, _p.setBright); 1469 /** @expose */ 1470 _p.name; 1471 cc.defineGetterSetter(_p, "name", _p.getName, _p.setName); 1472 /** @expose */ 1473 _p.actionTag; 1474 cc.defineGetterSetter(_p, "actionTag", _p.getActionTag, _p.setActionTag); 1475 /** @expose */ 1476 _p.opacity; 1477 cc.defineGetterSetter(_p, "opacity", _p.getOpacity, _p.setOpacity); 1478 1479 _p = null; 1480 1481 /** 1482 * allocates and initializes a UIWidget. 1483 * @constructs 1484 * @return {ccui.Widget} 1485 * @example 1486 * // example 1487 * var uiWidget = ccui.Widget.create(); 1488 */ 1489 ccui.Widget.create = function () { 1490 return new ccui.Widget(); 1491 }; 1492 1493 1494 // Constants 1495 //bright style 1496 ccui.Widget.BRIGHT_STYLE_NONE = -1; 1497 ccui.Widget.BRIGHT_STYLE_NORMAL = 0; 1498 ccui.Widget.BRIGHT_STYLE_HIGH_LIGHT = 1; 1499 1500 //widget type 1501 ccui.Widget.TYPE_WIDGET = 0; 1502 ccui.Widget.TYPE_CONTAINER = 1; 1503 1504 //texture resource type 1505 ccui.Widget.LOCAL_TEXTURE = 0; 1506 ccui.Widget.PLIST_TEXTURE = 1; 1507 1508 //touch event type 1509 ccui.Widget.TOUCH_BEGAN = 0; 1510 ccui.Widget.TOUCH_MOVED = 1; 1511 ccui.Widget.TOUCH_ENDED = 2; 1512 ccui.Widget.TOUCH_CANCELED = 3; 1513 1514 //size type 1515 ccui.Widget.SIZE_ABSOLUTE = 0; 1516 ccui.Widget.SIZE_PERCENT = 1; 1517 1518 //position type 1519 ccui.Widget.POSITION_ABSOLUTE = 0; 1520 ccui.Widget.POSITION_PERCENT = 1;