Merge branch 'manual-chapter2' into manual-chapter3

dev
Bartosz Leper 2015-08-02 20:15:47 +02:00
commit c04698ea26
21 zmienionych plików z 5170 dodań i 291 usunięć

969
blocks.js

Plik diff jest za duży Load Diff

17
byob.js
Wyświetl plik

@ -102,11 +102,11 @@ ArrowMorph, PushButtonMorph, contains, InputSlotMorph, ShadowMorph,
ToggleButtonMorph, IDE_Morph, MenuMorph, copy, ToggleElementMorph, ToggleButtonMorph, IDE_Morph, MenuMorph, copy, ToggleElementMorph,
Morph, fontHeight, StageMorph, SyntaxElementMorph, SnapSerializer, Morph, fontHeight, StageMorph, SyntaxElementMorph, SnapSerializer,
CommentMorph, localize, CSlotMorph, SpeechBubbleMorph, MorphicPreferences, CommentMorph, localize, CSlotMorph, SpeechBubbleMorph, MorphicPreferences,
SymbolMorph, isNil*/ SymbolMorph, isNil, CursorMorph*/
// Global stuff //////////////////////////////////////////////////////// // Global stuff ////////////////////////////////////////////////////////
modules.byob = '2015-June-25'; modules.byob = '2015-July-28';
// Declarations // Declarations
@ -1727,8 +1727,9 @@ BlockEditorMorph.prototype.popUp = function () {
// BlockEditorMorph ops // BlockEditorMorph ops
BlockEditorMorph.prototype.accept = function () { BlockEditorMorph.prototype.accept = function (origin) {
// check DialogBoxMorph comment for accept() // check DialogBoxMorph comment for accept()
if (origin instanceof CursorMorph) {return; }
if (this.action) { if (this.action) {
if (typeof this.target === 'function') { if (typeof this.target === 'function') {
if (typeof this.action === 'function') { if (typeof this.action === 'function') {
@ -1747,7 +1748,8 @@ BlockEditorMorph.prototype.accept = function () {
this.close(); this.close();
}; };
BlockEditorMorph.prototype.cancel = function () { BlockEditorMorph.prototype.cancel = function (origin) {
if (origin instanceof CursorMorph) {return; }
//this.refreshAllBlockInstances(); //this.refreshAllBlockInstances();
this.close(); this.close();
}; };
@ -1966,8 +1968,13 @@ PrototypeHatBlockMorph.prototype.init = function (definition) {
PrototypeHatBlockMorph.prototype.mouseClickLeft = function () { PrototypeHatBlockMorph.prototype.mouseClickLeft = function () {
// relay the mouse click to my prototype block to // relay the mouse click to my prototype block to
// pop-up a Block Dialog // pop-up a Block Dialog, unless the shift key
// is pressed, in which case initiate keyboard
// editing support
if (this.world().currentKey === 16) { // shift-clicked
return this.focus();
}
this.children[0].mouseClickLeft(); this.children[0].mouseClickLeft();
}; };

349
gui.js
Wyświetl plik

@ -43,6 +43,7 @@
TurtleIconMorph TurtleIconMorph
CostumeIconMorph CostumeIconMorph
WardrobeMorph WardrobeMorph
StageHandleMorph;
credits credits
@ -65,11 +66,11 @@ ScriptsMorph, isNil, SymbolMorph, BlockExportDialogMorph,
BlockImportDialogMorph, SnapTranslator, localize, List, InputSlotMorph, BlockImportDialogMorph, SnapTranslator, localize, List, InputSlotMorph,
SnapCloud, Uint8Array, HandleMorph, SVG_Costume, fontHeight, hex_sha512, SnapCloud, Uint8Array, HandleMorph, SVG_Costume, fontHeight, hex_sha512,
sb, CommentMorph, CommandBlockMorph, BlockLabelPlaceHolderMorph, Audio, sb, CommentMorph, CommandBlockMorph, BlockLabelPlaceHolderMorph, Audio,
SpeechBubbleMorph*/ SpeechBubbleMorph, ScriptFocusMorph*/
// Global stuff //////////////////////////////////////////////////////// // Global stuff ////////////////////////////////////////////////////////
modules.gui = '2015-June-25'; modules.gui = '2015-July-28';
// Declarations // Declarations
@ -81,11 +82,18 @@ var TurtleIconMorph;
var WardrobeMorph; var WardrobeMorph;
var SoundIconMorph; var SoundIconMorph;
var JukeboxMorph; var JukeboxMorph;
var StageHandleMorph;
// Get the full url without "snap.html" // Get the full url without "snap.html"
var baseUrl = document.URL.split('/'); var baseURL = (function getPath(location) {
baseUrl.pop(baseUrl.length - 1); var origin, path, slash;
baseUrl = baseUrl.join('/') + '/'; path = location.pathname; // starts with a /
origin = location.origin; // has no trailing /
slash = path.lastIndexOf('/');
path = path.slice(0, slash + 1); // keep a trailing /
return origin + path;
}(window.location));
// IDE_Morph /////////////////////////////////////////////////////////// // IDE_Morph ///////////////////////////////////////////////////////////
@ -230,6 +238,7 @@ IDE_Morph.prototype.init = function (isAutoFill) {
this.spriteBar = null; this.spriteBar = null;
this.spriteEditor = null; this.spriteEditor = null;
this.stage = null; this.stage = null;
this.stageHandle = null;
this.corralBar = null; this.corralBar = null;
this.corral = null; this.corral = null;
@ -975,9 +984,7 @@ IDE_Morph.prototype.createPalette = function (forSearching) {
IDE_Morph.prototype.createStage = function () { IDE_Morph.prototype.createStage = function () {
// assumes that the logo pane has already been created // assumes that the logo pane has already been created
if (this.stage) { if (this.stage) {this.stage.destroy(); }
this.stage.destroy();
}
StageMorph.prototype.frameRate = 0; StageMorph.prototype.frameRate = 0;
this.stage = new StageMorph(this.globalVariables); this.stage = new StageMorph(this.globalVariables);
this.stage.setExtent(this.stage.dimensions); // dimensions are fixed this.stage.setExtent(this.stage.dimensions); // dimensions are fixed
@ -992,6 +999,13 @@ IDE_Morph.prototype.createStage = function () {
this.add(this.stage); this.add(this.stage);
}; };
IDE_Morph.prototype.createStageHandle = function () {
// assumes that the stage has already been created
if (this.stageHandle) {this.stageHandle.destroy(); }
this.stageHandle = new StageHandleMorph(this.stage);
this.add(this.stageHandle);
};
IDE_Morph.prototype.createSpriteBar = function () { IDE_Morph.prototype.createSpriteBar = function () {
// assumes that the categories pane has already been created // assumes that the categories pane has already been created
var rotationStyleButtons = [], var rotationStyleButtons = [],
@ -1355,6 +1369,7 @@ IDE_Morph.prototype.createCorral = function () {
// assumes the corral bar has already been created // assumes the corral bar has already been created
var frame, template, padding = 5, myself = this; var frame, template, padding = 5, myself = this;
this.createStageHandle();
if (this.corral) { if (this.corral) {
this.corral.destroy(); this.corral.destroy();
} }
@ -1486,10 +1501,10 @@ IDE_Morph.prototype.fixLayout = function (situation) {
) * 10) / 10); ) * 10) / 10);
this.stage.setCenter(this.center()); this.stage.setCenter(this.center());
} else { } else {
// this.stage.setScale(this.isSmallStage ? 0.5 : 1);
this.stage.setScale(this.isSmallStage ? this.stageRatio : 1); this.stage.setScale(this.isSmallStage ? this.stageRatio : 1);
this.stage.setTop(this.logo.bottom() + padding); this.stage.setTop(this.logo.bottom() + padding);
this.stage.setRight(this.right()); this.stage.setRight(this.right());
this.stageHandle.fixLayout();
} }
// spriteBar // spriteBar
@ -1538,7 +1553,12 @@ IDE_Morph.prototype.setProjectName = function (string) {
IDE_Morph.prototype.setExtent = function (point) { IDE_Morph.prototype.setExtent = function (point) {
var padding = new Point(430, 110), var padding = new Point(430, 110),
minExt, minExt,
ext; ext,
maxWidth,
minWidth,
maxHeight,
minRatio,
maxRatio;
// determine the minimum dimensions making sense for the current mode // determine the minimum dimensions making sense for the current mode
if (this.isAppMode) { if (this.isAppMode) {
@ -1546,21 +1566,29 @@ IDE_Morph.prototype.setExtent = function (point) {
this.controlBar.height() + 10 this.controlBar.height() + 10
); );
} else { } else {
/* // auto-switches to small stage mode, commented out b/c I don't like it if (this.stageRatio > 1) {
if (point.x < 910) { minExt = padding.add(StageMorph.prototype.dimensions);
this.isSmallStage = true; } else {
this.stageRatio = 0.5; minExt = padding.add(
StageMorph.prototype.dimensions.multiplyBy(this.stageRatio)
);
} }
*/
minExt = this.isSmallStage ?
padding.add(StageMorph.prototype.dimensions.divideBy(2))
: padding.add(StageMorph.prototype.dimensions);
/*
minExt = this.isSmallStage ?
new Point(700, 350) : new Point(910, 490);
*/
} }
ext = point.max(minExt); ext = point.max(minExt);
// adjust stage ratio if necessary
maxWidth = ext.x - (this.spriteBar.tabBar.fullBounds().right() -
this.left());
minWidth = SpriteIconMorph.prototype.thumbSize.x * 3;
maxHeight = (ext.y - SpriteIconMorph.prototype.thumbSize.y * 3.5);
minRatio = minWidth / this.stage.dimensions.x;
maxRatio = Math.min(
(maxWidth / this.stage.dimensions.x),
(maxHeight / this.stage.dimensions.y)
);
this.stageRatio = Math.min(maxRatio, Math.max(minRatio, this.stageRatio));
// apply
IDE_Morph.uber.setExtent.call(this, ext); IDE_Morph.uber.setExtent.call(this, ext);
this.fixLayout(); this.fixLayout();
}; };
@ -1746,6 +1774,9 @@ IDE_Morph.prototype.stopAllScripts = function () {
}; };
IDE_Morph.prototype.selectSprite = function (sprite) { IDE_Morph.prototype.selectSprite = function (sprite) {
if (this.currentSprite && this.currentSprite.scripts.focus) {
this.currentSprite.scripts.focus.stopEditing();
}
this.currentSprite = sprite; this.currentSprite = sprite;
this.createPalette(); this.createPalette();
this.createSpriteBar(); this.createSpriteBar();
@ -1800,7 +1831,8 @@ IDE_Morph.prototype.applySavedSettings = function () {
click = this.getSetting('click'), click = this.getSetting('click'),
longform = this.getSetting('longform'), longform = this.getSetting('longform'),
longurls = this.getSetting('longurls'), longurls = this.getSetting('longurls'),
plainprototype = this.getSetting('plainprototype'); plainprototype = this.getSetting('plainprototype'),
keyboard = this.getSetting('keyboard');
// design // design
if (design === 'flat') { if (design === 'flat') {
@ -1840,6 +1872,13 @@ IDE_Morph.prototype.applySavedSettings = function () {
this.projectsInURLs = false; this.projectsInURLs = false;
} }
// keyboard editing
if (keyboard) {
ScriptsMorph.prototype.enableKeyboard = true;
} else {
ScriptsMorph.prototype.enableKeyboard = false;
}
// plain prototype labels // plain prototype labels
if (plainprototype) { if (plainprototype) {
BlockLabelPlaceHolderMorph.prototype.plainLabel = true; BlockLabelPlaceHolderMorph.prototype.plainLabel = true;
@ -2346,6 +2385,22 @@ IDE_Morph.prototype.settingsMenu = function () {
'check to enable\nsprite composition', 'check to enable\nsprite composition',
true true
); );
addPreference(
'Keyboard Editing',
function () {
ScriptsMorph.prototype.enableKeyboard =
!ScriptsMorph.prototype.enableKeyboard;
if (ScriptsMorph.prototype.enableKeyboard) {
myself.saveSetting('keyboard', true);
} else {
myself.removeSetting('keyboard');
}
},
ScriptsMorph.prototype.enableKeyboard,
'uncheck to disable\nkeyboard editing support',
'check to enable\nkeyboard editing support',
false
);
menu.addLine(); // everything below this line is stored in the project menu.addLine(); // everything below this line is stored in the project
addPreference( addPreference(
'Thread safe scripts', 'Thread safe scripts',
@ -2385,6 +2440,20 @@ IDE_Morph.prototype.settingsMenu = function () {
'check for block\nto text mapping features', 'check for block\nto text mapping features',
false false
); );
addPreference(
'Inheritance support',
function () {
StageMorph.prototype.enableInheritance =
!StageMorph.prototype.enableInheritance;
myself.currentSprite.blocksCache.variables = null;
myself.currentSprite.paletteCache.variables = null;
myself.refreshPalette();
},
StageMorph.prototype.enableInheritance,
'uncheck to disable\nsprite inheritance features',
'check for sprite\ninheritance features',
false
);
menu.popup(world, pos); menu.popup(world, pos);
}; };
@ -2497,10 +2566,10 @@ IDE_Morph.prototype.projectMenu = function () {
function () { function () {
// read a list of libraries from an external file, // read a list of libraries from an external file,
var libMenu = new MenuMorph(this, 'Import library'), var libMenu = new MenuMorph(this, 'Import library'),
libUrl = baseUrl + 'libraries/' + 'LIBRARIES'; libUrl = baseURL + 'libraries/' + 'LIBRARIES';
function loadLib(name) { function loadLib(name) {
var url = baseUrl + 'libraries/' + name + '.xml'; var url = baseURL + 'libraries/' + name + '.xml';
myself.droppedText(myself.getURL(url), name); myself.droppedText(myself.getURL(url), name);
} }
@ -2617,7 +2686,7 @@ IDE_Morph.prototype.aboutSnap = function () {
module, btn1, btn2, btn3, btn4, licenseBtn, translatorsBtn, module, btn1, btn2, btn3, btn4, licenseBtn, translatorsBtn,
world = this.world(); world = this.world();
aboutTxt = 'Snap! 4.0.1\nBuild Your Own Blocks\n\n' aboutTxt = 'Snap! 4.0.2\nBuild Your Own Blocks\n\n'
+ 'Copyright \u24B8 2015 Jens M\u00F6nig and ' + 'Copyright \u24B8 2015 Jens M\u00F6nig and '
+ 'Brian Harvey\n' + 'Brian Harvey\n'
+ 'jens@moenig.org, bh@cs.berkeley.edu\n\n' + 'jens@moenig.org, bh@cs.berkeley.edu\n\n'
@ -2834,6 +2903,7 @@ IDE_Morph.prototype.newProject = function () {
StageMorph.prototype.codeMappings = {}; StageMorph.prototype.codeMappings = {};
StageMorph.prototype.codeHeaders = {}; StageMorph.prototype.codeHeaders = {};
StageMorph.prototype.enableCodeMapping = false; StageMorph.prototype.enableCodeMapping = false;
StageMorph.prototype.enableInheritance = false;
SpriteMorph.prototype.useFlatLineEnds = false; SpriteMorph.prototype.useFlatLineEnds = false;
this.setProjectName(''); this.setProjectName('');
this.projectNotes = ''; this.projectNotes = '';
@ -3053,6 +3123,7 @@ IDE_Morph.prototype.rawOpenProjectString = function (str) {
StageMorph.prototype.codeMappings = {}; StageMorph.prototype.codeMappings = {};
StageMorph.prototype.codeHeaders = {}; StageMorph.prototype.codeHeaders = {};
StageMorph.prototype.enableCodeMapping = false; StageMorph.prototype.enableCodeMapping = false;
StageMorph.prototype.enableInheritance = false;
if (Process.prototype.isCatchingErrors) { if (Process.prototype.isCatchingErrors) {
try { try {
this.serializer.openProject( this.serializer.openProject(
@ -3094,6 +3165,7 @@ IDE_Morph.prototype.rawOpenCloudDataString = function (str) {
StageMorph.prototype.codeMappings = {}; StageMorph.prototype.codeMappings = {};
StageMorph.prototype.codeHeaders = {}; StageMorph.prototype.codeHeaders = {};
StageMorph.prototype.enableCodeMapping = false; StageMorph.prototype.enableCodeMapping = false;
StageMorph.prototype.enableInheritance = false;
if (Process.prototype.isCatchingErrors) { if (Process.prototype.isCatchingErrors) {
try { try {
model = this.serializer.parse(str); model = this.serializer.parse(str);
@ -3417,6 +3489,7 @@ IDE_Morph.prototype.toggleAppMode = function (appMode) {
this.controlBar.projectButton, this.controlBar.projectButton,
this.controlBar.settingsButton, this.controlBar.settingsButton,
this.controlBar.stageSizeButton, this.controlBar.stageSizeButton,
this.stageHandle,
this.corral, this.corral,
this.corralBar, this.corralBar,
this.spriteEditor, this.spriteEditor,
@ -3440,6 +3513,9 @@ IDE_Morph.prototype.toggleAppMode = function (appMode) {
morph.hide(); morph.hide();
} }
}); });
if (world.keyboardReceiver instanceof ScriptFocusMorph) {
world.keyboardReceiver.stopEditing();
}
} else { } else {
this.setColor(this.backgroundColor); this.setColor(this.backgroundColor);
this.controlBar.setColor(this.frameColor); this.controlBar.setColor(this.frameColor);
@ -3476,36 +3552,32 @@ IDE_Morph.prototype.toggleStageSize = function (isSmall) {
var myself = this, var myself = this,
smallRatio = 0.5, smallRatio = 0.5,
world = this.world(), world = this.world(),
shiftClicked = (world.currentKey === 16); shiftClicked = (world.currentKey === 16),
altClicked = (world.currentKey === 18);
function toggle() { function toggle() {
myself.isSmallStage = isNil(isSmall) ? !myself.isSmallStage : isSmall; myself.isSmallStage = isNil(isSmall) ? !myself.isSmallStage : isSmall;
} }
function zoomIn() { function zoomTo(targetRatio) {
myself.step = function () { var count = 1,
myself.stageRatio -= (myself.stageRatio - smallRatio) / 2; steps = 5;
myself.setExtent(world.extent()); myself.fps = 30;
if (myself.stageRatio < (smallRatio + 0.1)) {
myself.stageRatio = smallRatio;
myself.setExtent(world.extent());
delete myself.step;
}
};
}
function zoomOut() {
myself.isSmallStage = true; myself.isSmallStage = true;
myself.step = function () { myself.step = function () {
myself.stageRatio += (1 - myself.stageRatio) / 2; var diff;
myself.setExtent(world.extent()); if (count >= steps) {
if (myself.stageRatio > 0.9) { myself.stageRatio = targetRatio;
myself.stageRatio = 1;
myself.isSmallStage = false;
myself.setExtent(world.extent());
myself.controlBar.stageSizeButton.refresh();
delete myself.step; delete myself.step;
myself.fps = 0;
myself.isSmallStage = !(targetRatio === 1);
myself.controlBar.stageSizeButton.refresh();
} else {
count += 1;
diff = (targetRatio - myself.stageRatio) / 2;
myself.stageRatio += diff;
} }
myself.setExtent(world.extent());
}; };
} }
@ -3515,14 +3587,20 @@ IDE_Morph.prototype.toggleStageSize = function (isSmall) {
if (!this.isSmallStage || (smallRatio === this.stageRatio)) { if (!this.isSmallStage || (smallRatio === this.stageRatio)) {
toggle(); toggle();
} }
} else if (altClicked) {
smallRatio = this.width() / 2 /
this.stage.dimensions.x;
if (!this.isSmallStage || (smallRatio === this.stageRatio)) {
toggle();
}
} else { } else {
toggle(); toggle();
} }
if (this.isAnimating) { if (this.isAnimating) {
if (this.isSmallStage) { if (this.isSmallStage) {
zoomIn(); zoomTo(smallRatio);
} else { } else {
zoomOut(); zoomTo(1);
} }
} else { } else {
if (this.isSmallStage) {this.stageRatio = smallRatio; } if (this.isSmallStage) {this.stageRatio = smallRatio; }
@ -4219,7 +4297,7 @@ IDE_Morph.prototype.getURLsbeOrRelative = function (url) {
var request = new XMLHttpRequest(), var request = new XMLHttpRequest(),
myself = this; myself = this;
try { try {
request.open('GET', baseUrl + url, false); request.open('GET', baseURL + url, false);
request.send(); request.send();
if (request.status === 200) { if (request.status === 200) {
return request.responseText; return request.responseText;
@ -4660,7 +4738,7 @@ ProjectDialogMorph.prototype.setSource = function (source) {
myself.nameField.setContents(item.name || ''); myself.nameField.setContents(item.name || '');
} }
src = myself.ide.getURL( src = myself.ide.getURL(
baseUrl + 'Examples/' + item.name + '.xml' baseURL + 'Examples/' + item.name + '.xml'
); );
xml = myself.ide.serializer.parse(src); xml = myself.ide.serializer.parse(src);
@ -4714,9 +4792,9 @@ ProjectDialogMorph.prototype.getLocalProjectList = function () {
ProjectDialogMorph.prototype.getExamplesProjectList = function () { ProjectDialogMorph.prototype.getExamplesProjectList = function () {
var dir, var dir,
projects = []; projects = [];
//alert(baseUrl); //alert(baseURL);
dir = this.ide.getURL(baseUrl + 'Examples/'); dir = this.ide.getURL(baseURL + 'Examples/');
dir.split('\n').forEach( dir.split('\n').forEach(
function (line) { function (line) {
var startIdx = line.search(new RegExp('href=".*xml"')), var startIdx = line.search(new RegExp('href=".*xml"')),
@ -4835,7 +4913,7 @@ ProjectDialogMorph.prototype.openProject = function () {
if (this.source === 'cloud') { if (this.source === 'cloud') {
this.openCloudProject(proj); this.openCloudProject(proj);
} else if (this.source === 'examples') { } else if (this.source === 'examples') {
src = this.ide.getURL(baseUrl + 'Examples/' + proj.name + '.xml'); src = this.ide.getURL(baseURL + 'Examples/' + proj.name + '.xml');
this.ide.openProjectString(src); this.ide.openProjectString(src);
this.destroy(); this.destroy();
} else { // 'local' } else { // 'local'
@ -5042,7 +5120,7 @@ ProjectDialogMorph.prototype.shareProject = function () {
projectId = 'Username=' + projectId = 'Username=' +
encodeURIComponent(usr.toLowerCase()) + encodeURIComponent(usr.toLowerCase()) +
'&ProjectName=' + '&ProjectName=' +
encodeURIComponent(proj.projectName); encodeURIComponent(proj.ProjectName);
location.hash = projectId; location.hash = projectId;
} }
}, },
@ -5214,7 +5292,7 @@ function SpriteIconMorph(aSprite, aTemplate) {
} }
SpriteIconMorph.prototype.init = function (aSprite, aTemplate) { SpriteIconMorph.prototype.init = function (aSprite, aTemplate) {
var colors, action, query, myself = this; var colors, action, query, hover, myself = this;
if (!aTemplate) { if (!aTemplate) {
colors = [ colors = [
@ -5244,6 +5322,11 @@ SpriteIconMorph.prototype.init = function (aSprite, aTemplate) {
return false; return false;
}; };
hover = function () {
if (!aSprite.exemplar) {return null; }
return (localize('parent' + ':\n' + aSprite.exemplar.name));
};
// additional properties: // additional properties:
this.object = aSprite || new SpriteMorph(); // mandatory, actually this.object = aSprite || new SpriteMorph(); // mandatory, actually
this.version = this.object.version; this.version = this.object.version;
@ -5259,7 +5342,7 @@ SpriteIconMorph.prototype.init = function (aSprite, aTemplate) {
this.object.name, // label string this.object.name, // label string
query, // predicate/selector query, // predicate/selector
null, // environment null, // environment
null, // hint hover, // hint
aTemplate // optional, for cached background images aTemplate // optional, for cached background images
); );
@ -5430,6 +5513,9 @@ SpriteIconMorph.prototype.userMenu = function () {
menu.addItem("duplicate", 'duplicateSprite'); menu.addItem("duplicate", 'duplicateSprite');
menu.addItem("delete", 'removeSprite'); menu.addItem("delete", 'removeSprite');
menu.addLine(); menu.addLine();
if (StageMorph.prototype.enableInheritance) {
menu.addItem("parent...", 'chooseExemplar');
}
if (this.object.anchor) { if (this.object.anchor) {
menu.addItem( menu.addItem(
localize('detach from') + ' ' + this.object.anchor.name, localize('detach from') + ' ' + this.object.anchor.name,
@ -5464,6 +5550,10 @@ SpriteIconMorph.prototype.exportSprite = function () {
this.object.exportSprite(); this.object.exportSprite();
}; };
SpriteIconMorph.prototype.chooseExemplar = function () {
this.object.chooseExemplar();
};
SpriteIconMorph.prototype.showSpriteOnStage = function () { SpriteIconMorph.prototype.showSpriteOnStage = function () {
this.object.showOnStage(); this.object.showOnStage();
}; };
@ -6483,3 +6573,148 @@ JukeboxMorph.prototype.reactToDropOf = function (icon) {
this.sprite.sounds.add(costume, idx); this.sprite.sounds.add(costume, idx);
this.updateList(); this.updateList();
}; };
// StageHandleMorph ////////////////////////////////////////////////////////
// I am a horizontal resizing handle for a StageMorph
// StageHandleMorph inherits from Morph:
StageHandleMorph.prototype = new Morph();
StageHandleMorph.prototype.constructor = StageHandleMorph;
StageHandleMorph.uber = Morph.prototype;
// StageHandleMorph instance creation:
function StageHandleMorph(target) {
this.init(target);
}
StageHandleMorph.prototype.init = function (target) {
this.target = target || null;
HandleMorph.uber.init.call(this);
this.color = MorphicPreferences.isFlat ?
IDE_Morph.prototype.groupColor : new Color(190, 190, 190);
this.isDraggable = false;
this.noticesTransparentClick = true;
this.setExtent(new Point(12, 50));
};
// StageHandleMorph drawing:
StageHandleMorph.prototype.drawNew = function () {
this.normalImage = newCanvas(this.extent());
this.highlightImage = newCanvas(this.extent());
this.drawOnCanvas(
this.normalImage,
this.color
);
this.drawOnCanvas(
this.highlightImage,
MorphicPreferences.isFlat ?
new Color(245, 245, 255) : new Color(100, 100, 255),
this.color
);
this.image = this.normalImage;
this.fixLayout();
};
StageHandleMorph.prototype.drawOnCanvas = function (
aCanvas,
color,
shadowColor
) {
var context = aCanvas.getContext('2d'),
l = aCanvas.height / 8,
w = aCanvas.width / 6,
r = w / 2,
x,
y,
i;
context.lineWidth = w;
context.lineCap = 'round';
y = aCanvas.height / 2;
context.strokeStyle = color.toString();
x = aCanvas.width / 12;
for (i = 0; i < 3; i += 1) {
if (i > 0) {
context.beginPath();
context.moveTo(x, y - (l - r));
context.lineTo(x, y + (l - r));
context.stroke();
}
x += (w * 2);
l *= 2;
}
if (shadowColor) {
context.strokeStyle = shadowColor.toString();
x = aCanvas.width / 12 + w;
l = aCanvas.height / 8;
for (i = 0; i < 3; i += 1) {
if (i > 0) {
context.beginPath();
context.moveTo(x, y - (l - r));
context.lineTo(x, y + (l - r));
context.stroke();
}
x += (w * 2);
l *= 2;
}
}
};
// StageHandleMorph layout:
StageHandleMorph.prototype.fixLayout = function () {
if (!this.target) {return; }
var ide = this.target.parentThatIsA(IDE_Morph);
this.setTop(this.target.top() + 10);
this.setRight(this.target.left());
if (ide) {ide.add(this); } // come to front
};
// StageHandleMorph stepping:
StageHandleMorph.prototype.step = null;
StageHandleMorph.prototype.mouseDownLeft = function (pos) {
var world = this.world(),
offset = this.right() - pos.x,
myself = this,
ide = this.target.parentThatIsA(IDE_Morph);
if (!this.target) {
return null;
}
ide.isSmallStage = true;
ide.controlBar.stageSizeButton.refresh();
this.step = function () {
var newPos, newWidth;
if (world.hand.mouseButton) {
newPos = world.hand.bounds.origin.x + offset;
newWidth = myself.target.right() - newPos;
ide.stageRatio = newWidth / myself.target.dimensions.x;
ide.setExtent(world.extent());
} else {
this.step = null;
ide.isSmallStage = !(ide.stageRatio === 1);
ide.controlBar.stageSizeButton.refresh();
}
};
};
// StageHandleMorph events:
StageHandleMorph.prototype.mouseEnter = function () {
this.image = this.highlightImage;
this.changed();
};
StageHandleMorph.prototype.mouseLeave = function () {
this.image = this.normalImage;
this.changed();
};

Plik binarny nie jest wyświetlany.

Wyświetl plik

@ -2522,8 +2522,35 @@ ______
* Morphic, Objects, Blocks, XML: Optimizations and dramatic speed-up. Thanks, Nathan!! * Morphic, Objects, Blocks, XML: Optimizations and dramatic speed-up. Thanks, Nathan!!
* Objects: push maximum clone count up to 1000, tweak Note::play * Objects: push maximum clone count up to 1000, tweak Note::play
=== Start with v4.0.1 === === v4.0.1 (unreleased) ===
150626 150626
------ ------
* Morphic: Fix Inspector duplication, update documentation * Morphic: Fix Inspector duplication, update documentation
150727
------
* Polish translation update, thanks, Bartosz Leper!
* Turkish translation. Yay!! Thanks, Hakan Ataş!
* Hungarian translation. Yay!! Thanks, Makány György!
* GUI: relative-url fixes, Thanks, Michael!
* Morphic: enable exporting a screenshot of the World
* Morphic: enable more fine-grained control over dragging position correction
* Morphic: enable all Morphs to “scrollIntoView()”
* Morpic: keyboard accessibility for menus
* Objects: fixes and enhancements for nested sprites
* Blocks, Objects, BYOB, GUI: keyboard editing support
* Objects, Blocks, Threads, GUI, Store, Widgets: Prototypal inheritance for sprite-local variables
* Objects, Blocks: enable monitoring closurized non-locals and thread-temporaries (script vars of running processes)
* GUI: stage resizing handle
150728
------
* GUI: fixed relative urls, thanks, Michael!
* Morphic: escalate origin with “accept” and “cancel” events from text cursors
* BYOB: keep BlockEditors open when <enter> or <esc> keys are pressed
* GUI: stop keyboard editing of blocks when selecting another sprite
150730
------
* Blocks: improve keyboard editing for embedded rings

1695
lang-hu.js 100644

Plik diff jest za duży Load Diff

Wyświetl plik

@ -248,8 +248,8 @@ SnapTranslator.dict.pl = {
'tylko lewo/prawo', 'tylko lewo/prawo',
// new sprite button: // new sprite button:
'add a new sprite': 'add a new Turtle sprite':
'dodaj nowego duszka', 'dodaj nowego duszka-żółwia',
// tab help // tab help
'costumes tab help': 'costumes tab help':
@ -343,7 +343,7 @@ SnapTranslator.dict.pl = {
'think %s': 'think %s':
'pomy\u015Bl %s', 'pomy\u015Bl %s',
'Hello!': 'Hello!':
'Hallo!', 'Cześć!',
'Hmm...': 'Hmm...':
'Hmm...', 'Hmm...',
'change %eff effect by %n': 'change %eff effect by %n':
@ -545,9 +545,9 @@ SnapTranslator.dict.pl = {
'join %words': 'join %words':
'po\u0142\u0105cz %words', 'po\u0142\u0105cz %words',
'hello': 'hello':
'Hallo', 'witaj',
'world': 'world':
's\u0142owo', 'świecie',
'letter %n of %s': 'letter %n of %s':
'litera %n z %s', 'litera %n z %s',
'length of %s': 'length of %s':
@ -673,6 +673,8 @@ SnapTranslator.dict.pl = {
'Logowanie...', 'Logowanie...',
'Signup...': 'Signup...':
'Rejestracja...', 'Rejestracja...',
'Reset Password...':
'Zresetuj hasło...',
// settings menu // settings menu
'Language...': 'Language...':
@ -857,7 +859,7 @@ SnapTranslator.dict.pl = {
'Ok': 'Ok':
'Ok', 'Ok',
'Cancel': 'Cancel':
'Poniechaj', 'Anuluj',
'Yes': 'Yes':
'Tak', 'Tak',
'No': 'No':
@ -903,9 +905,53 @@ SnapTranslator.dict.pl = {
'Delete Project': 'Delete Project':
'Usu\u0144 projekt', 'Usu\u0144 projekt',
'Are you sure you want to delete': 'Are you sure you want to delete':
'Czy napewno chcesz usun\u0105\u0107?', 'Czy napewno chcesz usun\u0105\u0107',
'rename...': 'rename...':
'przemianuj', 'przemianuj',
'Cloud':
'Chmura',
'Browser':
'Przeglądarka',
'Examples':
'Przykłady',
'You are not logged in':
'Nie jesteś zalogowany',
'Updating\nproject list...':
'Aktualizowanie\nlisty projektów...',
'last changed':
'ostatnio zmieniony',
'Open':
'Otwórz',
'Share':
'Udostępnij',
'Unshare':
'Wyłącz udostępnianie',
'Share Project':
'Udostępnij projekt',
'Unshare Project':
'Wyłącz udostępnianie projektu',
'Are you sure you want to publish':
'Czy na pewno chcesz opublikować projekt',
'Are you sure you want to unpublish':
'Czy na pewno chcesz wyłączyć publikowanie projektu',
'sharing\nproject...':
'Udostępnianie\nprojektu...',
'shared.':
'Projekt udostępniony.',
'unsharing\nproject...':
'Wyłączanie\nudostępniania projektu...',
'unshared.':
'Udostępnianie wyłączone.',
'Fetching project\nfrom the cloud...':
'Wczytywanie projektu\nz chmury...',
'Opening project...':
'Otwieranie projektu...',
'Save Project':
'Zapisz projekt',
'Saving project\nto the cloud...':
'Zapisywanie projektu\ndo chmury...',
'saved.':
'Projekt zapisany.',
// costume editor // costume editor
'Costume Editor': 'Costume Editor':
@ -1081,7 +1127,7 @@ SnapTranslator.dict.pl = {
// costumes // costumes
'Turtle': 'Turtle':
'Duszek', 'Żółw',
'Empty': 'Empty':
'Pusty', 'Pusty',
@ -1221,5 +1267,61 @@ SnapTranslator.dict.pl = {
'last': 'last':
'ostatni', 'ostatni',
'any': 'any':
'dowolny' 'dowolny',
// Sign up dialog
'Sign up':
'Rejestracja',
'User name:':
'Nazwa użytkownika:',
'Birth date:':
'Data urodzenia:',
'year:':
'rok:',
'E-mail address:':
'Adres e-mail:',
'E-mail address of parent or guardian:':
'Adres e-mail rodzica lub opiekuna:',
'Terms of Service...':
'Regulamin...',
'Privacy...':
'Polityka prywatności...',
'I have read and agree\nto the Terms of Service':
'Przeczytałem i zgadzam się\nz Regulaminem',
'January':
'styczeń',
'February':
'luty',
'March':
'marzec',
'April':
'kwiecień',
'May':
'maj',
'June':
'czerwiec',
'July':
'lipiec',
'August':
'sierpień',
'September':
'wrzesień',
'October':
'październik',
'November':
'listopad',
'December':
'grudzień',
'please fill out\nthis field':
'Proszę wypełnić\nto pole',
'please agree to\nthe TOS':
'Proszę zaakceptować\nRegulamin',
'Sign in':
'Zaloguj się',
'Password:':
'Hasło:',
'stay signed in on this computer\nuntil logging out':
'Zapamiętaj mnie na tym komputerze\naż do wylogowania',
'Reset password':
'Zresetuj hasło'
}; };

1275
lang-tr.js 100644

Plik diff jest za duży Load Diff

Wyświetl plik

@ -3,3 +3,5 @@ list-utilities List utilities
stream-tools Streams (lazy lists) stream-tools Streams (lazy lists)
variadic-reporters Variadic reporters variadic-reporters Variadic reporters
word-sentence Words, sentences word-sentence Words, sentences
cases Multi-branched conditional (switch)
leap-library LEAP Motion controller

Wyświetl plik

@ -0,0 +1 @@
<blocks app="Snap! 4.0, http://snap.berkeley.edu" version="1"><block-definition s="cases: if %&apos;test&apos; then %&apos;result&apos; %&apos;more&apos;" type="command" category="control"><header></header><code></code><inputs><input type="%b"></input><input type="%cs"></input><input type="%mult%boolUE"></input></inputs><script><block s="doIfElse"><block var="test"/><script><block s="doRun"><block var="result"/><list></list></block></script><script><custom-block s="catch %upvar %cs"><l>tag</l><script><custom-block s="for each %upvar of %l %cs"><l>item</l><block var="more"/><script><block s="doIf"><block s="evaluate"><block var="item"/><list></list></block><script><custom-block s="throw %s"><block var="tag"/></custom-block></script></block></script></custom-block></script></custom-block></script></block></script></block-definition><block-definition s="catch %&apos;tag&apos; %&apos;action&apos;" type="command" category="control"><header></header><code></code><inputs><input type="%upvar"></input><input type="%cs"></input></inputs><script><block s="doCallCC"><block s="reifyScript"><script><block s="doSetVar"><l>tag</l><block var="cont"/></block><block s="doRun"><block var="action"/><list></list></block></script><list><l>cont</l></list></block></block></script></block-definition><block-definition s="throw %&apos;cont&apos;" type="command" category="control"><header></header><code></code><inputs><input type="%s">catchtag</input></inputs><script><block s="doRun"><block var="cont"/><list></list></block></script></block-definition><block-definition s="for each %&apos;item&apos; of %&apos;data&apos; %&apos;action&apos;" type="command" category="lists"><header></header><code></code><inputs><input type="%upvar"></input><input type="%l"></input><input type="%cs"></input></inputs><script><block s="doUntil"><custom-block s="empty? %l"><block var="data"/></custom-block><script><block s="doSetVar"><l>item</l><block s="reportListItem"><l>1</l><block var="data"/></block></block><block s="doRun"><block var="action"/><list><block s="reportListItem"><l>1</l><block var="data"/></block></list></block><block s="doSetVar"><l>data</l><block s="reportCDR"><block var="data"/></block></block></script></block></script></block-definition><block-definition s="else if %&apos;test&apos; then %&apos;action&apos;" type="predicate" category="control"><header></header><code></code><inputs><input type="%b"></input><input type="%cs"></input></inputs><script><block s="doIfElse"><block var="test"/><script><block s="doRun"><block var="action"/><list></list></block><block s="doReport"><block s="reportTrue"></block></block></script><script><block s="doReport"><block s="reportFalse"></block></block></script></block></script></block-definition><block-definition s="else %&apos;action&apos;" type="predicate" category="control"><header></header><code></code><inputs><input type="%cs"></input></inputs><script><block s="doRun"><block var="action"/><list></list></block><block s="doReport"><block s="reportTrue"></block></block></script></block-definition></blocks>

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

Wyświetl plik

@ -61,7 +61,7 @@ PushButtonMorph, SyntaxElementMorph, Color, Point, WatcherMorph,
StringMorph, SpriteMorph, ScrollFrameMorph, CellMorph, ArrowMorph, StringMorph, SpriteMorph, ScrollFrameMorph, CellMorph, ArrowMorph,
MenuMorph, snapEquals, Morph, isNil, localize, MorphicPreferences*/ MenuMorph, snapEquals, Morph, isNil, localize, MorphicPreferences*/
modules.lists = '2015-June-25'; modules.lists = '2015-July-27';
var List; var List;
var ListWatcherMorph; var ListWatcherMorph;
@ -158,9 +158,8 @@ List.prototype.add = function (element, index) {
if no index is specifed, append the element if no index is specifed, append the element
*/ */
var idx = index || this.length() + 1, var idx = index || this.length() + 1,
obj = element === 0 ? 0 obj = isNil(element) ? null : element;
: element === false ? false
: element || null;
this.becomeArray(); this.becomeArray();
this.contents.splice(idx - 1, 0, obj); this.contents.splice(idx - 1, 0, obj);
this.changed(); this.changed();

Wyświetl plik

@ -42,7 +42,7 @@
/*global modules, contains*/ /*global modules, contains*/
modules.locale = '2015-June-25'; modules.locale = '2015-July-27';
// Global stuff // Global stuff
@ -475,3 +475,28 @@ SnapTranslator.dict.te = {
'last_changed': 'last_changed':
'2015-02-20' '2015-02-20'
}; };
SnapTranslator.dict.tr = {
// translations meta information
'language_name':
'Türkçe',
'language_translator':
'Hakan Atas',
'translator_e-mail':
'hakanatas@gmail.com',
'last_changed':
'2015-7-27'
};
SnapTranslator.dict.hu = {
// translations meta information
'language_name':
'Magyar',
'language_translator':
'Makány György',
'translator_e-mail':
'makany.gyorgy@gmail.com',
'last_changed':
'2015-07-27'
};

Wyświetl plik

@ -1048,7 +1048,7 @@
/*global window, HTMLCanvasElement, getMinimumFontHeight, FileReader, Audio, /*global window, HTMLCanvasElement, getMinimumFontHeight, FileReader, Audio,
FileList, getBlurredShadowSupport*/ FileList, getBlurredShadowSupport*/
var morphicVersion = '2015-June-26'; var morphicVersion = '2015-July-28';
var modules = {}; // keep track of additional loaded modules var modules = {}; // keep track of additional loaded modules
var useBlurredShadows = getBlurredShadowSupport(); // check for Chrome-bug var useBlurredShadows = getBlurredShadowSupport(); // check for Chrome-bug
@ -2501,6 +2501,32 @@ Morph.prototype.keepWithin = function (aMorph) {
} }
}; };
Morph.prototype.scrollIntoView = function () {
var leftOff, rightOff, topOff, bottomOff,
sf = this.parentThatIsA(ScrollFrameMorph);
if (!sf) {return; }
rightOff = Math.min(
this.fullBounds().right() - sf.right(),
sf.contents.right() - sf.right()
);
if (rightOff > 0) {
sf.contents.moveBy(new Point(-rightOff, 0));
}
leftOff = this.fullBounds().left() - sf.left();
if (leftOff < 0) {
sf.contents.moveBy(new Point(-leftOff, 0));
}
topOff = this.fullBounds().top() - sf.top();
if (topOff < 0) {
sf.contents.moveBy(new Point(0, -topOff));
}
bottomOff = this.fullBounds().bottom() - sf.bottom();
if (bottomOff > 0) {
sf.contents.moveBy(new Point(0, -bottomOff));
}
sf.adjustScrollBars();
};
// Morph accessing - dimensional changes requiring a complete redraw // Morph accessing - dimensional changes requiring a complete redraw
Morph.prototype.setExtent = function (aPoint) { Morph.prototype.setExtent = function (aPoint) {
@ -3092,6 +3118,13 @@ Morph.prototype.rootForGrab = function () {
return this.parent.rootForGrab(); return this.parent.rootForGrab();
}; };
Morph.prototype.isCorrectingOutsideDrag = function () {
// make sure I don't "trail behind" the hand when dragged
// override for morphs that you want to be dragged outside
// their full bounds
return true;
};
Morph.prototype.wantsDropOf = function (aMorph) { Morph.prototype.wantsDropOf = function (aMorph) {
// default is to answer the general flag - change for my heirs // default is to answer the general flag - change for my heirs
if ((aMorph instanceof HandleMorph) || if ((aMorph instanceof HandleMorph) ||
@ -3174,6 +3207,17 @@ Morph.prototype.move = function () {
); );
}; };
Morph.prototype.moveCenter = function () {
this.world().activeHandle = new HandleMorph(
this,
null,
null,
null,
null,
'moveCenter'
);
};
Morph.prototype.hint = function (msg) { Morph.prototype.hint = function (msg) {
var m, text; var m, text;
text = msg; text = msg;
@ -3722,7 +3766,7 @@ HandleMorph.prototype.init = function (
this.target = target || null; this.target = target || null;
this.minExtent = new Point(minX || 0, minY || 0); this.minExtent = new Point(minX || 0, minY || 0);
this.inset = new Point(insetX || 0, insetY || insetX || 0); this.inset = new Point(insetX || 0, insetY || insetX || 0);
this.type = type || 'resize'; // can also be 'move' this.type = type || 'resize'; // can also be 'move', 'moveCenter'
HandleMorph.uber.init.call(this); HandleMorph.uber.init.call(this);
this.color = new Color(255, 255, 255); this.color = new Color(255, 255, 255);
this.isDraggable = false; this.isDraggable = false;
@ -3747,11 +3791,15 @@ HandleMorph.prototype.drawNew = function () {
); );
this.image = this.normalImage; this.image = this.normalImage;
if (this.target) { if (this.target) {
this.setPosition( if (this.type === 'moveCenter') {
this.target.bottomRight().subtract( this.setCenter(this.target.center());
this.extent().add(this.inset) } else { // 'resize', 'move'
) this.setPosition(
); this.target.bottomRight().subtract(
this.extent().add(this.inset)
)
);
}
this.target.add(this); this.target.add(this);
this.target.changed(); this.target.changed();
} }
@ -3763,6 +3811,7 @@ HandleMorph.prototype.drawOnCanvas = function (
shadowColor shadowColor
) { ) {
var context = aCanvas.getContext('2d'), var context = aCanvas.getContext('2d'),
isSquare = (this.type.indexOf('move') === 0),
p1, p1,
p11, p11,
p2, p2,
@ -3774,7 +3823,7 @@ HandleMorph.prototype.drawOnCanvas = function (
context.strokeStyle = color.toString(); context.strokeStyle = color.toString();
if (this.type === 'move') { if (isSquare) {
p1 = this.bottomLeft().subtract(this.position()); p1 = this.bottomLeft().subtract(this.position());
p11 = p1.copy(); p11 = p1.copy();
@ -3811,7 +3860,7 @@ HandleMorph.prototype.drawOnCanvas = function (
context.strokeStyle = shadowColor.toString(); context.strokeStyle = shadowColor.toString();
if (this.type === 'move') { if (isSquare) {
p1 = this.bottomLeft().subtract(this.position()); p1 = this.bottomLeft().subtract(this.position());
p11 = p1.copy(); p11 = p1.copy();
@ -3853,12 +3902,17 @@ HandleMorph.prototype.step = null;
HandleMorph.prototype.mouseDownLeft = function (pos) { HandleMorph.prototype.mouseDownLeft = function (pos) {
var world = this.root(), var world = this.root(),
offset = pos.subtract(this.bounds.origin), offset,
myself = this; myself = this;
if (!this.target) { if (!this.target) {
return null; return null;
} }
if (this.type === 'moveCenter') {
offset = pos.subtract(this.center());
} else {
offset = pos.subtract(this.bounds.origin);
}
this.step = function () { this.step = function () {
var newPos, newExt; var newPos, newExt;
if (world.hand.mouseButton) { if (world.hand.mouseButton) {
@ -3875,6 +3929,8 @@ HandleMorph.prototype.mouseDownLeft = function (pos) {
myself.extent().add(myself.inset) myself.extent().add(myself.inset)
) )
); );
} else if (this.type === 'moveCenter') {
myself.target.setCenter(newPos);
} else { // type === 'move' } else { // type === 'move'
myself.target.setPosition( myself.target.setPosition(
newPos.subtract(this.target.extent()) newPos.subtract(this.target.extent())
@ -4680,7 +4736,7 @@ CursorMorph.prototype.accept = function () {
if (world) { if (world) {
world.stopEditing(); world.stopEditing();
} }
this.escalateEvent('accept', null); this.escalateEvent('accept', this);
}; };
CursorMorph.prototype.cancel = function () { CursorMorph.prototype.cancel = function () {
@ -4689,7 +4745,7 @@ CursorMorph.prototype.cancel = function () {
if (world) { if (world) {
world.stopEditing(); world.stopEditing();
} }
this.escalateEvent('cancel', null); this.escalateEvent('cancel', this);
}; };
CursorMorph.prototype.undo = function () { CursorMorph.prototype.undo = function () {
@ -6652,6 +6708,8 @@ MenuMorph.prototype.init = function (target, title, environment, fontSize) {
this.label = null; this.label = null;
this.world = null; this.world = null;
this.isListContents = false; this.isListContents = false;
this.hasFocus = false;
this.selection = null;
// initialize inherited properties: // initialize inherited properties:
MenuMorph.uber.init.call(this); MenuMorph.uber.init.call(this);
@ -6871,6 +6929,7 @@ MenuMorph.prototype.popup = function (world, pos) {
} }
world.add(this); world.add(this);
world.activeMenu = this; world.activeMenu = this;
this.world = world; // optionally enable keyboard support
this.fullChanged(); this.fullChanged();
}; };
@ -6901,6 +6960,105 @@ MenuMorph.prototype.popUpCenteredInWorld = function (world) {
); );
}; };
// MenuMorph keyboard accessibility
MenuMorph.prototype.getFocus = function () {
this.world.keyboardReceiver = this;
this.selection = null;
this.selectFirst();
this.hasFocus = true;
};
MenuMorph.prototype.processKeyDown = function (event) {
//console.log(event.keyCode);
switch (event.keyCode) {
case 13: // 'enter'
case 32: // 'space'
if (this.selection) {
this.selection.mouseClickLeft();
}
return;
case 27: // 'esc'
return this.destroy();
case 38: // 'up arrow'
return this.selectUp();
case 40: // 'down arrow'
return this.selectDown();
default:
nop();
}
};
MenuMorph.prototype.processKeyUp = function (event) {
nop(event);
};
MenuMorph.prototype.processKeyPress = function (event) {
nop(event);
};
MenuMorph.prototype.selectFirst = function () {
var i;
for (i = 0; i < this.children.length; i += 1) {
if (this.children[i] instanceof MenuItemMorph) {
this.select(this.children[i]);
return;
}
}
};
MenuMorph.prototype.selectUp = function () {
var triggers, idx;
triggers = this.children.filter(function (each) {
return each instanceof MenuItemMorph;
});
if (!this.selection) {
if (triggers.length) {
this.select(triggers[0]);
}
return;
}
idx = triggers.indexOf(this.selection) - 1;
if (idx < 0) {
idx = triggers.length - 1;
}
this.select(triggers[idx]);
};
MenuMorph.prototype.selectDown = function () {
var triggers, idx;
triggers = this.children.filter(function (each) {
return each instanceof MenuItemMorph;
});
if (!this.selection) {
if (triggers.length) {
this.select(triggers[0]);
}
return;
}
idx = triggers.indexOf(this.selection) + 1;
if (idx >= triggers.length) {
idx = 0;
}
this.select(triggers[idx]);
};
MenuMorph.prototype.select = function (aMenuItem) {
this.unselectAllItems();
aMenuItem.image = aMenuItem.highlightImage;
aMenuItem.changed();
this.selection = aMenuItem;
};
MenuMorph.prototype.destroy = function () {
if (this.hasFocus) {
this.world.keyboardReceiver = null;
}
MenuMorph.uber.destroy.call(this);
};
// StringMorph ///////////////////////////////////////////////////////// // StringMorph /////////////////////////////////////////////////////////
// I am a single line of text // I am a single line of text
@ -9586,32 +9744,16 @@ HandMorph.prototype.processMouseMove = function (event) {
this.grabOrigin = this.morphToGrab.situation(); this.grabOrigin = this.morphToGrab.situation();
} }
if (morph) { if (morph) {
// if the mouse has left its fullBounds, center it // if the mouse has left its fullBounds, allow to center it
fb = morph.fullBounds(); fb = morph.fullBounds();
if (!fb.containsPoint(pos)) { if (!fb.containsPoint(pos) &&
morph.isCorrectingOutsideDrag()) {
this.bounds.origin = fb.center(); this.bounds.origin = fb.center();
this.grab(morph); this.grab(morph);
this.setPosition(pos); this.setPosition(pos);
} }
} }
} }
/*
original, more cautious code for grabbing Morphs,
retained in case of needing to fall back:
if (morph === this.morphToGrab) {
if (morph.isDraggable) {
this.grab(morph);
} else if (morph.isTemplate) {
morph = morph.fullCopy();
morph.isTemplate = false;
morph.isDraggable = true;
this.grab(morph);
}
}
*/
} }
this.mouseOverList.forEach(function (old) { this.mouseOverList.forEach(function (old) {
@ -10399,6 +10541,13 @@ WorldMorph.prototype.contextMenu = function () {
'inspect', 'inspect',
'open a window on\nall properties' 'open a window on\nall properties'
); );
menu.addItem(
"screenshot...",
function () {
window.open(this.fullImageClassic().toDataURL());
},
'open a new window\nwith a picture of this morph'
);
menu.addLine(); menu.addLine();
menu.addItem( menu.addItem(
"restore display", "restore display",

Wyświetl plik

@ -125,7 +125,7 @@ PrototypeHatBlockMorph*/
// Global stuff //////////////////////////////////////////////////////// // Global stuff ////////////////////////////////////////////////////////
modules.objects = '2015-June-25'; modules.objects = '2015-July-27';
var SpriteMorph; var SpriteMorph;
var StageMorph; var StageMorph;
@ -583,7 +583,7 @@ SpriteMorph.prototype.initBlocks = function () {
}, },
/* migrated to a newer block version: /* migrated to a newer block version:
receiveClick: { receiveClick: {
type: 'hat', type: 'hat',
category: 'control', category: 'control',
@ -900,17 +900,20 @@ SpriteMorph.prototype.initBlocks = function () {
reifyScript: { reifyScript: {
type: 'ring', type: 'ring',
category: 'other', category: 'other',
spec: '%rc %ringparms' spec: '%rc %ringparms',
alias: 'command ring lambda'
}, },
reifyReporter: { reifyReporter: {
type: 'ring', type: 'ring',
category: 'other', category: 'other',
spec: '%rr %ringparms' spec: '%rr %ringparms',
alias: 'reporter ring lambda'
}, },
reifyPredicate: { reifyPredicate: {
type: 'ring', type: 'ring',
category: 'other', category: 'other',
spec: '%rp %ringparms' spec: '%rp %ringparms',
alias: 'predicate ring lambda'
}, },
reportSum: { reportSum: {
type: 'reporter', type: 'reporter',
@ -920,12 +923,14 @@ SpriteMorph.prototype.initBlocks = function () {
reportDifference: { reportDifference: {
type: 'reporter', type: 'reporter',
category: 'operators', category: 'operators',
spec: '%n \u2212 %n' spec: '%n \u2212 %n',
alias: '-'
}, },
reportProduct: { reportProduct: {
type: 'reporter', type: 'reporter',
category: 'operators', category: 'operators',
spec: '%n \u00D7 %n' spec: '%n \u00D7 %n',
alias: '*'
}, },
reportQuotient: { reportQuotient: {
type: 'reporter', type: 'reporter',
@ -1103,6 +1108,13 @@ SpriteMorph.prototype.initBlocks = function () {
spec: 'script variables %scriptVars' spec: 'script variables %scriptVars'
}, },
// inheritance - experimental
doDeleteAttr: {
type: 'command',
category: 'variables',
spec: 'delete %shd'
},
// Lists // Lists
reportNewList: { reportNewList: {
type: 'reporter', type: 'reporter',
@ -1348,11 +1360,13 @@ SpriteMorph.prototype.init = function (globals) {
'confetti': 0 'confetti': 0
}; };
// sprite inheritance
this.exemplar = null;
SpriteMorph.uber.init.call(this); SpriteMorph.uber.init.call(this);
this.isDraggable = true; this.isDraggable = true;
this.isDown = false; this.isDown = false;
this.heading = 90; this.heading = 90;
this.changed(); this.changed();
this.drawNew(); this.drawNew();
@ -1642,7 +1656,8 @@ SpriteMorph.prototype.variableBlock = function (varName) {
SpriteMorph.prototype.blockTemplates = function (category) { SpriteMorph.prototype.blockTemplates = function (category) {
var blocks = [], myself = this, varNames, button, var blocks = [], myself = this, varNames, button,
cat = category || 'motion', txt; cat = category || 'motion', txt,
inheritedVars = this.inheritedVariableNames();
function block(selector) { function block(selector) {
if (StageMorph.prototype.hiddenPrimitives[selector]) { if (StageMorph.prototype.hiddenPrimitives[selector]) {
@ -1657,6 +1672,9 @@ SpriteMorph.prototype.blockTemplates = function (category) {
var newBlock = SpriteMorph.prototype.variableBlock(varName); var newBlock = SpriteMorph.prototype.variableBlock(varName);
newBlock.isDraggable = false; newBlock.isDraggable = false;
newBlock.isTemplate = true; newBlock.isTemplate = true;
if (contains(inheritedVars, varName)) {
newBlock.ghost();
}
return newBlock; return newBlock;
} }
@ -1705,15 +1723,18 @@ SpriteMorph.prototype.blockTemplates = function (category) {
} }
function addVar(pair) { function addVar(pair) {
var ide;
if (pair) { if (pair) {
if (myself.variables.silentFind(pair[0])) { if (myself.isVariableNameInUse(pair[0], pair[1])) {
myself.inform('that name is already in use'); myself.inform('that name is already in use');
} else { } else {
ide = myself.parentThatIsA(IDE_Morph);
myself.addVariable(pair[0], pair[1]); myself.addVariable(pair[0], pair[1]);
myself.toggleVariableWatcher(pair[0], pair[1]); if (!myself.showingVariableWatcher(pair[0])) {
myself.blocksCache[cat] = null; myself.toggleVariableWatcher(pair[0], pair[1]);
myself.paletteCache[cat] = null; }
myself.parentThatIsA(IDE_Morph).refreshPalette(); ide.flushBlocksCache('variables'); // b/c of inheritance
ide.refreshPalette();
} }
} }
} }
@ -2028,7 +2049,7 @@ SpriteMorph.prototype.blockTemplates = function (category) {
button.showHelp = BlockMorph.prototype.showHelp; button.showHelp = BlockMorph.prototype.showHelp;
blocks.push(button); blocks.push(button);
if (this.variables.allNames().length > 0) { if (this.deletableVariableNames().length > 0) {
button = new PushButtonMorph( button = new PushButtonMorph(
null, null,
function () { function () {
@ -2037,7 +2058,7 @@ SpriteMorph.prototype.blockTemplates = function (category) {
null, null,
myself myself
); );
myself.variables.allNames().forEach(function (name) { myself.deletableVariableNames().forEach(function (name) {
menu.addItem(name, name); menu.addItem(name, name);
}); });
menu.popUpAtHand(myself.world()); menu.popUpAtHand(myself.world());
@ -2067,6 +2088,15 @@ SpriteMorph.prototype.blockTemplates = function (category) {
blocks.push(block('doHideVar')); blocks.push(block('doHideVar'));
blocks.push(block('doDeclareVariables')); blocks.push(block('doDeclareVariables'));
// inheritance:
if (StageMorph.prototype.enableInheritance) {
blocks.push('-');
blocks.push(block('doDeleteAttr'));
}
///////////////////////////////
blocks.push('='); blocks.push('=');
blocks.push(block('reportNewList')); blocks.push(block('reportNewList'));
@ -2357,15 +2387,30 @@ SpriteMorph.prototype.freshPalette = function (category) {
// SpriteMorph blocks searching // SpriteMorph blocks searching
SpriteMorph.prototype.blocksMatching = function (searchString, strictly) { SpriteMorph.prototype.blocksMatching = function (
searchString,
strictly,
types, // optional, ['hat', 'command', 'reporter', 'predicate']
varNames // optional, list of reachable unique variable names
) {
// answer an array of block templates whose spec contains // answer an array of block templates whose spec contains
// the given search string, ordered by descending relevance // the given search string, ordered by descending relevance
// types is an optional array containing block types the search
// is limited to, e.g. "command", "hat", "reporter", "predicate".
// Note that "predicate" is not subsumed by "reporter" and has
// to be specified explicitly.
// if no types are specified all blocks are searched
var blocks = [], var blocks = [],
blocksDict, blocksDict,
myself = this, myself = this,
search = searchString.toLowerCase(), search = searchString.toLowerCase(),
stage = this.parentThatIsA(StageMorph); stage = this.parentThatIsA(StageMorph);
if (!types || !types.length) {
types = ['hat', 'command', 'reporter', 'predicate', 'ring'];
}
if (!varNames) {varNames = []; }
function labelOf(aBlockSpec) { function labelOf(aBlockSpec) {
var words = (BlockMorph.prototype.parseSpec(aBlockSpec)), var words = (BlockMorph.prototype.parseSpec(aBlockSpec)),
filtered = words.filter( filtered = words.filter(
@ -2396,29 +2441,39 @@ SpriteMorph.prototype.blocksMatching = function (searchString, strictly) {
return newBlock; return newBlock;
} }
// variable getters
varNames.forEach(function (vName) {
var rel = relevance(labelOf(vName), search);
if (rel !== -1) {
blocks.push([myself.variableBlock(vName), rel + '1']);
}
});
// custom blocks // custom blocks
[this.customBlocks, stage.globalBlocks].forEach(function (blocksList) { [this.customBlocks, stage.globalBlocks].forEach(function (blocksList) {
blocksList.forEach(function (definition) { blocksList.forEach(function (definition) {
var spec = localize(definition.blockSpec()).toLowerCase(), if (contains(types, definition.type)) {
rel = relevance(labelOf(spec), search); var spec = localize(definition.blockSpec()).toLowerCase(),
if (rel !== -1) { rel = relevance(labelOf(spec), search);
blocks.push([definition.templateInstance(), rel + '1']); if (rel !== -1) {
blocks.push([definition.templateInstance(), rel + '2']);
}
} }
}); });
}); });
// primitives // primitives
blocksDict = SpriteMorph.prototype.blocks; blocksDict = SpriteMorph.prototype.blocks;
Object.keys(blocksDict).forEach(function (selector) { Object.keys(blocksDict).forEach(function (selector) {
if (!StageMorph.prototype.hiddenPrimitives[selector]) { if (!StageMorph.prototype.hiddenPrimitives[selector] &&
contains(types, blocksDict[selector].type)) {
var block = blocksDict[selector], var block = blocksDict[selector],
spec = localize(block.spec).toLowerCase(), spec = localize(block.alias || block.spec).toLowerCase(),
rel = relevance(labelOf(spec), search); rel = relevance(labelOf(spec), search);
if ( if (
(rel !== -1) && (rel !== -1) &&
(!block.dev) && (!block.dev) &&
(!block.only || (block.only === myself.constructor)) (!block.only || (block.only === myself.constructor))
) { ) {
blocks.push([primitive(selector), rel + '2']); blocks.push([primitive(selector), rel + '3']);
} }
} }
}); });
@ -2426,18 +2481,43 @@ SpriteMorph.prototype.blocksMatching = function (searchString, strictly) {
return blocks.map(function (each) {return each[0]; }); return blocks.map(function (each) {return each[0]; });
}; };
SpriteMorph.prototype.searchBlocks = function () { SpriteMorph.prototype.searchBlocks = function (
searchString,
types,
varNames,
scriptFocus
) {
var myself = this, var myself = this,
unit = SyntaxElementMorph.prototype.fontSize, unit = SyntaxElementMorph.prototype.fontSize,
ide = this.parentThatIsA(IDE_Morph), ide = this.parentThatIsA(IDE_Morph),
oldSearch = '', oldSearch = '',
searchBar = new InputFieldMorph(''), searchBar = new InputFieldMorph(searchString || ''),
searchPane = ide.createPalette('forSearch'); searchPane = ide.createPalette('forSearch'),
blocksList = [],
selection,
focus;
function showSelection() {
if (focus) {focus.destroy(); }
if (!selection || !scriptFocus) {return; }
focus = selection.outline(
MorphicPreferences.isFlat ? new Color(150, 200, 255)
: new Color(255, 255, 255),
2
);
searchPane.contents.add(focus);
focus.scrollIntoView();
}
function show(blocks) { function show(blocks) {
var oldFlag = Morph.prototype.trackChanges, var oldFlag = Morph.prototype.trackChanges,
x = searchPane.contents.left() + 5, x = searchPane.contents.left() + 5,
y = (searchBar.bottom() + unit); y = (searchBar.bottom() + unit);
blocksList = blocks;
selection = null;
if (blocks.length && scriptFocus) {
selection = blocks[0];
}
Morph.prototype.trackChanges = false; Morph.prototype.trackChanges = false;
searchPane.contents.children = [searchPane.contents.children[0]]; searchPane.contents.children = [searchPane.contents.children[0]];
blocks.forEach(function (block) { blocks.forEach(function (block) {
@ -2447,6 +2527,7 @@ SpriteMorph.prototype.searchBlocks = function () {
y += unit * 0.3; y += unit * 0.3;
}); });
Morph.prototype.trackChanges = oldFlag; Morph.prototype.trackChanges = oldFlag;
showSelection();
searchPane.changed(); searchPane.changed();
} }
@ -2463,17 +2544,52 @@ SpriteMorph.prototype.searchBlocks = function () {
searchBar.drawNew(); searchBar.drawNew();
searchPane.accept = function () { searchPane.accept = function () {
var search = searchBar.getValue(); var search;
if (search.length > 0) { if (scriptFocus) {
show(myself.blocksMatching(search)); searchBar.cancel();
if (selection) {
scriptFocus.insertBlock(selection);
}
} else {
search = searchBar.getValue();
if (search.length > 0) {
show(myself.blocksMatching(search));
}
} }
}; };
searchPane.reactToKeystroke = function () { searchPane.reactToKeystroke = function (evt) {
var search = searchBar.getValue(); var search, idx, code = evt ? evt.keyCode : 0;
if (search !== oldSearch) { switch (code) {
oldSearch = search; case 38: // up arrow
show(myself.blocksMatching(search, search.length < 2)); if (!scriptFocus || !selection) {return; }
idx = blocksList.indexOf(selection) - 1;
if (idx < 0) {
idx = blocksList.length - 1;
}
selection = blocksList[idx];
showSelection();
return;
case 40: // down arrow
if (!scriptFocus || !selection) {return; }
idx = blocksList.indexOf(selection) + 1;
if (idx >= blocksList.length) {
idx = 0;
}
selection = blocksList[idx];
showSelection();
return;
default:
search = searchBar.getValue();
if (search !== oldSearch) {
oldSearch = search;
show(myself.blocksMatching(
search,
search.length < 2,
types,
varNames
));
}
} }
}; };
@ -2484,6 +2600,7 @@ SpriteMorph.prototype.searchBlocks = function () {
ide.fixLayout('refreshPalette'); ide.fixLayout('refreshPalette');
searchBar.edit(); searchBar.edit();
if (searchString) {searchPane.reactToKeystroke(); }
}; };
// SpriteMorph variable management // SpriteMorph variable management
@ -2491,7 +2608,7 @@ SpriteMorph.prototype.searchBlocks = function () {
SpriteMorph.prototype.addVariable = function (name, isGlobal) { SpriteMorph.prototype.addVariable = function (name, isGlobal) {
var ide = this.parentThatIsA(IDE_Morph); var ide = this.parentThatIsA(IDE_Morph);
if (isGlobal) { if (isGlobal) {
this.variables.parentFrame.addVar(name); this.globalVariables().addVar(name);
if (ide) { if (ide) {
ide.flushBlocksCache('variables'); ide.flushBlocksCache('variables');
} }
@ -2503,7 +2620,10 @@ SpriteMorph.prototype.addVariable = function (name, isGlobal) {
SpriteMorph.prototype.deleteVariable = function (varName) { SpriteMorph.prototype.deleteVariable = function (varName) {
var ide = this.parentThatIsA(IDE_Morph); var ide = this.parentThatIsA(IDE_Morph);
this.deleteVariableWatcher(varName); if (!contains(this.inheritedVariableNames(true), varName)) {
// check only shadowed variables
this.deleteVariableWatcher(varName);
}
this.variables.deleteVar(varName); this.variables.deleteVar(varName);
if (ide) { if (ide) {
ide.flushBlocksCache('variables'); // b/c the var could be global ide.flushBlocksCache('variables'); // b/c the var could be global
@ -2658,7 +2778,7 @@ SpriteMorph.prototype.userMenu = function () {
} }
menu.addItem("duplicate", 'duplicate'); menu.addItem("duplicate", 'duplicate');
menu.addItem("delete", 'remove'); menu.addItem("delete", 'remove');
menu.addItem("move", 'move'); menu.addItem("move", 'moveCenter');
if (!this.isClone) { if (!this.isClone) {
menu.addItem("edit", 'edit'); menu.addItem("edit", 'edit');
} }
@ -3176,12 +3296,20 @@ SpriteMorph.prototype.positionTalkBubble = function () {
SpriteMorph.prototype.prepareToBeGrabbed = function (hand) { SpriteMorph.prototype.prepareToBeGrabbed = function (hand) {
this.removeShadow(); this.removeShadow();
this.recordLayers(); this.recordLayers();
if (!this.bounds.containsPoint(hand.position())) { if (!this.bounds.containsPoint(hand.position()) &&
this.isCorrectingOutsideDrag()) {
this.setCenter(hand.position()); this.setCenter(hand.position());
} }
this.addShadow(); this.addShadow();
}; };
SpriteMorph.prototype.isCorrectingOutsideDrag = function () {
// make sure I don't "trail behind" the hand when dragged
// override for morphs that you want to be dragged outside
// their full bounds
return !this.parts.length;
};
SpriteMorph.prototype.justDropped = function () { SpriteMorph.prototype.justDropped = function () {
this.restoreLayers(); this.restoreLayers();
this.positionTalkBubble(); this.positionTalkBubble();
@ -3240,6 +3368,22 @@ SpriteMorph.prototype.moveBy = function (delta, justMe) {
} }
}; };
SpriteMorph.prototype.silentMoveBy = function (delta, justMe) {
SpriteMorph.uber.silentMoveBy.call(this, delta);
if (!justMe && this.parent instanceof HandMorph) {
this.parts.forEach(function (part) {
part.moveBy(delta);
});
}
};
SpriteMorph.prototype.rootForGrab = function () {
if (this.anchor) {
return this.anchor.rootForGrab();
}
return SpriteMorph.uber.rootForGrab.call(this);
};
SpriteMorph.prototype.slideBackTo = function (situation, inSteps) { SpriteMorph.prototype.slideBackTo = function (situation, inSteps) {
// override the inherited default to make sure my parts follow // override the inherited default to make sure my parts follow
var steps = inSteps || 5, var steps = inSteps || 5,
@ -3646,6 +3790,7 @@ SpriteMorph.prototype.reportThreadCount = function () {
SpriteMorph.prototype.findVariableWatcher = function (varName) { SpriteMorph.prototype.findVariableWatcher = function (varName) {
var stage = this.parentThatIsA(StageMorph), var stage = this.parentThatIsA(StageMorph),
globals = this.globalVariables(),
myself = this; myself = this;
if (stage === null) { if (stage === null) {
return null; return null;
@ -3655,7 +3800,7 @@ SpriteMorph.prototype.findVariableWatcher = function (varName) {
function (morph) { function (morph) {
return morph instanceof WatcherMorph return morph instanceof WatcherMorph
&& (morph.target === myself.variables && (morph.target === myself.variables
|| morph.target === myself.variables.parentFrame) || morph.target === globals)
&& morph.getter === varName; && morph.getter === varName;
} }
); );
@ -3663,6 +3808,7 @@ SpriteMorph.prototype.findVariableWatcher = function (varName) {
SpriteMorph.prototype.toggleVariableWatcher = function (varName, isGlobal) { SpriteMorph.prototype.toggleVariableWatcher = function (varName, isGlobal) {
var stage = this.parentThatIsA(StageMorph), var stage = this.parentThatIsA(StageMorph),
globals = this.globalVariables(),
watcher, watcher,
others; others;
if (stage === null) { if (stage === null) {
@ -3682,12 +3828,12 @@ SpriteMorph.prototype.toggleVariableWatcher = function (varName, isGlobal) {
// if no watcher exists, create a new one // if no watcher exists, create a new one
if (isNil(isGlobal)) { if (isNil(isGlobal)) {
isGlobal = contains(this.variables.parentFrame.names(), varName); isGlobal = contains(globals.names(), varName);
} }
watcher = new WatcherMorph( watcher = new WatcherMorph(
varName, varName,
this.blockColor.variables, this.blockColor.variables,
isGlobal ? this.variables.parentFrame : this.variables, isGlobal ? globals : this.variables,
varName varName
); );
watcher.setPosition(stage.position().add(10)); watcher.setPosition(stage.position().add(10));
@ -3954,6 +4100,176 @@ SpriteMorph.prototype.replaceDoubleDefinitionsFor = function (definition) {
} }
}; };
// SpriteMorph inheritance - general
SpriteMorph.prototype.chooseExemplar = function () {
var stage = this.parentThatIsA(StageMorph),
myself = this,
other = stage.children.filter(function (m) {
return m instanceof SpriteMorph &&
(!contains(m.allExemplars(), myself));
}),
menu;
menu = new MenuMorph(
function (aSprite) {myself.setExemplar(aSprite); },
localize('current parent') +
':\n' +
(this.exemplar ? this.exemplar.name : localize('none'))
);
other.forEach(function (eachSprite) {
menu.addItem(eachSprite.name, eachSprite);
});
menu.addLine();
menu.addItem(localize('none'), null);
menu.popUpAtHand(this.world());
};
SpriteMorph.prototype.setExemplar = function (another) {
var ide = this.parentThatIsA(IDE_Morph);
this.exemplar = another;
if (isNil(another)) {
this.variables.parentFrame = (this.globalVariables());
} else {
this.variables.parentFrame = (another.variables);
}
if (ide) {
ide.flushBlocksCache('variables');
ide.refreshPalette();
}
};
SpriteMorph.prototype.allExemplars = function () {
// including myself
var all = [],
current = this;
while (!isNil(current)) {
all.push(current);
current = current.exemplar;
}
return all;
};
SpriteMorph.prototype.specimens = function () {
// without myself
var myself = this;
return this.siblings().filter(function (m) {
return m instanceof SpriteMorph && (m.exemplar === myself);
});
};
SpriteMorph.prototype.allSpecimens = function () {
// without myself
var myself = this;
return this.siblings().filter(function (m) {
return m instanceof SpriteMorph && contains(m.allExemplars(), myself);
});
};
// SpriteMorph inheritance - variables
SpriteMorph.prototype.isVariableNameInUse = function (vName, isGlobal) {
if (isGlobal) {
return contains(this.variables.allNames(), vName);
}
if (contains(this.variables.names(), vName)) {return true; }
return contains(this.globalVariables().names(), vName);
};
SpriteMorph.prototype.globalVariables = function () {
var current = this.variables.parentFrame;
while (current.owner) {
current = current.parentFrame;
}
return current;
};
SpriteMorph.prototype.shadowVar = function (name, value) {
var ide = this.parentThatIsA(IDE_Morph);
this.variables.addVar(name, value);
if (ide) {
ide.flushBlocksCache('variables');
ide.refreshPalette();
}
};
SpriteMorph.prototype.inheritedVariableNames = function (shadowedOnly) {
var names = [],
own = this.variables.names(),
current = this.variables.parentFrame;
function test(each) {
return shadowedOnly ? contains(own, each) : !contains(own, each);
}
while (current.owner instanceof SpriteMorph) {
names.push.apply(
names,
current.names().filter(test)
);
current = current.parentFrame;
}
return names;
};
SpriteMorph.prototype.deletableVariableNames = function () {
var locals = this.variables.names(),
inherited = this.inheritedVariableNames();
return locals.concat(
this.globalVariables().names().filter(
function (each) {
return !contains(locals, each) && !contains(inherited, each);
}
)
);
};
// SpriteMorph inheritance - custom blocks
/*
// under construction, commented out for now
SpriteMorph.prototype.ownBlocks = function () {
var dict = {};
this.customBlocks.forEach(function (def) {
dict[def.blockSpec()] = def;
});
return dict;
};
SpriteMorph.prototype.allBlocks = function (valuesOnly) {
var dict = {};
this.allExemplars().reverse().forEach(function (sprite) {
sprite.customBlocks.forEach(function (def) {
dict[def.blockSpec()] = def;
});
});
if (valuesOnly) {
return Object.keys(dict).map(function (key) {return dict[key]; });
}
return dict;
};
SpriteMorph.prototype.inheritedBlocks = function (valuesOnly) {
var dict = {},
own = Object.keys(this.ownBlocks()),
others = this.allExemplars().reverse();
others.pop();
others.forEach(function (sprite) {
sprite.customBlocks.forEach(function (def) {
var spec = def.blockSpec();
if (!contains(own, spec)) {
dict[spec] = def;
}
});
});
if (valuesOnly) {
return Object.keys(dict).map(function (key) {return dict[key]; });
}
return dict;
};
*/
// SpriteMorph thumbnail // SpriteMorph thumbnail
SpriteMorph.prototype.thumbnail = function (extentPoint) { SpriteMorph.prototype.thumbnail = function (extentPoint) {
@ -4334,6 +4650,8 @@ StageMorph.prototype.codeMappings = {};
StageMorph.prototype.codeHeaders = {}; StageMorph.prototype.codeHeaders = {};
StageMorph.prototype.enableCodeMapping = false; StageMorph.prototype.enableCodeMapping = false;
StageMorph.prototype.enableInheritance = false;
// StageMorph instance creation // StageMorph instance creation
function StageMorph(globals) { function StageMorph(globals) {
@ -4767,6 +5085,8 @@ StageMorph.prototype.processKeyEvent = function (event, action) {
keyName = 'enter'; keyName = 'enter';
if (event.ctrlKey || event.metaKey) { if (event.ctrlKey || event.metaKey) {
keyName = 'ctrl enter'; keyName = 'ctrl enter';
} else if (event.shiftKey) {
keyName = 'shift enter';
} }
break; break;
case 27: case 27:
@ -4807,6 +5127,9 @@ StageMorph.prototype.fireKeyEvent = function (key) {
if (evt === 'ctrl enter') { if (evt === 'ctrl enter') {
return this.fireGreenFlagEvent(); return this.fireGreenFlagEvent();
} }
if (evt === 'shift enter') {
return this.editScripts();
}
if (evt === 'ctrl f') { if (evt === 'ctrl f') {
if (!ide.isAppMode) {ide.currentSprite.searchBlocks(); } if (!ide.isAppMode) {ide.currentSprite.searchBlocks(); }
return; return;
@ -4907,6 +5230,25 @@ StageMorph.prototype.removeAllClones = function () {
this.cloneCount = 0; this.cloneCount = 0;
}; };
StageMorph.prototype.editScripts = function () {
var ide = this.parentThatIsA(IDE_Morph),
scripts,
sorted;
if (ide.isAppMode || !ScriptsMorph.prototype.enableKeyboard) {return; }
scripts = this.parentThatIsA(IDE_Morph).currentSprite.scripts;
scripts.edit(scripts.position());
sorted = scripts.focus.sortedScripts();
if (sorted.length) {
scripts.focus.element = sorted[0];
if (scripts.focus.element instanceof HatBlockMorph) {
scripts.focus.nextCommand();
}
} else {
scripts.focus.moveBy(new Point(50, 50));
}
scripts.focus.fixLayout();
};
// StageMorph block templates // StageMorph block templates
StageMorph.prototype.blockTemplates = function (category) { StageMorph.prototype.blockTemplates = function (category) {
@ -4969,7 +5311,7 @@ StageMorph.prototype.blockTemplates = function (category) {
function addVar(pair) { function addVar(pair) {
if (pair) { if (pair) {
if (myself.variables.silentFind(pair[0])) { if (myself.isVariableNameInUse(pair[0])) {
myself.inform('that name is already in use'); myself.inform('that name is already in use');
} else { } else {
myself.addVariable(pair[0], pair[1]); myself.addVariable(pair[0], pair[1]);
@ -5271,9 +5613,7 @@ StageMorph.prototype.blockTemplates = function (category) {
blocks.push(block('doShowVar')); blocks.push(block('doShowVar'));
blocks.push(block('doHideVar')); blocks.push(block('doHideVar'));
blocks.push(block('doDeclareVariables')); blocks.push(block('doDeclareVariables'));
blocks.push('='); blocks.push('=');
blocks.push(block('reportNewList')); blocks.push(block('reportNewList'));
blocks.push('-'); blocks.push('-');
blocks.push(block('reportCONS')); blocks.push(block('reportCONS'));
@ -5472,7 +5812,7 @@ StageMorph.prototype.show = function () {
this.changed(); this.changed();
}; };
// StageMorph cloning overrice // StageMorph cloning override
StageMorph.prototype.createClone = nop; StageMorph.prototype.createClone = nop;
@ -5663,6 +6003,18 @@ StageMorph.prototype.doubleDefinitionsFor
StageMorph.prototype.replaceDoubleDefinitionsFor StageMorph.prototype.replaceDoubleDefinitionsFor
= SpriteMorph.prototype.replaceDoubleDefinitionsFor; = SpriteMorph.prototype.replaceDoubleDefinitionsFor;
// StageMorph inheritance support - variables
StageMorph.prototype.isVariableNameInUse
= SpriteMorph.prototype.isVariableNameInUse;
StageMorph.prototype.globalVariables
= SpriteMorph.prototype.globalVariables;
StageMorph.prototype.inheritedVariableNames = function () {
return [];
};
// SpriteBubbleMorph //////////////////////////////////////////////////////// // SpriteBubbleMorph ////////////////////////////////////////////////////////
/* /*
@ -6876,32 +7228,51 @@ WatcherMorph.prototype.isGlobal = function (selector) {
// WatcherMorph slider accessing: // WatcherMorph slider accessing:
WatcherMorph.prototype.setSliderMin = function (num) { WatcherMorph.prototype.setSliderMin = function (num, noUpdate) {
if (this.target instanceof VariableFrame) { if (this.target instanceof VariableFrame) {
this.sliderMorph.setSize(1); this.sliderMorph.setSize(1, noUpdate);
this.sliderMorph.setStart(num); this.sliderMorph.setStart(num, noUpdate);
this.sliderMorph.setSize(this.sliderMorph.rangeSize() / 5); this.sliderMorph.setSize(this.sliderMorph.rangeSize() / 5, noUpdate);
} }
}; };
WatcherMorph.prototype.setSliderMax = function (num) { WatcherMorph.prototype.setSliderMax = function (num, noUpdate) {
if (this.target instanceof VariableFrame) { if (this.target instanceof VariableFrame) {
this.sliderMorph.setSize(1); this.sliderMorph.setSize(1, noUpdate);
this.sliderMorph.setStop(num); this.sliderMorph.setStop(num, noUpdate);
this.sliderMorph.setSize(this.sliderMorph.rangeSize() / 5); this.sliderMorph.setSize(this.sliderMorph.rangeSize() / 5, noUpdate);
} }
}; };
// WatcherMorph updating: // WatcherMorph updating:
WatcherMorph.prototype.update = function () { WatcherMorph.prototype.update = function () {
var newValue, var newValue, sprite, num;
num;
if (this.target && this.getter) { if (this.target && this.getter) {
this.updateLabel(); this.updateLabel();
if (this.target instanceof VariableFrame) { if (this.target instanceof VariableFrame) {
newValue = this.target.vars[this.getter] ? newValue = this.target.vars[this.getter] ?
this.target.vars[this.getter].value : undefined; this.target.vars[this.getter].value : undefined;
if (newValue === undefined && this.target.owner) {
sprite = this.target.owner;
if (contains(sprite.inheritedVariableNames(), this.getter)) {
newValue = this.target.getVar(this.getter);
// ghost cell color
this.cellMorph.setColor(
SpriteMorph.prototype.blockColor.variables
.lighter(35)
);
} else {
this.destroy();
return;
}
} else {
// un-ghost the cell color
this.cellMorph.setColor(
SpriteMorph.prototype.blockColor.variables
);
}
} else { } else {
newValue = this.target[this.getter](); newValue = this.target[this.getter]();
} }
@ -6986,7 +7357,11 @@ WatcherMorph.prototype.fixLayout = function () {
this.sliderMorph.button.pressColor.b += 100; this.sliderMorph.button.pressColor.b += 100;
this.sliderMorph.setHeight(fontSize); this.sliderMorph.setHeight(fontSize);
this.sliderMorph.action = function (num) { this.sliderMorph.action = function (num) {
myself.target.vars[myself.getter].value = Math.round(num); myself.target.setVar(
myself.getter,
Math.round(num),
myself.target.owner
);
}; };
this.add(this.sliderMorph); this.add(this.sliderMorph);
} }
@ -7083,7 +7458,46 @@ WatcherMorph.prototype.userMenu = function () {
var myself = this, var myself = this,
menu = new MenuMorph(this), menu = new MenuMorph(this),
on = '\u25CF', on = '\u25CF',
off = '\u25CB'; off = '\u25CB',
vNames;
function monitor(vName) {
var stage = myself.parentThatIsA(StageMorph),
varFrame = myself.currentValue.outerContext.variables;
menu.addItem(
vName + '...',
function () {
var watcher = detect(
stage.children,
function (morph) {
return morph instanceof WatcherMorph
&& morph.target === varFrame
&& morph.getter === vName;
}
),
others;
if (watcher !== null) {
watcher.show();
watcher.fixLayout(); // re-hide hidden parts
return;
}
watcher = new WatcherMorph(
vName + ' ' + localize('(temporary)'),
SpriteMorph.prototype.blockColor.variables,
varFrame,
vName
);
watcher.setPosition(stage.position().add(10));
others = stage.watchers(watcher.left());
if (others.length > 0) {
watcher.setTop(others[others.length - 1].bottom());
}
stage.add(watcher);
watcher.fixLayout();
}
);
}
menu.addItem( menu.addItem(
(this.style === 'normal' ? on : off) + ' ' + localize('normal'), (this.style === 'normal' ? on : off) + ' ' + localize('normal'),
'styleNormal' 'styleNormal'
@ -7182,6 +7596,14 @@ WatcherMorph.prototype.userMenu = function () {
); );
} }
); );
} else if (this.currentValue instanceof Context) {
vNames = this.currentValue.outerContext.variables.names();
if (vNames.length) {
menu.addLine();
vNames.forEach(function (vName) {
monitor(vName);
});
}
} }
} }
return menu; return menu;

124
store.js
Wyświetl plik

@ -61,7 +61,7 @@ SyntaxElementMorph, Variable*/
// Global stuff //////////////////////////////////////////////////////// // Global stuff ////////////////////////////////////////////////////////
modules.store = '2015-June-25'; modules.store = '2015-July-27';
// XML_Serializer /////////////////////////////////////////////////////// // XML_Serializer ///////////////////////////////////////////////////////
@ -413,6 +413,8 @@ SnapSerializer.prototype.rawLoadProjectModel = function (xmlNode) {
model.stage.attributes.threadsafe === 'true'; model.stage.attributes.threadsafe === 'true';
StageMorph.prototype.enableCodeMapping = StageMorph.prototype.enableCodeMapping =
model.stage.attributes.codify === 'true'; model.stage.attributes.codify === 'true';
StageMorph.prototype.enableInheritance =
model.stage.attributes.inheritance === 'true';
model.hiddenPrimitives = model.project.childNamed('hidden'); model.hiddenPrimitives = model.project.childNamed('hidden');
if (model.hiddenPrimitives) { if (model.hiddenPrimitives) {
@ -459,9 +461,17 @@ SnapSerializer.prototype.rawLoadProjectModel = function (xmlNode) {
myself.loadValue(model); myself.loadValue(model);
}); });
// restore nesting associations // restore inheritance and nesting associations
myself.project.stage.children.forEach(function (sprite) { myself.project.stage.children.forEach(function (sprite) {
var anchor; var exemplar, anchor;
if (sprite.inheritanceInfo) { // only sprites can inherit
exemplar = myself.project.sprites[
sprite.inheritanceInfo.exemplar
];
if (exemplar) {
sprite.setExemplar(exemplar);
}
}
if (sprite.nestingInfo) { // only sprites may have nesting info if (sprite.nestingInfo) { // only sprites may have nesting info
anchor = myself.project.sprites[sprite.nestingInfo.anchor]; anchor = myself.project.sprites[sprite.nestingInfo.anchor];
if (anchor) { if (anchor) {
@ -471,6 +481,7 @@ SnapSerializer.prototype.rawLoadProjectModel = function (xmlNode) {
} }
}); });
myself.project.stage.children.forEach(function (sprite) { myself.project.stage.children.forEach(function (sprite) {
delete sprite.inheritanceInfo;
if (sprite.nestingInfo) { // only sprites may have nesting info if (sprite.nestingInfo) { // only sprites may have nesting info
sprite.nestingScale = +(sprite.nestingInfo.scale || sprite.scale); sprite.nestingScale = +(sprite.nestingInfo.scale || sprite.scale);
delete sprite.nestingInfo; delete sprite.nestingInfo;
@ -491,7 +502,7 @@ SnapSerializer.prototype.rawLoadProjectModel = function (xmlNode) {
/* Watchers */ /* Watchers */
model.sprites.childrenNamed('watcher').forEach(function (model) { model.sprites.childrenNamed('watcher').forEach(function (model) {
var watcher, color, target, hidden, extX, extY, vFrame; var watcher, color, target, hidden, extX, extY;
color = myself.loadColor(model.attributes.color); color = myself.loadColor(model.attributes.color);
target = Object.prototype.hasOwnProperty.call( target = Object.prototype.hasOwnProperty.call(
@ -512,20 +523,14 @@ SnapSerializer.prototype.rawLoadProjectModel = function (xmlNode) {
model.attributes, model.attributes,
'var' 'var'
)) { )) {
vFrame = isNil(target) ? project.globalVariables watcher = new WatcherMorph(
: target.variables; model.attributes['var'],
if (Object.prototype.hasOwnProperty.call( color,
vFrame.vars, isNil(target) ? project.globalVariables
model.attributes['var'] : target.variables,
)) { model.attributes['var'],
watcher = new WatcherMorph( hidden
model.attributes['var'], );
color,
vFrame,
model.attributes['var'],
hidden
);
}
} else { } else {
watcher = new WatcherMorph( watcher = new WatcherMorph(
localize(myself.watcherLabels[model.attributes.s]), localize(myself.watcherLabels[model.attributes.s]),
@ -535,35 +540,33 @@ SnapSerializer.prototype.rawLoadProjectModel = function (xmlNode) {
hidden hidden
); );
} }
if (watcher) { watcher.setStyle(model.attributes.style || 'normal');
watcher.setStyle(model.attributes.style || 'normal'); if (watcher.style === 'slider') {
if (watcher.style === 'slider') { watcher.setSliderMin(model.attributes.min || '1', true);
watcher.setSliderMin(model.attributes.min || '1'); watcher.setSliderMax(model.attributes.max || '100', true);
watcher.setSliderMax(model.attributes.max || '100'); }
} watcher.setPosition(
watcher.setPosition( project.stage.topLeft().add(new Point(
project.stage.topLeft().add(new Point( +model.attributes.x || 0,
+model.attributes.x || 0, +model.attributes.y || 0
+model.attributes.y || 0 ))
)) );
); project.stage.add(watcher);
project.stage.add(watcher); watcher.onNextStep = function () {this.currentValue = null; };
watcher.onNextStep = function () {this.currentValue = null; };
// set watcher's contentsMorph's extent if it is showing a list // set watcher's contentsMorph's extent if it is showing a list and
// and if its monitor dimensions are given // its monitor dimensions are given
if (watcher.currentValue instanceof List) { if (watcher.currentValue instanceof List) {
extX = model.attributes.extX; extX = model.attributes.extX;
if (extX) { if (extX) {
watcher.cellMorph.contentsMorph.setWidth(+extX); watcher.cellMorph.contentsMorph.setWidth(+extX);
}
extY = model.attributes.extY;
if (extY) {
watcher.cellMorph.contentsMorph.setHeight(+extY);
}
// adjust my contentsMorph's handle position
watcher.cellMorph.contentsMorph.handle.drawNew();
} }
extY = model.attributes.extY;
if (extY) {
watcher.cellMorph.contentsMorph.setHeight(+extY);
}
// adjust my contentsMorph's handle position
watcher.cellMorph.contentsMorph.handle.drawNew();
} }
}); });
this.objects = {}; this.objects = {};
@ -647,9 +650,17 @@ SnapSerializer.prototype.loadSprites = function (xmlString, ide) {
myself.loadObject(sprite, model); myself.loadObject(sprite, model);
}); });
// restore nesting associations // restore inheritance and nesting associations
project.stage.children.forEach(function (sprite) { project.stage.children.forEach(function (sprite) {
var anchor; var exemplar, anchor;
if (sprite.inheritanceInfo) { // only sprites can inherit
exemplar = project.sprites[
sprite.inheritanceInfo.exemplar
];
if (exemplar) {
sprite.setExemplar(exemplar);
}
}
if (sprite.nestingInfo) { // only sprites may have nesting info if (sprite.nestingInfo) { // only sprites may have nesting info
anchor = project.sprites[sprite.nestingInfo.anchor]; anchor = project.sprites[sprite.nestingInfo.anchor];
if (anchor) { if (anchor) {
@ -659,6 +670,7 @@ SnapSerializer.prototype.loadSprites = function (xmlString, ide) {
} }
}); });
project.stage.children.forEach(function (sprite) { project.stage.children.forEach(function (sprite) {
delete sprite.inheritanceInfo;
if (sprite.nestingInfo) { // only sprites may have nesting info if (sprite.nestingInfo) { // only sprites may have nesting info
sprite.nestingScale = +(sprite.nestingInfo.scale || sprite.scale); sprite.nestingScale = +(sprite.nestingInfo.scale || sprite.scale);
delete sprite.nestingInfo; delete sprite.nestingInfo;
@ -707,6 +719,14 @@ SnapSerializer.prototype.loadObject = function (object, model) {
this.loadScripts(object.scripts, model.require('scripts')); this.loadScripts(object.scripts, model.require('scripts'));
}; };
SnapSerializer.prototype.loadInheritanceInfo = function (object, model) {
// private
var info = model.childNamed('inherit');
if (info) {
object.inheritanceInfo = info.attributes;
}
};
SnapSerializer.prototype.loadNestingInfo = function (object, model) { SnapSerializer.prototype.loadNestingInfo = function (object, model) {
// private // private
var info = model.childNamed('nest'); var info = model.childNamed('nest');
@ -1416,6 +1436,7 @@ StageMorph.prototype.toXML = function (serializer) {
'costume="@" tempo="@" threadsafe="@" ' + 'costume="@" tempo="@" threadsafe="@" ' +
'lines="@" ' + 'lines="@" ' +
'codify="@" ' + 'codify="@" ' +
'inheritance="@" ' +
'scheduled="@" ~>' + 'scheduled="@" ~>' +
'<pentrails>$</pentrails>' + '<pentrails>$</pentrails>' +
'<costumes>%</costumes>' + '<costumes>%</costumes>' +
@ -1443,6 +1464,7 @@ StageMorph.prototype.toXML = function (serializer) {
this.isThreadSafe, this.isThreadSafe,
SpriteMorph.prototype.useFlatLineEnds ? 'flat' : 'round', SpriteMorph.prototype.useFlatLineEnds ? 'flat' : 'round',
this.enableCodeMapping, this.enableCodeMapping,
this.enableInheritance,
StageMorph.prototype.frameRate !== 0, StageMorph.prototype.frameRate !== 0,
this.trailsCanvas.toDataURL('image/png'), this.trailsCanvas.toDataURL('image/png'),
serializer.store(this.costumes, this.name + '_cst'), serializer.store(this.costumes, this.name + '_cst'),
@ -1475,6 +1497,7 @@ SpriteMorph.prototype.toXML = function (serializer) {
' draggable="@"' + ' draggable="@"' +
'%' + '%' +
' costume="@" color="@,@,@" pen="@" ~>' + ' costume="@" color="@,@,@" pen="@" ~>' +
'%' + // inheritance info
'%' + // nesting info '%' + // nesting info
'<costumes>%</costumes>' + '<costumes>%</costumes>' +
'<sounds>%</sounds>' + '<sounds>%</sounds>' +
@ -1497,6 +1520,13 @@ SpriteMorph.prototype.toXML = function (serializer) {
this.color.b, this.color.b,
this.penPoint, this.penPoint,
// inheritance info
this.exemplar
? '<inherit exemplar="' +
this.exemplar.name
+ '"/>'
: '',
// nesting info // nesting info
this.anchor this.anchor
? '<nest anchor="' + ? '<nest anchor="' +

Wyświetl plik

@ -83,7 +83,7 @@ ArgLabelMorph, localize, XML_Element, hex_sha512*/
// Global stuff //////////////////////////////////////////////////////// // Global stuff ////////////////////////////////////////////////////////
modules.threads = '2015-June-25'; modules.threads = '2015-July-27';
var ThreadManager; var ThreadManager;
var Process; var Process;
@ -1157,7 +1157,8 @@ Process.prototype.doSetVar = function (varName, value) {
if (name.expression.selector === 'reportGetVar') { if (name.expression.selector === 'reportGetVar') {
name.variables.setVar( name.variables.setVar(
name.expression.blockSpec, name.expression.blockSpec,
value value,
this.blockReceiver()
); );
return; return;
} }
@ -1173,7 +1174,8 @@ Process.prototype.doChangeVar = function (varName, value) {
if (name.expression.selector === 'reportGetVar') { if (name.expression.selector === 'reportGetVar') {
name.variables.changeVar( name.variables.changeVar(
name.expression.blockSpec, name.expression.blockSpec,
value value,
this.blockReceiver()
); );
return; return;
} }
@ -1206,7 +1208,8 @@ Process.prototype.doShowVar = function (varName) {
if (this.homeContext.receiver) { if (this.homeContext.receiver) {
stage = this.homeContext.receiver.parentThatIsA(StageMorph); stage = this.homeContext.receiver.parentThatIsA(StageMorph);
if (stage) { if (stage) {
target = varFrame.find(name); target = varFrame.silentFind(name);
if (!target) {return; }
// first try to find an existing (hidden) watcher // first try to find an existing (hidden) watcher
watcher = detect( watcher = detect(
stage.children, stage.children,
@ -1223,7 +1226,7 @@ Process.prototype.doShowVar = function (varName) {
} }
// if no watcher exists, create a new one // if no watcher exists, create a new one
isGlobal = contains( isGlobal = contains(
this.homeContext.receiver.variables.parentFrame.names(), this.homeContext.receiver.globalVariables().names(),
varName varName
); );
if (isGlobal || target.owner) { if (isGlobal || target.owner) {
@ -1302,6 +1305,23 @@ Process.prototype.doRemoveTemporaries = function () {
} }
}; };
// Process sprite inheritance primitives
Process.prototype.doDeleteAttr = function (attrName) {
// currently only variables are deletable
var name = attrName,
rcvr = this.blockReceiver();
if (name instanceof Context) {
if (name.expression.selector === 'reportGetVar') {
name = name.expression.blockSpec;
}
}
if (contains(rcvr.inheritedVariableNames(true), name)) {
rcvr.deleteVariable(name);
}
};
// Process lists primitives // Process lists primitives
Process.prototype.reportNewList = function (elements) { Process.prototype.reportNewList = function (elements) {
@ -3115,35 +3135,50 @@ VariableFrame.prototype.silentFind = function (name) {
return null; return null;
}; };
VariableFrame.prototype.setVar = function (name, value) { VariableFrame.prototype.setVar = function (name, value, sender) {
/* // change the specified variable if it exists
change the specified variable if it exists // else throw an error, because variables need to be
else throw an error, because variables need to be // declared explicitly (e.g. through a "script variables" block),
declared explicitly (e.g. through a "script variables" block), // before they can be accessed.
before they can be accessed. // if the found frame is inherited by the sender sprite
*/ // shadow it (create an explicit one for the sender)
// before setting the value ("create-on-write")
var frame = this.find(name); var frame = this.find(name);
if (frame) { if (frame) {
frame.vars[name].value = value; if (sender instanceof SpriteMorph &&
(frame.owner instanceof SpriteMorph) &&
(sender !== frame.owner)) {
sender.shadowVar(name, value);
} else {
frame.vars[name].value = value;
}
} }
}; };
VariableFrame.prototype.changeVar = function (name, delta) { VariableFrame.prototype.changeVar = function (name, delta, sender) {
/* // change the specified variable if it exists
change the specified variable if it exists // else throw an error, because variables need to be
else throw an error, because variables need to be // declared explicitly (e.g. through a "script variables" block,
declared explicitly (e.g. through a "script variables" block, // before they can be accessed.
before they can be accessed. // if the found frame is inherited by the sender sprite
*/ // shadow it (create an explicit one for the sender)
// before changing the value ("create-on-write")
var frame = this.find(name), var frame = this.find(name),
value; value,
newValue;
if (frame) { if (frame) {
value = parseFloat(frame.vars[name].value); value = parseFloat(frame.vars[name].value);
if (isNaN(value)) { newValue = isNaN(value) ? delta : value + parseFloat(delta);
frame.vars[name].value = delta; if (sender instanceof SpriteMorph &&
(frame.owner instanceof SpriteMorph) &&
(sender !== frame.owner)) {
sender.shadowVar(name, newValue);
} else { } else {
frame.vars[name].value = value + parseFloat(delta); frame.vars[name].value = newValue;
} }
} }
}; };

File diff suppressed because one or more lines are too long

Wyświetl plik

@ -74,7 +74,7 @@ HTMLCanvasElement, fontHeight, SymbolMorph, localize, SpeechBubbleMorph,
ArrowMorph, MenuMorph, isString, isNil, SliderMorph, MorphicPreferences, ArrowMorph, MenuMorph, isString, isNil, SliderMorph, MorphicPreferences,
ScrollFrameMorph*/ ScrollFrameMorph*/
modules.widgets = '2015-June-25'; modules.widgets = '2015-July-27';
var PushButtonMorph; var PushButtonMorph;
var ToggleButtonMorph; var ToggleButtonMorph;
@ -560,12 +560,13 @@ ToggleButtonMorph.prototype.init = function (
// ToggleButtonMorph events // ToggleButtonMorph events
ToggleButtonMorph.prototype.mouseEnter = function () { ToggleButtonMorph.prototype.mouseEnter = function () {
var contents = this.hint instanceof Function ? this.hint() : this.hint;
if (!this.state) { if (!this.state) {
this.image = this.highlightImage; this.image = this.highlightImage;
this.changed(); this.changed();
} }
if (this.hint) { if (contents) {
this.bubbleHelp(this.hint); this.bubbleHelp(contents);
} }
}; };