Skip to content

Commit 284fd66

Browse files
committed
Merge pull request #73 from bmcage/steppercomp
Stepper rework as variable
2 parents 86b0b3d + 64ff54a commit 284fd66

File tree

8 files changed

+259
-126
lines changed

8 files changed

+259
-126
lines changed

ardublockly/index.html

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
<script src="../blockly/arduino_compressed.js"></script>
1919
<!-- To use the uncompressed version comment out the above and comment in the ones below -->
2020
<!--script src="../blockly/blockly_uncompressed.js"></script>
21+
<script src="../blockly/blocks/component_variable.js"></script>
2122
<script src="../blockly/blocks/logic.js"></script>
2223
<script src="../blockly/blocks/loops.js"></script>
2324
<script src="../blockly/blocks/math.js"></script>

blockly/blocks/arduino/stepper.js

Lines changed: 69 additions & 109 deletions
Original file line numberDiff line numberDiff line change
@@ -28,64 +28,6 @@ goog.require('Blockly.Types');
2828
/** Common HSV hue for all blocks in this category. */
2929
Blockly.Blocks.stepper.HUE = 80;
3030

31-
/** Strings for easy reference. */
32-
Blockly.Blocks.stepper.noInstance = 'No_Instances';
33-
Blockly.Blocks.stepper.noName = 'Empty_input_name';
34-
35-
/**
36-
* Finds all user-created instances of the Stepper block config.
37-
* @return {!Array.<string>} Array of instance names.
38-
*/
39-
Blockly.Blocks.stepper.stepperInstances = function() {
40-
var stepperList = [];
41-
var blocks = Blockly.mainWorkspace.getTopBlocks();
42-
for (var x = 0; x < blocks.length; x++) {
43-
var getStepperSetupInstance = blocks[x].getStepperSetupInstance;
44-
if (getStepperSetupInstance) {
45-
var stepperInstance = getStepperSetupInstance.call(blocks[x]);
46-
if (stepperInstance) {
47-
stepperList.push(stepperInstance);
48-
}
49-
}
50-
}
51-
return stepperList;
52-
};
53-
54-
/**
55-
* Return a sorted list of instances names for set dropdown menu.
56-
* @return {!Array.<string>} Array of stepper instances names.
57-
*/
58-
Blockly.Blocks.stepper.stepperDropdownList = function() {
59-
var stepperList = Blockly.Blocks.stepper.stepperInstances();
60-
var options = [];
61-
if (stepperList.length > 0) {
62-
stepperList.sort(goog.string.caseInsensitiveCompare);
63-
// Variables are not language-specific, use the name as both the
64-
// user-facing text and the internal representation.
65-
for (var x = 0; x < stepperList.length; x++) {
66-
options[x] = [stepperList[x], stepperList[x]];
67-
}
68-
} else {
69-
// There are no config blocks in the work area
70-
options[0] = [Blockly.Blocks.stepper.noInstance,
71-
Blockly.Blocks.stepper.noInstance];
72-
}
73-
return options;
74-
};
75-
76-
/**
77-
* Class for a variable's dropdown field.
78-
* @extends {Blockly.FieldDropdown}
79-
* @constructor
80-
*/
81-
Blockly.Blocks.stepper.FieldStepperInstance = function() {
82-
Blockly.Blocks.stepper.FieldStepperInstance.superClass_.constructor
83-
.call(this, Blockly.Blocks.stepper.stepperDropdownList);
84-
};
85-
goog.inherits(
86-
Blockly.Blocks.stepper.FieldStepperInstance, Blockly.FieldDropdown);
87-
88-
8931
Blockly.Blocks['stepper_config'] = {
9032
/**
9133
* Block for for the stepper generator configuration including creating
@@ -97,7 +39,8 @@ Blockly.Blocks['stepper_config'] = {
9739
this.setColour(Blockly.Blocks.stepper.HUE);
9840
this.appendDummyInput()
9941
.appendField(Blockly.Msg.ARD_STEPPER_SETUP)
100-
.appendField(new Blockly.FieldTextInput('MyStepper'), 'STEPPER_NAME')
42+
.appendField(new Blockly.Blocks.ComponentFieldVariable(
43+
Blockly.Msg.ARD_STEPPER_DEFAULT_NAME, 'Stepper'), 'STEPPER_NAME')
10144
.appendField(Blockly.Msg.ARD_STEPPER_MOTOR);
10245
this.appendDummyInput()
10346
.setAlign(Blockly.ALIGN_RIGHT)
@@ -118,18 +61,41 @@ Blockly.Blocks['stepper_config'] = {
11861
this.setTooltip(Blockly.Msg.ARD_STEPPER_SETUP_TIP);
11962
},
12063
/**
121-
* Returns the stepper instance name, defined in the 'STEPPER_NAME' input
122-
* String block attached to this block.
123-
* @return {!string} List with the instance name.
64+
* Return the name of the component defined in this block
65+
* @return {!<string>} The name of the component
66+
* @this Blockly.Block
67+
*/
68+
getComponentName: function() {
69+
return 'Stepper';
70+
},
71+
/**
72+
* Return all variables referenced by this block.
73+
* @return {!Array.<string>} List of variable names.
12474
* @this Blockly.Block
12575
*/
126-
getStepperSetupInstance: function() {
127-
var InstanceName = this.getFieldValue('STEPPER_NAME');
128-
if (!InstanceName) {
129-
InstanceName = Blockly.Blocks.stepper.noName;
76+
getVars: function() {
77+
return [this.getFieldValue('STEPPER_NAME')];
78+
},
79+
/**
80+
* Notification that a variable is renaming.
81+
* If the name matches one of this block's variables, rename it.
82+
* @param {string} oldName Previous name of variable.
83+
* @param {string} newName Renamed variable.
84+
* @this Blockly.Block
85+
*/
86+
renameVar: function(oldName, newName) {
87+
if (Blockly.Names.equals(oldName, this.getFieldValue('STEPPER_NAME'))) {
88+
this.setFieldValue(newName, 'STEPPER_NAME');
13089
}
131-
// Replace all spaces with underscores
132-
return InstanceName.replace(/ /g, '_');
90+
},
91+
/**
92+
* Gets the variable type required.
93+
* @param {!string} varName Name of the variable selected in this block to
94+
* check.
95+
* @return {string} String to indicate the variable type.
96+
*/
97+
getVarType: function(varName) {
98+
return Blockly.Types.ARRAY;
13399
},
134100
/**
135101
* Updates the content of the the pin related fields.
@@ -153,8 +119,8 @@ Blockly.Blocks['stepper_step'] = {
153119
this.setColour(Blockly.Blocks.stepper.HUE);
154120
this.appendDummyInput()
155121
.appendField(Blockly.Msg.ARD_STEPPER_STEP)
156-
.appendField(new Blockly.Blocks.stepper.FieldStepperInstance(),
157-
'STEPPER_NAME');
122+
.appendField(new Blockly.Blocks.ComponentFieldVariable(
123+
Blockly.Msg.ARD_STEPPER_DEFAULT_NAME, 'Stepper'), 'STEPPER_NAME')
158124
this.appendValueInput('STEPPER_STEPS')
159125
.setCheck(Blockly.Types.NUMBER.checkList);
160126
this.appendDummyInput()
@@ -163,6 +129,35 @@ Blockly.Blocks['stepper_step'] = {
163129
this.setNextStatement(true);
164130
this.setTooltip(Blockly.Msg.ARD_STEPPER_STEP_TIP);
165131
},
132+
/**
133+
* Return all variables referenced by this block.
134+
* @return {!Array.<string>} List of variable names.
135+
* @this Blockly.Block
136+
*/
137+
getVars: function() {
138+
return [this.getFieldValue('STEPPER_NAME')];
139+
},
140+
/**
141+
* Notification that a variable is renaming.
142+
* If the name matches one of this block's variables, rename it.
143+
* @param {string} oldName Previous name of variable.
144+
* @param {string} newName Renamed variable.
145+
* @this Blockly.Block
146+
*/
147+
renameVar: function(oldName, newName) {
148+
if (Blockly.Names.equals(oldName, this.getFieldValue('STEPPER_NAME'))) {
149+
this.setFieldValue(newName, 'STEPPER_NAME');
150+
}
151+
},
152+
/**
153+
* Gets the variable type required.
154+
* @param {!string} varName Name of the variable selected in this block to
155+
* check.
156+
* @return {string} String to indicate the variable type.
157+
*/
158+
getVarType: function(varName) {
159+
return Blockly.Types.ARRAY;
160+
},
166161
/**
167162
* Called whenever anything on the workspace changes.
168163
* It checks the instances of stepper_config and attaches a warning to this
@@ -173,46 +168,11 @@ Blockly.Blocks['stepper_step'] = {
173168
if (!this.workspace) { return; } // Block has been deleted.
174169

175170
var currentDropdown = this.getFieldValue('STEPPER_NAME');
176-
var instances = Blockly.Blocks.stepper.stepperDropdownList();
177-
178-
// Check for configuration block presence
179-
if (instances[0][0] === Blockly.Blocks.stepper.noInstance) {
180-
// Ensure dropdown menu says there is no config block
181-
if (currentDropdown !== Blockly.Blocks.stepper.noInstance) {
182-
this.setFieldValue(Blockly.Blocks.stepper.noInstance, 'STEPPER_NAME');
183-
}
184-
this.setWarningText(Blockly.Msg.ARD_STEPPER_STEP_WARN1);
171+
if (Blockly.Blocks.ComponentFieldVariable.CheckSetupPresent(this.workspace, currentDropdown, 'Stepper')) {
172+
this.setWarningText(null);
185173
} else {
186-
// Configuration blocks present, check if any selected and contains name
187-
var existingConfigSelected = false;
188-
for (var x = 0; x < instances.length; x++) {
189-
// Check if any of the config blocks does not have a name
190-
if (instances[x][0] === Blockly.Blocks.stepper.noName) {
191-
// If selected config has no name either, set warning and exit func
192-
if (currentDropdown === Blockly.Blocks.stepper.noName) {
193-
this.setWarningText(Blockly.Msg.ARD_STEPPER_STEP_WARN2);
194-
return;
195-
}
196-
} else if (instances[x][0] === currentDropdown) {
197-
existingConfigSelected = true;
198-
}
199-
}
200-
201-
// At this point select config has a name, check if it exist
202-
if (existingConfigSelected) {
203-
// All good, just remove any warnings and exit the function
204-
this.setWarningText(null);
205-
} else {
206-
if ((currentDropdown === Blockly.Blocks.stepper.noName) ||
207-
(currentDropdown === Blockly.Blocks.stepper.noInstance)) {
208-
// Just pick the first config block
209-
this.setFieldValue(instances[0][0], 'STEPPER_NAME');
210-
this.setWarningText(null);
211-
} else {
212-
// Al this point just set a warning to select a valid stepper config
213-
this.setWarningText(Blockly.Msg.ARD_STEPPER_STEP_WARN3);
214-
}
215-
}
174+
// Set a warning to select a valid stepper config
175+
this.setWarningText(Blockly.Msg.ARD_COMPONENT_WARN1.replace('%1', Blockly.Msg.ARD_STEPPER_COMPONENT).replace('%1', Blockly.Msg.ARD_STEPPER_COMPONENT));
216176
}
217177
}
218178
};
Lines changed: 166 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,166 @@
1+
/**
2+
* @license
3+
* Visual Blocks Editor
4+
*
5+
* Copyright 2012 Google Inc.
6+
* https://developers.google.com/blockly/
7+
*
8+
* Licensed under the Apache License, Version 2.0 (the "License");
9+
* you may not use this file except in compliance with the License.
10+
* You may obtain a copy of the License at
11+
*
12+
* http://www.apache.org/licenses/LICENSE-2.0
13+
*
14+
* Unless required by applicable law or agreed to in writing, software
15+
* distributed under the License is distributed on an "AS IS" BASIS,
16+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17+
* See the License for the specific language governing permissions and
18+
* limitations under the License.
19+
*/
20+
21+
/**
22+
* @fileoverview Variable input field of a specific component type.
23+
* @author [email protected] (Neil Fraser)
24+
*/
25+
'use strict';
26+
27+
goog.provide('Blockly.Blocks.ComponentFieldVariable');
28+
29+
goog.require('Blockly.Blocks');
30+
31+
32+
/**
33+
* Class for a variable's dropdown field.
34+
* @param {?string} varname The default name for the variable. If null,
35+
* a unique variable name will be generated.
36+
* @param {?string} component_type The type of component to show in the dropdown list, eg 'Stepper'
37+
* @param {Function=} opt_validator A function that is executed when a new
38+
* option is selected. Its sole argument is the new option value.
39+
* @extends {Blockly.FieldVariable}
40+
* @constructor
41+
*/
42+
Blockly.Blocks.ComponentFieldVariable = function(varname, component_type, opt_validator) {
43+
/** @type {string} */
44+
this.component_type = component_type;
45+
Blockly.Blocks.ComponentFieldVariable.superClass_.constructor.call(this,
46+
varname, opt_validator);
47+
this.setValue(varname || '');
48+
};
49+
goog.inherits(Blockly.Blocks.ComponentFieldVariable, Blockly.FieldVariable);
50+
51+
Blockly.Blocks.ComponentFieldVariable.ComponentVariables = function(root, component_type) {
52+
var blocks;
53+
if (root.getDescendants) {
54+
// Root is Block.
55+
blocks = root.getDescendants();
56+
} else if (root.getAllBlocks) {
57+
// Root is Workspace.
58+
blocks = root.getAllBlocks();
59+
} else {
60+
throw 'Not Block or Workspace: ' + root;
61+
}
62+
var variableHash = Object.create(null);
63+
// Iterate through every block and add each variable to the hash.
64+
for (var x = 0; x < blocks.length; x++) {
65+
if (blocks[x].getComponentName && blocks[x].getVars &&
66+
(blocks[x].getComponentName() == component_type)) {
67+
var blockVariables = blocks[x].getVars();
68+
for (var y = 0; y < blockVariables.length; y++) {
69+
var varName = blockVariables[y];
70+
// Variable name may be null if the block is only half-built.
71+
if (varName) {
72+
variableHash[varName.toLowerCase()] = varName;
73+
}
74+
}
75+
}
76+
}
77+
// Flatten the hash into a list.
78+
var variableList = [];
79+
for (var name in variableHash) {
80+
variableList.push(variableHash[name]);
81+
}
82+
return variableList;
83+
};
84+
85+
86+
/**
87+
* Return a sorted list of variable names for variable dropdown menus.
88+
* Include a special option at the end for creating a new variable name.
89+
* @return {!Array.<string>} Array of variable names.
90+
* @this {!ComponentFieldVariable}
91+
*/
92+
Blockly.Blocks.ComponentFieldVariable.prototype.dropdownCreate = function() {
93+
if (this.sourceBlock_ && this.sourceBlock_.workspace) {
94+
var variableList =
95+
Blockly.Blocks.ComponentFieldVariable.ComponentVariables(this.sourceBlock_.workspace,
96+
this.component_type);
97+
} else {
98+
var variableList = [];
99+
}
100+
// Ensure that the currently selected variable is an option.
101+
var name = this.getText();
102+
if (name && variableList.indexOf(name) == -1) {
103+
variableList.push(name);
104+
}
105+
variableList.sort(goog.string.caseInsensitiveCompare);
106+
variableList.push(Blockly.Msg.RENAME_VARIABLE);
107+
variableList.push(Blockly.Msg.NEW_VARIABLE);
108+
// Variables are not language-specific, use the name as both the user-facing
109+
// text and the internal representation.
110+
var options = [];
111+
for (var x = 0; x < variableList.length; x++) {
112+
options[x] = [variableList[x], variableList[x]];
113+
}
114+
return options;
115+
};
116+
117+
118+
/**
119+
* Finds all user-created instances of the ComponentFieldVariable block config.
120+
* @param {!Blockly.Workspace} workspace The block's workspace.
121+
* @param {?string} component_type The type of component setup block to obtain instances from
122+
* @return {!Array.<string>} Array of instance names.
123+
*/
124+
Blockly.Blocks.ComponentFieldVariable.Instances = function(workspace, component_type) {
125+
var instList = [];
126+
var blocks = Blockly.mainWorkspace.getAllBlocks();
127+
for (var x = 0; x < blocks.length; x++) {
128+
var getSetupInstance = blocks[x].getComponentName;
129+
if (getSetupInstance) {
130+
var Instances = getSetupInstance.call();
131+
if (Instances) {
132+
if (Instances == component_type) {
133+
instList.push(blocks[x].getVars()[0]);
134+
}
135+
}
136+
}
137+
}
138+
return instList;
139+
};
140+
141+
/**
142+
* Check to know of a setup block (which sets pin number) is present for a used
143+
* ComponentFieldVariable.
144+
* @param {!Blockly.Workspace} workspace The block's workspace.
145+
* @param {?string} currentDropdown The selected name in the dropdown for which to check
146+
* if setup block present
147+
* @param {?string} component_type The type of component setup block must be checked
148+
* @return {<boolean>} Wether setup block is present or not
149+
*/
150+
Blockly.Blocks.ComponentFieldVariable.CheckSetupPresent = function(workspace, currentDropdown, component_type) {
151+
var instances = Blockly.Blocks.ComponentFieldVariable.Instances(workspace, component_type);
152+
153+
// Check for configuration block presence
154+
if (! instances) {
155+
return false;
156+
} else {
157+
// Configuration blocks present, check if any selected in this block
158+
var existingConfigSelected = false;
159+
for (var x = 0; x < instances.length; x++) {
160+
if (instances[x] === currentDropdown) {
161+
existingConfigSelected = true;
162+
}
163+
}
164+
return existingConfigSelected;
165+
}
166+
}

0 commit comments

Comments
 (0)