kopia lustrzana https://github.com/backface/turtlestitch
Prototypal inheritance for sprite-local variables
rodzic
76d9d6bd49
commit
7994d6c0ca
11
blocks.js
11
blocks.js
|
@ -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
18
gui.js
|
@ -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();
|
||||
};
|
||||
|
|
295
objects.js
295
objects.js
|
@ -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
124
store.js
|
@ -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="' +
|
||||
|
|
80
threads.js
80
threads.js
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
Ładowanie…
Reference in New Issue