mirror of
https://github.com/scratchfoundation/scratch-vm.git
synced 2025-07-10 21:14:06 -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;
|
window.workspace = workspace;
|
||||||
|
|
||||||
// Attach scratch-blocks events to VM.
|
// Attach scratch-blocks events to VM.
|
||||||
// @todo: Re-enable flyout listening after fixing GH-69.
|
|
||||||
workspace.addChangeListener(vm.blockListener);
|
workspace.addChangeListener(vm.blockListener);
|
||||||
|
var flyoutWorkspace = workspace.getFlyout().getWorkspace();
|
||||||
|
flyoutWorkspace.addChangeListener(vm.flyoutBlockListener);
|
||||||
|
|
||||||
// Create FPS counter.
|
// Create FPS counter.
|
||||||
var stats = new window.Stats();
|
var stats = new window.Stats();
|
||||||
|
@ -117,11 +118,9 @@ window.onload = function() {
|
||||||
|
|
||||||
// Receipt of new block XML for the selected target.
|
// Receipt of new block XML for the selected target.
|
||||||
vm.on('workspaceUpdate', function (data) {
|
vm.on('workspaceUpdate', function (data) {
|
||||||
window.Blockly.Events.disable();
|
|
||||||
workspace.clear();
|
workspace.clear();
|
||||||
var dom = window.Blockly.Xml.textToDom(data.xml);
|
var dom = window.Blockly.Xml.textToDom(data.xml);
|
||||||
window.Blockly.Xml.domToWorkspace(dom, workspace);
|
window.Blockly.Xml.domToWorkspace(dom, workspace);
|
||||||
window.Blockly.Events.enable();
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// Receipt of new list of targets, selected target update.
|
// 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
|
* Create event listener for blocks. Handles validation and serves as a generic
|
||||||
* adapter between the blocks and the runtime interface.
|
* adapter between the blocks and the runtime interface.
|
||||||
* @param {Object} e Blockly "block" event
|
* @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.
|
* @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
|
// Validate event
|
||||||
if (typeof e !== 'object') return;
|
if (typeof e !== 'object') return;
|
||||||
if (typeof e.blockId !== 'string') return;
|
if (typeof e.blockId !== 'string') return;
|
||||||
|
@ -204,7 +203,7 @@ Blocks.prototype.blocklyListen = function (e, isFlyout, opt_runtime) {
|
||||||
var newBlocks = adapter(e);
|
var newBlocks = adapter(e);
|
||||||
// A create event can create many blocks. Add them all.
|
// A create event can create many blocks. Add them all.
|
||||||
for (var i = 0; i < newBlocks.length; i++) {
|
for (var i = 0; i < newBlocks.length; i++) {
|
||||||
this.createBlock(newBlocks[i], isFlyout);
|
this.createBlock(newBlocks[i]);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 'change':
|
case 'change':
|
||||||
|
@ -226,8 +225,10 @@ Blocks.prototype.blocklyListen = function (e, isFlyout, opt_runtime) {
|
||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
case 'delete':
|
case 'delete':
|
||||||
// Don't accept delete events for shadow blocks being obscured.
|
// Don't accept delete events for missing blocks,
|
||||||
if (this._blocks[e.blockId].shadow) {
|
// or shadow blocks being obscured.
|
||||||
|
if (!this._blocks.hasOwnProperty(e.blockId) ||
|
||||||
|
this._blocks[e.blockId].shadow) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// Inform any runtime to forget about glows on this script.
|
// 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
|
* Block management: create blocks and scripts from a `create` event
|
||||||
* @param {!Object} block Blockly create event to be processed
|
* @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?
|
// Does the block already exist?
|
||||||
// Could happen, e.g., for an unobscured shadow.
|
// Could happen, e.g., for an unobscured shadow.
|
||||||
if (this._blocks.hasOwnProperty(block.id)) {
|
if (this._blocks.hasOwnProperty(block.id)) {
|
||||||
|
@ -258,9 +258,8 @@ Blocks.prototype.createBlock = function (block, opt_isFlyoutBlock) {
|
||||||
this._blocks[block.id] = block;
|
this._blocks[block.id] = block;
|
||||||
// Push block id to scripts array.
|
// Push block id to scripts array.
|
||||||
// Blocks are added as a top-level stack if they are marked as a top-block
|
// 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
|
// (if they were top-level XML in the event).
|
||||||
// flyout blocks.
|
if (block.topLevel) {
|
||||||
if (!opt_isFlyoutBlock && block.topLevel) {
|
|
||||||
this._addScript(block.id);
|
this._addScript(block.id);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -288,6 +287,10 @@ Blocks.prototype.changeBlock = function (args) {
|
||||||
* @param {!Object} e Blockly move event to be processed
|
* @param {!Object} e Blockly move event to be processed
|
||||||
*/
|
*/
|
||||||
Blocks.prototype.moveBlock = function (e) {
|
Blocks.prototype.moveBlock = function (e) {
|
||||||
|
if (!this._blocks.hasOwnProperty(e.id)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// Move coordinate changes.
|
// Move coordinate changes.
|
||||||
if (e.newCoordinate) {
|
if (e.newCoordinate) {
|
||||||
this._blocks[e.id].x = e.newCoordinate.x;
|
this._blocks[e.id].x = e.newCoordinate.x;
|
||||||
|
|
|
@ -22,19 +22,34 @@ var execute = function (sequencer, thread) {
|
||||||
var currentBlockId = thread.peekStack();
|
var currentBlockId = thread.peekStack();
|
||||||
var currentStackFrame = thread.peekStackFrame();
|
var currentStackFrame = thread.peekStackFrame();
|
||||||
|
|
||||||
// Verify that the block still exists.
|
// Check where the block lives: target blocks or flyout blocks.
|
||||||
if (!target ||
|
var targetHasBlock = (
|
||||||
typeof target.blocks.getBlock(currentBlockId) === 'undefined') {
|
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.
|
// No block found: stop the thread; script no longer exists.
|
||||||
sequencer.retireThread(thread);
|
sequencer.retireThread(thread);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Query info about the block.
|
// 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 blockFunction = runtime.getOpcodeFunction(opcode);
|
||||||
var isHat = runtime.getIsHat(opcode);
|
var isHat = runtime.getIsHat(opcode);
|
||||||
var fields = target.blocks.getFields(currentBlockId);
|
|
||||||
var inputs = target.blocks.getInputs(currentBlockId);
|
|
||||||
|
|
||||||
if (!opcode) {
|
if (!opcode) {
|
||||||
console.warn('Could not get opcode for block: ' + currentBlockId);
|
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).
|
// Add any mutation to args (e.g., for procedures).
|
||||||
var mutation = target.blocks.getMutation(currentBlockId);
|
var mutation = blockContainer.getMutation(currentBlockId);
|
||||||
if (mutation) {
|
if (mutation) {
|
||||||
argValues.mutation = mutation;
|
argValues.mutation = mutation;
|
||||||
}
|
}
|
||||||
|
@ -165,7 +180,7 @@ var execute = function (sequencer, thread) {
|
||||||
sequencer.stepToProcedure(thread, procedureName);
|
sequencer.stepToProcedure(thread, procedureName);
|
||||||
},
|
},
|
||||||
getProcedureParamNames: function (procedureName) {
|
getProcedureParamNames: function (procedureName) {
|
||||||
return thread.target.blocks.getProcedureParamNames(procedureName);
|
return blockContainer.getProcedureParamNames(procedureName);
|
||||||
},
|
},
|
||||||
pushParam: function (paramName, paramValue) {
|
pushParam: function (paramName, paramValue) {
|
||||||
thread.pushParam(paramName, paramValue);
|
thread.pushParam(paramName, paramValue);
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
var EventEmitter = require('events');
|
var EventEmitter = require('events');
|
||||||
var Sequencer = require('./sequencer');
|
var Sequencer = require('./sequencer');
|
||||||
|
var Blocks = require('./blocks');
|
||||||
var Thread = require('./thread');
|
var Thread = require('./thread');
|
||||||
var util = require('util');
|
var util = require('util');
|
||||||
|
|
||||||
|
@ -44,6 +45,8 @@ function Runtime () {
|
||||||
/** @type {!Sequencer} */
|
/** @type {!Sequencer} */
|
||||||
this.sequencer = new Sequencer(this);
|
this.sequencer = new Sequencer(this);
|
||||||
|
|
||||||
|
this.flyoutBlocks = new Blocks();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Map to look up a block primitive's implementation function by its opcode.
|
* 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.
|
* 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) {
|
if (thread.requestScriptGlowInFrame && target == this._editingTarget) {
|
||||||
var blockForThread = thread.peekStack() || thread.topBlock;
|
var blockForThread = thread.peekStack() || thread.topBlock;
|
||||||
var script = target.blocks.getTopLevelScript(blockForThread);
|
var script = target.blocks.getTopLevelScript(blockForThread);
|
||||||
|
if (!script) {
|
||||||
|
// Attempt to find in flyout blocks.
|
||||||
|
script = this.flyoutBlocks.getTopLevelScript(blockForThread);
|
||||||
|
}
|
||||||
if (script) {
|
if (script) {
|
||||||
requestedGlowsThisFrame.push(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.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) {
|
VirtualMachine.prototype.blockListener = function (e) {
|
||||||
if (this.editingTarget) {
|
if (this.editingTarget) {
|
||||||
this.editingTarget.blocks.blocklyListen(
|
this.editingTarget.blocks.blocklyListen(e, this.runtime);
|
||||||
e,
|
|
||||||
false,
|
|
||||||
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
|
* 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.
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue