Skip to content

Commit 3e1b711

Browse files
committed
Dark paint editor
1 parent 245630b commit 3e1b711

File tree

8 files changed

+180
-7
lines changed

8 files changed

+180
-7
lines changed

api/feature/traps.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,5 +6,6 @@ export default function () {
66
paint: ScratchTools.Scratch.scratchPaint,
77
sound: ScratchTools.Scratch.scratchSound,
88
blocks: ScratchTools.traps.getScratchBlocks,
9+
getPaper: ScratchTools.Scratch.getPaper,
910
};
1011
}

api/spaces.js

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,31 @@ ScratchTools.appendToSharedSpace = function ({ space, element, order, scope }) {
170170
);
171171
},
172172
},
173+
paintEditorZoomControls: {
174+
element: () => {
175+
return (
176+
q(".sa-paintEditorZoomControls-wrapper") ||
177+
(() => {
178+
const wrapper = Object.assign(document.createElement("div"), {
179+
className: "sa-paintEditorZoomControls-wrapper",
180+
});
181+
182+
wrapper.style.display = "flex";
183+
wrapper.style.flexDirection = "row-reverse";
184+
wrapper.style.height = "calc(1.95rem + 2px)";
185+
186+
const zoomControls = q("[class^='paint-editor_zoom-controls']");
187+
188+
zoomControls.replaceWith(wrapper);
189+
wrapper.appendChild(zoomControls);
190+
191+
return wrapper;
192+
})()
193+
);
194+
},
195+
from: () => [],
196+
until: () => [],
197+
},
173198
assetContextMenuAfterDelete: {
174199
element: () => scope,
175200
from: () => {

api/vm.js

Lines changed: 40 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ ScratchTools.traps = {
5353
scratchGui: ScratchTools.Scratch.scratchGui || null,
5454
scratchPaint: ScratchTools.Scratch.scratchPaint || null,
5555
scratchSound: ScratchTools.Scratch.scratchSound || null,
56+
paper: ScratchTools.Scratch.getPaper || null,
5657
getVm: function () {
5758
return vm;
5859
},
@@ -73,10 +74,10 @@ const waitForContextMenu = function ({ id, callback, block, disabled, label }) {
7374
label,
7475
});
7576
return {
76-
delete: function() {
77-
delete openContextMenus[openContextMenus.indexOf(insertion)]
78-
}
79-
}
77+
delete: function () {
78+
delete openContextMenus[openContextMenus.indexOf(insertion)];
79+
},
80+
};
8081
};
8182

