Files

420 lines
16 KiB
JavaScript

import { app } from "../../scripts/app.js";
import { ComfyWidgets } from "../../scripts/widgets.js";
app.registerExtension({
name: "SKB.DisplayEverything",
async beforeRegisterNodeDef(nodeType, nodeData, app) {
if (nodeData.name !== "DisplayEverything") return;
const prototype = nodeType.prototype;
prototype.onNodeCreated = function() {
this.size = [320, 180];
this.originalText = "";
this.fonts = ['Arial', 'Verdana', 'Georgia', 'Tahoma', 'Helvetica', 'Open Sans', 'Roboto', 'Lato', 'Merriweather', 'PT Sans'];
this.selectedFontIndex = 0;
// Instance-level onMouseDown handler for toolbar interactions
this.onMouseDown = function(event) {
const localY = event.canvasY - this.pos[1];
const localX = event.canvasX - this.pos[0];
// Allow widget interaction in widget area (below icons)
if (localY >= 40) {
// Widget area - allow default behavior for text editing
return false;
}
const iconWidth = 20;
const iconSpacing = 4;
const rightMargin = 25;
let xPosition = this.size[0] - iconWidth - rightMargin;
const actions = [
() => this.setColor('#000000'),
() => this.setColor('#cccccc'),
() => this.setColor('#ffffff'),
() => this.openFontDialog(),
this.toggleItalic,
this.toggleBold,
this.increaseFontSize,
this.decreaseFontSize,
];
const iconPositions = actions.map((action, index) => {
const x = xPosition - (index * (iconWidth + iconSpacing));
return {
x: x,
y: 0,
width: iconWidth,
height: 40,
action: actions[index]
};
});
for (const pos of iconPositions) {
if (localX >= pos.x && localX < pos.x + pos.width &&
localY >= pos.y && localY < pos.y + pos.height) {
pos.action.call(this);
this.setDirtyCanvas(true);
return true;
}
}
return false;
}.bind(this);
// Instance-level onMouseMove handler for hover in toolbar area
this.onMouseMove = function(event) {
const localY = event.canvasY - this.pos[1];
const localX = event.canvasX - this.pos[0];
// Only trigger hover effects in icon area (top 40px)
if (localY >= 0 && localY < 40) {
this.setDirtyCanvas(true);
}
}.bind(this);
this.createWidget();
};
prototype.createWidget = function() {
const widget = ComfyWidgets.STRING(this, "output", ["STRING", { multiline: true, readonly: false }], app);
this.showValueWidget = widget.widget;
const self = this;
if (this.showValueWidget) {
this.showValueWidget.callback = function(value) {
self.originalText = value ?? "";
};
}
this.setupWidget();
};
prototype.setupWidget = function() {
if (!this.showValueWidget || !this.showValueWidget.inputEl || !this.fonts) return;
const inputEl = this.showValueWidget.inputEl;
inputEl.id = inputEl.id || `inputEl-${this.id}`;
const currentFont = this.fonts[this.selectedFontIndex] || 'Arial';
const toolbarHeight = 10;
const padding = 1;
const currentStyle = {
fontSize: inputEl.style.fontSize || '14px',
fontWeight: inputEl.style.fontWeight || 'normal',
fontStyle: inputEl.style.fontStyle || 'normal',
color: inputEl.style.color || '#ffffff',
backgroundColor: this.backgroundColor || 'rgba(0, 0, 0, 0.7)'
};
inputEl.readOnly = true;
inputEl.spellcheck = false;
inputEl.style.fontFamily = `'${currentFont}', sans-serif`;
inputEl.style.cssText = `
color: ${currentStyle.color};
border: none;
border-radius: 8px;
padding: 8px;
font-family: '${currentFont}', sans-serif !important;
font-size: ${currentStyle.fontSize};
font-weight: ${currentStyle.fontWeight};
font-style: ${currentStyle.fontStyle};
line-height: 1.6;
box-shadow: 0 4px 8px rgba(0,0,0,0.2);
position: absolute;
left: ${padding}px;
right: ${padding}px;
top: ${toolbarHeight + padding}px;
height: calc(100% - ${toolbarHeight + padding + 10}px);
width: calc(100% - ${padding * 2}px);
overflow-y: auto;
overflow-x: hidden;
z-index: 1;
white-space: pre-wrap;
word-wrap: break-word;
background-color: ${currentStyle.backgroundColor};
box-sizing: border-box;
resize: none;
user-select: text;
cursor: default;
`;
this.setDirtyCanvas(true, true);
};
prototype.onDrawForeground = function(ctx) {
if (this.flags.collapsed) return;
this.drawIconPanel(ctx);
};
prototype.drawIconPanel = function(ctx) {
ctx.fillStyle = "rgba(45, 45, 45, 0.9)";
ctx.fillRect(0, 0, this.size[0], 40);
const icons = [
{ color: '#000000', icon: '⬤', fontSize: '14px' },
{ color: '#cccccc', icon: '⬤', fontSize: '14px' },
{ color: '#ffffff', icon: '⬤', fontSize: '14px' },
{ icon: '⚙️', fontSize: '14px' },
{ icon: 'I', fontSize: '14px' },
{ icon: 'B', fontSize: '14px' },
{ icon: '+', fontSize: '14px' },
{ icon: '-', fontSize: '14px' },
{ icon: '❏', fontSize: '14px' }
];
this.drawIcons(ctx, icons);
};
prototype.drawIcons = function(ctx, icons) {
const iconWidth = 20;
const iconSpacing = 4;
const rightMargin = 25;
let xPosition = this.size[0] - iconWidth - rightMargin;
icons.forEach(icon => {
ctx.fillStyle = icon.color || '#ffffff';
ctx.font = (icon.fontSize || '16px') + ' Arial';
ctx.textAlign = 'center';
ctx.textBaseline = 'middle';
ctx.fillText(icon.icon, xPosition + iconWidth / 2, 20);
xPosition -= (iconWidth + iconSpacing);
});
};
prototype.openFontDialog = function() {
const dialog = document.createElement('div');
dialog.style.cssText = `
position: fixed;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
background: #252525;
padding: 20px;
border-radius: 8px;
z-index: 10000;
box-shadow: 0 4px 20px rgba(0,0,0,0.3);
width: 300px;
max-height: 400px;
display: flex;
flex-direction: column;
`;
const title = document.createElement('div');
title.textContent = 'Font Selection';
title.style.cssText = `
color: white;
font-size: 16px;
margin-bottom: 15px;
padding-bottom: 10px;
border-bottom: 1px solid #444;
`;
dialog.appendChild(title);
const fontList = document.createElement('div');
fontList.style.cssText = `
overflow-y: auto;
margin-bottom: 15px;
max-height: 250px;
`;
const self = this;
this.fonts.forEach((font, index) => {
const fontOption = document.createElement('div');
fontOption.textContent = font;
fontOption.style.cssText = `
color: white;
padding: 8px 12px;
margin: 4px 0;
cursor: pointer;
border-radius: 4px;
font-family: '${font}', sans-serif;
background: ${this.selectedFontIndex === index ? '#444' : 'transparent'};
`;
fontOption.onmouseover = () => {
if (this.selectedFontIndex !== index) {
fontOption.style.background = '#333';
}
};
fontOption.onmouseout = () => {
if (this.selectedFontIndex !== index) {
fontOption.style.background = 'transparent';
}
};
fontOption.onclick = () => {
self.selectedFontIndex = index;
if (self.showValueWidget && self.showValueWidget.inputEl) {
const inputEl = self.showValueWidget.inputEl;
inputEl.style.fontFamily = `'${font}', sans-serif`;
self.setupWidget();
self.setDirtyCanvas(true, true);
}
document.body.removeChild(dialog);
};
fontList.appendChild(fontOption);
});
dialog.appendChild(fontList);
const buttonContainer = document.createElement('div');
buttonContainer.style.cssText = `
display: flex;
justify-content: flex-end;
gap: 10px;
margin-top: 10px;
`;
const cancelButton = document.createElement('button');
cancelButton.textContent = 'İptal';
cancelButton.style.cssText = `
padding: 6px 12px;
border: none;
border-radius: 4px;
background: #444;
color: white;
cursor: pointer;
transition: background 0.2s;
`;
cancelButton.onmouseover = () => {
cancelButton.style.background = '#555';
};
cancelButton.onmouseout = () => {
cancelButton.style.background = '#444';
};
cancelButton.onclick = () => document.body.removeChild(dialog);
buttonContainer.appendChild(cancelButton);
dialog.appendChild(buttonContainer);
document.body.appendChild(dialog);
};
prototype.decreaseFontSize = function() {
const currentSize = parseFloat(this.showValueWidget.inputEl.style.fontSize) || 14;
this.showValueWidget.inputEl.style.fontSize = `${Math.max(12, currentSize - 1)}px`;
};
prototype.increaseFontSize = function() {
const currentSize = parseFloat(this.showValueWidget.inputEl.style.fontSize) || 14;
this.showValueWidget.inputEl.style.fontSize = `${Math.min(24, currentSize + 1)}px`;
};
prototype.toggleBold = function() {
this.showValueWidget.inputEl.style.fontWeight =
this.showValueWidget.inputEl.style.fontWeight === 'bold' ? 'normal' : 'bold';
};
prototype.toggleItalic = function() {
this.showValueWidget.inputEl.style.fontStyle =
this.showValueWidget.inputEl.style.fontStyle === 'italic' ? 'normal' : 'italic';
};
prototype.setColor = function(color) {
this.showValueWidget.inputEl.style.color = color;
};
prototype.onRemoved = function() {
if (this.wrapper && this.wrapper.parentNode) {
this.wrapper.parentNode.removeChild(this.wrapper);
}
};
prototype.onExecuted = function(message) {
if (message && message.text !== undefined) {
const text = Array.isArray(message.text) ? message.text[0] : message.text;
this.originalText = text.replace(/\\u([0-9a-fA-F]{4})/g, (_, grp) => String.fromCharCode(parseInt(grp, 16)))
.replace(/^["']|["']$/g, '');
this.showValueWidget.value = this.originalText;
this.setupWidget();
}
};
prototype.onWidgetChanged = function(name, value) {
if (name === "output" && this.outputs && this.outputs[0]) {
this.outputs[0].value = value;
this.originalText = value;
this.triggerSlot(0, value);
}
};
prototype.setupNode = function() {
this.size = [320, 240];
this.fonts = ['Arial', 'Verdana', 'Georgia', 'Tahoma', 'Helvetica', 'Open Sans', 'Roboto', 'Lato', 'Merriweather', 'PT Sans'];
this.selectedFontIndex = 0;
this.originalText = "";
this.fontSelectVisible = false;
};
prototype.onSerialize = function(o) {
o.selectedFontIndex = this.selectedFontIndex;
o.fontSize = this.showValueWidget?.inputEl?.style.fontSize;
o.fontWeight = this.showValueWidget?.inputEl?.style.fontWeight;
o.fontStyle = this.showValueWidget?.inputEl?.style.fontStyle;
o.textColor = this.showValueWidget?.inputEl?.style.color;
o.backgroundColor = this.backgroundColor || 'rgba(0, 0, 0, 0.7)';
};
prototype.onConfigure = function(o) {
if (o.selectedFontIndex !== undefined) {
this.selectedFontIndex = o.selectedFontIndex;
}
if (this.showValueWidget && this.showValueWidget.inputEl) {
if (o.fontSize) this.showValueWidget.inputEl.style.fontSize = o.fontSize;
if (o.fontWeight) this.showValueWidget.inputEl.style.fontWeight = o.fontWeight;
if (o.fontStyle) this.showValueWidget.inputEl.style.fontStyle = o.fontStyle;
if (o.textColor) this.showValueWidget.inputEl.style.color = o.textColor;
if (o.backgroundColor) {
this.backgroundColor = o.backgroundColor;
this.showValueWidget.inputEl.style.backgroundColor = o.backgroundColor;
}
this.setupWidget();
}
};
prototype.openBackgroundColorDialog = function() {
const colorPicker = document.createElement('input');
colorPicker.type = 'color';
colorPicker.value = '#000000';
const self = this;
colorPicker.addEventListener('change', function() {
if (self.showValueWidget && self.showValueWidget.inputEl) {
const hex = this.value;
const r = parseInt(hex.slice(1, 3), 16);
const g = parseInt(hex.slice(3, 5), 16);
const b = parseInt(hex.slice(5, 7), 16);
const backgroundColor = `rgba(${r}, ${g}, ${b}, 0.7)`;
self.showValueWidget.inputEl.style.backgroundColor = backgroundColor;
self.backgroundColor = backgroundColor;
self.setDirtyCanvas(true);
}
document.body.removeChild(colorPicker);
});
colorPicker.addEventListener('cancel', function() {
document.body.removeChild(colorPicker);
});
document.body.appendChild(colorPicker);
colorPicker.click();
};
}
});