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.LayoutComponent_ReferencePoint = {
 27     BOTTOM_LEFT: 0,
 28     TOP_LEFT: 1,
 29     BOTTOM_RIGHT: 2,
 30     TOP_RIGHT: 3
 31 };
 32 ccui.LayoutComponent_PositionType = {
 33     Position: 0,
 34     RelativePosition: 1,
 35     PreRelativePosition: 2,
 36     PreRelativePositionEnable: 3
 37 };
 38 ccui.LayoutComponent_SizeType = {
 39     Size: 0,
 40     PreSize: 1,
 41     PreSizeEnable: 2
 42 };
 43 
 44 //refactor since v3.3
 45 ccui.LayoutComponent = cc.Component.extend({
 46     _horizontalEdge: 0,
 47     _verticalEdge: 0,
 48 
 49     _leftMargin: 0,
 50     _rightMargin: 0,
 51     _bottomMargin: 0,
 52     _topMargin: 0,
 53 
 54     _usingPositionPercentX: false,
 55     _positionPercentX: 0,
 56     _usingPositionPercentY: false,
 57     _positionPercentY: 0,
 58 
 59     _usingStretchWidth: false,
 60     _usingStretchHeight: false,
 61 
 62     _percentWidth: 0,
 63     _usingPercentWidth: false,
 64 
 65     _percentHeight: 0,
 66     _usingPercentHeight: false,
 67 
 68     _actived: true,
 69     _isPercentOnly: false,
 70 
 71     ctor: function () {
 72         this._name = ccui.LayoutComponent.NAME;
 73     },
 74 
 75     init: function () {
 76         var ret = true;
 77 
 78         if (!cc.Component.prototype.init.call(this)) {
 79             return false;
 80         }
 81 
 82         //put layout component initalized code here
 83 
 84         return ret;
 85     },
 86 
 87     getPercentContentSize: function () {
 88         return cc.p(this._percentWidth, this._percentHeight);
 89     },
 90     setPercentContentSize: function (percent) {
 91         this.setPercentWidth(percent.x);
 92         this.setPercentHeight(percent.y);
 93     },
 94 
 95     setUsingPercentContentSize: function (isUsed) {
 96         this._usingPercentWidth = this._usingPercentHeight = isUsed;
 97     },
 98 
 99     //old
100     SetActiveEnable: function (enable) {
101         this._actived = enable;
102     },
103 
104     //v3.3
105     getUsingPercentContentSize: function () {
106         return this._usingPercentWidth && this._usingPercentHeight;
107     },
108 
109     //position & margin
110     getAnchorPosition: function () {
111         return this._owner.getAnchorPoint();
112     },
113 
114     setAnchorPosition: function (point, y) {
115         var oldRect = this._owner.getBoundingBox();
116         this._owner.setAnchorPoint(point, y);
117         var newRect = this._owner.getBoundingBox();
118         var offSetX = oldRect.x - newRect.x, offSetY = oldRect.y - newRect.y;
119 
120         var ownerPosition = this._owner.getPosition();
121         ownerPosition.x += offSetX;
122         ownerPosition.y += offSetY;
123         this.setPosition(ownerPosition);
124     },
125 
126     getPosition: function () {
127         return this._owner.getPosition();
128     },
129 
130     setPosition: function (position, y) {
131         var parent = this._getOwnerParent(), x;
132         if (parent != null) {
133             if (y === undefined) {
134                 x = position.x;
135                 y = position.y;
136             } else
137                 x = position;
138             var parentSize = parent.getContentSize();
139 
140             if (parentSize.width !== 0)
141                 this._positionPercentX = x / parentSize.width;
142             else {
143                 this._positionPercentX = 0;
144                 if (this._usingPositionPercentX)
145                     x = 0;
146             }
147 
148             if (parentSize.height !== 0)
149                 this._positionPercentY = y / parentSize.height;
150             else {
151                 this._positionPercentY = 0;
152                 if (this._usingPositionPercentY)
153                     y = 0;
154             }
155 
156             this._owner.setPosition(x, y);
157             this._refreshHorizontalMargin();
158             this._refreshVerticalMargin();
159         } else
160             this._owner.setPosition(position, y);
161     },
162 
163     isPositionPercentXEnabled: function () {
164         return this._usingPositionPercentX;
165     },
166     setPositionPercentXEnabled: function (isUsed) {
167         this._usingPositionPercentX = isUsed;
168         if (this._usingPositionPercentX)
169             this._horizontalEdge = ccui.LayoutComponent.horizontalEdge.NONE;
170     },
171 
172     getPositionPercentX: function () {
173         return this._positionPercentX;
174     },
175     setPositionPercentX: function (percentMargin) {
176         this._positionPercentX = percentMargin;
177 
178         var parent = this._getOwnerParent();
179         if (parent !== null) {
180             this._owner.setPositionX(parent.width * this._positionPercentX);
181             this._refreshHorizontalMargin();
182         }
183     },
184 
185     isPositionPercentYEnabled: function () {
186         return this._usingPositionPercentY;
187     },
188     setPositionPercentYEnabled: function (isUsed) {
189         this._usingPositionPercentY = isUsed;
190         if (this._usingPositionPercentY)
191             this._verticalEdge = ccui.LayoutComponent.verticalEdge.NONE;
192     },
193 
194     getPositionPercentY: function () {
195         return this._positionPercentY;
196     },
197     setPositionPercentY: function (percentMargin) {
198         this._positionPercentY = percentMargin;
199 
200         var parent = this._getOwnerParent();
201         if (parent !== null) {
202             this._owner.setPositionY(parent.height * this._positionPercentY);
203             this._refreshVerticalMargin();
204         }
205     },
206 
207     getHorizontalEdge: function () {
208         return this._horizontalEdge;
209     },
210     setHorizontalEdge: function (hEdge) {
211         this._horizontalEdge = hEdge;
212         if (this._horizontalEdge !== ccui.LayoutComponent.horizontalEdge.NONE)
213             this._usingPositionPercentX = false;
214 
215         var parent = this._getOwnerParent();
216         if (parent !== null) {
217             var ownerPoint = this._owner.getPosition();
218             var parentSize = parent.getContentSize();
219             if (parentSize.width !== 0)
220                 this._positionPercentX = ownerPoint.x / parentSize.width;
221             else {
222                 this._positionPercentX = 0;
223                 ownerPoint.x = 0;
224                 if (this._usingPositionPercentX)
225                     this._owner.setPosition(ownerPoint);
226             }
227             this._refreshHorizontalMargin();
228         }
229     },
230 
231     getVerticalEdge: function () {
232         return this._verticalEdge;
233     },
234     setVerticalEdge: function (vEdge) {
235         this._verticalEdge = vEdge;
236         if (this._verticalEdge !== ccui.LayoutComponent.verticalEdge.NONE)
237             this._usingPositionPercentY = false;
238 
239         var parent = this._getOwnerParent();
240         if (parent !== null) {
241             var ownerPoint = this._owner.getPosition();
242             var parentSize = parent.getContentSize();
243             if (parentSize.height !== 0)
244                 this._positionPercentY = ownerPoint.y / parentSize.height;
245             else {
246                 this._positionPercentY = 0;
247                 ownerPoint.y = 0;
248                 if (this._usingPositionPercentY)
249                     this._owner.setPosition(ownerPoint);
250             }
251             this._refreshVerticalMargin();
252         }
253     },
254 
255     getLeftMargin: function () {
256         return this._leftMargin;
257     },
258     setLeftMargin: function (margin) {
259         this._leftMargin = margin;
260     },
261 
262     getRightMargin: function () {
263         return this._rightMargin;
264     },
265     setRightMargin: function (margin) {
266         this._rightMargin = margin;
267     },
268 
269     getTopMargin: function () {
270         return this._topMargin;
271     },
272     setTopMargin: function (margin) {
273         this._topMargin = margin;
274     },
275 
276     getBottomMargin: function () {
277         return this._bottomMargin;
278     },
279     setBottomMargin: function (margin) {
280         this._bottomMargin = margin;
281     },
282 
283     //size &
284     getSize: function () {
285         return this.getOwner().getContentSize();
286     },
287     setSize: function (size) {
288         var parent = this._getOwnerParent();
289         if (parent !== null) {
290             var ownerSize = size, parentSize = parent.getContentSize();
291 
292             if (parentSize.width !== 0)
293                 this._percentWidth = ownerSize.width / parentSize.width;
294             else {
295                 this._percentWidth = 0;
296                 if (this._usingPercentWidth)
297                     ownerSize.width = 0;
298             }
299 
300             if (parentSize.height !== 0)
301                 this._percentHeight = ownerSize.height / parentSize.height;
302             else {
303                 this._percentHeight = 0;
304                 if (this._usingPercentHeight)
305                     ownerSize.height = 0;
306             }
307 
308             this._owner.setContentSize(ownerSize);
309 
310             this._refreshHorizontalMargin();
311             this._refreshVerticalMargin();
312         }
313         else
314             this._owner.setContentSize(size);
315     },
316 
317     isPercentWidthEnabled: function () {
318         return this._usingPercentWidth;
319     },
320     setPercentWidthEnabled: function (isUsed) {
321         this._usingPercentWidth = isUsed;
322         if (this._usingPercentWidth)
323             this._usingStretchWidth = false;
324     },
325 
326     getSizeWidth: function () {
327         return this._owner.width;
328     },
329     setSizeWidth: function (width) {
330         var ownerSize = this._owner.getContentSize();
331         ownerSize.width = width;
332 
333         var parent = this._getOwnerParent();
334         if (parent !== null) {
335             var parentSize = parent.getContentSize();
336             if (parentSize.width !== 0)
337                 this._percentWidth = ownerSize.width / parentSize.width;
338             else {
339                 this._percentWidth = 0;
340                 if (this._usingPercentWidth)
341                     ownerSize.width = 0;
342             }
343             this._owner.setContentSize(ownerSize);
344             this._refreshHorizontalMargin();
345         } else
346             this._owner.setContentSize(ownerSize);
347     },
348 
349     getPercentWidth: function () {
350         return this._percentWidth;
351     },
352     setPercentWidth: function (percentWidth) {
353         this._percentWidth = percentWidth;
354 
355         var parent = this._getOwnerParent();
356         if (parent !== null) {
357             var ownerSize = this._owner.getContentSize();
358             ownerSize.width = parent.width * this._percentWidth;
359             this._owner.setContentSize(ownerSize);
360             this._refreshHorizontalMargin();
361         }
362     },
363 
364     isPercentHeightEnabled: function () {
365         return this._usingPercentHeight;
366     },
367     setPercentHeightEnabled: function (isUsed) {
368         this._usingPercentHeight = isUsed;
369         if (this._usingPercentHeight)
370             this._usingStretchHeight = false;
371     },
372 
373     getSizeHeight: function () {
374         return this._owner.height;
375     },
376     setSizeHeight: function (height) {
377         var ownerSize = this._owner.getContentSize();
378         ownerSize.height = height;
379 
380         var parent = this._getOwnerParent();
381         if (parent !== null) {
382             var parentSize = parent.getContentSize();
383             if (parentSize.height !== 0)
384                 this._percentHeight = ownerSize.height / parentSize.height;
385             else {
386                 this._percentHeight = 0;
387                 if (this._usingPercentHeight)
388                     ownerSize.height = 0;
389             }
390             this._owner.setContentSize(ownerSize);
391             this._refreshVerticalMargin();
392         }
393         else
394             this._owner.setContentSize(ownerSize);
395     },
396 
397     getPercentHeight: function () {
398         return this._percentHeight;
399     },
400     setPercentHeight: function (percentHeight) {
401         this._percentHeight = percentHeight;
402 
403         var parent = this._getOwnerParent();
404         if (parent !== null) {
405             var ownerSize = this._owner.getContentSize();
406             ownerSize.height = parent.height * this._percentHeight;
407             this._owner.setContentSize(ownerSize);
408             this._refreshVerticalMargin();
409         }
410     },
411 
412     isStretchWidthEnabled: function () {
413         return this._usingStretchWidth;
414     },
415     setStretchWidthEnabled: function (isUsed) {
416         this._usingStretchWidth = isUsed;
417         if (this._usingStretchWidth)
418             this._usingPercentWidth = false;
419     },
420 
421     isStretchHeightEnabled: function () {
422         return this._usingStretchHeight;
423     },
424     setStretchHeightEnabled: function (isUsed) {
425         this._usingStretchHeight = isUsed;
426         if (this._usingStretchHeight)
427             this._usingPercentHeight = false;
428     },
429 
430     setPercentOnlyEnabled: function(enable){
431         this._isPercentOnly = enable;
432     },
433 
434     setActiveEnabled: function (enable) {
435         this._actived = enable;
436     },
437     refreshLayout: function () {
438         if(!this._actived)
439             return;
440 
441         var parent = this._getOwnerParent();
442         if (parent === null)
443             return;
444 
445         var parentSize = parent.getContentSize(), locOwner = this._owner;
446         var ownerAnchor = locOwner.getAnchorPoint(), ownerSize = locOwner.getContentSize();
447         var ownerPosition = locOwner.getPosition();
448 
449         switch (this._horizontalEdge) {
450             case ccui.LayoutComponent.horizontalEdge.NONE:
451                 if (this._usingStretchWidth && !this._isPercentOnly) {
452                     ownerSize.width = parentSize.width * this._percentWidth;
453                     ownerPosition.x = this._leftMargin + ownerAnchor.x * ownerSize.width;
454                 } else {
455                     if (this._usingPositionPercentX)
456                         ownerPosition.x = parentSize.width * this._positionPercentX;
457                     if (this._usingPercentWidth)
458                         ownerSize.width = parentSize.width * this._percentWidth;
459                 }
460                 break;
461             case ccui.LayoutComponent.horizontalEdge.LEFT:
462                 if(this._isPercentOnly)
463                     break;
464                 if (this._usingPercentWidth || this._usingStretchWidth)
465                     ownerSize.width = parentSize.width * this._percentWidth;
466                 ownerPosition.x = this._leftMargin + ownerAnchor.x * ownerSize.width;
467                 break;
468             case ccui.LayoutComponent.horizontalEdge.RIGHT:
469                 if(this._isPercentOnly)
470                     break;
471                 if (this._usingPercentWidth || this._usingStretchWidth)
472                     ownerSize.width = parentSize.width * this._percentWidth;
473                 ownerPosition.x = parentSize.width - (this._rightMargin + (1 - ownerAnchor.x) * ownerSize.width);
474                 break;
475             case ccui.LayoutComponent.horizontalEdge.CENTER:
476                 if(this._isPercentOnly)
477                     break;
478                 if (this._usingStretchWidth) {
479                     ownerSize.width = parentSize.width - this._leftMargin - this._rightMargin;
480                     if (ownerSize.width < 0)
481                         ownerSize.width = 0;
482                     ownerPosition.x = this._leftMargin + ownerAnchor.x * ownerSize.width;
483                 } else {
484                     if (this._usingPercentWidth)
485                         ownerSize.width = parentSize.width * this._percentWidth;
486                     ownerPosition.x = parentSize.width * this._positionPercentX;
487                 }
488                 break;
489             default:
490                 break;
491         }
492 
493         switch (this._verticalEdge) {
494             case ccui.LayoutComponent.verticalEdge.NONE:
495                 if (this._usingStretchHeight && !this._isPercentOnly) {
496                     ownerSize.height = parentSize.height * this._percentHeight;
497                     ownerPosition.y = this._bottomMargin + ownerAnchor.y * ownerSize.height;
498                 } else {
499                     if (this._usingPositionPercentY)
500                         ownerPosition.y = parentSize.height * this._positionPercentY;
501                     if (this._usingPercentHeight)
502                         ownerSize.height = parentSize.height * this._percentHeight;
503                 }
504                 break;
505             case ccui.LayoutComponent.verticalEdge.BOTTOM:
506                 if(this._isPercentOnly)
507                     break;
508                 if (this._usingPercentHeight || this._usingStretchHeight)
509                     ownerSize.height = parentSize.height * this._percentHeight;
510                 ownerPosition.y = this._bottomMargin + ownerAnchor.y * ownerSize.height;
511                 break;
512             case ccui.LayoutComponent.verticalEdge.TOP:
513                 if(this._isPercentOnly)
514                     break;
515                 if (this._usingPercentHeight || this._usingStretchHeight)
516                     ownerSize.height = parentSize.height * this._percentHeight;
517                 ownerPosition.y = parentSize.height - (this._topMargin + (1 - ownerAnchor.y) * ownerSize.height);
518                 break;
519             case ccui.LayoutComponent.verticalEdge.CENTER:
520                 if(this._isPercentOnly)
521                     break;
522                 if (this._usingStretchHeight) {
523                     ownerSize.height = parentSize.height - this._topMargin - this._bottomMargin;
524                     if (ownerSize.height < 0)
525                         ownerSize.height = 0;
526                     ownerPosition.y = this._bottomMargin + ownerAnchor.y * ownerSize.height;
527                 } else {
528                     if(this._usingPercentHeight)
529                         ownerSize.height = parentSize.height * this._percentHeight;
530                     ownerPosition.y = parentSize.height * this._positionPercentY;
531                 }
532                 break;
533             default:
534                 break;
535         }
536 
537         locOwner.setPosition(ownerPosition);
538         locOwner.setContentSize(ownerSize);
539 
540         if(locOwner instanceof ccui.PageView){
541             locOwner.forceDoLayout();
542 
543             var layoutVector = locOwner.getPages();
544             for(var i=0; i<layoutVector.length; i++){
545                 ccui.helper.doLayout(layoutVector[i]);
546             }
547         }else{
548             ccui.helper.doLayout(locOwner);
549         }
550     },
551 
552     _getOwnerParent: function () {
553         return this._owner ? this._owner.getParent() : null;
554     },
555     _refreshHorizontalMargin: function () {
556         var parent = this._getOwnerParent();
557         if (parent === null)
558             return;
559 
560         var ownerPoint = this._owner.getPosition(), ownerAnchor = this._owner.getAnchorPoint();
561         var ownerSize = this._owner.getContentSize(), parentSize = parent.getContentSize();
562 
563         this._leftMargin = ownerPoint.x - ownerAnchor.x * ownerSize.width;
564         this._rightMargin = parentSize.width - (ownerPoint.x + (1 - ownerAnchor.x) * ownerSize.width);
565     },
566     _refreshVerticalMargin: function () {
567         var parent = this._getOwnerParent();
568         if (parent === null)
569             return;
570 
571         var ownerPoint = this._owner.getPosition(), ownerAnchor = this._owner.getAnchorPoint();
572         var ownerSize = this._owner.getContentSize(), parentSize = parent.getContentSize();
573 
574         this._bottomMargin = ownerPoint.y - ownerAnchor.y * ownerSize.height;
575         this._topMargin = parentSize.height - (ownerPoint.y + (1 - ownerAnchor.y) * ownerSize.height);
576     }
577 });
578 
579 ccui.LayoutComponent.horizontalEdge = {NONE: 0, LEFT: 1, RIGHT: 2, CENTER: 3};
580 ccui.LayoutComponent.verticalEdge = {NONE: 0, BOTTOM: 1, TOP: 2, CENTER: 3};
581 
582 ccui.LayoutComponent.NAME = "__ui_layout";
583 ccui.LayoutComponent.bindLayoutComponent = function (node) {
584     var layout = node.getComponent(ccui.LayoutComponent.NAME);
585     if (layout !== undefined)
586         return layout;
587 
588     layout = new ccui.LayoutComponent();
589     layout.init();
590     node.addComponent(layout);
591     if (!(node instanceof ccui.Widget)) {
592         node.addEventListener && node.addEventListener("load", function () {
593             layout.refreshLayout();
594         }, this);
595     }
596 
597     return layout;
598 };