dragonbones-runtime
Version:
the tools to build dragonbones file for diffrent framework
311 lines (277 loc) • 11.1 kB
text/typescript
//////////////////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 2014-present, Egret Technology.
// All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
// * Neither the name of the Egret nor the
// names of its contributors may be used to endorse or promote products
// derived from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY EGRET AND CONTRIBUTORS "AS IS" AND ANY EXPRESS
// OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
// OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
// IN NO EVENT SHALL EGRET AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;LOSS OF USE, DATA,
// OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
// EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
//////////////////////////////////////////////////////////////////////////////////////
namespace eui {
/**
* The BasicLayout class arranges the layout elements according to their individual settings,
* independent of each-other. BasicLayout, also called absolute layout, requires that you
* explicitly position each container child.
* You can use the <code>x</code> and <code>y</code> properties of the child,
* or constraints to position each child.
*
* @version Egret 2.4
* @version eui 1.0
* @platform Web,Native
* @includeExample extension/eui/layout/BasicLayoutExample.ts
* @language en_US
*/
/**
* BasicLayout 类根据其各个设置彼此独立地排列布局元素。
* BasicLayout(也称为绝对布局)要求显式定位每个容器子代。
* 可以使用子代的 <code>x</code> 和 <code>y</code> 属性,或使用约束来定位每个子代。
*
* @version Egret 2.4
* @version eui 1.0
* @platform Web,Native
* @includeExample extension/eui/layout/BasicLayoutExample.ts
* @language zh_CN
*/
export class BasicLayout extends LayoutBase {
/**
* Constructor.
* @version Egret 2.4
* @version eui 1.0
* @platform Web,Native
* @language en_US
*/
/**
* 构造函数。
* @version Egret 2.4
* @version eui 1.0
* @platform Web,Native
* @language zh_CN
*/
public constructor() {
super();
}
/**
* BasicLayout does not support virtual layout, setting this property is invalid.
*
* @version Egret 2.4
* @version eui 1.0
* @platform Web,Native
* @language en_US
*/
/**
* BasicLayout不支持虚拟布局,设置这个属性无效。
*
* @version Egret 2.4
* @version eui 1.0
* @platform Web,Native
* @language zh_CN
*/
public useVirtualLayout:boolean;
/**
* @inheritDoc
*
* @version Egret 2.4
* @version eui 1.0
* @platform Web,Native
*/
public measure():void {
super.measure();
sys.measure(this.$target);
}
/**
* @inheritDoc
*
* @version Egret 2.4
* @version eui 1.0
* @platform Web,Native
*/
public updateDisplayList(unscaledWidth:number, unscaledHeight:number):void {
super.updateDisplayList(unscaledWidth, unscaledHeight);
let target = this.$target;
let pos = sys.updateDisplayList(target, unscaledWidth, unscaledHeight);
target.setContentSize(Math.ceil(pos.x), Math.ceil(pos.y));
}
}
if (DEBUG) {
Object.defineProperty(BasicLayout.prototype, "useVirtualLayout", {
/**
* 此布局不支持虚拟布局,设置这个属性无效
*/
get: function () {
return this.$useVirtualLayout;
},
set: function (value) {
egret.$error(2201);
},
enumerable: true,
configurable: true
});
}
}
namespace eui.sys {
let UIComponentClass = "eui.UIComponent";
/**
* @private
* @param value 要格式化的相对值
* @param total 在此值方向上的总长度
*/
function formatRelative(value:number|string, total:number):number {
if (!value || typeof value == "number") {
return <number>value;
}
let str = <string>value;
let index = str.indexOf("%");
if (index == -1) {
return +str;
}
let percent = +str.substring(0, index);
return percent * 0.01 * total;
}
/**
* @private
* 一个工具方法,使用BasicLayout规则测量目标对象。
*/
export function measure(target:eui.Group|eui.Component):void {
if (!target) {
return;
}
let width = 0;
let height = 0;
let bounds = egret.$TempRectangle;
let count = target.numChildren;
for (let i = 0; i < count; i++) {
let layoutElement = <eui.UIComponent> (target.getChildAt(i));
if (!egret.is(layoutElement, UIComponentClass) || !layoutElement.$includeInLayout) {
continue;
}
let values = layoutElement.$UIComponent;
let hCenter = +values[sys.UIKeys.horizontalCenter];
let vCenter = +values[sys.UIKeys.verticalCenter];
let left = +values[sys.UIKeys.left];
let right = +values[sys.UIKeys.right];
let top = +values[sys.UIKeys.top];
let bottom = +values[sys.UIKeys.bottom];
let extX:number;
let extY:number;
layoutElement.getPreferredBounds(bounds);
if (!isNaN(left) && !isNaN(right)) {
extX = left + right;
}
else if (!isNaN(hCenter)) {
extX = Math.abs(hCenter) * 2;
}
else if (!isNaN(left) || !isNaN(right)) {
extX = isNaN(left) ? 0 : left;
extX += isNaN(right) ? 0 : right;
}
else {
extX = bounds.x;
}
if (!isNaN(top) && !isNaN(bottom)) {
extY = top + bottom;
}
else if (!isNaN(vCenter)) {
extY = Math.abs(vCenter) * 2;
}
else if (!isNaN(top) || !isNaN(bottom)) {
extY = isNaN(top) ? 0 : top;
extY += isNaN(bottom) ? 0 : bottom;
}
else {
extY = bounds.y;
}
let preferredWidth = bounds.width;
let preferredHeight = bounds.height;
width = Math.ceil(Math.max(width, extX + preferredWidth));
height = Math.ceil(Math.max(height, extY + preferredHeight));
}
target.setMeasuredSize(width, height);
}
/**
* @private
* 一个工具方法,使用BasicLayout规则布局目标对象。
*/
export function updateDisplayList(target:eui.Group|eui.Component,
unscaledWidth:number, unscaledHeight:number):egret.Point {
if (!target)
return;
let count = target.numChildren;
let maxX = 0;
let maxY = 0;
let bounds = egret.$TempRectangle;
for (let i = 0; i < count; i++) {
let layoutElement = <eui.UIComponent> (target.getChildAt(i));
if (!egret.is(layoutElement, UIComponentClass) || !layoutElement.$includeInLayout) {
continue;
}
let values = layoutElement.$UIComponent;
let hCenter = formatRelative(values[sys.UIKeys.horizontalCenter], unscaledWidth*0.5);
let vCenter = formatRelative(values[sys.UIKeys.verticalCenter], unscaledHeight*0.5);
let left = formatRelative(values[sys.UIKeys.left], unscaledWidth);
let right = formatRelative(values[sys.UIKeys.right], unscaledWidth);
let top = formatRelative(values[sys.UIKeys.top], unscaledHeight);
let bottom = formatRelative(values[sys.UIKeys.bottom], unscaledHeight);
let percentWidth = values[sys.UIKeys.percentWidth];
let percentHeight = values[sys.UIKeys.percentHeight];
let childWidth = NaN;
let childHeight = NaN;
if (!isNaN(left) && !isNaN(right)) {
childWidth = unscaledWidth - right - left;
}
else if (!isNaN(percentWidth)) {
childWidth = Math.round(unscaledWidth * Math.min(percentWidth * 0.01, 1));
}
if (!isNaN(top) && !isNaN(bottom)) {
childHeight = unscaledHeight - bottom - top;
}
else if (!isNaN(percentHeight)) {
childHeight = Math.round(unscaledHeight * Math.min(percentHeight * 0.01, 1));
}
layoutElement.setLayoutBoundsSize(childWidth, childHeight);
layoutElement.getLayoutBounds(bounds);
let elementWidth = bounds.width;
let elementHeight = bounds.height;
let childX = NaN;
let childY = NaN;
if (!isNaN(hCenter))
childX = Math.round((unscaledWidth - elementWidth) / 2 + hCenter);
else if (!isNaN(left))
childX = left;
else if (!isNaN(right))
childX = unscaledWidth - elementWidth - right;
else
childX = bounds.x;
if (!isNaN(vCenter))
childY = Math.round((unscaledHeight - elementHeight) / 2 + vCenter);
else if (!isNaN(top))
childY = top;
else if (!isNaN(bottom))
childY = unscaledHeight - elementHeight - bottom;
else
childY = bounds.y;
layoutElement.setLayoutBoundsPosition(childX, childY);
maxX = Math.max(maxX, childX + elementWidth);
maxY = Math.max(maxY, childY + elementHeight);
}
return egret.$TempPoint.setTo(maxX, maxY);
}
}