From 7554dfa22b0f80696758cef15954bf657ac16929 Mon Sep 17 00:00:00 2001 From: codingisfun2831 <124097137+codingisfun2831t@users.noreply.github.com> Date: Sat, 30 May 2026 16:40:03 -0400 Subject: [PATCH 1/5] add reporter block shapes mod - only color for now --- mods/reporter-block-shapes.js | 145 ++++++++++++++++++++++++++++++++++ 1 file changed, 145 insertions(+) create mode 100644 mods/reporter-block-shapes.js diff --git a/mods/reporter-block-shapes.js b/mods/reporter-block-shapes.js new file mode 100644 index 0000000..4cd8ea1 --- /dev/null +++ b/mods/reporter-block-shapes.js @@ -0,0 +1,145 @@ +return class extends Mod { + // Metadata + ID = "reporter-block-shapes"; // the id of the addon + NAME = "Reporter Block Shapes"; // human-readable name + DESCRIPTION = "Change the shape of a reporter depending on what it returns."; // description + VERSION = "1.0.0"; // version + AUTHOR = "codingisfun2831"; // author + DEPENDS = []; // dependencies (addon ids, useful for libraries) + DO_MENU = false; // whether to add a menu item + + // Main function - gets ran when the addon is loaded + main() { + // getBlockShape - return shape string for a reporter block + + ReporterBlockMorph.prototype.getBlockShape = function () { + var choice; + + if (this.isPredicate) return "Diamond"; + if (this.reports === "color") return "Rectangle"; + + if (this.selector == "getPenAttribute" || this.selector == "reportAspect") { + choice = this.inputs()[0].evaluate(); + if (choice instanceof Array && choice[0] === "color") return "Rectangle"; + } + + return "Oval"; + } + + // fix up outlinePath for that + ReporterBlockMorph.prototype._outlinePath = + ReporterBlockMorph.prototype.outlinePath; + ReporterBlockMorph.prototype.outlinePath = function (ctx, inset) { + let shape = this.getBlockShape(); + let func = "outlinePath" + shape; + + if (this[func]) this[func](ctx, inset); + else this.outlinePathOval(ctx, inset); + }; + + // and drawEdges + ReporterBlockMorph.prototype._drawEdges = + ReporterBlockMorph.prototype.drawEdges; + ReporterBlockMorph.prototype.drawEdges = function (ctx) { + let shape = this.getBlockShape(); + let func = "drawEdges" + shape; + + if (this[func]) this[func](ctx); + else this.drawEdgesOval(ctx); + }; + + // rectangle shape + ReporterBlockMorph.prototype.outlinePathRectangle = function (ctx, inset) { + // not how i want to do it at all, but we need to do this so + // c slots work fine (no color reporter should use one, but + // i'm still gonna do this) + + // draw the 'flat' shape + var h = this.height(), + w = this.width(), + pos = this.position(); + + // top left: + ctx.arc( + 0, + 0, + 0, + radians(-180), + radians(-90), + false + ); + + // top right: + ctx.arc( + w, + 0, + 0, + radians(-90), + radians(-0), + false + ); + + // C-Slots + this.cSlots().forEach(slot => { + slot.outlinePath(ctx, inset, slot.position().subtract(pos)); + }); + + // bottom right: + ctx.arc( + w, + h, + 0, + radians(0), + radians(90), + false + ); + + // bottom left: + ctx.arc( + 0, + h, + 0, + radians(90), + radians(180), + false + ); + + ctx.lineTo(0, 0); // close the path so we can clip it for rings + }; + + ReporterBlockMorph.prototype.drawEdgesRectangle = function (ctx) { + var h = this.height(), + w = this.width(); + + ctx.lineWidth = this.edge; + + ctx.beginPath(); + ctx.moveTo(0, h); + ctx.lineTo(0, 0); + ctx.lineTo(w, 0); + ctx.strokeStyle = this.cachedClrBright; + ctx.stroke(); + + ctx.beginPath(); + ctx.moveTo(w, 0); + ctx.lineTo(w, h); + ctx.lineTo(0, h); + ctx.strokeStyle = this.cachedClrDark; + ctx.stroke(); + }; + } + + // Cleanup function - get ran when the addon is "deleted" + cleanupFunc() { + // delete extra funcs + delete ReporterBlockMorph.prototype.getBlockShape; + delete ReporterBlockMorph.prototype.outlinePathRectangle; + delete ReporterBlockMorph.prototype.drawEdgesRectangle; + + // bring back old funcs + ReporterBlockMorph.prototype.drawEdges = + ReporterBlockMorph.prototype._drawEdges; + ReporterBlockMorph.prototype.outlinePath = + ReporterBlockMorph.prototype._outlinePath; + } +} \ No newline at end of file From 8ebbd349b860e3d8cac69844178341a9a2f9ca34 Mon Sep 17 00:00:00 2001 From: e016 Date: Tue, 2 Jun 2026 11:28:55 -0600 Subject: [PATCH 2/5] start work on block shapes addon --- mods/block-shapes.js | 217 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 217 insertions(+) create mode 100644 mods/block-shapes.js diff --git a/mods/block-shapes.js b/mods/block-shapes.js new file mode 100644 index 0000000..3cadd42 --- /dev/null +++ b/mods/block-shapes.js @@ -0,0 +1,217 @@ +return class extends Mod { + // Metadata + ID = "reporter-block-shapes"; // the id of the addon + NAME = "Reporter Block Shapes"; // human-readable name + DESCRIPTION = "Change the shape of a reporter depending on what it returns. Inspired by Snavanced, by alessandrito123"; // description + VERSION = "1.0.0"; // version + AUTHOR = "codingisfun2831, d016"; // author + DEPENDS = []; // dependencies (addon ids, useful for libraries) + DO_MENU = false; // whether to add a menu item + OPTIONS_FORMAT = [ + { + id: "squareType", + name: "Square Block Type", + type: "string", + default: "color", + menu: { + "color": "color", + "string": "text", + "list": "list", + }, + readOnly: true, + } + ] + + // Main function - gets ran when the addon is loaded + main() { + // getBlockShape - return shape string for a reporter block + let options = this.options, + api = this.api; + this.addEventListener("optionsChanged", (e) => { + api.ide.rerender() + }); + ReporterBlockMorph.prototype.getBlockShape = function () { + var choice; + + if (this.reports === options.squareType) return "Rectangle"; + if ([ + "agent", + "sprite", + "stage", + "costume", // should we include costumes and sounds??? + "sound" + ].includes(this.reports)) return "Object"; + if (this.isPredicate) return "Diamond"; + + if ((this.selector == "getPenAttribute" || this.selector == "reportAspect") && options.squareType === "color") { + choice = this.inputs()[0].evaluate(); + if (choice instanceof Array && choice[0] === "color") return "Rectangle"; + } + + return "Oval"; + } + + // fix up outlinePath for that + api.wrapFunction(ReporterBlockMorph.prototype, "outlinePath", function (ctx, inset) { + let shape = this.getBlockShape(); + let func = "outlinePath" + shape; + + if (this[func]) this[func](ctx, inset); + else this.outlinePathOval(ctx, inset); + }, true); + + // and drawEdges + api.wrapFunction(ReporterBlockMorph.prototype, "drawEdges", function (ctx) { + let shape = this.getBlockShape(); + let func = "drawEdges" + shape; + + if (this[func]) this[func](ctx); + else this.drawEdgesOval(ctx); + }, true); + + // rectangle shape + ReporterBlockMorph.prototype.outlinePathRectangle = function (ctx, inset) { + // not how i want to do it at all, but we need to do this so + // c slots work fine (no color reporter should use one, but + // i'm still gonna do this) + + // draw the 'flat' shape + var h = this.height(), + w = this.width(), + pos = this.position(), + corner = this.corner; + + // top left: + ctx.arc( + corner + inset, + corner + inset, + corner, + radians(-180), + radians(-90), + false + ); + + // top right: + ctx.arc( + w - corner - inset, + corner + inset, + corner, + radians(-90), + radians(-0), + false + ); + + // C-Slots + this.cSlots().forEach(slot => { + slot.outlinePath(ctx, inset, slot.position().subtract(pos)); + }); + + // bottom right: + ctx.arc( + w - corner - inset, + h - corner - inset, + corner, + radians(0), + radians(90), + false + ); + + // bottom left: + ctx.arc( + corner + inset, + h - corner - inset, + corner, + radians(90), + radians(180), + false + ); + + ctx.lineTo(inset, corner + inset); // close the path so we can clip it for rings + }; + + ReporterBlockMorph.prototype.drawEdgesRectangle = function (ctx) { + var h = this.height(), + w = this.width(); + + ctx.lineWidth = this.edge; + + ctx.beginPath(); + ctx.moveTo(0, h); + ctx.lineTo(0, 0); + ctx.lineTo(w, 0); + ctx.strokeStyle = this.cachedClrBright; + ctx.stroke(); + + ctx.beginPath(); + ctx.moveTo(w, 0); + ctx.lineTo(w, h); + ctx.lineTo(0, h); + ctx.strokeStyle = this.cachedClrDark; + ctx.stroke(); + }; + + ReporterBlockMorph.prototype.outlinePathObject = function (ctx, inset) { + // draw the 'flat' shape: + var w = this.width(), + h = this.height(), + h2 = Math.floor(h / 2), + r = this.rounding, + right = w - r, + pos = this.position(), + cslots = this.cSlots(); + + ctx.moveTo(r, h2); + ctx.lineTo(inset, inset); + ctx.lineTo(right - inset, inset); + + if (cslots.length) { + this.cSlots().forEach(slot => { + slot.outlinePath(ctx, inset, slot.position().subtract(pos)); + }); + } else { + ctx.lineTo(w - inset, h2); + } + + ctx.lineTo(right - inset, h - inset); + ctx.lineTo(inset, h - inset); + } + ReporterBlockMorph.prototype.drawEdgesObject = function (ctx) { + + } + SyntaxElementMorph.prototype.fixLayout.__blockShapesModLoaded__ = true + if (!SyntaxElementMorph.prototype.fixLayout.__isBlockShapes__) { + SyntaxElementMorph.prototype.fixLayout = new Proxy( + SyntaxElementMorph.prototype.fixLayout, + { + apply(target, ctx, args) { + if (!SyntaxElementMorph.prototype.fixLayout.__blockShapesModLoaded__) { + return Reflect.apply(target, ctx, args) + }; + let isObject = ctx.getBlockShape && (ctx.getBlockShape() === "Object") + if (isObject) { + ctx.isPredicate = true + } + console.warn(ctx, ctx.getBlockShape) + Reflect.apply(target, ctx, args) + if (isObject) { + const parts = ctx.parts(); + ctx.bounds.setWidth(ctx.width() + ctx.corner) + parts.forEach((part) => part.setLeft(part.left() + ctx.corner)) + } + } + } + ) + SyntaxElementMorph.prototype.fixLayout.__isBlockShapes__ = Symbol("thisIsBlockShapes") + } + this.api.ide.refreshIDE(); + } + + // Cleanup function - get ran when the addon is "deleted" + cleanupFunc() { + // delete extra funcs + delete ReporterBlockMorph.prototype.getBlockShape; + delete ReporterBlockMorph.prototype.outlinePathRectangle; + delete ReporterBlockMorph.prototype.drawEdgesRectangle; + SyntaxElementMorph.prototype.fixLayout.__blockShapesModLoaded__ = false + } +} \ No newline at end of file From 2e17e47f05c2d9f718fd7f8490e52b1e18015a85 Mon Sep 17 00:00:00 2001 From: e016 Date: Tue, 2 Jun 2026 11:38:56 -0600 Subject: [PATCH 3/5] added drawEdgesObject to block-shapes.js --- mods/block-shapes.js | 147 ++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 146 insertions(+), 1 deletion(-) diff --git a/mods/block-shapes.js b/mods/block-shapes.js index 3cadd42..5a063d3 100644 --- a/mods/block-shapes.js +++ b/mods/block-shapes.js @@ -176,7 +176,150 @@ return class extends Mod { ctx.lineTo(inset, h - inset); } ReporterBlockMorph.prototype.drawEdgesObject = function (ctx) { - + // add 3D-Effect + var w = this.width(), + h = this.height(), + h2 = Math.floor(h / 2), + r = this.rounding, + shift = this.edge / 2, + cslots = this.cSlots(), + top = this.top(), + y, + gradient; + + ctx.lineWidth = this.edge; + ctx.lineJoin = 'round'; + ctx.lineCap = 'round'; + + // half-tone edges + // bottom left corner + gradient = ctx.createLinearGradient( + r, + 0, + -r, + 0 + ); + gradient.addColorStop(1, this.cachedClr); + gradient.addColorStop(0, this.cachedClrBright); + ctx.strokeStyle = gradient; + ctx.beginPath(); + ctx.moveTo(r, h2); + ctx.lineTo(shift, h - shift); + ctx.closePath(); + ctx.stroke(); + + // normal gradient edges + // top edge: left corner + gradient = ctx.createLinearGradient( + r, + 0, + 0, + 0 + ); + gradient.addColorStop(0, this.cachedClrBright); + gradient.addColorStop(1, this.cachedClr); + ctx.strokeStyle = gradient; + ctx.beginPath(); + ctx.moveTo(r, h2); + ctx.lineTo(shift, shift); + ctx.closePath(); + ctx.stroke(); + + // top edge: straight line + gradient = ctx.createLinearGradient( + 0, + 0, + 0, + this.edge + ); + gradient.addColorStop(0, this.cachedClrBright); + gradient.addColorStop(1, this.cachedClr); + ctx.strokeStyle = gradient; + ctx.beginPath(); + ctx.moveTo(shift, shift); + + // right edge + if (cslots.length) { + // end of top edge + ctx.lineTo(w - r - shift, shift); + ctx.closePath(); + ctx.stroke(); + + // right vertical edge + gradient = ctx.createLinearGradient(w - r - this.edge, 0, w - r, 0); + gradient.addColorStop(0, this.cachedClr); + gradient.addColorStop(1, this.cachedClrDark); + + ctx.lineWidth = this.edge; + ctx.lineJoin = 'round'; + ctx.lineCap = 'round'; + ctx.strokeStyle = gradient; + + ctx.beginPath(); + ctx.moveTo(w - r - shift, this.edge + shift); + cslots.forEach(slot => { + y = slot.top() - top; + ctx.lineTo(w - r - shift, y); + ctx.stroke(); + ctx.beginPath(); + ctx.moveTo(w - r - shift, y + slot.height()); + }); + ctx.lineTo(w - r - shift, h - shift); + ctx.stroke(); + } else { + // end of top edge + ctx.lineTo(w - r, shift); + ctx.closePath(); + ctx.stroke(); + + // top diagonal slope right + gradient = ctx.createLinearGradient( + w - r, + 0, + w + r, + 0 + ); + gradient.addColorStop(0, this.cachedClr); + gradient.addColorStop(1, this.cachedClrDark); + ctx.strokeStyle = gradient; + ctx.beginPath(); + ctx.moveTo(w - shift, h2); + ctx.lineTo(w - r, shift); + ctx.closePath(); + ctx.stroke(); + + // bottom diagonal slope right + gradient = ctx.createLinearGradient( + w - r, + 0, + w, + 0 + ); + gradient.addColorStop(0, this.cachedClr); + gradient.addColorStop(1, this.cachedClrDark); + ctx.strokeStyle = gradient; + ctx.beginPath(); + ctx.moveTo(w - r, h - shift); + ctx.lineTo(w - shift, h2); + ctx.closePath(); + ctx.stroke(); + } + + // bottom edge: straight line + gradient = ctx.createLinearGradient( + 0, + h - this.edge, + 0, + h + ); + gradient.addColorStop(0, this.cachedClr); + gradient.addColorStop(1, this.cachedClrDark); + ctx.strokeStyle = gradient; + ctx.beginPath(); + ctx.moveTo(shift, h - shift); + ctx.lineTo(w - r - shift, h - shift); + ctx.closePath(); + ctx.stroke(); } SyntaxElementMorph.prototype.fixLayout.__blockShapesModLoaded__ = true if (!SyntaxElementMorph.prototype.fixLayout.__isBlockShapes__) { @@ -212,6 +355,8 @@ return class extends Mod { delete ReporterBlockMorph.prototype.getBlockShape; delete ReporterBlockMorph.prototype.outlinePathRectangle; delete ReporterBlockMorph.prototype.drawEdgesRectangle; + delete ReporterBlockMorph.prototype.outlinePathObject; + delete ReporterBlockMorph.prototype.drawEdgesObject; SyntaxElementMorph.prototype.fixLayout.__blockShapesModLoaded__ = false } } \ No newline at end of file From 431e6f07b8cb85d992c265d853f94c28accba292 Mon Sep 17 00:00:00 2001 From: codingisfun2831 <124097137+codingisfun2831t@users.noreply.github.com> Date: Sun, 7 Jun 2026 18:24:07 -0400 Subject: [PATCH 4/5] made block-shapes replace reporter-block-shapes --- mods/block-shapes.js | 362 ---------------------------------- mods/reporter-block-shapes.js | 285 ++++++++++++++++++++++---- 2 files changed, 251 insertions(+), 396 deletions(-) delete mode 100644 mods/block-shapes.js diff --git a/mods/block-shapes.js b/mods/block-shapes.js deleted file mode 100644 index 5a063d3..0000000 --- a/mods/block-shapes.js +++ /dev/null @@ -1,362 +0,0 @@ -return class extends Mod { - // Metadata - ID = "reporter-block-shapes"; // the id of the addon - NAME = "Reporter Block Shapes"; // human-readable name - DESCRIPTION = "Change the shape of a reporter depending on what it returns. Inspired by Snavanced, by alessandrito123"; // description - VERSION = "1.0.0"; // version - AUTHOR = "codingisfun2831, d016"; // author - DEPENDS = []; // dependencies (addon ids, useful for libraries) - DO_MENU = false; // whether to add a menu item - OPTIONS_FORMAT = [ - { - id: "squareType", - name: "Square Block Type", - type: "string", - default: "color", - menu: { - "color": "color", - "string": "text", - "list": "list", - }, - readOnly: true, - } - ] - - // Main function - gets ran when the addon is loaded - main() { - // getBlockShape - return shape string for a reporter block - let options = this.options, - api = this.api; - this.addEventListener("optionsChanged", (e) => { - api.ide.rerender() - }); - ReporterBlockMorph.prototype.getBlockShape = function () { - var choice; - - if (this.reports === options.squareType) return "Rectangle"; - if ([ - "agent", - "sprite", - "stage", - "costume", // should we include costumes and sounds??? - "sound" - ].includes(this.reports)) return "Object"; - if (this.isPredicate) return "Diamond"; - - if ((this.selector == "getPenAttribute" || this.selector == "reportAspect") && options.squareType === "color") { - choice = this.inputs()[0].evaluate(); - if (choice instanceof Array && choice[0] === "color") return "Rectangle"; - } - - return "Oval"; - } - - // fix up outlinePath for that - api.wrapFunction(ReporterBlockMorph.prototype, "outlinePath", function (ctx, inset) { - let shape = this.getBlockShape(); - let func = "outlinePath" + shape; - - if (this[func]) this[func](ctx, inset); - else this.outlinePathOval(ctx, inset); - }, true); - - // and drawEdges - api.wrapFunction(ReporterBlockMorph.prototype, "drawEdges", function (ctx) { - let shape = this.getBlockShape(); - let func = "drawEdges" + shape; - - if (this[func]) this[func](ctx); - else this.drawEdgesOval(ctx); - }, true); - - // rectangle shape - ReporterBlockMorph.prototype.outlinePathRectangle = function (ctx, inset) { - // not how i want to do it at all, but we need to do this so - // c slots work fine (no color reporter should use one, but - // i'm still gonna do this) - - // draw the 'flat' shape - var h = this.height(), - w = this.width(), - pos = this.position(), - corner = this.corner; - - // top left: - ctx.arc( - corner + inset, - corner + inset, - corner, - radians(-180), - radians(-90), - false - ); - - // top right: - ctx.arc( - w - corner - inset, - corner + inset, - corner, - radians(-90), - radians(-0), - false - ); - - // C-Slots - this.cSlots().forEach(slot => { - slot.outlinePath(ctx, inset, slot.position().subtract(pos)); - }); - - // bottom right: - ctx.arc( - w - corner - inset, - h - corner - inset, - corner, - radians(0), - radians(90), - false - ); - - // bottom left: - ctx.arc( - corner + inset, - h - corner - inset, - corner, - radians(90), - radians(180), - false - ); - - ctx.lineTo(inset, corner + inset); // close the path so we can clip it for rings - }; - - ReporterBlockMorph.prototype.drawEdgesRectangle = function (ctx) { - var h = this.height(), - w = this.width(); - - ctx.lineWidth = this.edge; - - ctx.beginPath(); - ctx.moveTo(0, h); - ctx.lineTo(0, 0); - ctx.lineTo(w, 0); - ctx.strokeStyle = this.cachedClrBright; - ctx.stroke(); - - ctx.beginPath(); - ctx.moveTo(w, 0); - ctx.lineTo(w, h); - ctx.lineTo(0, h); - ctx.strokeStyle = this.cachedClrDark; - ctx.stroke(); - }; - - ReporterBlockMorph.prototype.outlinePathObject = function (ctx, inset) { - // draw the 'flat' shape: - var w = this.width(), - h = this.height(), - h2 = Math.floor(h / 2), - r = this.rounding, - right = w - r, - pos = this.position(), - cslots = this.cSlots(); - - ctx.moveTo(r, h2); - ctx.lineTo(inset, inset); - ctx.lineTo(right - inset, inset); - - if (cslots.length) { - this.cSlots().forEach(slot => { - slot.outlinePath(ctx, inset, slot.position().subtract(pos)); - }); - } else { - ctx.lineTo(w - inset, h2); - } - - ctx.lineTo(right - inset, h - inset); - ctx.lineTo(inset, h - inset); - } - ReporterBlockMorph.prototype.drawEdgesObject = function (ctx) { - // add 3D-Effect - var w = this.width(), - h = this.height(), - h2 = Math.floor(h / 2), - r = this.rounding, - shift = this.edge / 2, - cslots = this.cSlots(), - top = this.top(), - y, - gradient; - - ctx.lineWidth = this.edge; - ctx.lineJoin = 'round'; - ctx.lineCap = 'round'; - - // half-tone edges - // bottom left corner - gradient = ctx.createLinearGradient( - r, - 0, - -r, - 0 - ); - gradient.addColorStop(1, this.cachedClr); - gradient.addColorStop(0, this.cachedClrBright); - ctx.strokeStyle = gradient; - ctx.beginPath(); - ctx.moveTo(r, h2); - ctx.lineTo(shift, h - shift); - ctx.closePath(); - ctx.stroke(); - - // normal gradient edges - // top edge: left corner - gradient = ctx.createLinearGradient( - r, - 0, - 0, - 0 - ); - gradient.addColorStop(0, this.cachedClrBright); - gradient.addColorStop(1, this.cachedClr); - ctx.strokeStyle = gradient; - ctx.beginPath(); - ctx.moveTo(r, h2); - ctx.lineTo(shift, shift); - ctx.closePath(); - ctx.stroke(); - - // top edge: straight line - gradient = ctx.createLinearGradient( - 0, - 0, - 0, - this.edge - ); - gradient.addColorStop(0, this.cachedClrBright); - gradient.addColorStop(1, this.cachedClr); - ctx.strokeStyle = gradient; - ctx.beginPath(); - ctx.moveTo(shift, shift); - - // right edge - if (cslots.length) { - // end of top edge - ctx.lineTo(w - r - shift, shift); - ctx.closePath(); - ctx.stroke(); - - // right vertical edge - gradient = ctx.createLinearGradient(w - r - this.edge, 0, w - r, 0); - gradient.addColorStop(0, this.cachedClr); - gradient.addColorStop(1, this.cachedClrDark); - - ctx.lineWidth = this.edge; - ctx.lineJoin = 'round'; - ctx.lineCap = 'round'; - ctx.strokeStyle = gradient; - - ctx.beginPath(); - ctx.moveTo(w - r - shift, this.edge + shift); - cslots.forEach(slot => { - y = slot.top() - top; - ctx.lineTo(w - r - shift, y); - ctx.stroke(); - ctx.beginPath(); - ctx.moveTo(w - r - shift, y + slot.height()); - }); - ctx.lineTo(w - r - shift, h - shift); - ctx.stroke(); - } else { - // end of top edge - ctx.lineTo(w - r, shift); - ctx.closePath(); - ctx.stroke(); - - // top diagonal slope right - gradient = ctx.createLinearGradient( - w - r, - 0, - w + r, - 0 - ); - gradient.addColorStop(0, this.cachedClr); - gradient.addColorStop(1, this.cachedClrDark); - ctx.strokeStyle = gradient; - ctx.beginPath(); - ctx.moveTo(w - shift, h2); - ctx.lineTo(w - r, shift); - ctx.closePath(); - ctx.stroke(); - - // bottom diagonal slope right - gradient = ctx.createLinearGradient( - w - r, - 0, - w, - 0 - ); - gradient.addColorStop(0, this.cachedClr); - gradient.addColorStop(1, this.cachedClrDark); - ctx.strokeStyle = gradient; - ctx.beginPath(); - ctx.moveTo(w - r, h - shift); - ctx.lineTo(w - shift, h2); - ctx.closePath(); - ctx.stroke(); - } - - // bottom edge: straight line - gradient = ctx.createLinearGradient( - 0, - h - this.edge, - 0, - h - ); - gradient.addColorStop(0, this.cachedClr); - gradient.addColorStop(1, this.cachedClrDark); - ctx.strokeStyle = gradient; - ctx.beginPath(); - ctx.moveTo(shift, h - shift); - ctx.lineTo(w - r - shift, h - shift); - ctx.closePath(); - ctx.stroke(); - } - SyntaxElementMorph.prototype.fixLayout.__blockShapesModLoaded__ = true - if (!SyntaxElementMorph.prototype.fixLayout.__isBlockShapes__) { - SyntaxElementMorph.prototype.fixLayout = new Proxy( - SyntaxElementMorph.prototype.fixLayout, - { - apply(target, ctx, args) { - if (!SyntaxElementMorph.prototype.fixLayout.__blockShapesModLoaded__) { - return Reflect.apply(target, ctx, args) - }; - let isObject = ctx.getBlockShape && (ctx.getBlockShape() === "Object") - if (isObject) { - ctx.isPredicate = true - } - console.warn(ctx, ctx.getBlockShape) - Reflect.apply(target, ctx, args) - if (isObject) { - const parts = ctx.parts(); - ctx.bounds.setWidth(ctx.width() + ctx.corner) - parts.forEach((part) => part.setLeft(part.left() + ctx.corner)) - } - } - } - ) - SyntaxElementMorph.prototype.fixLayout.__isBlockShapes__ = Symbol("thisIsBlockShapes") - } - this.api.ide.refreshIDE(); - } - - // Cleanup function - get ran when the addon is "deleted" - cleanupFunc() { - // delete extra funcs - delete ReporterBlockMorph.prototype.getBlockShape; - delete ReporterBlockMorph.prototype.outlinePathRectangle; - delete ReporterBlockMorph.prototype.drawEdgesRectangle; - delete ReporterBlockMorph.prototype.outlinePathObject; - delete ReporterBlockMorph.prototype.drawEdgesObject; - SyntaxElementMorph.prototype.fixLayout.__blockShapesModLoaded__ = false - } -} \ No newline at end of file diff --git a/mods/reporter-block-shapes.js b/mods/reporter-block-shapes.js index 4cd8ea1..5a063d3 100644 --- a/mods/reporter-block-shapes.js +++ b/mods/reporter-block-shapes.js @@ -2,23 +2,48 @@ return class extends Mod { // Metadata ID = "reporter-block-shapes"; // the id of the addon NAME = "Reporter Block Shapes"; // human-readable name - DESCRIPTION = "Change the shape of a reporter depending on what it returns."; // description + DESCRIPTION = "Change the shape of a reporter depending on what it returns. Inspired by Snavanced, by alessandrito123"; // description VERSION = "1.0.0"; // version - AUTHOR = "codingisfun2831"; // author + AUTHOR = "codingisfun2831, d016"; // author DEPENDS = []; // dependencies (addon ids, useful for libraries) DO_MENU = false; // whether to add a menu item + OPTIONS_FORMAT = [ + { + id: "squareType", + name: "Square Block Type", + type: "string", + default: "color", + menu: { + "color": "color", + "string": "text", + "list": "list", + }, + readOnly: true, + } + ] // Main function - gets ran when the addon is loaded main() { // getBlockShape - return shape string for a reporter block - + let options = this.options, + api = this.api; + this.addEventListener("optionsChanged", (e) => { + api.ide.rerender() + }); ReporterBlockMorph.prototype.getBlockShape = function () { var choice; + if (this.reports === options.squareType) return "Rectangle"; + if ([ + "agent", + "sprite", + "stage", + "costume", // should we include costumes and sounds??? + "sound" + ].includes(this.reports)) return "Object"; if (this.isPredicate) return "Diamond"; - if (this.reports === "color") return "Rectangle"; - - if (this.selector == "getPenAttribute" || this.selector == "reportAspect") { + + if ((this.selector == "getPenAttribute" || this.selector == "reportAspect") && options.squareType === "color") { choice = this.inputs()[0].evaluate(); if (choice instanceof Array && choice[0] === "color") return "Rectangle"; } @@ -27,26 +52,22 @@ return class extends Mod { } // fix up outlinePath for that - ReporterBlockMorph.prototype._outlinePath = - ReporterBlockMorph.prototype.outlinePath; - ReporterBlockMorph.prototype.outlinePath = function (ctx, inset) { + api.wrapFunction(ReporterBlockMorph.prototype, "outlinePath", function (ctx, inset) { let shape = this.getBlockShape(); let func = "outlinePath" + shape; if (this[func]) this[func](ctx, inset); else this.outlinePathOval(ctx, inset); - }; + }, true); // and drawEdges - ReporterBlockMorph.prototype._drawEdges = - ReporterBlockMorph.prototype.drawEdges; - ReporterBlockMorph.prototype.drawEdges = function (ctx) { + api.wrapFunction(ReporterBlockMorph.prototype, "drawEdges", function (ctx) { let shape = this.getBlockShape(); let func = "drawEdges" + shape; if (this[func]) this[func](ctx); else this.drawEdgesOval(ctx); - }; + }, true); // rectangle shape ReporterBlockMorph.prototype.outlinePathRectangle = function (ctx, inset) { @@ -57,13 +78,14 @@ return class extends Mod { // draw the 'flat' shape var h = this.height(), w = this.width(), - pos = this.position(); + pos = this.position(), + corner = this.corner; // top left: ctx.arc( - 0, - 0, - 0, + corner + inset, + corner + inset, + corner, radians(-180), radians(-90), false @@ -71,9 +93,9 @@ return class extends Mod { // top right: ctx.arc( - w, - 0, - 0, + w - corner - inset, + corner + inset, + corner, radians(-90), radians(-0), false @@ -86,9 +108,9 @@ return class extends Mod { // bottom right: ctx.arc( - w, - h, - 0, + w - corner - inset, + h - corner - inset, + corner, radians(0), radians(90), false @@ -96,15 +118,15 @@ return class extends Mod { // bottom left: ctx.arc( - 0, - h, - 0, + corner + inset, + h - corner - inset, + corner, radians(90), radians(180), false ); - ctx.lineTo(0, 0); // close the path so we can clip it for rings + ctx.lineTo(inset, corner + inset); // close the path so we can clip it for rings }; ReporterBlockMorph.prototype.drawEdgesRectangle = function (ctx) { @@ -127,6 +149,204 @@ return class extends Mod { ctx.strokeStyle = this.cachedClrDark; ctx.stroke(); }; + + ReporterBlockMorph.prototype.outlinePathObject = function (ctx, inset) { + // draw the 'flat' shape: + var w = this.width(), + h = this.height(), + h2 = Math.floor(h / 2), + r = this.rounding, + right = w - r, + pos = this.position(), + cslots = this.cSlots(); + + ctx.moveTo(r, h2); + ctx.lineTo(inset, inset); + ctx.lineTo(right - inset, inset); + + if (cslots.length) { + this.cSlots().forEach(slot => { + slot.outlinePath(ctx, inset, slot.position().subtract(pos)); + }); + } else { + ctx.lineTo(w - inset, h2); + } + + ctx.lineTo(right - inset, h - inset); + ctx.lineTo(inset, h - inset); + } + ReporterBlockMorph.prototype.drawEdgesObject = function (ctx) { + // add 3D-Effect + var w = this.width(), + h = this.height(), + h2 = Math.floor(h / 2), + r = this.rounding, + shift = this.edge / 2, + cslots = this.cSlots(), + top = this.top(), + y, + gradient; + + ctx.lineWidth = this.edge; + ctx.lineJoin = 'round'; + ctx.lineCap = 'round'; + + // half-tone edges + // bottom left corner + gradient = ctx.createLinearGradient( + r, + 0, + -r, + 0 + ); + gradient.addColorStop(1, this.cachedClr); + gradient.addColorStop(0, this.cachedClrBright); + ctx.strokeStyle = gradient; + ctx.beginPath(); + ctx.moveTo(r, h2); + ctx.lineTo(shift, h - shift); + ctx.closePath(); + ctx.stroke(); + + // normal gradient edges + // top edge: left corner + gradient = ctx.createLinearGradient( + r, + 0, + 0, + 0 + ); + gradient.addColorStop(0, this.cachedClrBright); + gradient.addColorStop(1, this.cachedClr); + ctx.strokeStyle = gradient; + ctx.beginPath(); + ctx.moveTo(r, h2); + ctx.lineTo(shift, shift); + ctx.closePath(); + ctx.stroke(); + + // top edge: straight line + gradient = ctx.createLinearGradient( + 0, + 0, + 0, + this.edge + ); + gradient.addColorStop(0, this.cachedClrBright); + gradient.addColorStop(1, this.cachedClr); + ctx.strokeStyle = gradient; + ctx.beginPath(); + ctx.moveTo(shift, shift); + + // right edge + if (cslots.length) { + // end of top edge + ctx.lineTo(w - r - shift, shift); + ctx.closePath(); + ctx.stroke(); + + // right vertical edge + gradient = ctx.createLinearGradient(w - r - this.edge, 0, w - r, 0); + gradient.addColorStop(0, this.cachedClr); + gradient.addColorStop(1, this.cachedClrDark); + + ctx.lineWidth = this.edge; + ctx.lineJoin = 'round'; + ctx.lineCap = 'round'; + ctx.strokeStyle = gradient; + + ctx.beginPath(); + ctx.moveTo(w - r - shift, this.edge + shift); + cslots.forEach(slot => { + y = slot.top() - top; + ctx.lineTo(w - r - shift, y); + ctx.stroke(); + ctx.beginPath(); + ctx.moveTo(w - r - shift, y + slot.height()); + }); + ctx.lineTo(w - r - shift, h - shift); + ctx.stroke(); + } else { + // end of top edge + ctx.lineTo(w - r, shift); + ctx.closePath(); + ctx.stroke(); + + // top diagonal slope right + gradient = ctx.createLinearGradient( + w - r, + 0, + w + r, + 0 + ); + gradient.addColorStop(0, this.cachedClr); + gradient.addColorStop(1, this.cachedClrDark); + ctx.strokeStyle = gradient; + ctx.beginPath(); + ctx.moveTo(w - shift, h2); + ctx.lineTo(w - r, shift); + ctx.closePath(); + ctx.stroke(); + + // bottom diagonal slope right + gradient = ctx.createLinearGradient( + w - r, + 0, + w, + 0 + ); + gradient.addColorStop(0, this.cachedClr); + gradient.addColorStop(1, this.cachedClrDark); + ctx.strokeStyle = gradient; + ctx.beginPath(); + ctx.moveTo(w - r, h - shift); + ctx.lineTo(w - shift, h2); + ctx.closePath(); + ctx.stroke(); + } + + // bottom edge: straight line + gradient = ctx.createLinearGradient( + 0, + h - this.edge, + 0, + h + ); + gradient.addColorStop(0, this.cachedClr); + gradient.addColorStop(1, this.cachedClrDark); + ctx.strokeStyle = gradient; + ctx.beginPath(); + ctx.moveTo(shift, h - shift); + ctx.lineTo(w - r - shift, h - shift); + ctx.closePath(); + ctx.stroke(); + } + SyntaxElementMorph.prototype.fixLayout.__blockShapesModLoaded__ = true + if (!SyntaxElementMorph.prototype.fixLayout.__isBlockShapes__) { + SyntaxElementMorph.prototype.fixLayout = new Proxy( + SyntaxElementMorph.prototype.fixLayout, + { + apply(target, ctx, args) { + if (!SyntaxElementMorph.prototype.fixLayout.__blockShapesModLoaded__) { + return Reflect.apply(target, ctx, args) + }; + let isObject = ctx.getBlockShape && (ctx.getBlockShape() === "Object") + if (isObject) { + ctx.isPredicate = true + } + console.warn(ctx, ctx.getBlockShape) + Reflect.apply(target, ctx, args) + if (isObject) { + const parts = ctx.parts(); + ctx.bounds.setWidth(ctx.width() + ctx.corner) + parts.forEach((part) => part.setLeft(part.left() + ctx.corner)) + } + } + } + ) + SyntaxElementMorph.prototype.fixLayout.__isBlockShapes__ = Symbol("thisIsBlockShapes") + } + this.api.ide.refreshIDE(); } // Cleanup function - get ran when the addon is "deleted" @@ -135,11 +355,8 @@ return class extends Mod { delete ReporterBlockMorph.prototype.getBlockShape; delete ReporterBlockMorph.prototype.outlinePathRectangle; delete ReporterBlockMorph.prototype.drawEdgesRectangle; - - // bring back old funcs - ReporterBlockMorph.prototype.drawEdges = - ReporterBlockMorph.prototype._drawEdges; - ReporterBlockMorph.prototype.outlinePath = - ReporterBlockMorph.prototype._outlinePath; + delete ReporterBlockMorph.prototype.outlinePathObject; + delete ReporterBlockMorph.prototype.drawEdgesObject; + SyntaxElementMorph.prototype.fixLayout.__blockShapesModLoaded__ = false } } \ No newline at end of file From ca3e28177f44de06d2bd9433b3b9d78a0e78aebc Mon Sep 17 00:00:00 2001 From: codingisfun2831 <124097137+codingisfun2831t@users.noreply.github.com> Date: Sun, 7 Jun 2026 18:31:57 -0400 Subject: [PATCH 5/5] switch to a new getRealReports for the special block report logic --- mods/reporter-block-shapes.js | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/mods/reporter-block-shapes.js b/mods/reporter-block-shapes.js index 5a063d3..c7a5d89 100644 --- a/mods/reporter-block-shapes.js +++ b/mods/reporter-block-shapes.js @@ -30,23 +30,30 @@ return class extends Mod { this.addEventListener("optionsChanged", (e) => { api.ide.rerender() }); - ReporterBlockMorph.prototype.getBlockShape = function () { + + ReporterBlockMorph.prototype.getRealReports = function() { var choice; - if (this.reports === options.squareType) return "Rectangle"; + if ((this.selector == "getPenAttribute" || this.selector == "reportAspect")) { + choice = this.inputs()[0].evaluate(); + if (choice instanceof Array && choice[0] === "color") return "color"; + } + + return this.reports; + }; + + ReporterBlockMorph.prototype.getBlockShape = function () { + var reports = this.getRealReports(); + + if (reports === options.squareType) return "Rectangle"; if ([ "agent", "sprite", "stage", "costume", // should we include costumes and sounds??? "sound" - ].includes(this.reports)) return "Object"; + ].includes(reports)) return "Object"; if (this.isPredicate) return "Diamond"; - - if ((this.selector == "getPenAttribute" || this.selector == "reportAspect") && options.squareType === "color") { - choice = this.inputs()[0].evaluate(); - if (choice instanceof Array && choice[0] === "color") return "Rectangle"; - } return "Oval"; }