soiz1 commited on
Commit
0411bb9
·
verified ·
1 Parent(s): 0d309b5

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 ogSkew = paper.Item.prototype.skew;
114
- paper.Item.prototype.skew = function(...args) {
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 ogSkew.call(this, ...args);
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
- // calculate the new center & clear session storage
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.skew(value, 0);
354
  } else {
355
  value -= item[panelTag]?.ky ?? 0;
356
- item.skew(0, value);
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 === "select") {
 
 
 
 
 
 
 
 
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 !== "") input.value = 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();