diff --git a/HISTORY.md b/HISTORY.md
index 0c9b3367..dc42b30f 100755
--- a/HISTORY.md
+++ b/HISTORY.md
@@ -4,6 +4,7 @@
### 2019-01-14
* Symbols: added 'loop' arrow symbol
+* Blocks, Objects, Store: added 'loop' symbol to primitive loop blocks
### 2019-01-12
* Threads: try to identify Brian's problem with parsing a CSV
diff --git a/snap.html b/snap.html
index a2885653..ef33897b 100755
--- a/snap.html
+++ b/snap.html
@@ -6,9 +6,9 @@
-
+
-
+
@@ -17,7 +17,7 @@
-
+
diff --git a/src/blocks.js b/src/blocks.js
index b5d9bf0a..b5e9c3bd 100644
--- a/src/blocks.js
+++ b/src/blocks.js
@@ -148,7 +148,7 @@ CustomCommandBlockMorph, SymbolMorph, ToggleButtonMorph, DialMorph*/
// Global stuff ////////////////////////////////////////////////////////
-modules.blocks = '2019-January-09';
+modules.blocks = '2019-January-14';
var SyntaxElementMorph;
var BlockMorph;
@@ -778,6 +778,8 @@ SyntaxElementMorph.prototype.setLabelColor = function (
|| (morph instanceof InputSlotMorph
&& morph.isReadOnly)) {
morph.setLabelColor(textColor, shadowColor, shadowOffset);
+ } else if (morph.isLoop) { // C-shaped slot with loop arrow symbol
+ morph.loop().setLabelColor(textColor, shadowColor, shadowOffset);
}
});
};
@@ -1467,6 +1469,21 @@ SyntaxElementMorph.prototype.labelPart = function (spec) {
part.isStatic = true; // rejects reporter drops
part.isLambda = true; // auto-reifies nested script
break;
+ case '%loop':
+ part = new CSlotMorph();
+ part.isStatic = true;
+ part.isLoop = true; // has a loop symbol
+ part.add(this.labelPart('%loopArrow'));
+ break;
+ case '%loopArrow':
+ part = new SymbolMorph('loop');
+ part.size = this.fontSize * 0.7;
+ part.color = new Color(255, 255, 255);
+ part.shadowColor = this.color.darker(this.labelContrast);
+ part.shadowOffset = MorphicPreferences.isFlat ?
+ new Point() : this.embossing;
+ part.drawNew();
+ break;
case '%clr':
part = new ColorSlotMorph();
part.isStatic = true;
@@ -1781,7 +1798,7 @@ SyntaxElementMorph.prototype.fixLayout = function (silently) {
} else {
part.setPosition(new Point(x, y));
if (!part.isBlockLabelBreak) {
- if (part.slotSpec === '%c') {
+ if (part.slotSpec === '%c' || part.slotSpec === '%loop') {
x += part.width();
} else if (part.isVisible) {
x += part.fullBounds().width() + space;
@@ -7821,6 +7838,7 @@ CSlotMorph.prototype.init = function (silently) {
CommandSlotMorph.uber.init.call(this, null, true); // silently
this.isHole = true;
this.isLambda = false; // see Process.prototype.evaluateInput
+ this.isLoop = false; // has a loop arrow symbol
this.color = new Color(0, 17, 173);
this.setExtent(
new Point(230, this.corner * 4 + this.cSlotPadding),
@@ -7829,7 +7847,7 @@ CSlotMorph.prototype.init = function (silently) {
};
CSlotMorph.prototype.getSpec = function () {
- return '%c';
+ return this.isLoop? '%loop' : '%c';
};
CSlotMorph.prototype.mappedCode = function (definitions) {
@@ -7857,7 +7875,6 @@ CSlotMorph.prototype.mappedCode = function (definitions) {
return codeLines.join('\n');
};
-
// CSlotMorph layout:
CSlotMorph.prototype.fixLayout = function () {
@@ -7885,10 +7902,38 @@ CSlotMorph.prototype.fixLayout = function () {
}
};
+CSlotMorph.prototype.fixLoopLayout = function () {
+ var loop;
+ if (this.isLoop) {
+ loop = this.loop();
+ if (loop) {
+ loop.setRight(this.right() - this.corner);
+ loop.setBottom(this.bottom() + this.cSlotPadding + this.edge);
+ }
+ }
+};
+
+CSlotMorph.prototype.loop = function () {
+ if (this.isLoop) {
+ return detect(
+ this.children,
+ function (child) {
+ return child instanceof SymbolMorph;
+ }
+ );
+ }
+ return null;
+};
+
// CSlotMorph drawing:
CSlotMorph.prototype.drawNew = function () {
var context;
+
+ // position loop symbol, if any
+ this.fixLoopLayout();
+
+ // init
this.cachedClr = this.color.toString();
this.cachedClrBright = this.bright();
this.cachedClrDark = this.dark();
diff --git a/src/objects.js b/src/objects.js
index b238d74c..b6713599 100644
--- a/src/objects.js
+++ b/src/objects.js
@@ -83,7 +83,7 @@ BlockEditorMorph, BlockDialogMorph, PrototypeHatBlockMorph, localize,
TableMorph, TableFrameMorph, normalizeCanvas, BooleanSlotMorph, HandleMorph,
AlignmentMorph, Process, XML_Element, VectorPaintEditorMorph*/
-modules.objects = '2019-January-11';
+modules.objects = '2019-January-14';
var SpriteMorph;
var StageMorph;
@@ -605,18 +605,18 @@ SpriteMorph.prototype.initBlocks = function () {
doForever: {
type: 'command',
category: 'control',
- spec: 'forever %c'
+ spec: 'forever %loop'
},
doRepeat: {
type: 'command',
category: 'control',
- spec: 'repeat %n %c',
+ spec: 'repeat %n %loop',
defaults: [10]
},
doUntil: {
type: 'command',
category: 'control',
- spec: 'repeat until %b %c'
+ spec: 'repeat until %b %loop'
},
doIf: {
type: 'command',
diff --git a/src/store.js b/src/store.js
index 83bc3623..0c7daf6b 100644
--- a/src/store.js
+++ b/src/store.js
@@ -61,7 +61,7 @@ normalizeCanvas, contains*/
// Global stuff ////////////////////////////////////////////////////////
-modules.store = '2019-January-11';
+modules.store = '2019-January-14';
// XML_Serializer ///////////////////////////////////////////////////////
@@ -2104,7 +2104,7 @@ TemplateSlotMorph.prototype.toXML = function (serializer) {
};
CommandSlotMorph.prototype.toXML = function (serializer) {
- var block = this.children[0];
+ var block = this.nestedBlock();
if (block instanceof BlockMorph) {
if (block instanceof ReporterBlockMorph) {
return serializer.format(
diff --git a/src/symbols.js b/src/symbols.js
index 535d06cb..afdac60e 100644
--- a/src/symbols.js
+++ b/src/symbols.js
@@ -1269,7 +1269,7 @@ SymbolMorph.prototype.drawSymbolLoop = function (canvas, aColor) {
w2 = canvas.width / 2,
w4 = w2 / 2,
h2 = canvas.height / 2,
- l = Math.max(h / 20, 0.5);
+ l = Math.max(h / 10, 0.5);
ctx.lineWidth = l * 2;
ctx.strokeStyle = aColor.toString();