@@ -29,6 +29,7 @@ import { createFieldFlydown } from '../fields/field_flydown';
2929import { createFieldNonEditableText } from '../fields/FieldNonEditableText' ;
3030import { MRC_STYLE_EVENT_HANDLER } from '../themes/styles' ;
3131import * as toolboxItems from '../toolbox/items' ;
32+ import * as storageModule from '../storage/module' ;
3233import * as storageModuleContent from '../storage/module_content' ;
3334
3435export const BLOCK_NAME = 'mrc_event_handler' ;
@@ -52,22 +53,26 @@ const WARNING_ID_EVENT_CHANGED = 'event changed';
5253export type EventHandlerBlock = Blockly . Block & EventHandlerMixin & Blockly . BlockSvg ;
5354
5455interface EventHandlerMixin extends EventHandlerMixinType {
55- mrcPathOfSender : string ;
5656 mrcSenderType : SenderType ;
5757 mrcParameters : Parameter [ ] ;
5858 mrcOtherBlockId : string ,
59+ mrcMechanismBlockId : string ,
5960}
6061
6162type EventHandlerMixinType = typeof EVENT_HANDLER ;
6263
6364/** Extra state for serialising event handler blocks. */
6465export interface EventHandlerExtraState {
65- pathOfSender : string ;
6666 senderType : SenderType ;
6767 /** The parameters of the event handler. */
6868 params : Parameter [ ] ;
6969 /** The id of the mrc_event block that defines the event. */
7070 otherBlockId : string ,
71+ /**
72+ * The id of the mrc_mechanism block that adds the mechanism to the robot.
73+ * Specified only if the sender type is MECHANISM.
74+ */
75+ mechanismBlockId ?: string ,
7176}
7277
7378const EVENT_HANDLER = {
@@ -77,8 +82,8 @@ const EVENT_HANDLER = {
7782 init ( this : EventHandlerBlock ) : void {
7883 this . appendDummyInput ( 'TITLE' )
7984 . appendField ( Blockly . Msg . WHEN )
80- . appendField ( createFieldNonEditableText ( 'sender ' ) , FIELD_SENDER )
81- . appendField ( createFieldNonEditableText ( 'eventName ' ) , FIELD_EVENT_NAME ) ;
85+ . appendField ( createFieldNonEditableText ( '' ) , FIELD_SENDER )
86+ . appendField ( createFieldNonEditableText ( '' ) , FIELD_EVENT_NAME ) ;
8287 this . appendDummyInput ( 'PARAMS' )
8388 . appendField ( Blockly . Msg . WITH ) ;
8489 this . setOutput ( false ) ;
@@ -94,11 +99,13 @@ const EVENT_HANDLER = {
9499 */
95100 saveExtraState ( this : EventHandlerBlock ) : EventHandlerExtraState {
96101 const extraState : EventHandlerExtraState = {
97- pathOfSender : this . mrcPathOfSender ,
98102 senderType : this . mrcSenderType ,
99103 params : [ ] ,
100104 otherBlockId : this . mrcOtherBlockId ,
101105 } ;
106+ if ( this . mrcMechanismBlockId ) {
107+ extraState . mechanismBlockId = this . mrcMechanismBlockId ;
108+ }
102109
103110 this . mrcParameters . forEach ( ( param ) => {
104111 extraState . params . push ( {
@@ -114,10 +121,11 @@ const EVENT_HANDLER = {
114121 * Applies the given state to this block.
115122 */
116123 loadExtraState ( this : EventHandlerBlock , extraState : EventHandlerExtraState ) : void {
117- this . mrcPathOfSender = extraState . pathOfSender ;
118124 this . mrcSenderType = extraState . senderType ;
119125 this . mrcParameters = [ ] ;
120126 this . mrcOtherBlockId = extraState . otherBlockId ;
127+ this . mrcMechanismBlockId = extraState . mechanismBlockId
128+ ? extraState . mechanismBlockId : '' ;
121129
122130 extraState . params . forEach ( ( param ) => {
123131 this . mrcParameters . push ( {
@@ -158,29 +166,30 @@ const EVENT_HANDLER = {
158166 input . removeField ( fieldName ) ;
159167 } ) ;
160168 } ,
169+
170+ /**
171+ * mrcOnLoad is called for each EventHandlerBlock when the blocks are loaded in the blockly
172+ * workspace.
173+ */
161174 mrcOnLoad : function ( this : EventHandlerBlock ) : void {
162- // mrcOnLoad is called for each EventHandlerBlock when the blocks are loaded in the blockly workspace.
163175 const warnings : string [ ] = [ ] ;
164176
165- // If this block is an event handler for a robot event, check that the robot event
166- // still exists and hasn't been changed.
167- // If the robot event doesn't exist, put a visible warning on this block.
168- // If the robot event has changed, update the block if possible or put a
169- // visible warning on it .
170- if ( this . mrcSenderType === SenderType . ROBOT ) {
171- let foundRobotEvent = false ;
172- const editor = Editor . getEditorForBlocklyWorkspace ( this . workspace ) ;
173- if ( editor ) {
177+ const editor = Editor . getEditorForBlocklyWorkspace ( this . workspace ) ;
178+ if ( editor ) {
179+ if ( this . mrcSenderType === SenderType . ROBOT ) {
180+ // This block is an event handler for a robot event.
181+ // Check whether the robot event still exists and whether it has been changed .
182+ // If the robot event doesn't exist, put a visible warning on this block.
183+ // If the robot event has changed, update the block if possible or put a
184+ // visible warning on it.
185+ let foundRobotEvent = false ;
174186 const robotEvents = editor . getEventsFromRobot ( ) ;
175187 for ( const robotEvent of robotEvents ) {
176188 if ( robotEvent . blockId === this . mrcOtherBlockId ) {
177189 foundRobotEvent = true ;
178-
179- // If the event name has changed, we can fix this block.
180190 if ( this . getFieldValue ( FIELD_EVENT_NAME ) !== robotEvent . name ) {
181191 this . setFieldValue ( robotEvent . name , FIELD_EVENT_NAME ) ;
182192 }
183-
184193 this . mrcParameters = [ ] ;
185194 robotEvent . args . forEach ( arg => {
186195 this . mrcParameters . push ( {
@@ -198,6 +207,65 @@ const EVENT_HANDLER = {
198207 warnings . push ( 'This block is an event handler for an event that no longer exists.' ) ;
199208 }
200209 }
210+
211+ if ( this . mrcSenderType === SenderType . MECHANISM ) {
212+ // This block is an event handler for a mechanism event.
213+ // Check whether the mechanism still exists, whether it has been
214+ // changed, whether the event still exists, and whether the event has
215+ // been changed.
216+ // If the mechanism doesn't exist, put a visible warning on this block.
217+ // If the mechanism has changed, update the block if possible or put a
218+ // visible warning on it.
219+ // If the event doesn't exist, put a visible warning on this block.
220+ // If the event has changed, update the block if possible or put a
221+ // visible warning on it.
222+ let foundMechanism = false ;
223+ const mechanismsInRobot = editor . getMechanismsFromRobot ( ) ;
224+ for ( const mechanismInRobot of mechanismsInRobot ) {
225+ if ( mechanismInRobot . blockId === this . mrcMechanismBlockId ) {
226+ foundMechanism = true ;
227+
228+ // If the mechanism name has changed, we can handle that.
229+ if ( this . getFieldValue ( FIELD_SENDER ) !== mechanismInRobot . name ) {
230+ this . setFieldValue ( mechanismInRobot . name , FIELD_SENDER ) ;
231+ }
232+
233+ let foundMechanismEvent = false ;
234+ const mechanism = editor . getMechanism ( mechanismInRobot ) ;
235+ const mechanismEvents : storageModuleContent . Event [ ] = mechanism
236+ ? editor . getEventsFromMechanism ( mechanism ) : [ ] ;
237+ for ( const mechanismEvent of mechanismEvents ) {
238+ if ( mechanismEvent . blockId === this . mrcOtherBlockId ) {
239+ foundMechanismEvent = true ;
240+ if ( this . getFieldValue ( FIELD_EVENT_NAME ) !== mechanismEvent . name ) {
241+ this . setFieldValue ( mechanismEvent . name , FIELD_EVENT_NAME ) ;
242+ }
243+
244+ this . mrcParameters = [ ] ;
245+ mechanismEvent . args . forEach ( arg => {
246+ this . mrcParameters . push ( {
247+ name : arg . name ,
248+ type : arg . type ,
249+ } ) ;
250+ } ) ;
251+ this . mrcUpdateParams ( ) ;
252+
253+ // Since we found the mechanism event, we can break out of the loop.
254+ break ;
255+ }
256+ }
257+ if ( ! foundMechanismEvent ) {
258+ warnings . push ( 'This block is an event handler for an event that no longer exists.' ) ;
259+ }
260+
261+ // Since we found the mechanism, we can break out of the loop.
262+ break ;
263+ }
264+ }
265+ if ( ! foundMechanism ) {
266+ warnings . push ( 'This block is an event handler for an event in a mechanism that no longer exists.' ) ;
267+ }
268+ }
201269 }
202270
203271 if ( warnings . length ) {
@@ -211,6 +279,16 @@ const EVENT_HANDLER = {
211279 this . setWarningText ( null , WARNING_ID_EVENT_CHANGED ) ;
212280 }
213281 } ,
282+ getEventBlockId : function ( this : EventHandlerBlock ) : string {
283+ return this . mrcOtherBlockId ;
284+ } ,
285+ renameMechanismName : function ( this : EventHandlerBlock , mechanismBlockId : string , newName : string ) : void {
286+ // renameMechanismName is called when a mechanism block in the same module is modified.
287+ if ( this . mrcSenderType === SenderType . MECHANISM &&
288+ mechanismBlockId === this . mrcMechanismBlockId ) {
289+ this . setFieldValue ( newName , FIELD_SENDER ) ;
290+ }
291+ } ,
214292} ;
215293
216294export function setup ( ) : void {
@@ -282,11 +360,37 @@ export function pythonFromBlock(
282360 code = generator . scrub_ ( block , code ) ;
283361
284362 generator . addClassMethodDefinition ( funcName , code ) ;
285- generator . addEventHandler ( sender , eventName , funcName ) ;
363+ generateRegisterEventHandler ( block , generator , sender , eventName , funcName ) ;
286364
287365 return '' ;
288366}
289367
368+ function generateRegisterEventHandler (
369+ block : EventHandlerBlock ,
370+ generator : ExtendedPythonGenerator ,
371+ sender : string ,
372+ eventName : string ,
373+ funcName : string ) {
374+ // Create the line of code that will register this event handler.
375+ let fullSender = '' ;
376+ if ( block . mrcSenderType === SenderType . ROBOT ) {
377+ fullSender = 'self.' + sender ;
378+ } else if ( block . mrcSenderType === SenderType . MECHANISM ) {
379+ switch ( generator . getModuleType ( ) ) {
380+ case storageModule . MODULE_TYPE_ROBOT :
381+ fullSender = 'self.' + sender ;
382+ break ;
383+ case storageModule . MODULE_TYPE_OPMODE :
384+ fullSender = 'self.robot.' + sender ;
385+ break ;
386+ }
387+ }
388+ if ( fullSender ) {
389+ generator . addRegisterEventHandlerStatement (
390+ fullSender + '.register_event_handler("' + eventName + '", self.' + funcName + ')\n' ) ;
391+ }
392+ }
393+
290394// Functions used for creating blocks for the toolbox.
291395
292396export function addRobotEventHandlerBlocks (
@@ -298,10 +402,8 @@ export function addRobotEventHandlerBlocks(
298402}
299403
300404function createRobotEventHandlerBlock (
301- event : storageModuleContent . Event ) : toolboxItems . Block {
405+ event : storageModuleContent . Event ) : toolboxItems . Block {
302406 const extraState : EventHandlerExtraState = {
303- // TODO(lizlooney): ask Alan what pathOfSender is for.
304- pathOfSender : '' ,
305407 senderType : SenderType . ROBOT ,
306408 params : [ ] ,
307409 otherBlockId : event . blockId ,
@@ -319,6 +421,37 @@ function createRobotEventHandlerBlock(
319421 return new toolboxItems . Block ( BLOCK_NAME , extraState , fields , Object . keys ( inputs ) . length ? inputs : null ) ;
320422}
321423
424+ export function addMechanismEventHandlerBlocks (
425+ mechanismInRobot : storageModuleContent . MechanismInRobot ,
426+ events : storageModuleContent . Event [ ] ,
427+ contents : toolboxItems . ContentsType [ ] ) {
428+ events . forEach ( event => {
429+ contents . push ( createMechanismEventHandlerBlock ( mechanismInRobot , event ) ) ;
430+ } ) ;
431+ }
432+
433+ function createMechanismEventHandlerBlock (
434+ mechanismInRobot : storageModuleContent . MechanismInRobot ,
435+ event : storageModuleContent . Event ) : toolboxItems . Block {
436+ const extraState : EventHandlerExtraState = {
437+ senderType : SenderType . MECHANISM ,
438+ params : [ ] ,
439+ otherBlockId : event . blockId ,
440+ mechanismBlockId : mechanismInRobot . blockId ,
441+ } ;
442+ event . args . forEach ( arg => {
443+ extraState . params . push ( {
444+ name : arg . name ,
445+ type : arg . type ,
446+ } ) ;
447+ } ) ;
448+ const fields : { [ key : string ] : any } = { } ;
449+ fields [ FIELD_SENDER ] = mechanismInRobot . name ;
450+ fields [ FIELD_EVENT_NAME ] = event . name ;
451+ const inputs : { [ key : string ] : any } = { } ;
452+ return new toolboxItems . Block ( BLOCK_NAME , extraState , fields , Object . keys ( inputs ) . length ? inputs : null ) ;
453+ }
454+
322455// Misc
323456
324457export function getHasAnyEnabledEventHandlers ( workspace : Blockly . Workspace ) : boolean {
@@ -327,10 +460,35 @@ export function getHasAnyEnabledEventHandlers(workspace: Blockly.Workspace): boo
327460 } ) . length > 0 ;
328461}
329462
330- export function getEventHandlerNames ( workspace : Blockly . Workspace , names : string [ ] ) : void {
331- // Here we collect the event names of the event handlers in the given
332- // workspace, regardless of whether the event handler is enabled.
463+ export function getRobotEventHandlerBlocks (
464+ workspace : Blockly . Workspace ,
465+ blocks : EventHandlerBlock [ ] ) : void {
333466 workspace . getBlocksByType ( BLOCK_NAME ) . forEach ( block => {
334- names . push ( block . getFieldValue ( FIELD_EVENT_NAME ) ) ;
467+ const eventHandlerBlock = block as EventHandlerBlock ;
468+ if ( eventHandlerBlock . mrcSenderType == SenderType . ROBOT ) {
469+ blocks . push ( eventHandlerBlock ) ;
470+ }
471+ } ) ;
472+ }
473+
474+ export function getMechanismEventHandlerBlocks (
475+ workspace : Blockly . Workspace ,
476+ mechanismBlockId : string ,
477+ blocks : EventHandlerBlock [ ] ) : void {
478+ workspace . getBlocksByType ( BLOCK_NAME ) . forEach ( block => {
479+ const eventHandlerBlock = block as EventHandlerBlock ;
480+ if ( eventHandlerBlock . mrcSenderType == SenderType . MECHANISM ) {
481+ if ( eventHandlerBlock . mrcMechanismBlockId === mechanismBlockId ) {
482+ blocks . push ( eventHandlerBlock ) ;
483+ }
484+ }
485+ } ) ;
486+ }
487+
488+ export function renameMechanismName ( workspace : Blockly . Workspace , mechanismBlockId : string , newName : string ) : void {
489+ const eventHandlerBlocks : EventHandlerBlock [ ] = [ ] ;
490+ getMechanismEventHandlerBlocks ( workspace , mechanismBlockId , eventHandlerBlocks ) ;
491+ eventHandlerBlocks . forEach ( block => {
492+ ( block as EventHandlerBlock ) . renameMechanismName ( mechanismBlockId , newName ) ;
335493 } ) ;
336494}
0 commit comments