diff --git a/src/LGraphCanvas.ts b/src/LGraphCanvas.ts index b46d10c19..1caf88472 100644 --- a/src/LGraphCanvas.ts +++ b/src/LGraphCanvas.ts @@ -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 }) diff --git a/src/LGraphNode.ts b/src/LGraphNode.ts index eefbdbde4..2324166ba 100644 --- a/src/LGraphNode.ts +++ b/src/LGraphNode.ts @@ -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 } diff --git a/src/widgets/ButtonWidget.ts b/src/widgets/ButtonWidget.ts new file mode 100644 index 000000000..f7d33726e --- /dev/null +++ b/src/widgets/ButtonWidget.ts @@ -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 + + 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) + } +}