Spaces:
Runtime error
Runtime error
Update src/addons/addons/paint-tool-panel/userscript.js
Browse files
src/addons/addons/paint-tool-panel/userscript.js
CHANGED
|
@@ -8,6 +8,8 @@ export default async function () {
|
|
| 8 |
const valueObserverObj = { r: 0, sx: 1, sy: 1, kx: 0, ky: 0, outlineRatio: 1 };
|
| 9 |
const panelID = "costume-editor-panel";
|
| 10 |
const epsilon = 1e-8;
|
|
|
|
|
|
|
| 11 |
|
| 12 |
const guiIMGS = {
|
| 13 |
"panel": `<svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><rect x="10.796" y="6.222" width="4.813" height="2.174" rx=".5" ry=".5" fill="#fff" fill-rule="evenodd" stroke="#575e75" stroke-width=".75"/><path fill="none" stroke="red" stroke-linecap="round" stroke-linejoin="round" stroke-width=".75" style="paint-order:markers stroke fill" d="M3 3h14v14H3z"/><g fill="#fff" fill-rule="evenodd" stroke-width=".75"><path stroke="red" stroke-linecap="round" stroke-linejoin="round" style="paint-order:markers fill stroke" d="M3 3h14v1.896H3z"/><rect x="10.796" y="9.722" width="4.813" height="2.174" rx=".5" ry=".5" stroke="#575e75"/><rect x="10.796" y="13.222" width="4.813" height="2.174" rx=".5" ry=".5" stroke="#575e75"/></g><path d="M9.563 7.309H4.242m5.321 6.978H4.242m5.321-3.478H4.242" style="paint-order:markers stroke fill" fill="none" stroke="red" stroke-linecap="round" stroke-linejoin="round" stroke-width=".75"/></svg>`,
|
|
@@ -50,6 +52,10 @@ export default async function () {
|
|
| 50 |
items: [
|
| 51 |
{ title: "x", input: "number", params: "sx" },
|
| 52 |
{ title: "y", input: "number", params: "sy" },
|
|
|
|
|
|
|
|
|
|
|
|
|
| 53 |
{ title: "Group Scaling", id: "groupScale", input: "toggler" },
|
| 54 |
"br",
|
| 55 |
{ title: "Scale Outlines", id: "strokeScale", input: "toggler" },
|
|
@@ -59,7 +65,8 @@ export default async function () {
|
|
| 59 |
title: "Skewing",
|
| 60 |
items: [
|
| 61 |
{ title: "x", input: "number", params: "sx" },
|
| 62 |
-
{ title: "y", input: "number", params: "sy" }
|
|
|
|
| 63 |
]
|
| 64 |
},
|
| 65 |
{
|
|
@@ -110,16 +117,16 @@ export default async function () {
|
|
| 110 |
return ogScale.call(this, ...args);
|
| 111 |
};
|
| 112 |
|
| 113 |
-
const
|
| 114 |
-
paper.Item.prototype.
|
| 115 |
const kx = typeof args[0] === "number" ? args[0] : 1;
|
| 116 |
const ky = typeof args[1] === "number" ? args[1] : kx;
|
| 117 |
for (const child of this._children ?? [this]) {
|
| 118 |
if (!child[panelTag]) child[panelTag] = structuredClone(valueObserverObj);
|
| 119 |
-
child[panelTag].kx += kx;
|
| 120 |
-
child[panelTag].ky += ky;
|
| 121 |
}
|
| 122 |
-
return
|
| 123 |
};
|
| 124 |
}
|
| 125 |
|
|
@@ -138,8 +145,9 @@ export default async function () {
|
|
| 138 |
for (const item of selectedItems) func(item, value);
|
| 139 |
|
| 140 |
queueMicrotask(() => {
|
|
|
|
| 141 |
if (sessionCenterNeedsUpdate) {
|
| 142 |
-
//
|
| 143 |
modalStorage.sessionStore = { center: getCenter(selectedItems) };
|
| 144 |
sessionCenterNeedsUpdate = false;
|
| 145 |
}
|
|
@@ -228,6 +236,16 @@ export default async function () {
|
|
| 228 |
}
|
| 229 |
}
|
| 230 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 231 |
/* GUI Utils */
|
| 232 |
function getButtonURI(name, dontCompile) {
|
| 233 |
const themeHex = isPM ? "#00c3ff" : document.documentElement.style.getPropertyValue("--looks-secondary") || "#ff4c4c";
|
|
@@ -271,6 +289,18 @@ export default async function () {
|
|
| 271 |
value: (item1[panelTag] ? isX ? item1[panelTag].sx : item1[panelTag].sy : 1) * 100
|
| 272 |
};
|
| 273 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 274 |
case "Skewing/x":
|
| 275 |
case "Skewing/y": {
|
| 276 |
if (selectedItems.length > 1) return { value: "", placeholder: "mixed" };
|
|
@@ -350,10 +380,10 @@ export default async function () {
|
|
| 350 |
case "Skewing/y": return (item, value) => {
|
| 351 |
if (isX) {
|
| 352 |
value -= item[panelTag]?.kx ?? 0;
|
| 353 |
-
item
|
| 354 |
} else {
|
| 355 |
value -= item[panelTag]?.ky ?? 0;
|
| 356 |
-
item
|
| 357 |
}
|
| 358 |
}
|
| 359 |
case "Layering/order": return (item, value) => {
|
|
@@ -381,6 +411,7 @@ export default async function () {
|
|
| 381 |
const inputStyle = `text-align: center; font-size: 13px; width: 60px; height: 25px; margin: 5px; border: solid 2px var(--ui-black-transparent, hsla(0, 0%, 0%, 0.15)); border-radius: 15px;`;
|
| 382 |
const selectStyle = `text-align: center; font-size: 13px; height: 25px; margin: 5px; border: solid 2px var(--ui-black-transparent, hsla(0, 0%, 0%, 0.15)); border-radius: 5px;`;
|
| 383 |
const togglerStyle = `background: transparent; border: none; margin-left: 3px; padding: 5px 0 0 0;`;
|
|
|
|
| 384 |
|
| 385 |
const selectedItems = getRealSelection();
|
| 386 |
const center = getCenter(selectedItems);
|
|
@@ -411,7 +442,15 @@ export default async function () {
|
|
| 411 |
|
| 412 |
const id = `${tool.title}/${item.title}`;
|
| 413 |
let input;
|
| 414 |
-
if (item.input === "
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 415 |
input = document.createElement("select");
|
| 416 |
input.setAttribute("style", selectStyle);
|
| 417 |
input.id = id;
|
|
@@ -481,15 +520,30 @@ export default async function () {
|
|
| 481 |
if (item === "br") continue;
|
| 482 |
|
| 483 |
const id = `${tool.title}/${item.title}`;
|
| 484 |
-
const input = toolDiv.querySelector(`input[id="${id}"], select[id="${id}"`);
|
| 485 |
if (input) {
|
| 486 |
const params = getToolParams(id, selectedItems);
|
| 487 |
-
if (params.value !== "")
|
|
|
|
|
|
|
|
|
|
| 488 |
}
|
| 489 |
}
|
| 490 |
}
|
| 491 |
}
|
| 492 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 493 |
function closeToolModal() {
|
| 494 |
const existingModal = document.querySelector(`div[class="costume-tool-modal"]`);
|
| 495 |
if (existingModal) existingModal.remove();
|
|
|
|
| 8 |
const valueObserverObj = { r: 0, sx: 1, sy: 1, kx: 0, ky: 0, outlineRatio: 1 };
|
| 9 |
const panelID = "costume-editor-panel";
|
| 10 |
const epsilon = 1e-8;
|
| 11 |
+
const toRad = Math.PI / 180;
|
| 12 |
+
const toDeg = 180 / Math.PI;
|
| 13 |
|
| 14 |
const guiIMGS = {
|
| 15 |
"panel": `<svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><rect x="10.796" y="6.222" width="4.813" height="2.174" rx=".5" ry=".5" fill="#fff" fill-rule="evenodd" stroke="#575e75" stroke-width=".75"/><path fill="none" stroke="red" stroke-linecap="round" stroke-linejoin="round" stroke-width=".75" style="paint-order:markers stroke fill" d="M3 3h14v14H3z"/><g fill="#fff" fill-rule="evenodd" stroke-width=".75"><path stroke="red" stroke-linecap="round" stroke-linejoin="round" style="paint-order:markers fill stroke" d="M3 3h14v1.896H3z"/><rect x="10.796" y="9.722" width="4.813" height="2.174" rx=".5" ry=".5" stroke="#575e75"/><rect x="10.796" y="13.222" width="4.813" height="2.174" rx=".5" ry=".5" stroke="#575e75"/></g><path d="M9.563 7.309H4.242m5.321 6.978H4.242m5.321-3.478H4.242" style="paint-order:markers stroke fill" fill="none" stroke="red" stroke-linecap="round" stroke-linejoin="round" stroke-width=".75"/></svg>`,
|
|
|
|
| 52 |
items: [
|
| 53 |
{ title: "x", input: "number", params: "sx" },
|
| 54 |
{ title: "y", input: "number", params: "sy" },
|
| 55 |
+
"br",
|
| 56 |
+
{ title: "width", input: "monitor", params: "width" },
|
| 57 |
+
{ title: "height", input: "monitor", params: "height" },
|
| 58 |
+
"br",
|
| 59 |
{ title: "Group Scaling", id: "groupScale", input: "toggler" },
|
| 60 |
"br",
|
| 61 |
{ title: "Scale Outlines", id: "strokeScale", input: "toggler" },
|
|
|
|
| 65 |
title: "Skewing",
|
| 66 |
items: [
|
| 67 |
{ title: "x", input: "number", params: "sx" },
|
| 68 |
+
{ title: "y", input: "number", params: "sy" },
|
| 69 |
+
{ title: "Group Skewing", id: "groupSkew", input: "toggler" },
|
| 70 |
]
|
| 71 |
},
|
| 72 |
{
|
|
|
|
| 117 |
return ogScale.call(this, ...args);
|
| 118 |
};
|
| 119 |
|
| 120 |
+
const ogShear = paper.Item.prototype.shear;
|
| 121 |
+
paper.Item.prototype.shear = function(...args) {
|
| 122 |
const kx = typeof args[0] === "number" ? args[0] : 1;
|
| 123 |
const ky = typeof args[1] === "number" ? args[1] : kx;
|
| 124 |
for (const child of this._children ?? [this]) {
|
| 125 |
if (!child[panelTag]) child[panelTag] = structuredClone(valueObserverObj);
|
| 126 |
+
child[panelTag].kx += Math.atan(kx) * toDeg;
|
| 127 |
+
child[panelTag].ky += Math.atan(ky) * toDeg;
|
| 128 |
}
|
| 129 |
+
return ogShear.call(this, ...args);
|
| 130 |
};
|
| 131 |
}
|
| 132 |
|
|
|
|
| 145 |
for (const item of selectedItems) func(item, value);
|
| 146 |
|
| 147 |
queueMicrotask(() => {
|
| 148 |
+
updateMonitors();
|
| 149 |
if (sessionCenterNeedsUpdate) {
|
| 150 |
+
// perform tasks for bounding box updates
|
| 151 |
modalStorage.sessionStore = { center: getCenter(selectedItems) };
|
| 152 |
sessionCenterNeedsUpdate = false;
|
| 153 |
}
|
|
|
|
| 236 |
}
|
| 237 |
}
|
| 238 |
|
| 239 |
+
function skewItem(item, x, y, isLocked) {
|
| 240 |
+
let pivot = isLocked ? new paper.Point(modalStorage.sessionStore.center) : item.bounds.center;
|
| 241 |
+
|
| 242 |
+
item.translate(pivot.multiply(-1));
|
| 243 |
+
item.shear(Math.tan(x * toRad), Math.tan(y * toRad));
|
| 244 |
+
item.translate(pivot);
|
| 245 |
+
|
| 246 |
+
sessionCenterNeedsUpdate = true;
|
| 247 |
+
}
|
| 248 |
+
|
| 249 |
/* GUI Utils */
|
| 250 |
function getButtonURI(name, dontCompile) {
|
| 251 |
const themeHex = isPM ? "#00c3ff" : document.documentElement.style.getPropertyValue("--looks-secondary") || "#ff4c4c";
|
|
|
|
| 289 |
value: (item1[panelTag] ? isX ? item1[panelTag].sx : item1[panelTag].sy : 1) * 100
|
| 290 |
};
|
| 291 |
}
|
| 292 |
+
case "Scaling/width":
|
| 293 |
+
case "Scaling/height": {
|
| 294 |
+
if (selectedItems.length > 1) {
|
| 295 |
+
const groupBounds = paper.Rectangle.create(selectedItems.map(i => i.bounds))
|
| 296 |
+
.reduce((a, b) => a.unite(b));
|
| 297 |
+
return {
|
| 298 |
+
value: (groupBounds[name.endsWith("width") ? "width" : "height"] / 2).toFixed(2)
|
| 299 |
+
};
|
| 300 |
+
} else return {
|
| 301 |
+
value: (item1.getBounds()[name.endsWith("width") ? "width" : "height"] / 2).toFixed(2)
|
| 302 |
+
};
|
| 303 |
+
}
|
| 304 |
case "Skewing/x":
|
| 305 |
case "Skewing/y": {
|
| 306 |
if (selectedItems.length > 1) return { value: "", placeholder: "mixed" };
|
|
|
|
| 380 |
case "Skewing/y": return (item, value) => {
|
| 381 |
if (isX) {
|
| 382 |
value -= item[panelTag]?.kx ?? 0;
|
| 383 |
+
skewItem(item, value, 0, modalStorage["groupSkew"]);
|
| 384 |
} else {
|
| 385 |
value -= item[panelTag]?.ky ?? 0;
|
| 386 |
+
skewItem(item, 0, value, modalStorage["groupSkew"]);
|
| 387 |
}
|
| 388 |
}
|
| 389 |
case "Layering/order": return (item, value) => {
|
|
|
|
| 411 |
const inputStyle = `text-align: center; font-size: 13px; width: 60px; height: 25px; margin: 5px; border: solid 2px var(--ui-black-transparent, hsla(0, 0%, 0%, 0.15)); border-radius: 15px;`;
|
| 412 |
const selectStyle = `text-align: center; font-size: 13px; height: 25px; margin: 5px; border: solid 2px var(--ui-black-transparent, hsla(0, 0%, 0%, 0.15)); border-radius: 5px;`;
|
| 413 |
const togglerStyle = `background: transparent; border: none; margin-left: 3px; padding: 5px 0 0 0;`;
|
| 414 |
+
const monitorStyle = `text-align: center; font-size: 13px; margin: 5px; padding: 5px; border: solid 2px var(--ui-black-transparent, hsla(0, 0%, 0%, 0.15)); border-radius: 5px;`;
|
| 415 |
|
| 416 |
const selectedItems = getRealSelection();
|
| 417 |
const center = getCenter(selectedItems);
|
|
|
|
| 442 |
|
| 443 |
const id = `${tool.title}/${item.title}`;
|
| 444 |
let input;
|
| 445 |
+
if (item.input === "monitor") {
|
| 446 |
+
input = document.createElement("div");
|
| 447 |
+
input.setAttribute("style", monitorStyle);
|
| 448 |
+
input.classList.add("monitor");
|
| 449 |
+
input.id = id;
|
| 450 |
+
|
| 451 |
+
const param = getToolParams(id, selectedItems);
|
| 452 |
+
input.textContent = param.value;
|
| 453 |
+
} else if (item.input === "select") {
|
| 454 |
input = document.createElement("select");
|
| 455 |
input.setAttribute("style", selectStyle);
|
| 456 |
input.id = id;
|
|
|
|
| 520 |
if (item === "br") continue;
|
| 521 |
|
| 522 |
const id = `${tool.title}/${item.title}`;
|
| 523 |
+
const input = toolDiv.querySelector(`input[id="${id}"], select[id="${id}"], div[id="${id}"]`);
|
| 524 |
if (input) {
|
| 525 |
const params = getToolParams(id, selectedItems);
|
| 526 |
+
if (params.value !== "") {
|
| 527 |
+
if (item.input === "monitor") input.textContent = params.value;
|
| 528 |
+
else input.value = params.value;
|
| 529 |
+
}
|
| 530 |
}
|
| 531 |
}
|
| 532 |
}
|
| 533 |
}
|
| 534 |
|
| 535 |
+
function updateMonitors() {
|
| 536 |
+
const selectedItems = getRealSelection();
|
| 537 |
+
const toolDiv = modalStorage.toolDiv;
|
| 538 |
+
if (!toolDiv) return;
|
| 539 |
+
|
| 540 |
+
const monitors = modalStorage.toolDiv.querySelectorAll(`[class="monitor"]`);
|
| 541 |
+
for (const monitor of monitors) {
|
| 542 |
+
const params = getToolParams(monitor.id, selectedItems);
|
| 543 |
+
if (params.value !== "") monitor.textContent = params.value;
|
| 544 |
+
}
|
| 545 |
+
}
|
| 546 |
+
|
| 547 |
function closeToolModal() {
|
| 548 |
const existingModal = document.querySelector(`div[class="costume-tool-modal"]`);
|
| 549 |
if (existingModal) existingModal.remove();
|