mirror of
https://github.com/unanmed/HumanBreak.git
synced 2025-02-28 17:37:07 +08:00
feat: 自定义状态栏的编辑
This commit is contained in:
parent
1e341fb63e
commit
ad2cb0b757
1
components.d.ts
vendored
1
components.d.ts
vendored
@ -9,6 +9,7 @@ declare module '@vue/runtime-core' {
|
|||||||
export interface GlobalComponents {
|
export interface GlobalComponents {
|
||||||
AButton: typeof import('ant-design-vue/es')['Button']
|
AButton: typeof import('ant-design-vue/es')['Button']
|
||||||
ADivider: typeof import('ant-design-vue/es')['Divider']
|
ADivider: typeof import('ant-design-vue/es')['Divider']
|
||||||
|
AInput: typeof import('ant-design-vue/es')['Input']
|
||||||
AInputNumber: typeof import('ant-design-vue/es')['InputNumber']
|
AInputNumber: typeof import('ant-design-vue/es')['InputNumber']
|
||||||
AProgress: typeof import('ant-design-vue/es')['Progress']
|
AProgress: typeof import('ant-design-vue/es')['Progress']
|
||||||
ASelect: typeof import('ant-design-vue/es')['Select']
|
ASelect: typeof import('ant-design-vue/es')['Select']
|
||||||
|
11
src/App.vue
11
src/App.vue
@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<div id="ui-new">
|
<div id="ui">
|
||||||
<div id="ui-main">
|
<div id="ui-main">
|
||||||
<div id="ui-list">
|
<div id="ui-list">
|
||||||
<div class="ui-one" v-for="(ui, index) of mainUi.stack">
|
<div class="ui-one" v-for="(ui, index) of mainUi.stack">
|
||||||
@ -41,14 +41,6 @@ function show(index: number) {
|
|||||||
|
|
||||||
<style lang="less" scoped>
|
<style lang="less" scoped>
|
||||||
#ui {
|
#ui {
|
||||||
width: 90%;
|
|
||||||
height: 90%;
|
|
||||||
display: flex;
|
|
||||||
justify-content: center;
|
|
||||||
overflow: hidden;
|
|
||||||
}
|
|
||||||
|
|
||||||
#ui-new {
|
|
||||||
width: 0;
|
width: 0;
|
||||||
height: 0;
|
height: 0;
|
||||||
left: 0;
|
left: 0;
|
||||||
@ -56,6 +48,7 @@ function show(index: number) {
|
|||||||
position: fixed;
|
position: fixed;
|
||||||
overflow: visible;
|
overflow: visible;
|
||||||
display: block;
|
display: block;
|
||||||
|
font-family: 'normal';
|
||||||
}
|
}
|
||||||
|
|
||||||
#ui-main {
|
#ui-main {
|
||||||
|
@ -93,8 +93,8 @@ export class Keyboard extends EventEmitter<VirtualKeyboardEvent> {
|
|||||||
* @param assist 辅助按键
|
* @param assist 辅助按键
|
||||||
*/
|
*/
|
||||||
withAssist(assist: number) {
|
withAssist(assist: number) {
|
||||||
this.assist = assist;
|
|
||||||
const symbol = this.createScope();
|
const symbol = this.createScope();
|
||||||
|
this.assist = assist;
|
||||||
return symbol;
|
return symbol;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import { EmitableEvent, EventEmitter } from '@/core/common/eventEmitter';
|
import { EmitableEvent, EventEmitter } from '@/core/common/eventEmitter';
|
||||||
import { KeyCode } from '@/plugin/keyCodes';
|
import { KeyCode } from '@/plugin/keyCodes';
|
||||||
import { flipBinary, has } from '@/plugin/utils';
|
import { deleteWith, flipBinary, has } from '@/plugin/utils';
|
||||||
import {
|
import {
|
||||||
FunctionalComponent,
|
FunctionalComponent,
|
||||||
markRaw,
|
markRaw,
|
||||||
@ -8,7 +8,10 @@ import {
|
|||||||
reactive,
|
reactive,
|
||||||
shallowReactive
|
shallowReactive
|
||||||
} from 'vue';
|
} from 'vue';
|
||||||
import { createToolbarComponents } from '../init/toolbar';
|
import {
|
||||||
|
createToolbarComponents,
|
||||||
|
createToolbarEditorComponents
|
||||||
|
} from '../init/toolbar';
|
||||||
import { gameKey } from '../init/hotkey';
|
import { gameKey } from '../init/hotkey';
|
||||||
import { unwarpBinary } from './hotkey';
|
import { unwarpBinary } from './hotkey';
|
||||||
import { fixedUi } from '../init/ui';
|
import { fixedUi } from '../init/ui';
|
||||||
@ -24,7 +27,6 @@ interface CustomToolbarEvent extends EmitableEvent {
|
|||||||
interface ToolbarItemBase<T extends ToolbarItemType> {
|
interface ToolbarItemBase<T extends ToolbarItemType> {
|
||||||
type: T;
|
type: T;
|
||||||
id: string;
|
id: string;
|
||||||
com: CustomToolbarComponent<T>;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 快捷键
|
// 快捷键
|
||||||
@ -49,7 +51,7 @@ interface ToolbarItemMap {
|
|||||||
assistKey: AssistKeyToolbarItem;
|
assistKey: AssistKeyToolbarItem;
|
||||||
}
|
}
|
||||||
|
|
||||||
type ToolbarItemType = keyof ToolbarItemMap;
|
export type ToolbarItemType = keyof ToolbarItemMap;
|
||||||
|
|
||||||
export type SettableItemData<T extends ToolbarItemType = ToolbarItemType> =
|
export type SettableItemData<T extends ToolbarItemType = ToolbarItemType> =
|
||||||
Omit<ToolbarItemMap[T], 'id' | 'type'>;
|
Omit<ToolbarItemMap[T], 'id' | 'type'>;
|
||||||
@ -64,19 +66,27 @@ export type CustomToolbarComponent<
|
|||||||
T extends ToolbarItemType = ToolbarItemType
|
T extends ToolbarItemType = ToolbarItemType
|
||||||
> = FunctionalComponent<CustomToolbarProps<T>>;
|
> = FunctionalComponent<CustomToolbarProps<T>>;
|
||||||
|
|
||||||
const COM = createToolbarComponents();
|
type ToolItemEmitFn<T extends ToolbarItemType> = (
|
||||||
|
this: CustomToolbar,
|
||||||
|
id: string,
|
||||||
|
item: ToolbarItemMap[T]
|
||||||
|
) => boolean;
|
||||||
|
|
||||||
const comMap: {
|
interface RegisteredCustomToolInfo {
|
||||||
[P in ToolbarItemType]: CustomToolbarComponent<P>;
|
name: string;
|
||||||
} = {
|
onEmit: ToolItemEmitFn<ToolbarItemType>;
|
||||||
hotkey: COM.KeyTool,
|
show: CustomToolbarComponent;
|
||||||
item: COM.ItemTool,
|
editor: CustomToolbarComponent;
|
||||||
assistKey: COM.AssistKeyTool
|
onCreate: (item: any) => ToolbarItemBase<ToolbarItemType>;
|
||||||
};
|
}
|
||||||
|
|
||||||
|
const COM = createToolbarComponents();
|
||||||
|
const EDITOR = createToolbarEditorComponents();
|
||||||
|
|
||||||
export class CustomToolbar extends EventEmitter<CustomToolbarEvent> {
|
export class CustomToolbar extends EventEmitter<CustomToolbarEvent> {
|
||||||
static num: number = 0;
|
static num: number = 0;
|
||||||
static list: CustomToolbar[] = shallowReactive([]);
|
static list: CustomToolbar[] = shallowReactive([]);
|
||||||
|
static info: Record<string, RegisteredCustomToolInfo> = {};
|
||||||
|
|
||||||
items: ValueOf<ToolbarItemMap>[] = reactive([]);
|
items: ValueOf<ToolbarItemMap>[] = reactive([]);
|
||||||
num: number = CustomToolbar.num++;
|
num: number = CustomToolbar.num++;
|
||||||
@ -88,6 +98,7 @@ export class CustomToolbar extends EventEmitter<CustomToolbarEvent> {
|
|||||||
height: number = 70;
|
height: number = 70;
|
||||||
// ----- other
|
// ----- other
|
||||||
assistKey: number = 0;
|
assistKey: number = 0;
|
||||||
|
showIds: number[] = [];
|
||||||
|
|
||||||
constructor(id: string) {
|
constructor(id: string) {
|
||||||
super();
|
super();
|
||||||
@ -100,14 +111,15 @@ export class CustomToolbar extends EventEmitter<CustomToolbarEvent> {
|
|||||||
* 添加一个自定义项
|
* 添加一个自定义项
|
||||||
* @param item 要添加的自定义工具栏项
|
* @param item 要添加的自定义工具栏项
|
||||||
*/
|
*/
|
||||||
add<K extends ToolbarItemType>(item: Omit<ToolbarItemMap[K], 'com'>) {
|
add<K extends ToolbarItemType>(item: ToolbarItemMap[K]) {
|
||||||
// @ts-ignore
|
const index = this.items.findIndex(v => v.id === item.id);
|
||||||
const data: ToolbarItemMap[K] = {
|
if (index !== -1) {
|
||||||
com: markRaw(comMap[item.type]),
|
console.warn(`添加了id重复的自定义工具,已将其覆盖`);
|
||||||
...item
|
this.items[index] = item;
|
||||||
} as ToolbarItemMap[K];
|
} else {
|
||||||
this.items.push(data);
|
this.items.push(item);
|
||||||
this.emit('add', data);
|
}
|
||||||
|
this.emit('add', item);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -148,34 +160,21 @@ export class CustomToolbar extends EventEmitter<CustomToolbarEvent> {
|
|||||||
const item = this.items.find(v => v.id === id);
|
const item = this.items.find(v => v.id === id);
|
||||||
if (!item) return this;
|
if (!item) return this;
|
||||||
this.emit('emit', id, item);
|
this.emit('emit', id, item);
|
||||||
if (item.type === 'hotkey') {
|
const info = CustomToolbar.info[item.type];
|
||||||
// 按键
|
if (!info) {
|
||||||
const assist = item.assist | this.assistKey;
|
console.warn(`触发了未知的自定义工具类型:'${item.type}'`);
|
||||||
const { ctrl, shift, alt } = unwarpBinary(assist);
|
return this;
|
||||||
const ev = new KeyboardEvent('keyup', {
|
|
||||||
ctrlKey: ctrl,
|
|
||||||
shiftKey: shift,
|
|
||||||
altKey: alt
|
|
||||||
});
|
|
||||||
|
|
||||||
// todo: Advanced KeyboardEvent simulate
|
|
||||||
gameKey.emitKey(item.key, assist, 'up', ev);
|
|
||||||
} else if (item.type === 'item') {
|
|
||||||
// 道具
|
|
||||||
core.tryUseItem(item.item);
|
|
||||||
} else if (item.type === 'assistKey') {
|
|
||||||
// 辅助按键
|
|
||||||
if (item.assist === KeyCode.Ctrl) {
|
|
||||||
this.assistKey = flipBinary(this.assistKey, 0);
|
|
||||||
} else if (item.assist === KeyCode.Shift) {
|
|
||||||
this.assistKey = flipBinary(this.assistKey, 1);
|
|
||||||
} else if (item.assist === KeyCode.Alt) {
|
|
||||||
this.assistKey = flipBinary(this.assistKey, 2);
|
|
||||||
}
|
}
|
||||||
|
const success = info.onEmit.call(this, id, item);
|
||||||
|
if (!success) {
|
||||||
|
console.warn(`触发自定义工具失败,id:'${id}',type:${item.type}`);
|
||||||
}
|
}
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 强制刷新这个自定义工具栏的所有显示
|
||||||
|
*/
|
||||||
refresh() {
|
refresh() {
|
||||||
const items = this.items.splice(0);
|
const items = this.items.splice(0);
|
||||||
nextTick(() => {
|
nextTick(() => {
|
||||||
@ -194,14 +193,134 @@ export class CustomToolbar extends EventEmitter<CustomToolbarEvent> {
|
|||||||
has(height) && (this.height = height);
|
has(height) && (this.height = height);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 显示这个自定义工具栏,可以显示多个,且内容互通
|
||||||
|
*/
|
||||||
show() {
|
show() {
|
||||||
fixedUi.open('toolbar', { bar: this });
|
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));
|
||||||
}
|
}
|
||||||
|
|
||||||
static get(id: string) {
|
static get(id: string) {
|
||||||
return this.list.find(v => v.id === id);
|
return this.list.find(v => v.id === id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 注册一类自定义工具
|
||||||
|
* @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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
CustomToolbar.register(
|
||||||
|
'hotkey',
|
||||||
|
'快捷键',
|
||||||
|
function (id, item) {
|
||||||
|
// 按键
|
||||||
|
const assist = item.assist | this.assistKey;
|
||||||
|
const { ctrl, shift, alt } = unwarpBinary(assist);
|
||||||
|
const ev = new KeyboardEvent('keyup', {
|
||||||
|
ctrlKey: ctrl,
|
||||||
|
shiftKey: shift,
|
||||||
|
altKey: alt
|
||||||
|
});
|
||||||
|
|
||||||
|
// todo: Advanced KeyboardEvent simulate
|
||||||
|
gameKey.emitKey(item.key, assist, 'up', ev);
|
||||||
|
return true;
|
||||||
|
},
|
||||||
|
COM.KeyTool,
|
||||||
|
EDITOR.KeyTool,
|
||||||
|
item => {
|
||||||
|
return {
|
||||||
|
key: KeyCode.Unknown,
|
||||||
|
assist: 0,
|
||||||
|
...item
|
||||||
|
};
|
||||||
|
}
|
||||||
|
);
|
||||||
|
CustomToolbar.register(
|
||||||
|
'item',
|
||||||
|
'使用道具',
|
||||||
|
function (id, item) {
|
||||||
|
// 道具
|
||||||
|
core.tryUseItem(item.item);
|
||||||
|
return true;
|
||||||
|
},
|
||||||
|
COM.ItemTool,
|
||||||
|
EDITOR.ItemTool,
|
||||||
|
item => {
|
||||||
|
return {
|
||||||
|
item: 'book',
|
||||||
|
...item
|
||||||
|
};
|
||||||
|
}
|
||||||
|
);
|
||||||
|
CustomToolbar.register(
|
||||||
|
'assistKey',
|
||||||
|
'辅助按键',
|
||||||
|
function (id, item) {
|
||||||
|
// 辅助按键
|
||||||
|
if (item.assist === KeyCode.Ctrl) {
|
||||||
|
this.assistKey = flipBinary(this.assistKey, 0);
|
||||||
|
} else if (item.assist === KeyCode.Shift) {
|
||||||
|
this.assistKey = flipBinary(this.assistKey, 1);
|
||||||
|
} else if (item.assist === KeyCode.Alt) {
|
||||||
|
this.assistKey = flipBinary(this.assistKey, 2);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
},
|
||||||
|
COM.AssistKeyTool,
|
||||||
|
EDITOR.AssistKeyTool,
|
||||||
|
item => {
|
||||||
|
return {
|
||||||
|
assist: KeyCode.Ctrl,
|
||||||
|
...item
|
||||||
|
};
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
hook.once('reset', () => {
|
hook.once('reset', () => {
|
||||||
const toolbar = new CustomToolbar('test');
|
const toolbar = new CustomToolbar('test');
|
||||||
|
@ -1,10 +1,13 @@
|
|||||||
import { KeyCodeUtils } from '@/plugin/keyCodes';
|
import { KeyCode, KeyCodeUtils } from '@/plugin/keyCodes';
|
||||||
import type {
|
import type {
|
||||||
CustomToolbarComponent,
|
CustomToolbarComponent,
|
||||||
CustomToolbarProps
|
CustomToolbarProps
|
||||||
} from '../custom/toolbar';
|
} from '../custom/toolbar';
|
||||||
import BoxAnimate from '@/components/boxAnimate.vue';
|
import BoxAnimate from '@/components/boxAnimate.vue';
|
||||||
import { checkAssist } from '../custom/hotkey';
|
import { checkAssist } from '../custom/hotkey';
|
||||||
|
import { getVitualKeyOnce } from '@/plugin/utils';
|
||||||
|
import { cloneDeep } from 'lodash-es';
|
||||||
|
import { Select, SelectOption } from 'ant-design-vue';
|
||||||
|
|
||||||
// todo: 新增更改设置的ToolItem
|
// todo: 新增更改设置的ToolItem
|
||||||
|
|
||||||
@ -25,6 +28,16 @@ export function createToolbarComponents() {
|
|||||||
return com;
|
return com;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function createToolbarEditorComponents() {
|
||||||
|
const com: Components = {
|
||||||
|
DefaultTool: DefaultToolEditor,
|
||||||
|
KeyTool: KeyToolEdtior,
|
||||||
|
ItemTool: ItemToolEditor,
|
||||||
|
AssistKeyTool: AssistKeyToolEditor
|
||||||
|
};
|
||||||
|
return com;
|
||||||
|
}
|
||||||
|
|
||||||
function DefaultTool(props: CustomToolbarProps) {
|
function DefaultTool(props: CustomToolbarProps) {
|
||||||
return <span>未知工具</span>;
|
return <span>未知工具</span>;
|
||||||
}
|
}
|
||||||
@ -70,3 +83,123 @@ function AssistKeyTool(props: CustomToolbarProps<'assistKey'>) {
|
|||||||
</span>
|
</span>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function DefaultToolEditor(props: CustomToolbarProps) {
|
||||||
|
return <span></span>;
|
||||||
|
}
|
||||||
|
|
||||||
|
function KeyToolEdtior(props: CustomToolbarProps<'hotkey'>) {
|
||||||
|
const { item, toolbar } = props;
|
||||||
|
|
||||||
|
const getKey = async () => {
|
||||||
|
const { key, assist } = await getVitualKeyOnce(false, item.assist);
|
||||||
|
toolbar.set<'hotkey'>(item.id, {
|
||||||
|
key,
|
||||||
|
assist
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const unwarpAssist = (assist: number) => {
|
||||||
|
let res = '';
|
||||||
|
if (assist & (1 << 0)) {
|
||||||
|
res += 'Ctrl + ';
|
||||||
|
}
|
||||||
|
if (assist & (1 << 1)) {
|
||||||
|
res += 'Shift + ';
|
||||||
|
}
|
||||||
|
if (assist & (1 << 2)) {
|
||||||
|
res += 'Alt + ';
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
};
|
||||||
|
|
||||||
|
const getKeyShow = (key: KeyCode, assist: number) => {
|
||||||
|
return (
|
||||||
|
unwarpAssist(assist) +
|
||||||
|
(key === KeyCode.Unknown ? '' : KeyCodeUtils.toString(key))
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
style="
|
||||||
|
display: flex; flex-direction: row; justify-content: space-between;
|
||||||
|
align-items: center; padding: 0 5%; margin: 1%
|
||||||
|
"
|
||||||
|
>
|
||||||
|
<span>触发按键</span>
|
||||||
|
<span
|
||||||
|
style="background-color: #000; width: 50%; text-align: end; padding: 0 5%"
|
||||||
|
onClick={getKey}
|
||||||
|
>
|
||||||
|
{getKeyShow(item.key, item.assist)}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function ItemToolEditor(props: CustomToolbarProps<'item'>) {
|
||||||
|
const { item, toolbar } = props;
|
||||||
|
|
||||||
|
const items = cloneDeep(core.status.hero.items.constants);
|
||||||
|
Object.assign(items, core.status.hero.items.tools);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
style="
|
||||||
|
display: flex; flex-direction: row; justify-content: space-between;
|
||||||
|
align-items: center; padding: 0 5%; margin: 1%
|
||||||
|
"
|
||||||
|
>
|
||||||
|
<span>使用道具</span>
|
||||||
|
<Select
|
||||||
|
style="width: 180px; font-size: 80%; height: 100%; background-color: #000"
|
||||||
|
value={item.item}
|
||||||
|
onChange={value =>
|
||||||
|
toolbar.set<'item'>(item.id, {
|
||||||
|
item: value as ItemIdOf<'tools' | 'constants'>
|
||||||
|
})
|
||||||
|
}
|
||||||
|
>
|
||||||
|
{Object.entries(items).map(v => {
|
||||||
|
return (
|
||||||
|
<SelectOption value={v[0]}>
|
||||||
|
{
|
||||||
|
core.material.items[v[0] as AllIdsOf<'items'>]
|
||||||
|
.name
|
||||||
|
}
|
||||||
|
</SelectOption>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</Select>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function AssistKeyToolEditor(props: CustomToolbarProps<'assistKey'>) {
|
||||||
|
const { item, toolbar } = props;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
style="
|
||||||
|
display: flex; flex-direction: row; justify-content: space-between;
|
||||||
|
align-items: center; padding: 0 5%; margin: 1%
|
||||||
|
"
|
||||||
|
>
|
||||||
|
<span>辅助按键</span>
|
||||||
|
<Select
|
||||||
|
style="width: 180px; font-size: 80%; height: 100%; background-color: #000"
|
||||||
|
value={item.assist}
|
||||||
|
onChange={value =>
|
||||||
|
toolbar.set<'assistKey'>(item.id, {
|
||||||
|
assist: value as KeyCode.Ctrl
|
||||||
|
})
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<SelectOption value={KeyCode.Ctrl}>Ctrl</SelectOption>
|
||||||
|
<SelectOption value={KeyCode.Shift}>Shift</SelectOption>
|
||||||
|
<SelectOption value={KeyCode.Alt}>Alt</SelectOption>
|
||||||
|
</Select>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
@ -356,7 +356,8 @@ export function flipBinary(num: number, col: number) {
|
|||||||
*/
|
*/
|
||||||
export function getVitualKeyOnce(
|
export function getVitualKeyOnce(
|
||||||
emitAssist: boolean = false,
|
emitAssist: boolean = false,
|
||||||
assist: number = 0
|
assist: number = 0,
|
||||||
|
emittable: KeyCode[] = []
|
||||||
): Promise<KeyboardEmits> {
|
): Promise<KeyboardEmits> {
|
||||||
return new Promise(res => {
|
return new Promise(res => {
|
||||||
const key = Keyboard.get('full')!;
|
const key = Keyboard.get('full')!;
|
||||||
@ -365,11 +366,16 @@ export function getVitualKeyOnce(
|
|||||||
key.on('emit', (item, assist, index, ev) => {
|
key.on('emit', (item, assist, index, ev) => {
|
||||||
ev.preventDefault();
|
ev.preventDefault();
|
||||||
if (emitAssist) {
|
if (emitAssist) {
|
||||||
|
if (emittable.length === 0 || emittable.includes(item.key)) {
|
||||||
res({ key: item.key, assist: 0 });
|
res({ key: item.key, assist: 0 });
|
||||||
key.disposeScope();
|
key.disposeScope();
|
||||||
mainUi.close(id);
|
mainUi.close(id);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
if (!isAssist(item.key)) {
|
if (
|
||||||
|
!isAssist(item.key) &&
|
||||||
|
(emittable.length === 0 || emittable.includes(item.key))
|
||||||
|
) {
|
||||||
res({ key: item.key, assist });
|
res({ key: item.key, assist });
|
||||||
key.disposeScope();
|
key.disposeScope();
|
||||||
mainUi.close(id);
|
mainUi.close(id);
|
||||||
|
@ -1,6 +1,9 @@
|
|||||||
<template>
|
<template>
|
||||||
<Column :left="30" @close="exit">
|
<div id="tools">
|
||||||
<template #left>
|
<span class="button-text" @click="exit"><left-outlined /> 返回</span>
|
||||||
|
</div>
|
||||||
|
<div id="tool-editor">
|
||||||
|
<Scroll class="tool-list-scroll">
|
||||||
<div id="tool-list">
|
<div id="tool-list">
|
||||||
<div
|
<div
|
||||||
v-for="(item, i) of list"
|
v-for="(item, i) of list"
|
||||||
@ -12,48 +15,172 @@
|
|||||||
<a-button
|
<a-button
|
||||||
type="danger"
|
type="danger"
|
||||||
class="tool-list-delete"
|
class="tool-list-delete"
|
||||||
@click.stop="deleteTool"
|
@click.stop="deleteTool(item.id)"
|
||||||
>删除</a-button
|
>删除</a-button
|
||||||
>
|
>
|
||||||
</div>
|
</div>
|
||||||
<div id="tool-list-add">
|
<div id="tool-list-add">
|
||||||
<div id="tool-add-div" @click="addTool">
|
<div
|
||||||
|
id="tool-add-div"
|
||||||
|
@click="addingTool = true"
|
||||||
|
v-if="!addingTool"
|
||||||
|
>
|
||||||
<PlusOutlined></PlusOutlined>
|
<PlusOutlined></PlusOutlined>
|
||||||
<span>新增工具栏</span>
|
<span>新增工具栏</span>
|
||||||
</div>
|
</div>
|
||||||
|
<div v-else>
|
||||||
|
<a-input
|
||||||
|
style="height: 100%; font-size: 80%; width: 100%"
|
||||||
|
v-model:value="addingToolId"
|
||||||
|
@blur="addTool"
|
||||||
|
></a-input>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</div>
|
||||||
<template #right>
|
</Scroll>
|
||||||
|
<a-divider
|
||||||
|
class="divider"
|
||||||
|
dashed
|
||||||
|
style="border-color: #ddd4"
|
||||||
|
:type="isMobile ? 'horizontal' : 'vertical'"
|
||||||
|
></a-divider>
|
||||||
<div id="tool-info">
|
<div id="tool-info">
|
||||||
<div id="tool-detail"></div>
|
<div id="tool-detail">
|
||||||
|
<Scroll class="tool-item-list-scroll">
|
||||||
|
<div class="tool-item-list">
|
||||||
|
<div
|
||||||
|
class="tool-item-list-item"
|
||||||
|
v-for="item of bar.items"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="tool-item-header"
|
||||||
|
:folded="!unfolded[item.id]"
|
||||||
|
@click="triggerFold(item.id)"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
style="
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
width: 100%;
|
||||||
|
"
|
||||||
|
>
|
||||||
|
<span
|
||||||
|
class="tool-fold"
|
||||||
|
:folded="!unfolded[item.id]"
|
||||||
|
>
|
||||||
|
<RightOutlined></RightOutlined>
|
||||||
|
</span>
|
||||||
|
<span class="tool-name">
|
||||||
|
<span
|
||||||
|
v-if="editId !== item.id"
|
||||||
|
style="cursor: text"
|
||||||
|
@click.stop="editName(item.id)"
|
||||||
|
>
|
||||||
|
{{ item.id }}
|
||||||
|
</span>
|
||||||
|
<span v-else>
|
||||||
|
<a-input
|
||||||
|
@blur="editNameSuccess(item.id)"
|
||||||
|
@click.stop=""
|
||||||
|
v-model:value="editValue"
|
||||||
|
class="tool-name-edit"
|
||||||
|
></a-input>
|
||||||
|
</span>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<a-button
|
||||||
|
type="danger"
|
||||||
|
class="tool-item-delete"
|
||||||
|
@click.stop="deleteItem(item)"
|
||||||
|
>删除</a-button
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
<div v-if="!!unfolded[item.id]">
|
||||||
|
<component
|
||||||
|
:is="CustomToolbar.info[item.type].editor"
|
||||||
|
:item="item"
|
||||||
|
:toolbar="bar"
|
||||||
|
></component>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div id="tool-item-add">
|
||||||
|
<div
|
||||||
|
id="tool-item-add-div"
|
||||||
|
v-if="!addingItem"
|
||||||
|
@click="addingItem = true"
|
||||||
|
>
|
||||||
|
<PlusOutlined></PlusOutlined>
|
||||||
|
<span>新增工具</span>
|
||||||
|
</div>
|
||||||
|
<div id="tool-item-add-type" v-else>
|
||||||
|
<span>工具类型</span>
|
||||||
|
<a-select
|
||||||
|
v-model:value="addingType"
|
||||||
|
style="
|
||||||
|
width: 120px;
|
||||||
|
height: 100%;
|
||||||
|
font-size: 80%;
|
||||||
|
background-color: #222;
|
||||||
|
"
|
||||||
|
>
|
||||||
|
<a-select-option
|
||||||
|
v-for="(
|
||||||
|
info, type
|
||||||
|
) of CustomToolbar.info"
|
||||||
|
:value="type"
|
||||||
|
>{{ info.name }}</a-select-option
|
||||||
|
>
|
||||||
|
</a-select>
|
||||||
|
<a-button
|
||||||
|
type="primary"
|
||||||
|
style="font-size: 80%; height: 100%"
|
||||||
|
@click="addItem(true)"
|
||||||
|
>确定</a-button
|
||||||
|
>
|
||||||
|
<a-button
|
||||||
|
@click="addItem(false)"
|
||||||
|
style="
|
||||||
|
background-color: #222;
|
||||||
|
font-size: 80%;
|
||||||
|
height: 100%;
|
||||||
|
"
|
||||||
|
>取消</a-button
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</Scroll>
|
||||||
|
</div>
|
||||||
<a-divider dashed></a-divider>
|
<a-divider dashed></a-divider>
|
||||||
<div id="tool-preview">
|
<div id="tool-preview">
|
||||||
<div id="tool-preview-container">
|
<div id="tool-preview-container">
|
||||||
<div
|
<div class="tool-preview-item" v-for="item of bar.items">
|
||||||
class="tool-preview-item"
|
|
||||||
v-for="item of bar.items"
|
|
||||||
>
|
|
||||||
<component
|
<component
|
||||||
:is="(item.com as any)"
|
:is="(CustomToolbar.info[item.type].show as any)"
|
||||||
:item="item"
|
:item="item"
|
||||||
:bar="bar"
|
:toolbar="bar"
|
||||||
></component>
|
></component>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</div>
|
||||||
</Column>
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { CustomToolbar } from '@/core/main/custom/toolbar';
|
import { CustomToolbar, ToolbarItemType } from '@/core/main/custom/toolbar';
|
||||||
import { GameUi } from '@/core/main/custom/ui';
|
import { GameUi } from '@/core/main/custom/ui';
|
||||||
import Column from '../components/colomn.vue';
|
import { computed, reactive, ref } from 'vue';
|
||||||
import { computed, ref } from 'vue';
|
import {
|
||||||
import { PlusOutlined } from '@ant-design/icons-vue';
|
PlusOutlined,
|
||||||
|
RightOutlined,
|
||||||
|
LeftOutlined
|
||||||
|
} from '@ant-design/icons-vue';
|
||||||
import { mainUi } from '@/core/main/init/ui';
|
import { mainUi } from '@/core/main/init/ui';
|
||||||
|
import { isMobile } from '@/plugin/use';
|
||||||
|
import Scroll from '@/components/scroll.vue';
|
||||||
|
import { deleteWith, tip } from '@/plugin/utils';
|
||||||
|
import { Modal } from 'ant-design-vue';
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
ui: GameUi;
|
ui: GameUi;
|
||||||
@ -65,25 +192,148 @@ const list = CustomToolbar.list;
|
|||||||
const selected = ref(0);
|
const selected = ref(0);
|
||||||
const bar = computed(() => list[selected.value]);
|
const bar = computed(() => list[selected.value]);
|
||||||
|
|
||||||
|
const unfolded = reactive<Record<string, boolean>>({});
|
||||||
|
const editId = ref<string>();
|
||||||
|
const editValue = ref<string>();
|
||||||
|
|
||||||
|
// 添加自定义工具
|
||||||
|
const addingItem = ref(false);
|
||||||
|
const addingType = ref<ToolbarItemType>('item');
|
||||||
|
|
||||||
|
// 添加自定义工具栏
|
||||||
|
const addingTool = ref(false);
|
||||||
|
const addingToolId = ref('');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 编辑名称
|
||||||
|
*/
|
||||||
|
function editName(id: string) {
|
||||||
|
editId.value = id;
|
||||||
|
editValue.value = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 编辑名称完成
|
||||||
|
*/
|
||||||
|
function editNameSuccess(id: string) {
|
||||||
|
if (bar.value.items.some(v => v.id === editId.value)) {
|
||||||
|
tip('error', '名称重复!');
|
||||||
|
} else {
|
||||||
|
const item = bar.value.items.find(v => v.id === id)!;
|
||||||
|
item.id = editValue.value!;
|
||||||
|
}
|
||||||
|
editId.value = void 0;
|
||||||
|
editValue.value = void 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除自定义工具
|
||||||
|
*/
|
||||||
|
function deleteItem(item: any) {
|
||||||
|
Modal.confirm({
|
||||||
|
title: '确定要删除这个自定义工具吗?',
|
||||||
|
onOk() {
|
||||||
|
deleteWith(bar.value.items, item);
|
||||||
|
},
|
||||||
|
onCancel() {}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function addItem(add: boolean) {
|
||||||
|
if (add) {
|
||||||
|
bar.value.add(
|
||||||
|
// @ts-ignore
|
||||||
|
CustomToolbar.info[addingType.value].onCreate({
|
||||||
|
id: `tool-item-${bar.value.items.length}`,
|
||||||
|
type: addingType.value
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
|
addingItem.value = false;
|
||||||
|
addingType.value = 'item';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 更改折叠
|
||||||
|
*/
|
||||||
|
function triggerFold(id: string) {
|
||||||
|
unfolded[id] = !unfolded[id];
|
||||||
|
}
|
||||||
|
|
||||||
function exit() {
|
function exit() {
|
||||||
mainUi.close(props.num);
|
mainUi.close(props.num);
|
||||||
}
|
}
|
||||||
|
|
||||||
function deleteTool() {}
|
function deleteTool(id: string) {
|
||||||
|
Modal.confirm({
|
||||||
|
title: '确定要删除这个自定义工具栏吗?',
|
||||||
|
onOk() {
|
||||||
|
const index = CustomToolbar.list.findIndex(v => v.id === id);
|
||||||
|
if (index !== -1) {
|
||||||
|
CustomToolbar.list[index].closeAll();
|
||||||
|
CustomToolbar.list.splice(index, 1);
|
||||||
|
}
|
||||||
|
selected.value = 0;
|
||||||
|
},
|
||||||
|
onCancel() {}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
function addTool() {}
|
function addTool() {
|
||||||
|
if (addingToolId.value === '') {
|
||||||
|
addingToolId.value = '';
|
||||||
|
addingTool.value = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (CustomToolbar.list.some(v => v.id === addingToolId.value)) {
|
||||||
|
tip('error', '工具栏名称重复!');
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
const bar = new CustomToolbar(addingToolId.value);
|
||||||
|
}
|
||||||
|
addingToolId.value = '';
|
||||||
|
addingTool.value = false;
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="less" scoped>
|
<style lang="less" scoped>
|
||||||
|
#tools {
|
||||||
|
width: 100%;
|
||||||
|
font-family: 'normal';
|
||||||
|
font-size: 3.2vh;
|
||||||
|
height: 5vh;
|
||||||
|
position: fixed;
|
||||||
|
left: 10vw;
|
||||||
|
top: 5vh;
|
||||||
|
}
|
||||||
|
|
||||||
|
#tool-editor {
|
||||||
|
width: 70%;
|
||||||
|
height: 70%;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
font-family: 'normal';
|
||||||
|
font-size: 150%;
|
||||||
|
user-select: none;
|
||||||
|
align-self: center;
|
||||||
|
}
|
||||||
|
|
||||||
.tool-list-item {
|
.tool-list-item {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.tool-list-scroll {
|
||||||
|
height: 100%;
|
||||||
|
width: 30%;
|
||||||
|
}
|
||||||
|
|
||||||
#tool-list {
|
#tool-list {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
|
height: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
#tool-list-add {
|
#tool-list-add {
|
||||||
@ -119,22 +369,140 @@ function addTool() {}
|
|||||||
#tool-info {
|
#tool-info {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
|
height: 100%;
|
||||||
|
width: 70%;
|
||||||
|
}
|
||||||
|
|
||||||
|
#tool-detail {
|
||||||
|
height: 60%;
|
||||||
|
|
||||||
|
.tool-item-header {
|
||||||
|
cursor: pointer;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
align-items: center;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tool-item-header[folded='false'] {
|
||||||
|
border-bottom: 0.5px solid #888;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tool-item-list-scroll {
|
||||||
|
height: 100%;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tool-item-list {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tool-item-list-item {
|
||||||
|
border: 1px solid #ddd8;
|
||||||
|
margin-bottom: 5%;
|
||||||
|
background-color: #222;
|
||||||
|
padding-left: 2%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tool-fold {
|
||||||
|
::v-deep(span) {
|
||||||
|
transition: all 0.2s ease;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.tool-fold[folded='false'] {
|
||||||
|
::v-deep(span) {
|
||||||
|
transform: rotate(90deg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.tool-name {
|
||||||
|
margin-left: 3%;
|
||||||
|
width: 40%;
|
||||||
|
display: flex;
|
||||||
|
|
||||||
|
.tool-name-edit {
|
||||||
|
width: 100%;
|
||||||
|
font-size: 100%;
|
||||||
|
height: 100%;
|
||||||
|
background-color: #000;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.tool-item-delete {
|
||||||
|
height: 100%;
|
||||||
|
justify-self: end;
|
||||||
|
font-size: 80%;
|
||||||
|
padding: 2px 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#tool-item-add-div {
|
||||||
|
padding: 1% 3% 1% 3%;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
flex-direction: row;
|
||||||
|
cursor: pointer;
|
||||||
|
padding: 1% 4%;
|
||||||
|
transition: background-color linear 0.1s;
|
||||||
|
border-radius: 5px;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
}
|
||||||
|
|
||||||
|
#tool-item-add-div:hover {
|
||||||
|
background-color: rgba(39, 251, 209, 0.316);
|
||||||
|
}
|
||||||
|
|
||||||
|
#tool-item-add-div:active {
|
||||||
|
background-color: rgba(39, 251, 209, 0.202);
|
||||||
|
}
|
||||||
|
|
||||||
|
#tool-item-add-type {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
flex-direction: row;
|
||||||
|
padding: 1% 4%;
|
||||||
|
justify-content: space-between;
|
||||||
|
border-radius: 5px;
|
||||||
|
background-color: rgba(39, 251, 209, 0.316);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#tool-preview {
|
#tool-preview {
|
||||||
|
height: 40%;
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
align-items: center;
|
align-items: start;
|
||||||
|
|
||||||
#tool-preview-container {
|
#tool-preview-container {
|
||||||
|
width: 90%;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
border: 2px solid #ddd9;
|
border: 2px solid #ddd9;
|
||||||
background-color: #0009;
|
background-color: #0009;
|
||||||
|
flex-wrap: wrap;
|
||||||
}
|
}
|
||||||
|
|
||||||
.tool-preview-item {
|
.tool-preview-item {
|
||||||
|
display: flex;
|
||||||
|
margin: 5px;
|
||||||
|
min-width: 50px;
|
||||||
|
height: 50px;
|
||||||
|
background-color: #222;
|
||||||
|
border: 1.5px solid #ddd8;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
transition: all 0.1s linear;
|
||||||
|
|
||||||
::v-deep(*) {
|
::v-deep(*) {
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.divider {
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
@ -15,7 +15,7 @@
|
|||||||
@click.stop="click"
|
@click.stop="click"
|
||||||
>
|
>
|
||||||
<component
|
<component
|
||||||
:is="(item.com as any)"
|
:is="(CustomToolbar.info[item.type].show as any)"
|
||||||
:item="item"
|
:item="item"
|
||||||
:toolbar="bar"
|
:toolbar="bar"
|
||||||
></component>
|
></component>
|
||||||
|
Loading…
Reference in New Issue
Block a user