diff --git a/frontend/App.tsx b/frontend/App.tsx index a677a46c..81b7ca58 100644 --- a/frontend/App.tsx +++ b/frontend/App.tsx @@ -137,7 +137,7 @@ interface AppContentProps { const AppContent: React.FC = ({ project, setProject }): React.JSX.Element => { const { t, i18n } = useTranslation(); - const { settings, updateLanguage, updateTheme, updateOpenTabs, getOpenTabs, storage, isLoading } = useUserSettings(); + const { settings, updateLanguage, updateTheme, updateShowSimpleClassNames, updateOpenTabs, getOpenTabs, storage, isLoading } = useUserSettings(); const [alertErrorMessage, setAlertErrorMessage] = React.useState(''); const [messageApi, contextHolder] = Antd.message.useMessage(); @@ -151,6 +151,8 @@ const AppContent: React.FC = ({ project, setProject }): React.J const [theme, setTheme] = React.useState('dark'); const [languageInitialized, setLanguageInitialized] = React.useState(false); const [themeInitialized, setThemeInitialized] = React.useState(false); + const [showSimpleClassNames, setShowSimpleClassNames] = React.useState(true); + const [showSimpleClassNamesInitialized, setShowSimpleClassNamesInitialized] = React.useState(false); const tabsRef = React.useRef(null); @@ -180,6 +182,19 @@ const AppContent: React.FC = ({ project, setProject }): React.J } }, [settings.theme, theme, themeInitialized, isLoading]); + /** Initialize showSimpleClassNames from UserSettings when app first starts. */ + React.useEffect(() => { + // Only proceed if settings are loaded + if (!isLoading) { + if (!showSimpleClassNamesInitialized && settings.showSimpleClassNames && settings.showSimpleClassNames !== showSimpleClassNames) { + setShowSimpleClassNames(settings.showSimpleClassNames); + setShowSimpleClassNamesInitialized(true); + } else if (!showSimpleClassNamesInitialized) { + setShowSimpleClassNamesInitialized(true); + } + } + }, [settings.showSimpleClassNames, showSimpleClassNames, showSimpleClassNamesInitialized, isLoading]); + /** Save language changes to UserSettings when i18n language changes. */ React.useEffect(() => { const handleLanguageChange = async (newLanguage: string) => { @@ -216,6 +231,22 @@ const AppContent: React.FC = ({ project, setProject }): React.J saveThemeChange(); }, [theme, settings.theme, updateTheme, themeInitialized, isLoading]); + /** Save showSimpleClassNames changes to UserSettings when showSimpleClassNames changes. */ + React.useEffect(() => { + const saveShowSimpleClassNamesChange = async () => { + // Only save if this is not the initial load and showSimpleClassNames is different from settings + if (showSimpleClassNamesInitialized && showSimpleClassNames !== settings.showSimpleClassNames && !isLoading) { + try { + await updateShowSimpleClassNames(showSimpleClassNames); + } catch (error) { + console.error('Failed to save showSimpleClassNames setting:', error); + } + } + }; + + saveShowSimpleClassNamesChange(); + }, [showSimpleClassNames, settings.showSimpleClassNames, updateShowSimpleClassNames, showSimpleClassNamesInitialized, isLoading]); + /** Initializes custom blocks and Python generator. */ const initializeBlocks = (): void => { const forBlock = Object.create(null); @@ -533,6 +564,8 @@ const AppContent: React.FC = ({ project, setProject }): React.J openWPIToolboxSettings={() => setToolboxSettingsModalIsOpen(true)} theme={theme} setTheme={setTheme} + showSimpleClassNames={showSimpleClassNames} + setShowSimpleClassNames={setShowSimpleClassNames} saveCurrentTab={saveCurrentTab} /> = ({ project, setProject }): React.J onProjectChanged={onProjectChanged} storage={storage} theme={theme} + showSimpleClassNames={showSimpleClassNames} shownPythonToolboxCategories={shownPythonToolboxCategories} messageApi={messageApi} openGamepadConfigDialog={openGamepadConfigDialog} diff --git a/frontend/blocks/mrc_call_python_function.ts b/frontend/blocks/mrc_call_python_function.ts index c32a2d39..62715f5e 100644 --- a/frontend/blocks/mrc_call_python_function.ts +++ b/frontend/blocks/mrc_call_python_function.ts @@ -24,6 +24,7 @@ import * as Blockly from 'blockly'; import { Order } from 'blockly/python'; import { + classNameToShowOnBlocks, getAllowedTypesForSetCheck, getClassData, getModuleData, @@ -93,6 +94,7 @@ interface CallPythonFunctionMixin extends CallPythonFunctionMixinType { mrcComponentClassName: string, mrcOriginalComponentName: string, mrcMechanismClassName: string, + mrcModuleOrClassName: string, mrcMapComponentNameToId: {[componentName: string]: string}, } type CallPythonFunctionMixinType = typeof CALL_PYTHON_FUNCTION; @@ -161,6 +163,11 @@ type CallPythonFunctionExtraState = { * The mechanism class name. Specified only if the function kind is INSTANCE_MECHANISM. */ mechanismClassName?: string, + /** + * The module or class name. Specified only if the function kind is MODULE, STATIC, CONSTRUCTOR, + * or INSTANCE. + */ + moduleOrClassName?: string, } const CALL_PYTHON_FUNCTION = { @@ -179,7 +186,7 @@ const CALL_PYTHON_FUNCTION = { break; } case FunctionKind.MODULE: { - const moduleName = this.getFieldValue(FIELD_MODULE_OR_CLASS_NAME); + const moduleName = this.mrcModuleOrClassName; const functionName = this.getFieldValue(FIELD_FUNCTION_NAME); tooltip = Blockly.Msg.CALL_MODULE_FUNCTION_TOOLTIP; tooltip = tooltip @@ -188,7 +195,7 @@ const CALL_PYTHON_FUNCTION = { break; } case FunctionKind.STATIC: { - const className = this.getFieldValue(FIELD_MODULE_OR_CLASS_NAME); + const className = this.mrcModuleOrClassName; const functionName = this.getFieldValue(FIELD_FUNCTION_NAME); tooltip = Blockly.Msg.CALL_STATIC_METHOD_TOOLTIP; tooltip = tooltip @@ -197,13 +204,13 @@ const CALL_PYTHON_FUNCTION = { break; } case FunctionKind.CONSTRUCTOR: { - const className = this.getFieldValue(FIELD_MODULE_OR_CLASS_NAME); + const className = this.mrcModuleOrClassName; tooltip = Blockly.Msg.CALL_CONSTRUCTOR_TOOLTIP; tooltip = tooltip.replace('{{className}}', className); break; } case FunctionKind.INSTANCE: { - const className = this.getFieldValue(FIELD_MODULE_OR_CLASS_NAME); + const className = this.mrcModuleOrClassName; const functionName = this.getFieldValue(FIELD_FUNCTION_NAME); tooltip = Blockly.Msg.CALL_INSTANCE_METHOD_TOOLTIP; tooltip = tooltip @@ -321,6 +328,9 @@ const CALL_PYTHON_FUNCTION = { if (this.mrcMechanismClassName) { extraState.mechanismClassName = this.mrcMechanismClassName; } + if (this.mrcModuleOrClassName) { + extraState.moduleOrClassName = this.mrcModuleOrClassName; + } return extraState; }, /** @@ -348,6 +358,7 @@ const CALL_PYTHON_FUNCTION = { this.mrcMechanismId = extraState.mechanismId ? extraState.mechanismId : ''; this.mrcComponentClassName = extraState.componentClassName ? extraState.componentClassName : ''; this.mrcMechanismClassName = extraState.mechanismClassName ? extraState.mechanismClassName : ''; + this.mrcModuleOrClassName = extraState.moduleOrClassName ? extraState.moduleOrClassName : ''; // Initialize mrcMapComponentNameToId here. It will be filled during checkFunction. this.mrcMapComponentNameToId = {}; this.updateBlock_(); @@ -664,7 +675,7 @@ const CALL_PYTHON_FUNCTION = { checkModuleFunction: function(this: CallPythonFunctionBlock, warnings: string[]): void { // If this block is calling a module function, check whether the module and function still // exist. If the module or function doesn't exist, put a visible warning on this block. - const moduleName = this.getFieldValue(FIELD_MODULE_OR_CLASS_NAME); + const moduleName = this.mrcModuleOrClassName; const moduleData = getModuleData(moduleName); if (moduleData) { let foundFunction = false; @@ -686,7 +697,7 @@ const CALL_PYTHON_FUNCTION = { checkStaticMethod: function(this: CallPythonFunctionBlock, warnings: string[]): void { // If this block is calling a static method, check whether the class and method still // exist. If the class or method doesn't exist, put a visible warning on this block. - const className = this.getFieldValue(FIELD_MODULE_OR_CLASS_NAME); + const className = this.mrcModuleOrClassName; const classData = getClassData(className); if (classData) { let foundFunction = false; @@ -709,7 +720,7 @@ const CALL_PYTHON_FUNCTION = { // If this block is calling a constructor defined in a class, check whether the class and // constructor still exist. // If the class or constructor doesn't exist, put a visible warning on this block. - const className = this.getFieldValue(FIELD_MODULE_OR_CLASS_NAME); + const className = this.mrcModuleOrClassName; const classData = getClassData(className); if (classData) { let foundFunction = false; @@ -729,7 +740,7 @@ const CALL_PYTHON_FUNCTION = { checkInstanceMethod: function(this: CallPythonFunctionBlock, warnings: string[]): void { // If this block is calling a class method, check whether the class and method still exist. // If the class or method doesn't exist, put a visible warning on this block. - const className = this.getFieldValue(FIELD_MODULE_OR_CLASS_NAME); + const className = this.mrcModuleOrClassName; const classData = getClassData(className); if (classData) { let foundFunction = false; @@ -1024,6 +1035,23 @@ const CALL_PYTHON_FUNCTION = { } } }, + + /** + * mrcShowSimpleClassNames is called for each CallPythonFunctionBlock: + * 1. after a block is loaded in the blockly workspace + * 2. after a block is created + * 3. when showSimpleClassNames has been changed + */ + mrcShowSimpleClassNames: function(this: CallPythonFunctionBlock, _editor: Editor, showSimpleClassNames: boolean): void { + if (this.mrcFunctionKind === FunctionKind.STATIC || + this.mrcFunctionKind === FunctionKind.CONSTRUCTOR || + this.mrcFunctionKind === FunctionKind.INSTANCE) { + this.setFieldValue( + classNameToShowOnBlocks(this.mrcModuleOrClassName, showSimpleClassNames), + FIELD_MODULE_OR_CLASS_NAME); + } + }, + /** * mrcChangeIds is called when a module is copied so that the copy has different ids than the original. */ @@ -1048,18 +1076,18 @@ const CALL_PYTHON_FUNCTION = { this.getFieldValue(FIELD_FUNCTION_NAME); case FunctionKind.MODULE: return Blockly.Msg.CALL + ' ' + - this.getFieldValue(FIELD_MODULE_OR_CLASS_NAME) + '.' + + this.mrcModuleOrClassName + '.' + this.getFieldValue(FIELD_FUNCTION_NAME); case FunctionKind.STATIC: return Blockly.Msg.CALL + ' ' + - this.getFieldValue(FIELD_MODULE_OR_CLASS_NAME) + '.' + + this.mrcModuleOrClassName + '.' + this.getFieldValue(FIELD_FUNCTION_NAME); case FunctionKind.CONSTRUCTOR: return Blockly.Msg.CREATE + ' ' + - this.getFieldValue(FIELD_MODULE_OR_CLASS_NAME); + this.mrcModuleOrClassName; case FunctionKind.INSTANCE: return Blockly.Msg.CALL + ' ' + - this.getFieldValue(FIELD_MODULE_OR_CLASS_NAME) + '.' + + this.mrcModuleOrClassName + '.' + this.getFieldValue(FIELD_FUNCTION_NAME); case FunctionKind.INSTANCE_WITHIN: return Blockly.Msg.CALL + ' ' + @@ -1109,6 +1137,16 @@ const CALL_PYTHON_FUNCTION = { } } }, + upgrade_0012_to_0013: function(this: CallPythonFunctionBlock) { + if (this.mrcFunctionKind === FunctionKind.MODULE || + this.mrcFunctionKind === FunctionKind.STATIC || + this.mrcFunctionKind === FunctionKind.CONSTRUCTOR || + this.mrcFunctionKind === FunctionKind.INSTANCE) { + if (this.mrcModuleOrClassName === '') { + this.mrcModuleOrClassName = this.getFieldValue(FIELD_MODULE_OR_CLASS_NAME); + } + } + }, }; export function setup(): void { @@ -1135,7 +1173,7 @@ export function pythonFromBlock( break; } case FunctionKind.MODULE: { - const moduleName = block.getFieldValue(FIELD_MODULE_OR_CLASS_NAME); + const moduleName = block.mrcModuleOrClassName; const functionName = (block.mrcActualFunctionName) ? block.mrcActualFunctionName : block.getFieldValue(FIELD_FUNCTION_NAME); @@ -1143,7 +1181,7 @@ export function pythonFromBlock( break; } case FunctionKind.STATIC: { - const className = block.getFieldValue(FIELD_MODULE_OR_CLASS_NAME); + const className = block.mrcModuleOrClassName; const functionName = (block.mrcActualFunctionName) ? block.mrcActualFunctionName : block.getFieldValue(FIELD_FUNCTION_NAME); @@ -1151,7 +1189,7 @@ export function pythonFromBlock( break; } case FunctionKind.CONSTRUCTOR: { - const className = block.getFieldValue(FIELD_MODULE_OR_CLASS_NAME); + const className = block.mrcModuleOrClassName; code = className; break; } @@ -1402,18 +1440,27 @@ export function addModuleFunctionBlocks( contents: toolboxItems.ContentsType[]) { moduleData.functions.forEach(functionData => { const block = createModuleFunctionOrStaticMethodBlock( - FunctionKind.MODULE, moduleData.moduleName, moduleData.moduleName, functionData); + FunctionKind.MODULE, + moduleData.moduleName, + moduleData.moduleName, + functionData, + false); contents.push(block); }); } export function addStaticMethodBlocks( classData: ClassData, - contents: toolboxItems.ContentsType[]) { + contents: toolboxItems.ContentsType[], + showSimpleClassNames: boolean) { classData.staticMethods.forEach(functionData => { if (functionData.declaringClassName) { const block = createModuleFunctionOrStaticMethodBlock( - FunctionKind.STATIC, classData.moduleName, functionData.declaringClassName, functionData); + FunctionKind.STATIC, + classData.moduleName, + functionData.declaringClassName, + functionData, + showSimpleClassNames); contents.push(block); } }); @@ -1423,16 +1470,22 @@ function createModuleFunctionOrStaticMethodBlock( functionKind: FunctionKind, importModule: string, moduleOrClassName: string, - functionData: FunctionData): toolboxItems.Block { + functionData: FunctionData, + showSimpleClassNames: boolean): toolboxItems.Block { const extraState: CallPythonFunctionExtraState = { functionKind: functionKind, + moduleOrClassName: moduleOrClassName, returnType: functionData.returnType, args: [], tooltip: functionData.tooltip, importModule: importModule, }; const fields: {[key: string]: any} = {}; - fields[FIELD_MODULE_OR_CLASS_NAME] = moduleOrClassName; + if (functionKind === FunctionKind.MODULE) { + fields[FIELD_MODULE_OR_CLASS_NAME] = moduleOrClassName; + } else { + fields[FIELD_MODULE_OR_CLASS_NAME] = classNameToShowOnBlocks(moduleOrClassName, showSimpleClassNames); + } fields[FIELD_FUNCTION_NAME] = functionData.functionName; const inputs: {[key: string]: any} = {}; processArgs(functionData.args, extraState, inputs, functionData.declaringClassName); @@ -1441,24 +1494,30 @@ function createModuleFunctionOrStaticMethodBlock( export function addConstructorBlocks( classData: ClassData, - contents: toolboxItems.ContentsType[]) { + contents: toolboxItems.ContentsType[], + showSimpleClassNames: boolean) { classData.constructors.forEach(functionData => { - contents.push(createConstructorBlock(classData.moduleName, functionData)); + contents.push(createConstructorBlock(classData.moduleName, functionData, showSimpleClassNames)); }); } function createConstructorBlock( importModule: string, - functionData: FunctionData): toolboxItems.Block { + functionData: FunctionData, + showSimpleClassNames: boolean): toolboxItems.Block { const extraState: CallPythonFunctionExtraState = { functionKind: FunctionKind.CONSTRUCTOR, + moduleOrClassName: functionData.declaringClassName, returnType: functionData.returnType, args: [], tooltip: functionData.tooltip, importModule: importModule, }; + if (!functionData.declaringClassName) { + throw new Error('functionData.declaringClassName is missing'); + } const fields: {[key: string]: any} = {}; - fields[FIELD_MODULE_OR_CLASS_NAME] = functionData.declaringClassName; + fields[FIELD_MODULE_OR_CLASS_NAME] = classNameToShowOnBlocks(functionData.declaringClassName, showSimpleClassNames); const inputs: {[key: string]: any} = {}; processArgs(functionData.args, extraState, inputs, functionData.declaringClassName); return createBlock(extraState, fields, inputs); @@ -1466,22 +1525,28 @@ function createConstructorBlock( export function addInstanceMethodBlocks( classData: ClassData, - contents: toolboxItems.ContentsType[]) { + contents: toolboxItems.ContentsType[], + showSimpleClassNames: boolean) { classData.instanceMethods.forEach(functionData => { - contents.push(createInstanceMethodBlock(functionData)); + contents.push(createInstanceMethodBlock(functionData, showSimpleClassNames)); }); } function createInstanceMethodBlock( - functionData: FunctionData): toolboxItems.Block { + functionData: FunctionData, + showSimpleClassNames: boolean): toolboxItems.Block { + if (!functionData.declaringClassName) { + throw new Error('functionData.declaringClassName is missing'); + } const extraState: CallPythonFunctionExtraState = { functionKind: FunctionKind.INSTANCE, + moduleOrClassName: functionData.declaringClassName, returnType: functionData.returnType, args: [], tooltip: functionData.tooltip, }; const fields: {[key: string]: any} = {}; - fields[FIELD_MODULE_OR_CLASS_NAME] = functionData.declaringClassName; + fields[FIELD_MODULE_OR_CLASS_NAME] = classNameToShowOnBlocks(functionData.declaringClassName, showSimpleClassNames); fields[FIELD_FUNCTION_NAME] = functionData.functionName; const inputs: {[key: string]: any} = {}; // We include the arg for the self argument for INSTANCE methods because we want a socket that @@ -1731,3 +1796,13 @@ export function upgrade_0011_to_0012(workspace: Blockly.Workspace): void { (block as CallPythonFunctionBlock).upgrade_0011_to_0012(); }); } + +/** + * Upgrades the CallPythonFunctionBlocks in the given workspace from version 0012 to 0013. + * This function should only be called when upgrading old projects. + */ +export function upgrade_0012_to_0013(workspace: Blockly.Workspace): void { + workspace.getBlocksByType(BLOCK_NAME).forEach(block => { + (block as CallPythonFunctionBlock).upgrade_0012_to_0013(); + }); +} diff --git a/frontend/blocks/mrc_component.ts b/frontend/blocks/mrc_component.ts index 8ce2fdfc..caf86e0e 100644 --- a/frontend/blocks/mrc_component.ts +++ b/frontend/blocks/mrc_component.ts @@ -28,13 +28,16 @@ import { Editor } from '../editor/editor'; import { ExtendedPythonGenerator } from '../editor/extended_python_generator'; import { valueForComponentArgInput } from './utils/value'; import { getModuleTypeForWorkspace } from './utils/workspaces'; -import { componentClasses } from './utils/python'; +import { + classNameToShowOnBlocks, + componentClasses, + getAllowedTypesForSetCheck, + getClassData, + simpleClassName } from './utils/python'; import { makeLegalName } from './utils/validator'; import * as toolboxItems from '../toolbox/items'; -import { getAllowedTypesForSetCheck, getClassData } from './utils/python'; import * as storageModule from '../storage/module'; import * as storageModuleContent from '../storage/module_content'; -import * as storageNames from '../storage/names'; import { NONCOPYABLE_BLOCK } from './noncopyable_block'; import { BLOCK_NAME as MRC_MECHANISM_COMPONENT_HOLDER, @@ -64,6 +67,7 @@ type ConstructorArg = { type ComponentExtraState = { componentId?: string, importModule?: string, + className?: string, tooltip?: string, params?: ConstructorArg[], /** @@ -78,6 +82,7 @@ interface ComponentMixin extends ComponentMixinType { mrcComponentId: string, mrcArgs: ConstructorArg[], mrcImportModule: string, + mrcClassName: string, mrcTooltip: string, /** @@ -132,6 +137,9 @@ const COMPONENT = { if (this.mrcImportModule) { extraState.importModule = this.mrcImportModule; } + if (this.mrcClassName) { + extraState.className = this.mrcClassName; + } if (this.mrcTooltip) { extraState.tooltip = this.mrcTooltip; } @@ -143,6 +151,7 @@ const COMPONENT = { loadExtraState: function (this: ComponentBlock, extraState: ComponentExtraState): void { this.mrcComponentId = extraState.componentId ? extraState.componentId : this.id; this.mrcImportModule = extraState.importModule ? extraState.importModule : ''; + this.mrcClassName = extraState.className ? extraState.className : ''; this.mrcTooltip = extraState.tooltip ? extraState.tooltip : ''; this.mrcArgs = []; @@ -198,7 +207,7 @@ const COMPONENT = { }, getComponent: function (this: ComponentBlock): storageModuleContent.Component | null { const componentName = this.getFieldValue(FIELD_NAME); - const componentType = this.getFieldValue(FIELD_TYPE); + const componentType = this.mrcClassName; const args: storageModuleContent.MethodArg[] = []; this.getComponentArgs(args); return { @@ -273,7 +282,7 @@ const COMPONENT = { * Checks whether the component class exists and if not, puts a warning on the block. */ checkComponentClass: function(this: ComponentBlock): void { - const componentType = this.getFieldValue(FIELD_TYPE); + const componentType = this.mrcClassName; const classData = getClassData(componentType); if (classData) { // Remove previous warning. @@ -292,6 +301,17 @@ const COMPONENT = { } } }, + + /** + * mrcShowSimpleClassNames is called for each ComponentBlock: + * 1. after a block is loaded in the blockly workspace + * 2. after a block is created + * 3. when showSimpleClassNames has been changed + */ + mrcShowSimpleClassNames: function(this: ComponentBlock, _editor: Editor, showSimpleClassNames: boolean): void { + this.setFieldValue(classNameToShowOnBlocks(this.mrcClassName, showSimpleClassNames), FIELD_TYPE); + }, + /** * mrcChangeIds is called when a module is copied so that the copy has different ids than the original. */ @@ -301,7 +321,7 @@ const COMPONENT = { } }, mrcGetFullLabel: function(this: ComponentBlock): string { - return this.getFieldValue(FIELD_NAME) + ' ' + Blockly.Msg.OF_TYPE + ' ' + this.getFieldValue(FIELD_TYPE); + return this.getFieldValue(FIELD_NAME) + ' ' + Blockly.Msg.OF_TYPE + ' ' + this.mrcClassName; }, upgrade_005_to_006: function(this: ComponentBlock) { for (let i = 0; i < this.mrcArgs.length; i++) { @@ -328,6 +348,11 @@ const COMPONENT = { this.mrcImportModule = 'wpilib'; } }, + upgrade_0012_to_0013: function(this: ComponentBlock) { + if (this.mrcClassName === '') { + this.mrcClassName = this.getFieldValue(FIELD_TYPE); + } + } }; export const setup = function () { @@ -343,7 +368,7 @@ export const pythonFromBlock = function ( } const componentName = block.getFieldValue(FIELD_NAME); - const componentType = block.getFieldValue(FIELD_TYPE); + const componentType = block.mrcClassName; let code = 'self.' + componentName + ' = ' + componentType + '(\n'; if (generator.getModuleType() === storageModule.ModuleType.ROBOT) { @@ -371,15 +396,15 @@ export const pythonFromBlock = function ( } export function getAllPossibleComponents( - moduleType: storageModule.ModuleType): toolboxItems.ContentsType[] { + moduleType: storageModule.ModuleType, + showSimpleClassNames: boolean): toolboxItems.ContentsType[] { const contents: toolboxItems.ContentsType[] = []; // Iterate through all the component classes and add definition blocks. componentClasses.forEach(classData => { - const simpleClassName = classData.className.substring(classData.className.lastIndexOf('.') + 1); - const componentName = 'my_' + storageNames.pascalCaseToSnakeCase(simpleClassName); + const componentName = 'my' + simpleClassName(classData.className); classData.constructors.forEach(constructorData => { if (constructorData.isComponent) { - contents.push(createComponentBlock(componentName, classData, constructorData, moduleType)); + contents.push(createComponentBlock(componentName, classData, constructorData, moduleType, showSimpleClassNames)); } }); }); @@ -395,9 +420,11 @@ function createComponentBlock( componentName: string, classData: ClassData, constructorData: FunctionData, - moduleType: storageModule.ModuleType): toolboxItems.Block { + moduleType: storageModule.ModuleType, + showSimpleClassNames: boolean): toolboxItems.Block { const extraState: ComponentExtraState = { importModule: classData.moduleName, + className: classData.className, tooltip: constructorData.tooltip, params: [], moduleType: moduleType, @@ -407,7 +434,7 @@ function createComponentBlock( } const fields: {[key: string]: any} = {}; fields[FIELD_NAME] = componentName; - fields[FIELD_TYPE] = classData.className; + fields[FIELD_TYPE] = classNameToShowOnBlocks(classData.className, showSimpleClassNames); const inputs: {[key: string]: any} = {}; let i = 0; @@ -418,7 +445,7 @@ function createComponentBlock( defaultValue: argData.defaultValue, }); if (moduleType == storageModule.ModuleType.ROBOT) { - const input = valueForComponentArgInput(argData.type, argData.defaultValue); + const input = valueForComponentArgInput(argData.type, argData.defaultValue, showSimpleClassNames); if (input) { inputs[INPUT_ARG_PREFIX + i] = input; } @@ -457,3 +484,13 @@ export function upgrade_0011_to_0012(workspace: Blockly.Workspace): void { (block as ComponentBlock).upgrade_0011_to_0012(); }); } + +/** + * Upgrades the ComponentBlocks in the given workspace from version 0012 to 0013. + * This function should only be called when upgrading old projects. + */ +export function upgrade_0012_to_0013(workspace: Blockly.Workspace): void { + workspace.getBlocksByType(BLOCK_NAME).forEach(block => { + (block as ComponentBlock).upgrade_0012_to_0013(); + }); +} diff --git a/frontend/blocks/mrc_get_python_enum_value.ts b/frontend/blocks/mrc_get_python_enum_value.ts index f5ac15df..bdd16937 100644 --- a/frontend/blocks/mrc_get_python_enum_value.ts +++ b/frontend/blocks/mrc_get_python_enum_value.ts @@ -23,7 +23,7 @@ import * as Blockly from 'blockly'; import { Order } from 'blockly/python'; -import { getEnumData, getOutputCheck } from './utils/python'; +import { classNameToShowOnBlocks, getEnumData, getOutputCheck } from './utils/python'; import { EnumData } from './utils/python_json_types'; import { Editor } from '../editor/editor'; import { ExtendedPythonGenerator } from '../editor/extended_python_generator'; @@ -77,7 +77,7 @@ const GET_PYTHON_ENUM_VALUE = { .appendField('.'); this.setStyle(MRC_STYLE_ENUM); this.setTooltip(() => { - const enumClassName = this.getFieldValue(FIELD_ENUM_CLASS_NAME); + const enumClassName = this.mrcEnumType; const enumValue = this.getFieldValue(FIELD_ENUM_VALUE); let tooltip = replaceTokens(Blockly.Msg['GET_ENUM_VALUE_TOOLTIP'], { enumName: enumClassName, @@ -157,7 +157,7 @@ const GET_PYTHON_ENUM_VALUE = { checkBlock: function(this: GetPythonEnumValueBlock): void { const warnings: string[] = []; - const enumClassName = this.getFieldValue(FIELD_ENUM_CLASS_NAME); + const enumClassName = this.mrcEnumType; const enumData = getEnumData(enumClassName); if (enumData) { const blockEnumValue = this.getFieldValue(FIELD_ENUM_VALUE); @@ -184,6 +184,17 @@ const GET_PYTHON_ENUM_VALUE = { this.setWarningText(null, WARNING_ID_ENUM_CHANGED); } }, + + /** + * mrcShowSimpleClassNames is called for each GetPythonEnumValueBlock: + * 1. after a block is loaded in the blockly workspace + * 2. after a block is created + * 3. when showSimpleClassNames has been changed + */ + mrcShowSimpleClassNames: function(this: GetPythonEnumValueBlock, _editor: Editor, showSimpleClassNames: boolean): void { + this.setFieldValue( + classNameToShowOnBlocks(this.mrcEnumType, showSimpleClassNames), FIELD_ENUM_CLASS_NAME); + }, }; export const setup = function() { @@ -191,14 +202,13 @@ export const setup = function() { }; export const pythonFromBlock = function( - block: Blockly.Block, + block: GetPythonEnumValueBlock, generator: ExtendedPythonGenerator, ) { - const getPythonEnumValueBlock = block as GetPythonEnumValueBlock; - const enumClassName = block.getFieldValue(FIELD_ENUM_CLASS_NAME); + const enumClassName = block.mrcEnumType; const enumValue = block.getFieldValue(FIELD_ENUM_VALUE); - if (getPythonEnumValueBlock.mrcImportModule) { - generator.importModule(getPythonEnumValueBlock.mrcImportModule); + if (block.mrcImportModule) { + generator.importModule(block.mrcImportModule); } const code = enumClassName + '.' + enumValue; return [code, Order.MEMBER]; @@ -206,22 +216,28 @@ export const pythonFromBlock = function( // Functions used for creating blocks for the toolbox. -export function addEnumBlocks(enums: EnumData[], contents: toolboxItems.ContentsType[]) { +export function addEnumBlocks( + enums: EnumData[], + contents: toolboxItems.ContentsType[], + showSimpleClassNames: boolean) { for (const enumData of enums) { for (const enumValue of enumData.enumValues) { - const block = createEnumBlock(enumValue, enumData); + const block = createEnumBlock(enumValue, enumData, showSimpleClassNames); contents.push(block); } } } -export function createEnumBlock(enumValue: string, enumData: EnumData): toolboxItems.Block { +export function createEnumBlock( + enumValue: string, + enumData: EnumData, + showSimpleClassNames: boolean): toolboxItems.Block { const extraState: GetPythonEnumValueExtraState = { enumType: enumData.enumClassName, importModule: enumData.moduleName, }; const fields: {[key: string]: any} = {}; - fields[FIELD_ENUM_CLASS_NAME] = enumData.enumClassName; + fields[FIELD_ENUM_CLASS_NAME] = classNameToShowOnBlocks(enumData.enumClassName, showSimpleClassNames); fields[FIELD_ENUM_VALUE] = enumValue; return new toolboxItems.Block(BLOCK_NAME, extraState, fields, null); } diff --git a/frontend/blocks/mrc_get_python_variable.ts b/frontend/blocks/mrc_get_python_variable.ts index 5be21dce..ca5ace6a 100644 --- a/frontend/blocks/mrc_get_python_variable.ts +++ b/frontend/blocks/mrc_get_python_variable.ts @@ -27,6 +27,7 @@ import { createModuleOrClassVariableSetterBlock, createInstanceVariableSetterBlock } from '../blocks/mrc_set_python_variable'; import { + classNameToShowOnBlocks, getAllowedTypesForSetCheck, getClassData, getModuleData, @@ -153,7 +154,7 @@ const GET_PYTHON_VARIABLE = { let tooltip: string; switch (this.mrcVarKind) { case VariableKind.MODULE: { - const moduleName = this.getFieldValue(FIELD_MODULE_OR_CLASS_NAME); + const moduleName = this.mrcModuleOrClassName; tooltip = replaceTokens(Blockly.Msg['GET_MODULE_VARIABLE_TOOLTIP'], { moduleName: moduleName, varName: varName @@ -161,7 +162,7 @@ const GET_PYTHON_VARIABLE = { break; } case VariableKind.CLASS: { - const className = this.getFieldValue(FIELD_MODULE_OR_CLASS_NAME); + const className = this.mrcModuleOrClassName; tooltip = replaceTokens(Blockly.Msg['GET_CLASS_VARIABLE_TOOLTIP'], { className: className, varName: varName @@ -169,7 +170,7 @@ const GET_PYTHON_VARIABLE = { break; } case VariableKind.INSTANCE: { - const className = this.getFieldValue(FIELD_MODULE_OR_CLASS_NAME); + const className = this.mrcModuleOrClassName; tooltip = replaceTokens(Blockly.Msg['GET_INSTANCE_VARIABLE_TOOLTIP'], { varName: varName, className: className @@ -312,7 +313,7 @@ const GET_PYTHON_VARIABLE = { checkModuleVariable: function(this: GetPythonVariableBlock, warnings: string[]): void { // If this block is getting a module variable, check whether the module and variable still // exist. If the module or variable doesn't exist, put a visible warning on this block. - const moduleName = this.getFieldValue(FIELD_MODULE_OR_CLASS_NAME); + const moduleName = this.mrcModuleOrClassName; const moduleData = getModuleData(moduleName); if (moduleData) { let foundVariable = false; @@ -334,7 +335,7 @@ const GET_PYTHON_VARIABLE = { checkClassVariable: function(this: GetPythonVariableBlock, warnings: string[]): void { // If this block is getting a class variable, check whether the class and variable still // exist. If the class or variable doesn't exist, put a visible warning on this block. - const className = this.getFieldValue(FIELD_MODULE_OR_CLASS_NAME); + const className = this.mrcModuleOrClassName; const classData = getClassData(className); if (classData) { let foundVariable = false; @@ -356,7 +357,7 @@ const GET_PYTHON_VARIABLE = { checkInstanceVariable: function(this: GetPythonVariableBlock, warnings: string[]): void { // If this block is getting an instance variable, check whether the class and variable still // exist. If the class or variable doesn't exist, put a visible warning on this block. - const className = this.getFieldValue(FIELD_MODULE_OR_CLASS_NAME); + const className = this.mrcModuleOrClassName; const classData = getClassData(className); if (classData) { let foundVariable = false; @@ -375,6 +376,21 @@ const GET_PYTHON_VARIABLE = { warnings.push(Blockly.Msg.WARNING_GET_INSTANCE_VARIABLE_MISSING_CLASS); } }, + + /** + * mrcShowSimpleClassNames is called for each GetPythonVariableBlock: + * 1. after a block is loaded in the blockly workspace + * 2. after a block is created + * 3. when showSimpleClassNames has been changed + */ + mrcShowSimpleClassNames: function(this: GetPythonVariableBlock, _editor: Editor, showSimpleClassNames: boolean): void { + if (this.mrcVarKind === VariableKind.CLASS || + this.mrcVarKind === VariableKind.INSTANCE) { + this.setFieldValue( + classNameToShowOnBlocks(this.mrcModuleOrClassName, showSimpleClassNames), + FIELD_MODULE_OR_CLASS_NAME); + } + }, }; export const setup = function() { @@ -382,26 +398,25 @@ export const setup = function() { }; export const pythonFromBlock = function( - block: Blockly.Block, + block: GetPythonVariableBlock, generator: ExtendedPythonGenerator, ) { - const getPythonVariableBlock = block as GetPythonVariableBlock; - const varName = getPythonVariableBlock.mrcActualVariableName - ? getPythonVariableBlock.mrcActualVariableName + const varName = block.mrcActualVariableName + ? block.mrcActualVariableName : block.getFieldValue(FIELD_VARIABLE_NAME); - switch (getPythonVariableBlock.mrcVarKind) { + switch (block.mrcVarKind) { case VariableKind.MODULE: { - const moduleName = block.getFieldValue(FIELD_MODULE_OR_CLASS_NAME); - if (getPythonVariableBlock.mrcImportModule) { - generator.importModule(getPythonVariableBlock.mrcImportModule); + const moduleName = block.mrcModuleOrClassName; + if (block.mrcImportModule) { + generator.importModule(block.mrcImportModule); } const code = moduleName + '.' + varName; return [code, Order.MEMBER]; } case VariableKind.CLASS: { - const className = block.getFieldValue(FIELD_MODULE_OR_CLASS_NAME); - if (getPythonVariableBlock.mrcImportModule) { - generator.importModule(getPythonVariableBlock.mrcImportModule); + const className = block.mrcModuleOrClassName; + if (block.mrcImportModule) { + generator.importModule(block.mrcImportModule); } const code = className + '.' + varName; return [code, Order.MEMBER]; @@ -425,18 +440,29 @@ export function addModuleVariableBlocks( const varsByType: {[key: string]: VariableGettersAndSetters} = organizeVarDataByType(moduleData.moduleVariables); addModuleOrClassVariableBlocks( - VariableKind.MODULE, moduleData.moduleName, moduleData.moduleName, varsByType, contents); + VariableKind.MODULE, + moduleData.moduleName, + moduleData.moduleName, + varsByType, + contents, + false); } } export function addClassVariableBlocks( classData: ClassData, - contents: toolboxItems.ContentsType[]) { + contents: toolboxItems.ContentsType[], + showSimpleClassNames: boolean) { if (classData.classVariables.length) { const varsByType: {[key: string]: VariableGettersAndSetters} = organizeVarDataByType(classData.classVariables); addModuleOrClassVariableBlocks( - VariableKind.CLASS, classData.moduleName, classData.className, varsByType, contents); + VariableKind.CLASS, + classData.moduleName, + classData.className, + varsByType, + contents, + showSimpleClassNames); } } @@ -445,17 +471,18 @@ function addModuleOrClassVariableBlocks( importModule: string, moduleOrClassName: string, varsByType: {[key: string]: VariableGettersAndSetters}, - contents: toolboxItems.ContentsType[]) { + contents: toolboxItems.ContentsType[], + showSimpleClassNames: boolean) { for (const varType in varsByType) { const variableGettersAndSetters = varsByType[varType]; for (let i = 0; i < variableGettersAndSetters.varNamesForGetter.length; i++) { const varName = variableGettersAndSetters.varNamesForGetter[i]; const getterBlock = createModuleOrClassVariableGetterBlock( - varKind, importModule, moduleOrClassName, varType, varName); + varKind, importModule, moduleOrClassName, varType, varName, showSimpleClassNames); contents.push(getterBlock); if (variableGettersAndSetters.varNamesForSetter.includes(varName)) { const setterBlock = createModuleOrClassVariableSetterBlock( - varKind, importModule, moduleOrClassName, varType, varName); + varKind, importModule, moduleOrClassName, varType, varName, showSimpleClassNames); contents.push(setterBlock); } } @@ -467,7 +494,8 @@ function createModuleOrClassVariableGetterBlock( importModule: string, moduleOrClassName: string, varType: string, - varName: string): toolboxItems.Block { + varName: string, + showSimpleClassNames: boolean): toolboxItems.Block { const extraState: GetPythonVariableExtraState = { varKind: varKind, moduleOrClassName: moduleOrClassName, @@ -475,14 +503,19 @@ function createModuleOrClassVariableGetterBlock( importModule: importModule, }; const fields: {[key: string]: any} = {}; - fields[FIELD_MODULE_OR_CLASS_NAME] = moduleOrClassName; + if (varKind === VariableKind.MODULE) { + fields[FIELD_MODULE_OR_CLASS_NAME] = moduleOrClassName; + } else { + fields[FIELD_MODULE_OR_CLASS_NAME] = classNameToShowOnBlocks(moduleOrClassName, showSimpleClassNames); + } fields[FIELD_VARIABLE_NAME] = varName; return new toolboxItems.Block(BLOCK_NAME, extraState, fields, null); } export function addInstanceVariableBlocks( classData: ClassData, - contents: toolboxItems.ContentsType[]) { + contents: toolboxItems.ContentsType[], + showSimpleClassNames: boolean) { if (classData.instanceVariables.length) { const varsByType: {[key: string]: VariableGettersAndSetters} = organizeVarDataByType(classData.instanceVariables); @@ -490,10 +523,10 @@ export function addInstanceVariableBlocks( const variableGettersAndSetters = varsByType[varType]; for (let i = 0; i < variableGettersAndSetters.varNamesForGetter.length; i++) { const varName = variableGettersAndSetters.varNamesForGetter[i]; - const getterBlock = createInstanceVariableGetterBlock(classData.className, varType, varName); + const getterBlock = createInstanceVariableGetterBlock(classData.className, varType, varName, showSimpleClassNames); contents.push(getterBlock); if (variableGettersAndSetters.varNamesForSetter.includes(varName)) { - const setterBlock = createInstanceVariableSetterBlock(classData.className, varType, varName); + const setterBlock = createInstanceVariableSetterBlock(classData.className, varType, varName, showSimpleClassNames); contents.push(setterBlock); } } @@ -504,7 +537,8 @@ export function addInstanceVariableBlocks( function createInstanceVariableGetterBlock( className: string, varType: string, - varName: string): toolboxItems.Block { + varName: string, + showSimpleClassNames: boolean): toolboxItems.Block { const selfLabel = variable.getSelfArgName(className); const extraState: GetPythonVariableExtraState = { varKind: VariableKind.INSTANCE, @@ -514,7 +548,7 @@ function createInstanceVariableGetterBlock( selfType: className, }; const fields: {[key: string]: any} = {}; - fields[FIELD_MODULE_OR_CLASS_NAME] = className; + fields[FIELD_MODULE_OR_CLASS_NAME] = classNameToShowOnBlocks(className, showSimpleClassNames); fields[FIELD_VARIABLE_NAME] = varName; const inputs: {[key: string]: any} = {}; const selfVarName = variable.varNameForType(className); diff --git a/frontend/blocks/mrc_mechanism.ts b/frontend/blocks/mrc_mechanism.ts index 6858ffb1..ca548fa2 100644 --- a/frontend/blocks/mrc_mechanism.ts +++ b/frontend/blocks/mrc_mechanism.ts @@ -397,7 +397,7 @@ const MECHANISM = { } else { defaultValue = ''; } - const value = valueForComponentArgInput(this.mrcParameters[i].type, defaultValue); + const value = valueForComponentArgInput(this.mrcParameters[i].type, defaultValue, editor.getShowSimpleClassNames()); if (value) { // Connect the new block to the input. const newBlockState = value.block; @@ -506,7 +506,9 @@ export const pythonFromBlock = function ( } export function createMechanismBlock( - mechanism: storageModule.Mechanism, components: storageModuleContent.Component[]): toolboxItems.Block { + mechanism: storageModule.Mechanism, + components: storageModuleContent.Component[], + showSimpleClassNames: boolean): toolboxItems.Block { const snakeCaseName = storageNames.pascalCaseToSnakeCase(mechanism.className); const mechanismName = 'my_' + snakeCaseName; const extraState: MechanismExtraState = { @@ -538,7 +540,7 @@ export function createMechanismBlock( } else { defaultValue = ''; } - const input = valueForComponentArgInput(componentArg.type, defaultValue); + const input = valueForComponentArgInput(componentArg.type, defaultValue, showSimpleClassNames); if (input) { inputs[INPUT_ARG_PREFIX + i] = input; } diff --git a/frontend/blocks/mrc_set_python_variable.ts b/frontend/blocks/mrc_set_python_variable.ts index 96b9dd36..f1756c9d 100644 --- a/frontend/blocks/mrc_set_python_variable.ts +++ b/frontend/blocks/mrc_set_python_variable.ts @@ -25,6 +25,7 @@ import { Order } from 'blockly/python'; import { VariableKind } from './mrc_get_python_variable'; import { + classNameToShowOnBlocks, getAllowedTypesForSetCheck, getClassData, getModuleData } from './utils/python'; @@ -139,7 +140,7 @@ const SET_PYTHON_VARIABLE = { let tooltip: string; switch (this.mrcVarKind) { case VariableKind.MODULE: { - const moduleName = this.getFieldValue(FIELD_MODULE_OR_CLASS_NAME); + const moduleName = this.mrcModuleOrClassName; tooltip = replaceTokens(Blockly.Msg['SET_MODULE_VARIABLE_TOOLTIP'], { moduleName: moduleName, varName: varName @@ -147,7 +148,7 @@ const SET_PYTHON_VARIABLE = { break; } case VariableKind.CLASS: { - const className = this.getFieldValue(FIELD_MODULE_OR_CLASS_NAME); + const className = this.mrcModuleOrClassName; tooltip = replaceTokens(Blockly.Msg['SET_CLASS_VARIABLE_TOOLTIP'], { className: className, varName: varName @@ -155,7 +156,7 @@ const SET_PYTHON_VARIABLE = { break; } case VariableKind.INSTANCE: { - const className = this.getFieldValue(FIELD_MODULE_OR_CLASS_NAME); + const className = this.mrcModuleOrClassName; tooltip = replaceTokens(Blockly.Msg['SET_INSTANCE_VARIABLE_TOOLTIP'], { varName: varName, className: className @@ -257,7 +258,7 @@ const SET_PYTHON_VARIABLE = { }, mrcGetFullLabel: function(this: SetPythonVariableBlock): string { return Blockly.Msg.SET + ' ' + - this.getFieldValue(FIELD_MODULE_OR_CLASS_NAME) + '.' + + this.mrcModuleOrClassName + '.' + this.getFieldValue(FIELD_VARIABLE_NAME) + ' ' + Blockly.Msg.TO; }, @@ -302,7 +303,7 @@ const SET_PYTHON_VARIABLE = { checkModuleVariable: function(this: SetPythonVariableBlock, warnings: string[]): void { // If this block is setting a module variable, check whether the module and variable still // exist. If the module or variable doesn't exist, put a visible warning on this block. - const moduleName = this.getFieldValue(FIELD_MODULE_OR_CLASS_NAME); + const moduleName = this.mrcModuleOrClassName; const moduleData = getModuleData(moduleName); if (moduleData) { let foundVariable = false; @@ -328,7 +329,7 @@ const SET_PYTHON_VARIABLE = { checkClassVariable: function(this: SetPythonVariableBlock, warnings: string[]): void { // If this block is setting a class variable, check whether the class and variable still // exist. If the class or variable doesn't exist, put a visible warning on this block. - const className = this.getFieldValue(FIELD_MODULE_OR_CLASS_NAME); + const className = this.mrcModuleOrClassName; const classData = getClassData(className); if (classData) { let foundVariable = false; @@ -354,7 +355,7 @@ const SET_PYTHON_VARIABLE = { checkInstanceVariable: function(this: SetPythonVariableBlock, warnings: string[]): void { // If this block is setting an instance variable, check whether the class and variable still // exist. If the class or variable doesn't exist, put a visible warning on this block. - const className = this.getFieldValue(FIELD_MODULE_OR_CLASS_NAME); + const className = this.mrcModuleOrClassName; const classData = getClassData(className); if (classData) { let foundVariable = false; @@ -377,6 +378,21 @@ const SET_PYTHON_VARIABLE = { warnings.push(Blockly.Msg.WARNING_SET_INSTANCE_VARIABLE_MISSING_CLASS); } }, + + /** + * mrcShowSimpleClassNames is called for each SetPythonVariableBlock: + * 1. after a block is loaded in the blockly workspace + * 2. after a block is created + * 3. when showSimpleClassNames has been changed + */ + mrcShowSimpleClassNames: function(this: SetPythonVariableBlock, _editor: Editor, showSimpleClassNames: boolean): void { + if (this.mrcVarKind === VariableKind.CLASS || + this.mrcVarKind === VariableKind.INSTANCE) { + this.setFieldValue( + classNameToShowOnBlocks(this.mrcModuleOrClassName, showSimpleClassNames), + FIELD_MODULE_OR_CLASS_NAME); + } + }, }; export const setup = function() { @@ -393,7 +409,7 @@ export const pythonFromBlock = function( let code: string; switch (block.mrcVarKind) { case VariableKind.MODULE: { - const moduleName = block.getFieldValue(FIELD_MODULE_OR_CLASS_NAME); + const moduleName = block.mrcModuleOrClassName; const value = generator.valueToCode(block, 'VALUE', Order.NONE); if (block.mrcImportModule) { generator.importModule(block.mrcImportModule); @@ -402,7 +418,7 @@ export const pythonFromBlock = function( break; } case VariableKind.CLASS: { - const className = block.getFieldValue(FIELD_MODULE_OR_CLASS_NAME); + const className = block.mrcModuleOrClassName; const value = generator.valueToCode(block, 'VALUE', Order.NONE); if (block.mrcImportModule) { generator.importModule(block.mrcImportModule); @@ -429,7 +445,8 @@ export function createModuleOrClassVariableSetterBlock( importModule: string, moduleOrClassName: string, varType: string, - varName: string): toolboxItems.Block { + varName: string, + showSimpleClassNames: boolean): toolboxItems.Block { const extraState: SetPythonVariableExtraState = { varKind: varKind, moduleOrClassName: moduleOrClassName, @@ -437,7 +454,11 @@ export function createModuleOrClassVariableSetterBlock( importModule: importModule, }; const fields: {[key: string]: any} = {}; - fields[FIELD_MODULE_OR_CLASS_NAME] = moduleOrClassName; + if (varKind === VariableKind.MODULE) { + fields[FIELD_MODULE_OR_CLASS_NAME] = moduleOrClassName; + } else { + fields[FIELD_MODULE_OR_CLASS_NAME] = classNameToShowOnBlocks(moduleOrClassName, showSimpleClassNames); + } fields[FIELD_VARIABLE_NAME] = varName; const inputs: {[key: string]: any} = {}; const valueVarName = variable.varNameForType(varType); @@ -450,7 +471,8 @@ export function createModuleOrClassVariableSetterBlock( export function createInstanceVariableSetterBlock( className: string, varType: string, - varName: string): toolboxItems.Block { + varName: string, + showSimpleClassNames: boolean): toolboxItems.Block { const selfLabel = variable.getSelfArgName(className); const extraState: SetPythonVariableExtraState = { varKind: VariableKind.INSTANCE, @@ -460,7 +482,7 @@ export function createInstanceVariableSetterBlock( selfType: className, }; const fields: {[key: string]: any} = {}; - fields[FIELD_MODULE_OR_CLASS_NAME] = className; + fields[FIELD_MODULE_OR_CLASS_NAME] = classNameToShowOnBlocks(className, showSimpleClassNames); fields[FIELD_VARIABLE_NAME] = varName; const inputs: {[key: string]: any} = {}; const valueVarName = variable.varNameForType(varType); diff --git a/frontend/blocks/utils/python.ts b/frontend/blocks/utils/python.ts index 73c5c996..1fc98d90 100644 --- a/frontend/blocks/utils/python.ts +++ b/frontend/blocks/utils/python.ts @@ -340,3 +340,14 @@ export function isExistingPythonModule(moduleName: string): boolean { } return false; } + +export function classNameToShowOnBlocks(className: string, showSimpleClassNames: boolean): string { + return showSimpleClassNames ? simpleClassName(className) : className; +} + +export function simpleClassName(className: string): string { + const lastDot = className.lastIndexOf('.') + return (lastDot !== -1) + ? className.substring(lastDot + 1) + : className; +} \ No newline at end of file diff --git a/frontend/blocks/utils/value.ts b/frontend/blocks/utils/value.ts index 4551f705..49be36d9 100644 --- a/frontend/blocks/utils/value.ts +++ b/frontend/blocks/utils/value.ts @@ -75,7 +75,7 @@ export function valueForFunctionArgInput(argType: string, argDefaultValue: strin return null; } -export function valueForComponentArgInput(argType: string, argDefaultValue: string): any { +export function valueForComponentArgInput(argType: string, argDefaultValue: string, showSimpleClassNames: boolean): any { if (isPortType(argType)) { return createPort(argType); } @@ -131,7 +131,7 @@ export function valueForComponentArgInput(argType: string, argDefaultValue: stri } } return { - block: createEnumBlock(enumValue, enumData), + block: createEnumBlock(enumValue, enumData, showSimpleClassNames), }; } diff --git a/frontend/blocks/utils/variable.ts b/frontend/blocks/utils/variable.ts index 4c1d874e..b256fd77 100644 --- a/frontend/blocks/utils/variable.ts +++ b/frontend/blocks/utils/variable.ts @@ -19,7 +19,7 @@ * @author lizlooney@google.com (Liz Looney) */ -import { getAlias } from './python'; +import { getAlias, simpleClassName } from './python'; import * as toolboxItems from '../../toolbox/items'; @@ -83,9 +83,8 @@ export function varNameForType(type: string): string { } // If the type has a dot, it is an object and we should provide a variable // block for this type. - const lastDot = type.lastIndexOf('.') - if (lastDot !== -1) { - return 'my' + type.substring(lastDot + 1); + if (type.includes('.')) { + return 'my' + simpleClassName(type); } // Otherwise, we don't provide a variable block for this type. return '' @@ -93,9 +92,6 @@ export function varNameForType(type: string): string { /** Returns a reasonable name for a label of a self argument of a block that calls an instance method. */ export function getSelfArgName(className: string): string { - const lastDot = className.lastIndexOf('.') - const shortClassName = (lastDot !== -1) - ? className.substring(lastDot + 1) - : className; - return shortClassName.charAt(0).toLowerCase() + shortClassName.substring(1); + const simpleClassNameClassName = simpleClassName(className); + return simpleClassNameClassName.charAt(0).toLowerCase() + simpleClassNameClassName.substring(1); } diff --git a/frontend/editor/editor.ts b/frontend/editor/editor.ts index 42c88ab0..d7efeb4c 100644 --- a/frontend/editor/editor.ts +++ b/frontend/editor/editor.ts @@ -48,6 +48,7 @@ const MRC_ON_DESCENDANT_DISCONNECT = 'mrcOnDescendantDisconnect'; const MRC_ON_ANCESTOR_MOVE = 'mrcOnAncestorMove'; const MRC_ON_MODULE_CURRENT = 'mrcOnModuleCurrent'; const MRC_ON_MUTATOR_OPEN = 'mrcOnMutatorOpen'; +const MRC_SHOW_SIMPLE_CLASS_NAMES = 'mrcShowSimpleClassNames'; export class Editor { private static workspaceIdToEditor: { [workspaceId: string]: Editor } = {}; @@ -66,6 +67,7 @@ export class Editor { private mechanismClassNameToModuleContent: {[mechanismClassName: string]: storageModuleContent.ModuleContent} = {}; private bindedOnChange: any = null; private shownPythonToolboxCategories: Set | null = null; + private showSimpleClassNames: boolean = false; private toolbox: Blockly.utils.toolbox.ToolboxInfo = EMPTY_TOOLBOX; private toolboxUpdateTimeout: NodeJS.Timeout | null = null; @@ -109,6 +111,9 @@ export class Editor { if (MRC_ON_LOAD in block && typeof block[MRC_ON_LOAD] === 'function') { block[MRC_ON_LOAD](this); } + if (MRC_SHOW_SIMPLE_CLASS_NAMES in block && typeof block[MRC_SHOW_SIMPLE_CLASS_NAMES] === 'function') { + block[MRC_SHOW_SIMPLE_CLASS_NAMES](this, this.showSimpleClassNames); + } } }); } @@ -150,6 +155,9 @@ export class Editor { if (MRC_ON_CREATE in block && typeof block[MRC_ON_CREATE] === 'function') { block[MRC_ON_CREATE](this); } + if (MRC_SHOW_SIMPLE_CLASS_NAMES in block && typeof block[MRC_SHOW_SIMPLE_CLASS_NAMES] === 'function') { + block[MRC_SHOW_SIMPLE_CLASS_NAMES](this, this.showSimpleClassNames); + } } }); } @@ -298,6 +306,26 @@ export class Editor { }, 100); } + public updateShowSimpleClassNames(showSimpleClassNames: boolean): void { + this.showSimpleClassNames = showSimpleClassNames; + this.updateToolboxImpl(); + + // Go through all the blocks in the workspace and call their mrcOnShowSimpleClassNamesChanged method. + this.blocklyWorkspace.getAllBlocks().forEach(block => { + if (MRC_SHOW_SIMPLE_CLASS_NAMES in block && typeof block[MRC_SHOW_SIMPLE_CLASS_NAMES] === 'function') { + block[MRC_SHOW_SIMPLE_CLASS_NAMES](this, this.showSimpleClassNames); + } + }); + } + + public getShowSimpleClassNames(): boolean { + return this.showSimpleClassNames; + } + + public getShownPythonToolboxCategories(): Set | null { + return this.shownPythonToolboxCategories; + } + public updateToolbox(shownPythonToolboxCategories: Set): void { this.shownPythonToolboxCategories = shownPythonToolboxCategories; this.updateToolboxImpl(); @@ -308,7 +336,7 @@ export class Editor { // This editor has been abandoned. return; } - const toolbox = getToolboxJSON(this.shownPythonToolboxCategories, this); + const toolbox = getToolboxJSON(this); const previousToolbox = this.blocklyWorkspace.getToolbox(); if (previousToolbox) { applyExpandedCategories(previousToolbox, toolbox); diff --git a/frontend/i18n/locales/en.json b/frontend/i18n/locales/en.json index d6a40cbe..6358be83 100644 --- a/frontend/i18n/locales/en.json +++ b/frontend/i18n/locales/en.json @@ -41,6 +41,7 @@ "ROBOT": "Robot", "SETTINGS": "Settings", "WPI_TOOLBOX": "WPI Toolbox", + "SHOW_SIMPLE_CLASS_NAMES": "Shorten Class Names on Blocks", "THEME": "Theme", "LANGUAGE": "Language", "ENGLISH": "English", diff --git a/frontend/i18n/locales/es.json b/frontend/i18n/locales/es.json index 19febe23..b3628a54 100644 --- a/frontend/i18n/locales/es.json +++ b/frontend/i18n/locales/es.json @@ -36,6 +36,7 @@ "ROBOT": "Robot", "SETTINGS": "Configuración", "WPI_TOOLBOX": "Caja de Herramientas WPI", + "SHOW_SIMPLE_CLASS_NAMES": "Acortar los nombres de clase en los bloques", "THEME": "Tema", "LANGUAGE": "Idioma", "ENGLISH": "Inglés", diff --git a/frontend/i18n/locales/he.json b/frontend/i18n/locales/he.json index a555d2b9..1cc27a79 100644 --- a/frontend/i18n/locales/he.json +++ b/frontend/i18n/locales/he.json @@ -41,6 +41,7 @@ "ROBOT": "רובוט", "SETTINGS": "הגדרות", "WPI_TOOLBOX": "ערכת כלים WPI", + "SHOW_SIMPLE_CLASS_NAMES": "קיצור שמות כיתות על בלוקים", "THEME": "ערכת נושא", "LANGUAGE": "שפה", "ENGLISH": "אנגלית", diff --git a/frontend/reactComponents/Menu.tsx b/frontend/reactComponents/Menu.tsx index d47ede6e..73d648a1 100644 --- a/frontend/reactComponents/Menu.tsx +++ b/frontend/reactComponents/Menu.tsx @@ -59,6 +59,8 @@ export interface MenuProps { openWPIToolboxSettings: () => void; theme: string; setTheme: (theme: string) => void; + showSimpleClassNames: boolean; + setShowSimpleClassNames: (show: boolean) => void; saveCurrentTab: () => Promise; } @@ -91,7 +93,11 @@ function getItem( /** * Generates menu items for a given project. */ -function getMenuItems(t: (key: string) => string, project: storageProject.Project, currentLanguage: string): MenuItem[] { +function getMenuItems( + t: (key: string) => string, + project: storageProject.Project, + currentLanguage: string, + showSimpleClassNames: boolean): MenuItem[] { const mechanisms: MenuItem[] = []; const opmodes: MenuItem[] = []; @@ -127,6 +133,11 @@ function getMenuItems(t: (key: string) => string, project: storageProject.Projec ]), getItem(t('SETTINGS'), 'settings', , [ getItem(t('WPI_TOOLBOX'), 'wpi_toolbox'), + getItem( + t('SHOW_SIMPLE_CLASS_NAMES'), + 'toggle_show_simple_classNames', + showSimpleClassNames ? : undefined + ), getItem(t('THEME') + '...', 'theme', ), getItem(t('LANGUAGE'), 'language', , [ getItem( @@ -262,6 +273,8 @@ export function Component(props: MenuProps): React.JSX.Element { setAboutDialogVisible(true); } else if (key === 'wpi_toolbox'){ props.openWPIToolboxSettings(); + } else if (key === 'toggle_show_simple_classNames'){ + props.setShowSimpleClassNames(!props.showSimpleClassNames) } else if (key === 'theme') { setThemeModalOpen(true); } else if (key == 'deploy') { @@ -359,14 +372,14 @@ export function Component(props: MenuProps): React.JSX.Element { fetchMostRecentProject(); }, [projectNames]); - // Update menu items and save project when project or language changes + // Update menu items and save project when project, language, or showSimpleClassNames changes React.useEffect(() => { if (props.currentProject) { setMostRecentProjectName(); - setMenuItems(getMenuItems(t, props.currentProject, i18n.language)); + setMenuItems(getMenuItems(t, props.currentProject, i18n.language, props.showSimpleClassNames)); setNoProjects(false); } - }, [props.currentProject, i18n.language]); + }, [props.currentProject, i18n.language, props.showSimpleClassNames]); return ( <> diff --git a/frontend/reactComponents/TabContent.tsx b/frontend/reactComponents/TabContent.tsx index a6266e5e..0f9cb28c 100644 --- a/frontend/reactComponents/TabContent.tsx +++ b/frontend/reactComponents/TabContent.tsx @@ -52,6 +52,7 @@ export interface TabContentProps { project: storageProject.Project; storage: commonStorage.Storage; theme: string; + showSimpleClassNames: boolean; shownPythonToolboxCategories: Set; messageApi: MessageInstance; setAlertErrorMessage: (message: string) => void; @@ -69,6 +70,7 @@ export const TabContent = React.forwardRef(({ project, storage, theme, + showSimpleClassNames, shownPythonToolboxCategories, messageApi, setAlertErrorMessage, @@ -159,9 +161,17 @@ export const TabContent = React.forwardRef(({ await newEditor.makeCurrent(project); setEditorInstance(newEditor); + newEditor.updateShowSimpleClassNames(showSimpleClassNames); newEditor.loadModuleBlocks(); newEditor.updateToolbox(shownPythonToolboxCategories); - }, [module, project, storage, modulePath, shownPythonToolboxCategories, messageApi, handleBlocksChanged, openGamepadConfigDialog]); + }, [module, project, storage, modulePath, showSimpleClassNames, shownPythonToolboxCategories, messageApi, handleBlocksChanged, openGamepadConfigDialog]); + + /** Update editor when showSimpleClassNames changes. */ + React.useEffect(() => { + if (editorInstance) { + editorInstance.updateShowSimpleClassNames(showSimpleClassNames); + } + }, [showSimpleClassNames, editorInstance]); /** Update editor toolbox when categories change. */ React.useEffect(() => { diff --git a/frontend/reactComponents/Tabs.tsx b/frontend/reactComponents/Tabs.tsx index 7010920d..3df55bde 100644 --- a/frontend/reactComponents/Tabs.tsx +++ b/frontend/reactComponents/Tabs.tsx @@ -64,6 +64,7 @@ export interface TabsProps { setAlertErrorMessage: (message: string) => void; storage: commonStorage.Storage | null; theme: string; + showSimpleClassNames: boolean; shownPythonToolboxCategories: Set; messageApi: MessageInstance; openGamepadConfigDialog?: () => void; @@ -619,6 +620,7 @@ export const Component = React.forwardRef((props, ref): Reac project={props.project} storage={props.storage} theme={props.theme} + showSimpleClassNames={props.showSimpleClassNames} shownPythonToolboxCategories={props.shownPythonToolboxCategories} messageApi={props.messageApi} setAlertErrorMessage={props.setAlertErrorMessage} diff --git a/frontend/reactComponents/ToolboxSettings.tsx b/frontend/reactComponents/ToolboxSettings.tsx index 8ecb81fc..35050caa 100644 --- a/frontend/reactComponents/ToolboxSettings.tsx +++ b/frontend/reactComponents/ToolboxSettings.tsx @@ -55,7 +55,7 @@ const ToolboxSettingsModal: React.FC = ({ isOpen, sho const afterOpenChange = (open: boolean) => { // When the modal is opened, update the robotPyCategories. if (open) { - setRobotPyCategories(robotPyToolbox.getToolboxCategories(null)); + setRobotPyCategories(robotPyToolbox.getToolboxCategories(null, false)); } }; diff --git a/frontend/reactComponents/UserSettingsProvider.tsx b/frontend/reactComponents/UserSettingsProvider.tsx index 2e562ee3..e9265d00 100644 --- a/frontend/reactComponents/UserSettingsProvider.tsx +++ b/frontend/reactComponents/UserSettingsProvider.tsx @@ -26,10 +26,12 @@ import { Storage } from '../storage/common_storage'; /** Storage keys for user settings. */ const USER_LANGUAGE_KEY = 'userLanguage'; const USER_THEME_KEY = 'userTheme'; +const USER_SHOW_SIMPLE_CLASS_NAMES_KEY = 'userShowSimpleClassNames'; /** Default values for user settings. */ const DEFAULT_LANGUAGE = 'en'; const DEFAULT_THEME = 'dark'; +const DEFAULT_SHOW_SIMPLE_CLASS_NAMES = true; /** Helper function to generate project-specific storage key for open tabs. */ const getUserOptionsKey = (projectName: string): string => `user_options_${projectName}`; @@ -38,6 +40,7 @@ const getUserOptionsKey = (projectName: string): string => `user_options_${proje export interface UserSettings { language: string; theme: string; + showSimpleClassNames: boolean; } /** User settings context interface. */ @@ -45,6 +48,7 @@ export interface UserSettingsContextType { settings: UserSettings; updateLanguage: (language: string) => Promise; updateTheme: (theme: string) => Promise; + updateShowSimpleClassNames: (showSimpleClassNames: boolean) => Promise; updateOpenTabs: (projectName: string, tabPaths: string[]) => Promise; getOpenTabs: (projectName: string) => Promise; isLoading: boolean; @@ -71,6 +75,7 @@ export const UserSettingsProvider: React.FC = ({ const [settings, setSettings] = React.useState({ language: DEFAULT_LANGUAGE, theme: DEFAULT_THEME, + showSimpleClassNames: DEFAULT_SHOW_SIMPLE_CLASS_NAMES, }); const [isLoading, setIsLoading] = React.useState(true); const [error, setError] = React.useState(null); @@ -82,14 +87,16 @@ export const UserSettingsProvider: React.FC = ({ setIsLoading(true); setError(null); - const [language, theme] = await Promise.all([ + const [language, theme, showSimpleClassNames] = await Promise.all([ validStorage.fetchEntry(USER_LANGUAGE_KEY, DEFAULT_LANGUAGE), validStorage.fetchEntry(USER_THEME_KEY, DEFAULT_THEME), + validStorage.fetchEntry(USER_SHOW_SIMPLE_CLASS_NAMES_KEY, DEFAULT_SHOW_SIMPLE_CLASS_NAMES.toString()), ]); setSettings({ language, theme, + showSimpleClassNames: showSimpleClassNames.toLowerCase() === "true", }); } catch (err) { setError(`Failed to load user settings: ${err}`); @@ -139,6 +146,21 @@ export const UserSettingsProvider: React.FC = ({ } }; + /** Update showSimpleClassNames setting. */ + const updateShowSimpleClassNames = async (showSimpleClassNames: boolean): Promise => { + try { + setError(null); + if (storage) { + await storage.saveEntry(USER_SHOW_SIMPLE_CLASS_NAMES_KEY, showSimpleClassNames.toString()); + setSettings(prev => ({ ...prev, showSimpleClassNames })); + } + } catch (err) { + setError(`Failed to save showPackageName setting: ${err}`); + console.error('Error saving showPackageName setting:', err); + throw err; + } + }; + /** Update open tabs for a specific project. */ const updateOpenTabs = async (projectName: string, tabPaths: string[]): Promise => { try { @@ -183,6 +205,7 @@ export const UserSettingsProvider: React.FC = ({ settings, updateLanguage, updateTheme, + updateShowSimpleClassNames, updateOpenTabs, getOpenTabs, isLoading, diff --git a/frontend/storage/upgrade_project.ts b/frontend/storage/upgrade_project.ts index b75448bf..ee628f4b 100644 --- a/frontend/storage/upgrade_project.ts +++ b/frontend/storage/upgrade_project.ts @@ -38,17 +38,19 @@ import { import { upgrade_005_to_006 } from '../blocks/mrc_component'; import { upgrade_008_to_009 as upgrade_component_008_to_009, - upgrade_0011_to_0012 as upgrade_component_0011_to_0012 + upgrade_0011_to_0012 as upgrade_component_0011_to_0012, + upgrade_0012_to_0013 as upgrade_component_0012_to_0013 } from '../blocks/mrc_component'; import { upgrade_008_to_009 as upgrade_call_python_function_008_to_009, - upgrade_0011_to_0012 as upgrade_call_python_function_0011_to_0012 + upgrade_0011_to_0012 as upgrade_call_python_function_0011_to_0012, + upgrade_0012_to_0013 as upgrade_call_python_function_0012_to_0013 } from '../blocks/mrc_call_python_function'; import { GamepadTypeUtils } from '../types/GamepadType'; import * as workspaces from '../blocks/utils/workspaces'; export const NO_VERSION = '0.0.0'; -export const CURRENT_VERSION = '0.0.12'; +export const CURRENT_VERSION = '0.0.13'; export async function upgradeProjectIfNecessary( storage: commonStorage.Storage, projectName: string): Promise { @@ -118,6 +120,11 @@ export async function upgradeProjectIfNecessary( case '0.0.11': await upgradeFrom_0011_to_0012(storage, projectName, projectInfo); + // Intentional fallthrough after case '0.0.12' + // @ts-ignore + case '0.0.12': + await upgradeFrom_0012_to_0013(storage, projectName, projectInfo); + } await storageProject.saveProjectInfo(storage, projectName, projectInfo); } @@ -370,3 +377,18 @@ async function upgradeFrom_0011_to_0012( anyModuleType, upgrade); projectInfo.version = '0.0.12'; } + +async function upgradeFrom_0012_to_0013( + storage: commonStorage.Storage, + projectName: string, + projectInfo: storageProject.ProjectInfo): Promise { + const upgrade = function (workspace: Blockly.Workspace) { + upgrade_component_0012_to_0013(workspace); + upgrade_call_python_function_0012_to_0013(workspace); + }; + await upgradeBlocksFiles( + storage, projectName, + noModuleTypes, noPreupgrade, + anyModuleType, upgrade); + projectInfo.version = '0.0.13'; +} diff --git a/frontend/toolbox/hardware_category.ts b/frontend/toolbox/hardware_category.ts index ad02e725..00c4a694 100644 --- a/frontend/toolbox/hardware_category.ts +++ b/frontend/toolbox/hardware_category.ts @@ -32,7 +32,8 @@ import { addInstanceMechanismBlocks } from '../blocks/mrc_call_python_function'; import { Editor } from '../editor/editor'; -export function getHardwareCategory(editor: Editor): toolboxItems.Category { +export function getHardwareCategory( + editor: Editor): toolboxItems.Category { const moduleType = editor.getModuleType(); switch (moduleType) { case storageModule.ModuleType.ROBOT: @@ -77,7 +78,7 @@ function getRobotMechanismsCategory(editor: Editor): toolboxItems.Category { // Here we need all the components (regular and private) from the mechanism because we need // to create port parameters for all the components. const components = editor.getAllComponentsFromMechanism(mechanism); - mechanismBlocks.push(createMechanismBlock(mechanism, components)); + mechanismBlocks.push(createMechanismBlock(mechanism, components, editor.getShowSimpleClassNames())); }); contents.push({ @@ -199,7 +200,7 @@ function getComponentsCategory( contents.push({ kind: 'category', name: Blockly.Msg['MRC_CATEGORY_ADD_COMPONENT'], - contents: getAllPossibleComponents(moduleType), + contents: getAllPossibleComponents(moduleType, editor.getShowSimpleClassNames()), }); // Get all (regular and private) components from the current workspace. diff --git a/frontend/toolbox/robotpy_toolbox.ts b/frontend/toolbox/robotpy_toolbox.ts index a8fac58a..f86808cd 100644 --- a/frontend/toolbox/robotpy_toolbox.ts +++ b/frontend/toolbox/robotpy_toolbox.ts @@ -34,7 +34,9 @@ import { ClassData, ModuleData } from '../blocks/utils/python_json_types'; import * as toolboxItems from './items'; -export function getToolboxCategories(shownPythonToolboxCategories: Set | null): toolboxItems.Category[] { +export function getToolboxCategories( + shownPythonToolboxCategories: Set | null, + showSimpleClassNames: boolean): toolboxItems.Category[] { const contents: toolboxItems.Category[] = []; const allCategories: {[key: string]: toolboxItems.Category} = {}; @@ -48,7 +50,7 @@ export function getToolboxCategories(shownPythonToolboxCategories: Set | const name = (lastDot != -1) ? path.substring(lastDot + 1) : path; const contents: toolboxItems.ContentsType[] = []; - addModuleBlocks(moduleData, contents); + addModuleBlocks(moduleData, contents, showSimpleClassNames); const moduleCategory: toolboxItems.PythonModuleCategory = { kind: 'category', @@ -67,7 +69,7 @@ export function getToolboxCategories(shownPythonToolboxCategories: Set | const name = (lastDot != -1) ? path.substring(lastDot + 1) : path; const contents: toolboxItems.ContentsType[] = []; - addClassBlocks(classData, contents); + addClassBlocks(classData, contents, showSimpleClassNames); const classCategory: toolboxItems.PythonClassCategory = { kind: 'category', name: name, @@ -92,7 +94,10 @@ export function getToolboxCategories(shownPythonToolboxCategories: Set | return contents; } -function addModuleBlocks(moduleData: ModuleData, contents: toolboxItems.ContentsType[]) { +function addModuleBlocks( + moduleData: ModuleData, + contents: toolboxItems.ContentsType[], + showSimpleClassNames: boolean) { // Module variable blocks. addModuleVariableBlocks(moduleData, contents); @@ -100,23 +105,26 @@ function addModuleBlocks(moduleData: ModuleData, contents: toolboxItems.Contents addModuleFunctionBlocks(moduleData, contents); // Enum blocks - addEnumBlocks(moduleData.enums, contents); + addEnumBlocks(moduleData.enums, contents, showSimpleClassNames); } -function addClassBlocks(classData: ClassData, contents: toolboxItems.ContentsType[]) { +function addClassBlocks( + classData: ClassData, + contents: toolboxItems.ContentsType[], + showSimpleClassNames: boolean) { // Function blocks (constructors, instance methods, static methods) - addConstructorBlocks(classData, contents); - addInstanceMethodBlocks(classData, contents); - addStaticMethodBlocks(classData, contents); + addConstructorBlocks(classData, contents, showSimpleClassNames); + addInstanceMethodBlocks(classData, contents, showSimpleClassNames); + addStaticMethodBlocks(classData, contents, showSimpleClassNames); // Instance variable blocks - addInstanceVariableBlocks(classData, contents); + addInstanceVariableBlocks(classData, contents, showSimpleClassNames); // Class variable blocks. - addClassVariableBlocks(classData, contents); + addClassVariableBlocks(classData, contents, showSimpleClassNames); // Enum blocks - addEnumBlocks(classData.enums, contents); + addEnumBlocks(classData.enums, contents, showSimpleClassNames); } function addCategoriesToParents( diff --git a/frontend/toolbox/toolbox.ts b/frontend/toolbox/toolbox.ts index 35df8271..bd29c3ec 100644 --- a/frontend/toolbox/toolbox.ts +++ b/frontend/toolbox/toolbox.ts @@ -8,9 +8,7 @@ import { getCategory as getEventCategory } from './event_category'; import { getDriverStationCategory } from './driver_station_category'; export function getToolboxJSON( - shownPythonToolboxCategories: Set | null, editor: Editor): Blockly.utils.toolbox.ToolboxInfo { - const toolbox: Blockly.utils.toolbox.ToolboxInfo = { kind: 'categoryToolbox', contents: [] @@ -21,14 +19,14 @@ export function getToolboxJSON( case storageModule.ModuleType.MECHANISM: toolbox.contents.push(getHardwareCategory(editor)); toolbox.contents.push(new toolboxItems.Sep()); - toolbox.contents.push(...common.getToolboxItems(shownPythonToolboxCategories, editor)); + toolbox.contents.push(...common.getToolboxItems(editor)); toolbox.contents.push(getEventCategory(editor)); break; case storageModule.ModuleType.OPMODE: toolbox.contents.push(getDriverStationCategory(editor)); toolbox.contents.push(getHardwareCategory(editor)); toolbox.contents.push(new toolboxItems.Sep()); - toolbox.contents.push(...common.getToolboxItems(shownPythonToolboxCategories, editor)); + toolbox.contents.push(...common.getToolboxItems(editor)); break; } diff --git a/frontend/toolbox/toolbox_common.ts b/frontend/toolbox/toolbox_common.ts index db598d27..82e10615 100644 --- a/frontend/toolbox/toolbox_common.ts +++ b/frontend/toolbox/toolbox_common.ts @@ -34,11 +34,11 @@ import { Editor } from '../editor/editor'; export function getToolboxItems( - shownPythonToolboxCategories: Set | null, editor: Editor): toolboxItems.ContentsType[] { const contents: toolboxItems.ContentsType[] = []; - const robotPyCategories: toolboxItems.ContentsType[] = robotPyToolbox.getToolboxCategories(shownPythonToolboxCategories); + const robotPyCategories: toolboxItems.ContentsType[] = robotPyToolbox.getToolboxCategories( + editor.getShownPythonToolboxCategories(), editor.getShowSimpleClassNames()); if (robotPyCategories.length) { contents.push.apply(contents, robotPyCategories);