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 @@ +<?xml version="1.0" encoding="UTF-8"?> +<svg id="Layer_1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 13 13"> + <defs> + <style> + .cls-1 { + fill: #7860aa; + fill-rule: evenodd; + } + </style> + </defs> + <path class="cls-1" d="M13,1.08v6.85c0,.6-.47,1.07-1.07,1.07h-2.94v-3.92c0-.59-.48-1.08-1.07-1.08h-3.91V1.07c0-.6.48-1.07,1.07-1.07h6.85c.6,0,1.07.49,1.07,1.08Z"/> + <path class="cls-1" d="M8.99,9v2.93c0,.6-.48,1.07-1.07,1.07H1.07c-.6,0-1.07-.49-1.07-1.08v-6.85c0-.6.47-1.07,1.07-1.07h2.94v3.92c0,.59.48,1.08,1.07,1.08h3.91Z"/> +</svg> \ 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 @@ +<?xml version="1.0" encoding="UTF-8"?> +<svg id="Layer_1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 13 13"> + <defs> + <style> + .cls-1 { + opacity: .5; + } + + .cls-2 { + fill: #7860aa; + fill-rule: evenodd; + } + </style> + </defs> + <g class="cls-1"> + <path class="cls-2" d="M11.93,0h-6.85c-.6,0-1.07.47-1.07,1.07h0v2.93h3.91c.6,0,1.07.49,1.07,1.08v3.92h2.94c.6,0,1.07-.47,1.07-1.07h0V1.08c0-.6-.47-1.08-1.07-1.08Z"/> + <path class="cls-2" d="M5.08,9c-.6,0-1.07-.49-1.07-1.08v-3.92H1.07c-.6,0-1.07.47-1.07,1.07h0v6.85c0,.6.47,1.08,1.07,1.08h6.85c.6,0,1.07-.47,1.07-1.07h0v-2.93h-3.91Z"/> + </g> + <path class="cls-2" d="M8.99,6v-.92c0-.6-.47-1.08-1.07-1.08h-3.91v3.92c0,.6.47,1.08,1.07,1.08h3.91v-3Z"/> +</svg> \ 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 @@ +<?xml version="1.0" encoding="UTF-8"?> +<svg id="Layer_1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 13 13"> + <defs> + <style> + .cls-1 { + opacity: .5; + } + + .cls-1, .cls-2 { + fill: #7860aa; + fill-rule: evenodd; + } + </style> + </defs> + <path class="cls-2" d="M13,1.08v6.85c0,.6-.47,1.07-1.07,1.07h-2.94v-3.92c0-.59-.48-1.08-1.07-1.08h-3.91V1.07c0-.6.48-1.07,1.07-1.07h6.85c.6,0,1.07.49,1.07,1.08Z"/> + <path class="cls-1" d="M7.92,4H1.07c-.6,0-1.07.47-1.07,1.07h0v6.85c0,.6.47,1.08,1.07,1.08h6.85c.6,0,1.07-.47,1.07-1.07h0v-6.85c0-.6-.47-1.08-1.07-1.08Z"/> +</svg> \ 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 @@ +<?xml version="1.0" encoding="UTF-8"?> +<svg id="Layer_1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 13 13"> + <defs> + <style> + .cls-1 { + fill: #7860aa; + fill-rule: evenodd; + } + </style> + </defs> + <path class="cls-1" d="M11.93,0h-6.85c-.6,0-1.07.47-1.07,1.07h0v6.85c0,.6.47,1.08,1.07,1.08h6.85c.6,0,1.07-.47,1.07-1.07h0V1.08c0-.6-.47-1.08-1.07-1.08Z"/> + <path class="cls-1" d="M7.92,4H1.07c-.6,0-1.07.47-1.07,1.07h0v6.85c0,.6.47,1.08,1.07,1.08h6.85c.6,0,1.07-.47,1.07-1.07h0v-6.85c0-.6-.47-1.08-1.07-1.08Z"/> +</svg> \ 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