Skip to content

Commit d165af6

Browse files
committed
Add private components to mechanism
1 parent fb75c57 commit d165af6

File tree

8 files changed

+167
-7
lines changed

8 files changed

+167
-7
lines changed

src/blocks/mrc_mechanism.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -206,7 +206,7 @@ const MECHANISM = {
206206

207207
if (foundMechanism) {
208208
const components: storageModuleContent.Component[] = [];
209-
components.push(...editor.getComponentsFromMechanism(foundMechanism));
209+
components.push(...editor.getAllComponentsFromMechanism(foundMechanism));
210210

211211
// If the mechanism class name has changed, update this blcok.
212212
if (this.getFieldValue(FIELD_TYPE) !== foundMechanism.className) {

src/blocks/mrc_mechanism_component_holder.ts

Lines changed: 98 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ import { MRC_STYLE_MECHANISMS } from '../themes/styles';
2525
import * as ChangeFramework from './utils/change_framework';
2626
import { getLegalName } from './utils/python';
2727
import { ExtendedPythonGenerator } from '../editor/extended_python_generator';
28+
import { Editor } from '../editor/editor';
2829
import * as storageModule from '../storage/module';
2930
import * as storageModuleContent from '../storage/module_content';
3031
import { BLOCK_NAME as MRC_MECHANISM_NAME } from './mrc_mechanism';
@@ -41,17 +42,20 @@ export const BLOCK_NAME = 'mrc_mechanism_component_holder';
4142

4243
const INPUT_MECHANISMS = 'MECHANISMS';
4344
const INPUT_COMPONENTS = 'COMPONENTS';
45+
const INPUT_PRIVATE_COMPONENTS = 'PRIVATE_COMPONENTS';
4446
const INPUT_EVENTS = 'EVENTS';
4547

4648
export const TOOLBOX_UPDATE_EVENT = 'toolbox-update-requested';
4749

4850
type MechanismComponentHolderExtraState = {
4951
hideMechanisms?: boolean;
52+
hidePrivateComponents?: boolean;
5053
}
5154

5255
export type MechanismComponentHolderBlock = Blockly.Block & MechanismComponentHolderMixin;
5356
interface MechanismComponentHolderMixin extends MechanismComponentHolderMixinType {
5457
mrcHideMechanisms: boolean;
58+
mrcHidePrivateComponents: boolean;
5559
}
5660
type MechanismComponentHolderMixinType = typeof MECHANISM_COMPONENT_HOLDER;
5761

@@ -78,9 +82,9 @@ const MECHANISM_COMPONENT_HOLDER = {
7882
this.setInputsInline(false);
7983
this.appendStatementInput(INPUT_MECHANISMS).setCheck(MECHANISM_OUTPUT).appendField(Blockly.Msg.MECHANISMS);
8084
this.appendStatementInput(INPUT_COMPONENTS).setCheck(COMPONENT_OUTPUT).appendField(Blockly.Msg.COMPONENTS);
85+
this.appendStatementInput(INPUT_PRIVATE_COMPONENTS).setCheck(COMPONENT_OUTPUT).appendField(Blockly.Msg.PRIVATE_COMPONENTS);
8186
this.appendStatementInput(INPUT_EVENTS).setCheck(EVENT_OUTPUT).appendField(Blockly.Msg.EVENTS);
8287

83-
8488
this.setOutput(false);
8589
this.setStyle(MRC_STYLE_MECHANISMS);
8690
ChangeFramework.registerCallback(MRC_COMPONENT_NAME, [Blockly.Events.BLOCK_MOVE, Blockly.Events.BLOCK_CHANGE], this.onBlockChanged);
@@ -95,30 +99,48 @@ const MECHANISM_COMPONENT_HOLDER = {
9599
if (this.mrcHideMechanisms == true) {
96100
extraState.hideMechanisms = this.mrcHideMechanisms;
97101
}
102+
if (this.mrcHidePrivateComponents == true) {
103+
extraState.hidePrivateComponents = this.mrcHidePrivateComponents;
104+
}
98105
return extraState;
99106
},
100107
/**
101108
* Applies the given state to this block.
102109
*/
103110
loadExtraState: function (this: MechanismComponentHolderBlock, extraState: MechanismComponentHolderExtraState): void {
104111
this.mrcHideMechanisms = (extraState.hideMechanisms == undefined) ? false : extraState.hideMechanisms;
112+
this.mrcHidePrivateComponents = (extraState.hidePrivateComponents == undefined) ? false : extraState.hidePrivateComponents;
105113
this.updateBlock_();
106114
},
107115
/**
108116
* Update the block to reflect the newly loaded extra state.
109117
*/
110118
updateBlock_: function (this: MechanismComponentHolderBlock): void {
119+
// Handle mechanisms input visibility
111120
if (this.mrcHideMechanisms) {
112121
if (this.getInput(INPUT_MECHANISMS)) {
113122
this.removeInput(INPUT_MECHANISMS)
114123
}
115124
}
116125
else {
117126
if (this.getInput(INPUT_MECHANISMS) == null) {
118-
this.appendStatementInput(INPUT_MECHANISMS).setCheck(MECHANISM_OUTPUT).appendField('Mechanisms');
127+
this.appendStatementInput(INPUT_MECHANISMS).setCheck(MECHANISM_OUTPUT).appendField(Blockly.Msg.MECHANISMS);
119128
this.moveInputBefore(INPUT_MECHANISMS, INPUT_COMPONENTS)
120129
}
121130
}
131+
132+
// Handle private components input visibility
133+
if (this.mrcHidePrivateComponents) {
134+
if (this.getInput(INPUT_PRIVATE_COMPONENTS)) {
135+
this.removeInput(INPUT_PRIVATE_COMPONENTS)
136+
}
137+
}
138+
else {
139+
if (this.getInput(INPUT_PRIVATE_COMPONENTS) == null) {
140+
this.appendStatementInput(INPUT_PRIVATE_COMPONENTS).setCheck(COMPONENT_OUTPUT).appendField(Blockly.Msg.PRIVATE_COMPONENTS);
141+
this.moveInputBefore(INPUT_PRIVATE_COMPONENTS, INPUT_EVENTS)
142+
}
143+
}
122144
},
123145
onBlockChanged: function (block: Blockly.BlockSvg, blockEvent: Blockly.Events.BlockBase) {
124146
if (blockEvent.type == Blockly.Events.BLOCK_MOVE) {
@@ -179,6 +201,28 @@ const MECHANISM_COMPONENT_HOLDER = {
179201

180202
return components;
181203
},
204+
getPrivateComponents: function (this: MechanismComponentHolderBlock): storageModuleContent.Component[] {
205+
const components: storageModuleContent.Component[] = []
206+
207+
// Get component blocks from the PRIVATE_COMPONENTS input
208+
const privateComponentsInput = this.getInput(INPUT_PRIVATE_COMPONENTS);
209+
if (privateComponentsInput && privateComponentsInput.connection) {
210+
// Walk through all connected component blocks.
211+
let componentBlock = privateComponentsInput.connection.targetBlock();
212+
while (componentBlock) {
213+
if (componentBlock.type === MRC_COMPONENT_NAME) {
214+
const component = (componentBlock as ComponentBlock).getComponent();
215+
if (component) {
216+
components.push(component);
217+
}
218+
}
219+
// Move to the next block in the chain
220+
componentBlock = componentBlock.getNextBlock();
221+
}
222+
}
223+
224+
return components;
225+
},
182226
getEvents: function (this: MechanismComponentHolderBlock): storageModuleContent.Event[] {
183227
const events: storageModuleContent.Event[] = []
184228

@@ -243,9 +287,11 @@ function pythonFromBlockInMechanism(block: MechanismComponentHolderBlock, genera
243287
code += '):\n';
244288

245289
const components = generator.statementToCode(block, INPUT_COMPONENTS);
290+
const privateComponents = generator.statementToCode(block, INPUT_PRIVATE_COMPONENTS);
246291

247-
if (components) {
248-
code += components;
292+
const body = components + privateComponents;
293+
if (body) {
294+
code += body;
249295
generator.addClassMethodDefinition('define_hardware', code);
250296
}
251297
}
@@ -272,6 +318,7 @@ export const pythonFromBlock = function (
272318
*/
273319
export function hasAnyComponents(workspace: Blockly.Workspace): boolean {
274320
for (const block of workspace.getBlocksByType(BLOCK_NAME)) {
321+
// Check regular components
275322
const componentsInput = block.getInput(INPUT_COMPONENTS);
276323
if (componentsInput && componentsInput.connection) {
277324
// Walk through all connected component blocks.
@@ -284,6 +331,20 @@ export function hasAnyComponents(workspace: Blockly.Workspace): boolean {
284331
componentBlock = componentBlock.getNextBlock();
285332
}
286333
}
334+
335+
// Check private components
336+
const privateComponentsInput = block.getInput(INPUT_PRIVATE_COMPONENTS);
337+
if (privateComponentsInput && privateComponentsInput.connection) {
338+
// Walk through all connected private component blocks.
339+
let componentBlock = privateComponentsInput.connection.targetBlock();
340+
while (componentBlock) {
341+
if (componentBlock.type === MRC_COMPONENT_NAME && componentBlock.isEnabled()) {
342+
return true;
343+
}
344+
// Move to the next block in the chain
345+
componentBlock = componentBlock.getNextBlock();
346+
}
347+
}
287348
}
288349
return false;
289350
}
@@ -305,6 +366,20 @@ export function getComponentPorts(workspace: Blockly.Workspace, ports: {[key: st
305366
componentBlock = componentBlock.getNextBlock();
306367
}
307368
}
369+
370+
// Also include private components for port collection
371+
const privateComponentsInput = block.getInput(INPUT_PRIVATE_COMPONENTS);
372+
if (privateComponentsInput && privateComponentsInput.connection) {
373+
// Walk through all connected private component blocks.
374+
let componentBlock = privateComponentsInput.connection.targetBlock();
375+
while (componentBlock) {
376+
if (componentBlock.type === MRC_COMPONENT_NAME && componentBlock.isEnabled()) {
377+
(componentBlock as ComponentBlock).getComponentPorts(ports);
378+
}
379+
// Move to the next block in the chain
380+
componentBlock = componentBlock.getNextBlock();
381+
}
382+
}
308383
});
309384
}
310385

@@ -330,6 +405,25 @@ export function getComponents(
330405
});
331406
}
332407

408+
export function getPrivateComponents(
409+
workspace: Blockly.Workspace,
410+
components: storageModuleContent.Component[]): void {
411+
// Get the holder block and ask it for the private components.
412+
workspace.getBlocksByType(BLOCK_NAME).forEach(block => {
413+
const privateComponentsFromHolder: storageModuleContent.Component[] =
414+
(block as MechanismComponentHolderBlock).getPrivateComponents();
415+
components.push(...privateComponentsFromHolder);
416+
});
417+
}
418+
419+
export function getAllComponents(
420+
workspace: Blockly.Workspace,
421+
components: storageModuleContent.Component[]): void {
422+
// Get both regular and private components for when creating a mechanism
423+
getComponents(workspace, components);
424+
getPrivateComponents(workspace, components);
425+
}
426+
333427
export function getEvents(
334428
workspace: Blockly.Workspace,
335429
events: storageModuleContent.Event[]): void {

src/blocks/tokens.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ export function customTokens(t: (key: string) => string): typeof Blockly.Msg {
3838
MECHANISMS: t('MECHANISMS'),
3939
OPMODES: t('OPMODES'),
4040
COMPONENTS: t('BLOCKLY.COMPONENTS'),
41+
PRIVATE_COMPONENTS: t('BLOCKLY.PRIVATE_COMPONENTS'),
4142
EVENTS: t('BLOCKLY.EVENTS'),
4243
EVALUATE_BUT_IGNORE_RESULT: t('BLOCKLY.EVALUATE_BUT_IGNORE_RESULT'),
4344
EVALUATE_BUT_IGNORE_RESULT_TOOLTIP:

src/editor/editor.ts

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -273,6 +273,15 @@ export class Editor {
273273
return components;
274274
}
275275

276+
public getAllComponentsFromWorkspace(): storageModuleContent.Component[] {
277+
const components: storageModuleContent.Component[] = [];
278+
if (this.currentModule?.moduleType === storageModule.ModuleType.ROBOT ||
279+
this.currentModule?.moduleType === storageModule.ModuleType.MECHANISM) {
280+
mechanismComponentHolder.getAllComponents(this.blocklyWorkspace, components);
281+
}
282+
return components;
283+
}
284+
276285
public getMethodsForWithinFromWorkspace(): storageModuleContent.Method[] {
277286
const methods: storageModuleContent.Method[] = [];
278287
classMethodDef.getMethodsForWithin(this.blocklyWorkspace, methods);
@@ -415,6 +424,37 @@ export class Editor {
415424
throw new Error('getComponentsFromMechanism: mechanism not found: ' + mechanism.className);
416425
}
417426

427+
/**
428+
* Returns ALL components (including private components) defined in the given mechanism.
429+
* This is used when creating mechanism blocks that need all components for port parameters.
430+
*/
431+
public getAllComponentsFromMechanism(mechanism: storageModule.Mechanism): storageModuleContent.Component[] {
432+
if (this.currentModule?.modulePath === mechanism.modulePath) {
433+
return this.getAllComponentsFromWorkspace();
434+
}
435+
if (mechanism.className in this.mechanismClassNameToModuleContent) {
436+
// For saved mechanisms, we need to reconstruct all components from the blocks
437+
// since only public components are saved in the module content
438+
const moduleContent = this.mechanismClassNameToModuleContent[mechanism.className];
439+
const blocks = moduleContent.getBlocks();
440+
441+
// Create a temporary workspace to load the mechanism's blocks
442+
const tempWorkspace = new Blockly.Workspace();
443+
try {
444+
Blockly.serialization.workspaces.load(blocks, tempWorkspace);
445+
446+
// Extract all components (public and private) from the temporary workspace
447+
const allComponents: storageModuleContent.Component[] = [];
448+
mechanismComponentHolder.getAllComponents(tempWorkspace, allComponents);
449+
450+
return allComponents;
451+
} finally {
452+
tempWorkspace.dispose();
453+
}
454+
}
455+
throw new Error('getAllComponentsFromMechanism: mechanism not found: ' + mechanism.className);
456+
}
457+
418458
/**
419459
* Returns the events defined in the given mechanism.
420460
*/

src/i18n/locales/en/translation.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@
4646
"PARAMETER": "parameter",
4747
"PARAMETERS_CAN_ONLY_GO_IN_THEIR_METHODS_BLOCK": "Parameters can only go in their method's block",
4848
"COMPONENTS": "Components",
49+
"PRIVATE_COMPONENTS": "Private Components",
4950
"EVENTS": "Events",
5051
"EVALUATE_BUT_IGNORE_RESULT": "evaluate but ignore result",
5152
"NONE": "None",

src/i18n/locales/es/translation.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@
4747
"PARAMETER": "parámetro",
4848
"PARAMETERS_CAN_ONLY_GO_IN_THEIR_METHODS_BLOCK": "Los parámetros solo pueden ir en el bloque de su método",
4949
"COMPONENTS": "Componentes",
50+
"PRIVATE_COMPONENTS": "Componentes Privados",
5051
"EVENTS": "Eventos",
5152
"EVALUATE_BUT_IGNORE_RESULT": "evaluar pero ignorar resultado",
5253
"NONE": "None",

src/i18n/locales/he/translation.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@
4646
"PARAMETER": "פרמטר",
4747
"PARAMETERS_CAN_ONLY_GO_IN_THEIR_METHODS_BLOCK": "פרמטרים יכולים להיכנס רק בבלוק השיטה שלהם",
4848
"COMPONENTS": "רכיבים",
49+
"PRIVATE_COMPONENTS": "רכיבים פרטיים",
4950
"EVENTS": "אירועים",
5051
"EVALUATE_BUT_IGNORE_RESULT": "הערך אך התעלם מהתוצאה",
5152
"NONE": "אַף לֹא אֶחָד",

src/toolbox/hardware_category.ts

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ function getRobotMechanismsCategory(editor: Editor): toolboxItems.Category {
7777
if (mechanisms.length) {
7878
const mechanismBlocks: toolboxItems.Block[] = [];
7979
mechanisms.forEach(mechanism => {
80-
const components = editor.getComponentsFromMechanism(mechanism);
80+
const components = editor.getAllComponentsFromMechanism(mechanism);
8181
mechanismBlocks.push(createMechanismBlock(mechanism, components));
8282
});
8383

@@ -109,6 +109,24 @@ function getRobotMechanismsCategory(editor: Editor): toolboxItems.Category {
109109
contents: mechanismMethodBlocks,
110110
});
111111

112+
// Get the public components from the mechanism and add the blocks for calling the component functions.
113+
const componentsFromMechanism = editor.getComponentsFromMechanism(mechanism);
114+
if (componentsFromMechanism.length > 0) {
115+
const componentBlocks: toolboxItems.ContentsType[] = [];
116+
componentsFromMechanism.forEach(component => {
117+
componentBlocks.push({
118+
kind: 'category',
119+
name: component.name,
120+
contents: getInstanceComponentBlocks(component),
121+
});
122+
});
123+
mechanismCategories.push({
124+
kind: 'category',
125+
name: Blockly.Msg['MRC_CATEGORY_COMPONENTS'],
126+
contents: componentBlocks,
127+
});
128+
}
129+
112130
mechanismCategories.push(getMechanismEventHandlersCategory(editor, mechanismInRobot));
113131

114132
contents.push({
@@ -184,7 +202,11 @@ function getComponentsCategory(
184202
});
185203

186204
// Get components from the current workspace.
187-
editor.getComponentsFromWorkspace().forEach(component => {
205+
const componentsToShow = moduleType === storageModule.ModuleType.MECHANISM
206+
? editor.getAllComponentsFromWorkspace() // Show all components (including private) when editing mechanisms
207+
: editor.getComponentsFromWorkspace(); // Show only regular components when editing robots
208+
209+
componentsToShow.forEach(component => {
188210
// Get the blocks for this specific component
189211
contents.push({
190212
kind: 'category',

0 commit comments

Comments
 (0)