diff --git a/HISTORY.md b/HISTORY.md index 8ff29cd4..908ce65f 100755 --- a/HISTORY.md +++ b/HISTORY.md @@ -68,6 +68,9 @@ * Chinese, thanks, Simon! * Brazilian Portuguese, thank you, Cassiano D'Andrea! +### 2021-11-30 +* blocks, threads: block-assembly support, experimental + ### 2021-11-29 * renamed "r-g-b-a" option to "RGBA" and "r-g-b(-a)" to "RGB(A)" diff --git a/snap.html b/snap.html index 4f633cae..c92e171a 100755 --- a/snap.html +++ b/snap.html @@ -16,8 +16,8 @@ - - + + diff --git a/src/blocks.js b/src/blocks.js index 10ef8c75..f0ca75fe 100644 --- a/src/blocks.js +++ b/src/blocks.js @@ -153,14 +153,14 @@ radians, useBlurredShadows, SpeechBubbleMorph, modules, StageMorph, SymbolMorph, fontHeight, TableFrameMorph, SpriteMorph, Context, ListWatcherMorph, Rectangle, DialogBoxMorph, BlockInputFragmentMorph, PrototypeHatBlockMorph, WHITE, BLACK, Costume, IDE_Morph, BlockDialogMorph, BlockEditorMorph, localize, CLEAR, Point, -isSnapObject, PushButtonMorph, SpriteIconMorph, Process, AlignmentMorph, +isSnapObject, PushButtonMorph, SpriteIconMorph, Process, AlignmentMorph, List, CustomCommandBlockMorph, ToggleButtonMorph, DialMorph, SnapExtensions*/ /*jshint esversion: 6*/ // Global stuff //////////////////////////////////////////////////////// -modules.blocks = '2021-November-27'; +modules.blocks = '2021-November-30'; var SyntaxElementMorph; var BlockMorph; @@ -3614,6 +3614,8 @@ BlockMorph.prototype.restoreInputs = function (oldInputs, offset = 0) { return leftOver; }; +// BlockMorph helpscreens + BlockMorph.prototype.showHelp = function () { var myself = this, ide = this.parentThatIsA(IDE_Morph), @@ -3702,6 +3704,41 @@ BlockMorph.prototype.exportResultPic = function () { } }; +// BlockMorph components - EXPERIMENTAL + +BlockMorph.prototype.components = function () { // +++ + throw new Error('subclass responsility'); +}; + +BlockMorph.prototype.copyWithInputs = function (inputs) { + var cpy = this.fullCopy(), + slots = cpy.inputs(), + dta = inputs.itemsArray().map(inp => + inp instanceof Context ? inp.expression : inp + ); + slots.forEach(slt => { + if (slt instanceof BlockMorph) { + cpy.revertToDefaultInput(slt); + } + }); + dta.forEach((inp, i) => { + if (inp instanceof BlockMorph) { + if (inp instanceof CommandBlockMorph && slots[i].nestedBlock) { + slots[i].nestedBlock(inp); + } else { + cpy.replaceInput(slots[i], inp); + } + } else { + if (inp instanceof List && inp.length() === 0) { + nop(); // ignore, i.e. leave slot as is + } else { + slots[i].setContents(inp); + } + } + }); + return cpy; +}; + // BlockMorph code mapping /* @@ -5417,6 +5454,46 @@ CommandBlockMorph.prototype.extract = function () { } }; +// CommandBlockMorph components - EXPERIMENTAL + +CommandBlockMorph.prototype.components = function () { // +++ + var seq = new List(this.blockSequence()).map(block => { + var expr = block.fullCopy(), + nb = expr.nextBlock(), + inputs, parts; + if (nb) { + nb.destroy(); + } + expr.fixBlockColor(null, true); + inputs = expr.inputs(); + if (!inputs.length) { + return expr; + } + parts = new List([expr]); + inputs.forEach(inp => { + var val; + if (inp instanceof BlockMorph) { + parts.add(inp.components()); + } else { + val = inp.evaluate(); + parts.add(val instanceof BlockMorph ? val.components() : val); + + } + expr.revertToDefaultInput(inp, true); // empty + }); + return parts; + }); + return seq.length() === 1 ? seq.at(1) : seq; +}; + +CommandBlockMorph.prototype.copyWithNext = function (next) { + var exp = this.fullCopy(), + bottom = exp.bottomBlock(), + top = next.fullCopy().topBlock(); + bottom.nextBlock(top); + return exp; +}; + // CommandBlockMorph drawing: CommandBlockMorph.prototype.outlinePath = function(ctx, inset) { @@ -6180,6 +6257,32 @@ ReporterBlockMorph.prototype.userDestroy = function () { this.destroy(); }; +// ReporterBlockMorph components - EXPERIMENTAL + +ReporterBlockMorph.prototype.components = function () { // +++ + var expr = this.fullCopy(), + inputs = expr.inputs(), + parts; + expr.fixBlockColor(null, true); + if (!inputs.length || + inputs.every(slot => slot.isEmptySlot && slot.isEmptySlot())) { + return expr; + } + parts = new List([expr]); + inputs.forEach(inp => { + var val; + if (inp instanceof BlockMorph) { + parts.add(inp.components()); + } else { + val = inp.evaluate(); + parts.add(val instanceof BlockMorph ? val.components() : val); + + } + expr.revertToDefaultInput(inp, true); // empty + }); + return parts; +}; + // ReporterBlockMorph drawing: ReporterBlockMorph.prototype.outlinePath = function (ctx, inset) { diff --git a/src/threads.js b/src/threads.js index 3be3dbdb..b0d9c8db 100644 --- a/src/threads.js +++ b/src/threads.js @@ -64,7 +64,7 @@ SnapExtensions, AlignmentMorph, TextMorph, Cloud, HatBlockMorph*/ /*jshint esversion: 6*/ -modules.threads = '2021-November-27'; +modules.threads = '2021-November-30'; var ThreadManager; var Process; @@ -7009,6 +7009,20 @@ Context.prototype.isInCustomBlock = function () { return false; }; +// Context components - EXPERIMENTAL + +Context.prototype.components = function () { + var expr = this.expression.components(), + parts; + if (!this.inputs.length) { + return expr; + } + parts = new List(); + parts.add(expr); // blocks / other + this.inputs.forEach(name => parts.add(name)); + return parts; +}; + // Variable ///////////////////////////////////////////////////////////////// function Variable(value, isTransient, isHidden) {