Commit 7db18c3c authored by rockyl's avatar rockyl

自动布局

parent fc82b76e
This diff is collapsed.
This diff is collapsed.
......@@ -5433,6 +5433,11 @@ declare module engine {
export function injectProperties(target: any, source: any): any;
export function transPoint(str: any, sep?: string): {
x: number;
y: number;
}
export function md5(string: any): string;
export class ObjectPool {
......@@ -5568,7 +5573,7 @@ declare module engine {
PROCESS = "process"
}
export function getLogSwitch(id: any): boolean;
export function getLogSwitch(id: any): boolean | Array;
export class Process {
private readonly id;
......@@ -5826,6 +5831,10 @@ declare module engine {
*/
hitTestPoint(globalPoint: Point, isMouseEvent?: boolean): any;
hitTestSelf(globalPoint: any): this;
hitTestSelfBounds(globalPoint: any): this;
/**
* webgl渲染
* @param {WebglRenderer} renderer - The renderer
......@@ -6361,6 +6370,8 @@ declare module engine {
export function getTexture(str: string): any;
export let queryParams: any;
export function httpRequest(url: string, method?: string, params?: any, type?: 'text' | 'json' | 'jsonp', headers?: any): any;
export function jsonp(url: any, params: any): any;
......@@ -6369,6 +6380,30 @@ declare module engine {
export function createTextureSheet(baseTexture: BaseTexture, altaData: any): void;
export function parseSheet(sheet: any): void;
export function parseAssetConfig(assetConfig: any, uuid?: any): void;
export function parse(assetConfig: any, data: any): void;
export function getFont(name: any): any;
export function loadAssets(config: any, onProgress?: any, onComplete?: any): any;
export function getAssetByUUID(uuid: any): any;
export function getAssetByName(name: any): any;
export function playSound(uuid: any, options?: any, name?: any): any;
export function stopSound(name: any): void;
export function destroySound(name: any): void;
export function mute(muted?: boolean): void;
export function preloadSound(url: any, uuid: any): void;
export class Loader extends EventDispatcher {
/**
* 记录原始数据,json和image,贴图在建立时会被缓存
......@@ -6393,6 +6428,8 @@ declare module engine {
loadText(url: string, uuid?: string): any;
loadSound(url: string, uuid?: string): any;
loadImage(url: string, uuid?: string): any;
/**
......@@ -8098,20 +8135,6 @@ declare module engine {
popAll(view?: DisplayObject, options?: any): void;
}
export function parseSheet(sheet: any): void;
export function parseAssetConfig(assetConfig: any, uuid?: any): void;
export function parse(assetConfig: any, data: any): void;
export function getFont(name: any): any;
export function loadAssets(config: any, onProgress?: any, onComplete?: any): any;
export function getAssetByUUID(uuid: any): any;
export function getAssetByName(name: any): any;
export class ShapeBase extends Graphics {
protected __fieldDirty: boolean;
fillColor: any;
......@@ -8200,9 +8223,10 @@ declare module engine {
placeholderColor: any;
maxLength: number;
type: string;
pattern: string;
charRegStr: string;
private _oldFillColor;
private _oldStrokeColor;
private _charReg;
constructor();
......@@ -8212,13 +8236,16 @@ declare module engine {
protected _setText(value: any): void;
private setMaxLength;
private updateMaxLength;
private updateWithCharReg;
private setCharReg;
private showPlaceholderLabel;
setFocus(): void;
setBlur(): void;
private onFocus;
private onBlur;
private onInput;
private onClickStage;
......@@ -8275,6 +8302,9 @@ declare module engine {
}
export class HtmlView extends FloatDisplay {
constructor();
afterConstructor(): void;
}
export function registerNodeType(name: any, def: any): void;
......@@ -8374,12 +8404,6 @@ declare module engine {
export function getProps(id: any): any;
export function playSound(uuid: any, options?: any, name?: any): any;
export function stopSound(name: any): void;
export function destroySound(name: any): void;
export const _default: {
onProgress(done: any, total: any): void;
onComplete(): void;
......@@ -8389,13 +8413,11 @@ declare module engine {
export function launch(url: any, loadingDelegate?: any, onStart?: any): any;
export function launchWithLocalStorage(id: any, loadingDelegate?: any, onStart?: any): any;
export function launchWithWindowVariable(name: any, loadingDelegate?: any, onStart?: any): any;
export function launchWithLocalStorage(id: any, loadingDelegate?: any, onStart?: any): Promise<any>;
export function launchWithConfig(config: any, loadingDelegate?: any, onStart?: any): any;
export function launchWithWindowVariable(name: any, loadingDelegate?: any, onStart?: any): Promise<any>;
export let queryParams: any;
export function launchWithConfig(config: any, loadingDelegate?: any, onStart?: any): Promise<any>;
export const emojiRegexp: RegExp;
......
import {DisplayObject} from './DisplayObject';
import {Rectangle} from "../math/Rectangle";
import {Point} from '../math';
import {Point} from '../math/index';
import CanvasRenderer from '../renderers/CanvasRenderer';
import {Event} from "../events/Event"
import {WebglRenderer} from '../renderers/WebglRenderer';
......@@ -9,7 +9,8 @@ import {applyAutoAdjust} from "../../zeroing/decorators/auto-adjust";
import {applyScript} from "../../zeroing/decorators/scripts";
import {applyEvents} from "../../zeroing/decorators/events";
import {afterConstructor} from "../../zeroing/decorators/after-constructor";
import {injectProperties, instantiateScript} from "../../zeroing/utils";
import {injectProperties, instantiateScript} from "../../zeroing/utils/index";
import {isUI} from "../../zeroing/game-warpper/nodes/IUIComponent";
/**
* 容器类
......@@ -30,6 +31,8 @@ export default class Container extends DisplayObject {
horizonCenter: number;
verticalCenter: number;
private _lastLocalID;
/**
* 为false鼠标事件不再向下传递
*/
......@@ -407,6 +410,12 @@ export default class Container extends DisplayObject {
child.updateTransform();
}
}
if(isUI(this) && this._lastLocalID !== this.transform.localID){
this._lastLocalID = this.transform.localID;
//console.log(this.name, this.instanceId , 'dirty!');
this.stage.layoutInvalid = true;
}
}
/**
......
import Container from "./Container";
import {devicePixelRatio, osType, RENDERER_TYPE, StageScaleMode} from "../const"
import SystemRenderer from "../renderers/SystemRenderer";
import {Point, Rectangle} from "../math";
import {Point, Rectangle} from "../math/index";
import {EventDispatcher} from "../events/EventDispatcher";
import {Event} from "../events/Event";
import {FloatDisplay} from "./FloatDisplay";
......@@ -11,7 +11,7 @@ import {MouseEvent} from "../events/MouseEvent";
import {WebglRenderer} from "../renderers/WebglRenderer";
import {GDispatcher} from "../events/GDispatcher";
import CanvasRenderer from "../renderers/CanvasRenderer";
import {GlobalPro, isWebGLSupported} from "../utils";
import {GlobalPro, isWebGLSupported} from "../utils/index";
//如果以后还出现帧率问题,使用ticker;
//兼容requestAnimationFrame
......@@ -115,6 +115,11 @@ export class Stage extends Container {
*/
private static _stageList: any = {};
/**
* 布局失效
*/
layoutInvalid: boolean = false;
/**
* 是否暂停
* @property pause
......@@ -132,7 +137,7 @@ export class Stage extends Container {
this._pause = value;
if (value != this._pause) {
//触发事件
GDispatcher.dispatchEvent("onStagePause", { pause: value });
GDispatcher.dispatchEvent("onStagePause", {pause: value});
}
}
......@@ -575,7 +580,7 @@ export class Stage extends Container {
vH *= ih / 100;
}
}
return { w: vW, h: vH };
return {w: vW, h: vH};
}
/**
......@@ -1005,6 +1010,14 @@ export class Stage extends Container {
}
}
afterUpdateTransform() {
this.calculateBounds();
if (this.layoutInvalid) {
this.dispatchEvent(Event.LAYOUT_INVALID);
this.layoutInvalid = false;
}
}
public destroy(): void {
let s = this;
Stage.removeUpdateObj(s);
......
......@@ -231,6 +231,15 @@ export class Event extends HashObject {
* @type {string}
*/
public static TIMER_COMPLETE: string = "onTimerComplete";
/**
* 布局失效事件
* @property LAYOUT_INVALID
* @since 1.0.0
* @static
* @public
* @type {string}
*/
public static LAYOUT_INVALID: string = "LAYOUT_INVALID";
/**
* 数据更新事件
* @property UPDATE_DATA
......
......@@ -101,6 +101,13 @@ export default class Transform extends HashObject {
this._localID++;
}
/**
* 返回local矩阵的id
*/
get localID() {
return this._localID;
}
/**
* 当斜切改变时,先记录,优化计算
* @private
......
......@@ -131,11 +131,11 @@ export default class CanvasRenderer extends SystemRenderer {
}
displayObject.parent = this._tempDisplayObjectParent;
displayObject.updateTransform();
displayObject.parent = cacheParent;
displayObject.stage && displayObject.stage.afterUpdateTransform();
//初始化上下文状态
context.save();
context.setTransform(1, 0, 0, 1, 0, 0);
......
......@@ -179,6 +179,8 @@ export class WebglRenderer extends SystemRenderer {
displayObject.updateTransform();
displayObject.parent = cacheParent;
displayObject.stage && displayObject.stage.afterUpdateTransform();
//绑定渲染对象,没有则是默认root
this.bindRenderTexture(renderTexture, transform);
......
......@@ -4,4 +4,4 @@
export {ScrollViewBase} from "./ScrollViewBase";
export {ScrollListBase} from "./ScrollListBase";
export {Button} from "./Button";
\ No newline at end of file
//export {Button} from "./Button";
\ No newline at end of file
......@@ -4,8 +4,7 @@
* 自适应功能
*/
import {Event} from "../../2d/events";
import {Stage} from "../../2d/display";
import {Event} from "../../2d/events/index";
/**
* 应用自适应
......@@ -93,16 +92,10 @@ class AdjustProxy {
}
adjustLayout() {
return;
const that = this._host;
let pWidth, pHeight;
//if(that.parent instanceof Stage){
// pWidth = that.parent.desWidth;
// pHeight = that.parent.desHeight;
//}else{
pWidth = that.parent.width;
pHeight = that.parent.height;
//}
const {width: pWidth, height: pHeight} = that.parent;
const {width, height} = that;
const {percentWidth, percentHeight, left, top, right, bottom, horizonCenter, verticalCenter} = this.data;
......
......@@ -2,7 +2,7 @@
* Created by rockyl on 2019-11-05.
*/
import {Container, Stage} from "../../2d/display/index";
import {Stage} from "../../2d/display/index";
import {StackContainer} from "./StackContainer";
import {loadAssets} from "./assets-manager";
import {instantiate} from "./view-interpreter";
......@@ -14,11 +14,12 @@ import {injectEnv} from "./enviroment";
import {Toast} from "./Toast";
import {arrayFind} from "../utils";
import {registerCustomModules, registerScripts} from "..";
import {Node} from "./nodes/Node";
/**
* 游戏舞台
*/
export class GameStage extends Container {
export class GameStage extends Node {
private _sceneContainer: StackContainer; //场景容器
private _popupContainer: StackContainer; //弹层容器
private _toast: Toast;
......
......@@ -2,12 +2,13 @@
* Created by rockyl on 2019-11-05.
*/
import {Container, DisplayObject} from "../../2d/display/index";
import {DisplayObject} from "../../2d/display/index";
import {Node} from "./nodes/Node";
/**
* 栈式视图容器
*/
export class StackContainer extends Container {
export class StackContainer extends Node {
private _mutex: boolean;
private _stack = [];
......
......@@ -2,14 +2,13 @@
* Created by rockyl on 2019-11-25.
*/
import {Container} from "../../2d/display/index";
import {GameStage} from "./GameStage";
import {Label, Rect} from "./nodes";
import {Tween} from "../../2d/tween";
import {Label, Rect, Node} from "./nodes/index";
import {Tween} from "../../2d/tween/index";
export class Toast extends Container {
private _contentSample: Container;
private _content: Container;
export class Toast extends Node {
private _contentSample: Node;
private _content: Node;
private _gameStage: GameStage;
......@@ -80,7 +79,7 @@ export class Toast extends Container {
}
if (!view) {
if (!this._contentSample) {
this._contentSample = new Container();
this._contentSample = new Node();
let bg = new Rect();
bg.borderRadius = 10;
bg.percentWidth = 100;
......
/**
* Created by rockyl on 2020-03-03.
*/
import {Stage} from "../../2d/display/Stage";
import {Event} from "../../2d/events/Event";
import {traverseViewNode} from "../utils/utils";
import {isUI} from "./nodes/IUIComponent";
let _stage: Stage;
export function initAutoLayout(stage: Stage) {
_stage = stage;
_stage.addEventListener(Event.LAYOUT_INVALID, onLayoutInvalid)
}
function onLayoutInvalid() {
console.log('onLayoutInvalid');
//traverseViewNode(_stage, adjustLayout);
}
function adjustLayout(node) {
if (!isUI(node)) {
return;
}
const {width, height, parent: {width: pWidth, height: pHeight},} = node;
const {percentWidth, percentHeight, left, top, right, bottom, horizonCenter, verticalCenter} = node;
const applyPercentWidth = function () {
if (t(percentWidth)) {
node.width = pWidth * percentWidth / 100;
}
};
const applyPercentHeight = function () {
if (t(percentHeight)) {
node.height = pHeight * percentHeight / 100;
}
};
let pw = true, ph = true;
if (t(horizonCenter)) {
applyPercentWidth();
node.x = (pWidth - node.width) / 2 + horizonCenter;
} else {
if (t(left)) {
node.x = left;
if (t(right)) {
node.width = pWidth - left - right;
pw = false;
}
} else if (t(right)) {
node.x = pWidth - width - right;
}
if (pw) {
applyPercentWidth();
}
}
if (t(verticalCenter)) {
applyPercentHeight();
node.y = (pHeight - node.height) / 2 + verticalCenter;
} else {
if (t(top)) {
node.y = top;
if (t(bottom)) {
node.height = pHeight - top - bottom;
ph = false;
}
} else if (t(bottom)) {
node.y = pHeight - height - bottom;
}
if (ph) {
applyPercentHeight();
}
}
}
function t(v) {
return !isNaN(v) && v !== null && v !== undefined;
}
/**
* Created by Raykid on 2016/12/16.
*/
import {IAres, Compiler, AresOptions, IWatcher, WatcherCallback, AresCommandData} from "./Interfaces";
import {Mutator} from "./Mutator";
import {Watcher} from "./Watcher";
import {CommandContext, Command, commands} from "./Commands"
export const defaultCmdRegExp:RegExp = /^(data\-)?a[\-_](\w+)([:\$](.+))?$/;
/**
* 将数据模型和视图进行绑定
* @param data
* @param compiler 视图解析器,不同类型的视图需要使用不同的解析器解析后方可使用
* @param options 一些额外参数
* @returns {IAres} 绑定实体对象
*/
export function bind(data:any, compiler:Compiler, options?:AresOptions):IAres
{
return new Ares(data, compiler, options);
}
export class Ares implements IAres
{
private _data:any;
private _compiler:Compiler;
private _options:any;
/** 获取ViewModel */
public get data():any
{
return this._data;
}
/** 获取编译器 */
public get compiler():Compiler
{
return this._compiler;
}
public constructor(data:any, compiler:Compiler, options?:AresOptions)
{
// 记录变异对象
this._data = Mutator.mutate(data);
this._compiler = compiler;
this._options = options;
// 初始化Compiler
this._compiler.init(this);
// 调用回调
if(this._options && this._options.inited)
{
this._options.inited.call(this._data, this);
}
}
public createWatcher(target:any, exp:string, scope:any, callback:WatcherCallback):IWatcher
{
return new Watcher(this, target, exp, scope, callback);
}
/**
* 解析表达式成为命令数据
* @param key 属性名,合法的属性名应以a-或a_开头,以:或$分隔主命令和子命令
* @param value 属性值,如果属性名合法则会被用来作为表达式的字符串
* @param cmdRegExp 可选,如果不传则使用默认的命令正则表达式解析命令
* @return {CommandData|null} 命令数据,如果不是命令则返回null
*/
public parseCommand(key:string, value:string, cmdRegExp?:RegExp):AresCommandData
{
var result:RegExpExecArray = (cmdRegExp || defaultCmdRegExp).exec(key);
if(!result) return null;
// 取到key
var key:string = result[0];
// 取到命令名
var cmdName:string = result[2];
// 取到命令字符串
var exp:string = value;
// 取到子命令名
var subCmd:string = result[4] || "";
// 返回结构体
return {
cmdName: cmdName,
subCmd: subCmd,
propName: key,
exp: exp
};
}
/**
* 测试是否是通用命令
* @param data 命令数据
* @return {boolean} 返回一个布尔值,表示该表达式是否是通用命令
*/
public testCommand(data:AresCommandData):boolean
{
// 非空判断
if(!data) return false;
// 取到通用命令
var cmd:Command = commands[data.cmdName];
return (cmd != null);
}
/**
* 执行通用命令,如果该表达式是通用命令则直接执行,否则什么都不做
* @param data 命令数据
* @param target 目标对象
* @param scope 变量作用域
* @return {boolean} 返回一个布尔值,表示该表达式是否是通用命令
*/
public execCommand(data:AresCommandData, target:any, scope:any):boolean
{
// 非空判断
if(!data || !scope) return false;
// 取到通用命令
var cmd:Command = commands[data.cmdName];
// 没找到命令就返回false
if(!cmd) return false;
// 找到命令了,执行之
cmd({
target: target,
scope: scope,
entity: this,
data: data
});
return true;
}
}
\ No newline at end of file
/**
* Created by Raykid on 2017/7/19.
*/
import {IAres, AresCommandData} from "./Interfaces"
import {runExp} from "./Utils"
export interface CommandContext
{
target:any;
scope:any;
entity:IAres;
data:AresCommandData;
}
export interface Command
{
/**
* 执行命令
* @param context 命令上下文
* @return {any} 要替换原显示节点的显示节点
*/
(context?:CommandContext):any;
}
export const commands:{[name:string]:Command} = {
/** 一次性设置变量命令,在数据中插入一个变量 */
set: (context:CommandContext)=>
{
// 设置变量值
runExp(context.data.subCmd + "=" + context.data.exp, context.scope);
return context.target;
},
/** 绑定设置变量命令,在数据中插入一个变量(如果不提供子命令则不插入变量),并根据表达式的值同步更新变量的值 */
bind: (context:CommandContext)=>
{
// 创建订阅器,监听表达式值变化
context.entity.createWatcher(context.target, context.data.exp, context.scope, (value:any)=>{
// 如果子命令不为空,则更新变量值
if(context.data.subCmd)
runExp(context.data.subCmd + "=" + context.data.exp, context.scope);
});
return context.target;
}
};
\ No newline at end of file
/**
* Created by Raykid on 2016/12/22.
*/
import {Watcher} from "./Watcher";
export class Dep
{
private _map:{[uid:number]:Watcher} = {};
/**
* 添加数据变更订阅者
* @param watcher 数据变更订阅者
*/
public watch(watcher:Watcher):void
{
if(!this._map[watcher.uid])
{
this._map[watcher.uid] = watcher;
}
}
/**
* 数据变更,通知所有订阅者
* @param extra 可能的额外数据
*/
public notify(extra?:any):void
{
for(var uid in this._map)
{
var watcher:Watcher = this._map[uid];
watcher.update(extra);
}
}
}
\ No newline at end of file
/**
* Created by Raykid on 2016/12/22.
*/
export interface Compiler
{
/** 传递给编译器的皮肤对象 */
root:any;
/**
* 初始化编译器
* @param entity Ares实例
*/
init(entity:IAres):void;
/**
* 编译方法
* @param target 要编译的显示节点
* @param scope 作用域
*/
compile(target:any, scope:any):void;
}
export interface IAres
{
/** 获取ViewModel */
data:any;
/** 获取编译器 */
compiler:Compiler;
/**
* 创建一个订阅者
* @param target 作用目标,指表达式所在的显示对象
* @param exp 表达式
* @param scope 作用域
* @param callback 订阅器回调
*/
createWatcher(target:any, exp:string, scope:any, callback:WatcherCallback):IWatcher;
/**
* 解析表达式成为命令数据
* @param key 属性名,合法的属性名应以a-或a_开头,以:或$分隔主命令和子命令
* @param value 属性值,如果属性名合法则会被用来作为表达式的字符串
* @return {CommandData|null} 命令数据,如果不是命令则返回null
*/
parseCommand(key:string, value:string):AresCommandData;
/**
* 测试是否是通用命令
* @param data 命令数据
* @return {boolean} 返回一个布尔值,表示该表达式是否是通用命令
*/
testCommand(data:AresCommandData):boolean;
/**
* 执行通用命令,如果该表达式是通用命令则直接执行,否则什么都不做
* @param data 命令数据
* @param target 目标对象
* @param scope 变量作用域
* @return {boolean} 返回一个布尔值,表示该表达式是否是通用命令
*/
execCommand(data:AresCommandData, target:any, scope:any):boolean
}
export interface AresOptions
{
inited?:(entity?:IAres)=>void;
}
export interface IWatcher
{
/**
* 获取到表达式当前最新值
* @returns {any} 最新值
*/
getValue():any;
/**
* 当依赖的数据有更新时调用该方法
* @param extra 可能的额外数据
*/
update(extra?:any):void;
/** 销毁订阅者 */
dispose():void;
}
export interface WatcherCallback
{
(newValue?:any, oldValue?:any, extra?:any):void;
}
export interface AresCommandData
{
/** 主命令名 */
cmdName:string;
/** 子命令名 */
subCmd:string;
/** 命令属性全名 */
propName:string;
/** 表达式 */
exp:string;
}
\ No newline at end of file
/**
* Created by Raykid on 2016/12/22.
*/
import {Watcher} from "./Watcher";
import {Dep} from "./Dep";
export class Mutator
{
// 记录数组中会造成数据更新的所有方法名
private static _arrMethods:string[] = [
"push",
"pop",
"unshift",
"shift",
"splice",
"sort",
"reverse"
];
/**
* 将用户传进来的数据“变异”成为具有截获数据变更能力的数据
* @param data 原始数据
* @returns {any} 变异后的数据
*/
public static mutate(data:any):any
{
// 如果是简单类型,则啥也不做
if(!data || typeof data != "object") return;
// 是个复杂类型对象,但是以前变异过了就不再重做一遍了
if(!data.__ares_mutated__)
{
// 针对每个内部变量都进行一次变异
for(var key in data)
{
Mutator.mutateObject(data, key, data[key]);
}
// 打一个标记表示已经变异过了
Object.defineProperty(data, "__ares_mutated__", {
value: true,
writable: false,
enumerable: false,
configurable: false
});
}
return data;
}
private static mutateObject(data:any, key:string, value:any):void
{
// 对每个复杂类型对象都要有一个对应的依赖列表
var dep:Dep = new Dep();
// 变异过程
Object.defineProperty(data, key, {
enumerable: true,
configurable: false,
get: ()=>{
// 如果Watcher.updating不是null,说明当前正在执行表达式,那么获取的变量自然是其需要依赖的
var watcher:Watcher = Watcher.updating;
if(watcher) dep.watch(watcher);
// 利用闭包保存原始值
return value;
},
set: v=>{
if(v == value) return;
value = v;
// 如果是数组就走专门的数组变异方法,否则递归变异对象
if(Array.isArray(v)) Mutator.mutateArray(v, dep);
else Mutator.mutate(v);
// 触发通知
dep.notify();
}
});
// 递归变异
Mutator.mutate(value);
}
private static mutateArray(arr:any[], dep:Dep):void
{
// 变异当前数组
arr["__proto__"] = Mutator.defineReactiveArray(dep);
// 遍历当前数组,将内容对象全部变异
for(var i:number = 0, len:number = arr.length; i < len; i++)
{
Mutator.mutate(arr[i]);
}
}
private static defineReactiveArray(dep:Dep):any[]
{
var proto:any[] = Array.prototype;
var result:any[] = Object.create(proto);
// 遍历所有方法,一个一个地变异
Mutator._arrMethods.forEach((method:string)=>{
// 利用闭包记录一个原始方法
var oriMethod:Function = proto[method];
// 开始变异
Object.defineProperty(result, method, {
value: function(...args:any[]):any
{
// 首先调用原始方法,获取返回值
var result:any = oriMethod.apply(this, args);
// 数组插入项
var inserted:any[];
switch(method)
{
case "push":
case "unshift":
inserted = args;
break
case "splice":
inserted = args.slice(2);
break
}
// 监视数组插入项,而不是重新监视整个数组
if(inserted && inserted.length)
{
Mutator.mutateArray(inserted, dep);
}
// 触发更新
dep.notify({method: args});
// 返回值
return result;
}
});
});
// 提供替换数组设置的方法,因为直接设置数组下标的方式无法变异
Object.defineProperty(result, "$set", {
value: function(index:number, value:any):any
{
// 超出数组长度默认追加到最后
if(index >= this.length) index = this.length;
return this.splice(index, 1, value)[0];
}
});
// 提供替换数组移除的方法,因为直接移除的方式无法变异
Object.defineProperty(result, "$remove", {
value: function(item:any):any
{
var index = this.indexOf(item);
if(index > -1) return this.splice(index, 1);
return null;
}
});
return result;
}
}
\ No newline at end of file
/**
* Created by Raykid on 2016/12/22.
*/
/**
* 创建一个表达式求值方法,用于未来执行
* @param exp 表达式
* @returns {Function} 创建的方法
*/
export function createEvalFunc(exp:string):(scope:any)=>any
{
var func:(scope:any)=>any;
try
{
func = Function("scope", "with(scope){return " + exp + "}") as (scope:any)=>any;
}
catch(err)
{
// 可能是某些版本的解释器不认识模板字符串,将模板字符串变成普通字符串
var sepStr:string = (exp.indexOf('"') < 0 ? '"' : "'");
// 将exp中的·替换为'
var reg:RegExp = /([^\\]?)`/g;
exp = exp.replace(reg, "$1" + sepStr);
// 将exp中${...}替换为" + ... + "的形式
reg = /\$\{(.*?)\}/g;
exp = exp.replace(reg, sepStr + "+($1)+" + sepStr);
// 重新生成方法并返回
func = Function("scope", "with(scope){return " + exp + "}") as (scope:any)=>any;
}
return func;
}
/**
* 表达式求值,无法执行多条语句
* @param exp 表达式
* @param scope 表达式的作用域
* @returns {any} 返回值
*/
export function evalExp(exp:string, scope:any):any
{
return createEvalFunc(exp)(scope);
}
/**
* 创建一个执行方法,用于未来执行
* @param exp 表达式
* @returns {Function} 创建的方法
*/
export function createRunFunc(exp:string):(scope:any)=>void
{
return createEvalFunc("(function(){" + exp + "})()");
}
/**
* 直接执行表达式,不求值。该方法可以执行多条语句
* @param exp 表达式
* @param scope 表达式的作用域
*/
export function runExp(exp:string, scope:any):void
{
createRunFunc(exp)(scope);
}
\ No newline at end of file
import {IAres, IWatcher, WatcherCallback} from "./Interfaces";
import {createEvalFunc} from "./Utils";
/**
* Created by Raykid on 2016/12/22.
* 数据更新订阅者,当依赖的数据有更新时会触发callback通知外面
*/
export class Watcher implements IWatcher
{
/** 记录当前正在执行update方法的Watcher引用 */
public static updating:Watcher = null;
private static _uid:number = 0;
private _uid:number;
/** 获取Watcher的全局唯一ID */
public get uid():number
{
return this._uid;
}
private _value:any;
private _entity:IAres;
private _target:any;
private _exp:string;
private _scope:any;
private _expFunc:(scope:any)=>any;
private _callback:WatcherCallback;
private _disposed:boolean = false;
public constructor(entity:IAres, target:any, exp:string, scope:any, callback:WatcherCallback)
{
// 记录entity
this._entity = entity;
// 生成一个全局唯一的ID
this._uid = Watcher._uid ++;
// 记录作用目标、表达式和作用域
this._target = target;
this._exp = exp;
this._scope = scope;
// 将表达式和作用域解析为一个Function
this._expFunc = createEvalFunc(exp);
// 记录回调函数
this._callback = callback;
// 进行首次更新
this.update();
}
/**
* 获取到表达式当前最新值
* @returns {any} 最新值
*/
public getValue():any
{
if(this._disposed) return null;
var value:any = null;
// 记录自身
Watcher.updating = this;
// 设置通用属性
// 这里一定要用defineProperty将目标定义在当前节点上,否则会影响context.scope
Object.defineProperty(this._scope, "$root", {
configurable: true,
enumerable: false,
value: this._entity.compiler.root,
writable: false
});
// 这里一定要用defineProperty将目标定义在当前节点上,否则会影响context.scope
Object.defineProperty(this._scope, "$target", {
configurable: true,
enumerable: false,
value: this._target,
writable: false
});
// 表达式求值
try
{
value = this._expFunc.call(this._scope, this._scope);
}
catch(err)
{
// 输出错误日志
console.warn("表达式求值错误\nerr: " + err.toString() + "\nexp:" + this._exp + ",scope:" + JSON.stringify(this._scope));
}
// 移除通用属性
delete this._scope["$root"];
delete this._scope["$target"];
// 移除自身记录
Watcher.updating = null;
return value;
}
/**
* 当依赖的数据有更新时调用该方法
* @param extra 可能的额外数据
*/
public update(extra?:any):void
{
if(this._disposed) return;
var value:any = this.getValue();
if(!Watcher.isEqual(value, this._value))
{
this._callback && this._callback(value, this._value, extra);
this._value = Watcher.deepCopy(value);
}
}
/** 销毁订阅者 */
public dispose():void
{
if(this._disposed) return;
this._value = null;
this._target = null;
this._exp = null;
this._scope = null;
this._expFunc = null;
this._callback = null;
this._disposed = true;
}
/**
* 是否相等,包括基础类型和对象/数组的对比
*/
private static isEqual(a:any, b:any):boolean
{
return (a == b || (
Watcher.isObject(a) && Watcher.isObject(b)
? JSON.stringify(a) == JSON.stringify(b)
: false
));
}
/**
* 是否为对象(包括数组、正则等)
*/
private static isObject(obj:any):boolean
{
return (obj && typeof obj == "object");
}
/**
* 复制对象,若为对象则深度复制
*/
private static deepCopy(from:any):any
{
if (Watcher.isObject(from))
{
// 复杂类型对象,先字符串化,再对象化
return JSON.parse(JSON.stringify(from));
}
else
{
// 基本类型对象,直接返回之
return from;
}
}
}
\ No newline at end of file
/**
* Created by rockyl on 2020-03-02.
*/
......@@ -8,8 +8,11 @@ import Texture from "../../../2d/texture/Texture";
import {getFont} from "../bmp-text-manager";
import {dirtyFieldTrigger} from "../../decorators";
import {VERTICAL_ALIGN} from "../../../2d/const";
import {IUIComponent} from "./IUIComponent";
export class BitmapText extends Container implements IUIComponent {
isUI = true;
export class BitmapText extends Container {
private _charCache = [];
private _fontConfig;
......
......@@ -2,17 +2,19 @@
* Created by rockyl on 2020-01-07.
*/
import {FloatDisplay} from "../../../2d/display/index";
import {Container, FloatDisplay} from "../../../2d/display/index";
import {afterConstructor} from "../../decorators/after-constructor";
import {applyAutoAdjust} from "../../decorators/auto-adjust";
import {applyScript} from "../../decorators/scripts";
import {applyEvents} from "../../decorators/events";
import {IUIComponent} from "./IUIComponent";
@afterConstructor
@applyAutoAdjust
@applyScript
@applyEvents
export class HtmlView extends FloatDisplay{
export class HtmlView extends FloatDisplay implements IUIComponent{
isUI = true;
constructor() {
super();
......
/**
* Created by rockyl on 2020-03-03.
*/
export interface IUIComponent {
isUI: boolean,
}
export function isUI(obj){
return obj.isUI;
}
/**
* Created by rockyl on 2019-11-07.
*/
import {Sprite} from "../../../2d/display";
import {Sprite} from "../../../2d/display/index";
import Texture from "../../../2d/texture/Texture";
import {getAssetByName, getAssetByUUID} from "../assets-manager";
import {dataCenter} from "../data-center";
import {ESCAPE_REG_EXP} from "../../utils";
import {Event} from "../../../2d/events";
import {ESCAPE_REG_EXP} from "../../utils/index";
import {Event} from "../../../2d/events/index";
import {Container} from "../../../2d/display/index";
import {IUIComponent} from "./IUIComponent";
const assetScheme = 'asset://';
export class Image extends Sprite {
export class Image extends Sprite implements IUIComponent {
isUI = true;
private _originText;
private _escapes = [];
private _registeredEvents = [];
......
......@@ -4,11 +4,15 @@
import {TextField} from "../../../2d/text/index";
import {dataCenter} from "../data-center";
import {ESCAPE_REG_EXP, htmlToPureText} from "../../utils/index";
import {Container} from "../../../2d/display/index";
import {IUIComponent} from "./IUIComponent";
/**
* 文本
*/
export class Label extends TextField {
export class Label extends TextField implements IUIComponent {
isUI = true;
private _originText;
private _escapes = [];
private _registeredEvents = [];
......
/**
* Created by rockyl on 2020-03-03.
*/
import {Container} from "../../../2d/display/index";
import {IUIComponent} from "./IUIComponent";
export class Node extends Container implements IUIComponent{
isUI = true;
}
\ No newline at end of file
......@@ -6,8 +6,11 @@ import {ScrollListBase, ScrollListItemBase} from "../../../2d/ui/ScrollListBase"
import {Event} from "../../../2d/events";
import {proxyMethods} from "./ScrollView";
import Container from "../../../2d/display/Container";
import {IUIComponent} from "./IUIComponent";
export class ScrollListItem extends ScrollListItemBase implements IUIComponent {
isUI = true;
export class ScrollListItem extends ScrollListItemBase {
view: Container;
setView(view) {
......
......@@ -3,6 +3,8 @@
*/
import {ScrollViewBase} from "../../../2d/ui/ScrollViewBase";
import {Container} from "../../../2d/display/index";
import {IUIComponent} from "./IUIComponent";
export const proxyMethods = [
'onChildrenChange',
......@@ -18,7 +20,9 @@ export const proxyMethods = [
'removeChildren',
];
export class ScrollView extends ScrollViewBase {
export class ScrollView extends ScrollViewBase implements IUIComponent {
isUI = true;
constructor() {
super();
......
......@@ -9,6 +9,8 @@ import {TextField} from "../../../2d/text/index";
import {Point} from "../../../2d/math/index";
import {dirtyFieldTrigger} from "../../decorators";
import {VERTICAL_ALIGN} from "../../../2d/const";
import {Container} from "../../../2d/display/index";
import {IUIComponent} from "./IUIComponent";
let timer;
......@@ -26,7 +28,9 @@ function cancelDelayScrollTop() {
}
}
export class TextInput extends Label {
export class TextInput extends Label implements IUIComponent {
isUI = true;
private _floatDisplay: FloatDisplay;
private _placeholderLabel: TextField;
private _input: any;
......
......@@ -2,6 +2,7 @@
* Created by rockyl on 2019-11-07.
*/
export * from './Node'
export * from './shapes'
export * from './Image'
export * from './Label'
......@@ -10,3 +11,5 @@ export * from './ScrollView'
export * from './ScrollList'
export * from './BitmapText'
export * from './HtmlView'
export * from './IUIComponent'
......@@ -5,11 +5,15 @@ import Color from "color";
import {Event} from "../../../2d/events";
import {dirtyFieldDetector} from "../../decorators";
import Graphics from "../../../2d/graphics/Graphics";
import {Container} from "../../../2d/display/index";
import {IUIComponent} from "./IUIComponent";
/**
* 图形基类
*/
class ShapeBase extends Graphics {
class ShapeBase extends Graphics implements IUIComponent {
isUI = true;
protected __fieldDirty = true;
@dirtyFieldDetector
......
......@@ -2,12 +2,11 @@
* Created by rockyl on 2019-11-08.
*/
import {Container} from "../../2d/display/index";
import {Rect, Image, Label, Circle, ScrollView, TextInput, ScrollList, BitmapText, HtmlView} from "./nodes/index";
import {Node, Rect, Image, Label, Circle, ScrollView, TextInput, ScrollList, BitmapText, HtmlView} from "./nodes/index";
import {injectProperties, instantiateScript,} from "../utils/index";
const nodeTypeMapping = {
node: Container,
node: Node,
rect: Rect,
circle: Circle,
label: Label,
......
......@@ -10,6 +10,7 @@ import {globalLoader} from "../2d/loader/Loader";
import {Event} from "../2d/events/Event";
import builtinLoadingView from "./game-warpper/LoadingView";
import {queryParams} from "./web";
import {initAutoLayout} from "./game-warpper/auto-layout";
export let gameStage: GameStage;
......@@ -59,6 +60,7 @@ export async function launchWithConfig(config, loadingDelegate?, onStart?) {
scaleMode || StageScaleMode.FIXED_WIDTH,
rendererType || RENDERER_TYPE.WEBGL,
);
initAutoLayout(stage);
Stage.flushAll();
stage.addEventListener(Event.ON_INIT_STAGE, () => {
......
/**
* Created by rockyl on 2019-11-08.
*/
import Container from "../../2d/display/Container";
export const ESCAPE_REG_EXP = /\$\{[\u4e00-\u9fa5_a-zA-Z0-9\|]+\}/g;
export const linkedFlag = '$_linked_$';
......@@ -314,3 +315,18 @@ export function injectProperties(target, source) {
return target;
}
/**
* 遍历视图节点
* @param node
* @param callback
*/
export function traverseViewNode(node: Container, callback: Function) {
for (let child of node.children) {
callback(child);
if (child.children && child.children.length > 0) {
traverseViewNode(child, callback);
}
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment