Commit 7db18c3c authored by rockyl's avatar rockyl

自动布局

parent fc82b76e
This source diff could not be displayed because it is too large. You can view the blob instead.
This source diff could not be displayed because it is too large. You can view the blob instead.
......@@ -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;
......
This source diff could not be displayed because it is too large. You can view the blob instead.
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