diff options
Diffstat (limited to 'objects.js')
| -rw-r--r-- | objects.js | 198 |
1 files changed, 162 insertions, 36 deletions
@@ -9,7 +9,7 @@ written by Jens Mönig jens@moenig.org - Copyright (C) 2014 by Jens Mönig + Copyright (C) 2015 by Jens Mönig This file is part of Snap!. @@ -105,7 +105,7 @@ InspectorMorph, ListMorph, Math, MenuItemMorph, MenuMorph, Morph, MorphicPreferences, MouseSensorMorph, Node, Object, PenMorph, Point, Rectangle, ScrollFrameMorph, ShadowMorph, SliderButtonMorph, SliderMorph, String, StringFieldMorph, StringMorph, TextMorph, -TriggerMorph, WorldMorph, clone, contains, copy, degrees, detect, +TriggerMorph, WorldMorph, contains, copy, degrees, detect, document, getDocumentPositionOf, isNaN, isObject, isString, newCanvas, nop, parseFloat, radians, standardSettings, touchScreenSettings, useBlurredShadows, version, window, modules, IDE_Morph, VariableDialogMorph, @@ -125,7 +125,7 @@ PrototypeHatBlockMorph*/ // Global stuff //////////////////////////////////////////////////////// -modules.objects = '2014-November-24'; +modules.objects = '2015-June-25'; var SpriteMorph; var StageMorph; @@ -581,11 +581,22 @@ SpriteMorph.prototype.initBlocks = function () { category: 'control', spec: 'when %keyHat key pressed' }, + + /* migrated to a newer block version: + receiveClick: { type: 'hat', category: 'control', spec: 'when I am clicked' }, + */ + + receiveInteraction: { + type: 'hat', + category: 'control', + spec: 'when I am %interaction', + defaults: ['clicked'] + }, receiveMessage: { type: 'hat', category: 'control', @@ -793,6 +804,12 @@ SpriteMorph.prototype.initBlocks = function () { category: 'sensing', spec: 'frames' }, + reportThreadCount: { + dev: true, + type: 'reporter', + category: 'sensing', + spec: 'processes' + }, doAsk: { type: 'command', category: 'sensing', @@ -1151,6 +1168,13 @@ SpriteMorph.prototype.initBlocks = function () { category: 'lists', spec: 'map %repRing over %l' }, + doForEach: { + dev: true, + type: 'command', + category: 'lists', + spec: 'for %upvar in %l %cs', + defaults: [localize('each item')] + }, // Code mapping - experimental doMapCodeOrHeader: { // experimental @@ -1192,6 +1216,10 @@ SpriteMorph.prototype.initBlockMigrations = function () { doStopBlock: { selector: 'doStopThis', inputs: [['this block']] + }, + receiveClick: { + selector: 'receiveInteraction', + inputs: [['clicked']] } }; }; @@ -1240,8 +1268,6 @@ SpriteMorph.prototype.blockAlternatives = { setSize: ['changeSize'], // control: - receiveGo: ['receiveClick'], - receiveClick: ['receiveGo'], doBroadcast: ['doBroadcastAndWait'], doBroadcastAndWait: ['doBroadcast'], doIf: ['doIfElse', 'doUntil'], @@ -1302,6 +1328,7 @@ SpriteMorph.prototype.init = function (globals) { this.anchor = null; this.nestingScale = 1; this.rotatesWithAnchor = true; + this.layers = null; // cache for dragging nested sprites, don't serialize this.blocksCache = {}; // not to be serialized (!) this.paletteCache = {}; // not to be serialized (!) @@ -1406,15 +1433,13 @@ SpriteMorph.prototype.setName = function (string) { SpriteMorph.prototype.drawNew = function () { var myself = this, - currentCenter = this.center(), + currentCenter, facing, // actual costume heading based on my rotation style isFlipped, - isLoadingCostume = this.costume && - typeof this.costume.loaded === 'function', + isLoadingCostume, cst, pic, // (flipped copy of) actual costume based on my rotation style - stageScale = this.parent instanceof StageMorph ? - this.parent.scale : 1, + stageScale, newX, corners = [], origin, @@ -1428,6 +1453,11 @@ SpriteMorph.prototype.drawNew = function () { this.wantsRedraw = true; return; } + currentCenter = this.center(); + isLoadingCostume = this.costume && + typeof this.costume.loaded === 'function'; + stageScale = this.parent instanceof StageMorph ? + this.parent.scale : 1; facing = this.rotationStyle ? this.heading : 90; if (this.rotationStyle === 2) { facing = 90; @@ -1575,7 +1605,7 @@ SpriteMorph.prototype.blockForSelector = function (selector, setDefaults) { : new ReporterBlockMorph(info.type === 'predicate'); block.color = this.blockColor[info.category]; block.category = info.category; - block.selector = selector; + block.selector = migration ? migration.selector : selector; if (contains(['reifyReporter', 'reifyPredicate'], block.selector)) { block.isStatic = true; } @@ -1815,7 +1845,7 @@ SpriteMorph.prototype.blockTemplates = function (category) { blocks.push(block('receiveGo')); blocks.push(block('receiveKey')); - blocks.push(block('receiveClick')); + blocks.push(block('receiveInteraction')); blocks.push(block('receiveMessage')); blocks.push('-'); blocks.push(block('doBroadcast')); @@ -1911,6 +1941,8 @@ SpriteMorph.prototype.blockTemplates = function (category) { txt.setColor(this.paletteTextColor); blocks.push(txt); blocks.push('-'); + blocks.push(watcherToggle('reportThreadCount')); + blocks.push(block('reportThreadCount')); blocks.push(block('colorFiltered')); blocks.push(block('reportStackSize')); blocks.push(block('reportFrameCount')); @@ -2063,6 +2095,8 @@ SpriteMorph.prototype.blockTemplates = function (category) { blocks.push(txt); blocks.push('-'); blocks.push(block('reportMap')); + blocks.push('-'); + blocks.push(block('doForEach')); } ///////////////////////////////// @@ -2625,7 +2659,9 @@ SpriteMorph.prototype.userMenu = function () { menu.addItem("duplicate", 'duplicate'); menu.addItem("delete", 'remove'); menu.addItem("move", 'move'); - menu.addItem("edit", 'edit'); + if (!this.isClone) { + menu.addItem("edit", 'edit'); + } menu.addLine(); if (this.anchor) { menu.addItem( @@ -2641,6 +2677,7 @@ SpriteMorph.prototype.userMenu = function () { }; SpriteMorph.prototype.exportSprite = function () { + if (this.isClone) {return; } var ide = this.parentThatIsA(IDE_Morph); if (ide) { ide.exportSprite(this); @@ -2681,7 +2718,7 @@ SpriteMorph.prototype.remove = function () { SpriteMorph.prototype.createClone = function () { var stage = this.parentThatIsA(StageMorph); - if (stage && stage.cloneCount <= 300) { + if (stage && stage.cloneCount <= 1000) { this.fullCopy().clonify(stage); } }; @@ -2737,7 +2774,7 @@ SpriteMorph.prototype.setColor = function (aColor) { var x = this.xPosition(), y = this.yPosition(); if (!this.color.eq(aColor)) { - this.color = aColor; + this.color = aColor.copy(); this.drawNew(); this.gotoXY(x, y); } @@ -2971,7 +3008,7 @@ SpriteMorph.prototype.applyGraphicsEffects = function (canvas) { var i; if (value !== 0) { for (i = 0; i < p.length; i += 4) { - p[i] += value; //255 = 100% of this color + p[i] += value; //255 = 100% of this color p[i + 1] += value; p[i + 2] += value; } @@ -3044,7 +3081,7 @@ SpriteMorph.prototype.setEffect = function (effect, value) { if (eff === 'ghost') { this.alpha = 1 - Math.min(Math.max(+value || 0, 0), 100) / 100; } else { - this.graphicsValues[eff] = value; + this.graphicsValues[eff] = +value; } this.drawNew(); this.changed(); @@ -3059,7 +3096,7 @@ SpriteMorph.prototype.changeEffect = function (effect, value) { if (eff === 'ghost') { this.setEffect(effect, this.getGhostEffect() + (+value || 0)); } else { - this.setEffect(effect, this.graphicsValues[eff] + value); + this.setEffect(effect, +this.graphicsValues[eff] + (+value)); } }; @@ -3134,13 +3171,11 @@ SpriteMorph.prototype.positionTalkBubble = function () { bubble.changed(); }; -// dragging and dropping adjustments b/c of talk bubbles +// dragging and dropping adjustments b/c of talk bubbles and parts SpriteMorph.prototype.prepareToBeGrabbed = function (hand) { - var bubble = this.talkBubble(); - if (!bubble) {return null; } this.removeShadow(); - bubble.hide(); + this.recordLayers(); if (!this.bounds.containsPoint(hand.position())) { this.setCenter(hand.position()); } @@ -3148,7 +3183,9 @@ SpriteMorph.prototype.prepareToBeGrabbed = function (hand) { }; SpriteMorph.prototype.justDropped = function () { + this.restoreLayers(); this.positionTalkBubble(); + this.receiveUserInteraction('dropped'); }; // SpriteMorph drawing: @@ -3238,8 +3275,11 @@ SpriteMorph.prototype.setCenter = function (aPoint, justMe) { SpriteMorph.prototype.nestingBounds = function () { // same as fullBounds(), except that it uses "parts" instead of children - var result; - result = this.bounds; + // and special cases the costume-less "arrow" shape's bounding box + var result = this.bounds; + if (!this.costume && this.penBounds) { + result = this.penBounds.translateBy(this.position()); + } this.parts.forEach(function (part) { if (part.isVisible) { result = result.merge(part.nestingBounds()); @@ -3250,7 +3290,7 @@ SpriteMorph.prototype.nestingBounds = function () { // SpriteMorph motion primitives -Morph.prototype.setPosition = function (aPoint, justMe) { +SpriteMorph.prototype.setPosition = function (aPoint, justMe) { // override the inherited default to make sure my parts follow // unless it's justMe var delta = aPoint.subtract(this.topLeft()); @@ -3469,7 +3509,10 @@ SpriteMorph.prototype.allHatBlocksFor = function (message) { if (morph.selector) { if (morph.selector === 'receiveMessage') { event = morph.inputs()[0].evaluate(); - return event === message || (event instanceof Array); + return event === message + || (event instanceof Array + && message !== '__shout__go__' + && message !== '__clone__init__'); } if (morph.selector === 'receiveGo') { return message === '__shout__go__'; @@ -3477,9 +3520,6 @@ SpriteMorph.prototype.allHatBlocksFor = function (message) { if (morph.selector === 'receiveOnClone') { return message === '__clone__init__'; } - if (morph.selector === 'receiveClick') { - return message === '__click__'; - } } return false; }); @@ -3496,13 +3536,37 @@ SpriteMorph.prototype.allHatBlocksForKey = function (key) { }); }; +SpriteMorph.prototype.allHatBlocksForInteraction = function (interaction) { + return this.scripts.children.filter(function (morph) { + if (morph.selector) { + if (morph.selector === 'receiveInteraction') { + return morph.inputs()[0].evaluate()[0] === interaction; + } + } + return false; + }); +}; + // SpriteMorph events SpriteMorph.prototype.mouseClickLeft = function () { - var stage = this.parentThatIsA(StageMorph), - hats = this.allHatBlocksFor('__click__'), - procs = []; + return this.receiveUserInteraction('clicked'); +}; + +SpriteMorph.prototype.mouseEnter = function () { + return this.receiveUserInteraction('mouse-entered'); +}; + +SpriteMorph.prototype.mouseDownLeft = function () { + return this.receiveUserInteraction('pressed'); +}; +SpriteMorph.prototype.receiveUserInteraction = function (interaction) { + var stage = this.parentThatIsA(StageMorph), + procs = [], + hats; + if (!stage) {return; } // currently dragged + hats = this.allHatBlocksForInteraction(interaction); hats.forEach(function (block) { procs.push(stage.threads.startProcess(block, stage.isThreadSafe)); }); @@ -3510,6 +3574,7 @@ SpriteMorph.prototype.mouseClickLeft = function () { }; SpriteMorph.prototype.mouseDoubleClick = function () { + if (this.isClone) {return; } this.edit(); }; @@ -3567,6 +3632,16 @@ SpriteMorph.prototype.reportMouseY = function () { return 0; }; +// SpriteMorph thread count (for debugging) + +SpriteMorph.prototype.reportThreadCount = function () { + var stage = this.parentThatIsA(StageMorph); + if (stage) { + return stage.threads.processes.length; + } + return 0; +}; + // SpriteMorph variable watchers (for palette checkbox toggling) SpriteMorph.prototype.findVariableWatcher = function (varName) { @@ -4011,6 +4086,33 @@ SpriteMorph.prototype.allAnchors = function () { return result; }; +SpriteMorph.prototype.recordLayers = function () { + var stage = this.parentThatIsA(StageMorph); + if (!stage) { + this.layerCache = null; + return; + } + this.layers = this.allParts(); + this.layers.forEach(function (part) { + var bubble = part.talkBubble(); + if (bubble) {bubble.hide(); } + }); + this.layers.sort(function (x, y) { + return stage.children.indexOf(x) < stage.children.indexOf(y) ? + -1 : 1; + }); +}; + +SpriteMorph.prototype.restoreLayers = function () { + if (this.layers && this.layers.length > 1) { + this.layers.forEach(function (sprite) { + sprite.comeToFront(); + sprite.positionTalkBubble(); + }); + } + this.layers = null; +}; + // SpriteMorph highlighting SpriteMorph.prototype.addHighlight = function (oldHighlight) { @@ -4129,6 +4231,7 @@ SpriteMorph.prototype.mouseEnterDragging = function () { }; SpriteMorph.prototype.mouseLeave = function () { + this.receiveUserInteraction('mouse-departed'); if (!this.enableNesting) {return; } this.removeHighlight(); }; @@ -4959,7 +5062,7 @@ StageMorph.prototype.blockTemplates = function (category) { blocks.push(block('receiveGo')); blocks.push(block('receiveKey')); - blocks.push(block('receiveClick')); + blocks.push(block('receiveInteraction')); blocks.push(block('receiveMessage')); blocks.push('-'); blocks.push(block('doBroadcast')); @@ -5047,6 +5150,8 @@ StageMorph.prototype.blockTemplates = function (category) { txt.setColor(this.paletteTextColor); blocks.push(txt); blocks.push('-'); + blocks.push(watcherToggle('reportThreadCount')); + blocks.push(block('reportThreadCount')); blocks.push(block('colorFiltered')); blocks.push(block('reportStackSize')); blocks.push(block('reportFrameCount')); @@ -5195,6 +5300,8 @@ StageMorph.prototype.blockTemplates = function (category) { blocks.push(txt); blocks.push('-'); blocks.push(block('reportMap')); + blocks.push('-'); + blocks.push(block('doForEach')); } ///////////////////////////////// @@ -5333,7 +5440,7 @@ StageMorph.prototype.thumbnail = function (extentPoint, excludedSprite) { this.dimensions.y * this.scale ); this.children.forEach(function (morph) { - if (morph !== excludedSprite) { + if (morph.isVisible && (morph !== excludedSprite)) { fb = morph.fullBounds(); fimg = morph.fullImage(); if (fimg.width && fimg.height) { @@ -5495,6 +5602,9 @@ StageMorph.prototype.watcherFor = StageMorph.prototype.getLastAnswer = SpriteMorph.prototype.getLastAnswer; +StageMorph.prototype.reportThreadCount + = SpriteMorph.prototype.reportThreadCount; + // StageMorph message broadcasting StageMorph.prototype.allMessageNames @@ -5506,11 +5616,27 @@ StageMorph.prototype.allHatBlocksFor StageMorph.prototype.allHatBlocksForKey = SpriteMorph.prototype.allHatBlocksForKey; +StageMorph.prototype.allHatBlocksForInteraction + = SpriteMorph.prototype.allHatBlocksForInteraction; + // StageMorph events StageMorph.prototype.mouseClickLeft = SpriteMorph.prototype.mouseClickLeft; +StageMorph.prototype.mouseEnter + = SpriteMorph.prototype.mouseEnter; + +StageMorph.prototype.mouseLeave = function () { + this.receiveUserInteraction('mouse-departed'); +}; + +StageMorph.prototype.mouseDownLeft + = SpriteMorph.prototype.mouseDownLeft; + +StageMorph.prototype.receiveUserInteraction + = SpriteMorph.prototype.receiveUserInteraction; + // StageMorph custom blocks StageMorph.prototype.deleteAllBlockInstances @@ -6306,7 +6432,7 @@ Note.prototype.play = function () { if (!this.oscillator.stop) { this.oscillator.stop = this.oscillator.noteOff; } - this.oscillator.type = 0; + this.oscillator.type = 'sine'; this.oscillator.frequency.value = Math.pow(2, (this.pitch - 69) / 12) * 440; this.oscillator.connect(this.gainNode); @@ -6743,7 +6869,7 @@ WatcherMorph.prototype.object = function () { WatcherMorph.prototype.isGlobal = function (selector) { return contains( ['getLastAnswer', 'getLastMessage', 'getTempo', 'getTimer', - 'reportMouseX', 'reportMouseY'], + 'reportMouseX', 'reportMouseY', 'reportThreadCount'], selector ); }; |
