kopia lustrzana https://github.com/backface/turtlestitch
Merge master / resolve conflicts
commit
06284ae8a2
19
blocks.js
19
blocks.js
|
@ -148,7 +148,7 @@ CustomCommandBlockMorph, SymbolMorph*/
|
|||
|
||||
// Global stuff ////////////////////////////////////////////////////////
|
||||
|
||||
modules.blocks = '2017-September-01';
|
||||
modules.blocks = '2017-September-06';
|
||||
|
||||
var SyntaxElementMorph;
|
||||
var BlockMorph;
|
||||
|
@ -1025,7 +1025,8 @@ SyntaxElementMorph.prototype.labelPart = function (spec) {
|
|||
'whitespace' : ['whitespace'],
|
||||
'line' : ['line'],
|
||||
'tab' : ['tab'],
|
||||
'cr' : ['cr']
|
||||
'cr' : ['cr'],
|
||||
'csv' : ['csv']
|
||||
},
|
||||
false // read-only
|
||||
);
|
||||
|
@ -1972,7 +1973,7 @@ SyntaxElementMorph.prototype.exportPictureWithResult = function (aBubble) {
|
|||
// request to open pic in new window.
|
||||
ide.saveCanvasAs(
|
||||
pic,
|
||||
ide.projetName || localize('Untitled') + ' ' + localize('script pic')
|
||||
(ide.projetName || localize('untitled')) + ' ' + localize('script pic')
|
||||
);
|
||||
};
|
||||
|
||||
|
@ -2550,7 +2551,7 @@ BlockMorph.prototype.userMenu = function () {
|
|||
);
|
||||
ide.saveCanvasAs(
|
||||
myself.topBlock().scriptPic(),
|
||||
ide.projetName || localize('Untitled') + ' ' +
|
||||
(ide.projetName || localize('untitled')) + ' ' +
|
||||
localize('script pic')
|
||||
);
|
||||
},
|
||||
|
@ -6230,7 +6231,7 @@ ScriptsMorph.prototype.userMenu = function () {
|
|||
);
|
||||
if (ide) {
|
||||
menu.addLine();
|
||||
if (obj.exemplar) {
|
||||
if (!blockEditor && obj.exemplar) {
|
||||
addOption(
|
||||
'inherited',
|
||||
function () {
|
||||
|
@ -6304,7 +6305,7 @@ ScriptsMorph.prototype.exportScriptsPicture = function () {
|
|||
if (pic) {
|
||||
ide.saveCanvasAs(
|
||||
pic,
|
||||
ide.projetName || localize('Untitled') + ' ' +
|
||||
(ide.projetName || localize('untitled')) + ' ' +
|
||||
localize('script pic')
|
||||
);
|
||||
}
|
||||
|
@ -8193,7 +8194,7 @@ InputSlotMorph.prototype.distancesMenu = function () {
|
|||
allNames = [];
|
||||
|
||||
stage.children.forEach(function (morph) {
|
||||
if (morph instanceof SpriteMorph) {
|
||||
if (morph instanceof SpriteMorph && !morph.isTemporary) {
|
||||
if (morph.name !== rcvr.name) {
|
||||
allNames = allNames.concat(morph.name);
|
||||
}
|
||||
|
@ -8239,7 +8240,7 @@ InputSlotMorph.prototype.objectsMenu = function () {
|
|||
|
||||
dict[stage.name] = stage.name;
|
||||
stage.children.forEach(function (morph) {
|
||||
if (morph instanceof SpriteMorph) {
|
||||
if (morph instanceof SpriteMorph && !morph.isTemporary) {
|
||||
allNames.push(morph.name);
|
||||
}
|
||||
});
|
||||
|
@ -11655,7 +11656,7 @@ CommentMorph.prototype.userMenu = function () {
|
|||
var ide = myself.parentThatIsA(IDE_Morph);
|
||||
ide.saveCanvasAs(
|
||||
myself.fullImageClassic(),
|
||||
ide.projetName || localize('Untitled') + ' ' +
|
||||
(ide.projetName || localize('untitled')) + ' ' +
|
||||
localize('comment pic')
|
||||
);
|
||||
},
|
||||
|
|
4
byob.js
4
byob.js
|
@ -930,7 +930,7 @@ CustomCommandBlockMorph.prototype.userMenu = function () {
|
|||
var ide = this.world().children[0];
|
||||
ide.saveCanvasAs(
|
||||
this.topBlock().scriptPic(),
|
||||
ide.projectName || localize('Untitled') + ' ' +
|
||||
(ide.projectName || localize('untitled')) + ' ' +
|
||||
localize('script pic')
|
||||
);
|
||||
},
|
||||
|
@ -3705,7 +3705,7 @@ BlockExportDialogMorph.prototype.exportBlocks = function () {
|
|||
+ '</blocks>';
|
||||
ide.saveXMLAs(
|
||||
str,
|
||||
ide.projectName || localize('Untitled') + ' ' + localize('blocks')
|
||||
(ide.projectName || localize('untitled')) + ' ' + localize('blocks')
|
||||
);
|
||||
} else {
|
||||
new DialogBoxMorph().inform(
|
||||
|
|
264
gui.js
264
gui.js
|
@ -43,8 +43,9 @@
|
|||
TurtleIconMorph
|
||||
CostumeIconMorph
|
||||
WardrobeMorph
|
||||
StageHandleMorph;
|
||||
PaletteHandleMorph;
|
||||
StageHandleMorph
|
||||
PaletteHandleMorph
|
||||
CamSnapshotDialogMorph
|
||||
|
||||
|
||||
credits
|
||||
|
@ -74,7 +75,7 @@ isRetinaSupported, SliderMorph, Animation*/
|
|||
|
||||
// Global stuff ////////////////////////////////////////////////////////
|
||||
|
||||
modules.gui = '2017-September-01';
|
||||
modules.gui = '2017-September-08';
|
||||
|
||||
// Declarations
|
||||
|
||||
|
@ -89,6 +90,7 @@ var SoundIconMorph;
|
|||
var JukeboxMorph;
|
||||
var StageHandleMorph;
|
||||
var PaletteHandleMorph;
|
||||
var CamSnapshotDialogMorph;
|
||||
|
||||
// IDE_Morph ///////////////////////////////////////////////////////////
|
||||
|
||||
|
@ -1419,6 +1421,7 @@ IDE_Morph.prototype.createCorralBar = function () {
|
|||
var padding = 5,
|
||||
newbutton,
|
||||
paintbutton,
|
||||
cambutton,
|
||||
colors = [
|
||||
this.groupColor,
|
||||
this.frameColor.darker(50),
|
||||
|
@ -1480,6 +1483,46 @@ IDE_Morph.prototype.createCorralBar = function () {
|
|||
this.corralBar.left() + padding + newbutton.width() + padding
|
||||
);
|
||||
this.corralBar.add(paintbutton);
|
||||
|
||||
cambutton = new PushButtonMorph(
|
||||
this,
|
||||
"newCamSprite",
|
||||
new SymbolMorph("camera", 15)
|
||||
);
|
||||
|
||||
cambutton.corner = 12;
|
||||
cambutton.color = colors[0];
|
||||
cambutton.highlightColor = colors[1];
|
||||
cambutton.pressColor = colors[2];
|
||||
cambutton.labelMinExtent = new Point(36, 18);
|
||||
cambutton.padding = 0;
|
||||
cambutton.labelShadowOffset = new Point(-1, -1);
|
||||
cambutton.labelShadowColor = colors[1];
|
||||
cambutton.labelColor = this.buttonLabelColor;
|
||||
cambutton.contrast = this.buttonContrast;
|
||||
cambutton.drawNew();
|
||||
cambutton.hint = "take a camera snapshot and\nimport it as a new sprite";
|
||||
cambutton.fixLayout();
|
||||
cambutton.setCenter(this.corralBar.center());
|
||||
cambutton.setLeft(
|
||||
this.corralBar.left() +
|
||||
padding +
|
||||
newbutton.width() +
|
||||
padding +
|
||||
paintbutton.width() +
|
||||
padding
|
||||
);
|
||||
|
||||
if (location.protocol === 'http:') {
|
||||
cambutton.hint = 'Due to browser security policies, you need to\n' +
|
||||
'access Snap! through HTTPS to use the camera.\n\n' +
|
||||
'Plase replace the "http://" part of the address\n' +
|
||||
'in your browser by "https://" and try again.';
|
||||
cambutton.disable();
|
||||
}
|
||||
|
||||
this.corralBar.add(cambutton);
|
||||
|
||||
};
|
||||
|
||||
IDE_Morph.prototype.createCorral = function () {
|
||||
|
@ -2140,6 +2183,30 @@ IDE_Morph.prototype.paintNewSprite = function () {
|
|||
);
|
||||
};
|
||||
|
||||
IDE_Morph.prototype.newCamSprite = function () {
|
||||
var sprite = new SpriteMorph(this.globalVariables),
|
||||
camDialog,
|
||||
myself = this;
|
||||
|
||||
sprite.name = this.newSpriteName(sprite.name);
|
||||
sprite.setCenter(this.stage.center());
|
||||
this.stage.add(sprite);
|
||||
this.sprites.add(sprite);
|
||||
this.corral.addSprite(sprite);
|
||||
this.selectSprite(sprite);
|
||||
|
||||
camDialog = new CamSnapshotDialogMorph(
|
||||
this,
|
||||
sprite,
|
||||
function () { myself.removeSprite(sprite); },
|
||||
function (costume) {
|
||||
sprite.addCostume(costume);
|
||||
sprite.wearCostume(costume);
|
||||
});
|
||||
|
||||
camDialog.popUp(this.world());
|
||||
};
|
||||
|
||||
IDE_Morph.prototype.duplicateSprite = function (sprite) {
|
||||
var duplicate = sprite.fullCopy();
|
||||
duplicate.setPosition(this.world().hand.position());
|
||||
|
@ -6617,7 +6684,7 @@ SpriteIconMorph.prototype.init = function (aSprite, aTemplate) {
|
|||
|
||||
hover = function () {
|
||||
if (!aSprite.exemplar) {return null; }
|
||||
return (localize('parent' + ':\n' + aSprite.exemplar.name));
|
||||
return (localize('parent') + ':\n' + aSprite.exemplar.name);
|
||||
};
|
||||
|
||||
// additional properties:
|
||||
|
@ -7187,7 +7254,7 @@ CostumeIconMorph.prototype.removeCostume = function () {
|
|||
var wardrobe = this.parentThatIsA(WardrobeMorph),
|
||||
idx = this.parent.children.indexOf(this),
|
||||
ide = this.parentThatIsA(IDE_Morph);
|
||||
wardrobe.removeCostumeAt(idx - 2);
|
||||
wardrobe.removeCostumeAt(idx - 3); // ignore the paintbrush and camera buttons
|
||||
if (ide.currentSprite.costume === this.object) {
|
||||
ide.currentSprite.wearCostume(null);
|
||||
}
|
||||
|
@ -7455,12 +7522,14 @@ WardrobeMorph.prototype.updateList = function () {
|
|||
x = this.left() + 5,
|
||||
y = this.top() + 5,
|
||||
padding = 4,
|
||||
toolsPadding = 5,
|
||||
oldFlag = Morph.prototype.trackChanges,
|
||||
oldPos = this.contents.position(),
|
||||
icon,
|
||||
template,
|
||||
txt,
|
||||
paintbutton;
|
||||
paintbutton,
|
||||
cambutton;
|
||||
|
||||
this.changed();
|
||||
oldFlag = Morph.prototype.trackChanges;
|
||||
|
@ -7501,9 +7570,40 @@ WardrobeMorph.prototype.updateList = function () {
|
|||
paintbutton.setCenter(icon.center());
|
||||
paintbutton.setLeft(icon.right() + padding * 4);
|
||||
|
||||
|
||||
this.addContents(paintbutton);
|
||||
|
||||
cambutton = new PushButtonMorph(
|
||||
this,
|
||||
"newFromCam",
|
||||
new SymbolMorph("camera", 15)
|
||||
);
|
||||
cambutton.padding = 0;
|
||||
cambutton.corner = 12;
|
||||
cambutton.color = IDE_Morph.prototype.groupColor;
|
||||
cambutton.highlightColor = IDE_Morph.prototype.frameColor.darker(50);
|
||||
cambutton.pressColor = paintbutton.highlightColor;
|
||||
cambutton.labelMinExtent = new Point(36, 18);
|
||||
cambutton.labelShadowOffset = new Point(-1, -1);
|
||||
cambutton.labelShadowColor = paintbutton.highlightColor;
|
||||
cambutton.labelColor = TurtleIconMorph.prototype.labelColor;
|
||||
cambutton.contrast = this.buttonContrast;
|
||||
cambutton.drawNew();
|
||||
cambutton.hint = "Import a new costume from your webcam";
|
||||
cambutton.setPosition(new Point(x, y));
|
||||
cambutton.fixLayout();
|
||||
cambutton.setCenter(paintbutton.center());
|
||||
cambutton.setLeft(paintbutton.right() + toolsPadding);
|
||||
|
||||
if (location.protocol === 'http:') {
|
||||
cambutton.hint = 'Due to browser security policies, you need to\n' +
|
||||
'access Snap! through HTTPS to use the camera.\n\n' +
|
||||
'Plase replace the "http://" part of the address\n' +
|
||||
'in your browser by "https://" and try again.';
|
||||
cambutton.disable();
|
||||
}
|
||||
|
||||
this.addContents(cambutton);
|
||||
|
||||
txt = new TextMorph(localize(
|
||||
"costumes tab help" // look up long string in translator
|
||||
));
|
||||
|
@ -7514,7 +7614,6 @@ WardrobeMorph.prototype.updateList = function () {
|
|||
this.addContents(txt);
|
||||
y = txt.bottom() + padding;
|
||||
|
||||
|
||||
this.sprite.costumes.asArray().forEach(function (costume) {
|
||||
template = icon = new CostumeIconMorph(costume, template);
|
||||
icon.setPosition(new Point(x, y));
|
||||
|
@ -7574,6 +7673,25 @@ WardrobeMorph.prototype.paintNew = function () {
|
|||
});
|
||||
};
|
||||
|
||||
WardrobeMorph.prototype.newFromCam = function () {
|
||||
var camDialog,
|
||||
ide = this.parentThatIsA(IDE_Morph),
|
||||
myself = this,
|
||||
sprite = this.sprite;
|
||||
|
||||
camDialog = new CamSnapshotDialogMorph(
|
||||
ide,
|
||||
sprite,
|
||||
nop,
|
||||
function (costume) {
|
||||
sprite.addCostume(costume);
|
||||
sprite.wearCostume(costume);
|
||||
myself.updateList();
|
||||
});
|
||||
|
||||
camDialog.popUp(this.world());
|
||||
};
|
||||
|
||||
// Wardrobe drag & drop
|
||||
|
||||
WardrobeMorph.prototype.wantsDropOf = function (morph) {
|
||||
|
@ -8178,3 +8296,133 @@ PaletteHandleMorph.prototype.mouseDoubleClick = function () {
|
|||
this.target.parentThatIsA(IDE_Morph).setPaletteWidth(200);
|
||||
};
|
||||
|
||||
// CamSnapshotDialogMorph ////////////////////////////////////////////////////
|
||||
|
||||
/*
|
||||
I am a dialog morph that lets users take a snapshot using their webcam
|
||||
and use it as a costume for their sprites or a background for the Stage.
|
||||
*/
|
||||
|
||||
// CamSnapshotDialogMorph inherits from DialogBoxMorph:
|
||||
|
||||
|
||||
CamSnapshotDialogMorph.prototype = new DialogBoxMorph();
|
||||
CamSnapshotDialogMorph.prototype.constructor = CamSnapshotDialogMorph;
|
||||
CamSnapshotDialogMorph.uber = DialogBoxMorph.prototype;
|
||||
|
||||
// CamSnapshotDialogMorph instance creation
|
||||
|
||||
function CamSnapshotDialogMorph(ide, sprite, onCancel, onAccept) {
|
||||
this.init(ide, sprite, onCancel, onAccept);
|
||||
}
|
||||
|
||||
CamSnapshotDialogMorph.prototype.init = function (
|
||||
ide,
|
||||
sprite,
|
||||
onCancel,
|
||||
onAccept) {
|
||||
this.ide = ide;
|
||||
this.sprite = sprite;
|
||||
this.padding = 10;
|
||||
|
||||
this.oncancel = onCancel;
|
||||
this.accept = onAccept;
|
||||
|
||||
this.videoElement = null; // an HTML5 video element
|
||||
this.videoView = new Morph(); // a morph where we'll copy the video contents
|
||||
|
||||
CamSnapshotDialogMorph.uber.init.call(this);
|
||||
|
||||
this.labelString = 'Camera';
|
||||
this.createLabel();
|
||||
|
||||
this.buildContents();
|
||||
};
|
||||
|
||||
CamSnapshotDialogMorph.prototype.buildContents = function () {
|
||||
var myself = this;
|
||||
|
||||
this.videoElement = document.createElement('video');
|
||||
this.videoElement.hidden = true;
|
||||
document.body.appendChild(this.videoElement);
|
||||
|
||||
if (navigator.mediaDevices && navigator.mediaDevices.getUserMedia) {
|
||||
navigator.mediaDevices.getUserMedia({ video: true })
|
||||
.then(function (stream) {
|
||||
myself.videoElement.src = window.URL.createObjectURL(stream);
|
||||
myself.videoElement.play();
|
||||
myself.videoElement.stream = stream;
|
||||
});
|
||||
}
|
||||
|
||||
this.videoView.setExtent(this.ide.stage.dimensions);
|
||||
this.videoView.image = newCanvas(this.videoView.extent());
|
||||
this.videoView.drawOn = function (aCanvas) {
|
||||
var context = aCanvas.getContext('2d'),
|
||||
w = this.width(),
|
||||
h = this.height();
|
||||
|
||||
context.save();
|
||||
|
||||
// Flip the image so it looks like a mirror
|
||||
context.translate(w, 0);
|
||||
context.scale(-1, 1);
|
||||
|
||||
context.drawImage(
|
||||
myself.videoElement,
|
||||
this.left() * -1,
|
||||
this.top(),
|
||||
w,
|
||||
h
|
||||
);
|
||||
|
||||
context.restore();
|
||||
};
|
||||
|
||||
this.videoView.step = function () {
|
||||
this.changed();
|
||||
};
|
||||
|
||||
this.addBody(new AlignmentMorph('column', this.padding / 2));
|
||||
this.body.add(this.videoView);
|
||||
this.body.fixLayout();
|
||||
|
||||
this.addButton('ok', 'Save');
|
||||
this.addButton('cancel', 'Cancel');
|
||||
|
||||
this.fixLayout();
|
||||
this.drawNew();
|
||||
};
|
||||
|
||||
CamSnapshotDialogMorph.prototype.ok = function () {
|
||||
var stage = this.ide.stage,
|
||||
canvas = newCanvas(stage.dimensions),
|
||||
context = canvas.getContext('2d');
|
||||
|
||||
context.translate(stage.dimensions.x, 0);
|
||||
context.scale(-1, 1);
|
||||
|
||||
context.drawImage(
|
||||
this.videoElement,
|
||||
0,
|
||||
0,
|
||||
stage.dimensions.x,
|
||||
stage.dimensions.y
|
||||
);
|
||||
|
||||
this.accept(new Costume(canvas), this.sprite.newCostumeName('camera'));
|
||||
this.close();
|
||||
};
|
||||
|
||||
CamSnapshotDialogMorph.prototype.destroy = function () {
|
||||
this.oncancel.call(this);
|
||||
this.close();
|
||||
};
|
||||
|
||||
CamSnapshotDialogMorph.prototype.close = function () {
|
||||
if (this.videoElement) {
|
||||
this.videoElement.stream.getTracks()[0].stop();
|
||||
this.videoElement.remove();
|
||||
}
|
||||
CamSnapshotDialogMorph.uber.destroy.call(this);
|
||||
};
|
||||
|
|
22
history.txt
22
history.txt
|
@ -3601,12 +3601,31 @@ Fixes:
|
|||
* Morphic, Objects: fixed #1843
|
||||
* Croation translation update, thanks, Zeljko Hrvoj!
|
||||
|
||||
170904
|
||||
------
|
||||
* Blocks, Objects: fixed #1339
|
||||
|
||||
170905
|
||||
------
|
||||
* German translation update
|
||||
* Threads, Objects: Renamed “http” block to “url”, use location.protocol (support https)
|
||||
|
||||
170906
|
||||
------
|
||||
* Blocks, Threads: added “csv” option to the SPLIT primitive
|
||||
* Threads: allow https query from locally loaded sources (thanks, Michael, for the hint!)
|
||||
|
||||
170908
|
||||
------
|
||||
* GUI, Objects, Widgets, Symbols: Camera Snapshot Dialog. Thank you, Bernat!!
|
||||
|
||||
|
||||
v4.1 Features:
|
||||
* polymorphic sprite-local custom blocks
|
||||
* inheritance of sprite-local custom blocks
|
||||
* inheritance of sprite attributes (x, y, direction, size, costumes, costume #, sounds, scripts)
|
||||
* first-class costumes and sounds
|
||||
* camera snapshots for costumes and new sprites
|
||||
* localization support when typing expressions
|
||||
* support for user-forced line-breaks in custom block labels
|
||||
* ternary Boolean slot setting: support to limit Boolean input slots to “true/false” outside of rings and in palette
|
||||
|
@ -3625,6 +3644,8 @@ v4.1 Features:
|
|||
* two-item lists as x-y coordinate arguments for "point towards”, "go to" and “distance to” primitives
|
||||
* Piano keyboard as drop-down menu for entering musical notes, Thanks, Michael!
|
||||
* Basic “instruments” support: sine, square, sawtooth and triangle waves
|
||||
* Support https in “url” reporter
|
||||
* splitting csv-text
|
||||
|
||||
Fixes:
|
||||
* changed keyboard shortcut indicator for “find blocks” to “^”
|
||||
|
@ -3635,4 +3656,5 @@ Fixes:
|
|||
* fixed rotation-bug when flipping costumes in "only turn left/right" mode"
|
||||
* fixed variable renaming (“refactoring”) bugs, thanks, Bernat!
|
||||
* fixed “fill” block crash when applying the same color twice
|
||||
* fixed occasional empty drop-down menu items named “close”
|
||||
* fixed some typos
|
||||
|
|
78
lang-de.js
78
lang-de.js
|
@ -185,7 +185,7 @@ SnapTranslator.dict.de = {
|
|||
'translator_e-mail':
|
||||
'jens@moenig.org', // optional
|
||||
'last_changed':
|
||||
'2017-06-24', // this, too, will appear in the Translators tab
|
||||
'2017-09-05', // this, too, will appear in the Translators tab
|
||||
|
||||
// GUI
|
||||
// control bar:
|
||||
|
@ -381,8 +381,10 @@ SnapTranslator.dict.de = {
|
|||
'stoppe alle Kl\u00e4nge',
|
||||
'rest for %n beats':
|
||||
'spiele Pause f\u00fcr %n Schl\u00e4ge',
|
||||
'play note %n for %n beats':
|
||||
'spiele Note %n f\u00fcr %n Schl\u00e4ge',
|
||||
'play note %note for %n beats':
|
||||
'spiele Note %note f\u00fcr %n Schl\u00e4ge',
|
||||
'set instrument to %inst':
|
||||
'setze Instrument auf %inst',
|
||||
'change tempo by %n':
|
||||
'\u00e4ndere Tempo um %n',
|
||||
'set tempo to %n bpm':
|
||||
|
@ -390,6 +392,16 @@ SnapTranslator.dict.de = {
|
|||
'tempo':
|
||||
'Tempo',
|
||||
|
||||
// "instruments", i.e. wave forms
|
||||
'(1) sine':
|
||||
'(1) Sinus',
|
||||
'(2) square':
|
||||
'(2) Quadrat',
|
||||
'(3) sawtooth':
|
||||
'(3) Sägeblatt',
|
||||
'(4) triangle':
|
||||
'(4) Dreieck',
|
||||
|
||||
// pen:
|
||||
'clear':
|
||||
'wische',
|
||||
|
@ -495,10 +507,16 @@ SnapTranslator.dict.de = {
|
|||
'Wenn ich geklont werde',
|
||||
'create a clone of %cln':
|
||||
'klone %cln',
|
||||
'a new clone of %cln':
|
||||
'neuer Klon von %cln',
|
||||
'myself':
|
||||
'mich',
|
||||
'selbst',
|
||||
'delete this clone':
|
||||
'entferne diesen Klon',
|
||||
'tell %spr to %cl':
|
||||
'lasse %spr tun %cl',
|
||||
'ask %spr for %repRing':
|
||||
'frage %spr nach %repRing',
|
||||
|
||||
// sensing:
|
||||
'touching %col ?':
|
||||
|
@ -537,6 +555,24 @@ SnapTranslator.dict.de = {
|
|||
'Turbomodus?',
|
||||
'set turbo mode to %b':
|
||||
'setze Turbomodus auf %b',
|
||||
'current %dates':
|
||||
'Kalender %dates',
|
||||
'year':
|
||||
'Jahr',
|
||||
'month':
|
||||
'Monat',
|
||||
'date':
|
||||
'Datum',
|
||||
'day of week':
|
||||
'Wochentag',
|
||||
'hour':
|
||||
'Stunde',
|
||||
'minute':
|
||||
'Minute',
|
||||
'second':
|
||||
'Sekunde',
|
||||
'time in milliseconds':
|
||||
'Zeit in Millisekunden',
|
||||
|
||||
'filtered for %clr':
|
||||
'nach %clr gefiltert',
|
||||
|
@ -584,6 +620,8 @@ SnapTranslator.dict.de = {
|
|||
'ist %s ein(e) %typ ?',
|
||||
'is %s identical to %s ?':
|
||||
'ist %s identisch mit %s ?',
|
||||
'JavaScript function ( %mult%s ) { %code }':
|
||||
'JavaScript Funktion ( %mult%s ) { %code }',
|
||||
|
||||
'type of %s':
|
||||
'Typ von %s',
|
||||
|
@ -595,6 +633,8 @@ SnapTranslator.dict.de = {
|
|||
'Variablenname',
|
||||
'Script variable name':
|
||||
'Skriptvariablenname',
|
||||
'inherit %shd':
|
||||
'erbe %shd',
|
||||
'Delete a variable':
|
||||
'Variable l\u00f6schen',
|
||||
|
||||
|
@ -797,6 +837,10 @@ SnapTranslator.dict.de = {
|
|||
'ausschalten um Schieber\nin Eingabefeldern zu verhindern',
|
||||
'check to enable\ninput sliders for\nentry fields':
|
||||
'einschalten um Schieber\nin Eingabefeldern zu aktivieren',
|
||||
'Retina display support':
|
||||
'Retina Bildschirmauflösung',
|
||||
'Codification support':
|
||||
'Kodifikation',
|
||||
'Clicking sound':
|
||||
'Akustisches Klicken',
|
||||
'uncheck to turn\nblock clicking\nsound off':
|
||||
|
@ -909,6 +953,8 @@ SnapTranslator.dict.de = {
|
|||
// sprites:
|
||||
'edit':
|
||||
'Bearbeiten',
|
||||
'clone':
|
||||
'Klonen',
|
||||
'move':
|
||||
'Verschieben',
|
||||
'pivot':
|
||||
|
@ -921,6 +967,14 @@ SnapTranslator.dict.de = {
|
|||
'Alle Teile abtrennen',
|
||||
'export...':
|
||||
'Exportieren...',
|
||||
'parent...':
|
||||
'Vorfahr...',
|
||||
'current parent':
|
||||
'aktueller Vorfahr',
|
||||
'release':
|
||||
'Entlassen',
|
||||
'make temporary and\nhide in the sprite corral':
|
||||
'temporär machen\nund Icon verstecken',
|
||||
|
||||
// stage:
|
||||
'show all':
|
||||
|
@ -1099,6 +1153,8 @@ SnapTranslator.dict.de = {
|
|||
// block editor
|
||||
'Block Editor':
|
||||
'Blockeditor',
|
||||
'Method':
|
||||
'Methode',
|
||||
'Apply':
|
||||
'Anwenden',
|
||||
|
||||
|
@ -1437,4 +1493,18 @@ SnapTranslator.dict.de = {
|
|||
'Name',
|
||||
'stage':
|
||||
'B\u00fchne',
|
||||
'costumes':
|
||||
'Kostüme',
|
||||
'sounds':
|
||||
'Klänge',
|
||||
'scripts':
|
||||
'Skripte',
|
||||
|
||||
// inheritance
|
||||
'inherited':
|
||||
'geerbt',
|
||||
'check to inherit\nfrom':
|
||||
'einschalten, um zu erben\nvon',
|
||||
'uncheck to\ndisinherit':
|
||||
'ausschalten, um \nnicht mehr zu erben'
|
||||
};
|
||||
|
|
|
@ -42,7 +42,7 @@
|
|||
|
||||
/*global modules, contains*/
|
||||
|
||||
modules.locale = '2017-September-01';
|
||||
modules.locale = '2017-September-05';
|
||||
|
||||
// Global stuff
|
||||
|
||||
|
@ -160,7 +160,7 @@ SnapTranslator.dict.de = {
|
|||
'translator_e-mail':
|
||||
'jens@moenig.org',
|
||||
'last_changed':
|
||||
'2017-06-24'
|
||||
'2017-09-05'
|
||||
};
|
||||
|
||||
SnapTranslator.dict.it = {
|
||||
|
|
|
@ -82,7 +82,7 @@ SpeechBubbleMorph, RingMorph, isNil, FileReader, TableDialogMorph,
|
|||
BlockEditorMorph, BlockDialogMorph, PrototypeHatBlockMorph, localize,
|
||||
TableMorph, TableFrameMorph, normalizeCanvas, BooleanSlotMorph, HandleMorph*/
|
||||
|
||||
modules.objects = '2017-September-01';
|
||||
modules.objects = '2017-September-08';
|
||||
|
||||
var SpriteMorph;
|
||||
var StageMorph;
|
||||
|
@ -899,7 +899,7 @@ SpriteMorph.prototype.initBlocks = function () {
|
|||
reportURL: {
|
||||
type: 'reporter',
|
||||
category: 'sensing',
|
||||
spec: 'http:// %s',
|
||||
spec: 'url %s',
|
||||
defaults: ['snap.berkeley.edu']
|
||||
},
|
||||
reportIsFastTracking: {
|
||||
|
@ -5291,6 +5291,7 @@ SpriteMorph.prototype.chooseExemplar = function () {
|
|||
myself = this,
|
||||
other = stage.children.filter(function (m) {
|
||||
return m instanceof SpriteMorph &&
|
||||
!m.isTemporary &&
|
||||
(!contains(m.allExemplars(), myself));
|
||||
}),
|
||||
menu;
|
||||
|
|
42
symbols.js
42
symbols.js
|
@ -41,7 +41,7 @@
|
|||
|
||||
// Global stuff ////////////////////////////////////////////////////////
|
||||
|
||||
modules.symbols = '2017-September-01';
|
||||
modules.symbols = '2017-September-08';
|
||||
|
||||
var SymbolMorph;
|
||||
|
||||
|
@ -129,7 +129,8 @@ SymbolMorph.prototype.names = [
|
|||
'arrowRightOutline',
|
||||
'robot',
|
||||
'magnifyingGlass',
|
||||
'notes'
|
||||
'notes',
|
||||
'camera'
|
||||
];
|
||||
|
||||
// SymbolMorph instance creation:
|
||||
|
@ -303,6 +304,8 @@ SymbolMorph.prototype.symbolCanvasColored = function (aColor) {
|
|||
return this.drawSymbolMagnifyingGlass(canvas, aColor);
|
||||
case 'notes':
|
||||
return this.drawSymbolNotes(canvas, aColor);
|
||||
case 'camera':
|
||||
return this.drawSymbolCamera(canvas, aColor);
|
||||
default:
|
||||
return canvas;
|
||||
}
|
||||
|
@ -1516,3 +1519,38 @@ SymbolMorph.prototype.drawSymbolNotes = function (canvas, color) {
|
|||
ctx.stroke();
|
||||
return canvas;
|
||||
};
|
||||
|
||||
SymbolMorph.prototype.drawSymbolCamera = function (canvas, color) {
|
||||
// answer a canvas showing a camera
|
||||
var ctx = canvas.getContext('2d'),
|
||||
w = canvas.width,
|
||||
h = canvas.width,
|
||||
r = w * 0.16,
|
||||
l = Math.max(w / 20, 0.5);
|
||||
|
||||
ctx.lineWidth = l * 2;
|
||||
|
||||
// camera body
|
||||
ctx.fillStyle = color.toString();
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(l, h * 5 / 6);
|
||||
ctx.lineTo(w - l, h * 5 / 6);
|
||||
ctx.lineTo(w - l, h / 4);
|
||||
ctx.lineTo(w * 3 / 4 , h / 4);
|
||||
ctx.lineTo(w * 5 / 8 , l);
|
||||
ctx.lineTo(w * 3 / 8 , l);
|
||||
ctx.lineTo(w / 4 , h / 4);
|
||||
ctx.lineTo(l , h / 4);
|
||||
ctx.closePath();
|
||||
ctx.fill();
|
||||
|
||||
// camera lens
|
||||
ctx.save();
|
||||
ctx.globalCompositeOperation = 'destination-out';
|
||||
ctx.beginPath();
|
||||
ctx.arc(w / 2, h / 2, r, radians(0), radians(360), false);
|
||||
ctx.fill();
|
||||
ctx.restore();
|
||||
|
||||
return canvas;
|
||||
};
|
||||
|
|
51
threads.js
51
threads.js
|
@ -61,7 +61,7 @@ StageMorph, SpriteMorph, StagePrompterMorph, Note, modules, isString, copy,
|
|||
isNil, WatcherMorph, List, ListWatcherMorph, alert, console, TableMorph,
|
||||
TableFrameMorph, ColorSlotMorph, isSnapObject*/
|
||||
|
||||
modules.threads = '2017-September-01';
|
||||
modules.threads = '2017-September-06';
|
||||
|
||||
var ThreadManager;
|
||||
var Process;
|
||||
|
@ -2267,8 +2267,17 @@ Process.prototype.reportLastAnswer = function () {
|
|||
Process.prototype.reportURL = function (url) {
|
||||
var response;
|
||||
if (!this.httpRequest) {
|
||||
// use the location protocol unless the user specifies otherwise
|
||||
if (url.indexOf('//') < 0) {
|
||||
if (location.protocol === 'file:') {
|
||||
// allow requests from locally loaded sources
|
||||
url = 'https://' + url;
|
||||
} else {
|
||||
url = location.protocol + '//' + url;
|
||||
}
|
||||
}
|
||||
this.httpRequest = new XMLHttpRequest();
|
||||
this.httpRequest.open("GET", 'http://' + url, true);
|
||||
this.httpRequest.open("GET", url, true);
|
||||
this.httpRequest.send(null);
|
||||
} else if (this.httpRequest.readyState === 4) {
|
||||
response = this.httpRequest.responseText;
|
||||
|
@ -2718,12 +2727,50 @@ Process.prototype.reportTextSplit = function (string, delimiter) {
|
|||
case 'letter':
|
||||
del = '';
|
||||
break;
|
||||
case 'csv':
|
||||
return this.parseCSV(string);
|
||||
default:
|
||||
del = isNil(delimiter) ? '' : delimiter.toString();
|
||||
}
|
||||
return new List(str.split(del));
|
||||
};
|
||||
|
||||
Process.prototype.parseCSV = function (string) {
|
||||
// parse a single row of CSV data into a one-dimensional list
|
||||
// this assumes that the whole csv data has already been split
|
||||
// by lines.
|
||||
// taken from:
|
||||
// https://stackoverflow.com/questions/8493195/how-can-i-parse-a-csv-string-with-javascript-which-contains-comma-in-data
|
||||
|
||||
var re_valid = /^\s*(?:'[^'\\]*(?:\\[\S\s][^'\\]*)*'|"[^"\\]*(?:\\[\S\s][^"\\]*)*"|[^,'"\s\\]*(?:\s+[^,'"\s\\]+)*)\s*(?:,\s*(?:'[^'\\]*(?:\\[\S\s][^'\\]*)*'|"[^"\\]*(?:\\[\S\s][^"\\]*)*"|[^,'"\s\\]*(?:\s+[^,'"\s\\]+)*)\s*)*$/,
|
||||
re_value = /(?!\s*$)\s*(?:'([^'\\]*(?:\\[\S\s][^'\\]*)*)'|"([^"\\]*(?:\\[\S\s][^"\\]*)*)"|([^,'"\s\\]*(?:\s+[^,'"\s\\]+)*))\s*(?:,|$)/g,
|
||||
a = [];
|
||||
|
||||
if (!re_valid.test(string)) {
|
||||
return new List();
|
||||
}
|
||||
string.replace(
|
||||
re_value,
|
||||
function(m0, m1, m2, m3) {
|
||||
if (m1 !== undefined) {
|
||||
// remove backslash from \' in single quoted values.
|
||||
a.push(m1.replace(/\\'/g, "'"));
|
||||
} else if (m2 !== undefined) {
|
||||
// remove backslash from \" in double quoted values.
|
||||
a.push(m2.replace(/\\"/g, '"'));
|
||||
} else if (m3 !== undefined) {
|
||||
a.push(m3);
|
||||
}
|
||||
return '';
|
||||
}
|
||||
);
|
||||
// special case: empty last value.
|
||||
if (/,\s*$/.test(string)) {
|
||||
a.push('');
|
||||
}
|
||||
return new List(a);
|
||||
};
|
||||
|
||||
// Process debugging
|
||||
|
||||
Process.prototype.alert = function (data) {
|
||||
|
|
27
widgets.js
27
widgets.js
|
@ -85,7 +85,7 @@ HTMLCanvasElement, fontHeight, SymbolMorph, localize, SpeechBubbleMorph,
|
|||
ArrowMorph, MenuMorph, isString, isNil, SliderMorph, MorphicPreferences,
|
||||
ScrollFrameMorph, MenuItemMorph, Note*/
|
||||
|
||||
modules.widgets = '2017-September-01';
|
||||
modules.widgets = '2017-September-08';
|
||||
|
||||
var PushButtonMorph;
|
||||
var ToggleButtonMorph;
|
||||
|
@ -168,6 +168,7 @@ PushButtonMorph.prototype.init = function (
|
|||
this.hint = hint || null;
|
||||
this.template = template || null; // for pre-computed backbrounds
|
||||
// if a template is specified, its background images are used as cache
|
||||
this.enabled = true;
|
||||
|
||||
// initialize inherited properties:
|
||||
TriggerMorph.uber.init.call(this);
|
||||
|
@ -204,9 +205,11 @@ PushButtonMorph.prototype.mouseDownLeft = function () {
|
|||
};
|
||||
|
||||
PushButtonMorph.prototype.mouseClickLeft = function () {
|
||||
PushButtonMorph.uber.mouseClickLeft.call(this);
|
||||
if (this.label) {
|
||||
this.label.setCenter(this.center());
|
||||
if (this.enabled) {
|
||||
PushButtonMorph.uber.mouseClickLeft.call(this);
|
||||
if (this.label) {
|
||||
this.label.setCenter(this.center());
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -479,6 +482,22 @@ PushButtonMorph.prototype.createLabel = function () {
|
|||
this.add(this.label);
|
||||
};
|
||||
|
||||
// PushButtonMorph states
|
||||
|
||||
PushButtonMorph.prototype.disable = function () {
|
||||
this.enabled = false;
|
||||
this.forAllChildren(function (child) {
|
||||
child.alpha = 0.3;
|
||||
});
|
||||
};
|
||||
|
||||
PushButtonMorph.prototype.enable = function () {
|
||||
this.enabled = true;
|
||||
this.forAllChildren(function (child) {
|
||||
child.alpha = 1;
|
||||
});
|
||||
};
|
||||
|
||||
// ToggleButtonMorph ///////////////////////////////////////////////////////
|
||||
|
||||
/*
|
||||
|
|
Ładowanie…
Reference in New Issue