Skip to content

Commit 828c76d

Browse files
committed
Add details to OpMode
Fixes #90 Fixe #91
1 parent d3fe869 commit 828c76d

File tree

4 files changed

+147
-4
lines changed

4 files changed

+147
-4
lines changed

src/blocks/mrc_opmode_details.ts

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
/**
2+
* @license
3+
* Copyright 2025 Porpoiseful LLC
4+
*
5+
* Licensed under the Apache License, Version 2.0 (the "License");
6+
* you may not use this file except in compliance with the License.
7+
* You may obtain a copy of the License at
8+
*
9+
* https://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
18+
/**
19+
* @fileoverview Block for Opmode details
20+
* @author [email protected] (Alan Smith)
21+
*/
22+
23+
/**
24+
* @license
25+
* Copyright 2025 Porpoiseful LLC
26+
*
27+
* Licensed under the Apache License, Version 2.0 (the "License");
28+
* you may not use this file except in compliance with the License.
29+
* You may obtain a copy of the License at
30+
*
31+
* https://www.apache.org/licenses/LICENSE-2.0
32+
*
33+
* Unless required by applicable law or agreed to in writing, software
34+
* distributed under the License is distributed on an "AS IS" BASIS,
35+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
36+
* See the License for the specific language governing permissions and
37+
* limitations under the License.
38+
*/
39+
40+
/**
41+
* @fileoverview Create a component with a name of a certain type
42+
* @author [email protected] (Alan Smith)
43+
*/
44+
import * as Blockly from 'blockly';
45+
46+
import { ExtendedPythonGenerator, OpModeDetails } from '../editor/extended_python_generator';
47+
import { createFieldDropdown } from '../fields/FieldDropdown';
48+
import { MRC_STYLE_CLASS_BLOCKS } from '../themes/styles';
49+
50+
export const BLOCK_NAME = 'mrc_opmode_details';
51+
52+
type OpmodeDetailsBlock = Blockly.Block & OpmodeDetailsMixin;
53+
interface OpmodeDetailsMixin extends OpmodeDetailsMixinType {
54+
}
55+
type OpmodeDetailsMixinType = typeof OPMODE_DETAILS;
56+
57+
const OPMODE_DETAILS = {
58+
/**
59+
* Block initialization.
60+
*/
61+
init: function (this: OpmodeDetailsBlock): void {
62+
this.setStyle(MRC_STYLE_CLASS_BLOCKS);
63+
this.appendDummyInput()
64+
.appendField('Type')
65+
.appendField(createFieldDropdown(['Auto', 'Teleop', 'Test']), 'TYPE')
66+
.appendField(' ')
67+
.appendField('Enabled')
68+
.appendField(new Blockly.FieldCheckbox(true), 'ENABLED');
69+
70+
this.appendDummyInput()
71+
.appendField('Display Name')
72+
.appendField(new Blockly.FieldTextInput(''), 'NAME')
73+
this.appendDummyInput()
74+
.appendField('Display Group')
75+
.appendField(new Blockly.FieldTextInput(''), 'GROUP');
76+
77+
this.getField('TYPE')?.setTooltip('What sort of OpMode this is');
78+
this.getField('ENABLED')?.setTooltip('Whether the OpMode is shown on Driver Station');
79+
this.getField('NAME')?.setTooltip('The name shown on the Driver Station. If blank will use the class name.');
80+
this.getField('GROUP')?.setTooltip('An optional group to group OpModes on Driver Station');
81+
},
82+
}
83+
84+
export const setup = function () {
85+
Blockly.Blocks[BLOCK_NAME] = OPMODE_DETAILS;
86+
}
87+
88+
export const pythonFromBlock = function (
89+
block: OpmodeDetailsBlock,
90+
generator: ExtendedPythonGenerator,
91+
) {
92+
generator.setOpModeDetails(new OpModeDetails(
93+
block.getFieldValue('NAME'),
94+
block.getFieldValue('GROUP'),
95+
block.getFieldValue('ENABLED') == 'TRUE',
96+
block.getFieldValue('TYPE')
97+
));
98+
return '';
99+
}

src/blocks/setup_custom_blocks.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import * as Mechanism from './mrc_mechanism';
1212
import * as Component from './mrc_component';
1313
import * as MechanismContainerHolder from './mrc_mechanism_component_holder';
1414
import * as Port from './mrc_port';
15+
import * as OpModeDetails from './mrc_opmode_details';
1516