8283
let handledProcedures = {};
@@ -177,14 +178,46 @@ ScratchTools.Scratch.waitForContextMenu = function (info) {
177178
ScratchTools.Scratch.scratchPaint = function () {
178179
var app = document.querySelector(".paint-editor_mode-selector_28iiQ");
179180
if (app !== null) {
180-
return app[
181-
Object.keys(app).find((key) => key.startsWith("__reactInternalInstance"))
182-
].child.stateNode.store.getState()?.scratchPaint || null;
181+
return (
182+
app[
183+
Object.keys(app).find((key) =>
184+
key.startsWith("__reactInternalInstance")
185+
)
186+
].child.stateNode.store.getState()?.scratchPaint || null
187+
);
183188
} else {
184189
return null;
185190
}
186191
};
187192

193+
ScratchTools.Scratch.getPaper = function () {
194+
let paintElement = document.querySelector(
195+
"[class*='paint-editor_mode-selector']"
196+
);
197+
let paintState =
198+
paintElement[
199+
Object.keys(paintElement).find((key) =>
200+
key.startsWith("__reactInternalInstance")
201+
)
202+
].child;
203+
let tool;
204+
while (paintState) {
205+
let paintIn = paintState.child?.stateNode;
206+
if (paintIn?.tool) {
207+
tool = paintIn.tool;
208+
break;
209+
}
210+
if (paintIn?.blob && paintIn?.blob.tool) {
211+
tool = paintIn.blob.tool;
212+
break;
213+
}
214+
paintState = paintState.sibling;
215+
}
216+
if (tool) {
217+
return tool._scope;
218+
}
219+
};
220+
188221
async function alertForUpdates() {
189222
if (ScratchTools.Scratch.scratchGui().mode.hasEverEnteredEditor) {
190223
var purple = await (
Lines changed: 3 additions & 0 deletions
Loading
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
{
2+
"title": "Switch Paint Background",
3+
"description": "Adds a button next to the zoom controls in the paint editor that allows you to switch the background color of the paint editor between light and dark.",
4+
"credits": [
5+
{ "username": "GarboMuffin", "url": "https://scratch.mit.edu/users/GarboMuffin/" },
6+
{ "username": "Mechanical_coding", "url": "https://scratch.mit.edu/users/Mechanical_coding/" },
7+
{ "username": "rgantzos", "url": "https://scratch.mit.edu/users/rgantzos/" }
8+
],
9+
"type": ["Editor"],
10+
"tags": ["New", "Featured"],
11+
"dynamic": true,
12+
"scripts": [{ "file": "script.js", "runOn": "/projects/*" }],
13+
"styles": [{ "file": "style.css", "runOn": "/projects/*" }],
14+
"resources": [{ "name": "dark-paint-btn", "path": "/dark.svg" }]
15+
}
Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
export default async function ({ feature, console }) {
2+
let isDark;
3+
4+
const BACKGROUND_LIGHT = "#FFFFFF";
5+
const BACKGROUND_TILE_LIGHT = "#D9E3F2";
6+
const BACKGROUND_DARK = "#111";
7+
const BACKGROUND_TILE_DARK = "#222";
8+
const WORKSPACE_BOUNDS_LIGHT = "#ECF1F9";
9+
const WORKSPACE_BOUNDS_DARK = "#333";
10+
const OUTLINE_INNER_LIGHT = "#FFFFFF";
11+
const OUTLINE_INNER_DARK = "#555555";
12+
13+
ScratchTools.waitForElements(
14+
"div[class^='paint-editor_zoom-controls_']",
15+
function () {
16+
isDark = false
17+
18+
if (document.querySelector(".ste-dark-paint-btn")) return;
19+
20+
let button = document.createElement("div")
21+
button.className = "button-group_button-group_2_h4y ste-dark-paint-btn"
22+
23+
let span = document.createElement("span")
24+
span.className = "button_button_u6SE2 paint-editor_button-group-button_1I1tm"
25+
span.role = "button"
26+
button.appendChild(span)
27+
28+
let img = document.createElement("img")
29+
img.src = feature.self.getResource("dark-paint-btn")
30+
span.appendChild(img)
31+
32+
button.addEventListener("click", function() {
33+
isDark = !isDark
34+
updateTheme(isDark)
35+
})
36+
37+
feature.self.hideOnDisable(button)
38+
39+
ScratchTools.appendToSharedSpace({
40+
space: "paintEditorZoomControls",
41+
element: button,
42+
order: 0,
43+
});
44+
}
45+
);
46+
47+
function updateTheme(isDark) {
48+
let paper = feature.traps.getPaper();
49+
50+
let backgroundLayer = paper.project.layers.find(
51+
(el) => el.data?.["isBackgroundGuideLayer"]
52+
);
53+
let outlineLayer = paper.project.layers.find(
54+
(el) => el.data?.["isOutlineLayer"]
55+
);
56+
57+
const bitmapChildren = backgroundLayer.bitmapBackground.children;
58+
bitmapChildren[0].fillColor = isDark ? BACKGROUND_DARK : BACKGROUND_LIGHT;
59+
bitmapChildren[1].fillColor = isDark
60+
? BACKGROUND_TILE_DARK
61+
: BACKGROUND_TILE_LIGHT;
62+
63+
const vectorChildren = backgroundLayer.vectorBackground.children;
64+
vectorChildren[0].fillColor = isDark
65+
? WORKSPACE_BOUNDS_DARK
66+
: WORKSPACE_BOUNDS_LIGHT;
67+
vectorChildren[1].children[0].fillColor = isDark
68+
? BACKGROUND_DARK
69+
: BACKGROUND_LIGHT;
70+
vectorChildren[1].children[1].fillColor = isDark
71+
? BACKGROUND_TILE_DARK
72+
: BACKGROUND_TILE_LIGHT;
73+
74+
outlineLayer.children[0].strokeColor = isDark
75+
? OUTLINE_INNER_DARK
76+
: OUTLINE_INNER_LIGHT;
77+
}
78+
79+
feature.addEventListener("disabled", function() {
80+
updateTheme(false)
81+
})
82+
83+
feature.addEventListener("enabled", function() {
84+
updateTheme(isDark || false)
85+
})
86+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
.ste-dark-paint-btn img {
2+
width: 1.25rem;
3+
height: 1.25rem;
4+
vertical-align: middle;
5+
}

features/features.json

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,9 @@
11
[
2+
{
3+
"version": 2,
4+
"id": "dark-paint-editor",
5+
"versionAdded": "v3.5.0"
6+
},
27
{
38
"version": 2,
49
"id": "specific-replies",

0 commit comments

Comments
 (0)