@@ -28,13 +28,13 @@ import { ExtendedPythonGenerator } from '../editor/extended_python_generator';
2828import * as storageModule from '../storage/module' ;
2929import * as storageModuleContent from '../storage/module_content' ;
3030import { NONCOPYABLE_BLOCK } from './noncopyable_block' ;
31- import { BLOCK_NAME as MRC_MECHANISM_NAME } from './mrc_mechanism' ;
31+ import { createMechanismBlock , BLOCK_NAME as MRC_MECHANISM_NAME } from './mrc_mechanism' ;
3232import { OUTPUT_NAME as MECHANISM_OUTPUT } from './mrc_mechanism' ;
3333import { MechanismBlock } from './mrc_mechanism' ;
34- import { BLOCK_NAME as MRC_COMPONENT_NAME } from './mrc_component' ;
34+ import { BLOCK_NAME as MRC_COMPONENT_NAME } from './mrc_component' ;
3535import { OUTPUT_NAME as COMPONENT_OUTPUT } from './mrc_component' ;
3636import { ComponentBlock } from './mrc_component' ;
37- import { BLOCK_NAME as MRC_EVENT_NAME } from './mrc_event' ;
37+ import { BLOCK_NAME as MRC_EVENT_NAME } from './mrc_event' ;
3838import { OUTPUT_NAME as EVENT_OUTPUT } from './mrc_event' ;
3939import { EventBlock } from './mrc_event' ;
4040import { getModuleTypeForWorkspace } from './utils/workspaces' ;
@@ -103,49 +103,49 @@ const MECHANISM_COMPONENT_HOLDER = {
103103 // Handle mechanisms input visibility
104104 if ( ! this . mrcHideMechanisms ) {
105105 this . appendStatementInput ( INPUT_MECHANISMS )
106- . setCheck ( MECHANISM_OUTPUT )
107- . appendField ( Blockly . Msg . MECHANISMS ) ;
106+ . setCheck ( MECHANISM_OUTPUT )
107+ . appendField ( Blockly . Msg . MECHANISMS ) ;
108108 }
109109
110110 const componentsField = new Blockly . FieldLabel ( Blockly . Msg . COMPONENTS ) ;
111111 this . appendStatementInput ( INPUT_COMPONENTS )
112- . setCheck ( COMPONENT_OUTPUT )
113- . appendField ( componentsField ) ;
112+ . setCheck ( COMPONENT_OUTPUT )
113+ . appendField ( componentsField ) ;
114114
115115 // Handle private components input visibility
116116 if ( ! this . mrcHidePrivateComponents ) {
117- const privateComponentsField = new Blockly . FieldLabel ( Blockly . Msg . PRIVATE_COMPONENTS ) ;
118- this . appendStatementInput ( INPUT_PRIVATE_COMPONENTS )
119- . setCheck ( COMPONENT_OUTPUT )
120- . appendField ( privateComponentsField ) ;
121- // Set tooltips on both componentsField and privateComponentsField.
122- componentsField . setTooltip ( Blockly . Msg . COMPONENTS_TOOLTIP ) ;
123- privateComponentsField . setTooltip ( Blockly . Msg . PRIVATE_COMPONENTS_TOOLTIP ) ;
117+ const privateComponentsField = new Blockly . FieldLabel ( Blockly . Msg . PRIVATE_COMPONENTS ) ;
118+ this . appendStatementInput ( INPUT_PRIVATE_COMPONENTS )
119+ . setCheck ( COMPONENT_OUTPUT )
120+ . appendField ( privateComponentsField ) ;
121+ // Set tooltips on both componentsField and privateComponentsField.
122+ componentsField . setTooltip ( Blockly . Msg . COMPONENTS_TOOLTIP ) ;
123+ privateComponentsField . setTooltip ( Blockly . Msg . PRIVATE_COMPONENTS_TOOLTIP ) ;
124124 }
125125
126126 this . appendStatementInput ( INPUT_EVENTS )
127- . setCheck ( EVENT_OUTPUT )
128- . appendField ( Blockly . Msg . EVENTS ) ;
127+ . setCheck ( EVENT_OUTPUT )
128+ . appendField ( Blockly . Msg . EVENTS ) ;
129129 } ,
130130 /**
131131 * mrcOnLoad is called for each MechanismComponentHolderBlock when the blocks are loaded in the blockly
132132 * workspace.
133133 */
134- mrcOnLoad : function ( this : MechanismComponentHolderBlock , editor : Editor ) : void {
134+ mrcOnLoad : function ( this : MechanismComponentHolderBlock , editor : Editor ) : void {
135135 this . collectDescendants ( editor , false ) ;
136136 } ,
137137 /**
138138 * mrcOnDescendantDisconnect is called for each MechanismComponentHolderBlock when any descendant is
139139 * disconnected.
140140 */
141- mrcOnDescendantDisconnect : function ( this : MechanismComponentHolderBlock , editor : Editor ) : void {
141+ mrcOnDescendantDisconnect : function ( this : MechanismComponentHolderBlock , editor : Editor ) : void {
142142 this . collectDescendants ( editor , true ) ;
143143 } ,
144144 mrcDescendantsMayHaveChanged : function ( this : MechanismComponentHolderBlock , editor : Editor ) : void {
145145 this . collectDescendants ( editor , true ) ;
146146 } ,
147147 collectDescendants : function (
148- this : MechanismComponentHolderBlock , editor : Editor , updateToolboxIfDescendantsChanged : boolean ) : void {
148+ this : MechanismComponentHolderBlock , editor : Editor , updateToolboxIfDescendantsChanged : boolean ) : void {
149149 let mechanismBlockIds = '' ;
150150 let componentBlockIds = '' ;
151151 let privateComponentBlockIds = '' ;
@@ -202,9 +202,9 @@ const MECHANISM_COMPONENT_HOLDER = {
202202
203203 if ( updateToolboxIfDescendantsChanged ) {
204204 if ( mechanismBlockIds !== this . mrcMechanismBlockIds ||
205- componentBlockIds !== this . mrcComponentBlockIds ||
206- privateComponentBlockIds !== this . mrcPrivateComponentBlockIds ||
207- eventBlockIds !== this . mrcEventBlockIds ) {
205+ componentBlockIds !== this . mrcComponentBlockIds ||
206+ privateComponentBlockIds !== this . mrcPrivateComponentBlockIds ||
207+ eventBlockIds !== this . mrcEventBlockIds ) {
208208 editor . updateToolboxAfterDelay ( ) ;
209209 }
210210 }
@@ -221,14 +221,14 @@ const MECHANISM_COMPONENT_HOLDER = {
221221 setNameOfChildBlock ( this : MechanismComponentHolderBlock , child : Blockly . Block ) : void {
222222 const otherNames : string [ ] = [ ]
223223 this . getDescendants ( true )
224- . filter ( descendant =>
225- descendant . type === MRC_MECHANISM_NAME ||
226- descendant . type === MRC_COMPONENT_NAME ||
227- descendant . type === MRC_EVENT_NAME )
228- . filter ( descendant => descendant . id !== child . id )
229- . forEach ( descendant => {
230- otherNames . push ( descendant . getFieldValue ( 'NAME' ) ) ;
231- } ) ;
224+ . filter ( descendant =>
225+ descendant . type === MRC_MECHANISM_NAME ||
226+ descendant . type === MRC_COMPONENT_NAME ||
227+ descendant . type === MRC_EVENT_NAME )
228+ . filter ( descendant => descendant . id !== child . id )
229+ . forEach ( descendant => {
230+ otherNames . push ( descendant . getFieldValue ( 'NAME' ) ) ;
231+ } ) ;
232232 const currentName = child . getFieldValue ( 'NAME' ) ;
233233 // mechanism and component names must be valid python identifiers.
234234 // event names do not need to be valid python identifiers.
@@ -367,8 +367,8 @@ function pythonFromBlockInMechanism(block: MechanismComponentHolderBlock, genera
367367}
368368
369369export const pythonFromBlock = function (
370- block : MechanismComponentHolderBlock ,
371- generator : ExtendedPythonGenerator ) {
370+ block : MechanismComponentHolderBlock ,
371+ generator : ExtendedPythonGenerator ) {
372372 switch ( generator . getModuleType ( ) ) {
373373 case storageModule . ModuleType . ROBOT :
374374 pythonFromBlockInRobot ( block , generator ) ;
@@ -423,7 +423,7 @@ export function hasAnyComponents(workspace: Blockly.Workspace): boolean {
423423 * Collects the args for the mechanism's constructor and defineHardware method.
424424 */
425425export function getMechanismInitArgNames ( workspace : Blockly . Workspace , mechanismInitArgNames : string [ ] ) : void {
426- workspace . getBlocksByType ( BLOCK_NAME ) . forEach ( block => {
426+ workspace . getBlocksByType ( BLOCK_NAME ) . forEach ( block => {
427427 const inputConnections : Blockly . Connection [ ] = [ ] ;
428428 const componentsInput = block . getInput ( INPUT_COMPONENTS ) ;
429429 if ( componentsInput && componentsInput . connection ) {
@@ -449,8 +449,8 @@ export function getMechanismInitArgNames(workspace: Blockly.Workspace, mechanism
449449}
450450
451451export function getMechanisms (
452- workspace : Blockly . Workspace ,
453- mechanisms : storageModuleContent . MechanismInRobot [ ] ) : void {
452+ workspace : Blockly . Workspace ,
453+ mechanisms : storageModuleContent . MechanismInRobot [ ] ) : void {
454454 // Get the holder block and ask it for the mechanisms.
455455 workspace . getBlocksByType ( BLOCK_NAME ) . forEach ( block => {
456456 const mechanismsFromHolder : storageModuleContent . MechanismInRobot [ ] =
@@ -460,8 +460,8 @@ export function getMechanisms(
460460}
461461
462462export function getComponents (
463- workspace : Blockly . Workspace ,
464- components : storageModuleContent . Component [ ] ) : void {
463+ workspace : Blockly . Workspace ,
464+ components : storageModuleContent . Component [ ] ) : void {
465465 // Get the holder block and ask it for the components.
466466 workspace . getBlocksByType ( BLOCK_NAME ) . forEach ( block => {
467467 const componentsFromHolder : storageModuleContent . Component [ ] =
@@ -471,8 +471,8 @@ export function getComponents(
471471}
472472
473473export function getPrivateComponents (
474- workspace : Blockly . Workspace ,
475- components : storageModuleContent . Component [ ] ) : void {
474+ workspace : Blockly . Workspace ,
475+ components : storageModuleContent . Component [ ] ) : void {
476476 // Get the holder block and ask it for the private components.
477477 workspace . getBlocksByType ( BLOCK_NAME ) . forEach ( block => {
478478 const privateComponentsFromHolder : storageModuleContent . Component [ ] =
@@ -482,16 +482,16 @@ export function getPrivateComponents(
482482}
483483
484484export function getAllComponents (
485- workspace : Blockly . Workspace ,
486- components : storageModuleContent . Component [ ] ) : void {
485+ workspace : Blockly . Workspace ,
486+ components : storageModuleContent . Component [ ] ) : void {
487487 // Get both regular and private components for when creating a mechanism
488488 getComponents ( workspace , components ) ;
489489 getPrivateComponents ( workspace , components ) ;
490490}
491491
492492export function getEvents (
493- workspace : Blockly . Workspace ,
494- events : storageModuleContent . Event [ ] ) : void {
493+ workspace : Blockly . Workspace ,
494+ events : storageModuleContent . Event [ ] ) : void {
495495 // Get the holder block and ask it for the events.
496496 workspace . getBlocksByType ( BLOCK_NAME ) . forEach ( block => {
497497 const eventsFromHolder : storageModuleContent . Event [ ] =
@@ -507,17 +507,61 @@ export function mrcDescendantsMayHaveChanged(workspace: Blockly.Workspace, edito
507507 } ) ;
508508}
509509
510+ // This is called to add a mechanism block to the robot's workspace when a new mechanism is created
511+ // since we aren't guaranteed that the robot has a live workspace at this time, we have to work in JSON.
512+ export function mrcAddMechanismBlockToRobotContent ( robotContent : storageModuleContent . ModuleContent ,
513+ mechanism : storageModule . Mechanism ) : void {
514+ const mechanismBlock = createMechanismBlock ( mechanism , [ ] , false ) ;
515+
516+ // Build the plain JSON object for the new mechanism block (Blockly serialization format).
517+ const mechanismBlockJson : { [ key : string ] : unknown } = { type : mechanismBlock . type } ;
518+ if ( mechanismBlock . extraState ) {
519+ mechanismBlockJson [ 'extraState' ] = mechanismBlock . extraState ;
520+ }
521+ if ( mechanismBlock . fields ) {
522+ mechanismBlockJson [ 'fields' ] = mechanismBlock . fields ;
523+ }
524+ if ( mechanismBlock . inputs ) {
525+ mechanismBlockJson [ 'inputs' ] = mechanismBlock . inputs ;
526+ }
527+
528+ // Mutate the JSON blocks directly (no live workspace needed).
529+ const blocks = robotContent . getBlocks ( ) ;
530+ const topBlocks : { [ key : string ] : any } [ ] = blocks ?. blocks ?. blocks ?? [ ] ;
531+
532+ for ( const block of topBlocks ) {
533+ if ( block . type !== BLOCK_NAME ) {
534+ continue ;
535+ }
536+ if ( ! block . inputs ) {
537+ block . inputs = { } ;
538+ }
539+ if ( ! block . inputs [ INPUT_MECHANISMS ] ) {
540+ block . inputs [ INPUT_MECHANISMS ] = { block : mechanismBlockJson } ;
541+ } else {
542+ // Walk to the last block in the chain and append.
543+ let lastBlock = block . inputs [ INPUT_MECHANISMS ] . block ;
544+ while ( lastBlock . next ?. block ) {
545+ lastBlock = lastBlock . next . block ;
546+ }
547+ lastBlock . next = { block : mechanismBlockJson } ;
548+ }
549+ }
550+
551+ robotContent . setBlocks ( blocks ) ;
552+ }
553+
510554/**
511555 * Upgrades the MechanismComponentHolderBlock in the given workspace from version 001 to 002 by
512556 * setting mrcHidePrivateComponents to true.
513557 * This function should only be called when upgrading old projects.
514558 */
515559export function upgrade_001_to_002 ( workspace : Blockly . Workspace ) {
516- // Make sure the module type is ROBOT.
517- if ( getModuleTypeForWorkspace ( workspace ) !== storageModule . ModuleType . ROBOT ) {
518- throw new Error ( 'upgrade_001_to_002 should only be called for a robot module.' ) ;
560+ // Make sure the module type is ROBOT.
561+ if ( getModuleTypeForWorkspace ( workspace ) !== storageModule . ModuleType . ROBOT ) {
562+ throw new Error ( 'upgrade_001_to_002 should only be called for a robot module.' ) ;
563+ }
564+ workspace . getBlocksByType ( BLOCK_NAME ) . forEach ( block => {
565+ ( block as MechanismComponentHolderBlock ) . mrcHidePrivateComponents = true ;
566+ } ) ;
519567 }
520- workspace . getBlocksByType ( BLOCK_NAME ) . forEach ( block => {
521- ( block as MechanismComponentHolderBlock ) . mrcHidePrivateComponents = true ;
522- } ) ;
523- }
0 commit comments