Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/LiteGraphGlobal.ts
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ export class LiteGraphGlobal {
WIDGET_ADVANCED_OUTLINE_COLOR = "rgba(56, 139, 253, 0.8)"
WIDGET_TEXT_COLOR = "#DDD"
WIDGET_SECONDARY_TEXT_COLOR = "#999"
WIDGET_DISABLED_TEXT_COLOR = "#666"

LINK_COLOR = "#9A9"
EVENT_LINK_COLOR = "#A86"
Expand Down
57 changes: 57 additions & 0 deletions src/widgets/BaseSteppedWidget.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import { BaseWidget, type WidgetEventOptions } from "./BaseWidget"

/**
* Base class for widgets that have increment and decrement buttons.
*/
export abstract class BaseSteppedWidget extends BaseWidget {
/**
* Whether the widget can increment its value
* @returns `true` if the widget can increment its value, otherwise `false`
*/
abstract canIncrement(): boolean
/**
* Whether the widget can decrement its value
* @returns `true` if the widget can decrement its value, otherwise `false`
*/
abstract canDecrement(): boolean
/**
* Increment the value of the widget
* @param options The options for the widget event
*/
abstract incrementValue(options: WidgetEventOptions): void
/**
* Decrement the value of the widget
* @param options The options for the widget event
*/
abstract decrementValue(options: WidgetEventOptions): void

/**
* Draw the arrow buttons for the widget
* @param ctx The canvas rendering context
* @param margin The margin of the widget
* @param y The y position of the widget
* @param width The width of the widget
*/
drawArrowButtons(ctx: CanvasRenderingContext2D, margin: number, y: number, width: number) {
const { height, text_color, disabledTextColor } = this
const { arrowMargin, arrowWidth } = BaseWidget
const arrowTipX = margin + arrowMargin
const arrowInnerX = arrowTipX + arrowWidth

// Draw left arrow
ctx.fillStyle = this.canDecrement() ? text_color : disabledTextColor
ctx.beginPath()
ctx.moveTo(arrowInnerX, y + 5)
ctx.lineTo(arrowTipX, y + height * 0.5)
ctx.lineTo(arrowInnerX, y + height - 5)
ctx.fill()

// Draw right arrow
ctx.fillStyle = this.canIncrement() ? text_color : disabledTextColor
ctx.beginPath()
ctx.moveTo(width - arrowInnerX, y + 5)
ctx.lineTo(width - arrowTipX, y + height * 0.5)
ctx.lineTo(width - arrowInnerX, y + height - 5)
ctx.fill()
}
}
26 changes: 4 additions & 22 deletions src/widgets/BaseWidget.ts
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,10 @@ export abstract class BaseWidget implements IBaseWidget {
return LiteGraph.WIDGET_SECONDARY_TEXT_COLOR
}

get disabledTextColor() {
return LiteGraph.WIDGET_DISABLED_TEXT_COLOR
}

/**
* Draws the widget
* @param ctx The canvas context
Expand All @@ -97,28 +101,6 @@ export abstract class BaseWidget implements IBaseWidget {
*/
abstract drawWidget(ctx: CanvasRenderingContext2D, options: DrawWidgetOptions): void

drawArrowButtons(ctx: CanvasRenderingContext2D, margin: number, y: number, width: number) {
const { height } = this
const { arrowMargin, arrowWidth } = BaseWidget
const arrowTipX = margin + arrowMargin
const arrowInnerX = arrowTipX + arrowWidth

// Draw left arrow
ctx.fillStyle = this.text_color
ctx.beginPath()
ctx.moveTo(arrowInnerX, y + 5)
ctx.lineTo(arrowTipX, y + height * 0.5)
ctx.lineTo(arrowInnerX, y + height - 5)
ctx.fill()

// Draw right arrow
ctx.beginPath()
ctx.moveTo(width - arrowInnerX, y + 5)
ctx.lineTo(width - arrowTipX, y + height * 0.5)
ctx.lineTo(width - arrowInnerX, y + height - 5)
ctx.fill()
}

/**
* Handles the click event for the widget
* @param options The options for handling the click event
Expand Down
117 changes: 77 additions & 40 deletions src/widgets/ComboWidget.ts
Original file line number Diff line number Diff line change
@@ -1,21 +1,89 @@
import type { IComboWidget, IWidgetOptions } from "@/types/widgets"

import { LiteGraph } from "@/litegraph"
import { clamp, LiteGraph } from "@/litegraph"

import { BaseSteppedWidget } from "./BaseSteppedWidget"
import { BaseWidget, type DrawWidgetOptions, type WidgetEventOptions } from "./BaseWidget"

export class ComboWidget extends BaseWidget implements IComboWidget {
type Values = string[] | Record<string, string>

function toArray(values: Values): string[] {
return Array.isArray(values) ? values : Object.keys(values)
}

export class ComboWidget extends BaseSteppedWidget implements IComboWidget {
// IComboWidget properties
declare type: "combo"
declare value: string | number
declare options: IWidgetOptions<string>
// @ts-expect-error Workaround for Record<string, string> not being typed in IWidgetOptions
declare options: Omit<IWidgetOptions<string>, "values"> & { values: Values }

constructor(widget: IComboWidget) {
super(widget)
this.type = "combo"
this.value = widget.value
}

#getValues(): Values {
const { values } = this.options
if (values == null) throw new Error("[ComboWidget]: values is required")

return typeof values === "function"
// @ts-expect-error handle () => string[] type that is not typed in IWidgetOptions
? values(this, node)
: values
}

/**
* Checks if the value is {@link Array.at at} the given index in the combo list.
* @param index The index to check against
* @returns `true` if the value is at the given index, otherwise `false`.
*/
#valueIsAt(index: number): boolean {
const { values } = this.options
// If using legacy duck-typed method, just return true
if (typeof values === "function") return true

const valuesArray = toArray(values)
return this.value === valuesArray.at(index)
}

