1919 * @fileoverview Blocks for event handlers
2020 * @author [email protected] (Alan Smith) 2121 */
22+
2223import * as Blockly from 'blockly' ;
23- import { MRC_STYLE_EVENT_HANDLER } from '../themes/styles' ;
24- import { createFieldNonEditableText } from '../fields/FieldNonEditableText'
25- import { createFieldFlydown } from '../fields/field_flydown' ;
26- import { Order } from 'blockly/python' ;
27- import { ExtendedPythonGenerator } from '../editor/extended_python_generator' ;
24+ import { Order } from 'blockly/python' ;
25+
26+ import { ExtendedPythonGenerator } from '../editor/extended_python_generator' ;
27+ import { createFieldFlydown } from '../fields/field_flydown' ;
28+ import { createFieldNonEditableText } from '../fields/FieldNonEditableText' ;
29+ import { MRC_STYLE_EVENT_HANDLER } from '../themes/styles' ;
2830
2931export const BLOCK_NAME = 'mrc_event_handler' ;
3032
3133export enum SenderType {
32- ROBOT = 'robot' ,
33- MECHANISM = 'mechanism' ,
34- COMPONENT = 'component'
34+ ROBOT = 'robot' ,
35+ MECHANISM = 'mechanism' ,
36+ COMPONENT = 'component'
3537}
3638
37- export type Parameter = {
38- name : string ,
39- type ?: string ,
40- } ;
39+ export interface Parameter {
40+ name : string ;
41+ type ?: string ;
42+ }
4143
4244export type EventHandlerBlock = Blockly . Block & EventHandlerMixin & Blockly . BlockSvg ;
45+
4346interface EventHandlerMixin extends EventHandlerMixinType {
44- mrcPathOfSender : string ,
45- mrcTypeOfSender : SenderType ,
46- mrcParameters : Parameter [ ] ,
47+ mrcPathOfSender : string ;
48+ mrcTypeOfSender : SenderType ;
49+ mrcParameters : Parameter [ ] ;
4750}
48- type EventHandlerMixinType = typeof EVENT_HANDLER ;
49-
5051
51- /** Extra state for serialising call_python_* blocks. */
52- export type EventHandlerExtraState = {
53- pathOfSender : string ,
54- typeOfSender : SenderType ,
52+ type EventHandlerMixinType = typeof EVENT_HANDLER ;
5553
56- /** The parameters of the event handler. */
57- params : Parameter [ ] ,
58- } ;
54+ /** Extra state for serialising event handler blocks. */
55+ export interface EventHandlerExtraState {
56+ pathOfSender : string ;
57+ typeOfSender : SenderType ;
58+ /** The parameters of the event handler. */
59+ params : Parameter [ ] ;
60+ }
5961
6062const EVENT_HANDLER = {
61- /**
62- * Block initialization.
63- */
64- init : function ( this : EventHandlerBlock ) : void {
65- this . appendDummyInput ( "TITLE" )
66- . appendField ( 'When' )
67- . appendField ( createFieldNonEditableText ( 'sender' ) , 'SENDER' )
68- . appendField ( createFieldNonEditableText ( 'eventName' ) , 'EVENT_NAME' ) ;
69- this . appendDummyInput ( 'PARAMS' )
70- . appendField ( 'with' )
71- this . setOutput ( false ) ;
72- this . setStyle ( MRC_STYLE_EVENT_HANDLER ) ;
73- this . appendStatementInput ( 'STACK' ) . appendField ( '' ) ;
74- this . mrcParameters = [ ] ;
75- this . setPreviousStatement ( false ) ;
76- this . setNextStatement ( false ) ;
77- } ,
78- /**
79- * Returns the state of this block as a JSON serializable object.
80- */
81- saveExtraState : function (
82- this : EventHandlerBlock ) : EventHandlerExtraState {
83- const extraState : EventHandlerExtraState = {
84- pathOfSender : this . mrcPathOfSender ,
85- typeOfSender : this . mrcTypeOfSender ,
86- params : [ ] ,
87- } ;
63+ /**
64+ * Block initialization.
65+ */
66+ init ( this : EventHandlerBlock ) : void {
67+ this . appendDummyInput ( 'TITLE' )
68+ . appendField ( 'When' )
69+ . appendField ( createFieldNonEditableText ( 'sender' ) , 'SENDER' )
70+ . appendField ( createFieldNonEditableText ( 'eventName' ) , 'EVENT_NAME' ) ;
71+ this . appendDummyInput ( 'PARAMS' )
72+ . appendField ( 'with' ) ;
73+ this . setOutput ( false ) ;
74+ this . setStyle ( MRC_STYLE_EVENT_HANDLER ) ;
75+ this . appendStatementInput ( 'STACK' ) . appendField ( '' ) ;
76+ this . mrcParameters = [ ] ;
77+ this . setPreviousStatement ( false ) ;
78+ this . setNextStatement ( false ) ;
79+ } ,
80+
81+ /**
82+ * Returns the state of this block as a JSON serializable object.
83+ */
84+ saveExtraState ( this : EventHandlerBlock ) : EventHandlerExtraState {
85+ const extraState : EventHandlerExtraState = {
86+ pathOfSender : this . mrcPathOfSender ,
87+ typeOfSender : this . mrcTypeOfSender ,
88+ params : [ ] ,
89+ } ;
90+
91+ this . mrcParameters . forEach ( ( param ) => {
92+ extraState . params . push ( {
93+ name : param . name ,
94+ type : param . type ,
95+ } ) ;
96+ } ) ;
97+
98+ return extraState ;
99+ } ,
100+
101+ /**
102+ * Applies the given state to this block.
103+ */
104+ loadExtraState ( this : EventHandlerBlock , extraState : EventHandlerExtraState ) : void {
105+ this . mrcParameters = [ ] ;
106+ this . mrcPathOfSender = extraState . pathOfSender ;
107+ this . mrcTypeOfSender = extraState . typeOfSender ;
108+
109+ extraState . params . forEach ( ( param ) => {
110+ this . mrcParameters . push ( {
111+ name : param . name ,
112+ type : param . type ,
113+ } ) ;
114+ } ) ;
115+ this . mrcUpdateParams ( ) ;
116+ } ,
117+
118+ /**
119+ * Update the block to reflect the newly loaded extra state.
120+ */
121+ mrcUpdateParams ( this : EventHandlerBlock ) : void {
122+ if ( this . mrcParameters . length > 0 ) {
123+ const input = this . getInput ( 'PARAMS' ) ;
124+ if ( input ) {
125+ this . removeParameterFields ( input ) ;
88126 this . mrcParameters . forEach ( ( param ) => {
89- extraState . params . push ( {
90- 'name' : param . name ,
91- 'type' : param . type ,
92- } ) ;
93- } ) ;
94-
95- return extraState ;
96- } ,
97- /**
98- * Applies the given state to this block.
99- */
100- loadExtraState : function (
101- this : EventHandlerBlock ,
102- extraState : EventHandlerExtraState
103- ) : void {
104- this . mrcParameters = [ ] ;
105- this . mrcPathOfSender = extraState . pathOfSender ;
106- this . mrcTypeOfSender = extraState . typeOfSender ;
107-
108- extraState . params . forEach ( ( param ) => {
109- this . mrcParameters . push ( {
110- 'name' : param . name ,
111- 'type' : param . type ,
112- } ) ;
113- } ) ;
114- this . mrcUpdateParams ( ) ;
115- } ,
116- /**
117- * Update the block to reflect the newly loaded extra state.
118- */
119- mrcUpdateParams : function ( this : EventHandlerBlock ) {
120- if ( this . mrcParameters . length > 0 ) {
121- let input = this . getInput ( 'PARAMS' ) ;
122- if ( input ) {
123- this . removeParameterFields ( input ) ;
124- this . mrcParameters . forEach ( ( param ) => {
125- const paramName = 'PARAM_' + param . name ;
126- input . appendField ( createFieldFlydown ( param . name , false ) , paramName ) ;
127- } ) ;
128- }
129- } else {
130- this . removeInput ( 'PARAMS' , true ) ;
131- }
132- } ,
133- removeParameterFields : function ( input : Blockly . Input ) {
134- const fieldsToRemove = input . fieldRow
135- . filter ( field => field . name ?. startsWith ( 'PARAM_' ) )
136- . map ( field => field . name ! ) ;
137-
138- fieldsToRemove . forEach ( fieldName => {
139- input . removeField ( fieldName ) ;
127+ const paramName = `PARAM_${ param . name } ` ;
128+ input . appendField ( createFieldFlydown ( param . name , false ) , paramName ) ;
140129 } ) ;
141- } ,
142-
130+ }
131+ } else {
132+ this . removeInput ( 'PARAMS' , true ) ;
133+ }
134+ } ,
135+
136+ /**
137+ * Removes parameter fields from the given input.
138+ */
139+ removeParameterFields ( input : Blockly . Input ) : void {
140+ const fieldsToRemove = input . fieldRow
141+ . filter ( field => field . name ?. startsWith ( 'PARAM_' ) )
142+ . map ( field => field . name ! ) ;
143+
144+ fieldsToRemove . forEach ( fieldName => {
145+ input . removeField ( fieldName ) ;
146+ } ) ;
147+ } ,
143148} ;
144149
150+ export function setup ( ) : void {
151+ Blockly . Blocks [ BLOCK_NAME ] = EVENT_HANDLER ;
152+ }
145153
146- export const setup = function ( ) {
147- Blockly . Blocks [ BLOCK_NAME ] = EVENT_HANDLER ;
148- } ;
149-
150- export const pythonFromBlock = function (
154+ export function pythonFromBlock (
151155 block : EventHandlerBlock ,
152156 generator : ExtendedPythonGenerator ,
153- ) {
154- const blocklyName = block . getFieldValue ( 'SENDER' ) + '_' + block . getFieldValue ( 'EVENT_NAME' ) ;
155-
156- const funcName = generator . getProcedureName ( blocklyName ) ;
157-
158- let xfix1 = '' ;
159- if ( generator . STATEMENT_PREFIX ) {
160- xfix1 += generator . injectId ( generator . STATEMENT_PREFIX , block ) ;
161- }
162- if ( generator . STATEMENT_SUFFIX ) {
163- xfix1 += generator . injectId ( generator . STATEMENT_SUFFIX , block ) ;
164- }
165- if ( xfix1 ) {
166- xfix1 = generator . prefixLines ( xfix1 , generator . INDENT ) ;
167- }
168- let loopTrap = '' ;
169- if ( generator . INFINITE_LOOP_TRAP ) {
170- loopTrap = generator . prefixLines (
171- generator . injectId ( generator . INFINITE_LOOP_TRAP , block ) ,
172- generator . INDENT ,
173- ) ;
174- }
175- let branch = '' ;
176- if ( block . getInput ( 'STACK' ) ) {
177- branch = generator . statementToCode ( block , 'STACK' ) ;
178- }
179- let returnValue = '' ;
180- if ( block . getInput ( 'RETURN' ) ) {
181- returnValue = generator . valueToCode ( block , 'RETURN' , Order . NONE ) || '' ;
182- }
183- let xfix2 = '' ;
184- if ( branch && returnValue ) {
185- // After executing the function body, revisit this block for the return.
186- xfix2 = xfix1 ;
187- }
188-
189- if ( returnValue ) {
190- returnValue = generator . INDENT + 'return ' + returnValue + '\n' ;
191- } else if ( ! branch ) {
192- branch = generator . PASS ;
193- }
194-
195- let params = block . mrcParameters ;
196- let paramString = "self" ;
197-
198- if ( params . length != 0 ) {
199- block . mrcParameters . forEach ( ( param ) => {
200- paramString += ', ' + param . name ;
201- } ) ;
202- }
203-
204- let code = 'def ' +
205- funcName +
206- '(' +
207- paramString +
208- '):\n' ;
209-
210- code +=
211- xfix1 +
212- loopTrap +
213- branch +
214- xfix2 +
215- returnValue ;
216- code = generator . scrub_ ( block , code ) ;
217- generator . addClassMethodDefinition ( funcName , code ) ;
218- generator . addEventHandler (
219- block . getFieldValue ( 'SENDER' ) ,
220- block . getFieldValue ( 'EVENT_NAME' ) ,
221- funcName ) ;
222-
223- return ''
157+ ) : string {
158+ const blocklyName = `${ block . getFieldValue ( 'SENDER' ) } _${ block . getFieldValue ( 'EVENT_NAME' ) } ` ;
159+ const funcName = generator . getProcedureName ( blocklyName ) ;
160+
161+ let xfix1 = '' ;
162+ if ( generator . STATEMENT_PREFIX ) {
163+ xfix1 += generator . injectId ( generator . STATEMENT_PREFIX , block ) ;
164+ }
165+ if ( generator . STATEMENT_SUFFIX ) {
166+ xfix1 += generator . injectId ( generator . STATEMENT_SUFFIX , block ) ;
167+ }
168+ if ( xfix1 ) {
169+ xfix1 = generator . prefixLines ( xfix1 , generator . INDENT ) ;
170+ }
171+
172+ let loopTrap = '' ;
173+ if ( generator . INFINITE_LOOP_TRAP ) {
174+ loopTrap = generator . prefixLines (
175+ generator . injectId ( generator . INFINITE_LOOP_TRAP , block ) ,
176+ generator . INDENT ,
177+ ) ;
178+ }
179+
180+ let branch = '' ;
181+ if ( block . getInput ( 'STACK' ) ) {
182+ branch = generator . statementToCode ( block , 'STACK' ) ;
183+ }
184+
185+ let returnValue = '' ;
186+ if ( block . getInput ( 'RETURN' ) ) {
187+ returnValue = generator . valueToCode ( block , 'RETURN' , Order . NONE ) || '' ;
188+ }
189+
190+ let xfix2 = '' ;
191+ if ( branch && returnValue ) {
192+ // After executing the function body, revisit this block for the return.
193+ xfix2 = xfix1 ;
194+ }
195+
196+ if ( returnValue ) {
197+ returnValue = `${ generator . INDENT } return ${ returnValue } \n` ;
198+ } else if ( ! branch ) {
199+ branch = generator . PASS ;
200+ }
201+
202+ const params = block . mrcParameters ;
203+ let paramString = 'self' ;
204+
205+ if ( params . length !== 0 ) {
206+ block . mrcParameters . forEach ( ( param ) => {
207+ paramString += `, ${ param . name } ` ;
208+ } ) ;
209+ }
210+
211+ let code = `def ${ funcName } (${ paramString } ):\n` ;
212+ code += xfix1 + loopTrap + branch + xfix2 + returnValue ;
213+ code = generator . scrub_ ( block , code ) ;
214+
215+ generator . addClassMethodDefinition ( funcName , code ) ;
216+ generator . addEventHandler (
217+ block . getFieldValue ( 'SENDER' ) ,
218+ block . getFieldValue ( 'EVENT_NAME' ) ,
219+ funcName ) ;
220+
221+ return '' ;
224222}
0 commit comments