1617
const customBlocks = [
1718
CallPythonFunction,
@@ -27,6 +28,7 @@ const customBlocks = [
2728
Component,
2829
MechanismContainerHolder,
2930
Port,
31+
OpModeDetails
3032
];
3133

3234
export const setup = function(forBlock: any) {

src/editor/extended_python_generator.ts

Lines changed: 31 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,24 @@ import { FunctionArg } from '../blocks/mrc_call_python_function';
2727
import * as MechanismContainerHolder from '../blocks/mrc_mechanism_component_holder';
2828
import * as commonStorage from '../storage/common_storage';
2929

30+
export class OpModeDetails {
31+
constructor(private name: string, private group : string, private enabled : boolean, private type : string) {}
32+
annotations() : string{
33+
let code = '';
34+
35+
if(this.enabled){
36+
code += '@' + this.type + "\n";
37+
if(this.name){
38+
code += '@name("' + this.name + '")\n';
39+
}
40+
if(this.group){
41+
code += '@group("' + this.group + '")\n';
42+
}
43+
}
44+
return code;
45+
}
46+
}
47+
3048
// Extends the python generator to collect some information about functions and
3149
// variables that have been defined so they can be used in other modules.
3250

@@ -36,7 +54,9 @@ export class ExtendedPythonGenerator extends PythonGenerator {
3654

3755
private classMethods: {[key: string]: string} = Object.create(null);
3856
private ports: {[key: string]: string} = Object.create(null);
39-
57+
// Opmode details
58+
private details : OpModeDetails | null = null;
59+
4060
constructor() {
4161
super('Python');
4262
}
@@ -137,15 +157,17 @@ export class ExtendedPythonGenerator extends PythonGenerator {
137157
if (this.context && this.workspace) {
138158
const className = this.context.getClassName();
139159
const classParent = this.context.getClassParent();
160+
const annotations = this.details?.annotations();
140161
this.addImport(classParent);
162+
141163
const classDef = 'class ' + className + '(' + classParent + '):\n';
142164
const classMethods = [];
143165
for (const name in this.classMethods) {
144166
classMethods.push(this.classMethods[name])
145167
}
146168
this.classMethods = Object.create(null);
147169
this.ports = Object.create(null);
148-
code = classDef + this.prefixLines(classMethods.join('\n\n'), this.INDENT);
170+
code = annotations + classDef + this.prefixLines(classMethods.join('\n\n'), this.INDENT);
149171

150172
this.context.setExportedBlocks(this.produceExportedBlocks(this.workspace));
151173
}
@@ -262,6 +284,13 @@ export class ExtendedPythonGenerator extends PythonGenerator {
262284
}
263285
return exportedBlocks;
264286
}
287+
setOpModeDetails(details : OpModeDetails) {
288+
this.details = details;
289+
}
290+
291+
getOpModeDetails() : OpModeDetails | null{
292+
return this.details;
293+
}
265294
}
266295

267296
export const extendedPythonGenerator = new ExtendedPythonGenerator();

src/modules/opmode_start.json

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,24 @@
22
"blocks": {
33
"languageVersion": 0,
44
"blocks": [
5+
{
6+
"type": "mrc_opmode_details",
7+
"id": "ElbONc{)gh,UprTW(|1C",
8+
"x": 10,
9+
"y": 10,
10+
"deletable": false,
11+
"fields": {
12+
"NAME": "",
13+
"GROUP": "",
14+
"TYPE": "Auto",
15+
"ENABLED": true
16+
}
17+
},
518
{
619
"type": "mrc_class_method_def",
720
"id": "ElbONc{)s(,UprTW(|1C",
821
"x": 10,
9-
"y": 10,
22+
"y": 120,
1023
"deletable": false,
1124
"extraState": {
1225
"canChangeSignature": false,
@@ -29,7 +42,7 @@
2942
"type": "mrc_class_method_def",
3043
"id": "wxFAh6eaR1|3fTuV:UAd",
3144
"x": 10,
32-
"y": 200,
45+
"y": 300,
3346
"deletable": false,
3447
"extraState": {
3548
"canChangeSignature": false,

0 commit comments

Comments
 (0)