1 /****************************************************************************
  2  Copyright (c) 2013-2014 Chukong Technologies Inc.
  3 
  4  http://www.cocos2d-x.org
  5 
  6  Permission is hereby granted, free of charge, to any person obtaining a copy
  7  of this software and associated documentation files (the "Software"), to deal
  8  in the Software without restriction, including without limitation the rights
  9  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 10  copies of the Software, and to permit persons to whom the Software is
 11  furnished to do so, subject to the following conditions:
 12 
 13  The above copyright notice and this permission notice shall be included in
 14  all copies or substantial portions of the Software.
 15 
 16  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 17  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 18  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 19  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 20  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 21  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 22  THE SOFTWARE.
 23  ****************************************************************************/
 24 
 25 ccui.getLayoutManager = function (type) {
 26     switch (type) {
 27         case ccui.Layout.LINEAR_VERTICAL:
 28             return ccui.linearVerticalLayoutManager;
 29         case ccui.Layout.LINEAR_HORIZONTAL:
 30             return ccui.linearHorizontalLayoutManager;
 31         case ccui.Layout.RELATIVE:
 32             return ccui.relativeLayoutManager;
 33     }
 34     return null;
 35 };
 36 
 37 ccui.linearVerticalLayoutManager = {
 38     _doLayout: function(layout){
 39         var layoutSize = layout._getLayoutContentSize();
 40         var container = layout._getLayoutElements();
 41         var topBoundary = layoutSize.height;
 42 
 43         for (var i = 0, len = container.length; i < len; i++) {
 44             var child = container[i];
 45             if (child) {
 46                 var layoutParameter = child.getLayoutParameter();
 47 
 48                 if (layoutParameter){
 49                     var childGravity = layoutParameter.getGravity();
 50                     var ap = child.getAnchorPoint();
 51                     var cs = child.getContentSize();
 52                     var finalPosX = ap.x * cs.width;
 53                     var finalPosY = topBoundary - ((1.0-ap.y) * cs.height);
 54                     switch (childGravity){
 55                         case ccui.LinearLayoutParameter.NONE:
 56                         case ccui.LinearLayoutParameter.LEFT:
 57                             break;
 58                         case ccui.LinearLayoutParameter.RIGHT:
 59                             finalPosX = layoutSize.width - ((1.0 - ap.x) * cs.width);
 60                             break;
 61                         case ccui.LinearLayoutParameter.CENTER_HORIZONTAL:
 62                             finalPosX = layoutSize.width / 2.0 - cs.width * (0.5-ap.x);
 63                             break;
 64                         default:
 65                             break;
 66                     }
 67                     var mg = layoutParameter.getMargin();
 68                     finalPosX += mg.left;
 69                     finalPosY -= mg.top;
 70                     child.setPosition(finalPosX, finalPosY);
 71                     topBoundary = child.getPositionY() - child.getAnchorPoint().y * child.getContentSize().height - mg.bottom;
 72                 }
 73             }
 74         }
 75     }
 76 };
 77 
 78 ccui.linearHorizontalLayoutManager = {
 79     _doLayout: function(layout){
 80         var layoutSize = layout._getLayoutContentSize();
 81         var container = layout._getLayoutElements();
 82         var leftBoundary = 0.0;
 83         for (var i = 0, len = container.length;  i < len; i++) {
 84             var child = container[i];
 85             if (child) {
 86                 var layoutParameter = child.getLayoutParameter();
 87                 if (layoutParameter){
 88                     var childGravity = layoutParameter.getGravity();
 89                     var ap = child.getAnchorPoint();
 90                     var cs = child.getSize();
 91                     var finalPosX = leftBoundary + (ap.x * cs.width);
 92                     var finalPosY = layoutSize.height - (1.0 - ap.y) * cs.height;
 93                     switch (childGravity){
 94                         case ccui.LinearLayoutParameter.NONE:
 95                         case ccui.LinearLayoutParameter.TOP:
 96                             break;
 97                         case ccui.LinearLayoutParameter.BOTTOM:
 98                             finalPosY = ap.y * cs.height;
 99                             break;
100                         case ccui.LinearLayoutParameter.CENTER_VERTICAL:
101                             finalPosY = layoutSize.height / 2.0 - cs.height * (0.5 - ap.y);
102                             break;
103                         default:
104                             break;
105                     }
106                     var mg = layoutParameter.getMargin();
107                     finalPosX += mg.left;
108                     finalPosY -= mg.top;
109                     child.setPosition(finalPosX, finalPosY);
110                     leftBoundary = child.getRightBoundary() + mg.right;
111                 }
112             }
113         }
114     }
115 };
116 
117 ccui.relativeLayoutManager = {
118     _unlayoutChildCount: 0,
119     _widgetChildren: [],
120     _widget: null,
121     _finalPositionX:0,
122     _finalPositionY:0,
123     _relativeWidgetLP:null,
124 
125     _doLayout: function(layout){
126         this._widgetChildren = this._getAllWidgets(layout);
127 
128         var locChildren = this._widgetChildren;
129         while (this._unlayoutChildCount > 0) {
130             for (var i = 0, len = locChildren.length;  i < len; i++) {
131                 this._widget = locChildren[i];
132 
133                 var layoutParameter = this._widget.getLayoutParameter();
134                 if (layoutParameter){
135                     if (layoutParameter._put)
136                         continue;
137 
138                     var ret = this._calculateFinalPositionWithRelativeWidget(layout);
139                     if (!ret)
140                         continue;
141 
142                     this._calculateFinalPositionWithRelativeAlign();
143 
144                     this._widget.setPosition(this._finalPositionX, this._finalPositionY);
145                     layoutParameter._put = true;
146                 }
147             }
148             this._unlayoutChildCount--;
149         }
150         this._widgetChildren.length = 0;
151     },
152 
153     _getAllWidgets: function(layout){
154         var container = layout._getLayoutElements();
155         var locWidgetChildren = this._widgetChildren;
156         locWidgetChildren.length = 0;
157         for (var i = 0, len = container.length; i < len; i++){
158             var child = container[i];
159             if (child) {
160                 var layoutParameter = child.getLayoutParameter();
161                 layoutParameter._put = false;
162                 this._unlayoutChildCount++;
163                 locWidgetChildren.push(child);
164             }
165         }
166         return locWidgetChildren;
167     },
168 
169     _getRelativeWidget: function(widget){
170         var relativeWidget = null;
171         var layoutParameter = widget.getLayoutParameter();
172         var relativeName = layoutParameter.getRelativeToWidgetName();
173 
174         if (relativeName && relativeName.length != 0) {
175             var locChildren =  this._widgetChildren;
176             for(var i = 0, len = locChildren.length;  i  < len; i++){
177                 var child = locChildren[i];
178                 if (child){
179                     var rlayoutParameter = child.getLayoutParameter();
180                     if (rlayoutParameter &&  rlayoutParameter.getRelativeName() == relativeName) {
181                         relativeWidget = child;
182                         this._relativeWidgetLP = rlayoutParameter;
183                         break;
184                     }
185                 }
186             }
187         }
188         return relativeWidget;
189     },
190 
191     _calculateFinalPositionWithRelativeWidget: function(layout){
192         var locWidget = this._widget;
193         var ap = locWidget.getAnchorPoint();
194         var cs = locWidget.getContentSize();
195 
196         this._finalPositionX = 0.0;
197         this._finalPositionY = 0.0;
198 
199         var relativeWidget = this._getRelativeWidget(locWidget);
200         var layoutParameter = locWidget.getLayoutParameter();
201         var align = layoutParameter.getAlign();
202         var layoutSize = layout._getLayoutContentSize();
203 
204         switch (align) {
205             case ccui.RelativeLayoutParameter.NONE:
206             case ccui.RelativeLayoutParameter.PARENT_TOP_LEFT:
207                 this._finalPositionX = ap.x * cs.width;
208                 this._finalPositionY = layoutSize.height - ((1.0 - ap.y) * cs.height);
209                 break;
210             case ccui.RelativeLayoutParameter.PARENT_TOP_CENTER_HORIZONTAL:
211                 this._finalPositionX = layoutSize.width * 0.5 - cs.width * (0.5 - ap.x);
212                 this._finalPositionY = layoutSize.height - ((1.0 - ap.y) * cs.height);
213                 break;
214             case ccui.RelativeLayoutParameter.PARENT_TOP_RIGHT:
215                 this._finalPositionX = layoutSize.width - ((1.0 - ap.x) * cs.width);
216                 this._finalPositionY = layoutSize.height - ((1.0 - ap.y) * cs.height);
217                 break;
218             case ccui.RelativeLayoutParameter.PARENT_LEFT_CENTER_VERTICAL:
219                 this._finalPositionX = ap.x * cs.width;
220                 this._finalPositionY = layoutSize.height * 0.5 - cs.height * (0.5 - ap.y);
221                 break;
222             case ccui.RelativeLayoutParameter.CENTER_IN_PARENT:
223                 this._finalPositionX = layoutSize.width * 0.5 - cs.width * (0.5 - ap.x);
224                 this._finalPositionY = layoutSize.height * 0.5 - cs.height * (0.5 - ap.y);
225                 break;
226             case ccui.RelativeLayoutParameter.PARENT_RIGHT_CENTER_VERTICAL:
227                 this._finalPositionX = layoutSize.width - ((1.0 - ap.x) * cs.width);
228                 this._finalPositionY = layoutSize.height * 0.5 - cs.height * (0.5 - ap.y);
229                 break;
230             case ccui.RelativeLayoutParameter.PARENT_LEFT_BOTTOM:
231                 this._finalPositionX = ap.x * cs.width;
232                 this._finalPositionY = ap.y * cs.height;
233                 break;
234             case ccui.RelativeLayoutParameter.PARENT_BOTTOM_CENTER_HORIZONTAL:
235                 this._finalPositionX = layoutSize.width * 0.5 - cs.width * (0.5 - ap.x);
236                 this._finalPositionY = ap.y * cs.height;
237                 break;
238             case ccui.RelativeLayoutParameter.PARENT_RIGHT_BOTTOM:
239                 this._finalPositionX = layoutSize.width - ((1.0 - ap.x) * cs.width);
240                 this._finalPositionY = ap.y * cs.height;
241                 break;
242 
243             case ccui.RelativeLayoutParameter.LOCATION_ABOVE_LEFTALIGN:
244                 if (relativeWidget){
245                     if (this._relativeWidgetLP && !this._relativeWidgetLP._put)
246                         return false;
247                     this._finalPositionY = relativeWidget.getTopBoundary() + ap.y * cs.height;
248                     this._finalPositionX = relativeWidget.getLeftBoundary() + ap.x * cs.width;
249                 }
250                 break;
251             case ccui.RelativeLayoutParameter.LOCATION_ABOVE_CENTER:
252                 if (relativeWidget){
253                     if (this._relativeWidgetLP && !this._relativeWidgetLP._put)
254                         return false;
255                     var rbs = relativeWidget.getContentSize();
256                     this._finalPositionY = relativeWidget.getTopBoundary() + ap.y * cs.height;
257                     this._finalPositionX = relativeWidget.getLeftBoundary() + rbs.width * 0.5 + ap.x * cs.width - cs.width * 0.5;
258                 }
259                 break;
260             case ccui.RelativeLayoutParameter.LOCATION_ABOVE_RIGHTALIGN:
261                 if (relativeWidget) {
262                     if (this._relativeWidgetLP && !this._relativeWidgetLP._put)
263                         return false;
264                     this._finalPositionY = relativeWidget.getTopBoundary() + ap.y * cs.height;
265                     this._finalPositionX = relativeWidget.getRightBoundary() - (1.0 - ap.x) * cs.width;
266                 }
267                 break;
268             case ccui.RelativeLayoutParameter.LOCATION_LEFT_OF_TOPALIGN:
269                 if (relativeWidget){
270                     if (this._relativeWidgetLP && !this._relativeWidgetLP._put)
271                         return false;
272                     this._finalPositionY = relativeWidget.getTopBoundary() - (1.0 - ap.y) * cs.height;
273                     this._finalPositionX = relativeWidget.getLeftBoundary() - (1.0 - ap.x) * cs.width;
274                 }
275                 break;
276             case ccui.RelativeLayoutParameter.LOCATION_LEFT_OF_CENTER:
277                 if (relativeWidget) {
278                     if (this._relativeWidgetLP && !this._relativeWidgetLP._put)
279                         return false;
280                     var rbs = relativeWidget.getContentSize();
281                     this._finalPositionX = relativeWidget.getLeftBoundary() - (1.0 - ap.x) * cs.width;
282                     this._finalPositionY = relativeWidget.getBottomBoundary() + rbs.height * 0.5 + ap.y * cs.height - cs.height * 0.5;
283                 }
284                 break;
285             case ccui.RelativeLayoutParameter.LOCATION_LEFT_OF_BOTTOMALIGN:
286                 if (relativeWidget) {
287                     if (this._relativeWidgetLP && !this._relativeWidgetLP._put)
288                         return false;
289                     this._finalPositionY = relativeWidget.getBottomBoundary() + ap.y * cs.height;
290                     this._finalPositionX = relativeWidget.getLeftBoundary() - (1.0 - ap.x) * cs.width;
291                 }
292                 break;
293             case ccui.RelativeLayoutParameter.LOCATION_RIGHT_OF_TOPALIGN:
294                 if (relativeWidget){
295                     if (this._relativeWidgetLP && !this._relativeWidgetLP._put)
296                         return false;
297                     this._finalPositionY = relativeWidget.getTopBoundary() - (1.0 - ap.y) * cs.height;
298                     this._finalPositionX = relativeWidget.getRightBoundary() + ap.x * cs.width;
299                 }
300                 break;
301             case ccui.RelativeLayoutParameter.LOCATION_RIGHT_OF_CENTER:
302                 if (relativeWidget){
303                     if (this._relativeWidgetLP && !this._relativeWidgetLP._put)
304                         return false;
305                     var rbs = relativeWidget.getContentSize();
306                     var locationRight = relativeWidget.getRightBoundary();
307                     this._finalPositionX = locationRight + ap.x * cs.width;
308                     this._finalPositionY = relativeWidget.getBottomBoundary() + rbs.height * 0.5 + ap.y * cs.height - cs.height * 0.5;
309                 }
310                 break;
311             case ccui.RelativeLayoutParameter.LOCATION_RIGHT_OF_BOTTOMALIGN:
312                 if (relativeWidget){
313                     if (this._relativeWidgetLP && !this._relativeWidgetLP._put)
314                         return false;
315                     this._finalPositionY = relativeWidget.getBottomBoundary() + ap.y * cs.height;
316                     this._finalPositionX = relativeWidget.getRightBoundary() + ap.x * cs.width;
317                 }
318                 break;
319             case ccui.RelativeLayoutParameter.LOCATION_BELOW_LEFTALIGN:
320                 if (relativeWidget){
321                     if (this._relativeWidgetLP && !this._relativeWidgetLP._put)
322                         return false;
323                     this._finalPositionY =  relativeWidget.getBottomBoundary() - (1.0 - ap.y) * cs.height;
324                     this._finalPositionX = relativeWidget.getLeftBoundary() + ap.x * cs.width;
325                 }
326                 break;
327             case ccui.RelativeLayoutParameter.LOCATION_BELOW_CENTER:
328                 if (relativeWidget) {
329                     if (this._relativeWidgetLP && !this._relativeWidgetLP._put)
330                         return false;
331                     var rbs = relativeWidget.getContentSize();
332                     this._finalPositionY = relativeWidget.getBottomBoundary() - (1.0 - ap.y) * cs.height;
333                     this._finalPositionX = relativeWidget.getLeftBoundary() + rbs.width * 0.5 + ap.x * cs.width - cs.width * 0.5;
334                 }
335                 break;
336             case ccui.RelativeLayoutParameter.LOCATION_BELOW_RIGHTALIGN:
337                 if (relativeWidget) {
338                     if (this._relativeWidgetLP && !this._relativeWidgetLP._put)
339                         return false;
340                     this._finalPositionY = relativeWidget.getBottomBoundary() - (1.0 - ap.y) * cs.height;
341                     this._finalPositionX = relativeWidget.getRightBoundary() - (1.0 - ap.x) * cs.width;
342                 }
343                 break;
344             default:
345                 break;
346         }
347         return true;
348     },
349 
350     _calculateFinalPositionWithRelativeAlign: function(){
351         var layoutParameter = this._widget.getLayoutParameter();
352 
353         var mg = layoutParameter.getMargin();
354         var align = layoutParameter.getAlign();
355 
356         //handle margin
357         switch (align) {
358             case ccui.RelativeLayoutParameter.NONE:
359             case ccui.RelativeLayoutParameter.PARENT_TOP_LEFT:
360                 this._finalPositionX += mg.left;
361                 this._finalPositionY -= mg.top;
362                 break;
363             case ccui.RelativeLayoutParameter.PARENT_TOP_CENTER_HORIZONTAL:
364                 this._finalPositionY -= mg.top;
365                 break;
366             case ccui.RelativeLayoutParameter.PARENT_TOP_RIGHT:
367                 this._finalPositionX -= mg.right;
368                 this._finalPositionY -= mg.top;
369                 break;
370             case ccui.RelativeLayoutParameter.PARENT_LEFT_CENTER_VERTICAL:
371                 this._finalPositionX += mg.left;
372                 break;
373             case ccui.RelativeLayoutParameter.CENTER_IN_PARENT:
374                 break;
375             case ccui.RelativeLayoutParameter.PARENT_RIGHT_CENTER_VERTICAL:
376                 this._finalPositionX -= mg.right;
377                 break;
378             case ccui.RelativeLayoutParameter.PARENT_LEFT_BOTTOM:
379                 this._finalPositionX += mg.left;
380                 this._finalPositionY += mg.bottom;
381                 break;
382             case ccui.RelativeLayoutParameter.PARENT_BOTTOM_CENTER_HORIZONTAL:
383                 this._finalPositionY += mg.bottom;
384                 break;
385             case ccui.RelativeLayoutParameter.PARENT_RIGHT_BOTTOM:
386                 this._finalPositionX -= mg.right;
387                 this._finalPositionY += mg.bottom;
388                 break;
389             case ccui.RelativeLayoutParameter.LOCATION_ABOVE_LEFTALIGN:
390                 this._finalPositionY += mg.bottom;
391                 this._finalPositionX += mg.left;
392                 break;
393             case ccui.RelativeLayoutParameter.LOCATION_ABOVE_RIGHTALIGN:
394                 this._finalPositionY += mg.bottom;
395                 this._finalPositionX -= mg.right;
396                 break;
397             case ccui.RelativeLayoutParameter.LOCATION_ABOVE_CENTER:
398                 this._finalPositionY += mg.bottom;
399                 break;
400             case ccui.RelativeLayoutParameter.LOCATION_LEFT_OF_TOPALIGN:
401                 this._finalPositionX -= mg.right;
402                 this._finalPositionY -= mg.top;
403                 break;
404             case ccui.RelativeLayoutParameter.LOCATION_LEFT_OF_BOTTOMALIGN:
405                 this._finalPositionX -= mg.right;
406                 this._finalPositionY += mg.bottom;
407                 break;
408             case ccui.RelativeLayoutParameter.LOCATION_LEFT_OF_CENTER:
409                 this._finalPositionX -= mg.right;
410                 break;
411             case ccui.RelativeLayoutParameter.LOCATION_RIGHT_OF_TOPALIGN:
412                 this._finalPositionX += mg.left;
413                 this._finalPositionY -= mg.top;
414                 break;
415             case ccui.RelativeLayoutParameter.LOCATION_RIGHT_OF_BOTTOMALIGN:
416                 this._finalPositionX += mg.left;
417                 this._finalPositionY += mg.bottom;
418                 break;
419             case ccui.RelativeLayoutParameter.LOCATION_RIGHT_OF_CENTER:
420                 this._finalPositionX += mg.left;
421                 break;
422             case ccui.RelativeLayoutParameter.LOCATION_BELOW_LEFTALIGN:
423                 this._finalPositionY -= mg.top;
424                 this._finalPositionX += mg.left;
425                 break;
426             case ccui.RelativeLayoutParameter.LOCATION_BELOW_RIGHTALIGN:
427                 this._finalPositionY -= mg.top;
428                 this._finalPositionX -= mg.right;
429                 break;
430             case ccui.RelativeLayoutParameter.LOCATION_BELOW_CENTER:
431                 this._finalPositionY -= mg.top;
432                 break;
433             default:
434                 break;
435         }
436     }
437 };