mirror of
https://github.com/scratchfoundation/scratch-vm.git
synced 2025-06-04 17:44:43 -04:00
Clicking blocks in the toolbox (#267)
This commit is contained in:
parent
dcda82a009
commit
1e86d48a31
5 changed files with 55 additions and 26 deletions
|
@ -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.
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
15
src/index.js
15
src/index.js
|
@ -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.
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue