diff --git a/src/extensions/core/maskeditor.ts b/src/extensions/core/maskeditor.ts index 858e586b1..a3e999ced 100644 --- a/src/extensions/core/maskeditor.ts +++ b/src/extensions/core/maskeditor.ts @@ -120,6 +120,8 @@ class MaskEditorDialog extends ComfyDialog { mousedown_pan_x: number mousedown_pan_y: number last_pressure: number + pointer_type: string + brush_pointer_type_select: HTMLDivElement static getInstance() { if (!MaskEditorDialog.instance) { @@ -176,7 +178,7 @@ class MaskEditorDialog extends ComfyDialog { divElement.style.borderColor = 'var(--border-color)' divElement.style.borderStyle = 'solid' divElement.style.fontSize = '15px' - divElement.style.height = '21px' + divElement.style.height = '25px' divElement.style.padding = '1px 6px' divElement.style.display = 'flex' divElement.style.position = 'relative' @@ -210,7 +212,7 @@ class MaskEditorDialog extends ComfyDialog { divElement.style.borderColor = 'var(--border-color)' divElement.style.borderStyle = 'solid' divElement.style.fontSize = '15px' - divElement.style.height = '21px' + divElement.style.height = '25px' divElement.style.padding = '1px 6px' divElement.style.display = 'flex' divElement.style.position = 'relative' @@ -233,8 +235,77 @@ class MaskEditorDialog extends ComfyDialog { return divElement } + createPointerTypeSelect(self: any): HTMLDivElement { + const divElement = document.createElement('div') + divElement.id = 'maskeditor-pointer-type' + divElement.style.cssFloat = 'left' + divElement.style.fontFamily = 'sans-serif' + divElement.style.marginRight = '4px' + divElement.style.color = 'var(--input-text)' + divElement.style.backgroundColor = 'var(--comfy-input-bg)' + divElement.style.borderRadius = '8px' + divElement.style.borderColor = 'var(--border-color)' + divElement.style.borderStyle = 'solid' + divElement.style.fontSize = '15px' + divElement.style.height = '25px' + divElement.style.padding = '1px 6px' + divElement.style.display = 'flex' + divElement.style.position = 'relative' + divElement.style.top = '2px' + divElement.style.pointerEvents = 'auto' + + const labelElement = document.createElement('label') + labelElement.textContent = 'Pointer Type:' + + const selectElement = document.createElement('select') + selectElement.style.borderRadius = '0' + selectElement.style.borderColor = 'transparent' + selectElement.style.borderStyle = 'unset' + selectElement.style.fontSize = '0.9em' + + const optionArc = document.createElement('option') + optionArc.value = 'arc' + optionArc.text = 'Circle' + optionArc.selected = true // Fix for TypeScript, "selected" should be boolean + + const optionRect = document.createElement('option') + optionRect.value = 'rect' + optionRect.text = 'Square' + + selectElement.appendChild(optionArc) + selectElement.appendChild(optionRect) + + selectElement.addEventListener('change', (event: Event) => { + const target = event.target as HTMLSelectElement + self.pointer_type = target.value + this.setBrushBorderRadius(self) + }) + + divElement.appendChild(labelElement) + divElement.appendChild(selectElement) + + return divElement + } + + setBrushBorderRadius(self: any): void { + if (self.pointer_type === 'rect') { + this.brush.style.borderRadius = '0%' + // @ts-expect-error + this.brush.style.MozBorderRadius = '0%' + // @ts-expect-error + this.brush.style.WebkitBorderRadius = '0%' + } else { + this.brush.style.borderRadius = '50%' + // @ts-expect-error + this.brush.style.MozBorderRadius = '50%' + // @ts-expect-error + this.brush.style.WebkitBorderRadius = '50%' + } + } + setlayout(imgCanvas: HTMLCanvasElement, maskCanvas: HTMLCanvasElement) { const self = this + self.pointer_type = 'arc' // If it is specified as relative, using it only as a hidden placeholder for padding is recommended // to prevent anomalies where it exceeds a certain size and goes outside of the window. @@ -251,15 +322,11 @@ class MaskEditorDialog extends ComfyDialog { brush.style.backgroundColor = 'transparent' brush.style.outline = '1px dashed black' brush.style.boxShadow = '0 0 0 1px white' - brush.style.borderRadius = '50%' - // @ts-expect-error - brush.style.MozBorderRadius = '50%' - // @ts-expect-error - brush.style.WebkitBorderRadius = '50%' brush.style.position = 'absolute' brush.style.zIndex = '8889' brush.style.pointerEvents = 'none' this.brush = brush + this.setBrushBorderRadius(self) this.element.appendChild(imgCanvas) this.element.appendChild(maskCanvas) this.element.appendChild(bottom_panel) @@ -294,6 +361,7 @@ class MaskEditorDialog extends ComfyDialog { } ) + this.brush_pointer_type_select = this.createPointerTypeSelect(self) this.colorButton = this.createLeftButton(this.getColorButtonText(), () => { if (self.brush_color_mode === 'black') { self.brush_color_mode = 'white' @@ -325,6 +393,7 @@ class MaskEditorDialog extends ComfyDialog { bottom_panel.appendChild(cancelButton) bottom_panel.appendChild(this.brush_size_slider) bottom_panel.appendChild(this.brush_opacity_slider) + bottom_panel.appendChild(this.brush_pointer_type_select) bottom_panel.appendChild(this.colorButton) imgCanvas.style.position = 'absolute' @@ -818,7 +887,16 @@ class MaskEditorDialog extends ComfyDialog { self.maskCtx.beginPath() self.maskCtx.fillStyle = this.getMaskFillStyle() self.maskCtx.globalCompositeOperation = 'source-over' - self.maskCtx.arc(x, y, brush_size, 0, Math.PI * 2, false) + if (self.pointer_type === 'rect') { + self.maskCtx.rect( + x - brush_size, + y - brush_size, + brush_size * 2, + brush_size * 2 + ) + } else { + self.maskCtx.arc(x, y, brush_size, 0, Math.PI * 2, false) + } self.maskCtx.fill() self.lastx = x self.lasty = y @@ -839,7 +917,16 @@ class MaskEditorDialog extends ComfyDialog { for (var i = 0; i < distance; i += 5) { var px = self.lastx + directionX * i var py = self.lasty + directionY * i - self.maskCtx.arc(px, py, brush_size, 0, Math.PI * 2, false) + if (self.pointer_type === 'rect') { + self.maskCtx.rect( + px - brush_size, + py - brush_size, + brush_size * 2, + brush_size * 2 + ) + } else { + self.maskCtx.arc(px, py, brush_size, 0, Math.PI * 2, false) + } self.maskCtx.fill() } self.lastx = x @@ -875,7 +962,16 @@ class MaskEditorDialog extends ComfyDialog { requestAnimationFrame(() => { self.maskCtx.beginPath() self.maskCtx.globalCompositeOperation = 'destination-out' - self.maskCtx.arc(x, y, brush_size, 0, Math.PI * 2, false) + if (self.pointer_type === 'rect') { + self.maskCtx.rect( + x - brush_size, + y - brush_size, + brush_size * 2, + brush_size * 2 + ) + } else { + self.maskCtx.arc(x, y, brush_size, 0, Math.PI * 2, false) + } self.maskCtx.fill() self.lastx = x self.lasty = y @@ -895,7 +991,16 @@ class MaskEditorDialog extends ComfyDialog { for (var i = 0; i < distance; i += 5) { var px = self.lastx + directionX * i var py = self.lasty + directionY * i - self.maskCtx.arc(px, py, brush_size, 0, Math.PI * 2, false) + if (self.pointer_type === 'rect') { + self.maskCtx.rect( + px - brush_size, + py - brush_size, + brush_size * 2, + brush_size * 2 + ) + } else { + self.maskCtx.arc(px, py, brush_size, 0, Math.PI * 2, false) + } self.maskCtx.fill() } self.lastx = x @@ -950,7 +1055,16 @@ class MaskEditorDialog extends ComfyDialog { } else { self.maskCtx.globalCompositeOperation = 'destination-out' } - self.maskCtx.arc(x, y, brush_size, 0, Math.PI * 2, false) + if (self.pointer_type === 'rect') { + self.maskCtx.rect( + x - brush_size, + y - brush_size, + brush_size * 2, + brush_size * 2 + ) + } else { + self.maskCtx.arc(x, y, brush_size, 0, Math.PI * 2, false) + } self.maskCtx.fill() self.lastx = x self.lasty = y