diff --git a/src/blocks/mrc_call_python_function.ts b/src/blocks/mrc_call_python_function.ts index c82f6cc0..07ee5c5b 100644 --- a/src/blocks/mrc_call_python_function.ts +++ b/src/blocks/mrc_call_python_function.ts @@ -28,6 +28,7 @@ import { getClassData, getAllowedTypesForSetCheck, getOutputCheck } from './util import { FunctionData, findSuperFunctionData } from './utils/python_json_types'; import * as value from './utils/value'; import * as variable from './utils/variable'; +import { Editor } from '../editor/editor'; import { ExtendedPythonGenerator } from '../editor/extended_python_generator'; import { createFieldDropdown } from '../fields/FieldDropdown'; import { createFieldNonEditableText } from '../fields/FieldNonEditableText'; @@ -542,9 +543,13 @@ const CALL_PYTHON_FUNCTION = { break; } case FunctionKind.INSTANCE_COMPONENT: { - // TODO: We need the list of component names for this.mrcComponentClassName so we can + let componentNames: string[] = []; + // Get the list of component names whose type matches this.mrcComponentClassName so we can // create a dropdown that has the appropriate component names. - const componentNames: string[] = []; + const editor = Editor.getEditorForBlocklyWorkspace(this.workspace); + if (editor) { + componentNames = editor.getComponentNames(this.mrcComponentClassName); + } const componentName = this.getComponentName(); if (!componentNames.includes(componentName)) { componentNames.push(componentName); diff --git a/src/blocks/mrc_mechanism_component_holder.ts b/src/blocks/mrc_mechanism_component_holder.ts index 01c6f03c..12b245a5 100644 --- a/src/blocks/mrc_mechanism_component_holder.ts +++ b/src/blocks/mrc_mechanism_component_holder.ts @@ -25,6 +25,7 @@ import { MRC_STYLE_MECHANISMS } from '../themes/styles'; import * as ChangeFramework from './utils/change_framework'; import { getLegalName } from './utils/python'; import { ExtendedPythonGenerator } from '../editor/extended_python_generator'; +import * as commonStorage from '../storage/common_storage'; import { OUTPUT_NAME as MECHANISM_OUTPUT } from './mrc_mechanism'; import { BLOCK_NAME as MRC_MECHANISM_NAME } from './mrc_mechanism'; import { BLOCK_NAME as MRC_COMPONENT_NAME } from './mrc_component'; @@ -127,7 +128,33 @@ const MECHANISM_COMPONENT_HOLDER = { } } }, + getComponents: function (this: MechanismComponentHolderBlock): commonStorage.Component[] { + const components: commonStorage.Component[] = [] + + // Get component blocks from the COMPONENTS input + const componentsInput = this.getInput('COMPONENTS'); + if (componentsInput && componentsInput.connection) { + // Walk through all connected component blocks. + let componentBlock = componentsInput.connection.targetBlock(); + while (componentBlock) { + if (componentBlock.type === 'mrc_component') { + const componentName = componentBlock.getFieldValue('NAME'); + const componentType = componentBlock.getFieldValue('TYPE'); + + if (componentName && componentType) { + components.push({ + name: componentName, + className: componentType, + }); + } + } + // Move to the next block in the chain + componentBlock = componentBlock.getNextBlock(); + } + } + return components; + }, } let toolboxUpdateTimeout: NodeJS.Timeout | null = null; @@ -190,4 +217,4 @@ export const pythonFromBlock = function ( pythonFromBlockInMechanism(block, generator); } return '' -} \ No newline at end of file +} diff --git a/src/editor/editor.ts b/src/editor/editor.ts index 204bd517..7781210d 100644 --- a/src/editor/editor.ts +++ b/src/editor/editor.ts @@ -24,7 +24,7 @@ import * as Blockly from 'blockly/core'; import { extendedPythonGenerator } from './extended_python_generator'; import { GeneratorContext } from './generator_context'; import * as commonStorage from '../storage/common_storage'; - +import * as mechanismComponentHolder from '../blocks/mrc_mechanism_component_holder'; //import { testAllBlocksInToolbox } from '../toolbox/toolbox_tests'; import { MethodsCategory} from '../toolbox/methods_category'; import { EventsCategory} from '../toolbox/event_category'; @@ -151,7 +151,7 @@ export class Editor { ); this.moduleContent = moduleContents[this.modulePath]; if (this.robotPath === this.modulePath) { - this.robotContent = this.moduleContent + this.robotContent = this.moduleContent; } else { this.robotContent = moduleContents[this.robotPath]; } @@ -233,7 +233,14 @@ export class Editor { const components: commonStorage.Component[] = []; if (this.currentModule?.moduleType === commonStorage.MODULE_TYPE_ROBOT || this.currentModule?.moduleType === commonStorage.MODULE_TYPE_MECHANISM) { - // TODO(lizlooney): Fill the components array. + // Get the holder block and ask it for the components. + const holderBlocks = this.blocklyWorkspace.getBlocksByType(mechanismComponentHolder.BLOCK_NAME); + holderBlocks.forEach(holderBlock => { + const componentsFromHolder: commonStorage.Component[] = holderBlock.getComponents(); + componentsFromHolder.forEach(component => { + components.push(component); + }); + }); } return components; } @@ -247,4 +254,43 @@ export class Editor { throw e; } } + + /** + * Returns the names of components defined in the robot that have the given component class name. + */ + // TODO: what about components defined in a mechanism? + public getComponentNames(componentClassName: string): string[] { + let components: commonStorage.Component[]; + + if (this.currentModule?.moduleType === commonStorage.MODULE_TYPE_ROBOT) { + components = this.getComponents(); + } else { + if (!this.robotContent) { + throw new Error('getComponentNames: this.robotContent is null.'); + } + components = commonStorage.extractComponents(this.robotContent); + } + + const componentNames: string[] = []; + components.forEach((component) => { + if (component.className === componentClassName) { + componentNames.push(component.name); + } + }); + return componentNames; + } + + public static getEditorForBlocklyWorkspace(workspace: Blockly.Workspace): Editor | null { + if (workspace.id in Editor.workspaceIdToEditor) { + return Editor.workspaceIdToEditor[workspace.id]; + } + + // If the workspace id was not found, it might be because the workspace is associated with the + // toolbox flyout, not a real workspace. In that case, use the first editor. + const allEditors = Object.values(Editor.workspaceIdToEditor); + if (allEditors.length) { + return allEditors[0]; + } + return null; + } } diff --git a/src/toolbox/hardware_category.ts b/src/toolbox/hardware_category.ts index b9c0cb35..df274082 100644 --- a/src/toolbox/hardware_category.ts +++ b/src/toolbox/hardware_category.ts @@ -29,7 +29,7 @@ import * as Blockly from 'blockly/core'; import * as commonStorage from '../storage/common_storage'; import { getAllPossibleMechanisms } from './blocks_mechanisms'; import { getAllPossibleComponents, getBlocks } from './blocks_components'; -import * as MechanismComponentHolder from '../blocks/mrc_mechanism_component_holder'; +import * as mechanismComponentHolder from '../blocks/mrc_mechanism_component_holder'; export function getHardwareCategory(currentModule: commonStorage.Module) { if (currentModule.moduleType === commonStorage.MODULE_TYPE_OPMODE) { @@ -254,33 +254,19 @@ function getComponentsBlocks(currentModule: commonStorage.Module, hideParams : b // Get components from the current workspace const workspace = Blockly.getMainWorkspace(); if (workspace) { - const holderBlocks = workspace.getBlocksByType(MechanismComponentHolder.BLOCK_NAME); + // Get the holder block and ask it for the components. + const holderBlocks = workspace.getBlocksByType(mechanismComponentHolder.BLOCK_NAME); holderBlocks.forEach(holderBlock => { - // Get component blocks from the COMPONENTS input - const componentsInput = holderBlock.getInput('COMPONENTS'); - if (componentsInput && componentsInput.connection) { - let componentBlock = componentsInput.connection.targetBlock(); - - // Walk through all connected component blocks - while (componentBlock) { - if (componentBlock.type === 'mrc_component') { - const componentName = componentBlock.getFieldValue('NAME'); - const componentType = componentBlock.getFieldValue('TYPE'); - - if (componentName && componentType) { - // Get the blocks for this specific component - contents.push({ - kind: 'category', - name: componentName, - contents: getBlocks(componentType, componentName), - }); - } - } - // Move to the next block in the chain - componentBlock = componentBlock.getNextBlock(); - } - } + const componentsFromHolder: commonStorage.Component[] = holderBlock.getComponents(); + componentsFromHolder.forEach(component => { + // Get the blocks for this specific component + contents.push({ + kind: 'category', + name: component.name, + contents: getBlocks(component.className, component.name), + }); + }); }); } return { @@ -288,4 +274,4 @@ function getComponentsBlocks(currentModule: commonStorage.Module, hideParams : b name: 'Components', contents, }; -} \ No newline at end of file +}