HumanBreak/src/core/main/custom/toolbar.ts

444 lines
13 KiB
TypeScript
Raw Normal View History

import { EventEmitter } from '@/core/common/eventEmitter';
2024-04-26 17:39:20 +08:00
import { deleteWith, has } from '@/plugin/utils';
import { Component, nextTick, reactive, shallowReactive } from 'vue';
2023-12-18 17:10:28 +08:00
import { fixedUi } from '../init/ui';
2024-02-02 21:01:13 +08:00
import { GameStorage } from '../storage';
2024-04-26 17:39:20 +08:00
import type {
CustomToolbarComponent,
MiscToolbar,
SettableItemData,
ToolbarItemBase,
ToolbarItemMap,
ToolbarItemType
} from '../init/toolbar';
2024-05-04 13:23:03 +08:00
import { isMobile } from '@/plugin/use';
2023-12-17 18:11:58 +08:00
interface CustomToolbarEvent {
2023-12-17 18:11:58 +08:00
add: (item: ValueOf<ToolbarItemMap>) => void;
delete: (item: ValueOf<ToolbarItemMap>) => void;
set: (id: string, data: Partial<SettableItemData>) => void;
emit: (id: string, item: ValueOf<ToolbarItemMap>) => void;
2024-02-02 21:01:13 +08:00
posChange: (bar: CustomToolbar) => void;
2023-12-17 18:11:58 +08:00
}
2024-02-02 21:01:13 +08:00
interface ToolbarSaveData {
x: number;
y: number;
w: number;
h: number;
items: ValueOf<ToolbarItemMap>[];
}
2024-01-19 22:09:48 +08:00
type ToolItemEmitFn<T extends ToolbarItemType> = (
this: CustomToolbar,
id: string,
item: ToolbarItemMap[T]
) => boolean;
2023-12-17 18:11:58 +08:00
2024-01-19 22:09:48 +08:00
interface RegisteredCustomToolInfo {
name: string;
onEmit: ToolItemEmitFn<ToolbarItemType>;
show: CustomToolbarComponent;
editor: CustomToolbarComponent;
onCreate: (item: any) => ToolbarItemBase<ToolbarItemType>;
}
2024-04-26 17:39:20 +08:00
type MiscEmitFn = (
id: string,
toolbar: CustomToolbar,
item: MiscToolbar
) => void;
type ActivedFn = (info: MiscInfo) => boolean;
interface MiscInfo {
id: string;
name: string;
emit: MiscEmitFn;
display: () => Component;
2024-04-26 17:39:20 +08:00
activable?: boolean;
actived?: ActivedFn;
}
interface Misc {
info: Record<string, MiscInfo>;
/**
*
* @param id id
* @param name
* @param emit
* @param display
* @param activable
*/
register(
this: Misc,
id: string,
name: string,
emit: MiscEmitFn,
display: () => Component
2024-04-26 17:39:20 +08:00
): void;
2024-11-18 23:27:28 +08:00
/**
*
* @param id id
* @param activable
* @param actived
*/
2024-04-26 17:39:20 +08:00
bindActivable(id: string, activable: boolean, actived?: ActivedFn): void;
/**
*
* @param id dragdrag杂项工具的工具栏
*/
requestRefresh(id?: string): void;
}
2023-12-17 18:11:58 +08:00
2024-02-02 21:01:13 +08:00
const toolbarStorage = new GameStorage<Record<string, ToolbarSaveData>>(
GameStorage.fromAuthor('AncTe', 'toolbar')
);
2024-04-26 17:39:20 +08:00
const misc: Misc = {
info: {},
register(id, name, emit, display) {
this.info[id] = { id, name, emit, display };
},
bindActivable(id, activable, actived) {
this.info[id].activable = activable;
this.info[id].actived = actived;
},
requestRefresh(id) {
if (id) {
CustomToolbar.list.forEach(v => {
if (
v.items.some(v => {
return v.type === 'misc' && v.items?.includes(id);
})
) {
v.refresh();
}
});
} else {
CustomToolbar.list.forEach(v => {
if (v.items.some(v => v.type === 'misc')) {
v.refresh();
}
});
}
}
};
2023-12-17 18:11:58 +08:00
export class CustomToolbar extends EventEmitter<CustomToolbarEvent> {
static num: number = 0;
static list: CustomToolbar[] = shallowReactive([]);
2024-01-19 22:09:48 +08:00
static info: Record<string, RegisteredCustomToolInfo> = {};
2023-12-17 18:11:58 +08:00
2024-04-26 17:39:20 +08:00
static misc: Misc = misc;
2023-12-17 18:11:58 +08:00
items: ValueOf<ToolbarItemMap>[] = reactive([]);
num: number = CustomToolbar.num++;
id: string;
// ----- size
x: number = 300;
y: number = 300;
width: number = 300;
2023-12-18 17:10:28 +08:00
height: number = 70;
2023-12-17 18:11:58 +08:00
// ----- other
assistKey: number = 0;
2024-01-19 22:09:48 +08:00
showIds: number[] = [];
2023-12-17 18:11:58 +08:00
2024-04-26 17:39:20 +08:00
constructor(id: string, noshow: boolean = false) {
2023-12-17 18:11:58 +08:00
super();
this.id = id;
2024-04-20 12:27:38 +08:00
// 按比例设置初始大小
const setting = Mota.require('var', 'mainSetting');
const scale = setting.getValue('ui.toolbarScale', 100) / 100;
this.width *= scale;
this.height *= scale;
this.x *= scale;
this.y *= scale;
2024-04-26 17:39:20 +08:00
if (!noshow) this.show();
2023-12-17 18:11:58 +08:00
CustomToolbar.list.push(this);
}
/**
*
* @param item
*/
2024-01-19 22:09:48 +08:00
add<K extends ToolbarItemType>(item: ToolbarItemMap[K]) {
const index = this.items.findIndex(v => v.id === item.id);
if (index !== -1) {
console.warn(`添加了id重复的自定义工具已将其覆盖`);
this.items[index] = item;
} else {
this.items.push(item);
}
this.emit('add', item);
2023-12-18 17:15:39 +08:00
return this;
2023-12-17 18:11:58 +08:00
}
/**
*
* @param id id
*/
delete(id: string) {
const index = this.items.findIndex(v => v.id === id);
if (index === -1) return;
const item = this.items[index];
this.items.splice(index, 1);
this.emit('delete', item);
2023-12-18 17:15:39 +08:00
return this;
2023-12-17 18:11:58 +08:00
}
/**
*
* @param id id
* @param item
*/
set<T extends ToolbarItemType>(
id: string,
item: Partial<SettableItemData<T>>
) {
const toSet = this.items.find(v => v.id === id);
if (!toSet) return;
Object.assign(toSet, item);
this.emit('set', id, item);
2023-12-18 17:15:39 +08:00
return this;
2023-12-17 18:11:58 +08:00
}
/**
*
* @param id id
*/
emitTool(id: string) {
const item = this.items.find(v => v.id === id);
2023-12-18 17:10:28 +08:00
if (!item) return this;
this.emit('emit', id, item);
2024-01-19 22:09:48 +08:00
const info = CustomToolbar.info[item.type];
if (!info) {
console.warn(`触发了未知的自定义工具类型:'${item.type}'`);
return this;
}
const success = info.onEmit.call(this, id, item);
if (!success) {
console.warn(`触发自定义工具失败id:'${id}',type:${item.type}`);
2023-12-17 18:11:58 +08:00
}
2023-12-18 17:10:28 +08:00
return this;
}
2024-01-19 22:09:48 +08:00
/**
*
*/
2024-04-20 12:27:38 +08:00
refresh(reopen: boolean = false) {
if (reopen && this.showIds.length > 0) {
this.closeAll();
nextTick(() => {
this.show();
});
} else {
const items = this.items.splice(0);
nextTick(() => {
this.items.push(...items);
});
}
2023-12-18 17:15:39 +08:00
return this;
2023-12-17 18:11:58 +08:00
}
setPos(x?: number, y?: number) {
has(x) && (this.x = x);
has(y) && (this.y = y);
2024-04-20 12:27:38 +08:00
this.emit('posChange', this);
2023-12-17 18:11:58 +08:00
}
setSize(width?: number, height?: number) {
has(width) && (this.width = width);
has(height) && (this.height = height);
2024-04-20 12:27:38 +08:00
this.emit('posChange', this);
2023-12-17 18:11:58 +08:00
}
2024-01-19 22:09:48 +08:00
/**
*
2024-04-26 17:39:20 +08:00
* @param multi
2024-01-19 22:09:48 +08:00
*/
2024-04-26 17:39:20 +08:00
show(multi: boolean = false) {
if (
!multi &&
this.showIds.some(v => fixedUi.stack.some(vv => vv.num === v))
) {
return -1;
}
2024-01-19 22:09:48 +08:00
const id = fixedUi.open('toolbar', { bar: this });
this.showIds.push(id);
return id;
}
/**
*
* @param id id
*/
close(id: number) {
fixedUi.close(id);
deleteWith(this.showIds, id);
}
/**
*
*/
closeAll() {
this.showIds.forEach(v => fixedUi.close(v));
2024-02-02 21:01:13 +08:00
this.showIds = [];
2023-12-18 17:10:28 +08:00
}
2023-12-17 18:11:58 +08:00
static get(id: string) {
return this.list.find(v => v.id === id);
}
2024-01-19 22:09:48 +08:00
/**
*
* @param type
* @param name
* @param onEmit
* @param show
* @param editor
* @param onCreate
*/
static register<K extends ToolbarItemType>(
type: K,
name: string,
onEmit: ToolItemEmitFn<K>,
show: CustomToolbarComponent<K>,
editor: CustomToolbarComponent<K>,
onCreate: (item: any) => ToolbarItemMap[K]
) {
if (type in this.info) {
console.warn(`已存在名为'${type}'的自定义工具类型,已将其覆盖!`);
}
const info: RegisteredCustomToolInfo = {
name,
onEmit: onEmit as ToolItemEmitFn<ToolbarItemType>,
show: show as CustomToolbarComponent,
editor: editor as CustomToolbarComponent,
// @ts-ignore
onCreate
};
this.info[type] = info;
}
2024-02-02 21:01:13 +08:00
static save() {
toolbarStorage.clear();
2024-04-20 12:27:38 +08:00
const setting = Mota.require('var', 'mainSetting');
const scale = setting.getValue('ui.toolbarScale', 100) / 100;
2024-02-02 21:01:13 +08:00
this.list.forEach(v => {
const toSave: ToolbarSaveData = {
x: v.x,
y: v.y,
2024-04-20 12:27:38 +08:00
w: v.width / scale,
h: v.height / scale,
2024-02-02 21:01:13 +08:00
items: []
};
v.items.forEach(v => {
toSave.items.push(v);
});
toolbarStorage.setValue(v.id, toSave);
});
toolbarStorage.write();
}
static load() {
toolbarStorage.read();
for (const [key, value] of Object.entries(toolbarStorage.data)) {
2024-04-20 12:27:38 +08:00
const bar = this.get(key) ?? new CustomToolbar(key);
2024-02-02 21:01:13 +08:00
bar.x = value.x;
bar.y = value.y;
bar.width = value.w;
bar.height = value.h;
for (const item of value.items) {
bar.add(item);
}
}
}
2024-04-20 12:27:38 +08:00
static refreshAll(reopen: boolean = false): void {
CustomToolbar.list.forEach(v => v.refresh(reopen));
}
2024-02-02 21:01:13 +08:00
static showAll(): number[] {
return CustomToolbar.list.map(v => v.show());
}
static closeAll() {
this.list.forEach(v => v.closeAll());
}
2023-12-17 18:11:58 +08:00
}
2023-12-18 17:10:28 +08:00
2024-02-02 21:01:13 +08:00
Mota.require('var', 'loading').once('coreInit', () => {
CustomToolbar.load();
CustomToolbar.closeAll();
2024-04-20 12:27:38 +08:00
window.addEventListener('beforeunload', e => {
CustomToolbar.save();
});
window.addEventListener('blur', () => {
CustomToolbar.save();
});
2024-02-02 21:01:13 +08:00
});
Mota.require('var', 'hook').on('reset', () => {
CustomToolbar.showAll();
});
2024-05-04 13:23:03 +08:00
Mota.require('var', 'hook').once('reset', () => {
const mainStorage = GameStorage.for(GameStorage.fromGame('main'));
mainStorage.read();
2024-11-19 22:39:23 +08:00
if (!mainStorage.getValue('played', false)) {
2024-05-04 13:23:03 +08:00
mainStorage.setValue('played', true);
2024-11-19 22:28:48 +08:00
let defaultsTool = CustomToolbar.list.find(v => v.id === '@defaults');
const hasDefaults = !!defaultsTool;
if (!defaultsTool) {
defaultsTool = new CustomToolbar('@defaults', true);
}
2024-05-04 13:23:03 +08:00
defaultsTool.closeAll();
defaultsTool.items = reactive([]);
defaultsTool.add({
id: '@defaults_misc',
type: 'misc',
folded: false,
noDefaultAction: true,
items: [
'book',
'fly',
'save',
'load',
'toolbox',
'equipbox',
'shop',
'virtualKey',
2024-05-04 14:35:06 +08:00
'setting',
'undo',
'redo',
'danmaku',
'minimap'
2024-05-04 13:23:03 +08:00
]
});
2024-11-19 22:28:48 +08:00
// 计算位置,显示在游戏画面下方
2024-11-19 22:39:23 +08:00
if (!hasDefaults) {
const game = core.dom.gameDraw;
const bottom = game.offsetTop + game.offsetHeight;
const left = game.offsetLeft;
const width = game.offsetWidth;
if (isMobile) {
// 手机端显示在最下方
defaultsTool.setPos(16, bottom);
defaultsTool.setSize(window.innerWidth - 32, 85);
} else {
// 电脑显示在屏幕右方
defaultsTool.setPos(left, bottom);
defaultsTool.setSize(width, 70);
}
}
2024-05-04 13:23:03 +08:00
defaultsTool.show();
CustomToolbar.save();
}
});