Implement TextWidget (#484)

This commit is contained in:
Chenlei Hu
2025-02-08 17:01:54 -05:00
committed by GitHub
parent ab14827f87
commit 2d688a896d
3 changed files with 112 additions and 36 deletions

View File

@@ -71,6 +71,7 @@ import { NodeInputSlot, NodeOutputSlot, type ConnectionColorContext } from "./No
import { ComboWidget } from "./widgets/ComboWidget"
import { NumberWidget } from "./widgets/NumberWidget"
import { ButtonWidget } from "./widgets/ButtonWidget"
import { TextWidget } from "./widgets/TextWidget"
interface IShowSearchOptions {
node_to?: LGraphNode
@@ -2625,13 +2626,11 @@ export class LGraphCanvas implements ConnectionColorContext {
break
case "string":
case "text":
pointer.onClick = () => this.prompt(
"Value",
widget.value,
(v: any) => setWidgetValue(this, node, widget, v),
pointer.onClick = () => toClass(TextWidget, widget).onClick({
e,
widget.options ? widget.options.multiline : false,
)
node,
canvas: this,
})
break
default:
// Legacy custom widget callback
@@ -5898,36 +5897,7 @@ export class LGraphCanvas implements ConnectionColorContext {
break
case "string":
case "text":
ctx.textAlign = "left"
ctx.strokeStyle = outline_color
ctx.fillStyle = background_color
ctx.beginPath()
if (show_text)
ctx.roundRect(margin, y, widget_width - margin * 2, H, [H * 0.5])
else
ctx.rect(margin, y, widget_width - margin * 2, H)
ctx.fill()
if (show_text) {
if (!w.disabled) ctx.stroke()
ctx.save()
ctx.beginPath()
ctx.rect(margin, y, widget_width - margin * 2, H)
ctx.clip()
// ctx.stroke();
ctx.fillStyle = secondary_text_color
const label = w.label || w.name
if (label != null) ctx.fillText(label, margin * 2, y + H * 0.7)
ctx.fillStyle = text_color
ctx.textAlign = "right"
ctx.fillText(
String(w.value).substr(0, 30),
widget_width - margin * 2,
y + H * 0.7,
) // 30 chars max
ctx.restore()
}
toClass(TextWidget, w).drawWidget(ctx, { y, width: widget_width, show_text, margin })
break
// Custom widgets
default:

View File

@@ -37,6 +37,7 @@ import { ComboWidget } from "./widgets/ComboWidget"
import { NumberWidget } from "./widgets/NumberWidget"
import { ButtonWidget } from "./widgets/ButtonWidget"
import { NodeInputSlot, NodeOutputSlot } from "./NodeSlot"
import { TextWidget } from "./widgets/TextWidget"
export type NodeId = number | string
@@ -1683,6 +1684,10 @@ export class LGraphNode implements Positionable, IPinnable {
case "button":
widget = new ButtonWidget(custom_widget)
break
case "text":
case "string":
widget = new TextWidget(custom_widget)
break
default:
widget = custom_widget
}

101
src/widgets/TextWidget.ts Normal file
View File

@@ -0,0 +1,101 @@
import type { IStringWidget, IWidgetOptions } from "@/types/widgets"
import { BaseWidget } from "./BaseWidget"
import type { LGraphNode } from "@/LGraphNode"
import type { CanvasMouseEvent } from "@/types/events"
import type { LGraphCanvas } from "@/LGraphCanvas"
export class TextWidget extends BaseWidget implements IStringWidget {
// IStringWidget properties
declare type: "text" | "string"
declare value: string
declare options: IWidgetOptions<string>
constructor(widget: IStringWidget) {
super(widget)
this.type = widget.type as "text" | "string"
this.value = widget.value?.toString() ?? ""
}
/**
* Draws the widget
* @param ctx - The canvas context
* @param options - The options for drawing the widget
*/
override drawWidget(ctx: CanvasRenderingContext2D, options: {
y: number
width: number
show_text?: boolean
margin?: number
}) {
// Store original context attributes
const originalTextAlign = ctx.textAlign
const originalStrokeStyle = ctx.strokeStyle
const originalFillStyle = ctx.fillStyle
const { y, width, show_text = true, margin = 15 } = options
const widget_width = width
const H = this.height
ctx.textAlign = "left"
ctx.strokeStyle = this.outline_color
ctx.fillStyle = this.background_color
ctx.beginPath()
if (show_text)
ctx.roundRect(margin, y, widget_width - margin * 2, H, [H * 0.5])
else
ctx.rect(margin, y, widget_width - margin * 2, H)
ctx.fill()
if (show_text) {
if (!this.disabled) ctx.stroke()
ctx.save()
ctx.beginPath()
ctx.rect(margin, y, widget_width - margin * 2, H)
ctx.clip()
// Draw label
ctx.fillStyle = this.secondary_text_color
const label = this.label || this.name
if (label != null) {
ctx.fillText(label, margin * 2, y + H * 0.7)
}
// Draw value
ctx.fillStyle = this.text_color
ctx.textAlign = "right"
ctx.fillText(
String(this.value).substr(0, 30), // 30 chars max
widget_width - margin * 2,
y + H * 0.7,
)
ctx.restore()
}
// Restore original context attributes
ctx.textAlign = originalTextAlign
ctx.strokeStyle = originalStrokeStyle
ctx.fillStyle = originalFillStyle
}
override onClick(options: {
e: CanvasMouseEvent
node: LGraphNode
canvas: LGraphCanvas
}) {
const { e, node, canvas } = options
// Show prompt dialog for text input
canvas.prompt(
"Value",
this.value,
(v: string) => {
if (v !== null) {
this.setValue(v, { e, node, canvas })
}
},
e,
this.options?.multiline ?? false,
)
}
}