kopia lustrzana https://github.com/backface/turtlestitch
commit
c346ef43d7
286
gui.js
286
gui.js
|
@ -2296,6 +2296,22 @@ IDE_Morph.prototype.newCamSprite = function () {
|
||||||
camDialog.popUp(this.world());
|
camDialog.popUp(this.world());
|
||||||
};
|
};
|
||||||
|
|
||||||
|
IDE_Morph.prototype.recordNewSound = function () {
|
||||||
|
var soundRecorder,
|
||||||
|
myself = this;
|
||||||
|
|
||||||
|
soundRecorder = new SoundRecorderDialogMorph(
|
||||||
|
function (sound) {
|
||||||
|
if (sound) {
|
||||||
|
myself.currentSprite.addSound(sound, myself.newSoundName('recording'));
|
||||||
|
myself.spriteBar.tabBar.tabTo('sounds');
|
||||||
|
myself.hasChangedMedia = true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
soundRecorder.popUp(this.world());
|
||||||
|
};
|
||||||
|
|
||||||
IDE_Morph.prototype.duplicateSprite = function (sprite) {
|
IDE_Morph.prototype.duplicateSprite = function (sprite) {
|
||||||
var duplicate = sprite.fullCopy();
|
var duplicate = sprite.fullCopy();
|
||||||
duplicate.setPosition(this.world().hand.position());
|
duplicate.setPosition(this.world().hand.position());
|
||||||
|
@ -2346,17 +2362,37 @@ IDE_Morph.prototype.removeSprite = function (sprite) {
|
||||||
this.selectSprite(this.currentSprite);
|
this.selectSprite(this.currentSprite);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
IDE_Morph.prototype.newSoundName = function (name) {
|
||||||
|
var lastSound =
|
||||||
|
this.currentSprite.sounds.at(
|
||||||
|
this.currentSprite.sounds.length());
|
||||||
|
|
||||||
|
return this.newName(
|
||||||
|
lastSound.name || name,
|
||||||
|
this.currentSprite.sounds.asArray().map(
|
||||||
|
function (eachSound) {
|
||||||
|
return eachSound.name;
|
||||||
|
}
|
||||||
|
)
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
IDE_Morph.prototype.newSpriteName = function (name, ignoredSprite) {
|
IDE_Morph.prototype.newSpriteName = function (name, ignoredSprite) {
|
||||||
var ix = name.indexOf('('),
|
var all = this.sprites.asArray().concat(this.stage).filter(
|
||||||
stem = (ix < 0) ? name : name.substring(0, ix),
|
|
||||||
count = 1,
|
|
||||||
newName = stem,
|
|
||||||
all = this.sprites.asArray().concat(this.stage).filter(
|
|
||||||
function (each) {return each !== ignoredSprite; }
|
function (each) {return each !== ignoredSprite; }
|
||||||
).map(
|
).map(
|
||||||
function (each) {return each.name; }
|
function (each) {return each.name; }
|
||||||
);
|
);
|
||||||
while (contains(all, newName)) {
|
return this.newName(name, all)
|
||||||
|
};
|
||||||
|
|
||||||
|
IDE_Morph.prototype.newName = function (name, elements) {
|
||||||
|
var ix = name.indexOf('('),
|
||||||
|
stem = (ix < 0) ? name : name.substring(0, ix),
|
||||||
|
count = 1,
|
||||||
|
newName = stem;
|
||||||
|
|
||||||
|
while (contains(elements, newName)) {
|
||||||
count += 1;
|
count += 1;
|
||||||
newName = stem + '(' + count + ')';
|
newName = stem + '(' + count + ')';
|
||||||
}
|
}
|
||||||
|
@ -8114,7 +8150,7 @@ SoundIconMorph.prototype.renameSound = function () {
|
||||||
|
|
||||||
SoundIconMorph.prototype.removeSound = function () {
|
SoundIconMorph.prototype.removeSound = function () {
|
||||||
var jukebox = this.parentThatIsA(JukeboxMorph),
|
var jukebox = this.parentThatIsA(JukeboxMorph),
|
||||||
idx = this.parent.children.indexOf(this);
|
idx = this.parent.children.indexOf(this + 1);
|
||||||
jukebox.removeSound(idx);
|
jukebox.removeSound(idx);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -8183,7 +8219,9 @@ JukeboxMorph.prototype.updateList = function () {
|
||||||
oldFlag = Morph.prototype.trackChanges,
|
oldFlag = Morph.prototype.trackChanges,
|
||||||
icon,
|
icon,
|
||||||
template,
|
template,
|
||||||
txt;
|
txt,
|
||||||
|
ide = this.sprite.parentThatIsA(IDE_Morph),
|
||||||
|
recordButton;
|
||||||
|
|
||||||
this.changed();
|
this.changed();
|
||||||
oldFlag = Morph.prototype.trackChanges;
|
oldFlag = Morph.prototype.trackChanges;
|
||||||
|
@ -8204,7 +8242,31 @@ JukeboxMorph.prototype.updateList = function () {
|
||||||
txt.setColor(SpriteMorph.prototype.paletteTextColor);
|
txt.setColor(SpriteMorph.prototype.paletteTextColor);
|
||||||
txt.setPosition(new Point(x, y));
|
txt.setPosition(new Point(x, y));
|
||||||
this.addContents(txt);
|
this.addContents(txt);
|
||||||
y = txt.bottom() + padding;
|
|
||||||
|
recordButton = new PushButtonMorph(
|
||||||
|
ide,
|
||||||
|
'recordNewSound',
|
||||||
|
new SymbolMorph('circleSolid', 15),
|
||||||
|
);
|
||||||
|
recordButton.padding = 0;
|
||||||
|
recordButton.corner = 12;
|
||||||
|
recordButton.color = IDE_Morph.prototype.groupColor;
|
||||||
|
recordButton.highlightColor = IDE_Morph.prototype.frameColor.darker(50);
|
||||||
|
recordButton.pressColor = recordButton.highlightColor;
|
||||||
|
recordButton.labelMinExtent = new Point(36, 18);
|
||||||
|
recordButton.labelShadowOffset = new Point(-1, -1);
|
||||||
|
recordButton.labelShadowColor = recordButton.highlightColor;
|
||||||
|
recordButton.labelColor = TurtleIconMorph.prototype.labelColor;
|
||||||
|
recordButton.contrast = this.buttonContrast;
|
||||||
|
recordButton.drawNew();
|
||||||
|
recordButton.hint = 'Record a new sound';
|
||||||
|
recordButton.fixLayout();
|
||||||
|
recordButton.label.setColor(new Color(255, 20, 20));
|
||||||
|
recordButton.setPosition(txt.bottomLeft().add(new Point(0, padding * 2)));
|
||||||
|
|
||||||
|
this.addContents(recordButton);
|
||||||
|
|
||||||
|
y = recordButton.bottom() + padding;
|
||||||
|
|
||||||
this.sprite.sounds.asArray().forEach(function (sound) {
|
this.sprite.sounds.asArray().forEach(function (sound) {
|
||||||
template = icon = new SoundIconMorph(sound, template);
|
template = icon = new SoundIconMorph(sound, template);
|
||||||
|
@ -8674,3 +8736,209 @@ CamSnapshotDialogMorph.prototype.close = function () {
|
||||||
}
|
}
|
||||||
CamSnapshotDialogMorph.uber.destroy.call(this);
|
CamSnapshotDialogMorph.uber.destroy.call(this);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// SoundRecorderDialogMorph ////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
/*
|
||||||
|
I am a dialog morph that lets users record sound snippets for their
|
||||||
|
sprites or Stage.
|
||||||
|
*/
|
||||||
|
|
||||||
|
// SoundRecorderDialogMorph inherits from DialogBoxMorph:
|
||||||
|
|
||||||
|
SoundRecorderDialogMorph.prototype = new DialogBoxMorph();
|
||||||
|
SoundRecorderDialogMorph.prototype.constructor = SoundRecorderDialogMorph;
|
||||||
|
SoundRecorderDialogMorph.uber = DialogBoxMorph.prototype;
|
||||||
|
|
||||||
|
// SoundRecorderDialogMorph instance creation
|
||||||
|
|
||||||
|
function SoundRecorderDialogMorph(onAccept) {
|
||||||
|
this.init(onAccept);
|
||||||
|
}
|
||||||
|
|
||||||
|
SoundRecorderDialogMorph.prototype.init = function (onAccept) {
|
||||||
|
var myself = this;
|
||||||
|
this.padding = 10;
|
||||||
|
this.accept = onAccept;
|
||||||
|
|
||||||
|
this.mediaRecorder = null; // an HTML5 MediaRecorder object
|
||||||
|
this.audioElement = document.createElement('audio');
|
||||||
|
this.audioElement.hidden = true;
|
||||||
|
this.audioElement.onended = function (event) {
|
||||||
|
myself.stop();
|
||||||
|
};
|
||||||
|
document.body.appendChild(this.audioElement);
|
||||||
|
|
||||||
|
this.recordButton = null;
|
||||||
|
this.stopButton = null;
|
||||||
|
this.playButton = null;
|
||||||
|
this.progressBar = new BoxMorph();
|
||||||
|
|
||||||
|
SoundRecorderDialogMorph.uber.init.call(this);
|
||||||
|
this.labelString = 'Sound Recorder';
|
||||||
|
this.createLabel();
|
||||||
|
this.buildContents();
|
||||||
|
};
|
||||||
|
|
||||||
|
SoundRecorderDialogMorph.prototype.buildContents = function () {
|
||||||
|
var myself = this,
|
||||||
|
audioChunks = [];
|
||||||
|
|
||||||
|
this.recordButton = new PushButtonMorph(
|
||||||
|
this,
|
||||||
|
'record',
|
||||||
|
new SymbolMorph('circleSolid', 10)
|
||||||
|
);
|
||||||
|
this.recordButton.drawNew();
|
||||||
|
this.recordButton.fixLayout();
|
||||||
|
|
||||||
|
this.stopButton = new PushButtonMorph(
|
||||||
|
this,
|
||||||
|
'stop',
|
||||||
|
new SymbolMorph('rectangleSolid', 10)
|
||||||
|
);
|
||||||
|
this.stopButton.drawNew();
|
||||||
|
this.stopButton.fixLayout();
|
||||||
|
|
||||||
|
this.playButton = new PushButtonMorph(
|
||||||
|
this,
|
||||||
|
'play',
|
||||||
|
new SymbolMorph('pointRight', 10)
|
||||||
|
);
|
||||||
|
this.playButton.drawNew();
|
||||||
|
this.playButton.fixLayout();
|
||||||
|
|
||||||
|
this.buildProgressBar();
|
||||||
|
|
||||||
|
this.addBody(new AlignmentMorph('row', this.padding));
|
||||||
|
this.body.add(this.recordButton);
|
||||||
|
this.body.add(this.stopButton);
|
||||||
|
this.body.add(this.playButton);
|
||||||
|
this.body.add(this.progressBar);
|
||||||
|
|
||||||
|
this.body.fixLayout();
|
||||||
|
|
||||||
|
if (navigator.mediaDevices && navigator.mediaDevices.getUserMedia) {
|
||||||
|
navigator.mediaDevices.getUserMedia({ audio: true })
|
||||||
|
.then(function (stream) {
|
||||||
|
myself.mediaRecorder = new MediaRecorder(stream);
|
||||||
|
myself.mediaRecorder.ondataavailable = function (event) {
|
||||||
|
audioChunks.push(event.data);
|
||||||
|
};
|
||||||
|
myself.mediaRecorder.onstop = function (event) {
|
||||||
|
myself.audioElement.src =
|
||||||
|
window.URL.createObjectURL(
|
||||||
|
new Blob(
|
||||||
|
audioChunks,
|
||||||
|
{'type': 'audio/ogg; codecs=opus'}
|
||||||
|
)
|
||||||
|
);
|
||||||
|
myself.audioElement.load();
|
||||||
|
audioChunks = [];
|
||||||
|
};
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
this.addButton('ok', 'Save');
|
||||||
|
this.addButton('cancel', 'Cancel');
|
||||||
|
|
||||||
|
this.fixLayout();
|
||||||
|
this.drawNew();
|
||||||
|
};
|
||||||
|
|
||||||
|
SoundRecorderDialogMorph.prototype.buildProgressBar = function () {
|
||||||
|
var line = new Morph(),
|
||||||
|
myself = this;
|
||||||
|
|
||||||
|
this.progressBar.setExtent(new Point(150, 20));
|
||||||
|
this.progressBar.setColor(new Color(200, 200, 200));
|
||||||
|
this.progressBar.setBorderWidth(1);
|
||||||
|
this.progressBar.setBorderColor(new Color(150, 150, 150));
|
||||||
|
|
||||||
|
line.setExtent(new Point(130, 2));
|
||||||
|
line.setColor(new Color(50, 50, 50));
|
||||||
|
line.setCenter(this.progressBar.center());
|
||||||
|
this.progressBar.add(line);
|
||||||
|
|
||||||
|
this.progressBar.indicator = new Morph();
|
||||||
|
this.progressBar.indicator.setExtent(new Point(5, 15));
|
||||||
|
this.progressBar.indicator.setColor(new Color(50, 200, 50));
|
||||||
|
this.progressBar.indicator.setCenter(line.leftCenter());
|
||||||
|
|
||||||
|
this.progressBar.add(this.progressBar.indicator);
|
||||||
|
|
||||||
|
this.progressBar.setPercentage = function (percentage) {
|
||||||
|
this.indicator.setLeft(
|
||||||
|
line.left() +
|
||||||
|
(line.width() / 100 * percentage) -
|
||||||
|
this.indicator.width() / 2)
|
||||||
|
};
|
||||||
|
|
||||||
|
this.progressBar.step = function () {
|
||||||
|
if (myself.audioElement.duration) {
|
||||||
|
this.setPercentage(
|
||||||
|
myself.audioElement.currentTime /
|
||||||
|
myself.audioElement.duration * 100);
|
||||||
|
} else {
|
||||||
|
this.setPercentage(0);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
SoundRecorderDialogMorph.prototype.record = function () {
|
||||||
|
this.mediaRecorder.start();
|
||||||
|
this.recordButton.label.setColor(new Color(255, 0, 0));
|
||||||
|
this.playButton.label.setColor(new Color(0, 0, 0));
|
||||||
|
};
|
||||||
|
|
||||||
|
SoundRecorderDialogMorph.prototype.stop = function () {
|
||||||
|
var myself = this;
|
||||||
|
|
||||||
|
if (this.mediaRecorder && this.mediaRecorder.state !== 'inactive') {
|
||||||
|
this.mediaRecorder.stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
this.audioElement.pause();
|
||||||
|
this.audioElement.currentTime = 0;
|
||||||
|
|
||||||
|
this.recordButton.label.setColor(new Color(0, 0, 0));
|
||||||
|
this.playButton.label.setColor(new Color(0, 0, 0));
|
||||||
|
};
|
||||||
|
|
||||||
|
SoundRecorderDialogMorph.prototype.play = function () {
|
||||||
|
this.stop();
|
||||||
|
this.audioElement.oncanplaythrough = function () {
|
||||||
|
this.play();
|
||||||
|
this.oncanplaythrough = nop;
|
||||||
|
}
|
||||||
|
this.playButton.label.setColor(new Color(0, 255, 0));
|
||||||
|
};
|
||||||
|
|
||||||
|
SoundRecorderDialogMorph.prototype.ok = function () {
|
||||||
|
var myself = this;
|
||||||
|
this.stop();
|
||||||
|
this.audioElement.oncanplaythrough = function () {
|
||||||
|
if (this.duration && this.duration !== Infinity) {
|
||||||
|
myself.accept(this);
|
||||||
|
this.oncanplaythrough = nop;
|
||||||
|
myself.destroy();
|
||||||
|
} else {
|
||||||
|
// For some reason, we need to play the sound
|
||||||
|
// at least once to get its duration.
|
||||||
|
myself.buttons.children.forEach(function (button) {
|
||||||
|
button.disable();
|
||||||
|
});
|
||||||
|
this.play();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
SoundRecorderDialogMorph.prototype.destroy = function () {
|
||||||
|
this.stop();
|
||||||
|
this.audioElement.remove();
|
||||||
|
if (this.mediaRecorder) {
|
||||||
|
this.mediaRecorder.stream.getTracks()[0].stop();
|
||||||
|
}
|
||||||
|
SoundRecorderDialogMorph.uber.destroy.call(this);
|
||||||
|
};
|
||||||
|
|
Ładowanie…
Reference in New Issue