kopia lustrzana https://github.com/backface/turtlestitch
				
				
				
			Prepare for v4.0.3
* fixed occasional horizontal rendering artifacts in block “holes” (C-shaped slots and Ring holes) * improved user editing of input slots and fixed cursor behavior (note: the text cursor inside input slots also blinks again, as it should have) * always export comments attached to prototype hat blocks in the block editor along with script pic * when first opening a block editor on a custom block definition make it big enough to show everything (as much as fits on the screen) * remember block editor position and dimensions for each edited custom block definition when acknowledging (pressing OK or APPLY) for the session * speed up stacking of commands and loading of projects by suppressing redundant block redraws * introducing a “grab threshold” preference to suppress accidental grabbing through micro-movements of the hand. This addresses the “cannot-click-on-drop-downs-in-Chrome-under-Windows” set of bug reports, and also the issues that arise out of accidentally dragging off a copy of a parameter blob when trying to just click on it to rename it * new hidden (shift-click) option to adjust the grab threshold in the settings menu for the current session * expand list watchers inside result bubbles and speech/thought balloons to show everything (as much of the list’s first level as fist into either the scripting area for result bubbles or the stage for speech balloons - note resizing the stage affects the size of the list watchers inside speech balloons, i.e. making the stage bigger increases the number of visible elements even while the balloon is showing) * fixed a bug that make an occasional gray rectangle appear at the mouse pointer * added a way to invoke blocks synchronously in JavaScript - under construction (possibly to be used for generic “When” hat blocks and user-customizable drop-downs) * added methods to cache morphs’ fullImage and fullBounds while dragging * Reporters (also nested reporters) and sprite icons (in the corral) are now semi-transparent when being dragged, so you can see possible drop target halos /through/ them * in “prefer empty slot drops” mode (default) it is now much harder to drop reporters onto non-static C-slots inside custom blocks (e.g. in FOR loops) and onto variadic input arrowheads (to replace the whole input with an input list) * ScriptsMorphs are now noticing transparent clicks (addresses #997) * %interaction slots are now static, fixed #982 (it is no longer possible to drop reporters into the input slot of a “When I am…” hat block (never was intended that it should be possible) * fixed ctrl-f for the block editor in all situations (thanks, Brian, for the bug report)dev
							rodzic
							
								
									72bf4cfb8c
								
							
						
					
					
						commit
						6061403a89
					
				
							
								
								
									
										183
									
								
								blocks.js
								
								
								
								
							
							
						
						
									
										183
									
								
								blocks.js
								
								
								
								
							|  | @ -156,7 +156,7 @@ DialogBoxMorph, BlockInputFragmentMorph, PrototypeHatBlockMorph, Costume*/ | |||
| 
 | ||||
| // Global stuff ////////////////////////////////////////////////////////
 | ||||
| 
 | ||||
| modules.blocks = '2015-October-02'; | ||||
| modules.blocks = '2015-November-16'; | ||||
| 
 | ||||
| var SyntaxElementMorph; | ||||
| var BlockMorph; | ||||
|  | @ -349,22 +349,18 @@ function SyntaxElementMorph() { | |||
|     this.init(); | ||||
| } | ||||
| 
 | ||||
| SyntaxElementMorph.prototype.init = function () { | ||||
| SyntaxElementMorph.prototype.init = function (silently) { | ||||
|     this.cachedClr = null; | ||||
|     this.cachedClrBright = null; | ||||
|     this.cachedClrDark = null; | ||||
|     this.isStatic = false; // if true, I cannot be exchanged
 | ||||
| 
 | ||||
|     SyntaxElementMorph.uber.init.call(this); | ||||
|     SyntaxElementMorph.uber.init.call(this, silently); | ||||
| 
 | ||||
|     this.defaults = []; | ||||
|     this.cachedInputs = null; | ||||
| }; | ||||
| 
 | ||||
| // SyntaxElementMorph stepping:
 | ||||
| 
 | ||||
| SyntaxElementMorph.prototype.step = null; | ||||
| 
 | ||||
| // SyntaxElementMorph accessing:
 | ||||
| 
 | ||||
| SyntaxElementMorph.prototype.parts = function () { | ||||
|  | @ -472,8 +468,7 @@ SyntaxElementMorph.prototype.replaceInput = function (oldArg, newArg) { | |||
|     var scripts = this.parentThatIsA(ScriptsMorph), | ||||
|         replacement = newArg, | ||||
|         idx = this.children.indexOf(oldArg), | ||||
|         i = 0, | ||||
|         nb; | ||||
|         i = 0; | ||||
| 
 | ||||
|     // try to find the ArgLabel embedding the newArg,
 | ||||
|     // used for the undrop() feature
 | ||||
|  | @ -511,13 +506,6 @@ SyntaxElementMorph.prototype.replaceInput = function (oldArg, newArg) { | |||
|             oldArg.moveBy(replacement.extent()); | ||||
|             oldArg.fixBlockColor(); | ||||
|         } | ||||
|     } else if (oldArg instanceof CommandSlotMorph) { | ||||
|         nb = oldArg.nestedBlock(); | ||||
|         if (nb) { | ||||
|             scripts.add(nb); | ||||
|             nb.moveBy(replacement.extent()); | ||||
|             nb.fixBlockColor(); | ||||
|         } | ||||
|     } | ||||
|     if (replacement instanceof MultiArgMorph | ||||
|             || replacement instanceof ArgLabelMorph | ||||
|  | @ -703,10 +691,11 @@ SyntaxElementMorph.prototype.dark = function () { | |||
| 
 | ||||
| // SyntaxElementMorph color changing:
 | ||||
| 
 | ||||
| SyntaxElementMorph.prototype.setColor = function (aColor) { | ||||
| SyntaxElementMorph.prototype.setColor = function (aColor, silently) { | ||||
|     if (aColor) { | ||||
|         if (!this.color.eq(aColor)) { | ||||
|             this.color = aColor; | ||||
|             if (silently) {return; } | ||||
|             this.drawNew(); | ||||
|             this.children.forEach(function (child) { | ||||
|                 child.drawNew(); | ||||
|  | @ -942,6 +931,7 @@ SyntaxElementMorph.prototype.labelPart = function (spec) { | |||
|                 }, | ||||
|                 true // read-only
 | ||||
|             ); | ||||
|             part.isStatic = true; | ||||
|             break; | ||||
|         case '%dates': | ||||
|             part = new InputSlotMorph( | ||||
|  | @ -1302,6 +1292,11 @@ SyntaxElementMorph.prototype.labelPart = function (spec) { | |||
|         case '%cs': | ||||
|             part = new CSlotMorph(); // non-static
 | ||||
|             break; | ||||
|         case '%cl': | ||||
|             part = new CSlotMorph(); | ||||
|             part.isStatic = true; // rejects reporter drops
 | ||||
|             part.isLambda = true; // auto-reifies nested script
 | ||||
|             break; | ||||
|         case '%clr': | ||||
|             part = new ColorSlotMorph(); | ||||
|             part.isStatic = true; | ||||
|  | @ -1501,7 +1496,7 @@ SyntaxElementMorph.prototype.isObjInputFragment = function () { | |||
| 
 | ||||
| // SyntaxElementMorph layout:
 | ||||
| 
 | ||||
| SyntaxElementMorph.prototype.fixLayout = function () { | ||||
| SyntaxElementMorph.prototype.fixLayout = function (silently) { | ||||
|     var nb, | ||||
|         parts = this.parts(), | ||||
|         myself = this, | ||||
|  | @ -1682,8 +1677,8 @@ SyntaxElementMorph.prototype.fixLayout = function () { | |||
|         } | ||||
|     } | ||||
| 
 | ||||
|     // set my extent:
 | ||||
|     this.setExtent(new Point(blockWidth, blockHeight)); | ||||
|     // set my extent (silently, because we'll redraw later anyway):
 | ||||
|     this.silentSetExtent(new Point(blockWidth, blockHeight)); | ||||
| 
 | ||||
|     // adjust CSlots
 | ||||
|     parts.forEach(function (part) { | ||||
|  | @ -1697,7 +1692,7 @@ SyntaxElementMorph.prototype.fixLayout = function () { | |||
|     }); | ||||
| 
 | ||||
|     // redraw in order to erase CSlot backgrounds
 | ||||
|     this.drawNew(); | ||||
|     if (!silently) {this.drawNew(); } | ||||
| 
 | ||||
|     // position next block:
 | ||||
|     if (nb) { | ||||
|  | @ -1777,6 +1772,7 @@ SyntaxElementMorph.prototype.showBubble = function (value, exportPic) { | |||
|         morphToShow.update(true); | ||||
|         morphToShow.step = value.update; | ||||
|         morphToShow.isDraggable = false; | ||||
|         morphToShow.expand(this.parentThatIsA(ScrollFrameMorph).extent()); | ||||
|         isClickable = true; | ||||
|     } else if (value instanceof Morph) { | ||||
|         img = value.fullImage(); | ||||
|  | @ -1954,7 +1950,9 @@ SyntaxElementMorph.prototype.endLayout = function () { | |||
|     %lst    - chameleon colored rectangular drop-down for list names | ||||
|     %b        - chameleon colored hexagonal slot (for predicates) | ||||
|     %l        - list icon | ||||
|     %c        - C-shaped command slot | ||||
|     %c        - C-shaped command slot, special form for primitives | ||||
|     %cs       - C-shaped, auto-reifying, accepts reporter drops | ||||
|     %cl       - C-shaped, auto-reifying, rejects reporters | ||||
|     %clr    - interactive color slot | ||||
|     %t        - inline variable reporter template | ||||
|     %anyUE    - white rectangular type-in slot, unevaluated if replaced | ||||
|  | @ -2027,7 +2025,7 @@ function BlockMorph() { | |||
|     this.init(); | ||||
| } | ||||
| 
 | ||||
| BlockMorph.prototype.init = function () { | ||||
| BlockMorph.prototype.init = function (silently) { | ||||
|     this.selector = null; // name of method to be triggered
 | ||||
|     this.blockSpec = ''; // formal description of label and arguments
 | ||||
|     this.comment = null; // optional "sticky" comment morph
 | ||||
|  | @ -2036,7 +2034,7 @@ BlockMorph.prototype.init = function () { | |||
|     this.instantiationSpec = null; // spec to set upon fullCopy() of template
 | ||||
|     this.category = null; // for zebra coloring (non persistent)
 | ||||
| 
 | ||||
|     BlockMorph.uber.init.call(this); | ||||
|     BlockMorph.uber.init.call(this, silently); | ||||
|     this.color = new Color(0, 17, 173); | ||||
|     this.cashedInputs = null; | ||||
| }; | ||||
|  | @ -2101,7 +2099,7 @@ BlockMorph.prototype.parseSpec = function (spec) { | |||
|     return result; | ||||
| }; | ||||
| 
 | ||||
| BlockMorph.prototype.setSpec = function (spec) { | ||||
| BlockMorph.prototype.setSpec = function (spec, silently) { | ||||
|     var myself = this, | ||||
|         part, | ||||
|         inputIdx = -1; | ||||
|  | @ -2144,10 +2142,17 @@ BlockMorph.prototype.setSpec = function (spec) { | |||
|         } | ||||
|     }); | ||||
|     this.blockSpec = spec; | ||||
|     this.fixLayout(); | ||||
|     this.fixLayout(silently); | ||||
|     this.cachedInputs = null; | ||||
| }; | ||||
| 
 | ||||
| BlockMorph.prototype.userSetSpec = function (spec) { | ||||
|     var tb = this.topBlock(); | ||||
|     tb.fullChanged(); | ||||
|     this.setSpec(spec); | ||||
|     tb.fullChanged(); | ||||
| }; | ||||
| 
 | ||||
| BlockMorph.prototype.buildSpec = function () { | ||||
|     // create my blockSpec from my parts - for demo purposes only
 | ||||
|     var myself = this; | ||||
|  | @ -2448,6 +2453,7 @@ BlockMorph.prototype.ringify = function () { | |||
|         center = top.fullBounds().center(); | ||||
| 
 | ||||
|     if (this.parent === null) {return null; } | ||||
|     top.fullChanged(); | ||||
|     if (this.parent instanceof SyntaxElementMorph) { | ||||
|         if (this instanceof ReporterBlockMorph) { | ||||
|             this.parent.silentReplaceInput(this, ring); | ||||
|  | @ -2463,11 +2469,14 @@ BlockMorph.prototype.ringify = function () { | |||
|         ring.setCenter(center); | ||||
|     } | ||||
|     this.fixBlockColor(null, true); | ||||
|     top.fullChanged(); | ||||
| 
 | ||||
| }; | ||||
| 
 | ||||
| BlockMorph.prototype.unringify = function () { | ||||
|     // remove a Ring around me, if any
 | ||||
|     var ring = this.parentThatIsA(RingMorph), | ||||
|         top = this.topBlock(), | ||||
|         scripts = this.parentThatIsA(ScriptsMorph), | ||||
|         block, | ||||
|         center; | ||||
|  | @ -2476,6 +2485,7 @@ BlockMorph.prototype.unringify = function () { | |||
|     block = ring.contents(); | ||||
|     center = ring.center(); | ||||
| 
 | ||||
|     top.fullChanged(); | ||||
|     if (ring.parent instanceof SyntaxElementMorph) { | ||||
|         if (block instanceof ReporterBlockMorph) { | ||||
|             ring.parent.silentReplaceInput(ring, block); | ||||
|  | @ -2491,6 +2501,7 @@ BlockMorph.prototype.unringify = function () { | |||
|         ring.destroy(); | ||||
|     } | ||||
|     this.fixBlockColor(null, true); | ||||
|     top.fullChanged(); | ||||
| }; | ||||
| 
 | ||||
| BlockMorph.prototype.relabel = function (alternativeSelectors) { | ||||
|  | @ -2887,12 +2898,13 @@ BlockMorph.prototype.eraseHoles = function (context) { | |||
|         var w = hole.width(), | ||||
|             h = Math.floor(hole.height()) - 2; // Opera needs this
 | ||||
|         context.clearRect( | ||||
|             Math.floor(hole.bounds.origin.x - myself.bounds.origin.x) + 1, | ||||
|             Math.floor(hole.bounds.origin.y - myself.bounds.origin.y) + 1, | ||||
|             isReporter ? w - 1 : w + 1, | ||||
|             hole.bounds.origin.x - myself.bounds.origin.x + 1, | ||||
|             hole.bounds.origin.y - myself.bounds.origin.y + 1, | ||||
|             isReporter ? w - 2 : w + 1, | ||||
|             h | ||||
|         ); | ||||
|     }); | ||||
| 
 | ||||
| }; | ||||
| 
 | ||||
| // BlockMorph highlighting
 | ||||
|  | @ -3081,7 +3093,7 @@ BlockMorph.prototype.fixBlockColor = function (nearestBlock, isForced) { | |||
| 
 | ||||
| BlockMorph.prototype.forceNormalColoring = function () { | ||||
|     var clr = SpriteMorph.prototype.blockColor[this.category]; | ||||
|     this.setColor(clr); | ||||
|     this.setColor(clr, true); // silently
 | ||||
|     this.setLabelColor( | ||||
|         new Color(255, 255, 255), | ||||
|         clr.darker(this.labelContrast), | ||||
|  | @ -3096,10 +3108,11 @@ BlockMorph.prototype.alternateBlockColor = function () { | |||
|     if (this.color.eq(clr)) { | ||||
|         this.setColor( | ||||
|             this.zebraContrast < 0 ? clr.darker(Math.abs(this.zebraContrast)) | ||||
|                 : clr.lighter(this.zebraContrast) | ||||
|                 : clr.lighter(this.zebraContrast), | ||||
|             true // silently
 | ||||
|         ); | ||||
|     } else { | ||||
|         this.setColor(clr); | ||||
|         this.setColor(clr, true);  // silently
 | ||||
|     } | ||||
|     this.fixLabelColor(); | ||||
|     this.fixChildrensBlockColor(true); // has issues if not forced
 | ||||
|  | @ -3356,6 +3369,7 @@ BlockMorph.prototype.prepareToBeGrabbed = function (hand) { | |||
| }; | ||||
| 
 | ||||
| BlockMorph.prototype.justDropped = function () { | ||||
|     this.alpha = 1; | ||||
|     this.allComments().forEach(function (comment) { | ||||
|         comment.stopFollowing(); | ||||
|     }); | ||||
|  | @ -3444,9 +3458,9 @@ function CommandBlockMorph() { | |||
|     this.init(); | ||||
| } | ||||
| 
 | ||||
| CommandBlockMorph.prototype.init = function () { | ||||
|     CommandBlockMorph.uber.init.call(this); | ||||
|     this.setExtent(new Point(200, 100)); | ||||
| CommandBlockMorph.prototype.init = function (silently) { | ||||
|     CommandBlockMorph.uber.init.call(this, silently); | ||||
|     this.setExtent(new Point(200, 100), silently); | ||||
|     this.partOfCustomCommand = false; | ||||
|     this.exitTag = null; | ||||
| }; | ||||
|  | @ -3479,7 +3493,12 @@ CommandBlockMorph.prototype.nextBlock = function (block) { | |||
|         if (nb) { | ||||
|             block.bottomBlock().nextBlock(nb); | ||||
|         } | ||||
|         this.fixLayout(); | ||||
|         block.setPosition( | ||||
|             new Point( | ||||
|                 this.left(), | ||||
|                 this.bottom() - (this.corner) | ||||
|             ) | ||||
|         ); | ||||
|         if (affected) { | ||||
|             affected.fixLayout(); | ||||
|         } | ||||
|  | @ -4125,7 +4144,7 @@ function HatBlockMorph() { | |||
| } | ||||
| 
 | ||||
| HatBlockMorph.prototype.init = function () { | ||||
|     HatBlockMorph.uber.init.call(this); | ||||
|     HatBlockMorph.uber.init.call(this, true); // silently
 | ||||
|     this.setExtent(new Point(300, 150)); | ||||
| }; | ||||
| 
 | ||||
|  | @ -4302,10 +4321,10 @@ function ReporterBlockMorph(isPredicate) { | |||
|     this.init(isPredicate); | ||||
| } | ||||
| 
 | ||||
| ReporterBlockMorph.prototype.init = function (isPredicate) { | ||||
|     ReporterBlockMorph.uber.init.call(this); | ||||
| ReporterBlockMorph.prototype.init = function (isPredicate, silently) { | ||||
|     ReporterBlockMorph.uber.init.call(this, silently); | ||||
|     this.isPredicate = isPredicate || false; | ||||
|     this.setExtent(new Point(200, 80)); | ||||
|     this.setExtent(new Point(200, 80), silently); | ||||
| }; | ||||
| 
 | ||||
| // ReporterBlockMorph drag & drop:
 | ||||
|  | @ -4313,6 +4332,7 @@ ReporterBlockMorph.prototype.init = function (isPredicate) { | |||
| ReporterBlockMorph.prototype.snap = function (hand) { | ||||
|     // passing the hand is optional (for when blocks are dragged & dropped)
 | ||||
|     var scripts = this.parent, | ||||
|         nb, | ||||
|         target; | ||||
| 
 | ||||
|     if (!scripts instanceof ScriptsMorph) { | ||||
|  | @ -4329,6 +4349,16 @@ ReporterBlockMorph.prototype.snap = function (hand) { | |||
|         if (target instanceof MultiArgMorph) { | ||||
|             scripts.lastPreservedBlocks = target.inputs(); | ||||
|             scripts.lastReplacedInput = target.fullCopy(); | ||||
|         } else if (target instanceof CommandSlotMorph) { | ||||
|             scripts.lastReplacedInput = target; | ||||
|             nb = target.nestedBlock(); | ||||
|             if (nb) { | ||||
|                 nb = nb.fullCopy(); | ||||
|                 scripts.add(nb); | ||||
|                 nb.moveBy(nb.extent()); | ||||
|                 nb.fixBlockColor(); | ||||
|                 scripts.lastPreservedBlocks = [nb]; | ||||
|             } | ||||
|         } | ||||
|         target.parent.replaceInput(target, this); | ||||
|         if (this.snapSound) { | ||||
|  | @ -4352,6 +4382,7 @@ ReporterBlockMorph.prototype.prepareToBeGrabbed = function (handMorph) { | |||
|         this.setPosition(oldPos); | ||||
|     } | ||||
|     ReporterBlockMorph.uber.prepareToBeGrabbed.call(this, handMorph); | ||||
|     this.alpha = 0.85; | ||||
| }; | ||||
| 
 | ||||
| // ReporterBlockMorph enumerating
 | ||||
|  | @ -4413,7 +4444,7 @@ ReporterBlockMorph.prototype.mouseClickLeft = function (pos) { | |||
|             this.parent.parent.parent instanceof RingMorph; | ||||
|         new DialogBoxMorph( | ||||
|             this, | ||||
|             this.setSpec, | ||||
|             this.userSetSpec, | ||||
|             this | ||||
|         ).prompt( | ||||
|             isRing ? "Input name" : "Script variable name", | ||||
|  | @ -4987,6 +5018,7 @@ ScriptsMorph.prototype.init = function (owner) { | |||
| 
 | ||||
|     ScriptsMorph.uber.init.call(this); | ||||
|     this.setColor(new Color(70, 70, 70)); | ||||
|     this.noticesTransparentClick = true; | ||||
| }; | ||||
| 
 | ||||
| // ScriptsMorph deep copying:
 | ||||
|  | @ -5180,14 +5212,15 @@ ScriptsMorph.prototype.closestInput = function (reporter, hand) { | |||
|                 all, | ||||
|                 function (input) { | ||||
|                     return (input instanceof InputSlotMorph | ||||
|                             || input instanceof ArgMorph | ||||
|                             || (input instanceof ArgMorph | ||||
|                                 && !(input instanceof CommandSlotMorph) | ||||
|                                 && !(input instanceof MultiArgMorph)) | ||||
|                             || (input instanceof RingMorph | ||||
|                                 && !input.contents()) | ||||
|                             || input.isEmptySlot()) | ||||
|                         && !input.isLocked() | ||||
|                         && input.bounds.containsPoint(handPos) | ||||
|                         && !contains(blackList, input) | ||||
|                         && touchingVariadicArrowsIfAny(input, handPos); | ||||
|                         && !contains(blackList, input); | ||||
|                 } | ||||
|             ); | ||||
|             if (target) { | ||||
|  | @ -5550,12 +5583,12 @@ function ArgMorph(type) { | |||
|     this.init(type); | ||||
| } | ||||
| 
 | ||||
| ArgMorph.prototype.init = function (type) { | ||||
| ArgMorph.prototype.init = function (type, silently) { | ||||
|     this.type = type || null; | ||||
|     this.isHole = false; | ||||
|     ArgMorph.uber.init.call(this); | ||||
|     ArgMorph.uber.init.call(this, silently); | ||||
|     this.color = new Color(0, 17, 173); | ||||
|     this.setExtent(new Point(50, 50)); | ||||
|     this.setExtent(new Point(50, 50), silently); | ||||
| }; | ||||
| 
 | ||||
| // ArgMorph drag & drop: for demo puposes only
 | ||||
|  | @ -5663,10 +5696,13 @@ function CommandSlotMorph() { | |||
|     this.init(); | ||||
| } | ||||
| 
 | ||||
| CommandSlotMorph.prototype.init = function () { | ||||
|     CommandSlotMorph.uber.init.call(this); | ||||
| CommandSlotMorph.prototype.init = function (silently) { | ||||
|     CommandSlotMorph.uber.init.call(this, null, true); // silently
 | ||||
|     this.color = new Color(0, 17, 173); | ||||
|     this.setExtent(new Point(230, this.corner * 4 + this.cSlotPadding)); | ||||
|     this.setExtent( | ||||
|         new Point(230, this.corner * 4 + this.cSlotPadding), | ||||
|         silently | ||||
|     ); | ||||
| }; | ||||
| 
 | ||||
| CommandSlotMorph.prototype.getSpec = function () { | ||||
|  | @ -6118,8 +6154,8 @@ function RingCommandSlotMorph() { | |||
|     this.init(); | ||||
| } | ||||
| 
 | ||||
| RingCommandSlotMorph.prototype.init = function () { | ||||
|     RingCommandSlotMorph.uber.init.call(this); | ||||
| RingCommandSlotMorph.prototype.init = function (silently) { | ||||
|     RingCommandSlotMorph.uber.init.call(this, silently); | ||||
|     this.isHole = true; | ||||
|     this.noticesTransparentClick = true; | ||||
|     this.color = new Color(0, 17, 173); | ||||
|  | @ -6269,11 +6305,15 @@ function CSlotMorph() { | |||
|     this.init(); | ||||
| } | ||||
| 
 | ||||
| CSlotMorph.prototype.init = function () { | ||||
|     CommandSlotMorph.uber.init.call(this); | ||||
| CSlotMorph.prototype.init = function (silently) { | ||||
|     CommandSlotMorph.uber.init.call(this, null, true); // silently
 | ||||
|     this.isHole = true; | ||||
|     this.isLambda = false; // see Process.prototype.evaluateInput
 | ||||
|     this.color = new Color(0, 17, 173); | ||||
|     this.setExtent(new Point(230, this.corner * 4 + this.cSlotPadding)); | ||||
|     this.setExtent( | ||||
|         new Point(230, this.corner * 4 + this.cSlotPadding), | ||||
|         silently | ||||
|     ); | ||||
| }; | ||||
| 
 | ||||
| CSlotMorph.prototype.getSpec = function () { | ||||
|  | @ -6721,7 +6761,7 @@ InputSlotMorph.prototype.init = function ( | |||
|     this.minWidth = 0; // can be chaged for text-type inputs ("landscape")
 | ||||
|     this.constant = null; | ||||
| 
 | ||||
|     InputSlotMorph.uber.init.call(this); | ||||
|     InputSlotMorph.uber.init.call(this, null, true); | ||||
|     this.color = new Color(255, 255, 255); | ||||
|     this.add(contents); | ||||
|     this.add(arrow); | ||||
|  | @ -7874,7 +7914,7 @@ ArrowMorph.prototype.init = function (direction, size, padding, color) { | |||
|     this.size = size || ((size === 0) ? 0 : 50); | ||||
|     this.padding = padding || 0; | ||||
| 
 | ||||
|     ArrowMorph.uber.init.call(this); | ||||
|     ArrowMorph.uber.init.call(this, true); // silently
 | ||||
|     this.color = color || new Color(0, 0, 0); | ||||
|     this.setExtent(new Point(this.size, this.size)); | ||||
| }; | ||||
|  | @ -7963,7 +8003,7 @@ TextSlotMorph.prototype.init = function ( | |||
|     this.minWidth = 0; // can be chaged for text-type inputs ("landscape")
 | ||||
|     this.constant = null; | ||||
| 
 | ||||
|     InputSlotMorph.uber.init.call(this); | ||||
|     InputSlotMorph.uber.init.call(this, null, null, null, null, true); // sil.
 | ||||
|     this.color = new Color(255, 255, 255); | ||||
|     this.add(contents); | ||||
|     this.add(arrow); | ||||
|  | @ -8084,7 +8124,7 @@ SymbolMorph.prototype.init = function ( | |||
|     this.shadowOffset = shadowOffset || new Point(0, 0); | ||||
|     this.shadowColor = shadowColor || null; | ||||
| 
 | ||||
|     SymbolMorph.uber.init.call(this); | ||||
|     SymbolMorph.uber.init.call(this, true); // silently
 | ||||
|     this.color = color || new Color(0, 0, 0); | ||||
|     this.drawNew(); | ||||
| }; | ||||
|  | @ -9316,7 +9356,7 @@ function ColorSlotMorph(clr) { | |||
| } | ||||
| 
 | ||||
| ColorSlotMorph.prototype.init = function (clr) { | ||||
|     ColorSlotMorph.uber.init.call(this); | ||||
|     ColorSlotMorph.uber.init.call(this, null, true); // silently
 | ||||
|     this.setColor(clr || new Color(145, 26, 68)); | ||||
| }; | ||||
| 
 | ||||
|  | @ -9494,7 +9534,7 @@ MultiArgMorph.prototype.init = function ( | |||
|     this.shadowOffset = shadowOffset || null; | ||||
| 
 | ||||
|     this.canBeEmpty = true; | ||||
|     MultiArgMorph.uber.init.call(this); | ||||
|     MultiArgMorph.uber.init.call(this, null, true); // silently
 | ||||
| 
 | ||||
|     // MultiArgMorphs are transparent by default b/c of zebra coloring
 | ||||
|     this.alpha = isTransparent === false ? 1 : 0; | ||||
|  | @ -9882,7 +9922,7 @@ ArgLabelMorph.prototype.init = function (argMorph, labelTxt) { | |||
|     var label; | ||||
| 
 | ||||
|     this.labelText = localize(labelTxt || 'input list:'); | ||||
|     ArgLabelMorph.uber.init.call(this); | ||||
|     ArgLabelMorph.uber.init.call(this, null, true); // silently
 | ||||
| 
 | ||||
|     this.isStatic = true; // I cannot be exchanged
 | ||||
| 
 | ||||
|  | @ -10008,14 +10048,17 @@ function FunctionSlotMorph(isPredicate) { | |||
|     this.init(isPredicate); | ||||
| } | ||||
| 
 | ||||
| FunctionSlotMorph.prototype.init = function (isPredicate) { | ||||
|     FunctionSlotMorph.uber.init.call(this); | ||||
| FunctionSlotMorph.prototype.init = function (isPredicate, silently) { | ||||
|     FunctionSlotMorph.uber.init.call(this, null, true); // silently
 | ||||
|     this.isPredicate = isPredicate || false; | ||||
|     this.color = this.rfColor; | ||||
|     this.setExtent(new Point( | ||||
|         (this.fontSize + this.edge * 2) * 2, | ||||
|         this.fontSize + this.edge * 2 | ||||
|     )); | ||||
|     this.setExtent( | ||||
|         new Point( | ||||
|             (this.fontSize + this.edge * 2) * 2, | ||||
|             this.fontSize + this.edge * 2 | ||||
|         ), | ||||
|         silently | ||||
|     ); | ||||
| }; | ||||
| 
 | ||||
| FunctionSlotMorph.prototype.getSpec = function () { | ||||
|  | @ -10390,7 +10433,7 @@ function ReporterSlotMorph(isPredicate) { | |||
| } | ||||
| 
 | ||||
| ReporterSlotMorph.prototype.init = function (isPredicate) { | ||||
|     ReporterSlotMorph.uber.init.call(this, isPredicate); | ||||
|     ReporterSlotMorph.uber.init.call(this, isPredicate, true); | ||||
|     this.add(this.emptySlot()); | ||||
|     this.fixLayout(); | ||||
| }; | ||||
|  | @ -10481,7 +10524,7 @@ function RingReporterSlotMorph(isPredicate) { | |||
| } | ||||
| 
 | ||||
| RingReporterSlotMorph.prototype.init = function (isPredicate) { | ||||
|     RingReporterSlotMorph.uber.init.call(this, isPredicate); | ||||
|     RingReporterSlotMorph.uber.init.call(this, isPredicate, true); | ||||
|     this.alpha = RingMorph.prototype.alpha; | ||||
|     this.contrast = RingMorph.prototype.contrast; | ||||
|     this.isHole = true; | ||||
|  |  | |||
							
								
								
									
										58
									
								
								byob.js
								
								
								
								
							
							
						
						
									
										58
									
								
								byob.js
								
								
								
								
							|  | @ -108,7 +108,7 @@ SymbolMorph, isNil, CursorMorph*/ | |||
| 
 | ||||
| // Global stuff ////////////////////////////////////////////////////////
 | ||||
| 
 | ||||
| modules.byob = '2015-October-07'; | ||||
| modules.byob = '2015-November-16'; | ||||
| 
 | ||||
| // Declarations
 | ||||
| 
 | ||||
|  | @ -148,6 +148,7 @@ function CustomBlockDefinition(spec, receiver) { | |||
| 
 | ||||
|     // don't serialize (not needed for functionality):
 | ||||
|     this.receiver = receiver || null; // for serialization only (pointer)
 | ||||
|     this.editorDimensions = null; // a rectangle, last bounds of the editor
 | ||||
| } | ||||
| 
 | ||||
| // CustomBlockDefinition instantiating blocks
 | ||||
|  | @ -405,9 +406,7 @@ function CustomCommandBlockMorph(definition, isProto) { | |||
| CustomCommandBlockMorph.prototype.init = function (definition, isProto) { | ||||
|     this.definition = definition; // mandatory
 | ||||
|     this.isPrototype = isProto || false; // optional
 | ||||
| 
 | ||||
|     CustomCommandBlockMorph.uber.init.call(this); | ||||
| 
 | ||||
|     CustomCommandBlockMorph.uber.init.call(this, true); // silently
 | ||||
|     this.category = definition.category; | ||||
|     this.selector = 'evaluateCustomBlock'; | ||||
|     if (definition) { // needed for de-serializing
 | ||||
|  | @ -415,7 +414,7 @@ CustomCommandBlockMorph.prototype.init = function (definition, isProto) { | |||
|     } | ||||
| }; | ||||
| 
 | ||||
| CustomCommandBlockMorph.prototype.refresh = function () { | ||||
| CustomCommandBlockMorph.prototype.refresh = function (silently) { | ||||
|     var def = this.definition, | ||||
|         newSpec = this.isPrototype ? | ||||
|                 def.spec : def.blockSpec(), | ||||
|  | @ -429,7 +428,7 @@ CustomCommandBlockMorph.prototype.refresh = function () { | |||
|         } else { | ||||
|             this.fixBlockColor(); | ||||
|         } | ||||
|         this.setSpec(newSpec); | ||||
|         this.setSpec(newSpec, silently); | ||||
|         this.fixLabelColor(); | ||||
|         this.restoreInputs(oldInputs); | ||||
|     } else { // update all input slots' drop-downs
 | ||||
|  | @ -671,7 +670,7 @@ CustomCommandBlockMorph.prototype.mouseClickLeft = function () { | |||
| }; | ||||
| 
 | ||||
| CustomCommandBlockMorph.prototype.edit = function () { | ||||
|     var myself = this, block, hat; | ||||
|     var myself = this, editor, block, hat; | ||||
| 
 | ||||
|     if (this.isPrototype) { | ||||
|         block = this.definition.blockInstance(); | ||||
|  | @ -696,7 +695,11 @@ CustomCommandBlockMorph.prototype.edit = function () { | |||
|             myself.isInUse() | ||||
|         ); | ||||
|     } else { | ||||
|         new BlockEditorMorph(this.definition, this.receiver()).popUp(); | ||||
|         Morph.prototype.trackChanges = false; | ||||
|         editor = new BlockEditorMorph(this.definition, this.receiver()); | ||||
|         editor.popUp(); | ||||
|         Morph.prototype.trackChanges = true; | ||||
|         editor.changed(); | ||||
|     } | ||||
| }; | ||||
| 
 | ||||
|  | @ -763,7 +766,7 @@ CustomCommandBlockMorph.prototype.userMenu = function () { | |||
|         menu.addItem( | ||||
|             "script pic...", | ||||
|             function () { | ||||
|                 window.open(this.topBlock().fullImage().toDataURL()); | ||||
|                 window.open(this.topBlock().scriptPic().toDataURL()); | ||||
|             }, | ||||
|             'open a new window\nwith a picture of this script' | ||||
|         ); | ||||
|  | @ -936,7 +939,7 @@ CustomReporterBlockMorph.prototype.init = function ( | |||
|     this.definition = definition; // mandatory
 | ||||
|     this.isPrototype = isProto || false; // optional
 | ||||
| 
 | ||||
|     CustomReporterBlockMorph.uber.init.call(this, isPredicate); | ||||
|     CustomReporterBlockMorph.uber.init.call(this, isPredicate, true); // sil.
 | ||||
| 
 | ||||
|     this.category = definition.category; | ||||
|     this.selector = 'evaluateCustomBlock'; | ||||
|  | @ -946,7 +949,7 @@ CustomReporterBlockMorph.prototype.init = function ( | |||
| }; | ||||
| 
 | ||||
| CustomReporterBlockMorph.prototype.refresh = function () { | ||||
|     CustomCommandBlockMorph.prototype.refresh.call(this); | ||||
|     CustomCommandBlockMorph.prototype.refresh.call(this, true); | ||||
|     if (!this.isPrototype) { | ||||
|         this.isPredicate = (this.definition.type === 'predicate'); | ||||
|     } | ||||
|  | @ -1726,7 +1729,7 @@ BlockEditorMorph.prototype.init = function (definition, target) { | |||
|     this.addButton('updateDefinition', 'Apply'); | ||||
|     this.addButton('cancel', 'Cancel'); | ||||
| 
 | ||||
|     this.setExtent(new Point(375, 300)); | ||||
|     this.setExtent(new Point(375, 300)); // normal initial extent
 | ||||
|     this.fixLayout(); | ||||
|     proto.children[0].fixLayout(); | ||||
|     scripts.fixMultiArgs(); | ||||
|  | @ -1737,6 +1740,7 @@ BlockEditorMorph.prototype.popUp = function () { | |||
| 
 | ||||
|     if (world) { | ||||
|         BlockEditorMorph.uber.popUp.call(this, world); | ||||
|         this.setInitialDimensions(); | ||||
|         this.handle = new HandleMorph( | ||||
|             this, | ||||
|             280, | ||||
|  | @ -1744,9 +1748,18 @@ BlockEditorMorph.prototype.popUp = function () { | |||
|             this.corner, | ||||
|             this.corner | ||||
|         ); | ||||
|         world.keyboardReceiver = null; | ||||
|     } | ||||
| }; | ||||
| 
 | ||||
| BlockEditorMorph.prototype.justDropped = function () { | ||||
|     // override the inherited default behavior, which is to
 | ||||
|     // give keyboard focus to dialog boxes, as in this case
 | ||||
|     // we want Snap-global keyboard-shortcuts like ctrl-f
 | ||||
|     // to still work
 | ||||
|     nop(); | ||||
| }; | ||||
| 
 | ||||
| // BlockEditorMorph ops
 | ||||
| 
 | ||||
| BlockEditorMorph.prototype.accept = function (origin) { | ||||
|  | @ -1851,6 +1864,7 @@ BlockEditorMorph.prototype.updateDefinition = function () { | |||
|     this.definition.spec = this.prototypeSpec(); | ||||
|     this.definition.declarations = this.prototypeSlots(); | ||||
|     this.definition.scripts = []; | ||||
|     this.definition.editorDimensions = this.bounds.copy(); | ||||
| 
 | ||||
|     this.body.contents.children.forEach(function (morph) { | ||||
|         if (morph instanceof PrototypeHatBlockMorph) { | ||||
|  | @ -1927,6 +1941,26 @@ BlockEditorMorph.prototype.prototypeSlots = function () { | |||
| 
 | ||||
| // BlockEditorMorph layout
 | ||||
| 
 | ||||
| BlockEditorMorph.prototype.setInitialDimensions = function () { | ||||
|     var world = this.world(), | ||||
|         mex = world.extent().subtract(new Point(this.padding, this.padding)), | ||||
|         th = fontHeight(this.titleFontSize) + this.titlePadding * 2, | ||||
|         bh = this.buttons.height(); | ||||
| 
 | ||||
|     if (this.definition.editorDimensions) { | ||||
|         this.setPosition(this.definition.editorDimensions.origin); | ||||
|         this.setExtent(this.definition.editorDimensions.extent().min(mex)); | ||||
|         this.keepWithin(world); | ||||
|         return; | ||||
|     } | ||||
|     this.setExtent( | ||||
|         this.body.contents.extent().add( | ||||
|             new Point(this.padding, this.padding + th + bh) | ||||
|         ).min(mex) | ||||
|     ); | ||||
|     this.setCenter(this.world().center()); | ||||
| }; | ||||
| 
 | ||||
| BlockEditorMorph.prototype.fixLayout = function () { | ||||
|     var th = fontHeight(this.titleFontSize) + this.titlePadding * 2; | ||||
| 
 | ||||
|  |  | |||
							
								
								
									
										41
									
								
								gui.js
								
								
								
								
							
							
						
						
									
										41
									
								
								gui.js
								
								
								
								
							|  | @ -71,7 +71,7 @@ BlockRemovalDialogMorph*/ | |||
| 
 | ||||
| // Global stuff ////////////////////////////////////////////////////////
 | ||||
| 
 | ||||
| modules.gui = '2015-October-07'; | ||||
| modules.gui = '2015-November-16'; | ||||
| 
 | ||||
| // Declarations
 | ||||
| 
 | ||||
|  | @ -2227,6 +2227,15 @@ IDE_Morph.prototype.settingsMenu = function () { | |||
|         'Stage size...', | ||||
|         'userSetStageSize' | ||||
|     ); | ||||
|     if (shiftClicked) { | ||||
|         menu.addItem( | ||||
|             'Dragging threshold...', | ||||
|             'userSetDragThreshold', | ||||
|             'specify the distance the hand has to move\n' + | ||||
|                 'before it picks up an object', | ||||
|             new Color(100, 0, 0) | ||||
|         ); | ||||
|     } | ||||
|     menu.addLine(); | ||||
|     addPreference( | ||||
|         'Blurred shadows', | ||||
|  | @ -2713,7 +2722,7 @@ IDE_Morph.prototype.aboutSnap = function () { | |||
|         module, btn1, btn2, btn3, btn4, licenseBtn, translatorsBtn, | ||||
|         world = this.world(); | ||||
| 
 | ||||
|     aboutTxt = 'Snap! 4.0.2\nBuild Your Own Blocks\n\n' | ||||
|     aboutTxt = 'Snap! 4.0.3\nBuild Your Own Blocks\n\n' | ||||
|         + 'Copyright \u24B8 2015 Jens M\u00F6nig and ' | ||||
|         + 'Brian Harvey\n' | ||||
|         + 'jens@moenig.org, bh@cs.berkeley.edu\n\n' | ||||
|  | @ -4201,6 +4210,29 @@ IDE_Morph.prototype.setStageExtent = function (aPoint) { | |||
|     } | ||||
| }; | ||||
| 
 | ||||
| // IDE_Morph dragging threshold (internal feature)
 | ||||
| 
 | ||||
| IDE_Morph.prototype.userSetDragThreshold = function () { | ||||
|     new DialogBoxMorph( | ||||
|         this, | ||||
|         function (num) { | ||||
|             MorphicPreferences.grabThreshold = Math.min( | ||||
|                 Math.max(+num, 0), | ||||
|                 200 | ||||
|             ); | ||||
|         }, | ||||
|         this | ||||
|     ).prompt( | ||||
|         "Dragging threshold", | ||||
|         MorphicPreferences.grabThreshold.toString(), | ||||
|         this.world(), | ||||
|         null, // pic
 | ||||
|         null, // choices
 | ||||
|         null, // read only
 | ||||
|         true // numeric
 | ||||
|     ); | ||||
| }; | ||||
| 
 | ||||
| // IDE_Morph cloud interface
 | ||||
| 
 | ||||
| IDE_Morph.prototype.initializeCloud = function () { | ||||
|  | @ -5945,6 +5977,7 @@ SpriteIconMorph.prototype.prepareToBeGrabbed = function () { | |||
|     var ide = this.parentThatIsA(IDE_Morph), | ||||
|         idx; | ||||
|     this.mouseClickLeft(); // select me
 | ||||
|     this.alpha = 0.85; | ||||
|     if (ide) { | ||||
|         idx = ide.sprites.asArray().indexOf(this.object); | ||||
|         ide.sprites.remove(idx + 1); | ||||
|  | @ -5953,6 +5986,10 @@ SpriteIconMorph.prototype.prepareToBeGrabbed = function () { | |||
|     } | ||||
| }; | ||||
| 
 | ||||
| SpriteIconMorph.prototype.justDropped = function () { | ||||
|     this.alpha = 1; | ||||
| }; | ||||
| 
 | ||||
| SpriteIconMorph.prototype.wantsDropOf = function (morph) { | ||||
|     // allow scripts & media to be copied from one sprite to another
 | ||||
|     // by drag & drop
 | ||||
|  |  | |||
							
								
								
									
										72
									
								
								history.txt
								
								
								
								
							
							
						
						
									
										72
									
								
								history.txt
								
								
								
								
							|  | @ -2603,3 +2603,75 @@ ______ | |||
| * Store: Fix deserialization support for projects using inheritance | ||||
| * German translation update | ||||
| 
 | ||||
| 
 | ||||
| ++++++++++++++++++++++++++ | ||||
| new stuff - bulk of 151116 | ||||
| ++++++++++++++++++++++++++ | ||||
| 
 | ||||
| 151030 | ||||
| ------ | ||||
| * Blocks: Tweak precision of rendering of transparent “holes” | ||||
| * updated Czech translation (remember to integrate from email!) | ||||
| * Morphic: Streamlined nop-stepping | ||||
| * Blocks: Let SyntaxElements step (again), for better input slot editing experience | ||||
| 
 | ||||
| 151101 | ||||
| ------ | ||||
| * BYOB: Script pic: Always export comments attached to custom block definitions | ||||
| * Blocks: fixed #982 (made %interaction slot static) | ||||
| * Morphic: removed an obsolete line (“dragOrigin”) | ||||
| * BYOB: make block editor big enough to show the whole definition, if possible | ||||
| * BYOB: remember user-set position and size of block editor when pressing “OK”, per session (not serialized in project) | ||||
| * Blocks: speed up stacking of commands (also when done programmatically) by suppressing redraws | ||||
| * Morphic, Blocks, BYOB: Suppress redundant redraws | ||||
| 
 | ||||
| 151104 | ||||
| ------ | ||||
| * Morphic: new grabTheshold preference to suppress accidental grabbing through micro-movements of the hand | ||||
| * GUI: hidden (shift-click) option to adjust the grabThreshold for the current session | ||||
| * Lists, Blocks: Expand list watchers inside result bubbles to show everything | ||||
| * Objects: Expand list watchers inside speech/thought bubbles to show everything | ||||
| * Morphic: fixed a bug that occasionally expanded the Hand’s bounds when dragging morphs | ||||
| 
 | ||||
| 151107 | ||||
| ------ | ||||
| * Threads: invoke a block synchronously | ||||
| 
 | ||||
| 151009 | ||||
| ------ | ||||
| * Morphic: cache fullImage and fullBounds when dragging | ||||
| * Blocks: make reporters semi-transparent while dragging | ||||
| * GUI: make SpriteIcons semi-transparent while dragging | ||||
| * Blocks: make it harder to drop reporters onto filled custom C-slots and variadic slot arrows | ||||
| * Blocks: make ScriptsMorphs notice transparent clicks (addresses #997) | ||||
| * Blocks: fixed “undrop” for replacing C-slots with reporters | ||||
| * BYOB: fixed ctrl-f for the BlockEditor in all situations | ||||
| 
 | ||||
| 151111 | ||||
| ------ | ||||
| * Objects: fixed a between slideBackTo() and possible running scripts in sprites, thanks, Paul, for reporting it! | ||||
| 
 | ||||
| 151112 | ||||
| ------ | ||||
| * Blocks, Objects, Threads: new internal slot type: %cl for auto-reifying C-slots that reject reporter drops. Changed (hidden) “for each” to reject reporters in C-slot | ||||
| 
 | ||||
| 151113 | ||||
| ------ | ||||
| * Frames, snap.html: initial version of a new general purpose prototypal single inheritance object system | ||||
| * snap_slo.html: alternative animation-frame based outer scheduler, experimental | ||||
| * Threads: added optional timeout to the new synchronous invoke(block) function | ||||
| * Blocks: fixed too brutally optimized redraw for “ringify” and “unringify” | ||||
| 
 | ||||
| 151114 | ||||
| ------ | ||||
| * Frames, snap.html, snap_slo.html: remove initial version for now, needs more low-levelish rewrite (Map-based “shortcut” design doesn’t cut it). | ||||
| 
 | ||||
| 151116 | ||||
| ------ | ||||
| * Blocks, GUI: Slightly less transparency for dragged reporters and sprite icons | ||||
| 
 | ||||
| === v4.0.3 (unreleased) === | ||||
| 
 | ||||
| ++++++++++++++++++++++++++ | ||||
| end - bulk of 151116 | ||||
| ++++++++++++++++++++++++++ | ||||
|  |  | |||
							
								
								
									
										13
									
								
								lists.js
								
								
								
								
							
							
						
						
									
										13
									
								
								lists.js
								
								
								
								
							|  | @ -61,7 +61,7 @@ PushButtonMorph, SyntaxElementMorph, Color, Point, WatcherMorph, | |||
| StringMorph, SpriteMorph, ScrollFrameMorph, CellMorph, ArrowMorph, | ||||
| MenuMorph, snapEquals, Morph, isNil, localize, MorphicPreferences*/ | ||||
| 
 | ||||
| modules.lists = '2015-October-07'; | ||||
| modules.lists = '2015-November-16'; | ||||
| 
 | ||||
| var List; | ||||
| var ListWatcherMorph; | ||||
|  | @ -682,13 +682,14 @@ ListWatcherMorph.prototype.arrangeCells = function () { | |||
|     this.frame.contents.adjustBounds(); | ||||
| }; | ||||
| 
 | ||||
| ListWatcherMorph.prototype.expand = function () { | ||||
| ListWatcherMorph.prototype.expand = function (maxExtent) { | ||||
|     // make sure to show all (first 100) cells
 | ||||
|     // used for exporting a project summary
 | ||||
|     var fe = this.frame.contents.extent(), | ||||
|         w = fe.x + 6, | ||||
|         h = fe.y + this.label.height() + 6; | ||||
|     this.setExtent(new Point(w, h)); | ||||
|         ext = new Point(fe.x + 6, fe.y + this.label.height() + 6); | ||||
|     if (maxExtent) { | ||||
|         ext = ext.min(maxExtent); | ||||
|     } | ||||
|     this.setExtent(ext); | ||||
|     this.handle.setRight(this.right() - 3); | ||||
|     this.handle.setBottom(this.bottom() - 3); | ||||
| }; | ||||
|  |  | |||
							
								
								
									
										114
									
								
								morphic.js
								
								
								
								
							
							
						
						
									
										114
									
								
								morphic.js
								
								
								
								
							|  | @ -1052,7 +1052,7 @@ | |||
| /*global window, HTMLCanvasElement, getMinimumFontHeight, FileReader, Audio, | ||||
| FileList, getBlurredShadowSupport*/ | ||||
| 
 | ||||
| var morphicVersion = '2015-September-23'; | ||||
| var morphicVersion = '2015-November-16'; | ||||
| var modules = {}; // keep track of additional loaded modules
 | ||||
| var useBlurredShadows = getBlurredShadowSupport(); // check for Chrome-bug
 | ||||
| 
 | ||||
|  | @ -1072,7 +1072,8 @@ var standardSettings = { | |||
|     useVirtualKeyboard: true, | ||||
|     isTouchDevice: false, // turned on by touch events, don't set
 | ||||
|     rasterizeSVGs: false, | ||||
|     isFlat: false | ||||
|     isFlat: false, | ||||
|     grabThreshold: 5 | ||||
| }; | ||||
| 
 | ||||
| var touchScreenSettings = { | ||||
|  | @ -1091,7 +1092,8 @@ var touchScreenSettings = { | |||
|     useVirtualKeyboard: true, | ||||
|     isTouchDevice: false, | ||||
|     rasterizeSVGs: false, | ||||
|     isFlat: false | ||||
|     isFlat: false, | ||||
|     grabThreshold: 5 | ||||
| }; | ||||
| 
 | ||||
| var MorphicPreferences = standardSettings; | ||||
|  | @ -2207,7 +2209,10 @@ function Morph() { | |||
| Morph.prototype.init = function (noDraw) { | ||||
|     Morph.uber.init.call(this); | ||||
|     this.isMorph = true; | ||||
|     this.image = null; | ||||
|     this.bounds = new Rectangle(0, 0, 50, 40); | ||||
|     this.cachedFullImage = null; | ||||
|     this.cachedFullBounds = null; | ||||
|     this.color = new Color(80, 80, 80); | ||||
|     this.texture = null; // optional url of a fill-image
 | ||||
|     this.cachedTexture = null; // internal cache of actual bg image
 | ||||
|  | @ -2284,9 +2289,7 @@ Morph.prototype.nextSteps = function (arrayOfFunctions) { | |||
|     } | ||||
| }; | ||||
| 
 | ||||
| Morph.prototype.step = function () { | ||||
|     nop(); | ||||
| }; | ||||
| Morph.prototype.step = nop; | ||||
| 
 | ||||
| // Morph accessing - geometry getting:
 | ||||
| 
 | ||||
|  | @ -2412,6 +2415,9 @@ Morph.prototype.silentMoveBy = function (delta) { | |||
|     var children = this.children, | ||||
|         i = children.length; | ||||
|     this.bounds = this.bounds.translateBy(delta); | ||||
|     if (this.cachedFullBounds) { | ||||
|         this.cachedFullBounds = this.cachedFullBounds.translateBy(delta); | ||||
|     } | ||||
|     // ugly optimization avoiding forEach()
 | ||||
|     for (i; i > 0; i -= 1) { | ||||
|         children[i - 1].silentMoveBy(delta); | ||||
|  | @ -2533,7 +2539,12 @@ Morph.prototype.scrollIntoView = function () { | |||
| 
 | ||||
| // Morph accessing - dimensional changes requiring a complete redraw
 | ||||
| 
 | ||||
| Morph.prototype.setExtent = function (aPoint) { | ||||
| Morph.prototype.setExtent = function (aPoint, silently) { | ||||
|     // silently avoids redrawing the receiver
 | ||||
|     if (silently) { | ||||
|         this.silentSetExtent(aPoint); | ||||
|         return; | ||||
|     } | ||||
|     if (!aPoint.eq(this.extent())) { | ||||
|         this.changed(); | ||||
|         this.silentSetExtent(aPoint); | ||||
|  | @ -2640,29 +2651,31 @@ Morph.prototype.drawCachedTexture = function () { | |||
| */ | ||||
| 
 | ||||
| Morph.prototype.drawOn = function (aCanvas, aRect) { | ||||
|     var rectangle, area, delta, src, context, w, h, sl, st; | ||||
|     var rectangle, area, delta, src, context, w, h, sl, st, | ||||
|         pic = this.cachedFullImage || this.image, | ||||
|         bounds = this.cachedFullBounds || this.bounds; | ||||
|     if (!this.isVisible) { | ||||
|         return null; | ||||
|     } | ||||
|     rectangle = aRect || this.bounds(); | ||||
|     area = rectangle.intersect(this.bounds); | ||||
|     rectangle = aRect || bounds; | ||||
|     area = rectangle.intersect(bounds); | ||||
|     if (area.extent().gt(new Point(0, 0))) { | ||||
|         delta = this.position().neg(); | ||||
|         delta = bounds.position().neg(); | ||||
|         src = area.copy().translateBy(delta); | ||||
|         context = aCanvas.getContext('2d'); | ||||
|         context.globalAlpha = this.alpha; | ||||
| 
 | ||||
|         sl = src.left(); | ||||
|         st = src.top(); | ||||
|         w = Math.min(src.width(), this.image.width - sl); | ||||
|         h = Math.min(src.height(), this.image.height - st); | ||||
|         w = Math.min(src.width(), pic.width - sl); | ||||
|         h = Math.min(src.height(), pic.height - st); | ||||
| 
 | ||||
|         if (w < 1 || h < 1) { | ||||
|             return null; | ||||
|         } | ||||
| 
 | ||||
|         context.drawImage( | ||||
|             this.image, | ||||
|             pic, | ||||
|             sl, | ||||
|             st, | ||||
|             w, | ||||
|  | @ -2672,42 +2685,6 @@ Morph.prototype.drawOn = function (aCanvas, aRect) { | |||
|             w, | ||||
|             h | ||||
|         ); | ||||
| 
 | ||||
|     /* "for debugging purposes:" | ||||
| 
 | ||||
|         try { | ||||
|             context.drawImage( | ||||
|                 this.image, | ||||
|                 sl, | ||||
|                 st, | ||||
|                 w, | ||||
|                 h, | ||||
|                 area.left(), | ||||
|                 area.top(), | ||||
|                 w, | ||||
|                 h | ||||
|             ); | ||||
|         } catch (err) { | ||||
|             alert('internal error\n\n' + err | ||||
|                 + '\n ---' | ||||
|                 + '\n canvas: ' + aCanvas | ||||
|                 + '\n canvas.width: ' + aCanvas.width | ||||
|                 + '\n canvas.height: ' + aCanvas.height | ||||
|                 + '\n ---' | ||||
|                 + '\n image: ' + this.image | ||||
|                 + '\n image.width: ' + this.image.width | ||||
|                 + '\n image.height: ' + this.image.height | ||||
|                 + '\n ---' | ||||
|                 + '\n w: ' + w | ||||
|                 + '\n h: ' + h | ||||
|                 + '\n sl: ' + sl | ||||
|                 + '\n st: ' + st | ||||
|                 + '\n area.left: ' + area.left() | ||||
|                 + '\n area.top ' + area.top() | ||||
|                 ); | ||||
|         } | ||||
|     */ | ||||
| 
 | ||||
|     } | ||||
| }; | ||||
| 
 | ||||
|  | @ -2716,8 +2693,9 @@ Morph.prototype.fullDrawOn = function (aCanvas, aRect) { | |||
|     if (!this.isVisible) { | ||||
|         return null; | ||||
|     } | ||||
|     rectangle = aRect || this.fullBounds(); | ||||
|     rectangle = aRect || this.cachedFullBounds || this.fullBounds(); | ||||
|     this.drawOn(aCanvas, rectangle); | ||||
|     if (this.cachedFullImage) {return; } | ||||
|     this.children.forEach(function (child) { | ||||
|         child.fullDrawOn(aCanvas, rectangle); | ||||
|     }); | ||||
|  | @ -2911,7 +2889,9 @@ Morph.prototype.fullChanged = function () { | |||
|     if (this.trackChanges) { | ||||
|         var w = this.root(); | ||||
|         if (w instanceof WorldMorph) { | ||||
|             w.broken.push(this.fullBounds().spread()); | ||||
|             w.broken.push( | ||||
|                 (this.cachedFullBounds || this.fullBounds()).spread() | ||||
|             ); | ||||
|         } | ||||
|     } | ||||
| }; | ||||
|  | @ -9448,7 +9428,7 @@ function HandMorph(aWorld) { | |||
| // HandMorph initialization:
 | ||||
| 
 | ||||
| HandMorph.prototype.init = function (aWorld) { | ||||
|     HandMorph.uber.init.call(this); | ||||
|     HandMorph.uber.init.call(this, true); | ||||
|     this.bounds = new Rectangle(); | ||||
| 
 | ||||
|     // additional properties:
 | ||||
|  | @ -9456,6 +9436,7 @@ HandMorph.prototype.init = function (aWorld) { | |||
|     this.mouseButton = null; | ||||
|     this.mouseOverList = []; | ||||
|     this.morphToGrab = null; | ||||
|     this.grabPosition = null; | ||||
|     this.grabOrigin = null; | ||||
|     this.temporaries = []; | ||||
|     this.touchHoldTimeout = null; | ||||
|  | @ -9520,6 +9501,8 @@ HandMorph.prototype.grab = function (aMorph) { | |||
|         if (aMorph.prepareToBeGrabbed) { | ||||
|             aMorph.prepareToBeGrabbed(this); | ||||
|         } | ||||
|         aMorph.cachedFullImage = aMorph.fullImageClassic(); | ||||
|         aMorph.cachedFullBounds = aMorph.fullBounds(); | ||||
|         this.add(aMorph); | ||||
|         this.changed(); | ||||
|         if (oldParent && oldParent.reactToGrabOf) { | ||||
|  | @ -9535,6 +9518,8 @@ HandMorph.prototype.drop = function () { | |||
|         target = this.dropTargetFor(morphToDrop); | ||||
|         this.changed(); | ||||
|         target.add(morphToDrop); | ||||
|         morphToDrop.cachedFullImage = null; | ||||
|         morphToDrop.cachedFullBounds = null; | ||||
|         morphToDrop.changed(); | ||||
|         morphToDrop.removeShadow(); | ||||
|         this.children = []; | ||||
|  | @ -9545,7 +9530,6 @@ HandMorph.prototype.drop = function () { | |||
|         if (target.reactToDropOf) { | ||||
|             target.reactToDropOf(morphToDrop, this); | ||||
|         } | ||||
|         this.dragOrigin = null; | ||||
|     } | ||||
| }; | ||||
| 
 | ||||
|  | @ -9572,6 +9556,7 @@ HandMorph.prototype.processMouseDown = function (event) { | |||
|     this.destroyTemporaries(); | ||||
|     this.contextMenuEnabled = true; | ||||
|     this.morphToGrab = null; | ||||
|     this.grabPosition = null; | ||||
|     if (this.children.length !== 0) { | ||||
|         this.drop(); | ||||
|         this.mouseButton = null; | ||||
|  | @ -9599,6 +9584,7 @@ HandMorph.prototype.processMouseDown = function (event) { | |||
|         } | ||||
|         if (!morph.mouseMove) { | ||||
|             this.morphToGrab = morph.rootForGrab(); | ||||
|             this.grabPosition = this.bounds.origin.copy(); | ||||
|         } | ||||
|         if (event.button === 2 || event.ctrlKey) { | ||||
|             this.mouseButton = 'right'; | ||||
|  | @ -9708,8 +9694,7 @@ HandMorph.prototype.processMouseMove = function (event) { | |||
|         mouseOverNew, | ||||
|         myself = this, | ||||
|         morph, | ||||
|         topMorph, | ||||
|         fb; | ||||
|         topMorph; | ||||
| 
 | ||||
|     pos = new Point( | ||||
|         event.pageX - posInDocument.x, | ||||
|  | @ -9733,7 +9718,11 @@ HandMorph.prototype.processMouseMove = function (event) { | |||
|         } | ||||
| 
 | ||||
|         // if a morph is marked for grabbing, just grab it
 | ||||
|         if (this.mouseButton === 'left' && this.morphToGrab) { | ||||
|         if (this.mouseButton === 'left' && | ||||
|                 this.morphToGrab && | ||||
|                 (this.grabPosition.distanceTo(this.bounds.origin) > | ||||
|                     MorphicPreferences.grabThreshold)) { | ||||
|             this.setPosition(this.grabPosition); | ||||
|             if (this.morphToGrab.isDraggable) { | ||||
|                 morph = this.morphToGrab; | ||||
|                 this.grab(morph); | ||||
|  | @ -9747,16 +9736,7 @@ HandMorph.prototype.processMouseMove = function (event) { | |||
|                 this.grab(morph); | ||||
|                 this.grabOrigin = this.morphToGrab.situation(); | ||||
|             } | ||||
|             if (morph) { | ||||
|                 // if the mouse has left its fullBounds, allow to center it
 | ||||
|                 fb = morph.fullBounds(); | ||||
|                 if (!fb.containsPoint(pos) && | ||||
|                         morph.isCorrectingOutsideDrag()) { | ||||
|                     this.bounds.origin = fb.center(); | ||||
|                     this.grab(morph); | ||||
|                     this.setPosition(pos); | ||||
|                 } | ||||
|             } | ||||
|             this.setPosition(pos); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|  |  | |||
							
								
								
									
										23
									
								
								objects.js
								
								
								
								
							
							
						
						
									
										23
									
								
								objects.js
								
								
								
								
							|  | @ -125,7 +125,7 @@ PrototypeHatBlockMorph*/ | |||
| 
 | ||||
| // Global stuff ////////////////////////////////////////////////////////
 | ||||
| 
 | ||||
| modules.objects = '2015-October-07'; | ||||
| modules.objects = '2015-November-16'; | ||||
| 
 | ||||
| var SpriteMorph; | ||||
| var StageMorph; | ||||
|  | @ -1184,7 +1184,7 @@ SpriteMorph.prototype.initBlocks = function () { | |||
|             dev: true, | ||||
|             type: 'command', | ||||
|             category: 'lists', | ||||
|             spec: 'for %upvar in %l %cs', | ||||
|             spec: 'for %upvar in %l %cl', | ||||
|             defaults: [localize('each item')] | ||||
|         }, | ||||
| 
 | ||||
|  | @ -2326,7 +2326,7 @@ SpriteMorph.prototype.freshPalette = function (category) { | |||
|                 x = block.right() + unit / 2; | ||||
|                 ry = block.bottom(); | ||||
|             } else { | ||||
|                 if (block.fixLayout) {block.fixLayout(); } | ||||
|                 // if (block.fixLayout) {block.fixLayout(); }
 | ||||
|                 x = 0; | ||||
|                 y += block.height(); | ||||
|             } | ||||
|  | @ -3249,7 +3249,7 @@ SpriteMorph.prototype.bubble = function (data, isThought, isQuestion) { | |||
|     if (data === '' || isNil(data)) {return; } | ||||
|     bubble = new SpriteBubbleMorph( | ||||
|         data, | ||||
|         stage ? stage.scale : 1, | ||||
|         stage, | ||||
|         isThought, | ||||
|         isQuestion | ||||
|     ); | ||||
|  | @ -3539,6 +3539,7 @@ SpriteMorph.prototype.gotoXY = function (x, y, justMe) { | |||
|         newY, | ||||
|         dest; | ||||
| 
 | ||||
|     if (!stage) {return; } | ||||
|     newX = stage.center().x + (+x || 0) * stage.scale; | ||||
|     newY = stage.center().y - (+y || 0) * stage.scale; | ||||
|     if (this.costume) { | ||||
|  | @ -6054,18 +6055,19 @@ SpriteBubbleMorph.uber = SpeechBubbleMorph.prototype; | |||
| 
 | ||||
| // SpriteBubbleMorph instance creation:
 | ||||
| 
 | ||||
| function SpriteBubbleMorph(data, scale, isThought, isQuestion) { | ||||
|     this.init(data, scale, isThought, isQuestion); | ||||
| function SpriteBubbleMorph(data, stage, isThought, isQuestion) { | ||||
|     this.init(data, stage, isThought, isQuestion); | ||||
| } | ||||
| 
 | ||||
| SpriteBubbleMorph.prototype.init = function ( | ||||
|     data, | ||||
|     scale, | ||||
|     stage, | ||||
|     isThought, | ||||
|     isQuestion | ||||
| ) { | ||||
|     var sprite = SpriteMorph.prototype; | ||||
|     this.scale = scale || 1; | ||||
|     this.stage = stage; | ||||
|     this.scale = stage ? stage.scale : 1; | ||||
|     this.data = data; | ||||
|     this.isQuestion = isQuestion; | ||||
| 
 | ||||
|  | @ -6125,6 +6127,11 @@ SpriteBubbleMorph.prototype.dataAsMorph = function (data) { | |||
|         contents.isDraggable = false; | ||||
|         contents.update(true); | ||||
|         contents.step = contents.update; | ||||
|         if (this.stage) { | ||||
|             contents.expand(this.stage.extent().translateBy( | ||||
|                 -2 * (this.edge + this.border + this.padding) | ||||
|             )); | ||||
|         } | ||||
|     } else if (data instanceof Context) { | ||||
|         img = data.image(); | ||||
|         contents = new Morph(); | ||||
|  |  | |||
|  | @ -0,0 +1,38 @@ | |||
| <!DOCTYPE html> | ||||
| <html> | ||||
| 	<head> | ||||
| 		<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> | ||||
| 		<title>Snap! Build Your Own Blocks</title> | ||||
| 		<link rel="shortcut icon" href="favicon.ico"> | ||||
| 		<script type="text/javascript" src="morphic.js"></script> | ||||
| 		<script type="text/javascript" src="widgets.js"></script> | ||||
| 		<script type="text/javascript" src="blocks.js"></script> | ||||
| 		<script type="text/javascript" src="threads.js"></script> | ||||
| 		<script type="text/javascript" src="objects.js"></script> | ||||
| 		<script type="text/javascript" src="gui.js"></script> | ||||
| 		<script type="text/javascript" src="paint.js"></script> | ||||
| 		<script type="text/javascript" src="lists.js"></script> | ||||
| 		<script type="text/javascript" src="byob.js"></script> | ||||
| 		<script type="text/javascript" src="xml.js"></script> | ||||
| 		<script type="text/javascript" src="store.js"></script> | ||||
| 		<script type="text/javascript" src="locale.js"></script> | ||||
| 		<script type="text/javascript" src="cloud.js"></script> | ||||
| 		<script type="text/javascript" src="sha512.js"></script> | ||||
| 		<script type="text/javascript"> | ||||
| 			var world; | ||||
| 			window.onload = function () { | ||||
| 				world = new WorldMorph(document.getElementById('world')); | ||||
|                 world.worldCanvas.focus(); | ||||
| 				new IDE_Morph().openIn(world); | ||||
|         loop(); | ||||
| 			}; | ||||
| 			function loop() { | ||||
|         requestAnimationFrame(loop); | ||||
| 				world.doOneCycle(); | ||||
| 			} | ||||
| 		</script> | ||||
| 	</head> | ||||
| 	<body style="margin: 0;"> | ||||
| 		<canvas id="world" tabindex="1" style="position: absolute;" /> | ||||
| 	</body> | ||||
| </html> | ||||
							
								
								
									
										25
									
								
								threads.js
								
								
								
								
							
							
						
						
									
										25
									
								
								threads.js
								
								
								
								
							|  | @ -83,7 +83,7 @@ ArgLabelMorph, localize, XML_Element, hex_sha512*/ | |||
| 
 | ||||
| // Global stuff ////////////////////////////////////////////////////////
 | ||||
| 
 | ||||
| modules.threads = '2015-October-02'; | ||||
| modules.threads = '2015-November-16'; | ||||
| 
 | ||||
| var ThreadManager; | ||||
| var Process; | ||||
|  | @ -128,6 +128,26 @@ function snapEquals(a, b) { | |||
|     return x === y; | ||||
| } | ||||
| 
 | ||||
| function invoke(block, timeout) { | ||||
|     // exectue the given block synchronously, i.e. without yielding.
 | ||||
|     // if a timeout (in milliseconds) is specified, abort execution
 | ||||
|     // after the timeout has been reached and throw an error.
 | ||||
|     // For debugging purposes only.
 | ||||
|     // Caution: Kids, do not try this at home!
 | ||||
|     // use ThreadManager::startProcess instead
 | ||||
|     var proc = new Process(block), | ||||
|         startTime = Date.now(); | ||||
|     while (proc.isRunning()) { | ||||
|         if (timeout && ((Date.now() - startTime) > timeout)) { | ||||
|             throw (new Error("a synchronous Snap! script has timed out")); | ||||
|         } | ||||
|         proc.runStep(); | ||||
|     } | ||||
|     if (block instanceof ReporterBlockMorph) { | ||||
|         return proc.homeContext.inputs[0]; | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| // ThreadManager ///////////////////////////////////////////////////////
 | ||||
| 
 | ||||
| function ThreadManager() { | ||||
|  | @ -638,7 +658,8 @@ Process.prototype.evaluateInput = function (input) { | |||
|             if (contains( | ||||
|                     [CommandSlotMorph, ReporterSlotMorph], | ||||
|                     input.constructor | ||||
|                 ) || (input instanceof CSlotMorph && !input.isStatic)) { | ||||
|                 ) || (input instanceof CSlotMorph && | ||||
|                         (!input.isStatic || input.isLambda))) { | ||||
|                 // I know, this still needs yet to be done right....
 | ||||
|                 ans = this.reify(ans, new List()); | ||||
|             } | ||||
|  |  | |||
		Ładowanie…
	
		Reference in New Issue
	
	 Jens Mönig
						Jens Mönig