Prototypal inheritance for sprite-local variables

pull/3/merge
Jens Mönig 2015-07-27 00:35:36 +02:00
rodzic 76d9d6bd49
commit 7994d6c0ca
6 zmienionych plików z 430 dodań i 105 usunięć

Wyświetl plik

@ -1238,6 +1238,15 @@ SyntaxElementMorph.prototype.labelPart = function (spec) {
);
part.isStatic = true;
break;
case '%shd':
part = new InputSlotMorph(
null,
false,
'shadowedVariablesMenu',
true
);
part.isStatic = true;
break;
case '%lst':
part = new InputSlotMorph(
null,
@ -1873,7 +1882,6 @@ SyntaxElementMorph.prototype.endLayout = function () {
this.topBlock().fullChanged();
};
// BlockMorph //////////////////////////////////////////////////////////
/*
@ -1939,7 +1947,6 @@ SyntaxElementMorph.prototype.endLayout = function () {
%att - chameleon colored rectangular drop-down for attributes
%fun - chameleon colored rectangular drop-down for math functions
%typ - chameleon colored rectangular drop-down for data types
%var - chameleon colored rectangular drop-down for variable names
%lst - chameleon colored rectangular drop-down for list names
%b - chameleon colored hexagonal slot (for predicates)
%l - list icon

18
gui.js
Wyświetl plik

@ -2415,6 +2415,20 @@ IDE_Morph.prototype.settingsMenu = function () {
'check for block\nto text mapping features',
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);
};
@ -5508,6 +5522,10 @@ SpriteIconMorph.prototype.exportSprite = function () {
this.object.exportSprite();
};
SpriteIconMorph.prototype.chooseExemplar = function () {
this.object.chooseExemplar();
};
SpriteIconMorph.prototype.showSpriteOnStage = function () {
this.object.showOnStage();
};

Wyświetl plik

@ -583,7 +583,7 @@ SpriteMorph.prototype.initBlocks = function () {
},
/* migrated to a newer block version:
receiveClick: {
type: 'hat',
category: 'control',
@ -1108,6 +1108,13 @@ SpriteMorph.prototype.initBlocks = function () {
spec: 'script variables %scriptVars'
},
// inheritance - experimental
doDeleteAttr: {
type: 'command',
category: 'variables',
spec: 'delete %shd'
},
// Lists
reportNewList: {
type: 'reporter',
@ -1353,11 +1360,13 @@ SpriteMorph.prototype.init = function (globals) {
'confetti': 0
};
// sprite inheritance
this.exemplar = null;
SpriteMorph.uber.init.call(this);
this.isDraggable = true;
this.isDown = false;
this.heading = 90;
this.changed();
this.drawNew();
@ -1647,7 +1656,8 @@ SpriteMorph.prototype.variableBlock = function (varName) {
SpriteMorph.prototype.blockTemplates = function (category) {
var blocks = [], myself = this, varNames, button,
cat = category || 'motion', txt;
cat = category || 'motion', txt,
inheritedVars = this.inheritedVariableNames();
function block(selector) {
if (StageMorph.prototype.hiddenPrimitives[selector]) {
@ -1662,6 +1672,9 @@ SpriteMorph.prototype.blockTemplates = function (category) {
var newBlock = SpriteMorph.prototype.variableBlock(varName);
newBlock.isDraggable = false;
newBlock.isTemplate = true;
if (contains(inheritedVars, varName)) {
newBlock.ghost();
}
return newBlock;
}
@ -1710,15 +1723,18 @@ SpriteMorph.prototype.blockTemplates = function (category) {
}
function addVar(pair) {
var ide;
if (pair) {
if (myself.variables.silentFind(pair[0])) {
if (myself.isVariableNameInUse(pair[0], pair[1])) {
myself.inform('that name is already in use');
} else {
ide = myself.parentThatIsA(IDE_Morph);
myself.addVariable(pair[0], pair[1]);
myself.toggleVariableWatcher(pair[0], pair[1]);
myself.blocksCache[cat] = null;
myself.paletteCache[cat] = null;
myself.parentThatIsA(IDE_Morph).refreshPalette();
if (!myself.showingVariableWatcher(pair[0])) {
myself.toggleVariableWatcher(pair[0], pair[1]);
}
ide.flushBlocksCache('variables'); // b/c of inheritance
ide.refreshPalette();
}
}
}
@ -2033,7 +2049,7 @@ SpriteMorph.prototype.blockTemplates = function (category) {
button.showHelp = BlockMorph.prototype.showHelp;
blocks.push(button);
if (this.variables.allNames().length > 0) {
if (this.deletableVariableNames().length > 0) {
button = new PushButtonMorph(
null,
function () {
@ -2042,7 +2058,7 @@ SpriteMorph.prototype.blockTemplates = function (category) {
null,
myself
);
myself.variables.allNames().forEach(function (name) {
myself.deletableVariableNames().forEach(function (name) {
menu.addItem(name, name);
});
menu.popUpAtHand(myself.world());
@ -2072,6 +2088,15 @@ SpriteMorph.prototype.blockTemplates = function (category) {
blocks.push(block('doHideVar'));
blocks.push(block('doDeclareVariables'));
// inheritance:
if (StageMorph.prototype.enableInheritance) {
blocks.push('-');
blocks.push(block('doDeleteAttr'));
}
///////////////////////////////
blocks.push('=');
blocks.push(block('reportNewList'));
@ -2583,7 +2608,7 @@ SpriteMorph.prototype.searchBlocks = function (
SpriteMorph.prototype.addVariable = function (name, isGlobal) {
var ide = this.parentThatIsA(IDE_Morph);
if (isGlobal) {
this.variables.parentFrame.addVar(name);
this.globalVariables().addVar(name);
if (ide) {
ide.flushBlocksCache('variables');
}
@ -2595,7 +2620,10 @@ SpriteMorph.prototype.addVariable = function (name, isGlobal) {
SpriteMorph.prototype.deleteVariable = function (varName) {
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);
if (ide) {
ide.flushBlocksCache('variables'); // b/c the var could be global
@ -3762,6 +3790,7 @@ SpriteMorph.prototype.reportThreadCount = function () {
SpriteMorph.prototype.findVariableWatcher = function (varName) {
var stage = this.parentThatIsA(StageMorph),
globals = this.globalVariables(),
myself = this;
if (stage === null) {
return null;
@ -3771,7 +3800,7 @@ SpriteMorph.prototype.findVariableWatcher = function (varName) {
function (morph) {
return morph instanceof WatcherMorph
&& (morph.target === myself.variables
|| morph.target === myself.variables.parentFrame)
|| morph.target === globals)
&& morph.getter === varName;
}
);
@ -3779,6 +3808,7 @@ SpriteMorph.prototype.findVariableWatcher = function (varName) {
SpriteMorph.prototype.toggleVariableWatcher = function (varName, isGlobal) {
var stage = this.parentThatIsA(StageMorph),
globals = this.globalVariables(),
watcher,
others;
if (stage === null) {
@ -3798,12 +3828,12 @@ SpriteMorph.prototype.toggleVariableWatcher = function (varName, isGlobal) {
// if no watcher exists, create a new one
if (isNil(isGlobal)) {
isGlobal = contains(this.variables.parentFrame.names(), varName);
isGlobal = contains(globals.names(), varName);
}
watcher = new WatcherMorph(
varName,
this.blockColor.variables,
isGlobal ? this.variables.parentFrame : this.variables,
isGlobal ? globals : this.variables,
varName
);
watcher.setPosition(stage.position().add(10));
@ -4070,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.prototype.thumbnail = function (extentPoint) {
@ -4450,6 +4650,8 @@ StageMorph.prototype.codeMappings = {};
StageMorph.prototype.codeHeaders = {};
StageMorph.prototype.enableCodeMapping = false;
StageMorph.prototype.enableInheritance = false;
// StageMorph instance creation
function StageMorph(globals) {
@ -5109,7 +5311,7 @@ StageMorph.prototype.blockTemplates = function (category) {
function addVar(pair) {
if (pair) {
if (myself.variables.silentFind(pair[0])) {
if (myself.isVariableNameInUse(pair[0])) {
myself.inform('that name is already in use');
} else {
myself.addVariable(pair[0], pair[1]);
@ -5411,9 +5613,7 @@ StageMorph.prototype.blockTemplates = function (category) {
blocks.push(block('doShowVar'));
blocks.push(block('doHideVar'));
blocks.push(block('doDeclareVariables'));
blocks.push('=');
blocks.push(block('reportNewList'));
blocks.push('-');
blocks.push(block('reportCONS'));
@ -5612,7 +5812,7 @@ StageMorph.prototype.show = function () {
this.changed();
};
// StageMorph cloning overrice
// StageMorph cloning override
StageMorph.prototype.createClone = nop;
@ -5803,6 +6003,18 @@ StageMorph.prototype.doubleDefinitionsFor
StageMorph.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 ////////////////////////////////////////////////////////
/*
@ -7016,32 +7228,51 @@ WatcherMorph.prototype.isGlobal = function (selector) {
// WatcherMorph slider accessing:
WatcherMorph.prototype.setSliderMin = function (num) {
WatcherMorph.prototype.setSliderMin = function (num, noUpdate) {
if (this.target instanceof VariableFrame) {
this.sliderMorph.setSize(1);
this.sliderMorph.setStart(num);
this.sliderMorph.setSize(this.sliderMorph.rangeSize() / 5);
this.sliderMorph.setSize(1, noUpdate);
this.sliderMorph.setStart(num, noUpdate);
this.sliderMorph.setSize(this.sliderMorph.rangeSize() / 5, noUpdate);
}
};
WatcherMorph.prototype.setSliderMax = function (num) {
WatcherMorph.prototype.setSliderMax = function (num, noUpdate) {
if (this.target instanceof VariableFrame) {
this.sliderMorph.setSize(1);
this.sliderMorph.setStop(num);
this.sliderMorph.setSize(this.sliderMorph.rangeSize() / 5);
this.sliderMorph.setSize(1, noUpdate);
this.sliderMorph.setStop(num, noUpdate);
this.sliderMorph.setSize(this.sliderMorph.rangeSize() / 5, noUpdate);
}
};
// WatcherMorph updating:
WatcherMorph.prototype.update = function () {
var newValue,
num;
var newValue, sprite, num;
if (this.target && this.getter) {
this.updateLabel();
if (this.target instanceof VariableFrame) {
newValue = this.target.vars[this.getter] ?
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 {
newValue = this.target[this.getter]();
}
@ -7126,7 +7357,11 @@ WatcherMorph.prototype.fixLayout = function () {
this.sliderMorph.button.pressColor.b += 100;
this.sliderMorph.setHeight(fontSize);
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);
}

124
store.js
Wyświetl plik

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

Wyświetl plik

@ -83,7 +83,7 @@ ArgLabelMorph, localize, XML_Element, hex_sha512*/
// Global stuff ////////////////////////////////////////////////////////
modules.threads = '2015-June-25';
modules.threads = '2015-July-27';
var ThreadManager;
var Process;
@ -1157,7 +1157,8 @@ Process.prototype.doSetVar = function (varName, value) {
if (name.expression.selector === 'reportGetVar') {
name.variables.setVar(
name.expression.blockSpec,
value
value,
this.blockReceiver()
);
return;
}
@ -1173,7 +1174,8 @@ Process.prototype.doChangeVar = function (varName, value) {
if (name.expression.selector === 'reportGetVar') {
name.variables.changeVar(
name.expression.blockSpec,
value
value,
this.blockReceiver()
);
return;
}
@ -1223,7 +1225,7 @@ Process.prototype.doShowVar = function (varName) {
}
// if no watcher exists, create a new one
isGlobal = contains(
this.homeContext.receiver.variables.parentFrame.names(),
this.homeContext.receiver.globalVariables().names(),
varName
);
if (isGlobal || target.owner) {
@ -1302,6 +1304,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.prototype.reportNewList = function (elements) {
@ -3115,35 +3134,50 @@ VariableFrame.prototype.silentFind = function (name) {
return null;
};
VariableFrame.prototype.setVar = function (name, value) {
/*
change the specified variable if it exists
else throw an error, because variables need to be
declared explicitly (e.g. through a "script variables" block),
before they can be accessed.
*/
VariableFrame.prototype.setVar = function (name, value, sender) {
// change the specified variable if it exists
// else throw an error, because variables need to be
// declared explicitly (e.g. through a "script variables" block),
// 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);
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) {
/*
change the specified variable if it exists
else throw an error, because variables need to be
declared explicitly (e.g. through a "script variables" block,
before they can be accessed.
*/
VariableFrame.prototype.changeVar = function (name, delta, sender) {
// change the specified variable if it exists
// else throw an error, because variables need to be
// declared explicitly (e.g. through a "script variables" block,
// 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),
value;
value,
newValue;
if (frame) {
value = parseFloat(frame.vars[name].value);
if (isNaN(value)) {
frame.vars[name].value = delta;
newValue = isNaN(value) ? delta : value + parseFloat(delta);
if (sender instanceof SpriteMorph &&
(frame.owner instanceof SpriteMorph) &&
(sender !== frame.owner)) {
sender.shadowVar(name, newValue);
} else {
frame.vars[name].value = value + parseFloat(delta);
frame.vars[name].value = newValue;
}
}
};

Wyświetl plik

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