feat: animation system
This commit is contained in:
parent
406e71575f
commit
7534a613cb
22 changed files with 19733 additions and 19122 deletions
|
|
@ -1,3 +1,6 @@
|
|||
import { AnimationKeyframe } from "../components/AnimationKeyframe.js"
|
||||
import { AnimType } from "../types/enums/AnimType.js"
|
||||
import { KeyframeAnimationProperties } from "../types/properties/element/Animation.js"
|
||||
import { Binding } from "../types/properties/value.js"
|
||||
|
||||
export function FormatProperties(properties: any) {
|
||||
|
|
@ -27,3 +30,11 @@ export function FormatProperties(properties: any) {
|
|||
|
||||
return properties
|
||||
}
|
||||
|
||||
export function FormatAnimationProperties(properties: KeyframeAnimationProperties<AnimType>) {
|
||||
if (properties.next instanceof AnimationKeyframe) {
|
||||
properties.next = `${properties.next}`
|
||||
}
|
||||
|
||||
return properties
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,9 +1,11 @@
|
|||
import { AnimationKeyframe } from "../components/AnimationKeyframe.js"
|
||||
import { Class } from "../components/Class.js"
|
||||
import { UI } from "../components/UI.js"
|
||||
import { AnimType } from "../types/enums/AnimType.js"
|
||||
import { Renderer } from "../types/enums/Renderer.js"
|
||||
import { Type } from "../types/enums/Type.js"
|
||||
|
||||
type Element = UI<Type, Renderer | null>
|
||||
type Element = UI<Type, Renderer | null> | AnimationKeyframe<AnimType>
|
||||
interface FileInterface {
|
||||
namespace: string
|
||||
elements: Element[]
|
||||
|
|
@ -13,7 +15,7 @@ type Files = Map<string, FileInterface>
|
|||
export class Memory extends Class {
|
||||
protected static files: Files = new Map<string, FileInterface>()
|
||||
|
||||
public static add(element: UI<Type, Renderer | null>) {
|
||||
public static add(element: UI<Type, Renderer | null> | AnimationKeyframe<AnimType>) {
|
||||
let file = Memory.files.get(element.path)
|
||||
|
||||
if (!file) {
|
||||
|
|
|
|||
|
|
@ -1,5 +1,9 @@
|
|||
import { Memory } from "./Memory.js"
|
||||
|
||||
process.on("beforeExit", () => {
|
||||
// console.log(Memory.build())
|
||||
})
|
||||
const isBuildMode = process.argv.includes("--build")
|
||||
|
||||
if (isBuildMode) {
|
||||
process.on("beforeExit", () => {
|
||||
console.log(JSON.stringify(Memory.build(), null, 2))
|
||||
})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,3 +1,63 @@
|
|||
import { AnimType } from "../types/enums/AnimType.js"
|
||||
import { AnimationProperties } from "../types/properties/element/Animation.js"
|
||||
import { Class } from "./Class.js"
|
||||
import { KeyframeController } from "./KeyframeController.js"
|
||||
|
||||
export class Animation extends Class {}
|
||||
export class Animation<T extends AnimType> extends Class {
|
||||
protected keyframes: KeyframeController<AnimType>[] = []
|
||||
protected loop = false
|
||||
|
||||
constructor(
|
||||
readonly type: T,
|
||||
...keyframes: (AnimationProperties<T> | number)[]
|
||||
) {
|
||||
super()
|
||||
if (type === AnimType.WAIT) console.warn("Why are you create a wait animation?")
|
||||
this.addKeyframes(...keyframes)
|
||||
}
|
||||
|
||||
protected lastKey() {
|
||||
return this.keyframes[this.keyframes.length - 1]
|
||||
}
|
||||
|
||||
protected firstKey() {
|
||||
return this.keyframes[0]
|
||||
}
|
||||
|
||||
addKeyframes(...keyframes: (AnimationProperties<T> | number)[]) {
|
||||
for (const $ of keyframes) {
|
||||
let keyframe: AnimationProperties<AnimType>, animType: AnimType
|
||||
|
||||
if (typeof $ === "number") {
|
||||
keyframe = { duration: $ }
|
||||
animType = AnimType.WAIT
|
||||
} else {
|
||||
keyframe = $
|
||||
animType = this.type
|
||||
}
|
||||
|
||||
const keyframeController = new KeyframeController(animType, keyframe as AnimationProperties<T>)
|
||||
|
||||
const prevKeyframe = this.lastKey()
|
||||
if (prevKeyframe) prevKeyframe.setNext(keyframeController)
|
||||
|
||||
if (this.loop) keyframeController.setNext(this.firstKey() as KeyframeController<T>)
|
||||
|
||||
this.keyframes.push(keyframeController)
|
||||
}
|
||||
}
|
||||
|
||||
setLoop(boolean: boolean) {
|
||||
this.loop = boolean
|
||||
|
||||
if (this.loop) {
|
||||
const prevKeyframe = this.lastKey()
|
||||
if (prevKeyframe) prevKeyframe.setNext(this.firstKey() as KeyframeController<T>)
|
||||
} else {
|
||||
const prevKeyframe = this.lastKey()
|
||||
if (prevKeyframe) prevKeyframe.clearNext()
|
||||
}
|
||||
|
||||
return this
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,3 +1,61 @@
|
|||
import { FormatAnimationProperties } from "../compilers/FormatProperties.js"
|
||||
import { Memory } from "../compilers/Memory.js"
|
||||
import { AnimType } from "../types/enums/AnimType.js"
|
||||
import { KeyframeAnimationProperties } from "../types/properties/element/Animation.js"
|
||||
import { Class } from "./Class.js"
|
||||
import { RandomString } from "./Utils.js"
|
||||
|
||||
export class AnimationKeyframe extends Class {}
|
||||
import util from "node:util"
|
||||
|
||||
export class AnimationKeyframe<T extends AnimType> extends Class {
|
||||
readonly path: string
|
||||
readonly name: string
|
||||
readonly namespace: string
|
||||
|
||||
constructor(
|
||||
readonly type: T,
|
||||
readonly properties: KeyframeAnimationProperties<T>,
|
||||
name?: string,
|
||||
namespace?: string,
|
||||
path?: string,
|
||||
) {
|
||||
super()
|
||||
|
||||
if (name === "namespace") {
|
||||
console.error("The 'namespace' cannot be used as a name")
|
||||
process.exit(1)
|
||||
}
|
||||
|
||||
if (namespace && !/^\w+$/.test(namespace)) {
|
||||
console.error(`The '${namespace}' cannot be used as a namespace`)
|
||||
process.exit(1)
|
||||
}
|
||||
|
||||
this.name = name || RandomString(16)
|
||||
this.namespace = namespace || RandomString(16)
|
||||
this.path = path || `@/${this.namespace}`
|
||||
|
||||
Memory.add(this)
|
||||
}
|
||||
|
||||
protected toJsonUI() {
|
||||
return FormatAnimationProperties(this.properties)
|
||||
}
|
||||
|
||||
protected toJSON() {
|
||||
return {
|
||||
anim_type: this.type,
|
||||
...this.toJsonUI(),
|
||||
}
|
||||
}
|
||||
|
||||
protected toString() {
|
||||
return `@${this.namespace}.${this.name}`
|
||||
}
|
||||
|
||||
protected [util.inspect.custom]($: any, opts: any) {
|
||||
return `\x1b[33mAnimationKeyFrame\x1b[0m<\x1b[92m${
|
||||
this.type
|
||||
}\x1b[0m> \x1b[92m"${this}\x1b[92m"\x1b[0m ${util.inspect(this.toJsonUI(), opts)}\n`
|
||||
}
|
||||
}
|
||||
|
|
|
|||
19
src/components/KeyframeController.ts
Normal file
19
src/components/KeyframeController.ts
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
import { AnimType } from "../types/enums/AnimType.js"
|
||||
import { KeyframeAnimationProperties } from "../types/properties/element/Animation.js"
|
||||
import { AnimationKeyframe } from "./AnimationKeyframe.js"
|
||||
|
||||
export class KeyframeController<T extends AnimType> extends AnimationKeyframe<T> {
|
||||
constructor(type: T, properties: KeyframeAnimationProperties<T>, name?: string, namespace?: string, path?: string) {
|
||||
super(type, properties, name, namespace, path)
|
||||
}
|
||||
|
||||
setNext(keyframe: AnimationKeyframe<AnimType>) {
|
||||
this.properties.next = keyframe
|
||||
return this
|
||||
}
|
||||
|
||||
clearNext() {
|
||||
delete this.properties.next
|
||||
return this
|
||||
}
|
||||
}
|
||||
|
|
@ -1,30 +1,31 @@
|
|||
import { isCompileBinding } from "../compilers/bindings/Checker.js"
|
||||
import { Parser } from "../compilers/bindings/Parser.js"
|
||||
import { FormatProperties } from "../compilers/FormatProperties.js"
|
||||
import { Memory } from "../compilers/Memory.js"
|
||||
import { BindingType } from "../types/enums/BindingType.js"
|
||||
import { ArrayName } from "../types/enums/ArrayName.js"
|
||||
import { Operation } from "../types/enums/Operation.js"
|
||||
import { Renderer } from "../types/enums/Renderer.js"
|
||||
import { Type } from "../types/enums/Type.js"
|
||||
import { Properties } from "../types/properties/components.js"
|
||||
import { BindingItem } from "../types/properties/value.js"
|
||||
import { BindingItem, ButtonMapping, ModificationItem, VariableItem, Variables } from "../types/properties/value.js"
|
||||
import { Class } from "./Class.js"
|
||||
import { ExtendsOf, RandomString } from "./Utils.js"
|
||||
import { ExtendsOf, RandomString, ResolveBinding } from "./Utils.js"
|
||||
|
||||
import util from "node:util"
|
||||
|
||||
export class UI<T extends Type, K extends Renderer | null = null> extends Class {
|
||||
readonly path: string
|
||||
|
||||
readonly name: string
|
||||
readonly namespace: string
|
||||
readonly extend?: UI<Type, Renderer | null>
|
||||
|
||||
readonly extend?: UI<Type, Renderer | null>
|
||||
readonly extendable: boolean
|
||||
|
||||
readonly controls = new Map<string, [UI<Type, Renderer | null>, Properties<Type, Renderer | null>]>()
|
||||
readonly bindings: BindingItem[] = []
|
||||
readonly extendType?: Type
|
||||
properties: Properties<T, K> = <any>{}
|
||||
protected readonly controls = new Map<string, [UI<Type, Renderer | null>, Properties<Type, Renderer | null>]>()
|
||||
protected readonly bindings: BindingItem[] = []
|
||||
protected readonly variables: VariableItem[] = []
|
||||
protected readonly buttonMappings: ButtonMapping[] = []
|
||||
protected readonly extendType?: Type
|
||||
|
||||
protected properties: Properties<T, K> = <any>{}
|
||||
|
||||
constructor(
|
||||
public type?: T,
|
||||
|
|
@ -55,60 +56,72 @@ export class UI<T extends Type, K extends Renderer | null = null> extends Class
|
|||
Memory.add(this)
|
||||
}
|
||||
|
||||
protected UI_JSON() {
|
||||
const obj: any = {
|
||||
...FormatProperties(this.properties),
|
||||
}
|
||||
|
||||
if (this.type) {
|
||||
obj.type = this.type
|
||||
}
|
||||
|
||||
if (this.bindings.length) {
|
||||
obj.bindings = this.bindings
|
||||
}
|
||||
|
||||
if (this.controls.size) {
|
||||
obj.controls = []
|
||||
this.controls.forEach((e, key) => obj.controls.push({ [key + e[0]]: e[1] }))
|
||||
}
|
||||
|
||||
return obj
|
||||
}
|
||||
|
||||
/**
|
||||
* Set properties for this element
|
||||
* @param properties
|
||||
* @returns
|
||||
*/
|
||||
setProperties(properties: Properties<T, K>) {
|
||||
this.properties = { ...this.properties, ...properties }
|
||||
return this
|
||||
}
|
||||
|
||||
/**
|
||||
* Bind data (coming from the code) to this UI element to use.
|
||||
* @param bindings
|
||||
* @returns
|
||||
*/
|
||||
addBindings(...bindings: BindingItem[]) {
|
||||
for (const binding of bindings) {
|
||||
if (binding.source_property_name) {
|
||||
if (isCompileBinding(binding.source_property_name)) {
|
||||
const { gen, out } = new Parser(binding.source_property_name.slice(1, -1)).out()
|
||||
if (gen) this.bindings.push(...gen)
|
||||
binding.source_property_name = out
|
||||
}
|
||||
this.bindings.push(...ResolveBinding(...bindings))
|
||||
return this
|
||||
}
|
||||
|
||||
binding.binding_type = BindingType.VIEW
|
||||
|
||||
if (!binding.target_property_name) throw new Error("Binding must have a target property name")
|
||||
}
|
||||
this.bindings.push(binding)
|
||||
}
|
||||
/**
|
||||
* Changes variables values if conditions are met.
|
||||
* @param variables
|
||||
* @returns
|
||||
*/
|
||||
addVariables(variables: Variables) {
|
||||
Object.entries(variables).forEach(([key, value]) => {
|
||||
this.variables.push({
|
||||
requires: key,
|
||||
...value,
|
||||
})
|
||||
})
|
||||
|
||||
return this
|
||||
}
|
||||
|
||||
addChild<T extends Type, K extends Renderer | null>(child: UI<T, K>, properties?: Properties<T, K>, name?: string) {
|
||||
if (this === <any>child) {
|
||||
throw new Error("Cannot add a child to itself")
|
||||
}
|
||||
/**
|
||||
* Add button mappings for this element
|
||||
* @param mappings
|
||||
* @returns
|
||||
*/
|
||||
addButtonMappings(...mappings: ButtonMapping[]) {
|
||||
this.buttonMappings.push(...mappings)
|
||||
return this
|
||||
}
|
||||
|
||||
/**
|
||||
* Children of the UI element.
|
||||
* @param child
|
||||
* @param properties
|
||||
* @param name
|
||||
* @returns
|
||||
*/
|
||||
addChild<T extends Type, K extends Renderer | null>(child: UI<T, K>, properties?: Properties<T, K>, name?: string) {
|
||||
if (this === <any>child) throw new Error("Cannot add a child to itself")
|
||||
this.controls.set(name || RandomString(16), [child, properties || {}])
|
||||
return this
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a extend of this element
|
||||
* @param properties
|
||||
* @param name
|
||||
* @param namespace
|
||||
* @returns
|
||||
*/
|
||||
clone(properties?: Properties<T, K>, name?: string, namespace?: string) {
|
||||
return ExtendsOf(this, properties, name, namespace)
|
||||
}
|
||||
|
|
@ -117,40 +130,264 @@ export class UI<T extends Type, K extends Renderer | null = null> extends Class
|
|||
return `@${this.namespace}.${this.name}`
|
||||
}
|
||||
|
||||
protected toJSON() {
|
||||
return this.UI_JSON()
|
||||
}
|
||||
|
||||
protected [util.inspect.custom]($: any, opts: any) {
|
||||
protected toJsonUI() {
|
||||
const obj: any = {
|
||||
...FormatProperties(this.properties),
|
||||
}
|
||||
|
||||
if (this.bindings.length) {
|
||||
obj.bindings = this.bindings
|
||||
}
|
||||
if (this.type) obj.type = this.type
|
||||
|
||||
if (this.bindings.length) obj.bindings = this.bindings
|
||||
if (this.variables.length) obj.variables = this.variables
|
||||
if (this.buttonMappings.length) obj.button_mappings = this.buttonMappings
|
||||
|
||||
if (this.controls.size) {
|
||||
obj.controls = []
|
||||
this.controls.forEach((e, key) => obj.controls.push({ [key + e[0]]: e[1] }))
|
||||
}
|
||||
|
||||
const elementType = this.type || (this.extend ? `${this.extendType || "unknown"}:${this.extend}` : "unknown")
|
||||
|
||||
return `\x1b[33mUI\x1b[0m<\x1b[92m${
|
||||
elementType
|
||||
}\x1b[0m> \x1b[92m"${this}\x1b[92m"\x1b[0m ${util.inspect(obj, opts)}\n`
|
||||
}
|
||||
}
|
||||
|
||||
export class ModifyUI<T extends Type> extends UI<T, null> {
|
||||
constructor(namespace: string, name: string, path: string) {
|
||||
if (!path) throw new Error("ModifyUI cannot have a path")
|
||||
super(undefined, name, namespace, path)
|
||||
return obj
|
||||
}
|
||||
|
||||
protected toJSON() {
|
||||
const obj = this.UI_JSON()
|
||||
return obj
|
||||
return this.toJsonUI()
|
||||
}
|
||||
|
||||
protected [util.inspect.custom]($: any, opts: any) {
|
||||
return `\x1b[33mUI\x1b[0m<\x1b[92m${
|
||||
this.type || (this.extend ? `${this.extendType || "unknown"}:${this.extend}` : "unknown")
|
||||
}\x1b[0m> \x1b[92m"${this}\x1b[92m"\x1b[0m ${util.inspect(this.toJsonUI(), opts)}\n`
|
||||
}
|
||||
}
|
||||
|
||||
export class ModifyUI<T extends Type = Type.PANEL, S extends string = string> extends UI<T, null> {
|
||||
private isClearBinding: boolean = false
|
||||
private isClearVariables: boolean = false
|
||||
private isClearButtonMappings: boolean = false
|
||||
|
||||
protected modifications: ModificationItem[] = []
|
||||
|
||||
constructor(namespace: string, name: string, path: string) {
|
||||
super(undefined, name, namespace, path)
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove all bindings of this modify element
|
||||
* @returns
|
||||
*/
|
||||
clearBinding() {
|
||||
this.isClearBinding = true
|
||||
return this
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove all variables of this modfy element
|
||||
* @returns
|
||||
*/
|
||||
clearVariables() {
|
||||
this.isClearVariables = true
|
||||
return this
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove all button mappings of this element
|
||||
* @returns
|
||||
*/
|
||||
clearButtonMappings() {
|
||||
this.isClearButtonMappings = true
|
||||
return this
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows to modify the UI elements from resource packs below this one
|
||||
* @returns
|
||||
*/
|
||||
addModifications(...modifications: ModificationItem[]) {
|
||||
this.modifications.push(...modifications)
|
||||
return this
|
||||
}
|
||||
|
||||
insertBackChild<T extends Type, K extends Renderer | null>(
|
||||
child: UI<T, K>,
|
||||
properties?: Properties<T, K>,
|
||||
name?: string,
|
||||
) {
|
||||
if (this === <any>child) throw new Error("Cannot add a child to itself")
|
||||
if (!name) name = RandomString(16)
|
||||
|
||||
return this.addModifications({
|
||||
array_name: ArrayName.CONTROLS,
|
||||
operation: Operation.INSERT_BACK,
|
||||
value: {
|
||||
[`${name}${child}`]: properties || {},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
insertFrontChild<T extends Type, K extends Renderer | null>(
|
||||
child: UI<T, K>,
|
||||
properties?: Properties<T, K>,
|
||||
name?: string,
|
||||
) {
|
||||
if (this === <any>child) throw new Error("Cannot add a child to itself")
|
||||
if (!name) name = RandomString(16)
|
||||
|
||||
return this.addModifications({
|
||||
array_name: ArrayName.CONTROLS,
|
||||
operation: Operation.INSERT_FRONT,
|
||||
value: {
|
||||
[`${name}${child}`]: properties || {},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
insertAfterChild<T extends Type, K extends Renderer | null>(
|
||||
where: S,
|
||||
child: UI<T, K>,
|
||||
properties?: Properties<T, K>,
|
||||
name?: string,
|
||||
) {
|
||||
if (this === <any>child) throw new Error("Cannot add a child to itself")
|
||||
if (!name) name = RandomString(16)
|
||||
|
||||
return this.addModifications({
|
||||
array_name: ArrayName.CONTROLS,
|
||||
operation: Operation.INSERT_AFTER,
|
||||
control_name: where!,
|
||||
value: {
|
||||
[`${name}${child}`]: properties || {},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
insertBeforeChild<T extends Type, K extends Renderer | null>(
|
||||
where: S,
|
||||
child: UI<T, K>,
|
||||
properties?: Properties<T, K>,
|
||||
name?: string,
|
||||
) {
|
||||
if (this === <any>child) throw new Error("Cannot add a child to itself")
|
||||
if (!name) name = RandomString(16)
|
||||
|
||||
return this.addModifications({
|
||||
array_name: ArrayName.CONTROLS,
|
||||
operation: Operation.INSERT_BEFORE,
|
||||
control_name: where!,
|
||||
value: {
|
||||
[`${name}${child}`]: properties || {},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
insertChild<T extends Type, K extends Renderer | null>(child: UI<T, K>, properties?: Properties<T, K>) {
|
||||
return this.insertBackChild(child, properties)
|
||||
}
|
||||
|
||||
replaceChild<T extends Type, K extends Renderer | null>(where: S, child: UI<T, K>, properties?: Properties<T, K>) {
|
||||
return this.addModifications({
|
||||
array_name: ArrayName.CONTROLS,
|
||||
operation: Operation.REPLACE,
|
||||
control_name: where!,
|
||||
value: properties || {},
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a child of this element
|
||||
* @param name
|
||||
* @returns
|
||||
*/
|
||||
removeChild(name: S) {
|
||||
return this.addModifications({
|
||||
array_name: ArrayName.CONTROLS,
|
||||
operation: Operation.REMOVE,
|
||||
control_name: name,
|
||||
})
|
||||
}
|
||||
|
||||
insertBackBindings(...bindings: BindingItem[]) {
|
||||
return this.addModifications({
|
||||
array_name: ArrayName.BINDINGS,
|
||||
operation: Operation.INSERT_BACK,
|
||||
value: ResolveBinding(...bindings),
|
||||
})
|
||||
}
|
||||
|
||||
insertFrontBindings(...bindings: BindingItem[]) {
|
||||
return this.addModifications({
|
||||
array_name: ArrayName.BINDINGS,
|
||||
operation: Operation.INSERT_FRONT,
|
||||
value: ResolveBinding(...bindings),
|
||||
})
|
||||
}
|
||||
|
||||
insertBindings(...bindings: BindingItem[]) {
|
||||
return this.insertBackBindings(...bindings)
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a binding of this element
|
||||
* @param binding
|
||||
*/
|
||||
removeBinding(binding: BindingItem) {
|
||||
return this.addModifications({
|
||||
array_name: ArrayName.BINDINGS,
|
||||
operation: Operation.REMOVE,
|
||||
where: binding,
|
||||
})
|
||||
}
|
||||
|
||||
insertBackButtonMappings(...buttonMappings: ButtonMapping[]) {
|
||||
return this.addModifications({
|
||||
array_name: ArrayName.BUTTON_MAPPINGS,
|
||||
operation: Operation.INSERT_BACK,
|
||||
value: buttonMappings,
|
||||
})
|
||||
}
|
||||
|
||||
insertFrontButtonMappings(...buttonMappings: ButtonMapping[]) {
|
||||
return this.addModifications({
|
||||
array_name: ArrayName.BUTTON_MAPPINGS,
|
||||
operation: Operation.INSERT_FRONT,
|
||||
value: buttonMappings,
|
||||
})
|
||||
}
|
||||
|
||||
insertButtonMappings(...buttonMappings: ButtonMapping[]) {
|
||||
return this.insertBackButtonMappings(...buttonMappings)
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a button mapping of this element
|
||||
* @param buttonMapping
|
||||
* @returns
|
||||
*/
|
||||
removeButtonMapping(buttonMapping: ButtonMapping) {
|
||||
return this.addModifications({
|
||||
array_name: ArrayName.BUTTON_MAPPINGS,
|
||||
operation: Operation.REMOVE,
|
||||
where: buttonMapping,
|
||||
})
|
||||
}
|
||||
|
||||
protected toJsonUIModify() {
|
||||
const obj = this.toJsonUI()
|
||||
|
||||
if (this.isClearBinding) obj.bindings = []
|
||||
if (this.isClearVariables) obj.variables = []
|
||||
if (this.isClearButtonMappings) obj.button_mappings = []
|
||||
|
||||
if (this.modifications.length) obj.modifications = this.modifications
|
||||
|
||||
return obj
|
||||
}
|
||||
|
||||
protected toJSON() {
|
||||
const obj = this.toJsonUIModify()
|
||||
return obj
|
||||
}
|
||||
|
||||
protected [util.inspect.custom]($: any, opts: any) {
|
||||
return `\x1b[33mUI\x1b[0m<\x1b[92mmodify\x1b[0m> \x1b[92m"${this}\x1b[92m"\x1b[0m ${util.inspect(this.toJsonUIModify(), opts)}\n`
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import { Type } from "../types/enums/Type.js"
|
||||
import { Array3, Binding } from "../types/properties/value.js"
|
||||
import { Array3, Binding, BindingItem } from "../types/properties/value.js"
|
||||
import { ModifyUI, UI } from "./UI.js"
|
||||
|
||||
import { Renderer } from "../types/enums/Renderer.js"
|
||||
|
|
@ -27,8 +27,14 @@ import {
|
|||
SliderBox,
|
||||
} from "../types/properties/components.js"
|
||||
import { ItemAuxID } from "../types/enums/Items.js"
|
||||
import { Element, Namespace, VanillaType } from "../types/vanilla/intellisense.js"
|
||||
import { Element, Namespace, VanillaElementChilds, VanillaType } from "../types/vanilla/intellisense.js"
|
||||
import { paths } from "../types/vanilla/paths.js"
|
||||
import { isCompileBinding } from "../compilers/bindings/Checker.js"
|
||||
import { Parser } from "../compilers/bindings/Parser.js"
|
||||
import { BindingType } from "../types/enums/BindingType.js"
|
||||
import { AnimType } from "../types/enums/AnimType.js"
|
||||
import { AnimationKeyframe } from "./AnimationKeyframe.js"
|
||||
import { KeyframeAnimationProperties } from "../types/properties/element/Animation.js"
|
||||
|
||||
const CHARS = "0123456789abcdefghijklmnopqrstuvwxyz"
|
||||
type CompileBinding = `[${string}]`
|
||||
|
|
@ -60,6 +66,27 @@ export function Color(hex: string | number): Array3<number> {
|
|||
}
|
||||
}
|
||||
|
||||
export function ResolveBinding(...bindings: BindingItem[]) {
|
||||
const result: BindingItem[] = []
|
||||
|
||||
for (const binding of bindings) {
|
||||
if (binding.source_property_name) {
|
||||
if (isCompileBinding(binding.source_property_name)) {
|
||||
const { gen, out } = new Parser(binding.source_property_name.slice(1, -1)).out()
|
||||
if (gen) result.push(...gen)
|
||||
binding.source_property_name = out
|
||||
}
|
||||
|
||||
binding.binding_type = BindingType.VIEW
|
||||
|
||||
if (!binding.target_property_name) throw new Error("Binding must have a target property name")
|
||||
}
|
||||
result.push(binding)
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
export function RandomString(length: number, base: number = 32) {
|
||||
const chars = CHARS.slice(0, base)
|
||||
const out = new Array<string>(length)
|
||||
|
|
@ -112,7 +139,7 @@ export function b(input: string): CompileBinding {
|
|||
// Quick Elements
|
||||
export function Modify<T extends Namespace, K extends Element<T>>(namespace: T, name: K) {
|
||||
// @ts-ignore -- TS cannot prove this, but runtime guarantees it
|
||||
return new ModifyUI<VanillaType<T, K>>(name, namespace, paths[namespace][name])
|
||||
return new ModifyUI<VanillaType<T, K>, VanillaElementChilds<T, K>>(namespace, name, paths[namespace][name])
|
||||
}
|
||||
|
||||
export function Panel(properties?: Panel, namespace?: string, name?: string) {
|
||||
|
|
@ -219,3 +246,72 @@ export function ExtendsOf<T extends Type, K extends Renderer | null>(
|
|||
ui.extendType = element.type || element.extendType
|
||||
return ui as typeof element
|
||||
}
|
||||
|
||||
// Quick Keyframe
|
||||
export function KeyframeOffset(
|
||||
properties?: KeyframeAnimationProperties<AnimType.OFFSET>,
|
||||
namespace?: string,
|
||||
name?: string,
|
||||
) {
|
||||
return new AnimationKeyframe(AnimType.OFFSET, properties || {}, name, namespace)
|
||||
}
|
||||
|
||||
export function KeyframeSize(
|
||||
properties?: KeyframeAnimationProperties<AnimType.SIZE>,
|
||||
namespace?: string,
|
||||
name?: string,
|
||||
) {
|
||||
return new AnimationKeyframe(AnimType.SIZE, properties || {}, name, namespace)
|
||||
}
|
||||
|
||||
export function KeyframeUV(properties?: KeyframeAnimationProperties<AnimType.UV>, namespace?: string, name?: string) {
|
||||
return new AnimationKeyframe(AnimType.UV, properties || {}, name, namespace)
|
||||
}
|
||||
|
||||
export function KeyframeClip(
|
||||
properties?: KeyframeAnimationProperties<AnimType.CLIP>,
|
||||
namespace?: string,
|
||||
name?: string,
|
||||
) {
|
||||
return new AnimationKeyframe(AnimType.CLIP, properties || {}, name, namespace)
|
||||
}
|
||||
|
||||
export function KeyframeColor(
|
||||
properties?: KeyframeAnimationProperties<AnimType.COLOR>,
|
||||
namespace?: string,
|
||||
name?: string,
|
||||
) {
|
||||
return new AnimationKeyframe(AnimType.COLOR, properties || {}, name, namespace)
|
||||
}
|
||||
|
||||
export function KeyframeAlpha(
|
||||
properties?: KeyframeAnimationProperties<AnimType.ALPHA>,
|
||||
namespace?: string,
|
||||
name?: string,
|
||||
) {
|
||||
return new AnimationKeyframe(AnimType.ALPHA, properties || {}, name, namespace)
|
||||
}
|
||||
|
||||
export function KeyframeWait(
|
||||
properties?: KeyframeAnimationProperties<AnimType.WAIT>,
|
||||
namespace?: string,
|
||||
name?: string,
|
||||
) {
|
||||
return new AnimationKeyframe(AnimType.WAIT, properties || {}, name, namespace)
|
||||
}
|
||||
|
||||
export function KeyframeFlipBook(
|
||||
properties?: KeyframeAnimationProperties<AnimType.FLIP_BOOK>,
|
||||
namespace?: string,
|
||||
name?: string,
|
||||
) {
|
||||
return new AnimationKeyframe(AnimType.FLIP_BOOK, properties || {}, name, namespace)
|
||||
}
|
||||
|
||||
export function KeyframeAsepriteFlipBook(
|
||||
properties?: KeyframeAnimationProperties<AnimType.ASEPRITE_FLIP_BOOK>,
|
||||
namespace?: string,
|
||||
name?: string,
|
||||
) {
|
||||
return new AnimationKeyframe(AnimType.ASEPRITE_FLIP_BOOK, properties || {}, name, namespace)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,8 +1,9 @@
|
|||
import "./compilers/PreCompile.js"
|
||||
import "./compilers/RunEnd.js"
|
||||
|
||||
export * from "./components/Animation.js"
|
||||
export * from "./components/UI.js"
|
||||
export { Animation } from "./components/Animation.js"
|
||||
export { AnimationKeyframe } from "./components/AnimationKeyframe.js"
|
||||
export { ModifyUI, UI } from "./components/UI.js"
|
||||
export * from "./components/Utils.js"
|
||||
|
||||
export * from "./types/enums/index.js"
|
||||
|
|
|
|||
5
src/types/enums/ArrayName.ts
Normal file
5
src/types/enums/ArrayName.ts
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
export enum ArrayName {
|
||||
CONTROLS = "controls",
|
||||
BINDINGS = "bindings",
|
||||
BUTTON_MAPPINGS = "button_mappings",
|
||||
}
|
||||
13
src/types/enums/Operation.ts
Normal file
13
src/types/enums/Operation.ts
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
export enum Operation {
|
||||
INSERT_BACK = "insert_back",
|
||||
INSERT_FRONT = "insert_front",
|
||||
INSERT_AFTER = "insert_after",
|
||||
INSERT_BEFORE = "insert_before",
|
||||
MOVE_BACK = "move_back",
|
||||
MOVE_FRONT = "move_front",
|
||||
MOVE_AFTER = "move_after",
|
||||
MOVE_BEFORE = "move_before",
|
||||
SWAP = "swap",
|
||||
REMOVE = "remove",
|
||||
REPLACE = "replace",
|
||||
}
|
||||
|
|
@ -3,22 +3,59 @@ import { AnimType } from "../../enums/AnimType.js"
|
|||
import { Easing } from "../../enums/Easing.js"
|
||||
import { Array2, Array3, Value } from "../value.js"
|
||||
|
||||
export interface Animation {
|
||||
anim_type?: Value<string | AnimType>
|
||||
export interface DurationAnimation {
|
||||
duration?: Value<number>
|
||||
next?: Value<string | AnimationKeyframe>
|
||||
}
|
||||
|
||||
export interface EasingAnimation extends DurationAnimation {
|
||||
easing?: Value<string | Easing>
|
||||
}
|
||||
|
||||
export interface NumberAnimation extends DurationAnimation, EasingAnimation {
|
||||
from: Value<number>
|
||||
to: Value<number>
|
||||
}
|
||||
|
||||
export interface Array2Animation extends DurationAnimation, EasingAnimation {
|
||||
from: Array2<number | string>
|
||||
to: Array2<number | string>
|
||||
}
|
||||
|
||||
export interface Array3Animation extends DurationAnimation, EasingAnimation {
|
||||
from: Array3<number | string>
|
||||
to: Array3<number | string>
|
||||
}
|
||||
|
||||
export interface AsepriteFlipBookAnimation {
|
||||
initial_uv?: Value<Array2<number>>
|
||||
}
|
||||
|
||||
export interface FlipbookAnimation extends AsepriteFlipBookAnimation {
|
||||
frame_count?: Value<number>
|
||||
frame_step?: Value<number>
|
||||
fps?: Value<number>
|
||||
easing?: Value<string | Easing>
|
||||
}
|
||||
|
||||
export interface AnimationValueType {
|
||||
[AnimType.OFFSET]: Array2Animation
|
||||
[AnimType.SIZE]: Array2Animation
|
||||
[AnimType.UV]: Array2Animation
|
||||
[AnimType.CLIP]: Array2Animation
|
||||
[AnimType.COLOR]: Array3Animation
|
||||
[AnimType.ALPHA]: NumberAnimation
|
||||
[AnimType.WAIT]: DurationAnimation
|
||||
[AnimType.FLIP_BOOK]: FlipbookAnimation
|
||||
[AnimType.ASEPRITE_FLIP_BOOK]: AsepriteFlipBookAnimation
|
||||
}
|
||||
|
||||
export interface AnimationPropertiesItem {
|
||||
destroy_at_end?: Value<string>
|
||||
play_event?: Value<string>
|
||||
end_event?: Value<string>
|
||||
start_event?: Value<string>
|
||||
reset_event?: Value<string>
|
||||
easing?: Value<string | Easing>
|
||||
from?: Value<number | string | Array3<number> | Array2<string>>
|
||||
to?: Value<number | string | Array3<number> | Array2<string>>
|
||||
initial_uv?: Value<Array2<number>>
|
||||
fps?: Value<number>
|
||||
frame_count?: Value<number>
|
||||
frame_step?: Value<number>
|
||||
|
||||
reversible?: Value<boolean>
|
||||
resettable?: Value<boolean>
|
||||
scale_from_starting_alpha?: Value<boolean>
|
||||
|
|
@ -26,3 +63,13 @@ export interface Animation {
|
|||
looping?: Value<boolean>
|
||||
wait_until_rendered_to_play?: Value<boolean>
|
||||
}
|
||||
|
||||
export interface KeyframeAnimationPropertiesItem extends AnimationPropertiesItem {
|
||||
next?: Value<string | AnimationKeyframe<AnimType>>
|
||||
}
|
||||
|
||||
export type KeyframeAnimationProperties<T extends keyof AnimationValueType> = Partial<AnimationValueType[T]> &
|
||||
KeyframeAnimationPropertiesItem
|
||||
|
||||
export type AnimationProperties<T extends keyof AnimationValueType> = Partial<AnimationValueType[T]> &
|
||||
AnimationPropertiesItem
|
||||
|
|
|
|||
|
|
@ -1,3 +1,6 @@
|
|||
export * as ElementProperties from "./element/index.js"
|
||||
export * as ComponentProperties from "./components.js"
|
||||
export * as Value from "./value.js"
|
||||
|
||||
export { ArrayName } from "../enums/ArrayName.js"
|
||||
export { Operation } from "../enums/Operation.js"
|
||||
|
|
|
|||
|
|
@ -7,6 +7,8 @@ import { ButtonId } from "../enums/ButtonId.js"
|
|||
import { MappingType } from "../enums/MappingType.js"
|
||||
import { InputModeCondition } from "../enums/InputModeCondition.js"
|
||||
import { Scope } from "../enums/Scope.js"
|
||||
import { ArrayName } from "../enums/ArrayName.js"
|
||||
import { Operation } from "../enums/Operation.js"
|
||||
|
||||
export type Variable = `$${string}`
|
||||
export type Binding = `#${string}`
|
||||
|
|
@ -34,6 +36,15 @@ export type BindingItem = {
|
|||
resolve_ancestor_scope?: Value<boolean>
|
||||
}
|
||||
|
||||
export type VariableItem = {
|
||||
requires: string
|
||||
[key: Variable]: Value<any>
|
||||
}
|
||||
|
||||
export type Variables = {
|
||||
[key: Variable | `(${string})`]: Record<Variable, unknown>
|
||||
}
|
||||
|
||||
export type FocusContainerCustom = Array<{
|
||||
other_focus_container_name?: Value<string>
|
||||
focus_id_inside?: Value<string>
|
||||
|
|
@ -56,3 +67,13 @@ export type ButtonMapping = {
|
|||
export type PropertyBags = {
|
||||
[key: Binding]: Value<any>
|
||||
}
|
||||
|
||||
export type ModificationItem = {
|
||||
array_name?: ArrayName
|
||||
control_name?: string
|
||||
where?: BindingItem | object
|
||||
target?: object
|
||||
target_control?: string
|
||||
value?: object | (object | BindingItem)[]
|
||||
operation?: Operation
|
||||
}
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
Reference in a new issue