hzengine-core
Version:
An Visual Novel Engine for Zepp OS
526 lines (525 loc) • 24 kB
JavaScript
var __esDecorate = (this && this.__esDecorate) || function (ctor, descriptorIn, decorators, contextIn, initializers, extraInitializers) {
function accept(f) { if (f !== void 0 && typeof f !== "function") throw new TypeError("Function expected"); return f; }
var kind = contextIn.kind, key = kind === "getter" ? "get" : kind === "setter" ? "set" : "value";
var target = !descriptorIn && ctor ? contextIn["static"] ? ctor : ctor.prototype : null;
var descriptor = descriptorIn || (target ? Object.getOwnPropertyDescriptor(target, contextIn.name) : {});
var _, done = false;
for (var i = decorators.length - 1; i >= 0; i--) {
var context = {};
for (var p in contextIn) context[p] = p === "access" ? {} : contextIn[p];
for (var p in contextIn.access) context.access[p] = contextIn.access[p];
context.addInitializer = function (f) { if (done) throw new TypeError("Cannot add initializers after decoration has completed"); extraInitializers.push(accept(f || null)); };
var result = (0, decorators[i])(kind === "accessor" ? { get: descriptor.get, set: descriptor.set } : descriptor[key], context);
if (kind === "accessor") {
if (result === void 0) continue;
if (result === null || typeof result !== "object") throw new TypeError("Object expected");
if (_ = accept(result.get)) descriptor.get = _;
if (_ = accept(result.set)) descriptor.set = _;
if (_ = accept(result.init)) initializers.unshift(_);
}
else if (_ = accept(result)) {
if (kind === "field") initializers.unshift(_);
else descriptor[key] = _;
}
}
if (target) Object.defineProperty(target, contextIn.name, descriptor);
done = true;
};
var __runInitializers = (this && this.__runInitializers) || function (thisArg, initializers, value) {
var useValue = arguments.length > 2;
for (var i = 0; i < initializers.length; i++) {
value = useValue ? initializers[i].call(thisArg, value) : initializers[i].call(thisArg);
}
return useValue ? value : void 0;
};
import { Save, CustomSave } from "../storage/decorator.js";
// / <reference path="node_modules/@zeppos/device-types/dist/index.d.ts" />
// import * as hmUI from "@zos/ui";
// import {} from "@zos/ui";
// import { getDeviceInfo, SCREEN_SHAPE_SQUARE } from "@zos/device";
// const { width, height, screenShape } = getDeviceInfo();
let UI = (() => {
let __layerList_decorators;
let __layerList_initializers = [];
let __layerList_extraInitializers = [];
let __nextViewId_decorators;
let __nextViewId_initializers = [];
let __nextViewId_extraInitializers = [];
let __viewMap_decorators;
let __viewMap_initializers = [];
let __viewMap_extraInitializers = [];
let __routerMap_decorators;
let __routerMap_initializers = [];
let __routerMap_extraInitializers = [];
return class UI {
static {
const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(null) : void 0;
__layerList_decorators = [CustomSave("ui.layerList", function serializer(layerList) {
let obj = {};
for (let [key, value] of this.layerList) {
obj[key] = [value.name, value.z_index];
}
return obj;
}, function deserializer(obj) {
// destroy old layer
for (let [key, value] of this.layerList) {
value.destroy();
}
this.layerList.clear();
let newLayerList = new Map();
// create new layer
for (let key in obj) {
let newLayer = new UI.Layer(this._core, obj[key][0], obj[key][1]);
newLayerList.set(key, newLayer);
this._core.emit("afterAddLayer", newLayer);
}
return newLayerList;
})];
__nextViewId_decorators = [Save("ui.nextViewId")];
__viewMap_decorators = [CustomSave("ui.viewMap", function serializer(viewMap) {
let obj = {};
for (let [id, view] of viewMap) {
// 注意viewMap中的id是number,而obj中的id會自動轉成string
if (view.isSave)
obj[id] = view.serialize();
}
return obj;
}, function deserializer(obj) {
let newViewMap = new Map();
for (let key in obj) {
let item = obj[key];
let view = this._produceViewWithId(item.name, item.layer, item.prop, Number(key));
view.isSave = true;
newViewMap.set(Number(key), view);
}
return newViewMap;
})];
__routerMap_decorators = [CustomSave("ui.routerMap", function serializer(routerMap) {
let obj = {};
for (let [key, value] of routerMap) {
if (!value.isSave)
continue;
obj[key] = value.serialize();
}
return obj;
}, function deserializer(obj) {
let newRouterMap = new Map();
// reshow not save router
for (let [name, router] of this._routerMap) {
if (!router.isSave) {
if (router.length > 0) {
// TODO 因爲讀檔的時候會重置整個ui系統,所以要重新創建activeViewInstance 這裏感覺有點問題
router.activeViewInstance = this._core.ui.createView(router.viewStack[0][0], router.layer, router.viewStack[0][1], router.isSave);
}
newRouterMap.set(name, router);
}
}
// reshow save router
for (let key in obj) {
newRouterMap.set(key, UI.Router.deserialize(this, obj[key]));
}
return newRouterMap;
})];
__esDecorate(this, null, __layerList_decorators, { kind: "accessor", name: "_layerList", static: false, private: false, access: { has: obj => "_layerList" in obj, get: obj => obj._layerList, set: (obj, value) => { obj._layerList = value; } }, metadata: _metadata }, __layerList_initializers, __layerList_extraInitializers);
__esDecorate(this, null, __nextViewId_decorators, { kind: "accessor", name: "_nextViewId", static: false, private: false, access: { has: obj => "_nextViewId" in obj, get: obj => obj._nextViewId, set: (obj, value) => { obj._nextViewId = value; } }, metadata: _metadata }, __nextViewId_initializers, __nextViewId_extraInitializers);
__esDecorate(this, null, __viewMap_decorators, { kind: "accessor", name: "_viewMap", static: false, private: false, access: { has: obj => "_viewMap" in obj, get: obj => obj._viewMap, set: (obj, value) => { obj._viewMap = value; } }, metadata: _metadata }, __viewMap_initializers, __viewMap_extraInitializers);
__esDecorate(this, null, __routerMap_decorators, { kind: "accessor", name: "_routerMap", static: false, private: false, access: { has: obj => "_routerMap" in obj, get: obj => obj._routerMap, set: (obj, value) => { obj._routerMap = value; } }, metadata: _metadata }, __routerMap_initializers, __routerMap_extraInitializers);
if (_metadata) Object.defineProperty(this, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata });
}
_core;
constructor(_core) {
__runInitializers(this, __routerMap_extraInitializers);
this._core = _core;
this._initUI();
}
_initUI() {
this.addLayer("bg", 1);
this.addLayer("fg", 2);
this.addLayer("ct", 3);
this.addLayer("overlay", 4);
this.addRouter("page", "overlay", false);
}
_cleanUI() {
for (let [key, value] of this.layerList) {
value.destroy();
}
this.layerList.clear();
this._routerMap.clear();
}
resetUI() {
this._cleanUI();
this._initUI();
}
#_layerList_accessor_storage = __runInitializers(this, __layerList_initializers, new Map());
// Layer
get _layerList() { return this.#_layerList_accessor_storage; }
set _layerList(value) { this.#_layerList_accessor_storage = value; }
get layerList() {
return this._layerList;
}
addLayer(name, z_index) {
this._core.emit("beforeAddLayer", name, z_index);
if (this._layerList.has(name))
throw `Layer ${name} already exist`;
let newLayer = new UI.Layer(this._core, name, z_index);
this._layerList.set(name, newLayer);
this._core.emit("afterAddLayer", newLayer);
}
getLayer(name) {
return this.layerList.get(name);
}
// View Class
_viewClassMap = (__runInitializers(this, __layerList_extraInitializers), new Map());
// _activeViewList: [name: string, layer: string, instance: UI.View<unknown>][] =
// [];
registerView(name, cls) {
this._viewClassMap.set(name, cls);
}
#_nextViewId_accessor_storage = __runInitializers(this, __nextViewId_initializers, 50);
// View
get _nextViewId() { return this.#_nextViewId_accessor_storage; }
set _nextViewId(value) { this.#_nextViewId_accessor_storage = value; }
#_viewMap_accessor_storage = (__runInitializers(this, __nextViewId_extraInitializers), __runInitializers(this, __viewMap_initializers, new Map()));
get _viewMap() { return this.#_viewMap_accessor_storage; }
set _viewMap(value) { this.#_viewMap_accessor_storage = value; }
getView(id) {
return this._viewMap.get(id) ?? null;
}
createView(name, layer, prop, isSave) {
let id = this._nextViewId++;
let viewInstance = this._produceViewWithId(name, layer, prop, id);
this._core.debug.log(`creating view ${viewInstance.name}`);
viewInstance.isSave = isSave;
this._viewMap.set(id, viewInstance);
return viewInstance;
}
updateView(viewInstance, new_prop) {
viewInstance.commit(new_prop);
}
destroyView(viewInstance) {
if (viewInstance.id != null)
this._viewMap.delete(viewInstance.id);
viewInstance.destroy();
}
/**由調用者提供id,創建一個View,不會處理isSave,也不會更新viewMap */
_produceViewWithId(name, layer, prop, id) {
if (!this._viewClassMap.get(name)) {
throw "要创建的View不存在";
}
let _ViewFactory = this._viewClassMap.get(name);
let viewInstance = new _ViewFactory(layer, this._core);
viewInstance.id = id;
viewInstance.name = name;
viewInstance.create(prop);
this._core.debug.log(`producing view ${viewInstance.name}`);
return viewInstance;
}
#_routerMap_accessor_storage = (__runInitializers(this, __viewMap_extraInitializers), __runInitializers(this, __routerMap_initializers, new Map()));
get _routerMap() { return this.#_routerMap_accessor_storage; }
set _routerMap(value) { this.#_routerMap_accessor_storage = value; }
getRouter(tag) {
return this._routerMap.get(tag);
}
addRouter(tag, layer, isSave = true) {
if (this._routerMap.has(tag))
throw `Route with tag [${tag}] already exist!`;
let router = new UI.Router(this, tag, layer, isSave);
this._routerMap.set(tag, router);
return router;
}
getScreenSize() {
let [width, height] = this._core.platform.getScreenSize();
return { width, height };
}
/**
* 根据 BasicUniversalProp 计算屏幕上的位置
* @param prop 包含 BasicUniversalProp 的 prop
* @param size (可选)图像的尺寸,若不指定,返回的anchor坐标和origin坐标一样
* @returns
*/
calcPosition(prop, size) {
let { width, height } = this.getScreenSize();
// 1. 确定 anchor
// 2. 通过 align 确定初始位置
// 3. offset
// 返回左上角的位置
let anchor_coord = {
x: (width * ((prop.xalign ?? 0) + 1)) / 2 + // 根据 align 求出 anchor 位置
(prop.xoffset ?? 0), // offset
y: (height * ((prop.yalign ?? 0) + 1)) / 2 + // 根据 align 求出 anchor 位置
(prop.yoffset ?? 0), // offset
};
let origin_coord = {
x: anchor_coord.x - (((prop.xanchor ?? 0) + 1) / 2) * (size?.width ?? 0),
y: anchor_coord.y - (((prop.yanchor ?? 0) + 1) / 2) * (size?.height ?? 0),
};
return {
anchor: anchor_coord,
origin: origin_coord,
};
}
};
})();
export { UI };
(function (UI) {
class View {
layer;
core;
id = null;
name = null;
isSave = true;
_prop = null;
get prop() {
return this._prop;
}
set prop(prop) {
this._prop = prop;
}
constructor(layer, core) {
this.layer = layer;
this.core = core;
}
create(prop) {
this.prop = prop;
this.onCreate(prop);
}
commit(prop) {
this.prop = prop;
this.onCommit(prop);
}
destroy() {
this.onDestroy();
this.prop = null;
this.id = null;
}
serialize() {
if (this.name == null)
throw new Error("View name is null when serialize");
return {
name: this.name,
layer: this.layer,
prop: this.prop,
};
}
}
UI.View = View;
class MessageView extends View {
}
UI.MessageView = MessageView;
class MenuView extends View {
}
UI.MenuView = MenuView;
class FgImgView extends View {
}
UI.FgImgView = FgImgView;
class BgImgView extends View {
}
UI.BgImgView = BgImgView;
class Layer {
_core;
name;
z_index;
widgetFactory;
constructor(_core, name, z_index) {
this._core = _core;
this.name = name;
this.z_index = z_index;
// this.widgetFactory = hmUI.createWidget(
// (hmUI.widget as any).VIEW_CONTAINER,
// {
// scroll_enable: 0,
// z_index,
// }
// ) as unknown as Layer.WidgetFactory;
this.widgetFactory = _core.platform.createUILayer({
z_index,
});
}
destroy() {
// hmUI.deleteWidget(this.widgetFactory as any);
this._core.platform.deleteUILayer(this.widgetFactory);
}
}
UI.Layer = Layer;
class Router {
_ui;
tag;
layer;
isSave;
constructor(_ui, tag, layer, isSave = true) {
this._ui = _ui;
this.tag = tag;
this.layer = layer;
this.isSave = isSave;
}
serialize() {
return {
tag: this.tag,
layer: this.layer,
isSave: this.isSave,
viewStack: this.viewStack,
activeViewId: this.activeViewInstance?.id ?? null,
};
}
defaultRouteStrategy = {
destroy: (viewInstance, ui) => {
this._ui._core.debug.log(`destroy view ${viewInstance.name}`);
ui.destroyView(viewInstance);
},
create: (viewName, layer, prop, ui, isSave) => {
this._ui._core.debug.log(`create view ${viewName}`);
return ui.createView(viewName, layer, prop, isSave);
},
update: (viewInstance, prop, ui) => {
this._ui._core.debug.log(`update view ${viewInstance.name}`);
ui.updateView(viewInstance, prop);
},
};
static deserialize(ui, data) {
let router = new Router(ui, data.tag, data.layer, data.isSave);
router.viewStack = data.viewStack;
if (data.activeViewId != null) {
let viewInstance = ui.getView(data.activeViewId);
if (!viewInstance)
throw `View [${data.activeViewId}] not found when deserialize`;
router.activeViewInstance = viewInstance;
}
return router;
}
viewStack = [];
get length() {
return this.viewStack.length;
}
activeViewInstance = null;
push(view_name, prop, strategy) {
if (this.activeViewInstance) {
// this._ui.destroyView(this.activeViewInstance);
// (strategy?.destroy ?? this.defaultRouteStrategy.destroy!)(
// this.activeViewInstance,
// this._ui
// );
if (strategy?.destroy) {
strategy.destroy(this.activeViewInstance, this._ui);
}
else {
this.defaultRouteStrategy.destroy(this.activeViewInstance, this._ui);
}
this.activeViewInstance = null;
}
let layerInstance = this._ui.getLayer(this.layer);
if (!layerInstance)
throw `Layer [${this.layer}] not found`;
// this.activeViewInstance = (
// strategy?.create ?? this.defaultRouteStrategy.create!
// )(view_name, this.layer, prop, this._ui, this.isSave);
if (strategy?.create) {
this.activeViewInstance = strategy.create(view_name, this.layer, prop, this._ui, this.isSave);
}
else {
this.activeViewInstance = this.defaultRouteStrategy.create(view_name, this.layer, prop, this._ui, this.isSave);
}
this.viewStack.push([view_name, prop]);
}
pop(back_prop, strategy) {
if (this.activeViewInstance) {
// this._ui.destroyView(this.activeViewInstance);
// (strategy?.destroy ?? this.defaultRouteStrategy.destroy!)(
// this.activeViewInstance,
// this._ui
// );
if (strategy?.destroy) {
strategy.destroy(this.activeViewInstance, this._ui);
}
else {
this.defaultRouteStrategy.destroy(this.activeViewInstance, this._ui);
}
this.activeViewInstance = null;
}
this.viewStack.pop();
if (this.viewStack.length) {
let backViewInfo = this.viewStack[this.viewStack.length - 1];
let layerInstance = this._ui.getLayer(this.layer);
if (!layerInstance)
throw `Layer [${this.layer}] not found`;
// this.activeViewInstance = (
// strategy?.create ?? this.defaultRouteStrategy.create!
// )(
// backViewInfo[0],
// this.layer,
// back_prop ?? backViewInfo[1],
// this._ui,
// this.isSave
// );
if (strategy?.create) {
this.activeViewInstance = strategy.create(backViewInfo[0], this.layer, back_prop ?? backViewInfo[1], this._ui, this.isSave);
}
else {
this.activeViewInstance = this.defaultRouteStrategy.create(backViewInfo[0], this.layer, back_prop ?? backViewInfo[1], this._ui, this.isSave);
}
}
}
replace(view_name, prop, strategy) {
if (this.activeViewInstance) {
// this._ui.destroyView(this.activeViewInstance);
// (strategy?.destroy ?? this.defaultRouteStrategy.destroy!)(
// this.activeViewInstance,
// this._ui
// );
if (strategy?.destroy) {
strategy.destroy(this.activeViewInstance, this._ui);
}
else {
this.defaultRouteStrategy.destroy(this.activeViewInstance, this._ui);
}
this.activeViewInstance = null;
}
this.viewStack.pop();
let layerInstance = this._ui.getLayer(this.layer);
if (!layerInstance)
throw `Layer [${this.layer}] not found`;
// this.activeViewInstance = (
// strategy?.create ?? this.defaultRouteStrategy.create!
// )(view_name, this.layer, prop, this._ui, this.isSave);
if (strategy?.create) {
this.activeViewInstance = strategy.create(view_name, this.layer, prop, this._ui, this.isSave);
}
else {
this.activeViewInstance = this.defaultRouteStrategy.create(view_name, this.layer, prop, this._ui, this.isSave);
}
this.viewStack.push([view_name, prop]);
}
update(prop, strategy) {
if (!this.activeViewInstance)
throw `Update View but activeViewInstance is null`;
this.viewStack[this.viewStack.length - 1][1] = prop;
// (strategy?.update ?? this.defaultRouteStrategy.update!)(
// this.activeViewInstance,
// prop,
// this._ui
// );
if (strategy?.update) {
strategy.update(this.activeViewInstance, prop, this._ui);
}
else {
this.defaultRouteStrategy.update(this.activeViewInstance, prop, this._ui);
}
}
clear(strategy) {
if (this.activeViewInstance) {
// (strategy?.destroy ?? this.defaultRouteStrategy.destroy!)(
// this.activeViewInstance,
// this._ui
// );
if (strategy?.destroy) {
strategy.destroy(this.activeViewInstance, this._ui);
}
else {
this.defaultRouteStrategy.destroy(this.activeViewInstance, this._ui);
}
this.activeViewInstance = null;
}
this.viewStack = [];
}
}
UI.Router = Router;
})(UI || (UI = {}));