Group update - titlebar, resize, config (#270)

* Backport group header from frontend

* nit - TS types & redundant code

* Refactor - simplify group resize

* Fix group resize can be inverted

* Move group resize check to group class

* Add config for group padding & default colour

* nit - Remove redundant code
This commit is contained in:
filtered
2024-11-04 10:27:41 +11:00
committed by GitHub
parent 3be1937c41
commit ce8d39f650
2 changed files with 64 additions and 38 deletions

View File

@@ -260,6 +260,9 @@ export class LGraphCanvas {
selected_nodes: Dictionary<LGraphNode> = {}
/** All selected nodes, groups, and reroutes */
selectedItems: Set<Positionable> = new Set()
/** The group currently being resized. */
resizingGroup: LGraphGroup | null = null
/** @deprecated See {@link LGraphCanvas.selectedItems} */
selected_group: LGraphGroup | null = null
visible_nodes: LGraphNode[] = []
node_dragged?: LGraphNode
@@ -299,6 +302,7 @@ export class LGraphCanvas {
block_click?: boolean
last_click_position?: Point
resizing_node?: LGraphNode
/** @deprecated See {@link LGraphCanvas.resizingGroup} */
selected_group_resizing?: boolean
last_mouse_dragging: boolean
onMouseDown: (arg0: CanvasMouseEvent) => void
@@ -1253,7 +1257,6 @@ export class LGraphCanvas {
this.dragging_rectangle = null
this.selected_nodes = {}
/** The group currently being resized */
this.selected_group = null
this.visible_nodes = []
@@ -1428,13 +1431,14 @@ export class LGraphCanvas {
if (!skip_events) this.bindEvents()
}
//used in some events to capture them
_doNothing(e: Event) {
/** Captures an event and prevents default - returns false. */
_doNothing(e: Event): boolean {
//console.log("pointerevents: _doNothing "+e.type);
e.preventDefault()
return false
}
_doReturnTrue(e: Event) {
/** Captures an event and prevents default - returns true. */
_doReturnTrue(e: Event): boolean {
e.preventDefault()
return true
}
@@ -1722,7 +1726,6 @@ export class LGraphCanvas {
let node = this.graph.getNodeOnPos(e.canvasX, e.canvasY, this.visible_nodes)
let skip_action = false
const now = LiteGraph.getTime()
const is_primary = (e.isPrimary === undefined || !e.isPrimary)
const is_double_click = (now - this.last_mouseclick < 300)
this.mouse[0] = e.clientX
this.mouse[1] = e.clientY
@@ -1730,7 +1733,7 @@ export class LGraphCanvas {
this.graph_mouse[1] = e.canvasY
this.last_click_position = [this.mouse[0], this.mouse[1]]
this.pointer_is_double = this.pointer_is_down && is_primary
this.pointer_is_double = this.pointer_is_down && e.isPrimary
this.pointer_is_down = true
this.canvas.focus()
@@ -2057,11 +2060,8 @@ export class LGraphCanvas {
this.ctx.lineWidth = lineWidth
}
this.selected_group = this.graph.getGroupOnPos(e.canvasX, e.canvasY)
this.selected_group_resizing = false
const group = this.selected_group
const group = this.graph.getGroupOnPos(e.canvasX, e.canvasY)
this.selected_group = group
if (group && !this.read_only) {
if (e.ctrlKey) {
this.dragging_rectangle = null
@@ -2069,7 +2069,7 @@ export class LGraphCanvas {
const dist = distance([e.canvasX, e.canvasY], [group.pos[0] + group.size[0], group.pos[1] + group.size[1]])
if (dist * this.ds.scale < 10) {
this.selected_group_resizing = true
this.resizingGroup = group
} else {
const f = group.font_size || LiteGraph.DEFAULT_GROUP_FONT_SIZE
const headerHeight = f * 1.4
@@ -2086,7 +2086,7 @@ export class LGraphCanvas {
this.emitEvent({
subType: "group-double-click",
originalEvent: e,
group: this.selected_group,
group,
})
}
} else if (is_double_click && !this.read_only) {
@@ -2259,19 +2259,20 @@ export class LGraphCanvas {
//get node over
const node = this.graph.getNodeOnPos(e.canvasX, e.canvasY, this.visible_nodes)
const { resizingGroup } = this
if (this.dragging_rectangle) {
this.dragging_rectangle[2] = e.canvasX - this.dragging_rectangle[0]
this.dragging_rectangle[3] = e.canvasY - this.dragging_rectangle[1]
this.dirty_canvas = true
}
else if (this.selected_group_resizing && !this.read_only) {
//moving/resizing a group
this.selected_group.resize(
e.canvasX - this.selected_group.pos[0],
e.canvasY - this.selected_group.pos[1]
else if (resizingGroup && !this.read_only) {
// Resizing a group
const resized = resizingGroup.resize(
e.canvasX - resizingGroup.pos[0],
e.canvasY - resizingGroup.pos[1]
)
this.dirty_bgcanvas = true
if (resized) this.dirty_bgcanvas = true
} else if (this.dragging_canvas) {
this.ds.offset[0] += delta[0] / this.ds.scale
this.ds.offset[1] += delta[1] / this.ds.scale
@@ -2494,6 +2495,7 @@ export class LGraphCanvas {
this.block_click &&= false
if (e.which == 1) {
this.resizingGroup = null
if (this.node_widget) {
this.processNodeWidgets(this.node_widget[0], this.graph_mouse, e)
@@ -2501,12 +2503,7 @@ export class LGraphCanvas {
//left button
this.node_widget = null
if (this.selected_group) {
this.dirty_canvas = true
this.selected_group = null
}
this.selected_group_resizing = false
this.selected_group = null
this.isDragging = false
let node = this.graph.getNodeOnPos(

View File

@@ -12,12 +12,18 @@ export interface IGraphGroupFlags extends Record<string, unknown> {
}
export class LGraphGroup implements Positionable {
static minWidth = 140
static minHeight = 80
static resizeLength = 10
static padding = 4
static defaultColour = '#335'
id: number
color: string
title: string
font?: string
font_size: number = LiteGraph.DEFAULT_GROUP_FONT || 24
_bounding: Float32Array = new Float32Array([10, 10, 140, 80])
_bounding: Float32Array = new Float32Array([10, 10, LGraphGroup.minWidth, LGraphGroup.minHeight])
_pos: Point = this._bounding.subarray(0, 2)
_size: Size = this._bounding.subarray(2, 4)
/** @deprecated See {@link _children} */
@@ -54,10 +60,11 @@ export class LGraphGroup implements Positionable {
set size(v) {
if (!v || v.length < 2) return
this._size[0] = Math.max(140, v[0])
this._size[1] = Math.max(80, v[1])
this._size[0] = Math.max(LGraphGroup.minWidth, v[0])
this._size[1] = Math.max(LGraphGroup.minHeight, v[1])
}
get boundingRect() {
return this._bounding
}
@@ -113,26 +120,37 @@ export class LGraphGroup implements Positionable {
* @param {CanvasRenderingContext2D} ctx
*/
draw(graphCanvas: LGraphCanvas, ctx: CanvasRenderingContext2D): void {
const padding = 4
const { padding, resizeLength, defaultColour } = LGraphGroup
const font_size = this.font_size || LiteGraph.DEFAULT_GROUP_FONT_SIZE
ctx.fillStyle = this.color
ctx.strokeStyle = this.color
const [x, y] = this._pos
const [width, height] = this._size
// Titlebar
ctx.globalAlpha = 0.25 * graphCanvas.editor_alpha
ctx.fillStyle = this.color || defaultColour
ctx.strokeStyle = this.color || defaultColour
ctx.beginPath()
ctx.rect(x + 0.5, y + 0.5, width, font_size * 1.4)
ctx.fill()
// Group background, border
ctx.fillStyle = this.color
ctx.strokeStyle = this.color
ctx.beginPath()
ctx.rect(x + 0.5, y + 0.5, width, height)
ctx.fill()
ctx.globalAlpha = graphCanvas.editor_alpha
ctx.stroke()
// Resize marker
ctx.beginPath()
ctx.moveTo(x + width, y + height)
ctx.lineTo(x + width - 10, y + height)
ctx.lineTo(x + width, y + height - 10)
ctx.lineTo(x + width - resizeLength, y + height)
ctx.lineTo(x + width, y + height - resizeLength)
ctx.fill()
const font_size = this.font_size || LiteGraph.DEFAULT_GROUP_FONT_SIZE
// Title
ctx.font = font_size + "px Arial"
ctx.textAlign = "left"
ctx.fillText(this.title + (this.pinned ? "📌" : ""), x + padding, y + font_size)
@@ -148,11 +166,12 @@ export class LGraphGroup implements Positionable {
}
}
resize(width: number, height: number): void {
if (this.pinned) return
resize(width: number, height: number): boolean {
if (this.pinned) return false
this._size[0] = width
this._size[1] = height
this._size[0] = Math.max(LGraphGroup.minWidth, width)
this._size[1] = Math.max(LGraphGroup.minHeight, height)
return true
}
move(deltaX: number, deltaY: number, skipChildren: boolean = false): void {
@@ -264,6 +283,16 @@ export class LGraphGroup implements Positionable {
return isInsideRectangle(x, y, b[0], b[1], b[2], this.titleHeight)
}
isInResize(x: number, y: number): boolean {
const b = this._bounding
const right = b[0] + b[2]
const bottom = b[1] + b[3]
return x < right
&& y < bottom
&& (x - right) + (y - bottom) > -LGraphGroup.resizeLength
}
isPointInside = LGraphNode.prototype.isPointInside
setDirtyCanvas = LGraphNode.prototype.setDirtyCanvas
}