diff --git a/HISTORY.md b/HISTORY.md index 95de9520..68d016ba 100755 --- a/HISTORY.md +++ b/HISTORY.md @@ -3,6 +3,7 @@ ## in development ### 2019-01-21 +* let users make C-shape slots with loop arrow symbols. Sigh. * updated Indonesian translation, thanks, Emmanuella Rumanti ### 2019-01-19 diff --git a/snap.html b/snap.html index 20a775b3..2168e428 100755 --- a/snap.html +++ b/snap.html @@ -6,13 +6,13 @@ - + - + diff --git a/src/blocks.js b/src/blocks.js index 0492b8e2..9e958369 100644 --- a/src/blocks.js +++ b/src/blocks.js @@ -148,7 +148,7 @@ CustomCommandBlockMorph, SymbolMorph, ToggleButtonMorph, DialMorph*/ // Global stuff //////////////////////////////////////////////////////// -modules.blocks = '2019-January-19'; +modules.blocks = '2019-January-21'; var SyntaxElementMorph; var BlockMorph; @@ -1464,6 +1464,11 @@ SyntaxElementMorph.prototype.labelPart = function (spec) { case '%cs': part = new CSlotMorph(); // non-static break; + case '%ca': + part = new CSlotMorph(); // non-static + part.isLoop = true; // has a loop symbol + part.add(this.labelPart('%loopArrow')); + break; case '%cl': part = new CSlotMorph(); part.isStatic = true; // rejects reporter drops @@ -2219,6 +2224,7 @@ SyntaxElementMorph.prototype.endLayout = function () { %l - list icon %c - C-shaped command slot, special form for primitives %loop - C-shaped with loop arrow, special form for certain primitives + %ca - C-shaped with loop arrow, for custom blocks %cs - C-shaped, auto-reifying, accepts reporter drops %cl - C-shaped, auto-reifying, rejects reporters %clr - interactive color slot diff --git a/src/byob.js b/src/byob.js index 6cf50149..c895ead3 100644 --- a/src/byob.js +++ b/src/byob.js @@ -108,7 +108,7 @@ BooleanSlotMorph, XML_Serializer, SnapTranslator*/ // Global stuff //////////////////////////////////////////////////////// -modules.byob = '2018-November-12'; +modules.byob = '2019-January-21'; // Declarations @@ -1452,7 +1452,7 @@ function JaggedBlockMorph(spec) { JaggedBlockMorph.prototype.init = function (spec) { JaggedBlockMorph.uber.init.call(this); if (spec) {this.setSpec(spec); } - if (spec === '%cs') { + if (spec === '%cs' || (spec === '%ca')) { this.minWidth = 25; this.fixLayout(); } @@ -2581,7 +2581,7 @@ BlockLabelFragment.prototype.defTemplateSpecFragment = function () { suff = ' \u2191'; } else if (this.isMultipleInput()) { suff = '...'; - } else if (this.type === '%cs') { + } else if (this.type === '%cs' || this.type === '%ca') { suff = ' \u03BB'; // ' [\u03BB' } else if (this.type === '%b') { suff = ' ?'; @@ -2655,6 +2655,8 @@ BlockLabelFragment.prototype.setToMultipleInput = function () { if (!this.type) {return null; } // not an input at all if (this.type === '%upvar') { this.type = '%s'; + } else if (this.type === '%ca') { + this.type = '%cs'; } this.type = '%mult'.concat(this.singleInputType()); }; @@ -3282,7 +3284,7 @@ InputSlotDialogMorph.prototype.deleteFragment = function () { InputSlotDialogMorph.prototype.createSlotTypeButtons = function () { // populate my 'slots' area with radio buttons, labels and input fields - var myself = this, defLabel, defInput, defSwitch, + var myself = this, defLabel, defInput, defSwitch, loopArrow, oldFlag = Morph.prototype.trackChanges; Morph.prototype.trackChanges = false; @@ -3297,7 +3299,7 @@ InputSlotDialogMorph.prototype.createSlotTypeButtons = function () { this.addSlotTypeButton('Command\n(inline)', '%cmdRing'); //'%cmd'); this.addSlotTypeButton('Reporter', '%repRing'); //'%r'); this.addSlotTypeButton('Predicate', '%predRing'); //'%p'); - this.addSlotTypeButton('Command\n(C-shape)', '%cs'); + this.addSlotTypeButton('Command\n(C-shape)', ['%cs', '%ca']); this.addSlotTypeButton('Any\n(unevaluated)', '%anyUE'); this.addSlotTypeButton('Boolean\n(unevaluated)', '%boolUE'); @@ -3374,6 +3376,43 @@ InputSlotDialogMorph.prototype.createSlotTypeButtons = function () { this.slots.add(defSwitch); defSwitch.drawNew(); + // loop arrow checkbox // + loopArrow = new ToggleMorph( + 'checkbox', + this, // target + function () { // action + if (myself.fragment.type === '%ca') { + myself.setType('%cs'); + } else { + myself.setType('%ca'); + } + }, + null, // label string + function () {return myself.fragment.type === '%ca'; }, + null, // environment + null, // hint + null, // template + new SymbolMorph( + 'loop', + this.fontSize * 0.7, + new Color(255, 255, 255) + ), + null // builder method that constructs the element morph + ); + loopArrow.refresh = function () { + ToggleMorph.prototype.refresh.call(this); + if (myself.isExpanded && contains( + ['%cs', '%ca'], + myself.fragment.type + )) { + loopArrow.show(); + } else { + loopArrow.hide(); + } + }; + this.slots.loopArrow = loopArrow; + this.slots.add(loopArrow); + Morph.prototype.trackChanges = oldFlag; }; @@ -3402,7 +3441,7 @@ InputSlotDialogMorph.prototype.setSlotArity = function (arity) { InputSlotDialogMorph.prototype.addSlotTypeButton = function ( label, - spec + spec // slot spec or array of specs (I *hate* the arrow symbol, -Jens) ) { /* this method produces a radio button with a picture of the @@ -3423,13 +3462,17 @@ InputSlotDialogMorph.prototype.addSlotTypeButton = function ( faster. */ var myself = this, - action = function () {myself.setSlotType(spec); }, + action = function () { + myself.setSlotType(spec instanceof Array ? spec[0] : spec); + }, query, - element = new JaggedBlockMorph(spec), + element = new JaggedBlockMorph(spec instanceof Array ? spec[0] : spec), button; query = function () { - return myself.fragment.singleInputType() === spec; + return spec instanceof Array ? + contains(spec, myself.fragment.singleInputType()) + : myself.fragment.singleInputType() === spec; }; element.setCategory(this.category); element.rebuild(); @@ -3563,6 +3606,11 @@ InputSlotDialogMorph.prototype.fixSlotsLayout = function () { 0 )) ); + + // loop arrow + + this.slots.loopArrow.setPosition(this.slots.defaultInputLabel.position()); + Morph.prototype.trackChanges = oldFlag; this.slots.changed(); };