Skip to content

Commit a81f8c3

Browse files
authored
Adds event support (#121)
* Adds event support * Added calling the super class for update
1 parent 12281af commit a81f8c3

12 files changed

+428
-166
lines changed

src/App.tsx

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -38,9 +38,10 @@ import * as commonStorage from './storage/common_storage';
3838
import * as clientSideStorage from './storage/client_side_storage';
3939

4040
import * as CustomBlocks from './blocks/setup_custom_blocks';
41-
import {initialize as initializePythonBlocks} from './blocks/utils/python';
42-
import * as ChangeFramework from './blocks/utils/change_framework';
43-
import {mutatorOpenListener} from './blocks/mrc_class_method_def';
41+
42+
import { initialize as initializePythonBlocks } from './blocks/utils/python';
43+
import * as ChangeFramework from './blocks/utils/change_framework'
44+
import { mutatorOpenListener } from './blocks/mrc_param_container'
4445

4546
/** Storage key for shown toolbox categories. */
4647
const SHOWN_TOOLBOX_CATEGORIES_KEY = 'shownPythonToolboxCategories';

src/blocks/mrc_call_python_function.ts

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -40,16 +40,17 @@ import * as toolboxItems from '../toolbox/items';
4040

4141
export const BLOCK_NAME = 'mrc_call_python_function';
4242

43-
enum FunctionKind {
43+
export enum FunctionKind {
4444
MODULE = 'module',
4545
STATIC = 'static',
4646
CONSTRUCTOR = 'constructor',
4747
INSTANCE = 'instance',
4848
INSTANCE_WITHIN = 'instance_within',
49-
INSTANCE_COMPONENT = 'instance_component'
49+
INSTANCE_COMPONENT = 'instance_component',
50+
EVENT = 'event',
5051
}
5152

52-
const RETURN_TYPE_NONE = 'None';
53+
export const RETURN_TYPE_NONE = 'None';
5354

5455
const FIELD_MODULE_OR_CLASS_NAME = 'MODULE_OR_CLASS';
5556
const FIELD_FUNCTION_NAME = 'FUNC';
@@ -318,6 +319,11 @@ const CALL_PYTHON_FUNCTION = {
318319
tooltip = 'Calls the instance method ' + functionName + '.';
319320
break;
320321
}
322+
case FunctionKind.EVENT: {
323+
const functionName = this.getFieldValue(FIELD_FUNCTION_NAME);
324+
tooltip = 'Fires the event ' + functionName + '.';
325+
break;
326+
}
321327
case FunctionKind.INSTANCE_COMPONENT: {
322328
const className = this.mrcComponentClassName;
323329
const functionName = this.getFieldValue(FIELD_FUNCTION_NAME);
@@ -459,6 +465,15 @@ const CALL_PYTHON_FUNCTION = {
459465
}
460466
break;
461467
}
468+
case FunctionKind.EVENT: {
469+
const input = this.getInput('TITLE');
470+
if (!input) {
471+
this.appendDummyInput('TITLE')
472+
.appendField('fire')
473+
.appendField(createFieldNonEditableText(''), FIELD_FUNCTION_NAME);
474+
}
475+
break;
476+
}
462477
case FunctionKind.INSTANCE_COMPONENT: {
463478
const componentNames = Editor.getComponentNames(this.workspace, this.mrcComponentClassName);
464479
const componentName = this.getComponentName();
@@ -586,6 +601,12 @@ export const pythonFromBlock = function(
586601
code = 'self.' + functionName;
587602
break;
588603
}
604+
case FunctionKind.EVENT: {
605+
const blocklyName = block.getFieldValue(FIELD_FUNCTION_NAME);
606+
const functionName = generator.getProcedureName(blocklyName);
607+
code = 'if self.events.get("' + functionName + '", None):\n' + generator.INDENT + 'self.events["' + functionName + '"]';
608+
break;
609+
}
589610
case FunctionKind.INSTANCE_COMPONENT: {
590611
const componentName = callPythonFunctionBlock.getComponentName();
591612
const functionName = callPythonFunctionBlock.mrcActualFunctionName

src/blocks/mrc_class_method_def.ts

Lines changed: 5 additions & 131 deletions
Original file line numberDiff line numberDiff line change
@@ -23,20 +23,15 @@ import * as Blockly from 'blockly';
2323
import { MRC_STYLE_CLASS_BLOCKS } from '../themes/styles';
2424
import { createFieldNonEditableText } from '../fields/FieldNonEditableText'
2525
import { createFieldFlydown } from '../fields/field_flydown';
26-
import * as ChangeFramework from './utils/change_framework'
27-
import { getLegalName } from './utils/python';
2826
import { Order } from 'blockly/python';
2927
import { ExtendedPythonGenerator } from '../editor/extended_python_generator';
3028
import { renameMethodCallers, mutateMethodCallers } from './mrc_call_python_function'
3129
import { findConnectedBlocksOfType } from './utils/find_connected_blocks';
3230
import { BLOCK_NAME as MRC_GET_PARAMETER_BLOCK_NAME } from './mrc_get_parameter';
33-
31+
import { MUTATOR_BLOCK_NAME, PARAM_CONTAINER_BLOCK_NAME, MethodMutatorArgBlock } from './mrc_param_container'
3432

3533
export const BLOCK_NAME = 'mrc_class_method_def';
3634

37-
export const MUTATOR_BLOCK_NAME = 'methods_mutatorarg';
38-
const PARAM_CONTAINER_BLOCK_NAME = 'method_param_container';
39-
4035
export type Parameter = {
4136
name: string,
4237
type?: string,
@@ -314,133 +309,8 @@ function isMethodNameUsed(
314309
return false;
315310
}
316311

317-
const METHOD_PARAM_CONTAINER = {
318-
init: function (this: Blockly.Block) {
319-
this.appendDummyInput("TITLE").appendField('Parameters');
320-
this.appendStatementInput('STACK');
321-
this.setStyle(MRC_STYLE_CLASS_BLOCKS);
322-
this.contextMenu = false;
323-
},
324-
};
325-
326-
type MethodMutatorArgBlock = Blockly.Block & MethodMutatorArgMixin & Blockly.BlockSvg;
327-
interface MethodMutatorArgMixin extends MethodMutatorArgMixinType {
328-
originalName: string,
329-
}
330-
331-
type MethodMutatorArgMixinType = typeof METHODS_MUTATORARG;
332-
333-
function setName(block: Blockly.BlockSvg) {
334-
const parentBlock = ChangeFramework.getParentOfType(block, PARAM_CONTAINER_BLOCK_NAME);
335-
if (parentBlock) {
336-
const variableBlocks = parentBlock!.getDescendants(true)
337-
const otherNames: string[] = []
338-
variableBlocks?.forEach(function (variableBlock) {
339-
if (variableBlock != block) {
340-
otherNames.push(variableBlock.getFieldValue('NAME'));
341-
}
342-
});
343-
const currentName = block.getFieldValue('NAME');
344-
block.setFieldValue(getLegalName(currentName, otherNames), 'NAME');
345-
updateMutatorFlyout(block.workspace);
346-
}
347-
}
348-
349-
const METHODS_MUTATORARG = {
350-
init: function (this: MethodMutatorArgBlock) {
351-
this.appendDummyInput()
352-
.appendField(new Blockly.FieldTextInput(Blockly.Procedures.DEFAULT_ARG), 'NAME');
353-
this.setPreviousStatement(true);
354-
this.setNextStatement(true);
355-
this.setStyle(MRC_STYLE_CLASS_BLOCKS);
356-
this.originalName = '';
357-
this.contextMenu = false;
358-
ChangeFramework.registerCallback(MUTATOR_BLOCK_NAME, [Blockly.Events.BLOCK_MOVE, Blockly.Events.BLOCK_CHANGE], this.onBlockChanged);
359-
},
360-
onBlockChanged: function (block: Blockly.BlockSvg, blockEvent: Blockly.Events.BlockBase) {
361-
if (blockEvent.type == Blockly.Events.BLOCK_MOVE) {
362-
let blockMoveEvent = blockEvent as Blockly.Events.BlockMove;
363-
if (blockMoveEvent.reason?.includes('connect')) {
364-
setName(block);
365-
}
366-
}
367-
else {
368-
if (blockEvent.type == Blockly.Events.BLOCK_CHANGE) {
369-
setName(block);
370-
}
371-
}
372-
},
373-
}
374-
375-
376-
/**
377-
* Updates the procedure mutator's flyout so that the arg block is not a
378-
* duplicate of another arg.
379-
*
380-
* @param workspace The procedure mutator's workspace. This workspace's flyout
381-
* is what is being updated.
382-
*/
383-
function updateMutatorFlyout(workspace: Blockly.WorkspaceSvg) {
384-
const usedNames = [];
385-
const blocks = workspace.getBlocksByType(MUTATOR_BLOCK_NAME, false);
386-
for (let i = 0, block; (block = blocks[i]); i++) {
387-
usedNames.push(block.getFieldValue('NAME'));
388-
}
389-
const argValue = Blockly.Variables.generateUniqueNameFromOptions(
390-
Blockly.Procedures.DEFAULT_ARG,
391-
usedNames,
392-
);
393-
const jsonBlock = {
394-
kind: 'block',
395-
type: MUTATOR_BLOCK_NAME,
396-
fields: {
397-
NAME: argValue,
398-
},
399-
};
400-
401-
workspace.updateToolbox({ contents: [jsonBlock] });
402-
}
403-
404-
405-
/**
406-
* Listens for when a procedure mutator is opened. Then it triggers a flyout
407-
* update and adds a mutator change listener to the mutator workspace.
408-
*
409-
* @param e The event that triggered this listener.
410-
* @internal
411-
*/
412-
export function mutatorOpenListener(e: Blockly.Events.Abstract) {
413-
if (e.type != Blockly.Events.BUBBLE_OPEN) {
414-
return;
415-
}
416-
const bubbleEvent = e as Blockly.Events.BubbleOpen;
417-
if (
418-
!(bubbleEvent.bubbleType === 'mutator' && bubbleEvent.isOpen) ||
419-
!bubbleEvent.blockId
420-
) {
421-
return;
422-
}
423-
const workspaceId = bubbleEvent.workspaceId;
424-
const block = Blockly.common
425-
.getWorkspaceById(workspaceId)!
426-
.getBlockById(bubbleEvent.blockId) as Blockly.BlockSvg;
427-
428-
if (block.type !== BLOCK_NAME) {
429-
return;
430-
}
431-
const workspace = (
432-
block.getIcon(Blockly.icons.MutatorIcon.TYPE) as Blockly.icons.MutatorIcon
433-
).getWorkspace()!;
434-
435-
updateMutatorFlyout(workspace);
436-
ChangeFramework.setup(workspace);
437-
}
438-
439-
440312
export const setup = function () {
441313
Blockly.Blocks[BLOCK_NAME] = CLASS_METHOD_DEF;
442-
Blockly.Blocks[MUTATOR_BLOCK_NAME] = METHODS_MUTATORARG;
443-
Blockly.Blocks[PARAM_CONTAINER_BLOCK_NAME] = METHOD_PARAM_CONTAINER;
444314
};
445315

446316
export const pythonFromBlock = function (
@@ -486,6 +356,10 @@ export const pythonFromBlock = function (
486356
branch = generator.INDENT + 'super().__init__(' + class_specific + ')\n' +
487357
generator.defineClassVariables() + branch;
488358
}
359+
else if (funcName == 'update'){
360+
// Special case for update, to also call the update method of the base class
361+
branch = generator.INDENT + 'self.update()\n' + branch;
362+
}
489363
if (returnValue) {
490364
returnValue = generator.INDENT + 'return ' + returnValue + '\n';
491365
} else if (!branch) {

0 commit comments

Comments
 (0)