Skip to content

Commit f525fa0

Browse files
authored
In editor.ts: (#262)
Added code to onChangeAfterLoading to handle MOVE events. If the block being moved has a mrcOnMove method, call it. In mrc_event.ts: Added constants INPUT_TITLE, FIELD_PARAM_PREFIX, and WARNING_ID_NOT_IN_HOLDER. Removed call to ChangeFramework.registerCallback. Removed onBlockChanged. Added mrcHasWarning to EventMixin. Added mrcOnLoad so that the block is checked when the block is loaded. Added mrcOnMove so that the block is checked when the block is moved.
1 parent d9e16a6 commit f525fa0

File tree

6 files changed

+65
-28
lines changed

6 files changed

+65
-28
lines changed

src/blocks/mrc_event.ts

Lines changed: 46 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,6 @@ import * as Blockly from 'blockly';
2424
import { MRC_STYLE_EVENTS } from '../themes/styles'
2525
import { ExtendedPythonGenerator } from '../editor/extended_python_generator';
2626
import { MUTATOR_BLOCK_NAME, PARAM_CONTAINER_BLOCK_NAME, MethodMutatorArgBlock } from './mrc_param_container'
27-
import * as ChangeFramework from './utils/change_framework';
2827
import { BLOCK_NAME as MRC_MECHANISM_COMPONENT_HOLDER } from './mrc_mechanism_component_holder';
2928
import * as toolboxItems from '../toolbox/items';
3029
import * as storageModuleContent from '../storage/module_content';
@@ -33,13 +32,17 @@ import { renameMethodCallers, mutateMethodCallers } from './mrc_call_python_func
3332
export const BLOCK_NAME = 'mrc_event';
3433
export const OUTPUT_NAME = 'mrc_event';
3534

35+
const INPUT_TITLE = 'TITLE';
3636
const FIELD_EVENT_NAME = 'NAME';
37+
const FIELD_PARAM_PREFIX = 'PARAM_';
3738

3839
type Parameter = {
3940
name: string,
4041
type?: string,
4142
};
4243

44+
const WARNING_ID_NOT_IN_HOLDER = 'not in holder';
45+
4346
type EventExtraState = {
4447
eventId?: string,
4548
params?: Parameter[],
@@ -50,6 +53,14 @@ export type EventBlock = Blockly.Block & EventMixin & Blockly.BlockSvg;
5053
interface EventMixin extends EventMixinType {
5154
mrcEventId: string,
5255
mrcParameters: Parameter[],
56+
57+
/**
58+
* mrcHasWarning is set to true if we set the warning text on the block. It is checked to avoid
59+
* adding a warning if there already is one. Otherwise, if we get two move events (one for drag
60+
* and one for snap), and we call setWarningText for both events, we get a detached warning
61+
* balloon. See https://github.com/wpilibsuite/systemcore-blocks-interface/issues/248.
62+
*/
63+
mrcHasWarning: boolean,
5364
}
5465
type EventMixinType = typeof EVENT;
5566

@@ -59,12 +70,11 @@ const EVENT = {
5970
*/
6071
init: function (this: EventBlock): void {
6172
this.setStyle(MRC_STYLE_EVENTS);
62-
this.appendDummyInput("TITLE")
73+
this.appendDummyInput(INPUT_TITLE)
6374
.appendField(new Blockly.FieldTextInput('my_event'), FIELD_EVENT_NAME);
6475
this.setPreviousStatement(true, OUTPUT_NAME);
6576
this.setNextStatement(true, OUTPUT_NAME);
6677
this.setMutator(new Blockly.icons.MutatorIcon([MUTATOR_BLOCK_NAME], this));
67-
ChangeFramework.registerCallback(BLOCK_NAME, [Blockly.Events.BLOCK_MOVE], this.onBlockChanged);
6878
},
6979

7080
/**
@@ -91,6 +101,7 @@ const EVENT = {
91101
loadExtraState: function (this: EventBlock, extraState: EventExtraState): void {
92102
this.mrcEventId = extraState.eventId ? extraState.eventId : this.id;
93103
this.mrcParameters = [];
104+
this.mrcHasWarning = false;
94105

95106
if (extraState.params) {
96107
extraState.params.forEach((arg) => {
@@ -108,7 +119,7 @@ const EVENT = {
108119
*/
109120
updateBlock_: function (this: EventBlock): void {
110121
const name = this.getFieldValue(FIELD_EVENT_NAME);
111-
const input = this.getInput('TITLE');
122+
const input = this.getInput(INPUT_TITLE);
112123
if (!input) {
113124
return;
114125
}
@@ -136,8 +147,7 @@ const EVENT = {
136147
paramBlock.originalName = param.name;
137148
}
138149
this.mrcParameters.push(param);
139-
paramBlock =
140-
paramBlock.nextConnection && paramBlock.nextConnection.targetBlock();
150+
paramBlock = paramBlock.nextConnection && paramBlock.nextConnection.targetBlock();
141151
}
142152
this.mrcUpdateParams();
143153
mutateMethodCallers(this.workspace, this.mrcEventId, this.getEvent());
@@ -152,7 +162,7 @@ const EVENT = {
152162
let connection = topBlock!.getInput('STACK')!.connection;
153163

154164
for (let i = 0; i < this.mrcParameters.length; i++) {
155-
let itemBlock = workspace.newBlock(MUTATOR_BLOCK_NAME);
165+
const itemBlock = workspace.newBlock(MUTATOR_BLOCK_NAME);
156166
(itemBlock as Blockly.BlockSvg).initSvg();
157167
itemBlock.setFieldValue(this.mrcParameters[i].name, 'NAME');
158168
(itemBlock as MethodMutatorArgBlock).originalName = this.mrcParameters[i].name;
@@ -164,11 +174,11 @@ const EVENT = {
164174
},
165175
mrcUpdateParams: function (this: EventBlock) {
166176
if (this.mrcParameters.length > 0) {
167-
let input = this.getInput('TITLE');
177+
const input = this.getInput(INPUT_TITLE);
168178
if (input) {
169179
this.removeParameterFields(input);
170180
this.mrcParameters.forEach((param) => {
171-
const paramName = 'PARAM_' + param.name;
181+
const paramName = FIELD_PARAM_PREFIX + param.name;
172182
const field = new Blockly.FieldTextInput(param.name);
173183
field.EDITABLE = false;
174184
input.appendField(field, paramName);
@@ -178,7 +188,7 @@ const EVENT = {
178188
},
179189
removeParameterFields: function (input: Blockly.Input) {
180190
const fieldsToRemove = input.fieldRow
181-
.filter(field => field.name?.startsWith('PARAM_'))
191+
.filter(field => field.name?.startsWith(FIELD_PARAM_PREFIX))
182192
.map(field => field.name!);
183193

184194
fieldsToRemove.forEach(fieldName => {
@@ -197,21 +207,33 @@ const EVENT = {
197207
}
198208
return legalName;
199209
},
200-
onBlockChanged(block: Blockly.BlockSvg, blockEvent: Blockly.Events.BlockBase): void {
201-
const blockBlock = block as Blockly.Block;
202-
203-
if (blockEvent.type === Blockly.Events.BLOCK_MOVE) {
204-
const parent = ChangeFramework.getParentOfType(block, MRC_MECHANISM_COMPONENT_HOLDER);
205-
206-
if (parent) {
207-
// If it is, we allow it to stay.
208-
blockBlock.setWarningText(null);
209-
return;
210+
/**
211+
* mrcOnLoad is called for each EventBlock when the blocks are loaded in the blockly workspace.
212+
*/
213+
mrcOnLoad: function(this: EventBlock): void {
214+
this.checkParentIsHolder();
215+
},
216+
/**
217+
* mrcOnLoad is called when an EventBlock is moved.
218+
*/
219+
mrcOnMove: function(this: EventBlock): void {
220+
this.checkParentIsHolder();
221+
},
222+
checkParentIsHolder: function(this: EventBlock): void {
223+
const parentBlock = this.getParent();
224+
if (parentBlock && parentBlock.type === MRC_MECHANISM_COMPONENT_HOLDER) {
225+
// If the parent block is the mechanism_component_holder, the event block is allowed to stay.
226+
// Remove any previous warning.
227+
this.setWarningText(null, WARNING_ID_NOT_IN_HOLDER);
228+
this.mrcHasWarning = false;
229+
} else {
230+
// Otherwise, add a warning to the block.
231+
this.unplug(true);
232+
if (!this.mrcHasWarning) {
233+
this.setWarningText(Blockly.Msg.WARNING_EVENT_NOT_IN_HOLDER, WARNING_ID_NOT_IN_HOLDER);
234+
this.getIcon(Blockly.icons.IconType.WARNING)!.setBubbleVisible(true);
235+
this.mrcHasWarning = true;
210236
}
211-
// If we end up here it shouldn't be allowed
212-
block.unplug(true);
213-
blockBlock.setWarningText('Events can only go in the events section of the robot or mechanism');
214-
blockBlock.getIcon(Blockly.icons.IconType.WARNING)!.setBubbleVisible(true);
215237
}
216238
},
217239
getEvent: function (this: EventBlock): storageModuleContent.Event {

src/blocks/tokens.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,7 @@ export function customTokens(t: (key: string) => string): typeof Blockly.Msg {
8484
CALL_COMPONENT_INSTANCE_METHOD_TOOLTIP: t('BLOCKLY.TOOLTIP.CALL_COMPONENT_INSTANCE_METHOD'),
8585
CALL_ROBOT_INSTANCE_METHOD_TOOLTIP: t('BLOCKLY.TOOLTIP.CALL_ROBOT_INSTANCE_METHOD'),
8686
CALL_MECHANISM_INSTANCE_METHOD_TOOLTIP: t('BLOCKLY.TOOLTIP.CALL_MECHANISM_INSTANCE_METHOD'),
87+
WARNING_EVENT_NOT_IN_HOLDER: t('BLOCKLY.WARNING.EVENT_NOT_IN_HOLDER'),
8788
MRC_CATEGORY_HARDWARE: t('BLOCKLY.CATEGORY.HARDWARE'),
8889
MRC_CATEGORY_ROBOT: t('BLOCKLY.CATEGORY.ROBOT'),
8990
MRC_CATEGORY_COMPONENTS: t('BLOCKLY.CATEGORY.COMPONENTS'),

src/editor/editor.ts

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ const EMPTY_TOOLBOX: Blockly.utils.toolbox.ToolboxInfo = {
3939
};
4040

4141
const MRC_ON_LOAD = 'mrcOnLoad';
42+
const MRC_ON_MOVE = 'mrcOnMove';
4243
const MRC_VALIDATE = 'mrcValidate';
4344

4445
export class Editor {
@@ -121,7 +122,17 @@ export class Editor {
121122
if (this.blocklyWorkspace.isDragging()) {
122123
return;
123124
}
124-
// TODO(lizlooney): do we need to do anything here?
125+
126+
if (event.type === Blockly.Events.BLOCK_MOVE) {
127+
const blockMoveEvent = event as Blockly.Events.BlockMove;
128+
const block = this.blocklyWorkspace.getBlockById(blockMoveEvent.blockId!);
129+
if (!block) {
130+
return;
131+
}
132+
if (MRC_ON_MOVE in block && typeof block[MRC_ON_MOVE] === 'function') {
133+
block[MRC_ON_MOVE]();
134+
}
135+
}
125136
}
126137

127138
public makeCurrent(

src/i18n/locales/en/translation.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -141,7 +141,8 @@
141141
"CALL_ROBOT_INSTANCE_METHOD_MISSING_METHOD": "This block calls a method that no longer exists in the robot.",
142142
"CALL_MECHANISM_INSTANCE_METHOD_INSIDE_MECHANISM": "This block is not allowed to be used inside a mechanism.",
143143
"CALL_MECHANISM_INSTANCE_METHOD_MISSING_METHOD": "This block calls a method that no longer exists in the mechanism.",
144-
"CALL_MECHANISM_INSTANCE_METHOD_MISSING_MECHANISM": "This block calls a method in a mechanism that no longer exists."
144+
"CALL_MECHANISM_INSTANCE_METHOD_MISSING_MECHANISM": "This block calls a method in a mechanism that no longer exists.",
145+
"EVENT_NOT_IN_HOLDER": "This block can only go in the events section of the robot or mechanism."
145146
}
146147
}
147148
}

src/i18n/locales/es/translation.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -142,7 +142,8 @@
142142
"CALL_ROBOT_INSTANCE_METHOD_MISSING_METHOD": "Este bloque llama a un método que ya no existe en el robot.",
143143
"CALL_MECHANISM_INSTANCE_METHOD_INSIDE_MECHANISM": "No se permite utilizar este bloque dentro de un mecanismo.",
144144
"CALL_MECHANISM_INSTANCE_METHOD_MISSING_METHOD": "Este bloque llama a un método que ya no existe en el mecanismo.",
145-
"CALL_MECHANISM_INSTANCE_METHOD_MISSING_MECHANISM": "Este bloque llama a un método en un mecanismo que ya no existe."
145+
"CALL_MECHANISM_INSTANCE_METHOD_MISSING_MECHANISM": "Este bloque llama a un método en un mecanismo que ya no existe.",
146+
"EVENT_NOT_IN_HOLDER": "Este bloque solo puede ir en la sección de eventos del robot o mecanismo."
146147
}
147148
}
148149
}

src/i18n/locales/he/translation.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -141,7 +141,8 @@
141141
"CALL_ROBOT_INSTANCE_METHOD_MISSING_METHOD": "בלוק זה קורא למתודה שכבר לא קיימת ברובוט.",
142142
"CALL_MECHANISM_INSTANCE_METHOD_INSIDE_MECHANISM": "בלוק זה אינו מורשה לשימוש בתוך מנגנון.",
143143
"CALL_MECHANISM_INSTANCE_METHOD_MISSING_METHOD": "בלוק זה קורא למתודה שכבר לא קיימת במנגנון.",
144-
"CALL_MECHANISM_INSTANCE_METHOD_MISSING_MECHANISM": "בלוק זה קורא למתודה במנגנון שכבר לא קיים."
144+
"CALL_MECHANISM_INSTANCE_METHOD_MISSING_MECHANISM": "בלוק זה קורא למתודה במנגנון שכבר לא קיים.",
145+
"EVENT_NOT_IN_HOLDER": "בלוק זה יכול להיכנס רק לאזור האירועים של הרובוט או המנגנון."
145146
}
146147
}
147148
}

0 commit comments

Comments
 (0)