Merge branch 'develop' into feature/serialization

This commit is contained in:
Ray Schamp 2017-05-11 13:04:27 -04:00 committed by GitHub
commit 6c9701f4b2
8 changed files with 70 additions and 12 deletions

View file

@ -40,9 +40,9 @@
"lodash.defaultsdeep": "4.6.0", "lodash.defaultsdeep": "4.6.0",
"minilog": "3.1.0", "minilog": "3.1.0",
"promise": "7.1.1", "promise": "7.1.1",
"scratch-audio": "latest", "scratch-audio": "^0.1.0-prerelease.0",
"scratch-blocks": "latest", "scratch-blocks": "^0.1.0-prerelease.0",
"scratch-render": "latest", "scratch-render": "^0.1.0-prerelease.0",
"scratch-storage": "^0.1.0", "scratch-storage": "^0.1.0",
"script-loader": "0.7.0", "script-loader": "0.7.0",
"stats.js": "^0.17.0", "stats.js": "^0.17.0",

View file

@ -194,7 +194,7 @@ class Blocks {
// UI event: clicked scripts toggle in the runtime. // UI event: clicked scripts toggle in the runtime.
if (e.element === 'stackclick') { if (e.element === 'stackclick') {
if (optRuntime) { if (optRuntime) {
optRuntime.toggleScript(e.blockId); optRuntime.toggleScript(e.blockId, {showVisualReport: true});
} }
return; return;
} }
@ -273,16 +273,22 @@ class Blocks {
*/ */
changeBlock (args) { changeBlock (args) {
// Validate // Validate
if (args.element !== 'field' && args.element !== 'mutation') return; if (['field', 'mutation', 'checkbox'].indexOf(args.element) === -1) return;
const block = this._blocks[args.id]; const block = this._blocks[args.id];
if (typeof block === 'undefined') return; if (typeof block === 'undefined') return;
if (args.element === 'field') { switch (args.element) {
case 'field':
// Update block value // Update block value
if (!block.fields[args.name]) return; if (!block.fields[args.name]) return;
block.fields[args.name].value = args.value; block.fields[args.name].value = args.value;
} else if (args.element === 'mutation') { break;
case 'mutation':
block.mutation = mutationAdapter(args.value); block.mutation = mutationAdapter(args.value);
break;
case 'checkbox':
block.isMonitored = args.value;
break;
} }
} }
@ -342,6 +348,20 @@ class Blocks {
} }
} }
/**
* Block management: run all blocks.
* @param {!object} runtime Runtime to run all blocks in.
*/
runAllMonitored (runtime) {
Object.keys(this._blocks).forEach(blockId => {
if (this.getBlock(blockId).isMonitored) {
// @todo handle specific targets (e.g. apple x position)
runtime.toggleScript(blockId);
}
});
}
/** /**
* Block management: delete blocks and their associated scripts. * Block management: delete blocks and their associated scripts.
* @param {!object} e Blockly delete event to be processed. * @param {!object} e Blockly delete event to be processed.

View file

@ -85,7 +85,7 @@ const execute = function (sequencer, thread) {
} else { } else {
// In a non-hat, report the value visually if necessary if // In a non-hat, report the value visually if necessary if
// at the top of the thread stack. // at the top of the thread stack.
if (typeof resolvedValue !== 'undefined' && thread.atStackTop()) { if (typeof resolvedValue !== 'undefined' && thread.showVisualReport && thread.atStackTop()) {
runtime.visualReport(currentBlockId, resolvedValue); runtime.visualReport(currentBlockId, resolvedValue);
} }
// Finished any yields. // Finished any yields.

View file

@ -52,6 +52,13 @@ class Runtime extends EventEmitter {
*/ */
this.flyoutBlocks = new Blocks(); this.flyoutBlocks = new Blocks();
/**
* Storage container for monitor blocks.
* These will execute on a target maybe
* @type {!Blocks}
*/
this.monitorBlocks = new Blocks();
/** /**
* Currently known editing target for the VM. * Currently known editing target for the VM.
* @type {?Target} * @type {?Target}
@ -362,11 +369,13 @@ class Runtime extends EventEmitter {
* Create a thread and push it to the list of threads. * Create a thread and push it to the list of threads.
* @param {!string} id ID of block that starts the stack. * @param {!string} id ID of block that starts the stack.
* @param {!Target} target Target to run thread on. * @param {!Target} target Target to run thread on.
* @param {?boolean} optShowVisualReport true if the script should show speech bubble for its value
* @return {!Thread} The newly created thread. * @return {!Thread} The newly created thread.
*/ */
_pushThread (id, target) { _pushThread (id, target, optShowVisualReport) {
const thread = new Thread(id); const thread = new Thread(id);
thread.target = target; thread.target = target;
thread.showVisualReport = optShowVisualReport;
thread.pushStack(id); thread.pushStack(id);
this.threads.push(thread); this.threads.push(thread);
return thread; return thread;
@ -416,8 +425,11 @@ class Runtime extends EventEmitter {
/** /**
* Toggle a script. * Toggle a script.
* @param {!string} topBlockId ID of block that starts the script. * @param {!string} topBlockId ID of block that starts the script.
* @param {?object} opts optional arguments to toggle script
* @param {?string} opts.target target ID for target to run script on. If not supplied, uses editing target.
* @param {?boolean} opts.showVisualReport true if the speech bubble should pop up on the block, false if not.
*/ */
toggleScript (topBlockId) { toggleScript (topBlockId, opts) {
// Remove any existing thread. // Remove any existing thread.
for (let i = 0; i < this.threads.length; i++) { for (let i = 0; i < this.threads.length; i++) {
if (this.threads[i].topBlock === topBlockId) { if (this.threads[i].topBlock === topBlockId) {
@ -426,7 +438,10 @@ class Runtime extends EventEmitter {
} }
} }
// Otherwise add it. // Otherwise add it.
this._pushThread(topBlockId, this._editingTarget); this._pushThread(
topBlockId,
opts && opts.target ? opts.target : this._editingTarget,
opts ? opts.showVisualReport : false);
} }
/** /**
@ -632,6 +647,7 @@ class Runtime extends EventEmitter {
} }
} }
this.redrawRequested = false; this.redrawRequested = false;
this._pushMonitors();
const doneThreads = this.sequencer.stepThreads(); const doneThreads = this.sequencer.stepThreads();
this._updateGlows(doneThreads); this._updateGlows(doneThreads);
this._setThreadCount(this.threads.length + doneThreads.length); this._setThreadCount(this.threads.length + doneThreads.length);
@ -641,6 +657,13 @@ class Runtime extends EventEmitter {
} }
} }
/**
* Queue monitor blocks to sequencer to be run.
*/
_pushMonitors () {
this.monitorBlocks.runAllMonitored(this);
}
/** /**
* Set the current editing target known by the runtime. * Set the current editing target known by the runtime.
* @param {!Target} editingTarget New editing target. * @param {!Target} editingTarget New editing target.

View file

@ -20,7 +20,7 @@ class Target extends EventEmitter {
super(); super();
if (!blocks) { if (!blocks) {
blocks = new Blocks(this); blocks = new Blocks();
} }
/** /**
* A unique ID for this target. * A unique ID for this target.

View file

@ -92,6 +92,7 @@ window.onload = function () {
workspace.addChangeListener(vm.blockListener); workspace.addChangeListener(vm.blockListener);
const flyoutWorkspace = workspace.getFlyout().getWorkspace(); const flyoutWorkspace = workspace.getFlyout().getWorkspace();
flyoutWorkspace.addChangeListener(vm.flyoutBlockListener); flyoutWorkspace.addChangeListener(vm.flyoutBlockListener);
flyoutWorkspace.addChangeListener(vm.monitorBlockListener);
// Create FPS counter. // Create FPS counter.
const stats = new window.Stats(); const stats = new window.Stats();

View file

@ -696,6 +696,7 @@ class RenderedTarget extends Target {
newClone.effects = JSON.parse(JSON.stringify(this.effects)); newClone.effects = JSON.parse(JSON.stringify(this.effects));
newClone.variables = JSON.parse(JSON.stringify(this.variables)); newClone.variables = JSON.parse(JSON.stringify(this.variables));
newClone.lists = JSON.parse(JSON.stringify(this.lists)); newClone.lists = JSON.parse(JSON.stringify(this.lists));
newClone._customState = JSON.parse(JSON.stringify(this._customState));
newClone.initDrawable(); newClone.initDrawable();
newClone.updateAllDrawableProperties(); newClone.updateAllDrawableProperties();
// Place behind the current target. // Place behind the current target.

View file

@ -59,6 +59,7 @@ class VirtualMachine extends EventEmitter {
this.blockListener = this.blockListener.bind(this); this.blockListener = this.blockListener.bind(this);
this.flyoutBlockListener = this.flyoutBlockListener.bind(this); this.flyoutBlockListener = this.flyoutBlockListener.bind(this);
this.monitorBlockListener = this.monitorBlockListener.bind(this);
} }
/** /**
@ -413,6 +414,18 @@ class VirtualMachine extends EventEmitter {
this.runtime.flyoutBlocks.blocklyListen(e, this.runtime); this.runtime.flyoutBlocks.blocklyListen(e, this.runtime);
} }
/**
* Handle a Blockly event for the flyout to be passed to the monitor container.
* @param {!Blockly.Event} e Any Blockly event.
*/
monitorBlockListener (e) {
// Filter events by type, since monitor blocks only need to listen to these events.
// Monitor blocks shouldn't be destroyed when flyout blocks are deleted.
if (['create', 'change'].indexOf(e.type) !== -1) {
this.runtime.monitorBlocks.blocklyListen(e, this.runtime);
}
}
/** /**
* Set an editing target. An editor UI can use this function to switch * Set an editing target. An editor UI can use this function to switch
* between editing different targets, sprites, etc. * between editing different targets, sprites, etc.