287 lines
5.8 KiB
JavaScript
287 lines
5.8 KiB
JavaScript
import { app } from "../../scripts/app.js";
|
||
|
||
let panel;
|
||
let img;
|
||
let info;
|
||
let mini;
|
||
|
||
let executing = false;
|
||
let userClosed = false;
|
||
|
||
let scale = 1;
|
||
let offsetX = 0;
|
||
let offsetY = 0;
|
||
|
||
// Create the preview window
|
||
function createPreview() {
|
||
panel = document.createElement("div");
|
||
|
||
Object.assign(panel.style, {
|
||
position: "fixed",
|
||
left: "120px",
|
||
top: "120px",
|
||
width: "800px",
|
||
height: "700px",
|
||
background: "#111",
|
||
border: "1px solid #777",
|
||
zIndex: 99999,
|
||
resize: "both",
|
||
overflow: "hidden",
|
||
display: "none",
|
||
flexDirection: "column"
|
||
});
|
||
|
||
// Title bar
|
||
let header = document.createElement("div");
|
||
|
||
Object.assign(header.style, {
|
||
height: "35px",
|
||
background: "#222",
|
||
color: "white",
|
||
cursor: "move",
|
||
padding: "5px",
|
||
userSelect: "none"
|
||
});
|
||
|
||
header.innerHTML = "";
|
||
header.appendChild(document.createTextNode("HD Preview"));
|
||
|
||
let close = document.createElement("button");
|
||
close.innerText = "×";
|
||
|
||
Object.assign(close.style, {
|
||
float: "right",
|
||
width: "30px"
|
||
});
|
||
|
||
close.onclick = (e) => {
|
||
e.stopPropagation();
|
||
panel.style.display = "none";
|
||
mini.style.display = "block";
|
||
userClosed = true;
|
||
};
|
||
|
||
header.appendChild(close);
|
||
|
||
// Content area
|
||
let content = document.createElement("div");
|
||
|
||
Object.assign(content.style, {
|
||
flex: "1",
|
||
overflow: "hidden",
|
||
display: "flex",
|
||
justifyContent: "center",
|
||
alignItems: "center"
|
||
});
|
||
|
||
img = document.createElement("img");
|
||
|
||
Object.assign(img.style, {
|
||
maxWidth: "100%",
|
||
maxHeight: "100%",
|
||
cursor: "grab",
|
||
transformOrigin: "center"
|
||
});
|
||
|
||
content.appendChild(img);
|
||
|
||
info = document.createElement("div");
|
||
|
||
Object.assign(info.style, {
|
||
height: "25px",
|
||
color: "white"
|
||
});
|
||
|
||
panel.appendChild(header);
|
||
panel.appendChild(content);
|
||
panel.appendChild(info);
|
||
|
||
document.body.appendChild(panel);
|
||
|
||
// Window dragging
|
||
let moving = false;
|
||
let moveStartX = 0;
|
||
let moveStartY = 0;
|
||
let panelStartX = 0;
|
||
let panelStartY = 0;
|
||
|
||
header.addEventListener("pointerdown", (e) => {
|
||
if (e.target === close) return;
|
||
|
||
moving = true;
|
||
moveStartX = e.clientX;
|
||
moveStartY = e.clientY;
|
||
panelStartX = panel.offsetLeft;
|
||
panelStartY = panel.offsetTop;
|
||
header.setPointerCapture(e.pointerId);
|
||
header.style.cursor = "grabbing";
|
||
|
||
e.preventDefault();
|
||
e.stopPropagation();
|
||
});
|
||
|
||
header.addEventListener("pointermove", (e) => {
|
||
if (!moving) return;
|
||
|
||
let dx = e.clientX - moveStartX;
|
||
let dy = e.clientY - moveStartY;
|
||
|
||
panel.style.left = panelStartX + dx + "px";
|
||
panel.style.top = panelStartY + dy + "px";
|
||
});
|
||
|
||
header.addEventListener("pointerup", (e) => {
|
||
moving = false;
|
||
header.style.cursor = "move";
|
||
|
||
try {
|
||
header.releasePointerCapture(e.pointerId);
|
||
} catch (err) {}
|
||
});
|
||
|
||
// Image zoom
|
||
img.addEventListener("wheel", (e) => {
|
||
e.preventDefault();
|
||
|
||
scale *= e.deltaY < 0 ? 1.1 : 0.9;
|
||
scale = Math.max(0.2, Math.min(scale, 5));
|
||
|
||
updateImage();
|
||
});
|
||
|
||
// Image drag
|
||
let dragImg = false;
|
||
let lastX;
|
||
let lastY;
|
||
|
||
img.addEventListener("mousedown", (e) => {
|
||
dragImg = true;
|
||
lastX = e.clientX;
|
||
lastY = e.clientY;
|
||
img.style.cursor = "grabbing";
|
||
});
|
||
|
||
document.addEventListener("mousemove", (e) => {
|
||
if (!dragImg) return;
|
||
|
||
offsetX += e.clientX - lastX;
|
||
offsetY += e.clientY - lastY;
|
||
lastX = e.clientX;
|
||
lastY = e.clientY;
|
||
|
||
updateImage();
|
||
});
|
||
|
||
document.addEventListener("mouseup", () => {
|
||
dragImg = false;
|
||
if (img) img.style.cursor = "grab";
|
||
});
|
||
|
||
img.ondblclick = () => {
|
||
scale = 1;
|
||
offsetX = 0;
|
||
offsetY = 0;
|
||
updateImage();
|
||
};
|
||
|
||
// Mini floating button
|
||
mini = document.createElement("button");
|
||
mini.innerText = "HD";
|
||
|
||
Object.assign(mini.style, {
|
||
position: "fixed",
|
||
left: "30px",
|
||
top: "30px",
|
||
width: "60px",
|
||
height: "60px",
|
||
borderRadius: "50%",
|
||
zIndex: 100000
|
||
});
|
||
|
||
// Mini button interactions
|
||
let miniMoving = false;
|
||
let miniDragged = false;
|
||
let miniStartX = 0;
|
||
let miniStartY = 0;
|
||
let miniStartLeft = 0;
|
||
let miniStartTop = 0;
|
||
|
||
mini.addEventListener("click", () => {
|
||
if (miniDragged) {
|
||
miniDragged = false;
|
||
return;
|
||
}
|
||
|
||
panel.style.display = "flex";
|
||
mini.style.display = "none";
|
||
userClosed = false;
|
||
});
|
||
|
||
mini.addEventListener("mousedown", (e) => {
|
||
miniMoving = true;
|
||
miniDragged = false;
|
||
miniStartX = e.clientX;
|
||
miniStartY = e.clientY;
|
||
miniStartLeft = mini.offsetLeft;
|
||
miniStartTop = mini.offsetTop;
|
||
e.preventDefault();
|
||
});
|
||
|
||
document.addEventListener("mousemove", (e) => {
|
||
if (!miniMoving) return;
|
||
|
||
let dx = e.clientX - miniStartX;
|
||
let dy = e.clientY - miniStartY;
|
||
|
||
if (Math.abs(dx) > 5 || Math.abs(dy) > 5) {
|
||
miniDragged = true;
|
||
}
|
||
|
||
mini.style.left = miniStartLeft + dx + "px";
|
||
mini.style.top = miniStartTop + dy + "px";
|
||
});
|
||
|
||
document.addEventListener("mouseup", () => {
|
||
miniMoving = false;
|
||
});
|
||
|
||
document.body.appendChild(mini);
|
||
}
|
||
|
||
function updateImage() {
|
||
img.style.transform = `translate(${offsetX}px, ${offsetY}px) scale(${scale})`;
|
||
}
|
||
|
||
app.registerExtension({
|
||
name: "HighPreviewKSampler",
|
||
|
||
async setup() {
|
||
createPreview();
|
||
|
||
app.api.addEventListener("execution_start", () => {
|
||
executing = true;
|
||
// Do not reset userClosed here
|
||
panel.style.display = "flex";
|
||
mini.style.display = "none";
|
||
});
|
||
|
||
app.api.addEventListener("high_preview", (e) => {
|
||
let data = e.detail;
|
||
|
||
if (executing && !userClosed) {
|
||
panel.style.display = "flex";
|
||
mini.style.display = "none";
|
||
}
|
||
|
||
img.src = "data:image/png;base64," + data.image;
|
||
info.innerText = `Step ${data.step}/${data.total}`;
|
||
});
|
||
|
||
app.api.addEventListener("execution_success", () => {
|
||
executing = false;
|
||
if (panel.style.display === "none") {
|
||
mini.style.display = "block";
|
||
}
|
||
});
|
||
}
|
||
}); |