Clicking blocks in the toolbox ()

This commit is contained in:
Tim Mickel 2016-10-13 17:15:49 -04:00 committed by GitHub
parent dcda82a009
commit 1e86d48a31
5 changed files with 55 additions and 26 deletions

View file

@ -71,8 +71,9 @@ window.onload = function() {
window.workspace = workspace;
// Attach scratch-blocks events to VM.
// @todo: Re-enable flyout listening after fixing GH-69.
workspace.addChangeListener(vm.blockListener);
var flyoutWorkspace = workspace.getFlyout().getWorkspace();
flyoutWorkspace.addChangeListener(vm.flyoutBlockListener);
// Create FPS counter.
var stats = new window.Stats();
@ -117,11 +118,9 @@ window.onload = function() {
// Receipt of new block XML for the selected target.
vm.on('workspaceUpdate', function (data) {
window.Blockly.Events.disable();
workspace.clear();
var dom = window.Blockly.Xml.textToDom(data.xml);
window.Blockly.Xml.domToWorkspace(dom, workspace);
window.Blockly.Events.enable();
});
// Receipt of new list of targets, selected target update.

View file

@ -181,11 +181,10 @@ Blocks.prototype.getProcedureParamNames = function (name) {
* Create event listener for blocks. Handles validation and serves as a generic
* adapter between the blocks and the runtime interface.
* @param {Object} e Blockly "block" event
* @param {boolean} isFlyout If true, create a listener for flyout events.
* @param {?Runtime} opt_runtime Optional runtime to forward click events to.
*/
Blocks.prototype.blocklyListen = function (e, isFlyout, opt_runtime) {
Blocks.prototype.blocklyListen = function (e, opt_runtime) {
// Validate event
if (typeof e !== 'object') return;
if (typeof e.blockId !== 'string') return;
@ -204,7 +203,7 @@ Blocks.prototype.blocklyListen = function (e, isFlyout, opt_runtime) {
var newBlocks = adapter(e);
// A create event can create many blocks. Add them all.
for (var i = 0; i < newBlocks.length; i++) {
this.createBlock(newBlocks[i], isFlyout);
this.createBlock(newBlocks[i]);
}
break;
case 'change':
@ -226,8 +225,10 @@ Blocks.prototype.blocklyListen = function (e, isFlyout, opt_runtime) {
});
break;
case 'delete':
// Don't accept delete events for shadow blocks being obscured.
if (this._blocks[e.blockId].shadow) {
// Don't accept delete events for missing blocks,
// or shadow blocks being obscured.
if (!this._blocks.hasOwnProperty(e.blockId) ||
this._blocks[e.blockId].shadow) {
return;
}
// Inform any runtime to forget about glows on this script.
@ -246,9 +247,8 @@ Blocks.prototype.blocklyListen = function (e, isFlyout, opt_runtime) {
/**
* Block management: create blocks and scripts from a `create` event
* @param {!Object} block Blockly create event to be processed
* @param {boolean} opt_isFlyoutBlock Whether the block is in the flyout.
*/
Blocks.prototype.createBlock = function (block, opt_isFlyoutBlock) {
Blocks.prototype.createBlock = function (block) {
// Does the block already exist?
// Could happen, e.g., for an unobscured shadow.
if (this._blocks.hasOwnProperty(block.id)) {
@ -258,9 +258,8 @@ Blocks.prototype.createBlock = function (block, opt_isFlyoutBlock) {
this._blocks[block.id] = block;
// Push block id to scripts array.
// Blocks are added as a top-level stack if they are marked as a top-block
// (if they were top-level XML in the event) and if they are not
// flyout blocks.
if (!opt_isFlyoutBlock && block.topLevel) {
// (if they were top-level XML in the event).
if (block.topLevel) {
this._addScript(block.id);
}
};
@ -288,6 +287,10 @@ Blocks.prototype.changeBlock = function (args) {
* @param {!Object} e Blockly move event to be processed
*/
Blocks.prototype.moveBlock = function (e) {
if (!this._blocks.hasOwnProperty(e.id)) {
return;
}
// Move coordinate changes.
if (e.newCoordinate) {
this._blocks[e.id].x = e.newCoordinate.x;

View file

@ -22,19 +22,34 @@ var execute = function (sequencer, thread) {
var currentBlockId = thread.peekStack();
var currentStackFrame = thread.peekStackFrame();
// Verify that the block still exists.
if (!target ||
typeof target.blocks.getBlock(currentBlockId) === 'undefined') {
// Check where the block lives: target blocks or flyout blocks.
var targetHasBlock = (
typeof target.blocks.getBlock(currentBlockId) !== 'undefined'
);
var flyoutHasBlock = (
typeof runtime.flyoutBlocks.getBlock(currentBlockId) !== 'undefined'
);
// Stop if block or target no longer exists.
if (!target || (!targetHasBlock && !flyoutHasBlock)) {
// No block found: stop the thread; script no longer exists.
sequencer.retireThread(thread);
return;
}
// Query info about the block.
var opcode = target.blocks.getOpcode(currentBlockId);
var blockContainer = null;
if (targetHasBlock) {
blockContainer = target.blocks;
} else {
blockContainer = runtime.flyoutBlocks;
}
var opcode = blockContainer.getOpcode(currentBlockId);
var fields = blockContainer.getFields(currentBlockId);
var inputs = blockContainer.getInputs(currentBlockId);
var blockFunction = runtime.getOpcodeFunction(opcode);
var isHat = runtime.getIsHat(opcode);
var fields = target.blocks.getFields(currentBlockId);
var inputs = target.blocks.getInputs(currentBlockId);
if (!opcode) {
console.warn('Could not get opcode for block: ' + currentBlockId);
@ -133,7 +148,7 @@ var execute = function (sequencer, thread) {
}
// Add any mutation to args (e.g., for procedures).
var mutation = target.blocks.getMutation(currentBlockId);
var mutation = blockContainer.getMutation(currentBlockId);
if (mutation) {
argValues.mutation = mutation;
}
@ -165,7 +180,7 @@ var execute = function (sequencer, thread) {
sequencer.stepToProcedure(thread, procedureName);
},
getProcedureParamNames: function (procedureName) {
return thread.target.blocks.getProcedureParamNames(procedureName);
return blockContainer.getProcedureParamNames(procedureName);
},
pushParam: function (paramName, paramValue) {
thread.pushParam(paramName, paramValue);

View file

@ -1,5 +1,6 @@
var EventEmitter = require('events');
var Sequencer = require('./sequencer');
var Blocks = require('./blocks');
var Thread = require('./thread');
var util = require('util');
@ -44,6 +45,8 @@ function Runtime () {
/** @type {!Sequencer} */
this.sequencer = new Sequencer(this);
this.flyoutBlocks = new Blocks();
/**
* Map to look up a block primitive's implementation function by its opcode.
* This is a two-step lookup: package name first, then primitive name.
@ -463,6 +466,10 @@ Runtime.prototype._updateScriptGlows = function () {
if (thread.requestScriptGlowInFrame && target == this._editingTarget) {
var blockForThread = thread.peekStack() || thread.topBlock;
var script = target.blocks.getTopLevelScript(blockForThread);
if (!script) {
// Attempt to find in flyout blocks.
script = this.flyoutBlocks.getTopLevelScript(blockForThread);
}
if (script) {
requestedGlowsThisFrame.push(script);
}

View file

@ -44,6 +44,7 @@ function VirtualMachine () {
});
this.blockListener = this.blockListener.bind(this);
this.flyoutBlockListener = this.flyoutBlockListener.bind(this);
}
/**
@ -186,14 +187,18 @@ VirtualMachine.prototype.attachRenderer = function (renderer) {
*/
VirtualMachine.prototype.blockListener = function (e) {
if (this.editingTarget) {
this.editingTarget.blocks.blocklyListen(
e,
false,
this.runtime
);
this.editingTarget.blocks.blocklyListen(e, this.runtime);
}
};
/**
* Handle a Blockly event for the flyout.
* @param {!Blockly.Event} e Any Blockly event.
*/
VirtualMachine.prototype.flyoutBlockListener = function (e) {
this.runtime.flyoutBlocks.blocklyListen(e, this.runtime);
};
/**
* Set an editing target. An editor UI can use this function to switch
* between editing different targets, sprites, etc.