soiz1's picture
Upload 2891 files
6bcb42f verified
raw
history blame
13.5 kB
import {
removeAlpha,
multiply,
brighten,
alphaBlend,
recolorFilter,
} from "../../libraries/common/cs/text-color.esm.js";
const dataUriRegex = new RegExp("^data:image/svg\\+xml;base64,([A-Za-z0-9+/=]*)$");
const extensionsCategory = {
id: null,
settingId: "Pen-color",
colorId: "pen",
};
const twCategory = {
id: null,
settingId: "tw-color",
colorId: "tw"
};
const saCategory = {
settingId: "sa-color",
colorId: "sa",
};
const categories = [
{
id: "motion",
settingId: "motion-color",
colorId: "motion",
},
{
id: "looks",
settingId: "looks-color",
colorId: "looks",
},
{
id: "sound",
settingId: "sounds-color",
colorId: "sounds",
},
{
id: "events",
settingId: "events-color",
colorId: "event",
},
{
id: "control",
settingId: "control-color",
colorId: "control",
},
{
id: "sensing",
settingId: "sensing-color",
colorId: "sensing",
},
{
id: "operators",
settingId: "operators-color",
colorId: "operators",
},
{
id: "variables",
settingId: "data-color",
colorId: "data",
},
{
id: "lists",
settingId: "data-lists-color",
colorId: "data_lists",
},
{
id: "myBlocks",
settingId: "custom-color",
colorId: "more",
},
extensionsCategory,
twCategory,
saCategory,
];
export default async function ({ addon, console }) {
const Blockly = await addon.tab.traps.getBlockly();
const originalColors = JSON.parse(JSON.stringify(Blockly.Colours));
originalColors.sa = {
primary: "#29beb8",
secondary: "#3aa8a4",
tertiary: "#3aa8a4",
};
originalColors.tw = {
primary: "#ff4c4c",
secondary: "#e64444",
tertiary: "#e64444"
};
let textModeSetting = addon.settings.get("text");
const textMode = () => (addon.self.disabled ? "white" : textModeSetting);
const isColoredTextMode = () => textMode() === "colorOnWhite" || textMode() === "colorOnBlack";
const primaryColor = (category) => {
if (addon.self.disabled) return originalColors[category.colorId].primary;
// Colored on white: can't use #ffffff because of editor-dark-mode dropdown div handling
if (textMode() === "colorOnWhite") return "#feffff";
if (textMode() === "colorOnBlack") return "#282828";
return addon.settings.get(category.settingId);
};
const secondaryColor = (category) => {
if (addon.self.disabled) return originalColors[category.colorId].secondary;
if (isColoredTextMode())
return alphaBlend(primaryColor(category), multiply(addon.settings.get(category.settingId), { a: 0.15 }));
if (textMode() === "black") return brighten(addon.settings.get(category.settingId), { r: 0.6, g: 0.6, b: 0.6 });
return multiply(addon.settings.get(category.settingId), { r: 0.9, g: 0.9, b: 0.9 });
};
const tertiaryColor = (category) => {
if (addon.self.disabled) return originalColors[category.colorId].tertiary;
if (isColoredTextMode()) return addon.settings.get(category.settingId);
if (textMode() === "black") return multiply(addon.settings.get(category.settingId), { r: 0.65, g: 0.65, b: 0.65 });
return multiply(addon.settings.get(category.settingId), { r: 0.8, g: 0.8, b: 0.8 });
};
const fieldBackground = (category) => {
// Background color for open dropdowns and (in some textModes) Boolean inputs
// The argument can be a block, field, or category
if (category instanceof Blockly.Block || category instanceof Blockly.Field) {
const block = category instanceof Blockly.Block ? category : category.sourceBlock_;
if (isColoredTextMode() || textMode() === "black") {
let primary;
if (block.isShadow() && block.getParent()) primary = block.getParent().getColour();
else primary = block.getColour();
if (isColoredTextMode()) return alphaBlend(primary, multiply(block.getColourTertiary(), { a: 0.25 }));
else return brighten(primary, { r: 0.4, g: 0.4, b: 0.4 });
}
return block.getColourTertiary();
}
if (isColoredTextMode())
return alphaBlend(primaryColor(category), multiply(addon.settings.get(category.settingId), { a: 0.25 }));
if (textMode() === "black") return brighten(primaryColor(category), { r: 0.4, g: 0.4, b: 0.4 });
return tertiaryColor(category);
};
const textColor = (field) => {
if (addon.self.disabled || textMode() === "white") return "#ffffff";
if (textMode() === "black") return "#000000";
if (field) return field.sourceBlock_.getColourTertiary();
return "#000000";
};
const uncoloredTextColor = () => {
if (addon.self.disabled) return "#ffffff";
return {
white: "#ffffff",
black: "#575e75",
colorOnWhite: "#575e75",
colorOnBlack: "#ffffff",
}[textMode];
};
const otherColor = (settingId, colorId) => {
if (addon.self.disabled) return originalColors[colorId];
return addon.settings.get(settingId);
};
// Blockly doesn't handle colors with transparency
const oldBlockMakeColor = Blockly.Block.prototype.makeColour_;
Blockly.Block.prototype.makeColour_ = function (color) {
if (typeof color === "string" && /^#(?:[0-9A-Za-z]{2}){3,4}$/.test(color)) return color;
return oldBlockMakeColor(color);
};
const oldCategoryCreateDom = Blockly.Toolbox.Category.prototype.createDom;
Blockly.Toolbox.Category.prototype.createDom = function () {
// Category bubbles
if (this.iconURI_) {
if (addon.self.disabled) return oldCategoryCreateDom.call(this);
if (!["sa-blocks", "videoSensing", "text2speech"].includes(this.id_)) return oldCategoryCreateDom.call(this);
const match = dataUriRegex.exec(this.iconURI_);
if (match) {
const oldSvg = atob(match[1]);
const category = this.id_ === "sa-blocks" ? saCategory : extensionsCategory;
const newColor = isColoredTextMode ? tertiaryColor(category) : primaryColor(category);
if (newColor) {
const newSvg = oldSvg.replace(/#29beb8|#0ebd8c/gi, newColor);
this.iconURI_ = `data:image/svg+xml;base64,${btoa(newSvg)}`;
}
}
}
oldCategoryCreateDom.call(this);
if (this.iconURI_) return;
const category = categories.find((item) => item.id === this.id_);
if (!category) return;
this.bubble_.style.backgroundColor = isColoredTextMode() ? fieldBackground(category) : primaryColor(category);
this.bubble_.style.borderColor = tertiaryColor(category);
};
const oldBlockSetColour = Blockly.Block.prototype.setColour;
Blockly.Block.prototype.setColour = function (colour, colourSecondary, colourTertiary) {
// Extension blocks (color is set by VM)
if (colour.toLowerCase() === originalColors.pen.primary.toLowerCase()) {
colour = primaryColor(extensionsCategory);
colourSecondary = secondaryColor(extensionsCategory);
colourTertiary = tertiaryColor(extensionsCategory);
}
// TurboWarp Blocks
if (this.type.startsWith("tw_")) {
colour = primaryColor(twCategory);
colourSecondary = secondaryColor(twCategory);
colourTertiary = tertiaryColor(twCategory);
}
return oldBlockSetColour.call(this, colour, colourSecondary, colourTertiary);
};
const oldBlockUpdateColour = Blockly.BlockSvg.prototype.updateColour;
Blockly.BlockSvg.prototype.updateColour = function () {
oldBlockUpdateColour.call(this);
// Boolean inputs
if (isColoredTextMode()) {
for (const input of this.inputList) {
if (input.outlinePath) {
input.outlinePath.setAttribute("fill", fieldBackground(this));
}
}
}
};
const oldBlockShowContextMenu = Blockly.BlockSvg.prototype.showContextMenu_;
Blockly.BlockSvg.prototype.showContextMenu_ = function (e) {
Blockly.WidgetDiv.DIV.style.setProperty("--editorTheme3-hoveredItem", fieldBackground(this));
return oldBlockShowContextMenu.call(this, e);
};
const oldFieldLabelInit = Blockly.FieldLabel.prototype.init;
Blockly.FieldLabel.prototype.init = function () {
// Labels
oldFieldLabelInit.call(this);
this.textElement_.style.fill = textColor(this);
};
const oldFieldTextInputInit = Blockly.FieldTextInput.prototype.init;
Blockly.FieldTextInput.prototype.init = function () {
// Text inputs
oldFieldTextInputInit.call(this);
if (this.sourceBlock_.isShadow()) return;
// Labels in custom block editor
this.box_.setAttribute("fill", fieldBackground(this));
};
const oldFieldDropdownInit = Blockly.FieldDropdown.prototype.init;
Blockly.FieldDropdown.prototype.init = function () {
// Dropdowns
oldFieldDropdownInit.call(this);
this.textElement_.style.setProperty("fill", textColor(this), "important");
if (textColor(this) !== "#ffffff") this.arrow_.style.filter = recolorFilter(textColor(this));
};
const oldFieldDropdownShowEditor = Blockly.FieldDropdown.prototype.showEditor_;
Blockly.FieldDropdown.prototype.showEditor_ = function () {
oldFieldDropdownShowEditor.call(this);
// Open dropdowns
if (!this.disableColourChange_) {
if (this.sourceBlock_.isShadow()) {
this.sourceBlock_.setShadowColour(fieldBackground(this));
} else if (this.box_) {
this.box_.setAttribute("fill", fieldBackground(this));
}
}
// Dropdown menus
let primaryColor;
if (this.sourceBlock_.isShadow() && this.sourceBlock_.getParent())
primaryColor = this.sourceBlock_.getParent().getColour();
else primaryColor = this.sourceBlock_.getColour();
Blockly.DropDownDiv.DIV_.style.backgroundColor = removeAlpha(primaryColor);
if (isColoredTextMode()) {
Blockly.DropDownDiv.getContentDiv().style.setProperty("--editorTheme3-hoveredItem", fieldBackground(this));
} else {
Blockly.DropDownDiv.getContentDiv().style.removeProperty("--editorTheme3-hoveredItem");
}
};
const oldFieldVariableInit = Blockly.FieldVariable.prototype.init;
Blockly.FieldVariable.prototype.init = function () {
// Variable dropdowns
oldFieldVariableInit.call(this);
this.textElement_.style.setProperty("fill", textColor(this), "important");
};
const oldFieldVariableGetterInit = Blockly.FieldVariableGetter.prototype.init;
Blockly.FieldVariableGetter.prototype.init = function () {
// Variable reporters
oldFieldVariableGetterInit.call(this);
this.textElement_.style.fill = textColor(this);
};
const oldFieldMatrixUpdateMatrix = Blockly.FieldMatrix.prototype.updateMatrix_;
Blockly.FieldMatrix.prototype.updateMatrix_ = function () {
// Matrix inputs
oldFieldMatrixUpdateMatrix.call(this);
for (let i = 0; i < this.matrix_.length; i++) {
if (this.matrix_[i] !== "0") {
this.fillMatrixNode_(this.ledButtons_, i, uncoloredTextColor());
this.fillMatrixNode_(this.ledThumbNodes_, i, uncoloredTextColor());
}
}
};
const oldFieldMatrixCreateButton = Blockly.FieldMatrix.prototype.createButton_;
Blockly.FieldMatrix.prototype.createButton_ = function (fill) {
if (fill === "#FFFFFF") fill = uncoloredTextColor();
return oldFieldMatrixCreateButton.call(this, fill);
};
const oldFieldVerticalSeparatorInit = Blockly.FieldVerticalSeparator.prototype.init;
Blockly.FieldVerticalSeparator.prototype.init = function () {
// Vertical line between extension icon and block label
oldFieldVerticalSeparatorInit.call(this);
if (textMode() === "black") this.lineElement_.setAttribute("stroke", this.sourceBlock_.getColourTertiary());
};
const updateColors = () => {
const vm = addon.tab.traps.vm;
textModeSetting = addon.settings.get("text");
for (const category of categories) {
// CSS variables are used for compatibility with other addons
const prefix = `--editorTheme3-${category.colorId}`;
for (const [name, value] of Object.entries({
primary: primaryColor(category),
secondary: secondaryColor(category),
tertiary: tertiaryColor(category),
field: fieldBackground(category),
})) {
document.documentElement.style.setProperty(`${prefix}-${name}`, value);
}
// Update Blockly.Colours
if (!Blockly.Colours[category.colorId]) continue;
Blockly.Colours[category.colorId].primary = primaryColor(category);
Blockly.Colours[category.colorId].secondary = secondaryColor(category);
Blockly.Colours[category.colorId].tertiary = tertiaryColor(category);
}
addon.tab.setCustomBlockColor({
color: primaryColor(saCategory),
secondaryColor: secondaryColor(saCategory),
tertiaryColor: tertiaryColor(saCategory),
});
Blockly.Colours.textField = otherColor("input-color", "textField");
if (uncoloredTextColor() === "#575e75") Blockly.Colours.fieldShadow = "rgba(0, 0, 0, 0.15)";
else Blockly.Colours.fieldShadow = originalColors.fieldShadow;
const workspace = Blockly.getMainWorkspace();
const flyout = workspace.getFlyout();
const toolbox = workspace.getToolbox();
// Reload toolbox
if (vm.editingTarget) {
vm.emitWorkspaceUpdate();
}
const flyoutWorkspace = flyout.getWorkspace();
Blockly.Xml.clearWorkspaceAndLoadFromXml(Blockly.Xml.workspaceToDom(flyoutWorkspace), flyoutWorkspace);
toolbox.populate_(workspace.options.languageTree);
workspace.toolboxRefreshEnabled_ = true;
};
updateColors();
addon.settings.addEventListener("change", updateColors);
addon.self.addEventListener("disabled", updateColors);
addon.self.addEventListener("reenabled", updateColors);
}