Implement ButtonWidget (#483)

This commit is contained in:
Chenlei Hu
2025-02-08 16:50:02 -05:00
committed by GitHub
parent dd1dae7d2f
commit ab14827f87
3 changed files with 96 additions and 17 deletions

View File

@@ -70,6 +70,7 @@ import { toClass } from "./utils/type"
import { NodeInputSlot, NodeOutputSlot, type ConnectionColorContext } from "./NodeSlot"
import { ComboWidget } from "./widgets/ComboWidget"
import { NumberWidget } from "./widgets/NumberWidget"
import { ButtonWidget } from "./widgets/ButtonWidget"
interface IShowSearchOptions {
node_to?: LGraphNode
@@ -2564,9 +2565,11 @@ export class LGraphCanvas implements ConnectionColorContext {
switch (widget.type) {
case "button":
pointer.onClick = () => {
widget.callback?.(widget, this, node, pos, e)
widget.clicked = true
this.dirty_canvas = true
toClass(ButtonWidget, widget).onClick({
e,
node,
canvas: this,
})
}
break
case "slider": {
@@ -5838,20 +5841,7 @@ export class LGraphCanvas implements ConnectionColorContext {
switch (w.type) {
case "button":
ctx.fillStyle = background_color
if (w.clicked) {
ctx.fillStyle = "#AAA"
w.clicked = false
this.dirty_canvas = true
}
ctx.fillRect(margin, y, widget_width - margin * 2, H)
if (show_text && !w.disabled)
ctx.strokeRect(margin, y, widget_width - margin * 2, H)
if (show_text) {
ctx.textAlign = "center"
ctx.fillStyle = text_color
ctx.fillText(w.label || w.name, widget_width * 0.5, y + H * 0.7)
}
toClass(ButtonWidget, w).drawWidget(ctx, { y, width: widget_width, show_text, margin })
break
case "toggle":
toClass(BooleanWidget, w).drawWidget(ctx, { y, width: widget_width, show_text, margin })

View File

@@ -35,6 +35,7 @@ import { LLink } from "./LLink"
import { BooleanWidget } from "./widgets/BooleanWidget"
import { ComboWidget } from "./widgets/ComboWidget"
import { NumberWidget } from "./widgets/NumberWidget"
import { ButtonWidget } from "./widgets/ButtonWidget"
import { NodeInputSlot, NodeOutputSlot } from "./NodeSlot"
export type NodeId = number | string
@@ -1679,6 +1680,9 @@ export class LGraphNode implements Positionable, IPinnable {
case "number":
widget = new NumberWidget(custom_widget)
break
case "button":
widget = new ButtonWidget(custom_widget)
break
default:
widget = custom_widget
}

View File

@@ -0,0 +1,85 @@
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 ButtonWidget extends BaseWidget implements IStringWidget {
// IStringWidget properties
declare type: "button"
declare value: string
declare options: IWidgetOptions<boolean>
constructor(widget: IStringWidget) {
super(widget)
this.type = "button"
this.value = widget.value ?? ""
}
/**
* 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
// Draw button background
ctx.fillStyle = this.background_color
if (this.clicked) {
ctx.fillStyle = "#AAA"
this.clicked = false
}
ctx.fillRect(margin, y, widget_width - margin * 2, H)
// Draw button outline if not disabled
if (show_text && !this.disabled) {
ctx.strokeStyle = this.outline_color
ctx.strokeRect(margin, y, widget_width - margin * 2, H)
}
// Draw button text
if (show_text) {
ctx.textAlign = "center"
ctx.fillStyle = this.text_color
ctx.fillText(
this.label || this.name || "",
widget_width * 0.5,
y + H * 0.7,
)
}
// 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
const pos = canvas.graph_mouse
// Set clicked state and mark canvas as dirty
this.clicked = true
canvas.setDirty(true)
// Call the callback with widget instance and other context
this.callback?.(this, canvas, node, pos, e)
}
}