From 77adb943fd8faab973eb12642fadb698098973df Mon Sep 17 00:00:00 2001 From: Liz Looney Date: Wed, 13 Aug 2025 23:48:22 -0700 Subject: [PATCH 1/9] Make contents optional in Category class because custom categories don't have contents. --- src/toolbox/items.ts | 2 +- src/toolbox/robotpy_toolbox.ts | 11 +++++++---- src/toolbox/toolbox_common.ts | 2 +- 3 files changed, 9 insertions(+), 6 deletions(-) diff --git a/src/toolbox/items.ts b/src/toolbox/items.ts index 76d35a75..de135b71 100644 --- a/src/toolbox/items.ts +++ b/src/toolbox/items.ts @@ -77,7 +77,7 @@ export class Category extends Item { custom?: string; /** The blocks for this category. */ - contents: ContentsType[] = []; + contents?: ContentsType[] = []; constructor(name: string, contents: ContentsType[], categorystyle?: string, custom?: string) { super('category'); diff --git a/src/toolbox/robotpy_toolbox.ts b/src/toolbox/robotpy_toolbox.ts index 03be1e37..fb1e8ff5 100644 --- a/src/toolbox/robotpy_toolbox.ts +++ b/src/toolbox/robotpy_toolbox.ts @@ -51,13 +51,15 @@ export function getToolboxCategories(shownPythonToolboxCategories: Set | const lastDot = path.lastIndexOf('.'); const name = (lastDot != -1) ? path.substring(lastDot + 1) : path; + const contents: toolboxItems.ContentsType[] = []; + addModuleBlocks(moduleData, contents); + const moduleCategory: toolboxItems.PythonModuleCategory = { kind: 'category', name: name, moduleName: moduleData.moduleName, - contents: [], + contents: contents, }; - addModuleBlocks(moduleData, moduleCategory.contents); allCategories[path] = moduleCategory; moduleCategories[path] = moduleCategory; } @@ -68,13 +70,14 @@ export function getToolboxCategories(shownPythonToolboxCategories: Set | const lastDot = path.lastIndexOf('.'); const name = (lastDot != -1) ? path.substring(lastDot + 1) : path; + const contents: toolboxItems.ContentsType[] = []; + addClassBlocks(classData, contents); const classCategory: toolboxItems.PythonClassCategory = { kind: 'category', name: name, className: classData.className, - contents: [], + contents: contents, }; - addClassBlocks(classData, classCategory.contents); allCategories[path] = classCategory; classCategories[path] = classCategory; } diff --git a/src/toolbox/toolbox_common.ts b/src/toolbox/toolbox_common.ts index 2bc8f83b..bbb11f34 100644 --- a/src/toolbox/toolbox_common.ts +++ b/src/toolbox/toolbox_common.ts @@ -47,7 +47,7 @@ export function getToolboxItems( ); } const tCategory = testCategory(); - if (tCategory.contents.length > 0) { + if (tCategory.contents && tCategory.contents.length > 0) { contents.push.apply(contents, [tCategory]); } From f038119e445be1c07abf4df10b5bd9f129b9cc36 Mon Sep 17 00:00:00 2001 From: Liz Looney Date: Wed, 13 Aug 2025 23:52:17 -0700 Subject: [PATCH 2/9] Convert getCategory (in event_category.ts and methods_category.ts) from arrow functions to function declarations. See https://google.github.io/styleguide/tsguide.html#function-declarations In mrc_call_python_function.ts: Removed unnecessary semicolon. Changed "...method on a mechanism..." to "...method in a mechanism...". --- src/blocks/mrc_call_python_function.ts | 4 ++-- src/toolbox/event_category.ts | 14 ++++++++------ src/toolbox/methods_category.ts | 14 ++++++++------ 3 files changed, 18 insertions(+), 14 deletions(-) diff --git a/src/blocks/mrc_call_python_function.ts b/src/blocks/mrc_call_python_function.ts index 17fd18fe..a9c7ff7b 100644 --- a/src/blocks/mrc_call_python_function.ts +++ b/src/blocks/mrc_call_python_function.ts @@ -141,7 +141,7 @@ type CallPythonFunctionExtraState = { * Specified only if the function kind is INSTANCE_MECHANISM. */ mechanismBlockId?: string, -}; +} const CALL_PYTHON_FUNCTION = { /** @@ -697,7 +697,7 @@ const CALL_PYTHON_FUNCTION = { } } if (!foundMechanism) { - warnings.push('This block calls a method on a mechanism that no longer exists.'); + warnings.push('This block calls a method in a mechanism that no longer exists.'); } } } diff --git a/src/toolbox/event_category.ts b/src/toolbox/event_category.ts index cafa7449..fd32029d 100644 --- a/src/toolbox/event_category.ts +++ b/src/toolbox/event_category.ts @@ -30,12 +30,14 @@ import { Editor } from '../editor/editor'; const CUSTOM_CATEGORY_EVENTS = 'EVENTS'; -export const getCategory = () => ({ - kind: 'category', - categorystyle: MRC_CATEGORY_STYLE_METHODS, - name: Blockly.Msg['MRC_CATEGORY_EVENTS'], - custom: CUSTOM_CATEGORY_EVENTS, -}); +export function getCategory(): toolboxItems.Category { + return { + kind: 'category', + categorystyle: MRC_CATEGORY_STYLE_METHODS, + name: Blockly.Msg['MRC_CATEGORY_EVENTS'], + custom: CUSTOM_CATEGORY_EVENTS, + }; +} export class EventsCategory { constructor(blocklyWorkspace: Blockly.WorkspaceSvg) { diff --git a/src/toolbox/methods_category.ts b/src/toolbox/methods_category.ts index 47d74a44..32ed8652 100644 --- a/src/toolbox/methods_category.ts +++ b/src/toolbox/methods_category.ts @@ -32,12 +32,14 @@ import { Editor } from '../editor/editor'; const CUSTOM_CATEGORY_METHODS = 'METHODS'; -export const getCategory = () => ({ - kind: 'category', - categorystyle: MRC_CATEGORY_STYLE_METHODS, - name: Blockly.Msg['MRC_CATEGORY_METHODS'], - custom: CUSTOM_CATEGORY_METHODS, -}); +export function getCategory(): toolboxItems.Category { + return { + kind: 'category', + categorystyle: MRC_CATEGORY_STYLE_METHODS, + name: Blockly.Msg['MRC_CATEGORY_METHODS'], + custom: CUSTOM_CATEGORY_METHODS, + }; +} export class MethodsCategory { private robotClassBlocks = getBaseClassBlocks(CLASS_NAME_ROBOT_BASE); From e1b385f3eeb66067e9a23b5a014f9d5b325029f9 Mon Sep 17 00:00:00 2001 From: Liz Looney Date: Wed, 13 Aug 2025 23:57:37 -0700 Subject: [PATCH 3/9] Renamed getRobotEventsCategory to getRobotEventHandlersCategory. Renamed RobotEventsCategory to RobotEventHandlersCategory. In editor.ts, updated code that parses the module content text for the robot and mechanisms to use ? : instead of if/else. --- src/editor/editor.ts | 24 ++++++++++++------------ src/toolbox/hardware_category.ts | 17 +++++++++-------- 2 files changed, 21 insertions(+), 20 deletions(-) diff --git a/src/editor/editor.ts b/src/editor/editor.ts index fef6e8eb..a7ce1bd8 100644 --- a/src/editor/editor.ts +++ b/src/editor/editor.ts @@ -34,7 +34,7 @@ import * as mechanismComponentHolder from '../blocks/mrc_mechanism_component_hol //import { testAllBlocksInToolbox } from '../toolbox/toolbox_tests'; import { MethodsCategory } from '../toolbox/methods_category'; import { EventsCategory } from '../toolbox/event_category'; -import { RobotEventsCategory } from '../toolbox/hardware_category'; +import { RobotEventHandlersCategory } from '../toolbox/hardware_category'; import { getToolboxJSON } from '../toolbox/toolbox'; const EMPTY_TOOLBOX: Blockly.utils.toolbox.ToolboxDefinition = { @@ -67,7 +67,7 @@ export class Editor { // Create the custom toolbox categories so they register their flyout callbacks. new MethodsCategory(blocklyWorkspace); new EventsCategory(blocklyWorkspace); - new RobotEventsCategory(blocklyWorkspace); + new RobotEventHandlersCategory(blocklyWorkspace); } private onChangeWhileLoading(event: Blockly.Events.Abstract) { @@ -150,6 +150,7 @@ export class Editor { promises[this.robotPath] = this.storage.fetchModuleContentText(this.robotPath) } for (const mechanism of this.currentProject.mechanisms) { + // Fetch the module content text for the mechanism. if (mechanism.modulePath !== this.modulePath) { promises[mechanism.modulePath] = this.storage.fetchModuleContentText(mechanism.modulePath) } @@ -162,17 +163,16 @@ export class Editor { }) ); this.moduleContentText = modulePathToContentText[this.modulePath]; - if (this.robotPath === this.modulePath) { - this.robotContent = storageModuleContent.parseModuleContentText(this.moduleContentText); - } else { - this.robotContent = storageModuleContent.parseModuleContentText(modulePathToContentText[this.robotPath]); - } + this.robotContent = storageModuleContent.parseModuleContentText( + (this.robotPath === this.modulePath) + ? this.moduleContentText + : modulePathToContentText[this.robotPath]); for (const mechanism of this.currentProject.mechanisms) { - if (mechanism.modulePath === this.modulePath) { - this.mechanismClassNameToModuleContent[mechanism.className] = storageModuleContent.parseModuleContentText(this.moduleContentText); - } else { - this.mechanismClassNameToModuleContent[mechanism.className] = storageModuleContent.parseModuleContentText(modulePathToContentText[mechanism.modulePath]); - } + this.mechanismClassNameToModuleContent[mechanism.className] = + storageModuleContent.parseModuleContentText( + (mechanism.modulePath === this.modulePath) + ? this.moduleContentText + : modulePathToContentText[mechanism.modulePath]); } this.loadBlocksIntoBlocklyWorkspace(); } diff --git a/src/toolbox/hardware_category.ts b/src/toolbox/hardware_category.ts index c0c19861..deffd178 100644 --- a/src/toolbox/hardware_category.ts +++ b/src/toolbox/hardware_category.ts @@ -52,7 +52,7 @@ export function getHardwareCategory(currentModule: storageModule.Module): toolbo getRobotMechanismsCategory(currentModule), getRobotComponentsCategory(), getRobotMethodsCategory(), - getRobotEventsCategory(), + getRobotEventHandlersCategory(), ] }; } @@ -205,22 +205,23 @@ function getComponentsCategory(moduleType : string): toolboxItems.Category { }; } -const CUSTOM_CATEGORY_ROBOT_EVENTS = 'ROBOT_EVENTS'; +const CUSTOM_CATEGORY_EVENT_HANDLERS_ROBOT = 'EVENT_HANDLERS_ROBOT'; -// The robot events category is shown when the user is editing an opmode. +// The robot event handlers category is shown when the user is editing an opmode. // It allows the user to create event handlers for events previously defined in the Robot. -const getRobotEventsCategory = () => ({ +const getRobotEventHandlersCategory = () => ({ kind: 'category', name: Blockly.Msg['MRC_CATEGORY_EVENTS'], - custom: CUSTOM_CATEGORY_ROBOT_EVENTS, + custom: CUSTOM_CATEGORY_EVENT_HANDLERS_ROBOT, }); -export class RobotEventsCategory { +export class RobotEventHandlersCategory { constructor(blocklyWorkspace: Blockly.WorkspaceSvg) { - blocklyWorkspace.registerToolboxCategoryCallback(CUSTOM_CATEGORY_ROBOT_EVENTS, this.robotEventsFlyout.bind(this)); + blocklyWorkspace.registerToolboxCategoryCallback( + CUSTOM_CATEGORY_EVENT_HANDLERS_ROBOT, this.robotEventHandlersFlyout.bind(this)); } - public robotEventsFlyout(workspace: Blockly.WorkspaceSvg) { + public robotEventHandlersFlyout(workspace: Blockly.WorkspaceSvg) { const contents: toolboxItems.ContentsType[] = []; // Get the list of events from the robot and add the blocks for handling events. From d3797cde30ff256f9c2cd24ccb6d2a33186221a8 Mon Sep 17 00:00:00 2001 From: Liz Looney Date: Thu, 14 Aug 2025 00:05:43 -0700 Subject: [PATCH 4/9] Updated mrc_event_handler.ts to support mechanism events. --- src/blocks/mrc_event_handler.ts | 140 +++++++++++++++++++++++++++----- 1 file changed, 118 insertions(+), 22 deletions(-) diff --git a/src/blocks/mrc_event_handler.ts b/src/blocks/mrc_event_handler.ts index 2991492f..56a12adc 100644 --- a/src/blocks/mrc_event_handler.ts +++ b/src/blocks/mrc_event_handler.ts @@ -52,22 +52,26 @@ const WARNING_ID_EVENT_CHANGED = 'event changed'; export type EventHandlerBlock = Blockly.Block & EventHandlerMixin & Blockly.BlockSvg; interface EventHandlerMixin extends EventHandlerMixinType { - mrcPathOfSender: string; mrcSenderType: SenderType; mrcParameters: Parameter[]; mrcOtherBlockId: string, + mrcMechanismBlockId: string, } type EventHandlerMixinType = typeof EVENT_HANDLER; /** Extra state for serialising event handler blocks. */ export interface EventHandlerExtraState { - pathOfSender: string; senderType: SenderType; /** The parameters of the event handler. */ params: Parameter[]; /** The id of the mrc_event block that defines the event. */ otherBlockId: string, + /** + * The id of the mrc_mechanism block that adds the mechanism to the robot. + * Specified only if the sender type is MECHANISM. + */ + mechanismBlockId?: string, } const EVENT_HANDLER = { @@ -77,8 +81,8 @@ const EVENT_HANDLER = { init(this: EventHandlerBlock): void { this.appendDummyInput('TITLE') .appendField(Blockly.Msg.WHEN) - .appendField(createFieldNonEditableText('sender'), FIELD_SENDER) - .appendField(createFieldNonEditableText('eventName'), FIELD_EVENT_NAME); + .appendField(createFieldNonEditableText(''), FIELD_SENDER) + .appendField(createFieldNonEditableText(''), FIELD_EVENT_NAME); this.appendDummyInput('PARAMS') .appendField(Blockly.Msg.WITH); this.setOutput(false); @@ -94,11 +98,13 @@ const EVENT_HANDLER = { */ saveExtraState(this: EventHandlerBlock): EventHandlerExtraState { const extraState: EventHandlerExtraState = { - pathOfSender: this.mrcPathOfSender, senderType: this.mrcSenderType, params: [], otherBlockId: this.mrcOtherBlockId, }; + if (this.mrcMechanismBlockId) { + extraState.mechanismBlockId = this.mrcMechanismBlockId; + } this.mrcParameters.forEach((param) => { extraState.params.push({ @@ -114,10 +120,11 @@ const EVENT_HANDLER = { * Applies the given state to this block. */ loadExtraState(this: EventHandlerBlock, extraState: EventHandlerExtraState): void { - this.mrcPathOfSender = extraState.pathOfSender; this.mrcSenderType = extraState.senderType; this.mrcParameters = []; this.mrcOtherBlockId = extraState.otherBlockId; + this.mrcMechanismBlockId = extraState.mechanismBlockId + ? extraState.mechanismBlockId : ''; extraState.params.forEach((param) => { this.mrcParameters.push({ @@ -158,29 +165,30 @@ const EVENT_HANDLER = { input.removeField(fieldName); }); }, + + /** + * mrcOnLoad is called for each EventHandlerBlock when the blocks are loaded in the blockly + * workspace. + */ mrcOnLoad: function(this: EventHandlerBlock): void { - // mrcOnLoad is called for each EventHandlerBlock when the blocks are loaded in the blockly workspace. const warnings: string[] = []; - // If this block is an event handler for a robot event, check that the robot event - // still exists and hasn't been changed. - // If the robot event doesn't exist, put a visible warning on this block. - // If the robot event has changed, update the block if possible or put a - // visible warning on it. - if (this.mrcSenderType === SenderType.ROBOT) { - let foundRobotEvent = false; - const editor = Editor.getEditorForBlocklyWorkspace(this.workspace); - if (editor) { + const editor = Editor.getEditorForBlocklyWorkspace(this.workspace); + if (editor) { + if (this.mrcSenderType === SenderType.ROBOT) { + // This block is an event handler for a robot event. + // Check whether the robot event still exists and whether it has been changed. + // If the robot event doesn't exist, put a visible warning on this block. + // If the robot event has changed, update the block if possible or put a + // visible warning on it. + let foundRobotEvent = false; const robotEvents = editor.getEventsFromRobot(); for (const robotEvent of robotEvents) { if (robotEvent.blockId === this.mrcOtherBlockId) { foundRobotEvent = true; - - // If the event name has changed, we can fix this block. if (this.getFieldValue(FIELD_EVENT_NAME) !== robotEvent.name) { this.setFieldValue(robotEvent.name, FIELD_EVENT_NAME); } - this.mrcParameters = []; robotEvent.args.forEach(arg => { this.mrcParameters.push({ @@ -198,6 +206,65 @@ const EVENT_HANDLER = { warnings.push('This block is an event handler for an event that no longer exists.'); } } + + if (this.mrcSenderType === SenderType.MECHANISM) { + // This block is an event handler for a mechanism event. + // Check whether the mechanism still exists, whether it has been + // changed, whether the event still exists, and whether the event has + // been changed. + // If the mechanism doesn't exist, put a visible warning on this block. + // If the mechanism has changed, update the block if possible or put a + // visible warning on it. + // If the event doesn't exist, put a visible warning on this block. + // If the event has changed, update the block if possible or put a + // visible warning on it. + let foundMechanism = false; + const mechanismsInRobot = editor.getMechanismsFromRobot(); + for (const mechanismInRobot of mechanismsInRobot) { + if (mechanismInRobot.blockId === this.mrcMechanismBlockId) { + foundMechanism = true; + + // If the mechanism name has changed, we can handle that. + if (this.getFieldValue(FIELD_SENDER) !== mechanismInRobot.name) { + this.setFieldValue(mechanismInRobot.name, FIELD_SENDER); + } + + let foundMechanismEvent = false; + const mechanism = editor.getMechanism(mechanismInRobot); + const mechanismEvents: storageModuleContent.Event[] = mechanism + ? editor.getEventsFromMechanism(mechanism) : []; + for (const mechanismEvent of mechanismEvents) { + if (mechanismEvent.blockId === this.mrcOtherBlockId) { + foundMechanismEvent = true; + if (this.getFieldValue(FIELD_EVENT_NAME) !== mechanismEvent.name) { + this.setFieldValue(mechanismEvent.name, FIELD_EVENT_NAME); + } + + this.mrcParameters = []; + mechanismEvent.args.forEach(arg => { + this.mrcParameters.push({ + name: arg.name, + type: arg.type, + }); + }); + this.mrcUpdateParams(); + + // Since we found the mechanism event, we can break out of the loop. + break; + } + } + if (!foundMechanismEvent) { + warnings.push('This block is an event handler for an event that no longer exists.'); + } + + // Since we found the mechanism, we can break out of the loop. + break; + } + } + if (!foundMechanism) { + warnings.push('This block is an event handler for an event in a mechanism that no longer exists.'); + } + } } if (warnings.length) { @@ -298,10 +365,8 @@ export function addRobotEventHandlerBlocks( } function createRobotEventHandlerBlock( - event: storageModuleContent.Event): toolboxItems.Block { + event: storageModuleContent.Event): toolboxItems.Block { const extraState: EventHandlerExtraState = { - // TODO(lizlooney): ask Alan what pathOfSender is for. - pathOfSender: '', senderType: SenderType.ROBOT, params: [], otherBlockId: event.blockId, @@ -319,6 +384,37 @@ function createRobotEventHandlerBlock( return new toolboxItems.Block(BLOCK_NAME, extraState, fields, Object.keys(inputs).length ? inputs : null); } +export function addMechanismEventHandlerBlocks( + mechanismInRobot: storageModuleContent.MechanismInRobot, + events: storageModuleContent.Event[], + contents: toolboxItems.ContentsType[]) { + events.forEach(event => { + contents.push(createMechanismEventHandlerBlock(mechanismInRobot, event)); + }); +} + +function createMechanismEventHandlerBlock( + mechanismInRobot: storageModuleContent.MechanismInRobot, + event: storageModuleContent.Event): toolboxItems.Block { + const extraState: EventHandlerExtraState = { + senderType: SenderType.MECHANISM, + params: [], + otherBlockId: event.blockId, + mechanismBlockId: mechanismInRobot.blockId, + }; + event.args.forEach(arg => { + extraState.params.push({ + name: arg.name, + type: arg.type, + }); + }); + const fields: {[key: string]: any} = {}; + fields[FIELD_SENDER] = mechanismInRobot.name; + fields[FIELD_EVENT_NAME] = event.name; + const inputs: {[key: string]: any} = {}; + return new toolboxItems.Block(BLOCK_NAME, extraState, fields, Object.keys(inputs).length ? inputs : null); +} + // Misc export function getHasAnyEnabledEventHandlers(workspace: Blockly.Workspace): boolean { From d556fe5235d7a6359f02c1bea78371d2da4b121d Mon Sep 17 00:00:00 2001 From: Liz Looney Date: Thu, 14 Aug 2025 00:15:21 -0700 Subject: [PATCH 5/9] Moved CUSTOM_CATEGORY_EVENT_HANDLERS_ROBOT, getRobotEventHandlersCategory, and RobotEventHandlersCategory from hardware_category.ts to event_handlers_category.ts. --- src/editor/editor.ts | 2 +- src/toolbox/event_handlers_category.ts | 71 ++++++++++++++++++++++++++ src/toolbox/hardware_category.ts | 42 +-------------- 3 files changed, 73 insertions(+), 42 deletions(-) create mode 100644 src/toolbox/event_handlers_category.ts diff --git a/src/editor/editor.ts b/src/editor/editor.ts index a7ce1bd8..7b39eafe 100644 --- a/src/editor/editor.ts +++ b/src/editor/editor.ts @@ -34,7 +34,7 @@ import * as mechanismComponentHolder from '../blocks/mrc_mechanism_component_hol //import { testAllBlocksInToolbox } from '../toolbox/toolbox_tests'; import { MethodsCategory } from '../toolbox/methods_category'; import { EventsCategory } from '../toolbox/event_category'; -import { RobotEventHandlersCategory } from '../toolbox/hardware_category'; +import { RobotEventHandlersCategory } from '../toolbox/event_handlers_category'; import { getToolboxJSON } from '../toolbox/toolbox'; const EMPTY_TOOLBOX: Blockly.utils.toolbox.ToolboxDefinition = { diff --git a/src/toolbox/event_handlers_category.ts b/src/toolbox/event_handlers_category.ts new file mode 100644 index 00000000..9288a46c --- /dev/null +++ b/src/toolbox/event_handlers_category.ts @@ -0,0 +1,71 @@ +/** + * @license + * Copyright 2025 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @author lizlooney@google.com (Liz Looney) + */ + +import * as Blockly from 'blockly/core'; +import * as toolboxItems from './items'; +import { addRobotEventHandlerBlocks } from '../blocks/mrc_event_handler'; +import { Editor } from '../editor/editor'; + +// The robot event handlers category is shown when the user is editing an opmode. +// It allows the user to create event handlers for events previously defined in the Robot. + +// The event handlers category is a custom category because it must be updated dynamically. +// As the user places event handler blocks on the blockly workspace, we update the category so it +// doesn't contain blocks for the event handlers that have already been added to the blockly +// workspace. + +const CUSTOM_CATEGORY_EVENT_HANDLERS_ROBOT = 'EVENT_HANDLERS_ROBOT'; + +export const getRobotEventHandlersCategory = () => ({ + kind: 'category', + name: Blockly.Msg['MRC_CATEGORY_EVENTS'], + custom: CUSTOM_CATEGORY_EVENT_HANDLERS_ROBOT, +}); + +export class RobotEventHandlersCategory { + constructor(blocklyWorkspace: Blockly.WorkspaceSvg) { + blocklyWorkspace.registerToolboxCategoryCallback( + CUSTOM_CATEGORY_EVENT_HANDLERS_ROBOT, this.robotEventHandlersFlyout.bind(this)); + } + + public robotEventHandlersFlyout(workspace: Blockly.WorkspaceSvg) { + const contents: toolboxItems.ContentsType[] = []; + + // Get the list of events from the robot and add the blocks for handling events. + + const editor = Editor.getEditorForBlocklyWorkspace(workspace); + if (editor) { + const eventsFromRobot = editor.getEventsFromRobot(); + // Remove events if there is already a corresponding handler in the workspace. + const eventHandlerNames = editor.getEventHandlerNamesFromWorkspace(); + const eventsToShow = eventsFromRobot.filter(event => { + return !eventHandlerNames.includes(event.name); + }); + addRobotEventHandlerBlocks(eventsToShow, contents); + } + + const toolboxInfo = { + contents: contents, + }; + + return toolboxInfo; + } +} diff --git a/src/toolbox/hardware_category.ts b/src/toolbox/hardware_category.ts index deffd178..5baa68ee 100644 --- a/src/toolbox/hardware_category.ts +++ b/src/toolbox/hardware_category.ts @@ -22,13 +22,13 @@ import * as Blockly from 'blockly/core'; import * as storageModule from '../storage/module'; import * as toolboxItems from './items'; +import { getRobotEventHandlersCategory } from './event_handlers_category'; import { createMechanismBlock } from '../blocks/mrc_mechanism'; import { getAllPossibleComponents } from '../blocks/mrc_component'; import { getInstanceComponentBlocks, addInstanceRobotBlocks, addInstanceMechanismBlocks } from '../blocks/mrc_call_python_function'; -import { addRobotEventHandlerBlocks } from '../blocks/mrc_event_handler'; import { Editor } from '../editor/editor'; export function getHardwareCategory(currentModule: storageModule.Module): toolboxItems.Category { @@ -204,43 +204,3 @@ function getComponentsCategory(moduleType : string): toolboxItems.Category { contents, }; } - -const CUSTOM_CATEGORY_EVENT_HANDLERS_ROBOT = 'EVENT_HANDLERS_ROBOT'; - -// The robot event handlers category is shown when the user is editing an opmode. -// It allows the user to create event handlers for events previously defined in the Robot. -const getRobotEventHandlersCategory = () => ({ - kind: 'category', - name: Blockly.Msg['MRC_CATEGORY_EVENTS'], - custom: CUSTOM_CATEGORY_EVENT_HANDLERS_ROBOT, -}); - -export class RobotEventHandlersCategory { - constructor(blocklyWorkspace: Blockly.WorkspaceSvg) { - blocklyWorkspace.registerToolboxCategoryCallback( - CUSTOM_CATEGORY_EVENT_HANDLERS_ROBOT, this.robotEventHandlersFlyout.bind(this)); - } - - public robotEventHandlersFlyout(workspace: Blockly.WorkspaceSvg) { - const contents: toolboxItems.ContentsType[] = []; - - // Get the list of events from the robot and add the blocks for handling events. - - const editor = Editor.getEditorForBlocklyWorkspace(workspace); - if (editor) { - const eventsFromRobot = editor.getEventsFromRobot(); - // Remove events if there is already a corresponding handler in the workspace. - const eventHandlerNames = editor.getEventHandlerNamesFromWorkspace(); - const eventsToShow = eventsFromRobot.filter(event => { - return !eventHandlerNames.includes(event.name); - }); - addRobotEventHandlerBlocks(eventsToShow, contents); - } - - const toolboxInfo = { - contents: contents, - }; - - return toolboxInfo; - } -} From 6ebb3b5baa41f3941e7581914f00a76be2a1555c Mon Sep 17 00:00:00 2001 From: Liz Looney Date: Thu, 14 Aug 2025 00:35:15 -0700 Subject: [PATCH 6/9] Modified event_handlers_category.ts to work for robot events and mechanism events. Use the block id of the mrc_event blocks to identify which event handlers are already on the workspace. --- src/blocks/mrc_event_handler.ts | 28 ++++++- src/editor/editor.ts | 27 ++++-- src/toolbox/event_handlers_category.ts | 110 +++++++++++++++++++++---- src/toolbox/hardware_category.ts | 26 ++++-- 4 files changed, 156 insertions(+), 35 deletions(-) diff --git a/src/blocks/mrc_event_handler.ts b/src/blocks/mrc_event_handler.ts index 56a12adc..90af3c0e 100644 --- a/src/blocks/mrc_event_handler.ts +++ b/src/blocks/mrc_event_handler.ts @@ -278,6 +278,9 @@ const EVENT_HANDLER = { this.setWarningText(null, WARNING_ID_EVENT_CHANGED); } }, + getEventBlockId: function(this: EventHandlerBlock): string { + return this.mrcOtherBlockId; + }, }; export function setup(): void { @@ -423,10 +426,27 @@ export function getHasAnyEnabledEventHandlers(workspace: Blockly.Workspace): boo }).length > 0; } -export function getEventHandlerNames(workspace: Blockly.Workspace, names: string[]): void { - // Here we collect the event names of the event handlers in the given - // workspace, regardless of whether the event handler is enabled. +export function getRobotEventHandlerBlocks( + workspace: Blockly.Workspace, + blocks: EventHandlerBlock[]): void { + workspace.getBlocksByType(BLOCK_NAME).forEach(block => { + const eventHandlerBlock = block as EventHandlerBlock; + if (eventHandlerBlock.mrcSenderType == SenderType.ROBOT) { + blocks.push(eventHandlerBlock); + } + }); +} + +export function getMechanismEventHandlerBlocks( + workspace: Blockly.Workspace, + mechanismBlockId: string, + blocks: EventHandlerBlock[]): void { workspace.getBlocksByType(BLOCK_NAME).forEach(block => { - names.push(block.getFieldValue(FIELD_EVENT_NAME)); + const eventHandlerBlock = block as EventHandlerBlock; + if (eventHandlerBlock.mrcSenderType == SenderType.MECHANISM) { + if (eventHandlerBlock.mrcMechanismBlockId === mechanismBlockId) { + blocks.push(eventHandlerBlock); + } + } }); } diff --git a/src/editor/editor.ts b/src/editor/editor.ts index 7b39eafe..cc204cee 100644 --- a/src/editor/editor.ts +++ b/src/editor/editor.ts @@ -34,7 +34,10 @@ import * as mechanismComponentHolder from '../blocks/mrc_mechanism_component_hol //import { testAllBlocksInToolbox } from '../toolbox/toolbox_tests'; import { MethodsCategory } from '../toolbox/methods_category'; import { EventsCategory } from '../toolbox/event_category'; -import { RobotEventHandlersCategory } from '../toolbox/event_handlers_category'; +import { + registerRobotEventHandlersCategory, + registerMechanismEventHandlersCategory +} from '../toolbox/event_handlers_category'; import { getToolboxJSON } from '../toolbox/toolbox'; const EMPTY_TOOLBOX: Blockly.utils.toolbox.ToolboxDefinition = { @@ -67,7 +70,7 @@ export class Editor { // Create the custom toolbox categories so they register their flyout callbacks. new MethodsCategory(blocklyWorkspace); new EventsCategory(blocklyWorkspace); - new RobotEventHandlersCategory(blocklyWorkspace); + registerRobotEventHandlersCategory(blocklyWorkspace); } private onChangeWhileLoading(event: Blockly.Events.Abstract) { @@ -174,6 +177,10 @@ export class Editor { ? this.moduleContentText : modulePathToContentText[mechanism.modulePath]); } + // Register the custom toolbox categories for the mechanisms in the robot. + this.robotContent.getMechanisms().forEach(mechanismInRobot => { + registerMechanismEventHandlersCategory(this.blocklyWorkspace, mechanismInRobot); + }); this.loadBlocksIntoBlocklyWorkspace(); } } @@ -305,10 +312,18 @@ export class Editor { return events; } - public getEventHandlerNamesFromWorkspace(): string[] { - const names: string[] = []; - eventHandler.getEventHandlerNames(this.blocklyWorkspace, names); - return names; + public getRobotEventHandlersAlreadyInWorkspace(): eventHandler.EventHandlerBlock[] { + const eventHandlerBlocks: eventHandler.EventHandlerBlock[] = []; + eventHandler.getRobotEventHandlerBlocks(this.blocklyWorkspace, eventHandlerBlocks); + return eventHandlerBlocks; + } + + public getMechanismEventHandlersAlreadyInWorkspace( + mechanismInRobot: storageModuleContent.MechanismInRobot): eventHandler.EventHandlerBlock[] { + const eventHandlerBlocks: eventHandler.EventHandlerBlock[] = []; + eventHandler.getMechanismEventHandlerBlocks( + this.blocklyWorkspace, mechanismInRobot.blockId, eventHandlerBlocks); + return eventHandlerBlocks; } public async saveBlocks() { diff --git a/src/toolbox/event_handlers_category.ts b/src/toolbox/event_handlers_category.ts index 9288a46c..14f8349f 100644 --- a/src/toolbox/event_handlers_category.ts +++ b/src/toolbox/event_handlers_category.ts @@ -21,11 +21,13 @@ import * as Blockly from 'blockly/core'; import * as toolboxItems from './items'; -import { addRobotEventHandlerBlocks } from '../blocks/mrc_event_handler'; +import * as storageModuleContent from '../storage/module_content'; +import { addMechanismEventHandlerBlocks, addRobotEventHandlerBlocks } from '../blocks/mrc_event_handler'; import { Editor } from '../editor/editor'; -// The robot event handlers category is shown when the user is editing an opmode. -// It allows the user to create event handlers for events previously defined in the Robot. +// The event handlers category is shown when the user is editing an opmode. +// It allows the user to create event handlers for events previously defined in the Robot or in a +// mechanism. // The event handlers category is a custom category because it must be updated dynamically. // As the user places event handler blocks on the blockly workspace, we update the category so it @@ -33,31 +35,73 @@ import { Editor } from '../editor/editor'; // workspace. const CUSTOM_CATEGORY_EVENT_HANDLERS_ROBOT = 'EVENT_HANDLERS_ROBOT'; +const CUSTOM_CATEGORY_EVENT_HANDLERS_MECHANISM_PREFIX = 'EVENT_HANDLERS_MECHANISM_'; -export const getRobotEventHandlersCategory = () => ({ - kind: 'category', - name: Blockly.Msg['MRC_CATEGORY_EVENTS'], - custom: CUSTOM_CATEGORY_EVENT_HANDLERS_ROBOT, -}); +function getCustomValue(mechanismInRobot: storageModuleContent.MechanismInRobot | null): string { + return (mechanismInRobot === null) + ? CUSTOM_CATEGORY_EVENT_HANDLERS_ROBOT + : CUSTOM_CATEGORY_EVENT_HANDLERS_MECHANISM_PREFIX + mechanismInRobot.name; +} + +export function registerRobotEventHandlersCategory(blocklyWorkspace: Blockly.WorkspaceSvg): void { + new EventHandlersCategory(blocklyWorkspace, null); +} + +export function getRobotEventHandlersCategory(): toolboxItems.Category { + return { + kind: 'category', + name: Blockly.Msg['MRC_CATEGORY_EVENTS'], + custom: getCustomValue(null), + }; +} + +export function registerMechanismEventHandlersCategory( + blocklyWorkspace: Blockly.WorkspaceSvg, mechanismInRobot: storageModuleContent.MechanismInRobot): void { + new EventHandlersCategory(blocklyWorkspace, mechanismInRobot); +} -export class RobotEventHandlersCategory { - constructor(blocklyWorkspace: Blockly.WorkspaceSvg) { - blocklyWorkspace.registerToolboxCategoryCallback( - CUSTOM_CATEGORY_EVENT_HANDLERS_ROBOT, this.robotEventHandlersFlyout.bind(this)); +export function getMechanismEventHandlersCategory( + mechanismInRobot: storageModuleContent.MechanismInRobot): toolboxItems.Category { + return { + kind: 'category', + name: Blockly.Msg['MRC_CATEGORY_EVENTS'], + custom: getCustomValue(mechanismInRobot), + }; +} + +class EventHandlersCategory { + mechanismInRobot: storageModuleContent.MechanismInRobot | null; + + constructor( + blocklyWorkspace: Blockly.WorkspaceSvg, + mechanismInRobot: storageModuleContent.MechanismInRobot | null) { + this.mechanismInRobot = mechanismInRobot; + if (mechanismInRobot === null) { + blocklyWorkspace.registerToolboxCategoryCallback( + getCustomValue(mechanismInRobot), + this.robotEventHandlersFlyout.bind(this)); + } else { + blocklyWorkspace.registerToolboxCategoryCallback( + getCustomValue(mechanismInRobot), + this.mechanismEventHandlersFlyout.bind(this)); + } } public robotEventHandlersFlyout(workspace: Blockly.WorkspaceSvg) { const contents: toolboxItems.ContentsType[] = []; - // Get the list of events from the robot and add the blocks for handling events. - const editor = Editor.getEditorForBlocklyWorkspace(workspace); if (editor) { + // Get the list of events from the robot. const eventsFromRobot = editor.getEventsFromRobot(); // Remove events if there is already a corresponding handler in the workspace. - const eventHandlerNames = editor.getEventHandlerNamesFromWorkspace(); + const eventHandlerBlocks = editor.getRobotEventHandlersAlreadyInWorkspace(); + const eventBlockIds: string[] = []; + eventHandlerBlocks.forEach(eventHandlerBlock => { + eventBlockIds.push(eventHandlerBlock.getEventBlockId()); + }); const eventsToShow = eventsFromRobot.filter(event => { - return !eventHandlerNames.includes(event.name); + return !eventBlockIds.includes(event.blockId); }); addRobotEventHandlerBlocks(eventsToShow, contents); } @@ -68,4 +112,38 @@ export class RobotEventHandlersCategory { return toolboxInfo; } + + public mechanismEventHandlersFlyout(workspace: Blockly.WorkspaceSvg) { + const contents: toolboxItems.ContentsType[] = []; + + const editor = Editor.getEditorForBlocklyWorkspace(workspace); + if (editor && this.mechanismInRobot) { + // Get the list of events from the mechanism. + const mechanism = editor.getMechanism(this.mechanismInRobot); + if (mechanism) { + const eventsFromMechanism = editor.getEventsFromMechanism(mechanism); + // Remove events if there is already a corresponding handler in the workspace. + const eventHandlerBlocks = editor.getMechanismEventHandlersAlreadyInWorkspace( + this.mechanismInRobot); + const eventBlockIds: string[] = []; + eventHandlerBlocks.forEach(eventHandlerBlock => { + eventBlockIds.push(eventHandlerBlock.getEventBlockId()); + }); + const eventsToShow = eventsFromMechanism.filter(event => { + return !eventBlockIds.includes(event.blockId); + }); + addMechanismEventHandlerBlocks(this.mechanismInRobot, eventsToShow, contents); + if (contents.length === 0) { + const label : toolboxItems.Label = new toolboxItems.Label(Blockly.Msg['NO_MECHANISM_CONTENTS']); + contents.push(label); + } + } + } + + const toolboxInfo = { + contents: contents, + }; + + return toolboxInfo; + } } diff --git a/src/toolbox/hardware_category.ts b/src/toolbox/hardware_category.ts index 5baa68ee..68a380b9 100644 --- a/src/toolbox/hardware_category.ts +++ b/src/toolbox/hardware_category.ts @@ -22,7 +22,7 @@ import * as Blockly from 'blockly/core'; import * as storageModule from '../storage/module'; import * as toolboxItems from './items'; -import { getRobotEventHandlersCategory } from './event_handlers_category'; +import { getRobotEventHandlersCategory, getMechanismEventHandlersCategory } from './event_handlers_category'; import { createMechanismBlock } from '../blocks/mrc_mechanism'; import { getAllPossibleComponents } from '../blocks/mrc_component'; import { @@ -92,23 +92,31 @@ function getRobotMechanismsCategory(currentModule: storageModule.Module): toolbo if (editor) { editor.getMechanismsFromRobot().forEach(mechanismInRobot => { - const mechanismBlocks: toolboxItems.Item[] = []; - - // Add the blocks for this mechanism's methods. + // Add the blocks for this mechanism's methods and events. const mechanism = editor.getMechanism(mechanismInRobot); if (mechanism) { - const methodsFromMechanism = editor.getMethodsFromMechanism(mechanism); - addInstanceMechanismBlocks(mechanismInRobot, methodsFromMechanism, mechanismBlocks); + const mechanismCategories: toolboxItems.Category[] = []; - if(mechanismBlocks.length === 0){ + // Get the list of methods from the mechanism and add the blocks for calling the methods. + const mechanismMethodBlocks: toolboxItems.Item[] = []; + const methodsFromMechanism = editor.getMethodsFromMechanism(mechanism); + addInstanceMechanismBlocks(mechanismInRobot, methodsFromMechanism, mechanismMethodBlocks); + if (mechanismMethodBlocks.length === 0) { const label : toolboxItems.Label = new toolboxItems.Label(Blockly.Msg['NO_MECHANISM_CONTENTS']); - mechanismBlocks.push( label ); + mechanismMethodBlocks.push(label); } + mechanismCategories.push({ + kind: 'category', + name: Blockly.Msg['MRC_CATEGORY_METHODS'], + contents: mechanismMethodBlocks, + }); + + mechanismCategories.push(getMechanismEventHandlersCategory(mechanismInRobot)); contents.push({ kind: 'category', name: mechanismInRobot.name, - contents: mechanismBlocks, + contents: mechanismCategories, }); } }); From 092a0654eb892abfb5927c2517f57fb6a63aea08 Mon Sep 17 00:00:00 2001 From: Liz Looney Date: Thu, 14 Aug 2025 19:53:22 -0700 Subject: [PATCH 7/9] Update event handler blocks if the user renames a mechanism. --- src/blocks/mrc_event_handler.ts | 15 +++++++++++++++ src/blocks/mrc_mechanism.ts | 3 +++ 2 files changed, 18 insertions(+) diff --git a/src/blocks/mrc_event_handler.ts b/src/blocks/mrc_event_handler.ts index 90af3c0e..0aa488ac 100644 --- a/src/blocks/mrc_event_handler.ts +++ b/src/blocks/mrc_event_handler.ts @@ -281,6 +281,13 @@ const EVENT_HANDLER = { getEventBlockId: function(this: EventHandlerBlock): string { return this.mrcOtherBlockId; }, + renameMechanismName: function(this: EventHandlerBlock, mechanismBlockId: string, newName: string): void { + // renameMechanismName is called when a mechanism block in the same module is modified. + if (this.mrcSenderType === SenderType.MECHANISM && + mechanismBlockId === this.mrcMechanismBlockId) { + this.setFieldValue(newName, FIELD_SENDER); + } + }, }; export function setup(): void { @@ -450,3 +457,11 @@ export function getMechanismEventHandlerBlocks( } }); } + +export function renameMechanismName(workspace: Blockly.Workspace, mechanismBlockId: string, newName: string): void { + const eventHandlerBlocks: EventHandlerBlock[] = []; + getMechanismEventHandlerBlocks(workspace, mechanismBlockId, eventHandlerBlocks); + eventHandlerBlocks.forEach(block => { + (block as EventHandlerBlock).renameMechanismName(mechanismBlockId, newName); + }); +} diff --git a/src/blocks/mrc_mechanism.ts b/src/blocks/mrc_mechanism.ts index 63a3c010..a19fccaf 100644 --- a/src/blocks/mrc_mechanism.ts +++ b/src/blocks/mrc_mechanism.ts @@ -33,6 +33,7 @@ import * as storageModuleContent from '../storage/module_content'; import * as storageNames from '../storage/names'; import * as value from './utils/value'; import { renameMethodCallers } from './mrc_call_python_function' +import { renameMechanismName as renameMechanismNameInEventHandlers } from './mrc_event_handler' export const BLOCK_NAME = 'mrc_mechanism'; export const OUTPUT_NAME = 'mrc_mechansim'; @@ -154,6 +155,8 @@ const MECHANISM = { if (oldName && oldName !== name && oldName !== legalName) { // Rename any callers. renameMethodCallers(this.workspace, this.id, legalName); + // Rename any event handlers + renameMechanismNameInEventHandlers(this.workspace, this.id, legalName); } return legalName; }, From 37c7e3288a5e82604d72febb4f034923c1a882d4 Mon Sep 17 00:00:00 2001 From: Liz Looney Date: Thu, 14 Aug 2025 20:15:05 -0700 Subject: [PATCH 8/9] Update python generator for registerering event handlers. --- src/blocks/mrc_event_handler.ts | 29 ++++++++++++++++++++++++- src/editor/extended_python_generator.ts | 20 ++++++----------- 2 files changed, 35 insertions(+), 14 deletions(-) diff --git a/src/blocks/mrc_event_handler.ts b/src/blocks/mrc_event_handler.ts index 0aa488ac..6dc75f13 100644 --- a/src/blocks/mrc_event_handler.ts +++ b/src/blocks/mrc_event_handler.ts @@ -29,6 +29,7 @@ import { createFieldFlydown } from '../fields/field_flydown'; import { createFieldNonEditableText } from '../fields/FieldNonEditableText'; import { MRC_STYLE_EVENT_HANDLER } from '../themes/styles'; import * as toolboxItems from '../toolbox/items'; +import * as storageModule from '../storage/module'; import * as storageModuleContent from '../storage/module_content'; export const BLOCK_NAME = 'mrc_event_handler'; @@ -359,11 +360,37 @@ export function pythonFromBlock( code = generator.scrub_(block, code); generator.addClassMethodDefinition(funcName, code); - generator.addEventHandler(sender, eventName, funcName); + generateRegisterEventHandler(block, generator, sender, eventName, funcName); return ''; } +function generateRegisterEventHandler( + block: EventHandlerBlock, + generator: ExtendedPythonGenerator, + sender: string, + eventName: string, + funcName: string) { + // Create the line of code that will register this event handler. + let fullSender = ''; + if (block.mrcSenderType === SenderType.ROBOT) { + fullSender = 'self.' + sender; + } else if (block.mrcSenderType === SenderType.MECHANISM) { + switch (generator.getModuleType()) { + case storageModule.MODULE_TYPE_ROBOT: + fullSender = 'self.' + sender; + break; + case storageModule.MODULE_TYPE_OPMODE: + fullSender = 'self.robot.' + sender; + break; + } + } + if (fullSender) { + generator.addRegisterEventHandlerStatement( + fullSender + '.register_event_handler("' + eventName + '", self.' + funcName + ')\n'); + } +} + // Functions used for creating blocks for the toolbox. export function addRobotEventHandlerBlocks( diff --git a/src/editor/extended_python_generator.ts b/src/editor/extended_python_generator.ts index 225f478d..676d4bec 100644 --- a/src/editor/extended_python_generator.ts +++ b/src/editor/extended_python_generator.ts @@ -79,8 +79,7 @@ export class ExtendedPythonGenerator extends PythonGenerator { private hasAnyEventHandlers = false; private classMethods: {[key: string]: string} = Object.create(null); - // For eventHandlers, the keys are the function name. - private eventHandlers: {[key: string]: {sender: string, eventName: string}} = Object.create(null); + private registerEventHandlerStatements: string[] = []; // Opmode details private details : OpModeDetails | null = null; @@ -180,11 +179,8 @@ export class ExtendedPythonGenerator extends PythonGenerator { this.classMethods[methodName] = code; } - addEventHandler(sender: string, eventName: string, funcName: string): void { - this.eventHandlers[funcName] = { - 'sender': sender, - 'eventName': eventName - } + addRegisterEventHandlerStatement(registerEventHandlerStatement: string): void { + this.registerEventHandlerStatements.push(registerEventHandlerStatement); } getComponentPortParameters(): string[] { @@ -214,12 +210,10 @@ export class ExtendedPythonGenerator extends PythonGenerator { const classDef = 'class ' + className + '(' + simpleBaseClassName + '):\n'; const classMethods = []; - if (this.eventHandlers && Object.keys(this.eventHandlers).length > 0) { + if (this.registerEventHandlerStatements && this.registerEventHandlerStatements.length > 0) { let code = 'def register_event_handlers(self):\n'; - for (const funcName in this.eventHandlers) { - const event = this.eventHandlers[funcName]; - code += this.INDENT + 'self.' + event.sender + '.register_event_handler("' + - event.eventName + '", self.' + funcName + ')\n'; + for (const registerEventHandlerStatement of this.registerEventHandlerStatements) { + code += this.INDENT + registerEventHandlerStatement; } classMethods.push(code); } @@ -233,8 +227,8 @@ export class ExtendedPythonGenerator extends PythonGenerator { } classMethods.push(this.classMethods[name]) } - this.eventHandlers = Object.create(null); this.classMethods = Object.create(null); + this.registerEventHandlerStatements = []; this.componentPorts = Object.create(null); code = classDef + this.prefixLines(classMethods.join('\n\n'), this.INDENT); if (decorations){ From 0afd822bbf62b098c283551144dbf8eae61213b6 Mon Sep 17 00:00:00 2001 From: Liz Looney Date: Thu, 14 Aug 2025 20:25:11 -0700 Subject: [PATCH 9/9] Create functions for registering custom categories. Changed custom values to begin with MRC_. --- src/editor/editor.ts | 10 +++++----- src/toolbox/event_category.ts | 8 ++++++-- src/toolbox/event_handlers_category.ts | 6 ++++-- src/toolbox/methods_category.ts | 8 ++++++-- 4 files changed, 21 insertions(+), 11 deletions(-) diff --git a/src/editor/editor.ts b/src/editor/editor.ts index cc204cee..2b1b0837 100644 --- a/src/editor/editor.ts +++ b/src/editor/editor.ts @@ -32,8 +32,8 @@ import * as eventHandler from '../blocks/mrc_event_handler'; import * as classMethodDef from '../blocks/mrc_class_method_def'; 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'; +import { registerCategory as registerMethodsCategory } from '../toolbox/methods_category'; +import { registerCategory as registerEventsCategory } from '../toolbox/event_category'; import { registerRobotEventHandlersCategory, registerMechanismEventHandlersCategory @@ -67,9 +67,9 @@ export class Editor { this.blocklyWorkspace = blocklyWorkspace; this.generatorContext = generatorContext; this.storage = storage; - // Create the custom toolbox categories so they register their flyout callbacks. - new MethodsCategory(blocklyWorkspace); - new EventsCategory(blocklyWorkspace); + // Register the custom toolbox categories. + registerMethodsCategory(blocklyWorkspace); + registerEventsCategory(blocklyWorkspace); registerRobotEventHandlersCategory(blocklyWorkspace); } diff --git a/src/toolbox/event_category.ts b/src/toolbox/event_category.ts index fd32029d..ffa8fa27 100644 --- a/src/toolbox/event_category.ts +++ b/src/toolbox/event_category.ts @@ -28,7 +28,11 @@ import { createCustomEventBlock } from '../blocks/mrc_event'; import { addFireEventBlocks } from '../blocks/mrc_call_python_function'; import { Editor } from '../editor/editor'; -const CUSTOM_CATEGORY_EVENTS = 'EVENTS'; +const CUSTOM_CATEGORY_EVENTS = 'MRC_EVENTS'; + +export function registerCategory(blocklyWorkspace: Blockly.WorkspaceSvg): void { + new EventsCategory(blocklyWorkspace); +} export function getCategory(): toolboxItems.Category { return { @@ -39,7 +43,7 @@ export function getCategory(): toolboxItems.Category { }; } -export class EventsCategory { +class EventsCategory { constructor(blocklyWorkspace: Blockly.WorkspaceSvg) { blocklyWorkspace.registerToolboxCategoryCallback(CUSTOM_CATEGORY_EVENTS, this.eventsFlyout.bind(this)); } diff --git a/src/toolbox/event_handlers_category.ts b/src/toolbox/event_handlers_category.ts index 14f8349f..e4a239c0 100644 --- a/src/toolbox/event_handlers_category.ts +++ b/src/toolbox/event_handlers_category.ts @@ -34,10 +34,11 @@ import { Editor } from '../editor/editor'; // doesn't contain blocks for the event handlers that have already been added to the blockly // workspace. -const CUSTOM_CATEGORY_EVENT_HANDLERS_ROBOT = 'EVENT_HANDLERS_ROBOT'; -const CUSTOM_CATEGORY_EVENT_HANDLERS_MECHANISM_PREFIX = 'EVENT_HANDLERS_MECHANISM_'; +const CUSTOM_CATEGORY_EVENT_HANDLERS_ROBOT = 'MRC_EVENT_HANDLERS_ROBOT'; +const CUSTOM_CATEGORY_EVENT_HANDLERS_MECHANISM_PREFIX = 'MRC_EVENT_HANDLERS_MECHANISM_'; function getCustomValue(mechanismInRobot: storageModuleContent.MechanismInRobot | null): string { + // If the event is defined in the robot, mechanismInRobot is null. return (mechanismInRobot === null) ? CUSTOM_CATEGORY_EVENT_HANDLERS_ROBOT : CUSTOM_CATEGORY_EVENT_HANDLERS_MECHANISM_PREFIX + mechanismInRobot.name; @@ -70,6 +71,7 @@ export function getMechanismEventHandlersCategory( } class EventHandlersCategory { + // If the event is defined in the robot, mechanismInRobot is null. mechanismInRobot: storageModuleContent.MechanismInRobot | null; constructor( diff --git a/src/toolbox/methods_category.ts b/src/toolbox/methods_category.ts index 32ed8652..73d072ee 100644 --- a/src/toolbox/methods_category.ts +++ b/src/toolbox/methods_category.ts @@ -30,7 +30,11 @@ import { createCustomMethodBlock, getBaseClassBlocks, FIELD_METHOD_NAME } from ' import { Editor } from '../editor/editor'; -const CUSTOM_CATEGORY_METHODS = 'METHODS'; +const CUSTOM_CATEGORY_METHODS = 'MRC_METHODS'; + +export function registerCategory(blocklyWorkspace: Blockly.WorkspaceSvg): void { + new MethodsCategory(blocklyWorkspace); +} export function getCategory(): toolboxItems.Category { return { @@ -41,7 +45,7 @@ export function getCategory(): toolboxItems.Category { }; } -export class MethodsCategory { +class MethodsCategory { private robotClassBlocks = getBaseClassBlocks(CLASS_NAME_ROBOT_BASE); private mechanismClassBlocks = getBaseClassBlocks(CLASS_NAME_MECHANISM); private opmodeClassBlocks = getBaseClassBlocks(CLASS_NAME_OPMODE);