|
import { app } from "../../scripts/app.js"; |
|
function binarySearch(max, getValue, match) { |
|
let min = 0; |
|
while (min <= max) { |
|
let guess = Math.floor((min + max) / 2); |
|
const compareVal = getValue(guess); |
|
if (compareVal === match) |
|
return guess; |
|
if (compareVal < match) |
|
min = guess + 1; |
|
else |
|
max = guess - 1; |
|
} |
|
return max; |
|
} |
|
export function fitString(ctx, str, maxWidth) { |
|
let width = ctx.measureText(str).width; |
|
const ellipsis = "…"; |
|
const ellipsisWidth = measureText(ctx, ellipsis); |
|
if (width <= maxWidth || width <= ellipsisWidth) { |
|
return str; |
|
} |
|
const index = binarySearch(str.length, (guess) => measureText(ctx, str.substring(0, guess)), maxWidth - ellipsisWidth); |
|
return str.substring(0, index) + ellipsis; |
|
} |
|
export function measureText(ctx, str) { |
|
return ctx.measureText(str).width; |
|
} |
|
export function isLowQuality() { |
|
var _a; |
|
const canvas = app.canvas; |
|
return (((_a = canvas.ds) === null || _a === void 0 ? void 0 : _a.scale) || 1) <= 0.5; |
|
} |
|
export function drawNodeWidget(ctx, options) { |
|
const lowQuality = isLowQuality(); |
|
const data = { |
|
width: options.width, |
|
height: options.height, |
|
posY: options.posY, |
|
lowQuality, |
|
margin: 15, |
|
colorOutline: LiteGraph.WIDGET_OUTLINE_COLOR, |
|
colorBackground: LiteGraph.WIDGET_BGCOLOR, |
|
colorText: LiteGraph.WIDGET_TEXT_COLOR, |
|
colorTextSecondary: LiteGraph.WIDGET_SECONDARY_TEXT_COLOR, |
|
}; |
|
ctx.strokeStyle = options.colorStroke || data.colorOutline; |
|
ctx.fillStyle = options.colorBackground || data.colorBackground; |
|
ctx.beginPath(); |
|
ctx.roundRect(data.margin, data.posY, data.width - data.margin * 2, data.height, lowQuality ? [0] : options.borderRadius ? [options.borderRadius] : [options.height * 0.5]); |
|
ctx.fill(); |
|
if (!lowQuality) { |
|
ctx.stroke(); |
|
} |
|
return data; |
|
} |
|
export function drawRoundedRectangle(ctx, options) { |
|
const lowQuality = isLowQuality(); |
|
options = { ...options }; |
|
ctx.strokeStyle = options.colorStroke || LiteGraph.WIDGET_OUTLINE_COLOR; |
|
ctx.fillStyle = options.colorBackground || LiteGraph.WIDGET_BGCOLOR; |
|
ctx.beginPath(); |
|
ctx.roundRect(options.posX, options.posY, options.width, options.height, lowQuality ? [0] : options.borderRadius ? [options.borderRadius] : [options.height * 0.5]); |
|
ctx.fill(); |
|
!lowQuality && ctx.stroke(); |
|
} |
|
export function drawNumberWidgetPart(ctx, options) { |
|
const arrowWidth = 9; |
|
const arrowHeight = 10; |
|
const innerMargin = 3; |
|
const numberWidth = 32; |
|
const xBoundsArrowLess = [0, 0]; |
|
const xBoundsNumber = [0, 0]; |
|
const xBoundsArrowMore = [0, 0]; |
|
ctx.save(); |
|
let posX = options.posX; |
|
const { posY, height, value, textColor } = options; |
|
const midY = posY + height / 2; |
|
if (options.direction === -1) { |
|
posX = posX - arrowWidth - innerMargin - numberWidth - innerMargin - arrowWidth; |
|
} |
|
ctx.fill(new Path2D(`M ${posX} ${midY} l ${arrowWidth} ${arrowHeight / 2} l 0 -${arrowHeight} L ${posX} ${midY} z`)); |
|
xBoundsArrowLess[0] = posX; |
|
xBoundsArrowLess[1] = arrowWidth; |
|
posX += arrowWidth + innerMargin; |
|
ctx.textAlign = "center"; |
|
ctx.textBaseline = "middle"; |
|
const oldTextcolor = ctx.fillStyle; |
|
if (textColor) { |
|
ctx.fillStyle = textColor; |
|
} |
|
ctx.fillText(fitString(ctx, value.toFixed(2), numberWidth), posX + numberWidth / 2, midY); |
|
ctx.fillStyle = oldTextcolor; |
|
xBoundsNumber[0] = posX; |
|
xBoundsNumber[1] = numberWidth; |
|
posX += numberWidth + innerMargin; |
|
ctx.fill(new Path2D(`M ${posX} ${midY - arrowHeight / 2} l ${arrowWidth} ${arrowHeight / 2} l -${arrowWidth} ${arrowHeight / 2} v -${arrowHeight} z`)); |
|
xBoundsArrowMore[0] = posX; |
|
xBoundsArrowMore[1] = arrowWidth; |
|
ctx.restore(); |
|
return [xBoundsArrowLess, xBoundsNumber, xBoundsArrowMore]; |
|
} |
|
drawNumberWidgetPart.WIDTH_TOTAL = 9 + 3 + 32 + 3 + 9; |
|
export function drawTogglePart(ctx, options) { |
|
const lowQuality = isLowQuality(); |
|
ctx.save(); |
|
const { posX, posY, height, value } = options; |
|
const toggleRadius = height * 0.36; |
|
const toggleBgWidth = height * 1.5; |
|
if (!lowQuality) { |
|
ctx.beginPath(); |
|
ctx.roundRect(posX + 4, posY + 4, toggleBgWidth - 8, height - 8, [height * 0.5]); |
|
ctx.globalAlpha = app.canvas.editor_alpha * 0.25; |
|
ctx.fillStyle = "rgba(255,255,255,0.45)"; |
|
ctx.fill(); |
|
ctx.globalAlpha = app.canvas.editor_alpha; |
|
} |
|
ctx.fillStyle = value === true ? "#89B" : "#888"; |
|
const toggleX = lowQuality || value === false |
|
? posX + height * 0.5 |
|
: value === true |
|
? posX + height |
|
: posX + height * 0.75; |
|
ctx.beginPath(); |
|
ctx.arc(toggleX, posY + height * 0.5, toggleRadius, 0, Math.PI * 2); |
|
ctx.fill(); |
|
ctx.restore(); |
|
return [posX, toggleBgWidth]; |
|
} |
|
export function drawInfoIcon(ctx, x, y, size = 12) { |
|
ctx.save(); |
|
ctx.beginPath(); |
|
ctx.roundRect(x, y, size, size, [size * 0.1]); |
|
ctx.fillStyle = "#2f82ec"; |
|
ctx.strokeStyle = "#0f2a5e"; |
|
ctx.fill(); |
|
ctx.strokeStyle = "#FFF"; |
|
ctx.lineWidth = 2; |
|
const midX = x + size / 2; |
|
const serifSize = size * 0.175; |
|
ctx.stroke(new Path2D(` |
|
M ${midX} ${y + size * 0.15} |
|
v 2 |
|
M ${midX - serifSize} ${y + size * 0.45} |
|
h ${serifSize} |
|
v ${size * 0.325} |
|
h ${serifSize} |
|
h -${serifSize * 2} |
|
`)); |
|
ctx.restore(); |
|
} |
|
|