Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ import * as clientSideStorage from './storage/client_side_storage';
import * as CustomBlocks from './blocks/setup_custom_blocks';
import { initialize as initializePythonBlocks } from './blocks/utils/python';
import * as ChangeFramework from './blocks/utils/change_framework'
import { mutatorOpenListener } from './blocks/mrc_class_method_def'
import { mutatorOpenListener } from './blocks/mrc_param_container'

const App: React.FC = () => {
const [alertErrorMessage, setAlertErrorMessage] = React.useState('');
Expand Down
27 changes: 24 additions & 3 deletions src/blocks/mrc_call_python_function.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,16 +40,17 @@ import * as toolboxItems from '../toolbox/items';

export const BLOCK_NAME = 'mrc_call_python_function';

enum FunctionKind {
export enum FunctionKind {
MODULE = 'module',
STATIC = 'static',
CONSTRUCTOR = 'constructor',
INSTANCE = 'instance',
INSTANCE_WITHIN = 'instance_within',
INSTANCE_COMPONENT = 'instance_component'
INSTANCE_COMPONENT = 'instance_component',
EVENT = 'event',
}

const RETURN_TYPE_NONE = 'None';
export const RETURN_TYPE_NONE = 'None';

const FIELD_MODULE_OR_CLASS_NAME = 'MODULE_OR_CLASS';
const FIELD_FUNCTION_NAME = 'FUNC';
Expand Down Expand Up @@ -318,6 +319,11 @@ const CALL_PYTHON_FUNCTION = {
tooltip = 'Calls the instance method ' + functionName + '.';
break;
}
case FunctionKind.EVENT: {
const functionName = this.getFieldValue(FIELD_FUNCTION_NAME);
tooltip = 'Fires the event ' + functionName + '.';
break;
}
case FunctionKind.INSTANCE_COMPONENT: {
const className = this.mrcComponentClassName;
const functionName = this.getFieldValue(FIELD_FUNCTION_NAME);
Expand Down Expand Up @@ -459,6 +465,15 @@ const CALL_PYTHON_FUNCTION = {
}
break;
}
case FunctionKind.EVENT: {
const input = this.getInput('TITLE');
if (!input) {
this.appendDummyInput('TITLE')
.appendField('fire')
.appendField(createFieldNonEditableText(''), FIELD_FUNCTION_NAME);
}
break;
}
case FunctionKind.INSTANCE_COMPONENT: {
const componentNames = Editor.getComponentNames(this.workspace, this.mrcComponentClassName);
const componentName = this.getComponentName();
Expand Down Expand Up @@ -586,6 +601,12 @@ export const pythonFromBlock = function(
code = 'self.' + functionName;
break;
}
case FunctionKind.EVENT: {
const blocklyName = block.getFieldValue(FIELD_FUNCTION_NAME);
const functionName = generator.getProcedureName(blocklyName);
code = 'if self.events.get("' + functionName + '", None):\n' + generator.INDENT + 'self.events["' + functionName + '"]';
break;
}
case FunctionKind.INSTANCE_COMPONENT: {
const componentName = callPythonFunctionBlock.getComponentName();
const functionName = callPythonFunctionBlock.mrcActualFunctionName
Expand Down
136 changes: 5 additions & 131 deletions src/blocks/mrc_class_method_def.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,20 +23,15 @@ import * as Blockly from 'blockly';
import { MRC_STYLE_CLASS_BLOCKS } from '../themes/styles';
import { createFieldNonEditableText } from '../fields/FieldNonEditableText'
import { createFieldFlydown } from '../fields/field_flydown';
import * as ChangeFramework from './utils/change_framework'
import { getLegalName } from './utils/python';
import { Order } from 'blockly/python';
import { ExtendedPythonGenerator } from '../editor/extended_python_generator';
import { renameMethodCallers, mutateMethodCallers } from './mrc_call_python_function'
import { findConnectedBlocksOfType } from './utils/find_connected_blocks';
import { BLOCK_NAME as MRC_GET_PARAMETER_BLOCK_NAME } from './mrc_get_parameter';

import { MUTATOR_BLOCK_NAME, PARAM_CONTAINER_BLOCK_NAME, MethodMutatorArgBlock } from './mrc_param_container'

export const BLOCK_NAME = 'mrc_class_method_def';

export const MUTATOR_BLOCK_NAME = 'methods_mutatorarg';
const PARAM_CONTAINER_BLOCK_NAME = 'method_param_container';

export type Parameter = {
name: string,
type?: string,
Expand Down Expand Up @@ -314,133 +309,8 @@ function isMethodNameUsed(
return false;
}

const METHOD_PARAM_CONTAINER = {
init: function (this: Blockly.Block) {
this.appendDummyInput("TITLE").appendField('Parameters');
this.appendStatementInput('STACK');
this.setStyle(MRC_STYLE_CLASS_BLOCKS);
this.contextMenu = false;
},
};

type MethodMutatorArgBlock = Blockly.Block & MethodMutatorArgMixin & Blockly.BlockSvg;
interface MethodMutatorArgMixin extends MethodMutatorArgMixinType {
originalName: string,
}

type MethodMutatorArgMixinType = typeof METHODS_MUTATORARG;

function setName(block: Blockly.BlockSvg) {
const parentBlock = ChangeFramework.getParentOfType(block, PARAM_CONTAINER_BLOCK_NAME);
if (parentBlock) {
const variableBlocks = parentBlock!.getDescendants(true)
const otherNames: string[] = []
variableBlocks?.forEach(function (variableBlock) {
if (variableBlock != block) {
otherNames.push(variableBlock.getFieldValue('NAME'));
}
});
const currentName = block.getFieldValue('NAME');
block.setFieldValue(getLegalName(currentName, otherNames), 'NAME');
updateMutatorFlyout(block.workspace);
}
}

const METHODS_MUTATORARG = {
init: function (this: MethodMutatorArgBlock) {
this.appendDummyInput()
.appendField(new Blockly.FieldTextInput(Blockly.Procedures.DEFAULT_ARG), 'NAME');
this.setPreviousStatement(true);
this.setNextStatement(true);
this.setStyle(MRC_STYLE_CLASS_BLOCKS);
this.originalName = '';
this.contextMenu = false;
ChangeFramework.registerCallback(MUTATOR_BLOCK_NAME, [Blockly.Events.BLOCK_MOVE, Blockly.Events.BLOCK_CHANGE], this.onBlockChanged);
},
onBlockChanged: function (block: Blockly.BlockSvg, blockEvent: Blockly.Events.BlockBase) {
if (blockEvent.type == Blockly.Events.BLOCK_MOVE) {
let blockMoveEvent = blockEvent as Blockly.Events.BlockMove;
if (blockMoveEvent.reason?.includes('connect')) {
setName(block);
}
}
else {
if (blockEvent.type == Blockly.Events.BLOCK_CHANGE) {
setName(block);
}
}
},
}


/**
* Updates the procedure mutator's flyout so that the arg block is not a
* duplicate of another arg.
*
* @param workspace The procedure mutator's workspace. This workspace's flyout
* is what is being updated.
*/
function updateMutatorFlyout(workspace: Blockly.WorkspaceSvg) {
const usedNames = [];
const blocks = workspace.getBlocksByType(MUTATOR_BLOCK_NAME, false);
for (let i = 0, block; (block = blocks[i]); i++) {
usedNames.push(block.getFieldValue('NAME'));
}
const argValue = Blockly.Variables.generateUniqueNameFromOptions(
Blockly.Procedures.DEFAULT_ARG,
usedNames,
);
const jsonBlock = {
kind: 'block',
type: MUTATOR_BLOCK_NAME,
fields: {
NAME: argValue,
},
};

workspace.updateToolbox({ contents: [jsonBlock] });
}


/**
* Listens for when a procedure mutator is opened. Then it triggers a flyout
* update and adds a mutator change listener to the mutator workspace.
*
* @param e The event that triggered this listener.
* @internal
*/
export function mutatorOpenListener(e: Blockly.Events.Abstract) {
if (e.type != Blockly.Events.BUBBLE_OPEN) {
return;
}
const bubbleEvent = e as Blockly.Events.BubbleOpen;
if (
!(bubbleEvent.bubbleType === 'mutator' && bubbleEvent.isOpen) ||
!bubbleEvent.blockId
) {
return;
}
const workspaceId = bubbleEvent.workspaceId;
const block = Blockly.common
.getWorkspaceById(workspaceId)!
.getBlockById(bubbleEvent.blockId) as Blockly.BlockSvg;

if (block.type !== BLOCK_NAME) {
return;
}
const workspace = (
block.getIcon(Blockly.icons.MutatorIcon.TYPE) as Blockly.icons.MutatorIcon
).getWorkspace()!;

updateMutatorFlyout(workspace);
ChangeFramework.setup(workspace);
}


export const setup = function () {
Blockly.Blocks[BLOCK_NAME] = CLASS_METHOD_DEF;
Blockly.Blocks[MUTATOR_BLOCK_NAME] = METHODS_MUTATORARG;
Blockly.Blocks[PARAM_CONTAINER_BLOCK_NAME] = METHOD_PARAM_CONTAINER;
};

export const pythonFromBlock = function (
Expand Down Expand Up @@ -486,6 +356,10 @@ export const pythonFromBlock = function (
branch = generator.INDENT + 'super().__init__(' + class_specific + ')\n' +
generator.defineClassVariables() + branch;
}
else if (funcName == 'update'){
// Special case for update, to also call the update method of the base class
branch = generator.INDENT + 'self.update()\n' + branch;
}
if (returnValue) {
returnValue = generator.INDENT + 'return ' + returnValue + '\n';
} else if (!branch) {
Expand Down
Loading