From 9264f30198cd549045e94aa783b215a3841ab14d Mon Sep 17 00:00:00 2001 From: Paul Kaplan <pkaplan@media.mit.edu> Date: Wed, 30 Jan 2019 09:39:18 -0500 Subject: [PATCH] Make the toolbox xml reflect the costume, sound and backdrop name This invalidates the toolbox XML when switching back to the code tab after e.g. renaming a costume, making the code tab --- src/containers/blocks.jsx | 38 +++++++++++++++++++++++++---------- src/lib/make-toolbox-xml.js | 40 ++++++++++++++++++++++++++----------- 2 files changed, 56 insertions(+), 22 deletions(-) diff --git a/src/containers/blocks.jsx b/src/containers/blocks.jsx index e58337f53..98a01db1b 100644 --- a/src/containers/blocks.jsx +++ b/src/containers/blocks.jsx @@ -50,6 +50,7 @@ class Blocks extends React.Component { bindAll(this, [ 'attachVM', 'detachVM', + 'getToolboxXML', 'handleCategorySelected', 'handleConnectionModalStart', 'handleDrop', @@ -307,12 +308,32 @@ class Blocks extends React.Component { onVisualReport (data) { this.workspace.reportValue(data.id, data.value); } + getToolboxXML () { + // Use try/catch because this requires digging pretty deep into the VM + // Code inside intentionally ignores several error situations (no stage, etc.) + // Because they would get caught by this try/catch + try { + let {editingTarget: target, runtime} = this.props.vm; + const stage = runtime.getTargetForStage(); + if (!target) target = stage; // If no editingTarget, use the stage + + const stageCostumes = stage.getCostumes(); + const targetCostumes = target.getCostumes(); + const targetSounds = target.getSounds(); + const dynamicBlocksXML = this.props.vm.runtime.getBlocksXML(); + return makeToolboxXML(target.isStage, target.id, dynamicBlocksXML, + targetCostumes[0].name, + stageCostumes[0].name, + targetSounds.length > 0 ? targetSounds[0].name : '' + ); + } catch { + return null; + } + } onWorkspaceUpdate (data) { // When we change sprites, update the toolbox to have the new sprite's blocks - if (this.props.vm.editingTarget) { - const target = this.props.vm.editingTarget; - const dynamicBlocksXML = this.props.vm.runtime.getBlocksXML(); - const toolboxXML = makeToolboxXML(target.isStage, target.id, dynamicBlocksXML); + const toolboxXML = this.getToolboxXML(); + if (toolboxXML) { this.props.updateToolboxState(toolboxXML); } @@ -360,12 +381,9 @@ class Blocks extends React.Component { // this actually defines blocks and MUST run regardless of the UI state this.ScratchBlocks.defineBlocksWithJsonArray(blocksInfo.map(blockInfo => blockInfo.json).filter(x => x)); - // update the toolbox view: this can be skipped if we're not looking at a target, etc. - const runtime = this.props.vm.runtime; - const target = runtime.getEditingTarget() || runtime.getTargetForStage(); - if (target) { - const dynamicBlocksXML = runtime.getBlocksXML(); - const toolboxXML = makeToolboxXML(target.isStage, target.id, dynamicBlocksXML); + // Update the toolbox with new blocks + const toolboxXML = this.getToolboxXML(); + if (toolboxXML) { this.props.updateToolboxState(toolboxXML); } } diff --git a/src/lib/make-toolbox-xml.js b/src/lib/make-toolbox-xml.js index 936859666..4217b6e6b 100644 --- a/src/lib/make-toolbox-xml.js +++ b/src/lib/make-toolbox-xml.js @@ -138,7 +138,7 @@ const motion = function (isStage, targetId) { `; }; -const looks = function (isStage, targetId) { +const looks = function (isStage, targetId, costumeName, backdropName) { const hello = ScratchBlocks.ScratchMsgs.translate('LOOKS_HELLO', 'Hello!'); const hmm = ScratchBlocks.ScratchMsgs.translate('LOOKS_HMM', 'Hmm...'); return ` @@ -187,25 +187,33 @@ const looks = function (isStage, targetId) { ${isStage ? ` <block type="looks_switchbackdropto"> <value name="BACKDROP"> - <shadow type="looks_backdrops"/> + <shadow type="looks_backdrops"> + <field name="BACKDROP">${backdropName}</field> + </shadow> </value> </block> <block type="looks_switchbackdroptoandwait"> <value name="BACKDROP"> - <shadow type="looks_backdrops"/> + <shadow type="looks_backdrops"> + <field name="BACKDROP">${backdropName}</field> + </shadow> </value> </block> <block type="looks_nextbackdrop"/> ` : ` <block id="${targetId}_switchcostumeto" type="looks_switchcostumeto"> <value name="COSTUME"> - <shadow type="looks_costume"/> + <shadow type="looks_costume"> + <field name="COSTUME">${costumeName}</field> + </shadow> </value> </block> <block type="looks_nextcostume"/> <block type="looks_switchbackdropto"> <value name="BACKDROP"> - <shadow type="looks_backdrops"/> + <shadow type="looks_backdrops"> + <field name="BACKDROP">${backdropName}</field> + </shadow> </value> </block> <block type="looks_nextbackdrop"/> @@ -267,17 +275,21 @@ const looks = function (isStage, targetId) { `; }; -const sound = function (isStage, targetId) { +const sound = function (isStage, targetId, soundName) { return ` <category name="%{BKY_CATEGORY_SOUND}" id="sound" colour="#D65CD6" secondaryColour="#BD42BD"> <block id="${targetId}_sound_playuntildone" type="sound_playuntildone"> <value name="SOUND_MENU"> - <shadow type="sound_sounds_menu"/> + <shadow type="sound_sounds_menu"> + <field name="SOUND_MENU">${soundName}</field> + </shadow> </value> </block> <block id="${targetId}_sound_play" type="sound_play"> <value name="SOUND_MENU"> - <shadow type="sound_sounds_menu"/> + <shadow type="sound_sounds_menu"> + <field name="SOUND_MENU">${soundName}</field> + </shadow> </value> </block> <block type="sound_stopallsounds"/> @@ -692,17 +704,21 @@ const xmlClose = '</xml>'; /** * @param {!boolean} isStage - Whether the toolbox is for a stage-type target. * @param {?string} targetId - The current editing target - * @param {string?} categoriesXML - null for default toolbox, or an XML string with <category> elements. + * @param {?string} categoriesXML - null for default toolbox, or an XML string with <category> elements. + * @param {?string} costumeName - The name of the default selected costume dropdown. + * @param {?string} backdropName - The name of the default selected backdrop dropdown. + * @param {?string} soundName - The name of the default selected sound dropdown. * @returns {string} - a ScratchBlocks-style XML document for the contents of the toolbox. */ -const makeToolboxXML = function (isStage, targetId, categoriesXML) { +const makeToolboxXML = function (isStage, targetId, categoriesXML, + costumeName = '', backdropName = '', soundName = '') { const gap = [categorySeparator]; const everything = [ xmlOpen, motion(isStage, targetId), gap, - looks(isStage, targetId), gap, - sound(isStage, targetId), gap, + looks(isStage, targetId, costumeName, backdropName), gap, + sound(isStage, targetId, soundName), gap, events(isStage, targetId), gap, control(isStage, targetId), gap, sensing(isStage, targetId), gap, -- GitLab