override canIncrement(): boolean {
return !this.#valueIsAt(-1)
}

override canDecrement(): boolean {
return !this.#valueIsAt(0)
}

override incrementValue(options: WidgetEventOptions): void {
this.#tryChangeValue(1, options)
}

override decrementValue(options: WidgetEventOptions): void {
this.#tryChangeValue(-1, options)
}

#tryChangeValue(delta: number, options: WidgetEventOptions): void {
const values = this.#getValues()
const indexedValues = toArray(values)

// avoids double click event
options.canvas.last_mouseclick = 0

const foundIndex = typeof values === "object"
? indexedValues.indexOf(String(this.value)) + delta
// @ts-expect-error handle non-string values
: indexedValues.indexOf(this.value) + delta

const index = clamp(foundIndex, 0, indexedValues.length - 1)

const value = Array.isArray(values)
? values[index]
: index
this.setValue(value, options)
}

/**
* Draws the widget
* @param ctx The canvas context
Expand Down Expand Up @@ -123,45 +191,14 @@ export class ComboWidget extends BaseWidget implements IComboWidget {
const width = this.width || node.size[0]

// Determine if clicked on left/right arrows
const delta = x < 40
? -1
: (x > width - 40
? 1
: 0)

// Get values
let values = this.options.values
if (typeof values === "function") {
// @ts-expect-error handle () => string[] type that is not typed in IWidgetOptions
values = values(this, node)
}
// @ts-expect-error Record<string, string> is not typed in IWidgetOptions
const values_list = Array.isArray(values) ? values : Object.keys(values)

// Handle left/right arrow clicks
if (delta) {
let index = -1
// avoids double click event
canvas.last_mouseclick = 0
index = typeof values === "object"
? values_list.indexOf(String(this.value)) + delta
// @ts-expect-error handle non-string values
: values_list.indexOf(this.value) + delta

if (index >= values_list.length) index = values_list.length - 1
if (index < 0) index = 0

this.setValue(
Array.isArray(values)
? values[index]
: index,
{ e, node, canvas },
)
return
}
if (x < 40) return this.decrementValue({ e, node, canvas })
if (x > width - 40) return this.incrementValue({ e, node, canvas })

// Otherwise, show dropdown menu
const values = this.#getValues()
const values_list = toArray(values)

// Handle center click - show dropdown menu
// @ts-expect-error Record<string, string> is not typed in IWidgetOptions
const text_values = values != values_list ? Object.values(values) : values
new LiteGraph.ContextMenu(text_values, {
scale: Math.max(1, canvas.ds.scale),
Expand Down
24 changes: 21 additions & 3 deletions src/widgets/NumberWidget.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,10 @@ import type { INumericWidget, IWidgetOptions } from "@/types/widgets"

import { getWidgetStep } from "@/utils/widget"

import { BaseSteppedWidget } from "./BaseSteppedWidget"
import { BaseWidget, type DrawWidgetOptions, type WidgetEventOptions } from "./BaseWidget"

export class NumberWidget extends BaseWidget implements INumericWidget {
export class NumberWidget extends BaseSteppedWidget implements INumericWidget {
// INumberWidget properties
declare type: "number"
declare value: number
Expand All @@ -16,6 +17,24 @@ export class NumberWidget extends BaseWidget implements INumericWidget {
this.value = widget.value
}

override canIncrement(): boolean {
const { max } = this.options
return max == null || this.value < max
}

override canDecrement(): boolean {
const { min } = this.options
return min == null || this.value > min
}

override incrementValue(options: WidgetEventOptions): void {
this.setValue(this.value + getWidgetStep(this.options), options)
}

override decrementValue(options: WidgetEventOptions): void {
this.setValue(this.value - getWidgetStep(this.options), options)
}

override setValue(value: number, options: WidgetEventOptions) {
let newValue = value
if (this.options.min != null && newValue < this.options.min) {
Expand Down Expand Up @@ -126,8 +145,7 @@ export class NumberWidget extends BaseWidget implements INumericWidget {
* Handles drag events for the number widget
* @param options The options for handling the drag event
*/
override onDrag(options: WidgetEventOptions) {
const { e, node, canvas } = options
override onDrag({ e, node, canvas }: WidgetEventOptions) {
const width = this.width || node.width
const x = e.canvasX - node.pos[0]
const delta = x < 40
Expand Down
1 change: 1 addition & 0 deletions test/__snapshots__/litegraph.test.ts.snap
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,7 @@ LiteGraphGlobal {
"VERTICAL_LAYOUT": "vertical",
"WIDGET_ADVANCED_OUTLINE_COLOR": "rgba(56, 139, 253, 0.8)",
"WIDGET_BGCOLOR": "#222",
"WIDGET_DISABLED_TEXT_COLOR": "#666",
"WIDGET_OUTLINE_COLOR": "#666",
"WIDGET_SECONDARY_TEXT_COLOR": "#999",
"WIDGET_TEXT_COLOR": "#DDD",
Expand Down
Loading