kopia lustrzana https://github.com/backface/turtlestitch
Merge remote-tracking branch 'jmoenig/master'
commit
0492d299b4
|
@ -23,3 +23,6 @@ GNU Affero General Public License for more details.
|
|||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Want to use Snap! but scared by the open-source license? Get in touch with us,
|
||||
we'll make it work.
|
||||
|
|
146
blocks.js
146
blocks.js
|
@ -145,11 +145,11 @@ radians, useBlurredShadows, SpeechBubbleMorph, modules, StageMorph,
|
|||
fontHeight, TableFrameMorph, SpriteMorph, Context, ListWatcherMorph,
|
||||
CellMorph, DialogBoxMorph, BlockInputFragmentMorph, PrototypeHatBlockMorph,
|
||||
Costume, IDE_Morph, BlockDialogMorph, BlockEditorMorph, localize, isNil,
|
||||
isSnapObject, copy, PushButtonMorph, SpriteIconMorph*/
|
||||
isSnapObject, copy, PushButtonMorph, SpriteIconMorph, Process*/
|
||||
|
||||
// Global stuff ////////////////////////////////////////////////////////
|
||||
|
||||
modules.blocks = '2016-July-15';
|
||||
modules.blocks = '2016-October-27';
|
||||
|
||||
var SyntaxElementMorph;
|
||||
var BlockMorph;
|
||||
|
@ -186,7 +186,7 @@ WorldMorph.prototype.customMorphs = function () {
|
|||
/*
|
||||
return [
|
||||
new SymbolMorph(
|
||||
'pipette',
|
||||
'stepForward',
|
||||
50,
|
||||
new Color(250, 250, 250),
|
||||
new Point(-1, -1),
|
||||
|
@ -346,6 +346,7 @@ SyntaxElementMorph.prototype.init = function (silently) {
|
|||
this.cachedClr = null;
|
||||
this.cachedClrBright = null;
|
||||
this.cachedClrDark = null;
|
||||
this.cachedNormalColor = null; // for single-stepping
|
||||
this.isStatic = false; // if true, I cannot be exchanged
|
||||
|
||||
SyntaxElementMorph.uber.init.call(this, silently);
|
||||
|
@ -731,6 +732,20 @@ SyntaxElementMorph.prototype.setLabelColor = function (
|
|||
});
|
||||
};
|
||||
|
||||
SyntaxElementMorph.prototype.flash = function () {
|
||||
if (!this.cachedNormalColor) {
|
||||
this.cachedNormalColor = this.color;
|
||||
this.setColor(this.activeHighlight);
|
||||
}
|
||||
};
|
||||
|
||||
SyntaxElementMorph.prototype.unflash = function () {
|
||||
if (this.cachedNormalColor) {
|
||||
var clr = this.cachedNormalColor;
|
||||
this.cachedNormalColor = null;
|
||||
this.setColor(clr);
|
||||
}
|
||||
};
|
||||
|
||||
// SyntaxElementMorph zebra coloring
|
||||
|
||||
|
@ -2332,7 +2347,7 @@ BlockMorph.prototype.userMenu = function () {
|
|||
function () {
|
||||
new DialogBoxMorph(
|
||||
myself,
|
||||
myself.setSpec,
|
||||
myself.userSetSpec,
|
||||
myself
|
||||
).prompt(
|
||||
"Variable name",
|
||||
|
@ -2430,7 +2445,7 @@ BlockMorph.prototype.userMenu = function () {
|
|||
}
|
||||
return menu;
|
||||
}
|
||||
if (this.parentThatIsA(RingMorph)) {
|
||||
if (this.parent.parentThatIsA(RingMorph)) {
|
||||
menu.addLine();
|
||||
menu.addItem("unringify", 'unringify');
|
||||
menu.addItem("ringify", 'ringify');
|
||||
|
@ -2527,10 +2542,10 @@ BlockMorph.prototype.deleteBlock = function () {
|
|||
}
|
||||
});
|
||||
}
|
||||
if (this instanceof ReporterBlockMorph) {
|
||||
if (this.parent instanceof BlockMorph) {
|
||||
this.parent.revertToDefaultInput(this);
|
||||
}
|
||||
if ((this.parent instanceof BlockMorph)
|
||||
|| (this.parent instanceof MultiArgMorph)
|
||||
|| (this.parent instanceof ReporterSlotMorph)) {
|
||||
this.parent.revertToDefaultInput(this);
|
||||
} else { // CommandBlockMorph
|
||||
if (this.parent) {
|
||||
if (this.parent.fixLayout) {
|
||||
|
@ -2583,7 +2598,7 @@ BlockMorph.prototype.ringify = function () {
|
|||
|
||||
BlockMorph.prototype.unringify = function () {
|
||||
// remove a Ring around me, if any
|
||||
var ring = this.parentThatIsA(RingMorph),
|
||||
var ring = this.parent.parentThatIsA(RingMorph),
|
||||
top = this.topBlock(),
|
||||
scripts = this.parentThatIsA(ScriptsMorph),
|
||||
block,
|
||||
|
@ -5835,7 +5850,8 @@ ArgMorph.prototype.reactToSliderEdit = function () {
|
|||
}
|
||||
if (receiver) {
|
||||
stage = receiver.parentThatIsA(StageMorph);
|
||||
if (stage && stage.isThreadSafe) {
|
||||
if (stage && (stage.isThreadSafe ||
|
||||
Process.prototype.enableSingleStepping)) {
|
||||
stage.threads.startProcess(top, stage.isThreadSafe);
|
||||
} else {
|
||||
top.mouseClickLeft();
|
||||
|
@ -7529,7 +7545,6 @@ InputSlotMorph.prototype.mouseDownLeft = function (pos) {
|
|||
this.escalateEvent('mouseDownLeft', pos);
|
||||
} else {
|
||||
this.contents().edit();
|
||||
this.contents().selectAll();
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -7540,7 +7555,6 @@ InputSlotMorph.prototype.mouseClickLeft = function (pos) {
|
|||
this.dropDownMenu();
|
||||
} else {
|
||||
this.contents().edit();
|
||||
this.contents().selectAll();
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -7558,6 +7572,12 @@ InputSlotMorph.prototype.reactToEdit = function () {
|
|||
this.contents().clearSelection();
|
||||
};
|
||||
|
||||
InputSlotMorph.prototype.freshTextEdit = function (aStringOrTextMorph) {
|
||||
this.onNextStep = function () {
|
||||
aStringOrTextMorph.selectAll();
|
||||
};
|
||||
};
|
||||
|
||||
// InputSlotMorph menu:
|
||||
|
||||
InputSlotMorph.prototype.userMenu = function () {
|
||||
|
@ -7639,6 +7659,29 @@ InputSlotMorph.prototype.isEmptySlot = function () {
|
|||
return this.contents().text === '';
|
||||
};
|
||||
|
||||
// InputSlotMorph single-stepping:
|
||||
|
||||
InputSlotMorph.prototype.flash = function () {
|
||||
// don't redraw the label b/c zebra coloring
|
||||
if (!this.cachedNormalColor) {
|
||||
this.cachedNormalColor = this.color;
|
||||
this.color = this.activeHighlight;
|
||||
this.drawNew();
|
||||
this.changed();
|
||||
}
|
||||
};
|
||||
|
||||
InputSlotMorph.prototype.unflash = function () {
|
||||
// don't redraw the label b/c zebra coloring
|
||||
if (this.cachedNormalColor) {
|
||||
var clr = this.cachedNormalColor;
|
||||
this.cachedNormalColor = null;
|
||||
this.color = clr;
|
||||
this.drawNew();
|
||||
this.changed();
|
||||
}
|
||||
};
|
||||
|
||||
// InputSlotMorph drawing:
|
||||
|
||||
InputSlotMorph.prototype.drawNew = function () {
|
||||
|
@ -7647,13 +7690,15 @@ InputSlotMorph.prototype.drawNew = function () {
|
|||
// initialize my surface property
|
||||
this.image = newCanvas(this.extent());
|
||||
context = this.image.getContext('2d');
|
||||
if (this.parent) {
|
||||
if (this.cachedNormalColor) { // if flashing
|
||||
borderColor = this.color;
|
||||
} else if (this.parent) {
|
||||
borderColor = this.parent.color;
|
||||
} else {
|
||||
borderColor = new Color(120, 120, 120);
|
||||
}
|
||||
context.fillStyle = this.color.toString();
|
||||
if (this.isReadOnly) {
|
||||
if (this.isReadOnly && !this.cachedNormalColor) { // unless flashing
|
||||
context.fillStyle = borderColor.darker().toString();
|
||||
}
|
||||
|
||||
|
@ -7994,6 +8039,16 @@ TemplateSlotMorph.prototype.drawNew = function () {
|
|||
TemplateSlotMorph.prototype.drawRounded = ReporterBlockMorph
|
||||
.prototype.drawRounded;
|
||||
|
||||
// TemplateSlotMorph single-stepping
|
||||
|
||||
TemplateSlotMorph.prototype.flash = function () {
|
||||
this.template().flash();
|
||||
};
|
||||
|
||||
TemplateSlotMorph.prototype.unflash = function () {
|
||||
this.template().unflash();
|
||||
};
|
||||
|
||||
// BooleanSlotMorph ////////////////////////////////////////////////////
|
||||
|
||||
/*
|
||||
|
@ -8142,7 +8197,10 @@ BooleanSlotMorph.prototype.drawNew = function (progress) {
|
|||
this.fontSize + this.edge * 2
|
||||
));
|
||||
}
|
||||
this.color = this.parent ? this.parent.color : new Color(200, 200, 200);
|
||||
if (!(this.cachedNormalColor)) { // unless flashing
|
||||
this.color = this.parent ?
|
||||
this.parent.color : new Color(200, 200, 200);
|
||||
}
|
||||
this.cachedClr = this.color.toString();
|
||||
this.cachedClrBright = this.bright();
|
||||
this.cachedClrDark = this.dark();
|
||||
|
@ -8162,15 +8220,19 @@ BooleanSlotMorph.prototype.drawDiamond = function (context, progress) {
|
|||
gradient;
|
||||
|
||||
// draw the 'flat' shape:
|
||||
switch (this.value) {
|
||||
case true:
|
||||
context.fillStyle = 'rgb(0, 200, 0)';
|
||||
break;
|
||||
case false:
|
||||
context.fillStyle = 'rgb(200, 0, 0)';
|
||||
break;
|
||||
default:
|
||||
context.fillStyle = this.color.darker(25).toString();
|
||||
if (this.cachedNormalColor) { // if flashing
|
||||
context.fillStyle = this.color.toString();
|
||||
} else {
|
||||
switch (this.value) {
|
||||
case true:
|
||||
context.fillStyle = 'rgb(0, 200, 0)';
|
||||
break;
|
||||
case false:
|
||||
context.fillStyle = 'rgb(200, 0, 0)';
|
||||
break;
|
||||
default:
|
||||
context.fillStyle = this.color.darker(25).toString();
|
||||
}
|
||||
}
|
||||
|
||||
if (progress && !this.isEmptySlot()) {
|
||||
|
@ -8680,6 +8742,7 @@ SymbolMorph.uber = Morph.prototype;
|
|||
SymbolMorph.prototype.names = [
|
||||
'square',
|
||||
'pointRight',
|
||||
'stepForward',
|
||||
'gears',
|
||||
'file',
|
||||
'fullScreen',
|
||||
|
@ -8802,6 +8865,8 @@ SymbolMorph.prototype.symbolCanvasColored = function (aColor) {
|
|||
return this.drawSymbolStop(canvas, aColor);
|
||||
case 'pointRight':
|
||||
return this.drawSymbolPointRight(canvas, aColor);
|
||||
case 'stepForward':
|
||||
return this.drawSymbolStepForward(canvas, aColor);
|
||||
case 'gears':
|
||||
return this.drawSymbolGears(canvas, aColor);
|
||||
case 'file':
|
||||
|
@ -8945,6 +9010,28 @@ SymbolMorph.prototype.drawSymbolPointRight = function (canvas, color) {
|
|||
return canvas;
|
||||
};
|
||||
|
||||
SymbolMorph.prototype.drawSymbolStepForward = function (canvas, color) {
|
||||
// answer a canvas showing a right-pointing triangle
|
||||
// followed by a vertical bar
|
||||
var ctx = canvas.getContext('2d');
|
||||
|
||||
ctx.fillStyle = color.toString();
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(0, 0);
|
||||
ctx.lineTo(canvas.width * 0.75, Math.round(canvas.height / 2));
|
||||
ctx.lineTo(0, canvas.height);
|
||||
ctx.lineTo(0, 0);
|
||||
ctx.closePath();
|
||||
ctx.fill();
|
||||
ctx.fillRect(
|
||||
canvas.width * 0.75,
|
||||
0,
|
||||
canvas.width * 0.25,
|
||||
canvas.height
|
||||
);
|
||||
return canvas;
|
||||
};
|
||||
|
||||
SymbolMorph.prototype.drawSymbolGears = function (canvas, color) {
|
||||
// answer a canvas showing gears
|
||||
var ctx = canvas.getContext('2d'),
|
||||
|
@ -10371,7 +10458,7 @@ MultiArgMorph.prototype.mouseClickLeft = function (pos) {
|
|||
this.escalateEvent('mouseClickLeft', pos);
|
||||
return;
|
||||
}
|
||||
// if the <shift> key is pressed, repeat action 5 times
|
||||
// if the <shift> key is pressed, repeat action 3 times
|
||||
var arrows = this.arrows(),
|
||||
leftArrow = arrows.children[0],
|
||||
rightArrow = arrows.children[1],
|
||||
|
@ -12188,6 +12275,13 @@ ScriptFocusMorph.prototype.insertBlock = function (block) {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
// experimental: if the inserted block has inputs, go to the first one
|
||||
if (block.inputs && block.inputs().length) {
|
||||
this.element = block;
|
||||
this.atEnd = false;
|
||||
this.nextElement();
|
||||
}
|
||||
};
|
||||
|
||||
ScriptFocusMorph.prototype.insertVariableGetter = function () {
|
||||
|
|
48
byob.js
48
byob.js
|
@ -108,7 +108,7 @@ WatcherMorph, Variable*/
|
|||
|
||||
// Global stuff ////////////////////////////////////////////////////////
|
||||
|
||||
modules.byob = '2016-July-14';
|
||||
modules.byob = '2016-September-27';
|
||||
|
||||
// Declarations
|
||||
|
||||
|
@ -150,6 +150,7 @@ function CustomBlockDefinition(spec, receiver) {
|
|||
// don't serialize (not needed for functionality):
|
||||
this.receiver = receiver || null; // for serialization only (pointer)
|
||||
this.editorDimensions = null; // a rectangle, last bounds of the editor
|
||||
this.cachedIsRecursive = null; // for automatic yielding
|
||||
}
|
||||
|
||||
// CustomBlockDefinition instantiating blocks
|
||||
|
@ -343,6 +344,26 @@ CustomBlockDefinition.prototype.parseSpec = function (spec) {
|
|||
return parts;
|
||||
};
|
||||
|
||||
CustomBlockDefinition.prototype.isDirectlyRecursive = function () {
|
||||
var myspec;
|
||||
if (this.cachedIsRecursive !== null) {
|
||||
return this.cachedIsRecursive;
|
||||
}
|
||||
if (!this.body) {
|
||||
this.cachedIsRecursive = false;
|
||||
} else {
|
||||
myspec = this.spec;
|
||||
this.cachedIsRecursive = this.body.expression.anyChild(
|
||||
function (morph) {
|
||||
return morph instanceof BlockMorph &&
|
||||
morph.definition &&
|
||||
morph.definition.spec === myspec;
|
||||
}
|
||||
);
|
||||
}
|
||||
return this.cachedIsRecursive;
|
||||
};
|
||||
|
||||
// CustomBlockDefinition picturing
|
||||
|
||||
CustomBlockDefinition.prototype.scriptsPicture = function () {
|
||||
|
@ -769,7 +790,7 @@ CustomCommandBlockMorph.prototype.attachTargets = function () {
|
|||
};
|
||||
|
||||
CustomCommandBlockMorph.prototype.isInUse = function () {
|
||||
// anser true if an instance of my definition is found
|
||||
// answer true if an instance of my definition is found
|
||||
// in any of my receiver's scripts or block definitions
|
||||
var def = this.definition,
|
||||
ide = this.receiver().parentThatIsA(IDE_Morph);
|
||||
|
@ -1558,7 +1579,7 @@ BlockDialogMorph.prototype.createScopeButtons = function () {
|
|||
var myself = this;
|
||||
|
||||
this.addScopeButton(
|
||||
function () {myself.setScope('gobal'); },
|
||||
function () {myself.setScope('global'); },
|
||||
"for all sprites",
|
||||
function () {return myself.isGlobal; }
|
||||
);
|
||||
|
@ -1591,7 +1612,7 @@ BlockDialogMorph.prototype.addScopeButton = function (action, label, query) {
|
|||
|
||||
|
||||
BlockDialogMorph.prototype.setScope = function (varType) {
|
||||
this.isGlobal = (varType === 'gobal');
|
||||
this.isGlobal = (varType === 'global');
|
||||
this.scopes.children.forEach(function (c) {
|
||||
c.refresh();
|
||||
});
|
||||
|
@ -1754,7 +1775,9 @@ function BlockEditorMorph(definition, target) {
|
|||
}
|
||||
|
||||
BlockEditorMorph.prototype.init = function (definition, target) {
|
||||
var scripts, proto, scriptsFrame, block, comment, myself = this;
|
||||
var scripts, proto, scriptsFrame, block, comment, myself = this,
|
||||
isLive = Process.prototype.enableLiveCoding ||
|
||||
Process.prototype.enableSingleStepping;
|
||||
|
||||
// additional properties:
|
||||
this.definition = definition;
|
||||
|
@ -1789,7 +1812,9 @@ BlockEditorMorph.prototype.init = function (definition, target) {
|
|||
comment.block = proto;
|
||||
}
|
||||
if (definition.body !== null) {
|
||||
proto.nextBlock(definition.body.expression.fullCopy());
|
||||
proto.nextBlock(isLive ? definition.body.expression
|
||||
: definition.body.expression.fullCopy()
|
||||
);
|
||||
}
|
||||
scripts.add(proto);
|
||||
proto.fixBlockColor(null, true);
|
||||
|
@ -1819,8 +1844,10 @@ BlockEditorMorph.prototype.init = function (definition, target) {
|
|||
|
||||
this.addBody(scriptsFrame);
|
||||
this.addButton('ok', 'OK');
|
||||
this.addButton('updateDefinition', 'Apply');
|
||||
this.addButton('cancel', 'Cancel');
|
||||
if (!isLive) {
|
||||
this.addButton('updateDefinition', 'Apply');
|
||||
this.addButton('cancel', 'Cancel');
|
||||
}
|
||||
|
||||
this.setExtent(new Point(375, 300)); // normal initial extent
|
||||
this.fixLayout();
|
||||
|
@ -1962,6 +1989,7 @@ BlockEditorMorph.prototype.updateDefinition = function () {
|
|||
this.definition.variableNames = this.variableNames();
|
||||
this.definition.scripts = [];
|
||||
this.definition.editorDimensions = this.bounds.copy();
|
||||
this.definition.cachedIsRecursive = null; // flush the cache, don't update
|
||||
|
||||
this.body.contents.children.forEach(function (morph) {
|
||||
if (morph instanceof PrototypeHatBlockMorph) {
|
||||
|
@ -3282,7 +3310,7 @@ VariableDialogMorph.prototype.createTypeButtons = function () {
|
|||
var myself = this;
|
||||
|
||||
this.addTypeButton(
|
||||
function () {myself.setType('gobal'); },
|
||||
function () {myself.setType('global'); },
|
||||
"for all sprites",
|
||||
function () {return myself.isGlobal; }
|
||||
);
|
||||
|
@ -3297,7 +3325,7 @@ VariableDialogMorph.prototype.addTypeButton
|
|||
= BlockDialogMorph.prototype.addTypeButton;
|
||||
|
||||
VariableDialogMorph.prototype.setType = function (varType) {
|
||||
this.isGlobal = (varType === 'gobal');
|
||||
this.isGlobal = (varType === 'global');
|
||||
this.types.children.forEach(function (c) {
|
||||
c.refresh();
|
||||
});
|
||||
|
|
101
gui.js
101
gui.js
|
@ -68,11 +68,11 @@ fontHeight, hex_sha512, sb, CommentMorph, CommandBlockMorph,
|
|||
BlockLabelPlaceHolderMorph, Audio, SpeechBubbleMorph, ScriptFocusMorph,
|
||||
XML_Element, WatcherMorph, BlockRemovalDialogMorph, saveAs, TableMorph,
|
||||
isSnapObject, isRetinaEnabled, disableRetinaSupport, enableRetinaSupport,
|
||||
isRetinaSupported*/
|
||||
isRetinaSupported, SliderMorph*/
|
||||
|
||||
// Global stuff ////////////////////////////////////////////////////////
|
||||
|
||||
modules.gui = '2016-August-12';
|
||||
modules.gui = '2016-October-27';
|
||||
|
||||
// Declarations
|
||||
|
||||
|
@ -536,6 +536,7 @@ IDE_Morph.prototype.createControlBar = function () {
|
|||
// assumes the logo has already been created
|
||||
var padding = 5,
|
||||
button,
|
||||
slider,
|
||||
stopButton,
|
||||
pauseButton,
|
||||
startButton,
|
||||
|
@ -718,6 +719,23 @@ IDE_Morph.prototype.createControlBar = function () {
|
|||
this.controlBar.add(startButton);
|
||||
this.controlBar.startButton = startButton;
|
||||
|
||||
// steppingSlider
|
||||
slider = new SliderMorph(
|
||||
61,
|
||||
1,
|
||||
Process.prototype.flashTime * 100 + 1,
|
||||
6,
|
||||
'horizontal'
|
||||
);
|
||||
slider.action = function (num) {
|
||||
Process.prototype.flashTime = (num - 1) / 100;
|
||||
myself.controlBar.refreshResumeSymbol();
|
||||
};
|
||||
slider.alpha = MorphicPreferences.isFlat ? 0.1 : 0.3;
|
||||
slider.setExtent(new Point(50, 14));
|
||||
this.controlBar.add(slider);
|
||||
this.controlBar.steppingSlider = slider;
|
||||
|
||||
// projectButton
|
||||
button = new PushButtonMorph(
|
||||
this,
|
||||
|
@ -814,6 +832,9 @@ IDE_Morph.prototype.createControlBar = function () {
|
|||
}
|
||||
);
|
||||
|
||||
slider.setCenter(myself.controlBar.center());
|
||||
slider.setRight(stageSizeButton.left() - padding);
|
||||
|
||||
settingsButton.setCenter(myself.controlBar.center());
|
||||
settingsButton.setLeft(this.left());
|
||||
|
||||
|
@ -823,9 +844,41 @@ IDE_Morph.prototype.createControlBar = function () {
|
|||
projectButton.setCenter(myself.controlBar.center());
|
||||
projectButton.setRight(cloudButton.left() - padding);
|
||||
|
||||
this.refreshSlider();
|
||||
this.updateLabel();
|
||||
};
|
||||
|
||||
this.controlBar.refreshSlider = function () {
|
||||
if (Process.prototype.enableSingleStepping && !myself.isAppMode) {
|
||||
slider.drawNew();
|
||||
slider.show();
|
||||
} else {
|
||||
slider.hide();
|
||||
}
|
||||
this.refreshResumeSymbol();
|
||||
};
|
||||
|
||||
this.controlBar.refreshResumeSymbol = function () {
|
||||
var pauseSymbols;
|
||||
if (Process.prototype.enableSingleStepping &&
|
||||
Process.prototype.flashTime > 0.5) {
|
||||
myself.stage.threads.pauseAll(myself.stage);
|
||||
pauseSymbols = [
|
||||
new SymbolMorph('pause', 12),
|
||||
new SymbolMorph('stepForward', 14)
|
||||
];
|
||||
} else {
|
||||
pauseSymbols = [
|
||||
new SymbolMorph('pause', 12),
|
||||
new SymbolMorph('pointRight', 14)
|
||||
];
|
||||
}
|
||||
pauseButton.labelString = pauseSymbols;
|
||||
pauseButton.createLabel();
|
||||
pauseButton.fixLayout();
|
||||
pauseButton.refresh();
|
||||
};
|
||||
|
||||
this.controlBar.updateLabel = function () {
|
||||
var suffix = myself.world().isDevMode ?
|
||||
' - ' + localize('development mode') : '';
|
||||
|
@ -967,6 +1020,7 @@ IDE_Morph.prototype.createPalette = function (forSearching) {
|
|||
}
|
||||
this.palette.isDraggable = false;
|
||||
this.palette.acceptsDrops = true;
|
||||
this.palette.enableAutoScrolling = false;
|
||||
this.palette.contents.acceptsDrops = false;
|
||||
|
||||
this.palette.reactToDropOf = function (droppedMorph) {
|
||||
|
@ -1767,6 +1821,11 @@ IDE_Morph.prototype.toggleVariableFrameRate = function () {
|
|||
}
|
||||
};
|
||||
|
||||
IDE_Morph.prototype.toggleSingleStepping = function () {
|
||||
this.stage.threads.toggleSingleStepping();
|
||||
this.controlBar.refreshSlider();
|
||||
};
|
||||
|
||||
IDE_Morph.prototype.startFastTracking = function () {
|
||||
this.stage.isFastTracked = true;
|
||||
this.stage.fps = 0;
|
||||
|
@ -2551,6 +2610,14 @@ IDE_Morph.prototype.settingsMenu = function () {
|
|||
'EXPERIMENTAL! check to enable\n live custom control structures',
|
||||
true
|
||||
);
|
||||
addPreference(
|
||||
'Visible stepping',
|
||||
'toggleSingleStepping',
|
||||
Process.prototype.enableSingleStepping,
|
||||
'uncheck to turn off\nvisible stepping',
|
||||
'check to turn on\n visible stepping (slow)',
|
||||
false
|
||||
);
|
||||
menu.addLine(); // everything below this line is stored in the project
|
||||
addPreference(
|
||||
'Thread safe scripts',
|
||||
|
@ -2982,7 +3049,7 @@ IDE_Morph.prototype.aboutSnap = function () {
|
|||
module, btn1, btn2, btn3, btn4, licenseBtn, translatorsBtn,
|
||||
world = this.world();
|
||||
|
||||
aboutTxt = 'Snap! 4.0.8.7\nBuild Your Own Blocks\n\n'
|
||||
aboutTxt = 'Snap! 4.0.9\nBuild Your Own Blocks\n\n'
|
||||
+ 'Copyright \u24B8 2016 Jens M\u00F6nig and '
|
||||
+ 'Brian Harvey\n'
|
||||
+ 'jens@moenig.org, bh@cs.berkeley.edu\n\n'
|
||||
|
@ -3013,7 +3080,10 @@ IDE_Morph.prototype.aboutSnap = function () {
|
|||
|
||||
+ 'You should have received a copy of the\n'
|
||||
+ 'GNU Affero General Public License along with this program.\n'
|
||||
+ 'If not, see http://www.gnu.org/licenses/';
|
||||
+ 'If not, see http://www.gnu.org/licenses/\n\n'
|
||||
|
||||
+ 'Want to use Snap! but scared by the open-source license?\n'
|
||||
+ 'Get in touch with us, we\'ll make it work.';
|
||||
|
||||
creditsTxt = localize('Contributors')
|
||||
+ '\n\nNathan Dinsmore: Saving/Loading, Snap-Logo Design, '
|
||||
|
@ -3021,8 +3091,10 @@ IDE_Morph.prototype.aboutSnap = function () {
|
|||
+ '\nKartik Chandra: Paint Editor'
|
||||
+ '\nMichael Ball: Time/Date UI, many bugfixes'
|
||||
+ '\nBartosz Leper: Retina Display Support'
|
||||
+ '\nBernat Romagosa: Countless contributions'
|
||||
+ '\n"Ava" Yuan Yuan, Dylan Servilla: Graphic Effects'
|
||||
+ '\nKyle Hotchkiss: Block search design'
|
||||
+ '\nBrian Broll: Many bugfixes and optimizations'
|
||||
+ '\nIan Reynolds: UI Design, Event Bindings, '
|
||||
+ 'Sound primitives'
|
||||
+ '\nIvan Motyashov: Initial Squeak Porting'
|
||||
|
@ -5440,16 +5512,19 @@ ProjectDialogMorph.prototype.setSource = function (source) {
|
|||
if (myself.task === 'open') {
|
||||
|
||||
src = localStorage['-snap-project-' + item.name];
|
||||
xml = myself.ide.serializer.parse(src);
|
||||
|
||||
myself.notesText.text = xml.childNamed('notes').contents
|
||||
|| '';
|
||||
myself.notesText.drawNew();
|
||||
myself.notesField.contents.adjustBounds();
|
||||
myself.preview.texture = xml.childNamed('thumbnail').contents
|
||||
|| null;
|
||||
myself.preview.cachedTexture = null;
|
||||
myself.preview.drawNew();
|
||||
if (src) {
|
||||
xml = myself.ide.serializer.parse(src);
|
||||
|
||||
myself.notesText.text = xml.childNamed('notes').contents
|
||||
|| '';
|
||||
myself.notesText.drawNew();
|
||||
myself.notesField.contents.adjustBounds();
|
||||
myself.preview.texture =
|
||||
xml.childNamed('thumbnail').contents || null;
|
||||
myself.preview.cachedTexture = null;
|
||||
myself.preview.drawNew();
|
||||
}
|
||||
}
|
||||
myself.edit();
|
||||
};
|
||||
|
|
86
history.txt
86
history.txt
|
@ -3004,3 +3004,89 @@ http://snap.berkeley.edu/run#cloud:Username=jens&ProjectName=rotation
|
|||
* Morphic: replace deprecated KeyboardEvent.keyIdentifier with .key
|
||||
|
||||
== v4.0.8.7 ====
|
||||
|
||||
*** in development ***
|
||||
|
||||
160915
|
||||
------
|
||||
* new single stepping feature (like Scratch 1.4) with flashing blocks
|
||||
* slider for single-stepping speed
|
||||
* pausing now flashes the currently active blocks
|
||||
|
||||
160916
|
||||
------
|
||||
* enable single stepping for clone-scripts w. multiple blocks flashing per script
|
||||
* enable single stepping for custom block definitions
|
||||
* Objects: fixed #1410 (duplicating a sprite does not duplicate its sounds)
|
||||
|
||||
160918
|
||||
------
|
||||
* Treat single-stepping as thread safe (reverted on 160923)
|
||||
* Allow user to trigger one step at a time, both in normal and single-stepping mode
|
||||
|
||||
160919
|
||||
------
|
||||
* new “stepForward” symbol
|
||||
* dragging the single-step speed slider all the way to the left turns the “resume” side of the “pause” button into “stepForward”
|
||||
|
||||
160920
|
||||
------
|
||||
* atomic synching of single-stepping
|
||||
|
||||
160921
|
||||
------
|
||||
* remove shift-click-to-forward-one-frame option for the “resume” button
|
||||
|
||||
160922
|
||||
------
|
||||
* renamed “single stepping” to “visible stepping”, thanks, Brian!
|
||||
* updated German translation
|
||||
|
||||
160923
|
||||
------
|
||||
* custom block execution: only yield if directly recursive and unwrapped (“speed up”)
|
||||
* new feature: “wait 0” or “wait <empty>” now yields once, unless warped
|
||||
* revert treating visual stepping as thread safe, because of music scheduling
|
||||
|
||||
160924
|
||||
------
|
||||
* don’t update the recursion cache when updating a custom block definition
|
||||
|
||||
160929
|
||||
------
|
||||
* Objects: fixed #1437
|
||||
|
||||
161007
|
||||
------
|
||||
* Blocks: [Keyboard-Entry] if an inserted block has inputs, go to the first one
|
||||
|
||||
161010
|
||||
------
|
||||
* Morphic: configure autoscrolling
|
||||
* GUI: suppress autoscrolling for the palette and the project dialog
|
||||
|
||||
161011
|
||||
------
|
||||
* Blocks: make sure to fix multi-args when deleting a custom reporter definition
|
||||
|
||||
161011
|
||||
------
|
||||
* Objects: fixed #1456 (collect message names from all scripts, including custom block definitions)
|
||||
|
||||
161020
|
||||
------
|
||||
* Blocks: Tweak Keyboard-Entry
|
||||
|
||||
161021
|
||||
------
|
||||
* Threads: Fixed #1422
|
||||
|
||||
161024
|
||||
------
|
||||
* Text Editing Tweaks, thanks, Bernat!!
|
||||
* Store: fixed #1472
|
||||
* Threads: Tweak continuations
|
||||
|
||||
161027
|
||||
------
|
||||
== v4.0.9 ====
|
||||
|
|
|
@ -185,7 +185,7 @@ SnapTranslator.dict.de = {
|
|||
'translator_e-mail':
|
||||
'jens@moenig.org', // optional
|
||||
'last_changed':
|
||||
'2016-07-12', // this, too, will appear in the Translators tab
|
||||
'2016-10-27', // this, too, will appear in the Translators tab
|
||||
|
||||
// GUI
|
||||
// control bar:
|
||||
|
@ -821,6 +821,8 @@ SnapTranslator.dict.de = {
|
|||
'Tabellenunterstützung',
|
||||
'Table lines':
|
||||
'Tabellen mit Linien',
|
||||
'Visible stepping':
|
||||
'Programmausführung verfolgen',
|
||||
'Thread safe scripts':
|
||||
'Threadsicherheit',
|
||||
'uncheck to allow\nscript reentrance':
|
||||
|
|
340
lang-fr.js
340
lang-fr.js
|
@ -1,27 +1,27 @@
|
|||
/*
|
||||
|
||||
lang-de.js
|
||||
lang-de.js
|
||||
|
||||
German translation for SNAP!
|
||||
German translation for SNAP!
|
||||
|
||||
written by Jens Mönig
|
||||
written by Jens Mönig
|
||||
|
||||
Copyright (C) 2012 by Jens Mönig
|
||||
Copyright (C) 2012 by Jens Mönig
|
||||
|
||||
This file is part of Snap!.
|
||||
This file is part of Snap!.
|
||||
|
||||
Snap! is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation, either version 3 of
|
||||
the License, or (at your option) any later version.
|
||||
Snap! is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation, either version 3 of
|
||||
the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
|
||||
|
||||
|
@ -175,8 +175,10 @@ SnapTranslator.dict.fr = {
|
|||
à \u00E0
|
||||
É \u00C9
|
||||
è \u00E8
|
||||
é \u00E9
|
||||
ê \u00EA
|
||||
ç \u00E7
|
||||
ï \u00EF
|
||||
ô \u00F4
|
||||
ù \u00F9
|
||||
° \u00B0
|
||||
|
@ -195,7 +197,7 @@ SnapTranslator.dict.fr = {
|
|||
'translator_e-mail':
|
||||
'i.scool@mac.com', // optional
|
||||
'last_changed':
|
||||
'2016-01-27', // this, too, will appear in the Translators tab
|
||||
'2016-10-27', // this, too, will appear in the Translators tab
|
||||
|
||||
// GUI
|
||||
// control bar:
|
||||
|
@ -431,8 +433,8 @@ SnapTranslator.dict.fr = {
|
|||
'Quand %keyHat est press\u00E9',
|
||||
'when I am clicked':
|
||||
'Quand je suis press\u00E9 ',
|
||||
'when I am %interaction':
|
||||
'Quand je suis %interaction',
|
||||
'when I am %interaction':
|
||||
'Quand je suis %interaction',
|
||||
'when I receive %msgHat':
|
||||
'Quand je re\u00E7ois %msgHat',
|
||||
'broadcast %msg':
|
||||
|
@ -461,10 +463,10 @@ SnapTranslator.dict.fr = {
|
|||
'arr\u00EAter le bloc',
|
||||
'stop script':
|
||||
'arr\u00EAter le script',
|
||||
'stop %stopOthersChoices':
|
||||
'arr\u00EAter %stopOthersChoices',
|
||||
'stop %stopChoices':
|
||||
'arr\u00EAter %stopChoices',
|
||||
'stop %stopOthersChoices':
|
||||
'arr\u00EAter %stopOthersChoices',
|
||||
'stop %stopChoices':
|
||||
'arr\u00EAter %stopChoices',
|
||||
'stop all %stop':
|
||||
'arr\u00EAter tout %stop',
|
||||
'run %cmdRing %inputs':
|
||||
|
@ -489,14 +491,14 @@ SnapTranslator.dict.fr = {
|
|||
'supprime ce clone',
|
||||
'pause all %pause':
|
||||
'mettre en pause %pause',
|
||||
'all but this script':
|
||||
'tout sauf ce script',
|
||||
'other scripts in sprite':
|
||||
'les autres scripts de ce lutin',
|
||||
'this script':
|
||||
'ce script',
|
||||
'this block':
|
||||
'ce bloc',
|
||||
'all but this script':
|
||||
'tout sauf ce script',
|
||||
'other scripts in sprite':
|
||||
'les autres scripts de ce lutin',
|
||||
'this script':
|
||||
'ce script',
|
||||
'this block':
|
||||
'ce bloc',
|
||||
|
||||
// sensing:
|
||||
'touching %col ?':
|
||||
|
@ -527,6 +529,8 @@ SnapTranslator.dict.fr = {
|
|||
'chronom\u00E8tre',
|
||||
'%att of %spr':
|
||||
'%att de %spr',
|
||||
'my %get':
|
||||
'attribut %get',
|
||||
'http:// %s':
|
||||
'http:// %s',
|
||||
'turbo mode?':
|
||||
|
@ -671,6 +675,8 @@ SnapTranslator.dict.fr = {
|
|||
'Exporter le projet comme texte...',
|
||||
'Export project...':
|
||||
'Exporter le projet...',
|
||||
'save project data as XML\nto your downloads folder':
|
||||
'sauvegarder le projet au\nformat XML dans votre\ndossier T\u00E9l\u00E9chargements',
|
||||
'show project data as XML\nin a new browser window':
|
||||
'ouvrir le projet au format XML\ndans une nouvelle fen\u00EAtre de votre navigateur',
|
||||
'Export blocks...':
|
||||
|
@ -722,7 +728,7 @@ SnapTranslator.dict.fr = {
|
|||
+ 'lors du glisser-d\u00E9poser d\u0027un reporter',
|
||||
'uncheck to allow dropped\nreporters to kick out others':
|
||||
'd\u00E9cocher pour ne pas pr\u00E9f\u00E9rer des entr\u00E9es vides \n'
|
||||
+ 'lors du glisser-d\u00E9poser d\u0027un reporter',
|
||||
+ 'lors du glisser-d\u00E9poser d\u0027un reporter',
|
||||
'Long form input dialog':
|
||||
'Bo\u00EEte d\u0027entr\u00E9e en mode d\u00E9taill\u00E9',
|
||||
'check to always show slot\ntypes in the input dialog':
|
||||
|
@ -745,10 +751,10 @@ SnapTranslator.dict.fr = {
|
|||
'Cliquetis',
|
||||
'uncheck to turn\nblock clicking\nsound off':
|
||||
'd\u00E9cocher pour d\u00E9sactiver le cliquetis \n'
|
||||
+'lors de l\u0027embo\u00EEtement des blocs' ,
|
||||
+'lors de l\u0027embo\u00EEtement des blocs' ,
|
||||
'check to turn\nblock clicking\nsound on':
|
||||
'cocher pour activer le cliquetis \n'
|
||||
+'lors de l\u0027embo\u00EEtement des blocs',
|
||||
+'lors de l\u0027embo\u00EEtement des blocs',
|
||||
'Turbo mode':
|
||||
'Mode turbo',
|
||||
'check to prioritize\nscript execution':
|
||||
|
@ -760,7 +766,7 @@ SnapTranslator.dict.fr = {
|
|||
'check for alternative\nGUI design':
|
||||
'cocher pour un style d\'interface alternatif',
|
||||
'uncheck for default\nGUI design':
|
||||
'd\u00E9cocher pour le style classique d\'interface',
|
||||
'd\u00E9cocher pour le style classique d\'interface',
|
||||
'Keyboard Editing':
|
||||
'\u00C9dition au clavier',
|
||||
'uncheck to disable\nkeyboard editing support':
|
||||
|
@ -771,10 +777,10 @@ SnapTranslator.dict.fr = {
|
|||
'Scripts réentrants',
|
||||
'check to disallow\nscript reentrance':
|
||||
'cocher pour interdire\n la r\u00E9entrance des scripts\n'
|
||||
+ 'et les ex\u00E9cuter s\u00E9par\u00E9ment',
|
||||
+ 'et les ex\u00E9cuter s\u00E9par\u00E9ment',
|
||||
'uncheck to allow\nscript reentrance':
|
||||
'd\u00E9cocher pour permettre\n la r\u00E9entrance des scripts\n'
|
||||
+ 'o\u00F9 certains s\'ex\u00E9cutent en paral\u00E8lle',
|
||||
+ 'o\u00F9 certains s\'ex\u00E9cutent en paral\u00E8lle',
|
||||
'Prefer smooth animations':
|
||||
'Vitesse d\'animation fixe',
|
||||
'uncheck for greater speed\nat variable frame rates':
|
||||
|
@ -884,6 +890,12 @@ SnapTranslator.dict.fr = {
|
|||
'Oui',
|
||||
'No':
|
||||
'Non',
|
||||
'Open':
|
||||
'Ouvrir',
|
||||
'Browser':
|
||||
'Navigateur',
|
||||
'Examples':
|
||||
'Exemples',
|
||||
|
||||
// help
|
||||
'Help':
|
||||
|
@ -1020,8 +1032,8 @@ SnapTranslator.dict.fr = {
|
|||
'tabulations',
|
||||
'cr':
|
||||
'retours de ligne',
|
||||
'letter':
|
||||
'lettres',
|
||||
'letter':
|
||||
'lettres',
|
||||
|
||||
// About Snap
|
||||
'About Snap':
|
||||
|
@ -1095,8 +1107,28 @@ SnapTranslator.dict.fr = {
|
|||
'Vide',
|
||||
|
||||
// graphical effects
|
||||
'color':
|
||||
'couleur',
|
||||
'fisheye':
|
||||
'fisheye',
|
||||
'whirl':
|
||||
'tourbillon',
|
||||
'pixelate':
|
||||
'pixelisation',
|
||||
'mosaic':
|
||||
'mosa\u00EFque',
|
||||
'saturation':
|
||||
'saturation',
|
||||
'brightness':
|
||||
'luminosit\u00E9',
|
||||
'ghost':
|
||||
'transparence',
|
||||
'negative':
|
||||
'n\u00E9gatif',
|
||||
'comic':
|
||||
'moir\u00E9',
|
||||
'confetti':
|
||||
'confetti',
|
||||
|
||||
// keys
|
||||
'space':
|
||||
|
@ -1230,145 +1262,145 @@ SnapTranslator.dict.fr = {
|
|||
'any':
|
||||
'n\u0027importe quel',
|
||||
|
||||
// miscellaneous
|
||||
'find blocks...':
|
||||
'chercher des blocs...',
|
||||
'hide primitives':
|
||||
'cacher les primitives',
|
||||
'show primitives':
|
||||
'montrer les primitives',
|
||||
'Login...':
|
||||
'Connexion...',
|
||||
'Signup...':
|
||||
'S\u0027enregistrer...',
|
||||
'Reset Password...':
|
||||
'Remise \u00E0 z\u00E9ro du mot de passe...',
|
||||
'show all':
|
||||
'tout montrer',
|
||||
'pic...':
|
||||
'image...',
|
||||
'open a new window\nwith a picture of the stage':
|
||||
'ouvre une nouvelle fen\u00EAtre\navec une image de la sc\u00E8ne',
|
||||
'scripts pic...':
|
||||
'image des scripts...',
|
||||
'open a new window\nwith a picture of all scripts':
|
||||
'ouvre une nouvelle fen\u00EAtre\navec une image de tous les scripts',
|
||||
'Stage size...':
|
||||
'Taille de la sc\u00E8ne...',
|
||||
'Zoom blocks...':
|
||||
'Agrandir les blocs...',
|
||||
// miscellaneous
|
||||
'find blocks...':
|
||||
'chercher des blocs...',
|
||||
'hide primitives':
|
||||
'cacher les primitives',
|
||||
'show primitives':
|
||||
'montrer les primitives',
|
||||
'Login...':
|
||||
'Connexion...',
|
||||
'Signup...':
|
||||
'S\u0027enregistrer...',
|
||||
'Reset Password...':
|
||||
'Remise \u00E0 z\u00E9ro du mot de passe...',
|
||||
'show all':
|
||||
'tout montrer',
|
||||
'pic...':
|
||||
'image...',
|
||||
'open a new window\nwith a picture of the stage':
|
||||
'ouvre une nouvelle fen\u00EAtre\navec une image de la sc\u00E8ne',
|
||||
'scripts pic...':
|
||||
'image des scripts...',
|
||||
'open a new window\nwith a picture of all scripts':
|
||||
'ouvre une nouvelle fen\u00EAtre\navec une image de tous les scripts',
|
||||
'Stage size...':
|
||||
'Taille de la sc\u00E8ne...',
|
||||
'Zoom blocks...':
|
||||
'Agrandir les blocs...',
|
||||
|
||||
'Plain prototype labels':
|
||||
'\u00C9tiquettes simples de d\u00E9finition',
|
||||
'uncheck to always show (+) symbols\nin block prototype labels':
|
||||
'd\u00E9cocher pour montrer en permanance le symbole (+)\ndans les \u00e9tiquettes de d\u00E9finition de bloc',
|
||||
'check to hide (+) symbols\nin block prototype labels':
|
||||
'cocher pour cacher le symbole (+)\ndans les \u00e9tiquettes de d\u00E9finition de bloc',
|
||||
'Plain prototype labels':
|
||||
'\u00C9tiquettes simples de d\u00E9finition',
|
||||
'uncheck to always show (+) symbols\nin block prototype labels':
|
||||
'd\u00E9cocher pour montrer en permanance le symbole (+)\ndans les \u00e9tiquettes de d\u00E9finition de bloc',
|
||||
'check to hide (+) symbols\nin block prototype labels':
|
||||
'cocher pour cacher le symbole (+)\ndans les \u00e9tiquettes de d\u00E9finition de bloc',
|
||||
|
||||
'check for flat ends of lines':
|
||||
'cocher pour dessiner des fins de ligne plates',
|
||||
'uncheck for round ends of lines':
|
||||
'd\u00E9cocher pour dessiner des fins de lignes arrondies',
|
||||
'Flat line ends':
|
||||
'Fins de ligne plates',
|
||||
'check for flat ends of lines':
|
||||
'cocher pour dessiner des fins de ligne plates',
|
||||
'uncheck for round ends of lines':
|
||||
'd\u00E9cocher pour dessiner des fins de lignes arrondies',
|
||||
'Flat line ends':
|
||||
'Fins de ligne plates',
|
||||
|
||||
'Codification support':
|
||||
'Support de la \u00AB codification \u00BB',
|
||||
'uncheck to disable\nblock to text mapping features':
|
||||
'd\u00E9cocher pour d\u00E9activer\nla fonction de transformation :\nbloc vers texte',
|
||||
'check for block\nto text mapping features':
|
||||
'cocher pour activer\nla fonction de transformation :\nbloc vers texte',
|
||||
'Codification support':
|
||||
'Support de la \u00AB codification \u00BB',
|
||||
'uncheck to disable\nblock to text mapping features':
|
||||
'd\u00E9cocher pour d\u00E9activer\nla fonction de transformation :\nbloc vers texte',
|
||||
'check for block\nto text mapping features':
|
||||
'cocher pour activer\nla fonction de transformation :\nbloc vers texte',
|
||||
|
||||
'Inheritance support':
|
||||
'Support de l\'h\u00E9ritage',
|
||||
|
||||
'current %dates':
|
||||
'date courante %dates',
|
||||
'year':
|
||||
'current %dates':
|
||||
'date courante %dates',
|
||||
'year':
|
||||
'ann\u00E9e',
|
||||
'month':
|
||||
'month':
|
||||
'mois',
|
||||
'date':
|
||||
'date':
|
||||
'jour',
|
||||
'hour':
|
||||
'hour':
|
||||
'heure',
|
||||
'minute':
|
||||
'minute':
|
||||
'minute',
|
||||
'second':
|
||||
'second':
|
||||
'seconde',
|
||||
'time in milliseconds':
|
||||
'heure en millisecondes',
|
||||
'day of week':
|
||||
'jour de la semaine',
|
||||
'time in milliseconds':
|
||||
'heure en millisecondes',
|
||||
'day of week':
|
||||
'jour de la semaine',
|
||||
|
||||
'brightness':
|
||||
'luminosit\u00E9',
|
||||
'transparence':
|
||||
'transparence',
|
||||
'negative':
|
||||
'n\u00E9gatif',
|
||||
'comic':
|
||||
'bande dessin\u00E9e',
|
||||
'brightness':
|
||||
'luminosit\u00E9',
|
||||
'transparence':
|
||||
'transparence',
|
||||
'negative':
|
||||
'n\u00E9gatif',
|
||||
'comic':
|
||||
'bande dessin\u00E9e',
|
||||
|
||||
'clicked':
|
||||
'cliqu\u00E9',
|
||||
'pressed':
|
||||
'press\u00E9',
|
||||
'dropped':
|
||||
'd\u00E9pos\u00E9',
|
||||
'mouse-entered':
|
||||
'survol\u00E9',
|
||||
'mouse-departed':
|
||||
'quitt\u00E9',
|
||||
'clicked':
|
||||
'cliqu\u00E9',
|
||||
'pressed':
|
||||
'press\u00E9',
|
||||
'dropped':
|
||||
'd\u00E9pos\u00E9',
|
||||
'mouse-entered':
|
||||
'survol\u00E9',
|
||||
'mouse-departed':
|
||||
'quitt\u00E9',
|
||||
'when %b':
|
||||
'Quand %b',
|
||||
|
||||
'JavaScript function ( %mult%s ) { %code }':
|
||||
'fonction JavaScript ( %mult%s ) { %code }',
|
||||
'JavaScript function ( %mult%s ) { %code }':
|
||||
'fonction JavaScript ( %mult%s ) { %code }',
|
||||
|
||||
|
||||
// Copy / Paste
|
||||
'Press CTRL+C one more time to effectively copy to clipboard.':
|
||||
'Taper une nouvelle fois sur CTRL+C pour copier effectivement vers le presse-papier.',
|
||||
'Press CTRL+V one more time to effectively paste from clipboard.':
|
||||
'Taper une nouvelle fois sur CTRL+V pour coller effectivement depuis le presse-papier.',
|
||||
'Press CTRL+X one more time to effectively cut to clipboard.':
|
||||
'Taper une nouvelle fois sur CTRL+X pour couper effectivement vers le presse-papier.',
|
||||
// Copy / Paste
|
||||
'Press CTRL+C one more time to effectively copy to clipboard.':
|
||||
'Taper une nouvelle fois sur CTRL+C pour copier effectivement vers le presse-papier.',
|
||||
'Press CTRL+V one more time to effectively paste from clipboard.':
|
||||
'Taper une nouvelle fois sur CTRL+V pour coller effectivement depuis le presse-papier.',
|
||||
'Press CTRL+X one more time to effectively cut to clipboard.':
|
||||
'Taper une nouvelle fois sur CTRL+X pour couper effectivement vers le presse-papier.',
|
||||
|
||||
// Paint.js
|
||||
'undo':
|
||||
// Paint.js
|
||||
'undo':
|
||||
'd\u00E9faire',
|
||||
'Paintbrush tool\n(free draw)':
|
||||
'Pinceau\n(dessin \u00E0 main lev\u00E9e)',
|
||||
'Stroked Rectangle\n(shift: square)':
|
||||
'Rectangle\n(Maj : carr\u00E9)',
|
||||
'Stroked Ellipse\n(shift: circle)':
|
||||
'Ellipse\n(Maj : cercle)',
|
||||
'Eraser tool':
|
||||
'Gomme',
|
||||
'Set the rotation center':
|
||||
'Fixer le centre de rotation',
|
||||
'Line tool\n(shift: vertical/horizontal)':
|
||||
'Ligne\n(Maj: verticale/horizontale)',
|
||||
'Filled Rectangle\n(shift: square)':
|
||||
'Rectangle plein\n(Maj: carr\u00E9)',
|
||||
'Filled Ellipse\n(shift: circle)':
|
||||
'Ellipse pleine\n(Maj: cercle)',
|
||||
'Fill a region':
|
||||
'Remplir une r\u00E9gion',
|
||||
'Pipette tool\n(pick a color anywhere)':
|
||||
'Pipette\n(s\u00E9lectionnez une couleur n\u0027importe o\u00F9)',
|
||||
'grow':
|
||||
'Paintbrush tool\n(free draw)':
|
||||
'Pinceau\n(dessin \u00E0 main lev\u00E9e)',
|
||||
'Stroked Rectangle\n(shift: square)':
|
||||
'Rectangle\n(Maj : carr\u00E9)',
|
||||
'Stroked Ellipse\n(shift: circle)':
|
||||
'Ellipse\n(Maj : cercle)',
|
||||
'Eraser tool':
|
||||
'Gomme',
|
||||
'Set the rotation center':
|
||||
'Fixer le centre de rotation',
|
||||
'Line tool\n(shift: vertical/horizontal)':
|
||||
'Ligne\n(Maj: verticale/horizontale)',
|
||||
'Filled Rectangle\n(shift: square)':
|
||||
'Rectangle plein\n(Maj: carr\u00E9)',
|
||||
'Filled Ellipse\n(shift: circle)':
|
||||
'Ellipse pleine\n(Maj: cercle)',
|
||||
'Fill a region':
|
||||
'Remplir une r\u00E9gion',
|
||||
'Pipette tool\n(pick a color anywhere)':
|
||||
'Pipette\n(s\u00E9lectionnez une couleur n\u0027importe o\u00F9)',
|
||||
'grow':
|
||||
'agrandir',
|
||||
'shrink':
|
||||
'shrink':
|
||||
'r\u00E9duire',
|
||||
'flip \u2194':
|
||||
'miroir \u2194',
|
||||
'flip \u2195':
|
||||
'miroir \u2195',
|
||||
'Brush size':
|
||||
'Taille de pinceau',
|
||||
'Constrain proportions of shapes?\n(you can also hold shift)':
|
||||
'Contraindre les proportions de la forme ?\n(vous pouvez aussi maintenir appuy\u00E9 Maj)'
|
||||
'flip \u2194':
|
||||
'miroir \u2194',
|
||||
'flip \u2195':
|
||||
'miroir \u2195',
|
||||
'Brush size':
|
||||
'Taille de pinceau',
|
||||
'Constrain proportions of shapes?\n(you can also hold shift)':
|
||||
'Contraindre les proportions de la forme ?\n(vous pouvez aussi maintenir appuy\u00E9 Maj)'
|
||||
|
||||
};
|
||||
|
|
|
@ -42,7 +42,7 @@
|
|||
|
||||
/*global modules, contains*/
|
||||
|
||||
modules.locale = '2016-July-14';
|
||||
modules.locale = '2016-October-27';
|
||||
|
||||
// Global stuff
|
||||
|
||||
|
@ -160,7 +160,7 @@ SnapTranslator.dict.de = {
|
|||
'translator_e-mail':
|
||||
'jens@moenig.org',
|
||||
'last_changed':
|
||||
'2016-07-12'
|
||||
'2016-10-27'
|
||||
};
|
||||
|
||||
SnapTranslator.dict.it = {
|
||||
|
@ -259,7 +259,7 @@ SnapTranslator.dict.fr = {
|
|||
'translator_e-mail':
|
||||
'i.scool@mac.com',
|
||||
'last_changed':
|
||||
'2016-02-24'
|
||||
'2016-10-27'
|
||||
};
|
||||
|
||||
SnapTranslator.dict.si = {
|
||||
|
|
270
morphic.js
270
morphic.js
|
@ -1103,7 +1103,7 @@
|
|||
|
||||
/*global window, HTMLCanvasElement, FileReader, Audio, FileList*/
|
||||
|
||||
var morphicVersion = '2016-August-12';
|
||||
var morphicVersion = '2016-October-27';
|
||||
var modules = {}; // keep track of additional loaded modules
|
||||
var useBlurredShadows = getBlurredShadowSupport(); // check for Chrome-bug
|
||||
|
||||
|
@ -1245,6 +1245,11 @@ function fontHeight(height) {
|
|||
return minHeight * 1.2; // assuming 1/5 font size for ascenders
|
||||
}
|
||||
|
||||
function isWordChar(aCharacter) {
|
||||
// can't use \b or \w because they ignore diacritics
|
||||
return aCharacter.match(/[A-zÀ-ÿ0-9]/);
|
||||
}
|
||||
|
||||
function newCanvas(extentPoint, nonRetina) {
|
||||
// answer a new empty instance of Canvas, don't display anywhere
|
||||
// nonRetina - optional Boolean "false"
|
||||
|
@ -4960,7 +4965,8 @@ CursorMorph.prototype.init = function (aStringOrTextMorph) {
|
|||
|
||||
CursorMorph.prototype.initializeClipboardHandler = function () {
|
||||
// Add hidden text box for copying and pasting
|
||||
var myself = this;
|
||||
var myself = this,
|
||||
wrrld = this.target.world();
|
||||
|
||||
this.clipboardHandler = document.createElement('textarea');
|
||||
this.clipboardHandler.style.position = 'absolute';
|
||||
|
@ -4986,6 +4992,9 @@ CursorMorph.prototype.initializeClipboardHandler = function () {
|
|||
'keydown',
|
||||
function (event) {
|
||||
myself.processKeyDown(event);
|
||||
if (event.shiftKey) {
|
||||
wrrld.currentKey = 16;
|
||||
}
|
||||
this.value = myself.target.selection();
|
||||
this.select();
|
||||
|
||||
|
@ -4998,7 +5007,15 @@ CursorMorph.prototype.initializeClipboardHandler = function () {
|
|||
},
|
||||
false
|
||||
);
|
||||
|
||||
|
||||
this.clipboardHandler.addEventListener(
|
||||
'keyup',
|
||||
function (event) {
|
||||
wrrld.currentKey = null;
|
||||
},
|
||||
false
|
||||
);
|
||||
|
||||
this.clipboardHandler.addEventListener(
|
||||
'input',
|
||||
function (event) {
|
||||
|
@ -5056,28 +5073,47 @@ CursorMorph.prototype.processKeyPress = function (event) {
|
|||
|
||||
CursorMorph.prototype.processKeyDown = function (event) {
|
||||
// this.inspectKeyEvent(event);
|
||||
var shift = event.shiftKey;
|
||||
var shift = event.shiftKey,
|
||||
wordNavigation = event.ctrlKey || event.altKey,
|
||||
selecting = this.target.selection().length > 0;
|
||||
|
||||
this.keyDownEventUsed = false;
|
||||
if (event.ctrlKey && (!event.altKey)) {
|
||||
this.ctrl(event.keyCode, event.shiftKey);
|
||||
// notify target's parent of key event
|
||||
this.target.escalateEvent('reactToKeystroke', event);
|
||||
return;
|
||||
}
|
||||
if (event.metaKey) {
|
||||
this.cmd(event.keyCode, event.shiftKey);
|
||||
// notify target's parent of key event
|
||||
this.target.escalateEvent('reactToKeystroke', event);
|
||||
return;
|
||||
}
|
||||
|
||||
switch (event.keyCode) {
|
||||
case 37:
|
||||
this.goLeft(shift);
|
||||
if (selecting && !shift && !wordNavigation) {
|
||||
this.gotoSlot(Math.min(this.target.startMark, this.target.endMark));
|
||||
this.target.clearSelection();
|
||||
} else {
|
||||
this.goLeft(
|
||||
shift,
|
||||
wordNavigation ?
|
||||
this.slot - this.target.previousWordFrom(this.slot)
|
||||
: 1);
|
||||
}
|
||||
this.keyDownEventUsed = true;
|
||||
break;
|
||||
case 39:
|
||||
this.goRight(shift);
|
||||
if (selecting && !shift && !wordNavigation) {
|
||||
this.gotoSlot(Math.max(this.target.startMark, this.target.endMark));
|
||||
this.target.clearSelection();
|
||||
} else {
|
||||
this.goRight(
|
||||
shift,
|
||||
wordNavigation ?
|
||||
this.target.nextWordFrom(this.slot) - this.slot
|
||||
: 1);
|
||||
}
|
||||
this.keyDownEventUsed = true;
|
||||
break;
|
||||
case 38:
|
||||
|
@ -5168,9 +5204,9 @@ CursorMorph.prototype.gotoSlot = function (slot) {
|
|||
}
|
||||
};
|
||||
|
||||
CursorMorph.prototype.goLeft = function (shift) {
|
||||
CursorMorph.prototype.goLeft = function (shift, howMany) {
|
||||
this.updateSelection(shift);
|
||||
this.gotoSlot(this.slot - 1);
|
||||
this.gotoSlot(this.slot - (howMany || 1));
|
||||
this.updateSelection(shift);
|
||||
};
|
||||
|
||||
|
@ -5213,7 +5249,7 @@ CursorMorph.prototype.gotoPos = function (aPoint) {
|
|||
|
||||
CursorMorph.prototype.updateSelection = function (shift) {
|
||||
if (shift) {
|
||||
if (!this.target.endMark && !this.target.startMark) {
|
||||
if (isNil(this.target.endMark) && isNil(this.target.startMark)) {
|
||||
this.target.startMark = this.slot;
|
||||
this.target.endMark = this.slot;
|
||||
} else if (this.target.endMark !== this.slot) {
|
||||
|
@ -7793,7 +7829,7 @@ StringMorph.prototype.renderWithBlanks = function (context, startX, y) {
|
|||
});
|
||||
};
|
||||
|
||||
// StringMorph mesuring:
|
||||
// StringMorph measuring:
|
||||
|
||||
StringMorph.prototype.slotPosition = function (slot) {
|
||||
// answer the position point of the given index ("slot")
|
||||
|
@ -7818,8 +7854,10 @@ StringMorph.prototype.slotPosition = function (slot) {
|
|||
};
|
||||
|
||||
StringMorph.prototype.slotAt = function (aPoint) {
|
||||
// answer the slot (index) closest to the given point
|
||||
// answer the slot (index) closest to the given point taking
|
||||
// in account how far from the middle of the character it is,
|
||||
// so the cursor can be moved accordingly
|
||||
|
||||
var txt = this.isPassword ?
|
||||
this.password('*', this.text.length) : this.text,
|
||||
idx = 0,
|
||||
|
@ -7837,7 +7875,14 @@ StringMorph.prototype.slotAt = function (aPoint) {
|
|||
}
|
||||
}
|
||||
}
|
||||
return idx - 1;
|
||||
|
||||
// see where our click fell with respect to the middle of the char
|
||||
if (aPoint.x - this.left() >
|
||||
charX - context.measureText(txt[idx - 1]).width / 2) {
|
||||
return idx;
|
||||
} else {
|
||||
return idx - 1;
|
||||
}
|
||||
};
|
||||
|
||||
StringMorph.prototype.upFrom = function (slot) {
|
||||
|
@ -7860,6 +7905,41 @@ StringMorph.prototype.endOfLine = function () {
|
|||
return this.text.length;
|
||||
};
|
||||
|
||||
StringMorph.prototype.previousWordFrom = function (aSlot) {
|
||||
// answer the slot (index) slots indicating the position of the
|
||||
// previous word to the left of aSlot
|
||||
var index = aSlot - 1;
|
||||
|
||||
// while the current character is non-word one, we skip it, so that
|
||||
// if we are in the middle of a non-alphanumeric sequence, we'll get
|
||||
// right to the beginning of the previous word
|
||||
while (index > 0 && !isWordChar(this.text[index])) {
|
||||
index -= 1;
|
||||
}
|
||||
|
||||
// while the current character is a word one, we skip it until we
|
||||
// find the beginning of the current word
|
||||
while (index > 0 && isWordChar(this.text[index - 1])) {
|
||||
index -= 1;
|
||||
}
|
||||
|
||||
return index;
|
||||
};
|
||||
|
||||
StringMorph.prototype.nextWordFrom = function (aSlot) {
|
||||
var index = aSlot;
|
||||
|
||||
while (index < this.endOfLine() && !isWordChar(this.text[index])) {
|
||||
index += 1;
|
||||
}
|
||||
|
||||
while (index < this.endOfLine() && isWordChar(this.text[index])) {
|
||||
index += 1;
|
||||
}
|
||||
|
||||
return index;
|
||||
};
|
||||
|
||||
StringMorph.prototype.rawHeight = function () {
|
||||
// answer my corrected fontSize
|
||||
return this.height() / 1.2;
|
||||
|
@ -8025,13 +8105,13 @@ StringMorph.prototype.selectionStartSlot = function () {
|
|||
|
||||
StringMorph.prototype.clearSelection = function () {
|
||||
if (!this.currentlySelecting &&
|
||||
this.startMark === 0 &&
|
||||
this.endMark === 0) {
|
||||
isNil(this.startMark) &&
|
||||
isNil(this.endMark)) {
|
||||
return;
|
||||
}
|
||||
this.currentlySelecting = false;
|
||||
this.startMark = 0;
|
||||
this.endMark = 0;
|
||||
this.startMark = null;
|
||||
this.endMark = null;
|
||||
this.drawNew();
|
||||
this.changed();
|
||||
};
|
||||
|
@ -8047,8 +8127,13 @@ StringMorph.prototype.deleteSelection = function () {
|
|||
};
|
||||
|
||||
StringMorph.prototype.selectAll = function () {
|
||||
var cursor;
|
||||
if (this.isEditable) {
|
||||
this.startMark = 0;
|
||||
cursor = this.root().cursor;
|
||||
if (cursor) {
|
||||
cursor.gotoSlot(this.text.length);
|
||||
}
|
||||
this.endMark = this.text.length;
|
||||
this.drawNew();
|
||||
this.changed();
|
||||
|
@ -8056,13 +8141,31 @@ StringMorph.prototype.selectAll = function () {
|
|||
};
|
||||
|
||||
StringMorph.prototype.mouseDownLeft = function (pos) {
|
||||
if (this.isEditable) {
|
||||
if (this.world().currentKey === 16) {
|
||||
this.shiftClick(pos);
|
||||
} else if (this.isEditable) {
|
||||
this.clearSelection();
|
||||
} else {
|
||||
this.escalateEvent('mouseDownLeft', pos);
|
||||
}
|
||||
};
|
||||
|
||||
StringMorph.prototype.shiftClick = function (pos) {
|
||||
var cursor = this.root().cursor;
|
||||
|
||||
if (cursor) {
|
||||
if (!this.startMark) {
|
||||
this.startMark = cursor.slot;
|
||||
}
|
||||
cursor.gotoPos(pos);
|
||||
this.endMark = cursor.slot;
|
||||
this.drawNew();
|
||||
this.changed();
|
||||
}
|
||||
this.currentlySelecting = false;
|
||||
this.escalateEvent('mouseDownLeft', pos);
|
||||
};
|
||||
|
||||
StringMorph.prototype.mouseClickLeft = function (pos) {
|
||||
var cursor;
|
||||
if (this.isEditable) {
|
||||
|
@ -8079,18 +8182,79 @@ StringMorph.prototype.mouseClickLeft = function (pos) {
|
|||
}
|
||||
};
|
||||
|
||||
StringMorph.prototype.mouseDoubleClick = function (pos) {
|
||||
// selects the word at pos
|
||||
// if there is no word, we select whatever is between
|
||||
// the previous and next words
|
||||
var slot = this.slotAt(pos);
|
||||
|
||||
if (this.isEditable) {
|
||||
this.edit();
|
||||
|
||||
if (slot === this.text.length) {
|
||||
slot -= 1;
|
||||
}
|
||||
|
||||
if (isWordChar(this.text[slot])) {
|
||||
this.selectWordAt(slot);
|
||||
} else {
|
||||
this.selectBetweenWordsAt(slot);
|
||||
}
|
||||
} else {
|
||||
this.escalateEvent('mouseDoubleClick', pos);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
StringMorph.prototype.selectWordAt = function (slot) {
|
||||
var cursor = this.root().cursor;
|
||||
|
||||
if (slot === 0 || isWordChar(this.text[slot - 1])) {
|
||||
cursor.gotoSlot(this.previousWordFrom(slot));
|
||||
this.startMark = cursor.slot;
|
||||
this.endMark = this.nextWordFrom(cursor.slot);
|
||||
} else {
|
||||
cursor.gotoSlot(slot);
|
||||
this.startMark = slot;
|
||||
this.endMark = this.nextWordFrom(slot);
|
||||
}
|
||||
|
||||
this.drawNew();
|
||||
this.changed();
|
||||
};
|
||||
|
||||
StringMorph.prototype.selectBetweenWordsAt = function (slot) {
|
||||
var cursor = this.root().cursor;
|
||||
|
||||
cursor.gotoSlot(this.nextWordFrom(this.previousWordFrom(slot)));
|
||||
this.startMark = cursor.slot;
|
||||
this.endMark = cursor.slot;
|
||||
|
||||
while (this.endMark < this.text.length
|
||||
&& !isWordChar(this.text[this.endMark])) {
|
||||
this.endMark += 1;
|
||||
}
|
||||
|
||||
this.drawNew();
|
||||
this.changed();
|
||||
};
|
||||
|
||||
StringMorph.prototype.enableSelecting = function () {
|
||||
this.mouseDownLeft = function (pos) {
|
||||
var crs = this.root().cursor,
|
||||
already = crs ? crs.target === this : false;
|
||||
this.clearSelection();
|
||||
if (this.isEditable && (!this.isDraggable)) {
|
||||
this.edit();
|
||||
this.root().cursor.gotoPos(pos);
|
||||
this.startMark = this.slotAt(pos);
|
||||
this.endMark = this.startMark;
|
||||
this.currentlySelecting = true;
|
||||
if (!already) {this.escalateEvent('mouseDownLeft', pos); }
|
||||
if (this.world().currentKey === 16) {
|
||||
this.shiftClick(pos);
|
||||
} else {
|
||||
this.clearSelection();
|
||||
if (this.isEditable && (!this.isDraggable)) {
|
||||
this.edit();
|
||||
this.root().cursor.gotoPos(pos);
|
||||
this.startMark = this.slotAt(pos);
|
||||
this.endMark = this.startMark;
|
||||
this.currentlySelecting = true;
|
||||
if (!already) {this.escalateEvent('mouseDownLeft', pos); }
|
||||
}
|
||||
}
|
||||
};
|
||||
this.mouseMove = function (pos) {
|
||||
|
@ -8410,8 +8574,10 @@ TextMorph.prototype.slotPosition = function (slot) {
|
|||
};
|
||||
|
||||
TextMorph.prototype.slotAt = function (aPoint) {
|
||||
// answer the slot (index) closest to the given point
|
||||
// answer the slot (index) closest to the given point taking
|
||||
// in account how far from the middle of the character it is,
|
||||
// so the cursor can be moved accordingly
|
||||
|
||||
var charX = 0,
|
||||
row = 0,
|
||||
col = 0,
|
||||
|
@ -8423,11 +8589,19 @@ TextMorph.prototype.slotAt = function (aPoint) {
|
|||
row += 1;
|
||||
}
|
||||
row = Math.max(row, 1);
|
||||
|
||||
while (aPoint.x - this.left() > charX) {
|
||||
charX += context.measureText(this.lines[row - 1][col]).width;
|
||||
col += 1;
|
||||
}
|
||||
return this.lineSlots[Math.max(row - 1, 0)] + col - 1;
|
||||
|
||||
// see where our click fell with respect to the middle of the char
|
||||
if (aPoint.x - this.left() >
|
||||
charX - context.measureText(this.lines[row - 1][col]).width / 2) {
|
||||
return this.lineSlots[Math.max(row - 1, 0)] + col;
|
||||
} else {
|
||||
return this.lineSlots[Math.max(row - 1, 0)] + col - 1;
|
||||
}
|
||||
};
|
||||
|
||||
TextMorph.prototype.upFrom = function (slot) {
|
||||
|
@ -8469,6 +8643,10 @@ TextMorph.prototype.endOfLine = function (slot) {
|
|||
this.lines[this.columnRow(slot).y].length - 1;
|
||||
};
|
||||
|
||||
TextMorph.prototype.previousWordFrom = StringMorph.prototype.previousWordFrom;
|
||||
|
||||
TextMorph.prototype.nextWordFrom = StringMorph.prototype.nextWordFrom;
|
||||
|
||||
// TextMorph editing:
|
||||
|
||||
TextMorph.prototype.edit = StringMorph.prototype.edit;
|
||||
|
@ -8486,8 +8664,17 @@ TextMorph.prototype.selectAll = StringMorph.prototype.selectAll;
|
|||
|
||||
TextMorph.prototype.mouseDownLeft = StringMorph.prototype.mouseDownLeft;
|
||||
|
||||
TextMorph.prototype.shiftClick = StringMorph.prototype.shiftClick;
|
||||
|
||||
TextMorph.prototype.mouseClickLeft = StringMorph.prototype.mouseClickLeft;
|
||||
|
||||
TextMorph.prototype.mouseDoubleClick = StringMorph.prototype.mouseDoubleClick;
|
||||
|
||||
TextMorph.prototype.selectWordAt = StringMorph.prototype.selectWordAt;
|
||||
|
||||
TextMorph.prototype.selectBetweenWordsAt
|
||||
= StringMorph.prototype.selectBetweenWordsAt;
|
||||
|
||||
TextMorph.prototype.enableSelecting = StringMorph.prototype.enableSelecting;
|
||||
|
||||
TextMorph.prototype.disableSelecting = StringMorph.prototype.disableSelecting;
|
||||
|
@ -9255,7 +9442,8 @@ ScrollFrameMorph.prototype.init = function (scroller, size, sliderColor) {
|
|||
ScrollFrameMorph.uber.init.call(this);
|
||||
this.scrollBarSize = size || MorphicPreferences.scrollBarSize;
|
||||
this.autoScrollTrigger = null;
|
||||
this.isScrollingByDragging = true; // change if desired
|
||||
this.enableAutoScrolling = true; // change to suppress
|
||||
this.isScrollingByDragging = true; // change to suppress
|
||||
this.hasVelocity = true; // dto.
|
||||
this.padding = 0; // around the scrollable area
|
||||
this.growth = 0; // pixels or Point to grow right/left when near edge
|
||||
|
@ -10300,7 +10488,12 @@ HandMorph.prototype.processMouseMove = function (event) {
|
|||
|
||||
// autoScrolling support:
|
||||
if (myself.children.length > 0) {
|
||||
if (newMorph instanceof ScrollFrameMorph) {
|
||||
if (newMorph instanceof ScrollFrameMorph &&
|
||||
newMorph.enableAutoScrolling &&
|
||||
newMorph.contents.allChildren().some(function (any) {
|
||||
return any.wantsDropOf(myself.children[0]);
|
||||
})
|
||||
) {
|
||||
if (!newMorph.bounds.insetBy(
|
||||
MorphicPreferences.scrollBarSize * 3
|
||||
).containsPoint(myself.bounds.origin)) {
|
||||
|
@ -10563,8 +10756,8 @@ WorldMorph.prototype.init = function (aCanvas, fillPage) {
|
|||
this.broken = [];
|
||||
this.hand = new HandMorph(this);
|
||||
this.keyboardReceiver = null;
|
||||
this.lastEditedText = null;
|
||||
this.cursor = null;
|
||||
this.lastEditedText = null;
|
||||
this.activeMenu = null;
|
||||
this.activeHandle = null;
|
||||
this.virtualKeyboard = null;
|
||||
|
@ -11328,9 +11521,6 @@ WorldMorph.prototype.edit = function (aStringOrTextMorph) {
|
|||
if (this.cursor) {
|
||||
this.cursor.destroy();
|
||||
}
|
||||
if (this.lastEditedText) {
|
||||
this.lastEditedText.clearSelection();
|
||||
}
|
||||
this.cursor = new CursorMorph(aStringOrTextMorph);
|
||||
aStringOrTextMorph.parent.add(this.cursor);
|
||||
this.keyboardReceiver = this.cursor;
|
||||
|
@ -11348,6 +11538,11 @@ WorldMorph.prototype.edit = function (aStringOrTextMorph) {
|
|||
this.slide(aStringOrTextMorph);
|
||||
}
|
||||
}
|
||||
|
||||
if (this.lastEditedText !== aStringOrTextMorph) {
|
||||
aStringOrTextMorph.escalateEvent('freshTextEdit', aStringOrTextMorph);
|
||||
}
|
||||
this.lastEditedText = aStringOrTextMorph;
|
||||
};
|
||||
|
||||
WorldMorph.prototype.slide = function (aStringOrTextMorph) {
|
||||
|
@ -11393,10 +11588,10 @@ WorldMorph.prototype.slide = function (aStringOrTextMorph) {
|
|||
|
||||
WorldMorph.prototype.stopEditing = function () {
|
||||
if (this.cursor) {
|
||||
this.lastEditedText = this.cursor.target;
|
||||
this.cursor.target.escalateEvent('reactToEdit', this.cursor.target);
|
||||
this.cursor.target.clearSelection();
|
||||
this.cursor.destroy();
|
||||
this.cursor = null;
|
||||
this.lastEditedText.escalateEvent('reactToEdit', this.lastEditedText);
|
||||
}
|
||||
this.keyboardReceiver = null;
|
||||
if (this.virtualKeyboard) {
|
||||
|
@ -11404,6 +11599,7 @@ WorldMorph.prototype.stopEditing = function () {
|
|||
document.body.removeChild(this.virtualKeyboard);
|
||||
this.virtualKeyboard = null;
|
||||
}
|
||||
this.lastEditedText = null;
|
||||
this.worldCanvas.focus();
|
||||
};
|
||||
|
||||
|
|
73
objects.js
73
objects.js
|
@ -82,7 +82,7 @@ SpeechBubbleMorph, RingMorph, isNil, FileReader, TableDialogMorph,
|
|||
BlockEditorMorph, BlockDialogMorph, PrototypeHatBlockMorph, localize,
|
||||
TableMorph, TableFrameMorph, normalizeCanvas, BooleanSlotMorph*/
|
||||
|
||||
modules.objects = '2016-July-19';
|
||||
modules.objects = '2016-October-27';
|
||||
|
||||
var SpriteMorph;
|
||||
var StageMorph;
|
||||
|
@ -1409,9 +1409,11 @@ SpriteMorph.prototype.fullCopy = function (forClone) {
|
|||
c.costumes = new List(arr);
|
||||
arr = [];
|
||||
this.sounds.asArray().forEach(function (sound) {
|
||||
arr.push(sound);
|
||||
var snd = forClone ? sound : sound.copy();
|
||||
arr.push(snd);
|
||||
});
|
||||
c.sounds = new List(arr);
|
||||
arr = [];
|
||||
c.nestingScale = 1;
|
||||
c.rotatesWithAnchor = true;
|
||||
c.anchor = null;
|
||||
|
@ -2950,8 +2952,10 @@ SpriteMorph.prototype.setColor = function (aColor) {
|
|||
y = this.yPosition();
|
||||
if (!this.color.eq(aColor)) {
|
||||
this.color = aColor.copy();
|
||||
this.drawNew();
|
||||
this.gotoXY(x, y);
|
||||
if (!this.costume) {
|
||||
this.drawNew();
|
||||
this.silentGotoXY(x, y);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -3050,17 +3054,21 @@ SpriteMorph.prototype.overlappingImage = function (otherSprite) {
|
|||
SpriteMorph.prototype.doStamp = function () {
|
||||
var stage = this.parent,
|
||||
context = stage.penTrails().getContext('2d'),
|
||||
isWarped = this.isWarped;
|
||||
isWarped = this.isWarped,
|
||||
originalAlpha = context.globalAlpha;
|
||||
|
||||
if (isWarped) {
|
||||
this.endWarp();
|
||||
}
|
||||
context.save();
|
||||
context.scale(1 / stage.scale, 1 / stage.scale);
|
||||
context.globalAlpha = this.alpha;
|
||||
context.drawImage(
|
||||
this.image,
|
||||
(this.left() - stage.left()),
|
||||
(this.top() - stage.top())
|
||||
);
|
||||
context.globalAlpha = originalAlpha;
|
||||
context.restore();
|
||||
this.changed();
|
||||
if (isWarped) {
|
||||
|
@ -4000,14 +4008,33 @@ SpriteMorph.prototype.yCenter = function () {
|
|||
// SpriteMorph message broadcasting
|
||||
|
||||
SpriteMorph.prototype.allMessageNames = function () {
|
||||
var msgs = [];
|
||||
this.scripts.allChildren().forEach(function (morph) {
|
||||
var txt;
|
||||
if (morph.selector) {
|
||||
if (contains(
|
||||
['receiveMessage', 'doBroadcast', 'doBroadcastAndWait'],
|
||||
morph.selector
|
||||
)) {
|
||||
var msgs = [],
|
||||
all = this.scripts.children.slice();
|
||||
this.customBlocks.forEach(function (def) {
|
||||
if (def.body) {
|
||||
all.push(def.body.expression);
|
||||
}
|
||||
def.scripts.forEach(function (scr) {
|
||||
all.push(scr);
|
||||
});
|
||||
});
|
||||
if (this.globalBlocks) {
|
||||
this.globalBlocks.forEach(function (def) {
|
||||
if (def.body) {
|
||||
all.push(def.body.expression);
|
||||
}
|
||||
def.scripts.forEach(function (scr) {
|
||||
all.push(scr);
|
||||
});
|
||||
});
|
||||
}
|
||||
all.forEach(function (script) {
|
||||
script.allChildren().forEach(function (morph) {
|
||||
var txt;
|
||||
if (morph.selector && contains(
|
||||
['receiveMessage', 'doBroadcast', 'doBroadcastAndWait'],
|
||||
morph.selector
|
||||
)) {
|
||||
txt = morph.inputs()[0].evaluate();
|
||||
if (isString(txt) && txt !== '') {
|
||||
if (!contains(msgs, txt)) {
|
||||
|
@ -4015,7 +4042,7 @@ SpriteMorph.prototype.allMessageNames = function () {
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
return msgs;
|
||||
};
|
||||
|
@ -5435,7 +5462,7 @@ StageMorph.prototype.reactToDropOf = function (morph, hand) {
|
|||
// StageMorph stepping
|
||||
|
||||
StageMorph.prototype.step = function () {
|
||||
var current, elapsed, leftover, world = this.world();
|
||||
var current, elapsed, leftover, ide, world = this.world();
|
||||
|
||||
// handle keyboard events
|
||||
if (world.keyboardReceiver === null) {
|
||||
|
@ -5471,6 +5498,14 @@ StageMorph.prototype.step = function () {
|
|||
this.changed();
|
||||
} else {
|
||||
this.threads.step();
|
||||
|
||||
// single-stepping hook:
|
||||
if (this.threads.wantsToPause) {
|
||||
ide = this.parentThatIsA(IDE_Morph);
|
||||
if (ide) {
|
||||
ide.controlBar.pauseButton.refresh();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// update watchers
|
||||
|
@ -6938,13 +6973,13 @@ Costume.prototype.edit = function (aWorld, anIDE, isnew, oncancel, onsubmit) {
|
|||
function (img, rc) {
|
||||
myself.contents = img;
|
||||
myself.rotationCenter = rc;
|
||||
if (anIDE.currentSprite instanceof SpriteMorph) {
|
||||
// don't shrinkwrap stage costumes
|
||||
myself.shrinkWrap();
|
||||
}
|
||||
myself.version = Date.now();
|
||||
aWorld.changed();
|
||||
if (anIDE) {
|
||||
if (anIDE.currentSprite instanceof SpriteMorph) {
|
||||
// don't shrinkwrap stage costumes
|
||||
myself.shrinkWrap();
|
||||
}
|
||||
anIDE.currentSprite.wearCostume(myself);
|
||||
anIDE.hasChangedMedia = true;
|
||||
}
|
||||
|
|
10
store.js
10
store.js
|
@ -61,7 +61,7 @@ normalizeCanvas*/
|
|||
|
||||
// Global stuff ////////////////////////////////////////////////////////
|
||||
|
||||
modules.store = '2016-August-03';
|
||||
modules.store = '2016-October-27';
|
||||
|
||||
|
||||
// XML_Serializer ///////////////////////////////////////////////////////
|
||||
|
@ -630,8 +630,8 @@ SnapSerializer.prototype.loadSprites = function (xmlString, ide) {
|
|||
myself.objects[model.attributes.id] = sprite;
|
||||
}
|
||||
if (model.attributes.name) {
|
||||
sprite.name = model.attributes.name;
|
||||
project.sprites[model.attributes.name] = sprite;
|
||||
sprite.name = ide.newSpriteName(model.attributes.name);
|
||||
project.sprites[sprite.name] = sprite;
|
||||
}
|
||||
if (model.attributes.color) {
|
||||
sprite.color = myself.loadColor(model.attributes.color);
|
||||
|
@ -1619,8 +1619,8 @@ Costume.prototype.toXML = function (serializer) {
|
|||
this.name,
|
||||
this.rotationCenter.x,
|
||||
this.rotationCenter.y,
|
||||
this instanceof SVG_Costume ?
|
||||
this.contents.src : this.contents.toDataURL('image/png')
|
||||
this instanceof SVG_Costume ? this.contents.src
|
||||
: normalizeCanvas(this.contents).toDataURL('image/png')
|
||||
);
|
||||
};
|
||||
|
||||
|
|
170
threads.js
170
threads.js
|
@ -61,7 +61,7 @@ StageMorph, SpriteMorph, StagePrompterMorph, Note, modules, isString, copy,
|
|||
isNil, WatcherMorph, List, ListWatcherMorph, alert, console, TableMorph,
|
||||
TableFrameMorph, isSnapObject*/
|
||||
|
||||
modules.threads = '2016-August-12';
|
||||
modules.threads = '2016-October-27';
|
||||
|
||||
var ThreadManager;
|
||||
var Process;
|
||||
|
@ -175,6 +175,7 @@ function invoke(
|
|||
|
||||
function ThreadManager() {
|
||||
this.processes = [];
|
||||
this.wantsToPause = false; // single stepping support
|
||||
}
|
||||
|
||||
ThreadManager.prototype.pauseCustomHatBlocks = false;
|
||||
|
@ -275,6 +276,25 @@ ThreadManager.prototype.step = function () {
|
|||
// for sprites that are currently picked up, then filter out any
|
||||
// processes that have been terminated
|
||||
|
||||
var isInterrupted;
|
||||
if (Process.prototype.enableSingleStepping) {
|
||||
this.processes.forEach(function (proc) {
|
||||
if (proc.isInterrupted) {
|
||||
proc.runStep();
|
||||
isInterrupted = true;
|
||||
} else {
|
||||
proc.lastYield = Date.now();
|
||||
}
|
||||
});
|
||||
this.wantsToPause = (Process.prototype.flashTime > 0.5);
|
||||
if (isInterrupted) {
|
||||
if (this.wantsToPause) {
|
||||
this.pauseAll();
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
this.processes.forEach(function (proc) {
|
||||
if (!proc.homeContext.receiver.isPickedUp() && !proc.isDead) {
|
||||
proc.runStep();
|
||||
|
@ -290,6 +310,7 @@ ThreadManager.prototype.removeTerminatedProcesses = function () {
|
|||
var result;
|
||||
if ((!proc.isRunning() && !proc.errorFlag) || proc.isDead) {
|
||||
if (proc.topBlock instanceof BlockMorph) {
|
||||
proc.unflash();
|
||||
proc.topBlock.removeHighlight();
|
||||
}
|
||||
if (proc.prompter) {
|
||||
|
@ -371,6 +392,18 @@ ThreadManager.prototype.doWhen = function (block, stopIt) {
|
|||
}
|
||||
};
|
||||
|
||||
ThreadManager.prototype.toggleSingleStepping = function () {
|
||||
Process.prototype.enableSingleStepping =
|
||||
!Process.prototype.enableSingleStepping;
|
||||
if (!Process.prototype.enableSingleStepping) {
|
||||
this.processes.forEach(function (proc) {
|
||||
if (!proc.isPaused) {
|
||||
proc.unflash();
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
// Process /////////////////////////////////////////////////////////////
|
||||
|
||||
/*
|
||||
|
@ -429,6 +462,8 @@ ThreadManager.prototype.doWhen = function (block, stopIt) {
|
|||
procedureCount number counting procedure call entries,
|
||||
used to tag custom block calls, so "stop block"
|
||||
invocations can catch them
|
||||
flashingContext for single stepping
|
||||
isInterrupted boolean, indicates intra-step flashing of blocks
|
||||
*/
|
||||
|
||||
Process.prototype = {};
|
||||
|
@ -436,6 +471,8 @@ Process.prototype.constructor = Process;
|
|||
Process.prototype.timeout = 500; // msecs after which to force yield
|
||||
Process.prototype.isCatchingErrors = true;
|
||||
Process.prototype.enableLiveCoding = false; // experimental
|
||||
Process.prototype.enableSingleStepping = false; // experimental
|
||||
Process.prototype.flashTime = 0; // experimental
|
||||
|
||||
function Process(topBlock, onComplete, rightAway) {
|
||||
this.topBlock = topBlock || null;
|
||||
|
@ -459,6 +496,8 @@ function Process(topBlock, onComplete, rightAway) {
|
|||
this.exportResult = false;
|
||||
this.onComplete = onComplete || null;
|
||||
this.procedureCount = 0;
|
||||
this.flashingContext = null; // experimental, for single-stepping
|
||||
this.isInterrupted = false; // experimental, for single-stepping
|
||||
|
||||
if (topBlock) {
|
||||
this.homeContext.receiver = topBlock.receiver();
|
||||
|
@ -490,9 +529,10 @@ Process.prototype.runStep = function (deadline) {
|
|||
if (this.isPaused) { // allow pausing in between atomic steps:
|
||||
return this.pauseStep();
|
||||
}
|
||||
|
||||
this.readyToYield = false;
|
||||
while (!this.readyToYield
|
||||
this.isInterrupted = false;
|
||||
|
||||
while (!this.readyToYield && !this.isInterrupted
|
||||
&& this.context
|
||||
&& (Date.now() - this.lastYield < this.timeout)
|
||||
) {
|
||||
|
@ -510,6 +550,7 @@ Process.prototype.runStep = function (deadline) {
|
|||
}
|
||||
this.evaluateContext();
|
||||
}
|
||||
|
||||
this.lastYield = Date.now();
|
||||
this.isFirstStep = false;
|
||||
|
||||
|
@ -544,13 +585,20 @@ Process.prototype.stop = function () {
|
|||
};
|
||||
|
||||
Process.prototype.pause = function () {
|
||||
if (this.readyToTerminate) {
|
||||
return;
|
||||
}
|
||||
this.isPaused = true;
|
||||
this.flashPausedContext();
|
||||
if (this.context && this.context.startTime) {
|
||||
this.pauseOffset = Date.now() - this.context.startTime;
|
||||
}
|
||||
};
|
||||
|
||||
Process.prototype.resume = function () {
|
||||
if (!this.enableSingleStepping) {
|
||||
this.unflash();
|
||||
}
|
||||
this.isPaused = false;
|
||||
this.pauseOffset = null;
|
||||
};
|
||||
|
@ -586,7 +634,7 @@ Process.prototype.evaluateContext = function () {
|
|||
return this.evaluateBlock(exp, exp.inputs().length);
|
||||
}
|
||||
if (isString(exp)) {
|
||||
return this[exp]();
|
||||
return this[exp].apply(this, this.context.inputs);
|
||||
}
|
||||
this.popContext(); // default: just ignore it
|
||||
};
|
||||
|
@ -607,6 +655,7 @@ Process.prototype.evaluateBlock = function (block, argCount) {
|
|||
if (argCount > inputs.length) {
|
||||
this.evaluateNextInput(block);
|
||||
} else {
|
||||
if (this.flashContext()) {return; } // yield to flash the block
|
||||
if (this[selector]) {
|
||||
rcvr = this;
|
||||
}
|
||||
|
@ -636,11 +685,13 @@ Process.prototype.reportOr = function (block) {
|
|||
if (inputs.length < 1) {
|
||||
this.evaluateNextInput(block);
|
||||
} else if (inputs[0]) {
|
||||
if (this.flashContext()) {return; }
|
||||
this.returnValueToParentContext(true);
|
||||
this.popContext();
|
||||
} else if (inputs.length < 2) {
|
||||
this.evaluateNextInput(block);
|
||||
} else {
|
||||
if (this.flashContext()) {return; }
|
||||
this.returnValueToParentContext(inputs[1] === true);
|
||||
this.popContext();
|
||||
}
|
||||
|
@ -652,11 +703,13 @@ Process.prototype.reportAnd = function (block) {
|
|||
if (inputs.length < 1) {
|
||||
this.evaluateNextInput(block);
|
||||
} else if (!inputs[0]) {
|
||||
if (this.flashContext()) {return; }
|
||||
this.returnValueToParentContext(false);
|
||||
this.popContext();
|
||||
} else if (inputs.length < 2) {
|
||||
this.evaluateNextInput(block);
|
||||
} else {
|
||||
if (this.flashContext()) {return; }
|
||||
this.returnValueToParentContext(inputs[1] === true);
|
||||
this.popContext();
|
||||
}
|
||||
|
@ -664,6 +717,7 @@ Process.prototype.reportAnd = function (block) {
|
|||
|
||||
Process.prototype.doReport = function (block) {
|
||||
var outer = this.context.outerContext;
|
||||
if (this.flashContext()) {return; } // flash the block here, special form
|
||||
if (this.isClicked && (block.topBlock() === this.topBlock)) {
|
||||
this.isShowingResult = true;
|
||||
}
|
||||
|
@ -736,6 +790,7 @@ Process.prototype.evaluateArgLabel = function (argLabel) {
|
|||
Process.prototype.evaluateInput = function (input) {
|
||||
// evaluate the input unless it is bound to an implicit parameter
|
||||
var ans;
|
||||
if (this.flashContext()) {return; } // yield to flash the current argMorph
|
||||
if (input.bindingID) {
|
||||
if (this.isCatchingErrors) {
|
||||
try {
|
||||
|
@ -879,7 +934,8 @@ Process.prototype.reify = function (topBlock, parameterNames, isCustomBlock) {
|
|||
i = 0;
|
||||
|
||||
if (topBlock) {
|
||||
context.expression = this.enableLiveCoding ?
|
||||
context.expression = this.enableLiveCoding ||
|
||||
this.enableSingleStepping ?
|
||||
topBlock : topBlock.fullCopy();
|
||||
context.expression.show(); // be sure to make visible if in app mode
|
||||
|
||||
|
@ -898,7 +954,8 @@ Process.prototype.reify = function (topBlock, parameterNames, isCustomBlock) {
|
|||
}
|
||||
|
||||
} else {
|
||||
context.expression = this.enableLiveCoding ? [this.context.expression]
|
||||
context.expression = this.enableLiveCoding ||
|
||||
this.enableSingleStepping ? [this.context.expression]
|
||||
: [this.context.expression.fullCopy()];
|
||||
}
|
||||
|
||||
|
@ -1182,6 +1239,15 @@ Process.prototype.reportCallCC = function (aContext) {
|
|||
|
||||
Process.prototype.runContinuation = function (aContext, args) {
|
||||
var parms = args.asArray();
|
||||
|
||||
// determine whether the continuations is to show the result
|
||||
// in a value-balloon becuse the user has directly clicked on a reporter
|
||||
if (aContext.expression === 'expectReport' && parms.length) {
|
||||
this.stop();
|
||||
this.homeContext.inputs[0] = parms[0];
|
||||
return;
|
||||
}
|
||||
|
||||
this.context.parentContext = aContext.copyForContinuationCall();
|
||||
// passing parameter if any was passed
|
||||
if (parms.length === 1) {
|
||||
|
@ -1286,8 +1352,9 @@ Process.prototype.evaluateCustomBlock = function () {
|
|||
if (caller && !caller.tag) {
|
||||
caller.tag = this.procedureCount;
|
||||
}
|
||||
// yield commands unless explicitly "warped"
|
||||
if (!this.isAtomic) {
|
||||
// yield commands unless explicitly "warped" or directly recursive
|
||||
if (!this.isAtomic &&
|
||||
this.context.expression.definition.isDirectlyRecursive()) {
|
||||
this.readyToYield = true;
|
||||
}
|
||||
}
|
||||
|
@ -1911,6 +1978,11 @@ Process.prototype.doWait = function (secs) {
|
|||
this.context.startTime = Date.now();
|
||||
}
|
||||
if ((Date.now() - this.context.startTime) >= (secs * 1000)) {
|
||||
if (!this.isAtomic && (secs === 0)) {
|
||||
// "wait 0 secs" is a plain "yield"
|
||||
// that can be overridden by "warp"
|
||||
this.readyToYield = true;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
this.pushContext('doYield');
|
||||
|
@ -3276,6 +3348,67 @@ Process.prototype.reportFrameCount = function () {
|
|||
return this.frameCount;
|
||||
};
|
||||
|
||||
// Process single-stepping
|
||||
|
||||
Process.prototype.flashContext = function () {
|
||||
var expr = this.context.expression;
|
||||
if (this.enableSingleStepping &&
|
||||
!this.isAtomic &&
|
||||
expr instanceof SyntaxElementMorph &&
|
||||
!(expr instanceof CommandSlotMorph) &&
|
||||
!this.context.isFlashing &&
|
||||
expr.world()) {
|
||||
this.unflash();
|
||||
expr.flash();
|
||||
this.context.isFlashing = true;
|
||||
this.flashingContext = this.context;
|
||||
if (this.flashTime > 0 && (this.flashTime <= 0.5)) {
|
||||
this.pushContext('doIdle');
|
||||
this.context.addInput(this.flashTime);
|
||||
} else {
|
||||
this.pushContext('doInterrupt');
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
Process.prototype.flashPausedContext = function () {
|
||||
var flashable = this.context ? this.context.lastFlashable() : null;
|
||||
if (flashable) {
|
||||
this.unflash();
|
||||
flashable.expression.flash();
|
||||
flashable.isFlashing = true;
|
||||
this.flashingContext = flashable;
|
||||
}
|
||||
};
|
||||
|
||||
Process.prototype.doInterrupt = function () {
|
||||
this.popContext();
|
||||
if (!this.isAtomic) {
|
||||
this.isInterrupted = true;
|
||||
}
|
||||
};
|
||||
|
||||
Process.prototype.doIdle = function (secs) {
|
||||
if (!this.context.startTime) {
|
||||
this.context.startTime = Date.now();
|
||||
}
|
||||
if ((Date.now() - this.context.startTime) < (secs * 1000)) {
|
||||
this.pushContext('doInterrupt');
|
||||
return;
|
||||
}
|
||||
this.popContext();
|
||||
};
|
||||
|
||||
Process.prototype.unflash = function () {
|
||||
if (this.flashingContext) {
|
||||
this.flashingContext.expression.unflash();
|
||||
this.flashingContext.isFlashing = false;
|
||||
this.flashingContext = null;
|
||||
}
|
||||
};
|
||||
|
||||
// Context /////////////////////////////////////////////////////////////
|
||||
|
||||
/*
|
||||
|
@ -3298,6 +3431,7 @@ Process.prototype.reportFrameCount = function () {
|
|||
(if expression is a BlockMorph)
|
||||
pc the index of the next block to evaluate
|
||||
(if expression is an array)
|
||||
isContinuation flag for marking a transient continuation context
|
||||
startTime time when the context was first evaluated
|
||||
startValue initial value for interpolated operations
|
||||
activeAudio audio buffer for interpolated operations, don't persist
|
||||
|
@ -3306,6 +3440,7 @@ Process.prototype.reportFrameCount = function () {
|
|||
emptySlots caches the number of empty slots for reification
|
||||
tag string or number to optionally identify the Context,
|
||||
as a "return" target (for the "stop block" primitive)
|
||||
isFlashing flag for single-stepping
|
||||
*/
|
||||
|
||||
function Context(
|
||||
|
@ -3325,12 +3460,14 @@ function Context(
|
|||
}
|
||||
this.inputs = [];
|
||||
this.pc = 0;
|
||||
this.isContinuation = false;
|
||||
this.startTime = null;
|
||||
this.activeAudio = null;
|
||||
this.activeNote = null;
|
||||
this.isCustomBlock = false; // marks the end of a custom block's stack
|
||||
this.emptySlots = 0; // used for block reification
|
||||
this.tag = null; // lexical catch-tag for custom blocks
|
||||
this.isFlashing = false; // for single-stepping
|
||||
}
|
||||
|
||||
Context.prototype.toString = function () {
|
||||
|
@ -3394,7 +3531,9 @@ Context.prototype.continuation = function () {
|
|||
} else if (this.parentContext) {
|
||||
cont = this.parentContext;
|
||||
} else {
|
||||
return new Context(null, 'doStop');
|
||||
cont = new Context(null, 'expectReport');
|
||||
cont.isContinuation = true;
|
||||
return cont;
|
||||
}
|
||||
cont = cont.copyForContinuation();
|
||||
cont.tag = null;
|
||||
|
@ -3464,6 +3603,19 @@ Context.prototype.stopMusic = function () {
|
|||
}
|
||||
};
|
||||
|
||||
// Context single-stepping:
|
||||
|
||||
Context.prototype.lastFlashable = function () {
|
||||
// for experimental single-stepping when pausing
|
||||
if (this.expression instanceof SyntaxElementMorph &&
|
||||
!(this.expression instanceof CommandSlotMorph)) {
|
||||
return this;
|
||||
} else if (this.parentContext) {
|
||||
return this.parentContext.lastFlashable();
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
// Context debugging
|
||||
|
||||
Context.prototype.stackSize = function () {
|
||||
|
|
File diff suppressed because one or more lines are too long
Ładowanie…
Reference in New Issue