diff --git a/packages/design-system/src/icons/nodeSlot2.svg b/packages/design-system/src/icons/nodeSlot2.svg new file mode 100644 index 0000000000..cc12805700 --- /dev/null +++ b/packages/design-system/src/icons/nodeSlot2.svg @@ -0,0 +1,19 @@ + + + + + + + + + + + + + diff --git a/packages/design-system/src/icons/nodeSlot3.svg b/packages/design-system/src/icons/nodeSlot3.svg new file mode 100644 index 0000000000..fc94a178bb --- /dev/null +++ b/packages/design-system/src/icons/nodeSlot3.svg @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + diff --git a/src/lib/litegraph/src/node/NodeSlot.ts b/src/lib/litegraph/src/node/NodeSlot.ts index e7a2de3826..4e17069b28 100644 --- a/src/lib/litegraph/src/node/NodeSlot.ts +++ b/src/lib/litegraph/src/node/NodeSlot.ts @@ -30,6 +30,8 @@ export interface IDrawOptions { highlight?: boolean } +const ROTATION_OFFSET = -Math.PI / 2 + /** Shared base class for {@link LGraphNode} input and output slots. */ export abstract class NodeSlot extends SlotBase implements INodeSlot { pos?: Point @@ -130,6 +132,7 @@ export abstract class NodeSlot extends SlotBase implements INodeSlot { slot_type === SlotType.Array ? SlotShape.Grid : this.shape ) as SlotShape + ctx.save() ctx.beginPath() let doFill = true @@ -163,16 +166,52 @@ export abstract class NodeSlot extends SlotBase implements INodeSlot { if (lowQuality) { ctx.rect(pos[0] - 4, pos[1] - 4, 8, 8) } else { - let radius: number if (slot_shape === SlotShape.HollowCircle) { + const path = new Path2D() + path.arc(pos[0], pos[1], 10, 0, Math.PI * 2) + path.arc(pos[0], pos[1], highlight ? 2.5 : 1.5, 0, Math.PI * 2) + ctx.clip(path, 'evenodd') + } + const radius = highlight ? 5 : 4 + const typesSet = new Set( + `${this.type}` + .split(',') + .map( + this.isConnected + ? (type) => colorContext.getConnectedColor(type) + : (type) => colorContext.getDisconnectedColor(type) + ) + ) + const types = [...typesSet].slice(0, 3) + if (types.length > 1) { doFill = false - doStroke = true - ctx.lineWidth = 3 - ctx.strokeStyle = ctx.fillStyle - radius = highlight ? 4 : 3 - } else { - // Normal circle - radius = highlight ? 5 : 4 + const arcLen = (Math.PI * 2) / types.length + types.forEach((type, idx) => { + ctx.moveTo(pos[0], pos[1]) + ctx.fillStyle = type + ctx.arc( + pos[0], + pos[1], + radius, + arcLen * idx + ROTATION_OFFSET, + Math.PI * 2 + ROTATION_OFFSET + ) + ctx.fill() + ctx.beginPath() + }) + //add stroke dividers + ctx.save() + ctx.strokeStyle = 'black' + ctx.lineWidth = 0.5 + types.forEach((_, idx) => { + ctx.moveTo(pos[0], pos[1]) + const xOffset = Math.cos(arcLen * idx + ROTATION_OFFSET) * radius + const yOffset = Math.sin(arcLen * idx + ROTATION_OFFSET) * radius + ctx.lineTo(pos[0] + xOffset, pos[1] + yOffset) + }) + ctx.stroke() + ctx.restore() + ctx.beginPath() } ctx.arc(pos[0], pos[1], radius, 0, Math.PI * 2) } @@ -180,6 +219,7 @@ export abstract class NodeSlot extends SlotBase implements INodeSlot { if (doFill) ctx.fill() if (!lowQuality && doStroke) ctx.stroke() + ctx.restore() // render slot label const hideLabel = lowQuality || this.isWidgetInputSlot diff --git a/src/renderer/extensions/vueNodes/components/InputSlot.vue b/src/renderer/extensions/vueNodes/components/InputSlot.vue index e32be802d4..9205768e67 100644 --- a/src/renderer/extensions/vueNodes/components/InputSlot.vue +++ b/src/renderer/extensions/vueNodes/components/InputSlot.vue @@ -20,13 +20,13 @@ { return false }) -const slotColor = computed(() => { - if (hasSlotError.value) { - return 'var(--color-error)' - } - return getSlotColor(props.slotData.type) -}) - const { state: dragState } = useSlotLinkDragUIState() const slotKey = computed(() => getSlotKey(props.nodeId ?? '', props.index, true) diff --git a/src/renderer/extensions/vueNodes/components/OutputSlot.vue b/src/renderer/extensions/vueNodes/components/OutputSlot.vue index a05b969fa4..9a7506130f 100644 --- a/src/renderer/extensions/vueNodes/components/OutputSlot.vue +++ b/src/renderer/extensions/vueNodes/components/OutputSlot.vue @@ -10,8 +10,8 @@ @@ -22,7 +22,6 @@ import { computed, onErrorCaptured, ref, watchEffect } from 'vue' import type { ComponentPublicInstance } from 'vue' import { useErrorHandling } from '@/composables/useErrorHandling' -import { getSlotColor } from '@/constants/slotColors' import type { INodeSlot } from '@/lib/litegraph/src/litegraph' import { useSlotLinkDragUIState } from '@/renderer/core/canvas/links/slotLinkDragUIState' import { getSlotKey } from '@/renderer/core/layout/slots/slotIdentifier' @@ -67,9 +66,6 @@ onErrorCaptured((error) => { return false }) -// Get slot color based on type -const slotColor = computed(() => getSlotColor(props.slotData.type)) - const { state: dragState } = useSlotLinkDragUIState() const slotKey = computed(() => getSlotKey(props.nodeId ?? '', props.index, false) diff --git a/src/renderer/extensions/vueNodes/components/SlotConnectionDot.vue b/src/renderer/extensions/vueNodes/components/SlotConnectionDot.vue index 273c6ea503..3921128b02 100644 --- a/src/renderer/extensions/vueNodes/components/SlotConnectionDot.vue +++ b/src/renderer/extensions/vueNodes/components/SlotConnectionDot.vue @@ -1,20 +1,45 @@