mirror of
https://github.com/barsdeveloper/ueblueprint.git
synced 2026-02-03 23:55:04 +08:00
* Fix node reference when changing elements * Fix ScriptVariables parsing * Fix invariant text and niagara types * Niagara convert nodes * Move node tests to own files * More Niagara tests * Niagara float and smaller fixes * More Decoding * More decoding * WIP * Float is real * WIP * More types and colors * Test case and small polish * WIP * WIP * Fix niagara script variables merging * Fix Niagara variables * Fixing mirrored ExportPath * Fix Export paths name adjustments * Simplify arc calculation * Simplify a bit arc calculation * source / destionation => origin / target * Minor refactoring * Fix switched link position * Rename some properties for uniformity * Fix input escape * Simplify test * About window * Dialog backdrop style * About dialog touches * Remove dependency and minot improvement * Light mode * Fix link location and css small improvement * Link direction and minor fixes * Some minor fixes and refactoring * Refactoring WIP * Shorting repetitive bits * More tests * Simplify linking tests
305 lines
9.9 KiB
JavaScript
Executable File
305 lines
9.9 KiB
JavaScript
Executable File
import Configuration from "../Configuration.js"
|
|
import pinTemplate from "../decoding/pinTemplate.js"
|
|
import BooleanEntity from "../entity/BooleanEntity.js"
|
|
import GuidEntity from "../entity/GuidEntity.js"
|
|
import LinearColorEntity from "../entity/LinearColorEntity.js"
|
|
import PinEntity from "../entity/PinEntity.js"
|
|
import PinReferenceEntity from "../entity/PinReferenceEntity.js"
|
|
import SymbolEntity from "../entity/SymbolEntity.js"
|
|
import PinTemplate from "../template/pin/PinTemplate.js"
|
|
import ElementFactory from "./ElementFactory.js"
|
|
import IElement from "./IElement.js"
|
|
|
|
/**
|
|
* @template {IEntity} T
|
|
* @extends {IElement<PinEntity<T>, PinTemplate>}
|
|
*/
|
|
export default class PinElement extends IElement {
|
|
|
|
static properties = {
|
|
pinId: {
|
|
type: GuidEntity,
|
|
converter: {
|
|
fromAttribute: (value, type) => value
|
|
? GuidEntity.grammar.parse(value)
|
|
: null,
|
|
toAttribute: (value, type) => value?.toString(),
|
|
},
|
|
attribute: "data-id",
|
|
reflect: true,
|
|
},
|
|
pinType: {
|
|
type: String,
|
|
attribute: "data-type",
|
|
reflect: true,
|
|
},
|
|
advancedView: {
|
|
type: String,
|
|
attribute: "data-advanced-view",
|
|
reflect: true,
|
|
},
|
|
color: {
|
|
type: LinearColorEntity,
|
|
converter: {
|
|
fromAttribute: (value, type) => value
|
|
? LinearColorEntity.getLinearColorFromAnyFormat().parse(value)
|
|
: null,
|
|
/** @param {LinearColorEntity} value */
|
|
toAttribute: (value, type) => value?.toString() ?? "",
|
|
},
|
|
attribute: "data-color",
|
|
reflect: true,
|
|
},
|
|
defaultValue: {
|
|
type: String,
|
|
attribute: false,
|
|
},
|
|
isLinked: {
|
|
type: Boolean,
|
|
converter: BooleanEntity.booleanConverter,
|
|
attribute: "data-linked",
|
|
reflect: true,
|
|
},
|
|
pinDirection: {
|
|
type: String,
|
|
attribute: "data-direction",
|
|
reflect: true,
|
|
},
|
|
connectable: {
|
|
type: Boolean,
|
|
converter: BooleanEntity.booleanConverter,
|
|
attribute: "data-connectable",
|
|
reflect: true,
|
|
}
|
|
}
|
|
|
|
/** @type {NodeElement} */
|
|
nodeElement
|
|
|
|
static newObject(
|
|
entity = new PinEntity(),
|
|
template = /** @type {PinTemplate} */(new (pinTemplate(entity))()),
|
|
nodeElement = undefined
|
|
) {
|
|
const result = new PinElement()
|
|
result.initialize(entity, template, nodeElement)
|
|
return result
|
|
}
|
|
|
|
initialize(
|
|
entity = /** @type {PinEntity<T>} */(new PinEntity()),
|
|
template = /** @type {PinTemplate} */(new (pinTemplate(entity))()),
|
|
nodeElement = undefined
|
|
) {
|
|
this.nodeElement = nodeElement
|
|
this.advancedView = entity.bAdvancedView?.valueOf()
|
|
this.isLinked = false
|
|
this.connectable = !entity.bNotConnectable?.valueOf()
|
|
super.initialize(entity, template)
|
|
this.pinId = this.entity.PinId
|
|
this.updateType()
|
|
this.defaultValue = this.entity.getDefaultValue()
|
|
this.pinDirection = entity.isInput() ? "input" : entity.isOutput() ? "output" : "hidden"
|
|
/** @type {LinearColorEntity} */
|
|
this.color = PinElement.properties.color.converter.fromAttribute(this.entity.pinColor().toString())
|
|
}
|
|
|
|
setup() {
|
|
super.setup()
|
|
this.nodeElement = this.closest("ueb-node")
|
|
}
|
|
|
|
updateType() {
|
|
this.pinType = this.entity.getType()
|
|
const newColor = PinElement.properties.color.converter.fromAttribute(this.entity.pinColor().toString())
|
|
if (!this.color?.equals(newColor)) {
|
|
this.color = newColor
|
|
this.acknowledgeUpdate()
|
|
}
|
|
}
|
|
|
|
createPinReference() {
|
|
return new PinReferenceEntity(new SymbolEntity(this.nodeElement.getNodeName()), this.getPinId())
|
|
}
|
|
|
|
getPinId() {
|
|
return this.entity.PinId
|
|
}
|
|
|
|
getPinName() {
|
|
return this.entity.PinName?.toString() ?? ""
|
|
}
|
|
|
|
getPinDisplayName() {
|
|
return this.entity.pinTitle()
|
|
}
|
|
|
|
/** @param {PinElement} pin */
|
|
#traverseKnots(pin) {
|
|
while (pin?.isKnot()) {
|
|
const pins = pin.nodeElement.getPinElements()
|
|
pin = pin === pins[0] ? pins[1] : pins[0]
|
|
pin = pin.isLinked ? this.blueprint.getPin(pin.getLinks()[0]) : null
|
|
}
|
|
return pin?.isKnot() ? undefined : pin
|
|
}
|
|
|
|
isInput(ignoreKnots = false) {
|
|
/** @type {PinElement} */
|
|
let result = this
|
|
if (ignoreKnots) {
|
|
return this.#traverseKnots(result)?.isInput()
|
|
}
|
|
return result.entity.isInput()
|
|
}
|
|
|
|
/** @returns {boolean} True when the pin is the input part of a knot that can switch direction */
|
|
isInputLoosely() {
|
|
return this.isInput(false) && this.isInput(true) === undefined
|
|
}
|
|
|
|
/** @returns {boolean} True when the pin is input and if it is a knot it appears input */
|
|
isInputVisually() {
|
|
const template = /** @type {KnotNodeTemplate} */(this.nodeElement.template)
|
|
const isKnot = this.isKnot()
|
|
return isKnot && this.isInput() != template.switchDirectionsVisually
|
|
|| !isKnot && this.isInput()
|
|
}
|
|
|
|
isOutput(ignoreKnots = false) {
|
|
/** @type {PinElement} */
|
|
let result = this
|
|
if (ignoreKnots) {
|
|
return this.#traverseKnots(result)?.isOutput()
|
|
}
|
|
return result.entity.isOutput()
|
|
}
|
|
|
|
/** @returns {boolean} True when the pin is the output part of a knot that can switch direction */
|
|
isOutputLoosely() {
|
|
return this.isOutput(false) && this.isOutput(true) === undefined
|
|
}
|
|
|
|
/** @returns {boolean} True when the pin is output and if it is a knot it appears output */
|
|
isOutputVisually() {
|
|
const template = /** @type {KnotNodeTemplate} */(this.nodeElement.template)
|
|
const isKnot = this.isKnot()
|
|
return isKnot && this.isOutput() != template.switchDirectionsVisually
|
|
|| !isKnot && this.isOutput()
|
|
}
|
|
|
|
|
|
/** @returns {value is InstanceType<PinElement<>>} */
|
|
isKnot() {
|
|
return this.nodeElement?.getType() == Configuration.paths.knot
|
|
}
|
|
|
|
getLinkLocation(oppositeDirection = false) {
|
|
return this.template.getLinkLocation(oppositeDirection)
|
|
}
|
|
|
|
getNodeElement() {
|
|
return this.nodeElement
|
|
}
|
|
|
|
getLinks() {
|
|
return this.entity.LinkedTo?.valueOf() ?? []
|
|
}
|
|
|
|
getDefaultValue(maybeCreate = false) {
|
|
return this.defaultValue = this.entity.getDefaultValue(maybeCreate)
|
|
}
|
|
|
|
/** @param {T} value */
|
|
setDefaultValue(value) {
|
|
this.entity.DefaultValue = value
|
|
this.defaultValue = value
|
|
if (this.entity.recomputesNodeTitleOnChange) {
|
|
this.nodeElement?.computeNodeDisplayName()
|
|
}
|
|
}
|
|
|
|
/** @param {IElement[]} nodesWhitelist */
|
|
sanitizeLinks(nodesWhitelist = []) {
|
|
this.entity.LinkedTo = new (PinEntity.attributes.LinkedTo)(
|
|
this.entity.LinkedTo?.valueOf().filter(pinReference => {
|
|
let pin = this.blueprint.getPin(pinReference)
|
|
if (pin) {
|
|
if (nodesWhitelist.length && !nodesWhitelist.includes(pin.nodeElement)) {
|
|
return false
|
|
}
|
|
let link = this.blueprint.getLink(this, pin)
|
|
if (!link) {
|
|
link = /** @type {LinkElementConstructor} */(ElementFactory.getConstructor("ueb-link"))
|
|
.newObject(this, pin)
|
|
this.blueprint.addGraphElement(link)
|
|
}
|
|
}
|
|
return pin
|
|
})
|
|
)
|
|
this.isLinked = this.entity.isLinked()
|
|
}
|
|
|
|
/** @param {PinElement} targetPinElement */
|
|
linkTo(targetPinElement) {
|
|
const pinReference = this.createPinReference()
|
|
if (
|
|
this.isLinked
|
|
&& this.entity.isExecution()
|
|
&& this.isOutput(true)
|
|
&& this.getLinks().some(ref => !pinReference.equals(ref))
|
|
) {
|
|
if (this.isKnot()) {
|
|
|
|
}
|
|
this.unlinkFromAll()
|
|
}
|
|
if (this.entity.linkTo(targetPinElement.getNodeElement().getNodeName(), targetPinElement.entity)) {
|
|
this.isLinked = this.entity.isLinked()
|
|
if (this.entity.recomputesNodeTitleOnChange) {
|
|
this.nodeElement?.computeNodeDisplayName()
|
|
}
|
|
}
|
|
}
|
|
|
|
/** @param {PinElement} targetPinElement */
|
|
unlinkFrom(targetPinElement, removeLink = true) {
|
|
if (this.entity.unlinkFrom(targetPinElement.getNodeElement().getNodeName(), targetPinElement.entity)) {
|
|
this.isLinked = this.entity.isLinked()
|
|
if (removeLink) {
|
|
this.blueprint.getLink(this, targetPinElement)?.remove() // Might be called after the link is removed
|
|
}
|
|
if (this.entity.recomputesNodeTitleOnChange) {
|
|
this.nodeElement?.computeNodeDisplayName()
|
|
}
|
|
}
|
|
}
|
|
|
|
unlinkFromAll() {
|
|
this.getLinks().map(ref => this.blueprint.getPin(ref)).forEach(pin => this.unlinkFrom(pin))
|
|
const isLinked = false
|
|
}
|
|
|
|
/**
|
|
* @param {PinElement} originalPinElement
|
|
* @param {PinReferenceEntity} newReference
|
|
*/
|
|
redirectLink(originalPinElement, newReference) {
|
|
const index = this.getLinks().findIndex(pinReference =>
|
|
pinReference.objectName.toString() == originalPinElement.getNodeElement().getNodeName()
|
|
&& pinReference.pinGuid.toString() == originalPinElement.entity.PinId.toString()
|
|
)
|
|
if (index >= 0) {
|
|
this.entity.LinkedTo.valueOf()[index] = newReference
|
|
return true
|
|
}
|
|
return false
|
|
}
|
|
|
|
acknowledgeUpdate() {
|
|
let event = new CustomEvent(Configuration.pinUpdateEventName)
|
|
this.dispatchEvent(event)
|
|
}
|
|
}
|