Files
Fishing2/FGUIProject/plugins/whoot-tween/TweenCoustomInspector.js
2026-02-04 18:55:28 +08:00

461 lines
19 KiB
JavaScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.CustomAttributer = void 0;
const csharp_1 = require("csharp");
const puerts_1 = require("puerts");
const index_1 = require("./index");
const App = csharp_1.FairyEditor.App;
// 动效设置(参考 LanguageSettings 的存储方式)
const TweenSettings_1 = require("./TweenSettings");
class CustomAttributer extends csharp_1.FairyEditor.View.PluginInspector {
list;
components = [];
pattern = "*";
parent = false;
textMode;
mode = index_1.EMode.WRITE;
modeCtr;
// private btn_save: FairyGUI.GButton;
// private btn_reset: FairyGUI.GButton;
customData = "";
customDataObj = {};
constructor(data) {
super();
this.panel = csharp_1.FairyGUI.UIPackage.CreateObject("TweenAttributer", "Main").asCom;
// this.panel.GetChild("btn_save").asButton.visible = false;
// this.panel.GetChild("btn_reset").asButton.visible = false;
// this.panel.GetChild("btn_copy").asButton.visible = false;
let { components, mode, pattern, parent } = data;
this.components = components;
this.pattern = pattern;
this.parent = parent;
this.list = this.panel.GetChild("list_components").asList;
//this.textMode = this.panel.GetChild("text_mode").asTextField;
this.mode = mode || index_1.EMode.WRITE; // todo
if (this.components.length > 0) {
this.list.numItems = 0;
}
this.modeCtr = this.panel.GetController("op");
// this.btn_save = this.panel.GetChild("btn_save").asButton;
// this.btn_save.onClick.Add(() => {
// this.setCustomData();
// })
// this.btn_reset = this.panel.GetChild("btn_reset").asButton;
// this.btn_reset.onClick.Add(() => {
// this.showList(true);
// })
this.updateAction = () => { return this.updateUI(); };
}
lastSelectedComponent = "";
lastData = "";
updateUI() {
let curDoc = App.activeDoc;
let { inspectingTarget } = curDoc;
let id = this.parent ? curDoc.docURL : inspectingTarget.id;
// 实时获取自定义数据
let propName = this.parent ? "remark" : "customData";
this.customData = inspectingTarget.GetProperty(propName);
try {
this.customDataObj = JSON.parse(this.customData) || {};
}
catch (e) {
// console.log("自定义数据异常或没有发现自定义数据,无法渲染列表");
this.customDataObj = {};
}
// 根据匹配规则验证是否显示inspector
// 正则 & 字符串 通配符
let name = this.parent ? curDoc.displayTitle : inspectingTarget.name;
let pattern = isMatch(name, this.pattern);
if ((pattern && this.lastSelectedComponent != id) || this.customData !== this.lastData) { // 判断是否满足条件的组件以及是上一次选中的组件或者数据是否被修改
this.showList();
}
this.lastData = this.customData;
this.lastSelectedComponent = id;
return pattern;
}
showList(reset = false) {
this.list.numItems = 0;
// todo
// if (this.mode == EMode.WRITE) {
// this.textMode.SetVar("mode", "设置").FlushVars();
// this.modeCtr.SetSelectedPage("write");
// } else {
// this.textMode.SetVar("mode", "读取").FlushVars();
// this.modeCtr.SetSelectedPage("read");
// }
// 根据自定义属性和配置文件混合比较【以自定义属性为主】渲染列表数据
for (let item of this.components) {
let { type, name, id, key } = item;
let com = getComponent(type);
if (!key) {
console.log("未定义唯一keyID", id);
return;
}
if (!com) {
console.log("发现未定义扩展组件ID", id);
}
com.title = name || key;
const component = com.GetChild("component");
com.name = key;
this.renderItem(component, item, reset);
// 监听组件变更并保存到 json参考 LanguageCustomInspector 的做法)
this.bindPersistEvents(component, item);
this.list.AddChild(com);
}
this.list.ResizeToFit();
// 更新关联关系
for (let item of this.components) {
let { associate, key } = item;
// 找到关联组件
let associateCom, curCom;
for (let i = 0; i < this.list.numChildren; i++) {
let com = this.list.GetChildAt(i);
if (com.name == associate) {
associateCom = com;
}
if (com.name == key) {
curCom = com;
}
}
if (associateCom && !associateCom.GetChild("component").selected && curCom) {
this.list.RemoveChild(curCom);
}
}
}
/**
* 给渲染出来的控件绑定事件:
* -已暂时停用更新自定义属性SetProperty
* - 将动效设置保存到项目设置目录下的 jsonwhootTween/<package>.json
*/
bindPersistEvents(component, item) {
const persist = () => {
// 暂时不写回到自定义数据,仅保存到 json
// this.setCustomData();
// 将与动效相关的设置保存到 json
this.trySaveTweenSetting(item, component);
};
// 根据控件类型选择合适的触发时机
if (component instanceof csharp_1.FairyGUI.GComboBox) {
component.onChanged.Add(persist);
}
else if (component instanceof csharp_1.FairyEditor.Component.NumericInput) {
// 数字输入使用失焦触发
component.onFocusOut.Add(persist);
}
else if (component instanceof csharp_1.FairyGUI.GSlider) {
component.onChanged.Add(persist);
}
else if (component instanceof csharp_1.FairyGUI.GButton) { // SWITCH / RADIOBOX
component.onChanged.Add(persist);
}
else if (component instanceof csharp_1.FairyEditor.Component.ColorInput) {
component.onChanged.Add(persist);
}
else if (component instanceof csharp_1.FairyGUI.GLabel) { // 文本输入类:失焦时保存
component.onFocusOut.Add(persist);
}
}
/**
* 将与动效相关的设置保存到 json 文件。
* 规则:
* - 仅对下拉框ComboBox做持久化其 value 代表动效 key
* - 当选中值为 "null" 视为未启用useable=false否则为启用
*/
trySaveTweenSetting(item, component) {
try {
if (!(component instanceof csharp_1.FairyGUI.GComboBox))
return;
// 读取当前对象与文档信息
let sels = App.activeDoc.inspectingTargets;
let obj = sels.get_Item(0);
let activeDoc = App.activeDoc;
let packageName = activeDoc.packageItem.owner.name;
let docUrl = activeDoc.docURL;
let objId = obj.id;
// 父级组件通常没有有效的 id这里为父级使用文档级占位 id
if ((!objId || objId === "") && this.parent) {
objId = "__root__";
}
// 当前选择的动效 key
const selectedIndex = component.selectedIndex;
const selectedValue = component.values?.get_Item(selectedIndex);
// 条件:无(值为"null"或组件ID为空非父级场景不记录
if ((!objId || objId === "") && !this.parent)
return;
if (selectedValue == null)
return;
if (selectedValue === "null") {
// 选择“无”时,删除已存在的记录
TweenSettings_1.default.remove(packageName, docUrl, objId);
return;
}
const useable = true; // 只有有效选择才记录,直接标记为可用
// 保存到 whootTween/<package>.json
TweenSettings_1.default.update(packageName, docUrl, objId, selectedValue, useable);
// 保存后做一次清理:把已删除的组件从 json 中移除
this.cleanupDeletedComponents(packageName, docUrl);
}
catch (e) {
console.error("保存动效设置到 json 失败:", e);
}
}
/**
* 收集当前文档中仍然存在的组件ID递归并触发清理
*/
cleanupDeletedComponents(packageName, docUrl) {
try {
const ids = [];
const visited = {};
const collect = (node) => {
if (!node)
return;
const nid = node.id;
if (nid && !visited[nid]) {
visited[nid] = true;
ids.push(nid);
}
if (node instanceof csharp_1.FairyEditor.FComponent) {
const cnt = node.numChildren;
for (let i = 0; i < cnt; i++) {
const child = node.GetChildAt(i);
collect(child);
}
}
};
const activeDoc = App.activeDoc;
if (activeDoc && activeDoc.content) {
collect(activeDoc.content);
}
// 仅当有 id 列表时尝试清理(保留 __root__
TweenSettings_1.default.cleanupDoc(packageName, docUrl, ids);
}
catch (err) {
console.error('清理已删除组件记录失败', err);
}
}
renderItem(component, item, reset) {
let { value, key } = item;
if (!reset) {
let defaultVal = this.getValueByName(key);
value = defaultVal != undefined ? defaultVal : value;
}
// 下拉框
if (component instanceof csharp_1.FairyGUI.GComboBox && item.type == index_1.EComponent.COMBOBOX) {
let data = item.data;
let valueArr = csharp_1.System.Array.CreateInstance((0, puerts_1.$typeof)(csharp_1.System.String), data.values.length);
for (let i = 0; i < data.values.length; i++) {
let v = data.values[i];
valueArr.set_Item(i, v);
}
let itemArr = csharp_1.System.Array.CreateInstance((0, puerts_1.$typeof)(csharp_1.System.String), data.items.length);
for (let i = 0; i < data.items.length; i++) {
let v = data.items[i];
itemArr.set_Item(i, v);
}
component.items = itemArr;
component.values = valueArr;
// 优先使用外部配置TweenSettings进行回填
const extVal = this.getExternalTweenKey();
if (extVal && data.values.indexOf(extVal) >= 0) {
component.value = extVal;
}
else {
// 兼容customData 可能保存的是值字符串或索引
if (typeof value === 'string' && data.values.indexOf(value) >= 0) {
component.value = value;
}
else {
const idx = Number(value);
const finalIdx = isNaN(idx) ? 0 : idx;
component.value = data.values[finalIdx] ?? data.values[0];
}
}
}
else if (component instanceof csharp_1.FairyGUI.GLabel &&
(item.type == index_1.EComponent.TEXTINPUT ||
item.type == index_1.EComponent.TEXTAREA ||
item.type == index_1.EComponent.RESOURCEINPUT)) { // 文本输入框
component.title = value + "" || "";
}
else if (item.type == index_1.EComponent.COLORINPUT && component instanceof csharp_1.FairyEditor.Component.ColorInput) { // 颜色输入框
let colorValue = value + "" || "#000000";
component.colorValue = csharp_1.FairyEditor.ColorUtil.FromHexString(colorValue);
}
else if (component instanceof csharp_1.FairyGUI.GSlider && item.type == index_1.EComponent.SLIDER) { // 滑动块
let data = item.data;
component.min = +data.min || 0;
component.max = +data.max || 100;
component.value = +value || 0;
}
else if (component instanceof csharp_1.FairyEditor.Component.NumericInput && item.type == index_1.EComponent.NUMBERINPUT) { // 数字输入框
let data = item.data;
component.min = +data.min || 0;
component.max = +data.max || 100;
component.step = +data.step || 0;
component.value = +value || 0;
}
else if (component instanceof csharp_1.FairyGUI.GButton && item.type == index_1.EComponent.SWITCH) { // 切换器
component.selected = Boolean(value);
}
else if (component instanceof csharp_1.FairyGUI.GButton && item.type == index_1.EComponent.RADIOBOX) { // 单选框
let data = item.data;
component.GetChildAt(0).text = data.items[0];
component.GetChildAt(1).text = data.items[1];
component.selected = Boolean(value);
}
}
/**
* 读取当前对象在 TweenSettings 中的外部配置 key
*/
getExternalTweenKey() {
try {
let sels = App.activeDoc.inspectingTargets;
// puerts 映射的 IList$1 没有 Count 属性,这里直接尝试取第 0 项
if (!sels)
return null;
let obj = sels.get_Item(0);
let activeDoc = App.activeDoc;
let packageName = activeDoc.packageItem.owner.name;
let docUrl = activeDoc.docURL;
let objId = obj.id;
if ((!objId || objId === "") && this.parent) {
objId = "__root__";
}
let data = TweenSettings_1.default.get(packageName, docUrl, objId);
if (data && data.useable == 1 && data.key) {
return data.key;
}
}
catch (e) {
console.error('读取 TweenSettings 外部配置失败', e);
}
return null;
}
getListItemVal() {
for (let i = 0; i < this.list.numChildren; i++) {
let item = this.list.GetChildAt(i);
let component = item.GetChild("component");
let value = component.title;
if (component instanceof csharp_1.FairyEditor.Component.ColorInput) {
value = csharp_1.FairyEditor.ColorUtil.ToHexString(component.colorValue);
}
else if (component instanceof csharp_1.FairyGUI.GComboBox) {
// value = component.selectedIndex;
value = component.values.get_Item(component.selectedIndex);
}
else if (component instanceof csharp_1.FairyEditor.Component.NumericInput) {
value = component.value;
}
else if (this.components[i].type == index_1.EComponent.SWITCH) {
value = component.selected;
}
else if (this.components[i].type == index_1.EComponent.RADIOBOX) {
value = component.selected ? 1 : 0;
}
else if (this.components[i].type == index_1.EComponent.SLIDER) {
value = component.value;
}
let key = this.components[i].key;
if (this.customDataObj) {
this.customDataObj[key] = value;
}
}
return JSON.stringify(this.customDataObj) || "";
}
getValueByName(name) {
// let value = "";
// if (this.customDataObj?.[name]) {
// value = this.customDataObj[name];
// }
// return value;
return this.customDataObj[name];
}
setCustomData() {
let propName = this.parent ? "remark" : "customData";
let data = this.getListItemVal();
App.activeDoc.inspectingTarget.docElement.SetProperty(propName, data);
}
}
exports.CustomAttributer = CustomAttributer;
let isCharacterMatch = (s, p) => {
let dp = [];
for (let i = 0; i <= s.length; i++) {
let child = [];
for (let j = 0; j <= p.length; j++) {
child.push(false);
}
dp.push(child);
}
dp[s.length][p.length] = true;
for (let i = p.length - 1; i >= 0; i--) {
if (p[i] != "*")
break;
else
dp[s.length][i] = true;
}
for (let i = s.length - 1; i >= 0; i--) {
for (let j = p.length - 1; j >= 0; j--) {
if (s[i] == p[j] || p[j] == "?") {
dp[i][j] = dp[i + 1][j + 1];
}
else if (p[j] == "*") {
dp[i][j] = dp[i + 1][j] || dp[i][j + 1];
}
else {
dp[i][j] = false;
}
}
}
return dp[0][0];
};
let isRegMatch = (source, pattern) => {
const patt = new RegExp(pattern);
return patt.test(source);
};
let isMatch = (source, pattern) => {
if (pattern.includes("*") || pattern.includes("?")) {
return isCharacterMatch(source, pattern);
}
else if (pattern.includes("/")) {
return isRegMatch(source, pattern);
}
else {
return source.includes(pattern);
}
};
let getComponent = (componentType) => {
let component;
switch (componentType) {
case index_1.EComponent.TEXTINPUT:
component = csharp_1.FairyGUI.UIPackage.CreateObject("TweenAttributer", index_1.EComponent.TEXTINPUT).asCom;
break;
case index_1.EComponent.TEXTAREA:
component = csharp_1.FairyGUI.UIPackage.CreateObject("TweenAttributer", index_1.EComponent.TEXTAREA).asCom;
break;
case index_1.EComponent.COMBOBOX:
component = csharp_1.FairyGUI.UIPackage.CreateObject("TweenAttributer", index_1.EComponent.COMBOBOX).asCom;
break;
case index_1.EComponent.COLORINPUT:
component = csharp_1.FairyGUI.UIPackage.CreateObject("TweenAttributer", index_1.EComponent.COLORINPUT).asCom;
break;
case index_1.EComponent.NUMBERINPUT:
component = csharp_1.FairyGUI.UIPackage.CreateObject("TweenAttributer", index_1.EComponent.NUMBERINPUT).asCom;
break;
case index_1.EComponent.RESOURCEINPUT:
component = csharp_1.FairyGUI.UIPackage.CreateObject("TweenAttributer", index_1.EComponent.RESOURCEINPUT).asCom;
break;
case index_1.EComponent.SLIDER:
component = csharp_1.FairyGUI.UIPackage.CreateObject("TweenAttributer", index_1.EComponent.SLIDER).asCom;
break;
case index_1.EComponent.RADIOBOX:
component = csharp_1.FairyGUI.UIPackage.CreateObject("TweenAttributer", index_1.EComponent.RADIOBOX).asCom;
break;
case index_1.EComponent.SWITCH:
component = csharp_1.FairyGUI.UIPackage.CreateObject("TweenAttributer", index_1.EComponent.SWITCH).asCom;
break;
default:
break;
}
return component;
};