From 5914db3bb4491f686428064f96f5f5509b5f70b1 Mon Sep 17 00:00:00 2001
From: rgantzos <86856959+rgantzos@users.noreply.github.com>
Date: Mon, 2 Sep 2024 14:01:09 -0700
Subject: [PATCH] More Paint Functions
---
features/features.json | 5 +
features/more-editor-fonts/script.js | 1 +
features/more-paint-functions/data.json | 22 +++
.../more-paint-functions/icons/exclude.svg | 13 ++
.../more-paint-functions/icons/intersect.svg | 20 +++
.../more-paint-functions/icons/subtract.svg | 17 ++
features/more-paint-functions/icons/unite.svg | 13 ++
features/more-paint-functions/script.js | 161 ++++++++++++++++++
features/more-paint-functions/style.css | 7 +
9 files changed, 259 insertions(+)
create mode 100644 features/more-paint-functions/data.json
create mode 100644 features/more-paint-functions/icons/exclude.svg
create mode 100644 features/more-paint-functions/icons/intersect.svg
create mode 100644 features/more-paint-functions/icons/subtract.svg
create mode 100644 features/more-paint-functions/icons/unite.svg
create mode 100644 features/more-paint-functions/script.js
create mode 100644 features/more-paint-functions/style.css
diff --git a/features/features.json b/features/features.json
index 9f0054a1..9588ccbe 100644
--- a/features/features.json
+++ b/features/features.json
@@ -1,4 +1,9 @@
[
+ {
+ "version": 2,
+ "id": "more-paint-functions",
+ "versionAdded": "v4.0.0"
+ },
{
"version": 2,
"id": "asset-size",
diff --git a/features/more-editor-fonts/script.js b/features/more-editor-fonts/script.js
index 791529dc..7efad503 100644
--- a/features/more-editor-fonts/script.js
+++ b/features/more-editor-fonts/script.js
@@ -9,6 +9,7 @@ export default async function ({ feature, console }) {
feature.page.waitForElements(
"div[class^='asset-panel_wrapper_'] div[class^='action-menu_more-buttons_']",
function (menu) {
+ if (feature.traps.gui().editorTab.activeTabIndex !== 1) return;
if (menu.querySelector(".ste-more-fonts")) return;
let div = document.createElement("div");
diff --git a/features/more-paint-functions/data.json b/features/more-paint-functions/data.json
new file mode 100644
index 00000000..11c00e90
--- /dev/null
+++ b/features/more-paint-functions/data.json
@@ -0,0 +1,22 @@
+{
+ "title": "More Paint Functions",
+ "description": "Adds new functions to the paint editor. The new functions include unite (combining them into one), subtract (removing one shape from another), exclude (removing the overlap of 2 items), and intersect (removing everything but the overlap of 2 items). Each function only works with 2 items.",
+ "credits": [
+ { "username": "rgantzos", "url": "https://scratch.mit.edu/users/rgantzos/" }
+ ],
+ "type": ["Editor"],
+ "tags": ["New", "Featured"],
+ "dynamic": true,
+ "scripts": [{ "file": "script.js", "runOn": "/projects/*" }],
+ "styles": [{ "file": "style.css", "runOn": "/projects/*" }],
+ "resources": [
+ { "name": "function-exclude", "path": "/icons/exclude.svg" },
+ { "name": "function-intersect", "path": "/icons/intersect.svg" },
+ { "name": "function-subtract", "path": "/icons/subtract.svg" },
+ { "name": "function-unite", "path": "/icons/unite.svg" }
+ ],
+ "components": [{
+ "type": "warning",
+ "content": "In order to avoid clutter in the paint editor, this feature replaces the Copy, Paste and Delete buttons. However, hotkeys still work."
+ }]
+}
diff --git a/features/more-paint-functions/icons/exclude.svg b/features/more-paint-functions/icons/exclude.svg
new file mode 100644
index 00000000..76c50759
--- /dev/null
+++ b/features/more-paint-functions/icons/exclude.svg
@@ -0,0 +1,13 @@
+
+
\ No newline at end of file
diff --git a/features/more-paint-functions/icons/intersect.svg b/features/more-paint-functions/icons/intersect.svg
new file mode 100644
index 00000000..399d3a7d
--- /dev/null
+++ b/features/more-paint-functions/icons/intersect.svg
@@ -0,0 +1,20 @@
+
+
\ No newline at end of file
diff --git a/features/more-paint-functions/icons/subtract.svg b/features/more-paint-functions/icons/subtract.svg
new file mode 100644
index 00000000..4d10c195
--- /dev/null
+++ b/features/more-paint-functions/icons/subtract.svg
@@ -0,0 +1,17 @@
+
+
\ No newline at end of file
diff --git a/features/more-paint-functions/icons/unite.svg b/features/more-paint-functions/icons/unite.svg
new file mode 100644
index 00000000..dee97002
--- /dev/null
+++ b/features/more-paint-functions/icons/unite.svg
@@ -0,0 +1,13 @@
+
+
\ No newline at end of file
diff --git a/features/more-paint-functions/script.js b/features/more-paint-functions/script.js
new file mode 100644
index 00000000..ddfd0849
--- /dev/null
+++ b/features/more-paint-functions/script.js
@@ -0,0 +1,161 @@
+export default async function ({ feature, console }) {
+ function unite() {
+ let paper = feature.traps.getPaper();
+ let items = paper.project.selectedItems;
+
+ if (items.length !== 2) return;
+
+ for (var i in items) {
+ if (i > 0) {
+ items[0].unite(items[i]);
+ }
+ }
+
+ for (var i in items) {
+ items[i].remove();
+ }
+
+ paper.tool.onUpdateImage();
+ }
+
+ function subtract() {
+ let paper = feature.traps.getPaper();
+ let items = paper.project.selectedItems;
+
+ if (items.length !== 2) return;
+
+ for (var i in items) {
+ if (i > 0) {
+ items[0].subtract(items[i]);
+ }
+ }
+
+ for (var i in items) {
+ items[i].remove();
+ }
+
+ paper.tool.onUpdateImage();
+ }
+
+ function exclude() {
+ let paper = feature.traps.getPaper();
+ let items = paper.project.selectedItems;
+
+ if (items.length !== 2) return;
+
+ for (var i in items) {
+ if (i > 0) {
+ items[0].exclude(items[i]);
+ }
+ }
+
+ for (var i in items) {
+ items[i].remove();
+ }
+
+ paper.tool.onUpdateImage();
+ }
+
+ function intersect() {
+ let paper = feature.traps.getPaper();
+ let items = paper.project.selectedItems;
+
+ if (items.length !== 2) return;
+
+ for (var i in items) {
+ if (i > 0) {
+ items[0].intersect(items[i]);
+ }
+ }
+
+ for (var i in items) {
+ items[i].remove();
+ }
+
+ paper.tool.onUpdateImage();
+ }
+
+ ScratchTools.waitForElements(
+ "div[class^='mode-tools_mod-labeled-icon-height_']",
+ async function (row) {
+ if (row.querySelector(".ste-more-functions")) return;
+
+ let functions = [
+ {
+ name: "Unite",
+ icon: "function-unite",
+ callback: unite,
+ },
+ {
+ name: "Subtract",
+ icon: "function-subtract",
+ callback: subtract,
+ },
+ {
+ name: "Exclude",
+ icon: "function-exclude",
+ callback: exclude,
+ },
+ {
+ name: "Intersect",
+ icon: "function-intersect",
+ callback: intersect,
+ },
+ ];
+
+ for (var i in functions) {
+ row.appendChild(makeButton(functions[i]));
+ }
+
+ let align = await ScratchTools.waitForElement(".ste-align-items");
+ row.appendChild(align);
+ }
+ );
+
+ feature.redux.subscribe(function () {
+ if (document.querySelector(".ste-more-functions")) {
+ let span = document.querySelector(".ste-more-functions");
+ if (
+ feature.traps.paint().format === "BITMAP" ||
+ feature.traps.paint().selectedItems?.length < 2
+ ) {
+ document.querySelectorAll(".ste-more-functions").forEach(function (el) {
+ el.classList.add("button_mod-disabled_1rf31");
+ });
+ } else {
+ document.querySelectorAll(".ste-more-functions").forEach(function (el) {
+ el.classList.remove("button_mod-disabled_1rf31");
+ });
+ }
+ }
+ });
+
+ function makeButton({ name, icon, callback }) {
+ let span = document.createElement("span");
+ span.className =
+ "button_button_u6SE2 labeled-icon-button_mod-edit-field_1bXYC ste-more-functions";
+ span.role = "button";
+
+ let img = document.createElement("img");
+ img.src = feature.self.getResource(icon);
+ img.className = "labeled-icon-button_edit-field-icon_3j-Pf";
+ img.alt = name;
+ img.title = name;
+ img.draggable = false;
+ span.appendChild(img);
+
+ let label = document.createElement("span");
+ label.textContent = name;
+ label.className = "labeled-icon-button_edit-field-title_1ZoEV";
+ span.appendChild(label);
+
+ span.addEventListener("click", function (e) {
+ if (span.className.includes("disabled")) return;
+ callback();
+ });
+
+ feature.self.hideOnDisable(span);
+
+ return span;
+ }
+}
diff --git a/features/more-paint-functions/style.css b/features/more-paint-functions/style.css
new file mode 100644
index 00000000..752ac1b7
--- /dev/null
+++ b/features/more-paint-functions/style.css
@@ -0,0 +1,7 @@
+div[class*='mode-tools_mode-tools_'] > div[class*='mode-tools_mod-dashed-border_']:nth-child(1), div[class*='mode-tools_mode-tools_'] > div[class*='mode-tools_mod-dashed-border_']:nth-child(2) {
+ display: none;
+}
+
+div[class*='mode-tools_mode-tools_'] > div[class*='mode-tools_mod-labeled-icon-height_']:nth-child(3) {
+ margin-left: 0px !important;
+}
\ No newline at end of file