From bbd14c58b57087b50031b302d1327b0743f4f4a9 Mon Sep 17 00:00:00 2001 From: Mario Date: Wed, 16 Sep 2020 14:59:09 +0200 Subject: [PATCH] add new blocks --- src/components/Blockly/blocks/audio.js | 65 +++++++ src/components/Blockly/blocks/index.js | 5 +- src/components/Blockly/blocks/logic.js | 168 +++++++++++++++++- .../Blockly/blocks/sensebox-display.js | 1 - src/components/Blockly/blocks/sensebox-sd.js | 80 +++++++++ src/components/Blockly/blocks/text.js | 1 + src/components/Blockly/blocks/variables.js | 167 +++++++++++++++++ src/components/Blockly/generator/audio.js | 25 +++ src/components/Blockly/generator/index.js | 4 + src/components/Blockly/generator/logic.js | 59 +++++- .../Blockly/generator/sensebox-sd.js | 53 ++++++ src/components/Blockly/generator/text.js | 85 +++++++++ src/components/Blockly/generator/variables.js | 38 ++++ src/components/Blockly/helpers/colour.js | 3 + src/components/Blockly/helpers/types.js | 3 + src/components/Blockly/toolbox/Toolbox.js | 28 +++ 16 files changed, 780 insertions(+), 5 deletions(-) create mode 100644 src/components/Blockly/blocks/audio.js create mode 100644 src/components/Blockly/blocks/sensebox-sd.js create mode 100644 src/components/Blockly/blocks/text.js create mode 100644 src/components/Blockly/blocks/variables.js create mode 100644 src/components/Blockly/generator/audio.js create mode 100644 src/components/Blockly/generator/sensebox-sd.js create mode 100644 src/components/Blockly/generator/text.js create mode 100644 src/components/Blockly/generator/variables.js diff --git a/src/components/Blockly/blocks/audio.js b/src/components/Blockly/blocks/audio.js new file mode 100644 index 0000000..bb56c01 --- /dev/null +++ b/src/components/Blockly/blocks/audio.js @@ -0,0 +1,65 @@ +import Blockly from 'blockly/core'; +import { selectedBoard } from '../helpers/board' +import * as Types from '../helpers/types' +import { getColour } from '../helpers/colour'; + + +Blockly.Blocks['io_tone'] = { + init: function () { + this.appendDummyInput() + .appendField(Blockly.Msg.ARD_SETTONE) + .appendField(new Blockly.FieldDropdown( + selectedBoard().digitalPins), "TONEPIN"); + this.appendValueInput("FREQUENCY") + .setCheck(Types.NUMBER.checkList) + .appendField(Blockly.Msg.ARD_TONEFREQ); + this.appendDummyInput() + .appendField("Hz"); + this.setInputsInline(true); + this.setPreviousStatement(true); + this.setNextStatement(true); + this.setColour(getColour().audio); + this.setTooltip(Blockly.Msg.ARD_TONE_TIP); + this.setHelpUrl('https://www.arduino.cc/en/Reference/tone'); + }, + /** + * Called whenever anything on the workspace changes. + * It checks frequency values and sets a warning if out of range. + * @this Blockly.Block + */ + onchange: function (event) { + if (!this.workspace || event.type === Blockly.Events.MOVE || + event.type === Blockly.Events.UI) { + return; // Block deleted or irrelevant event + } + var freq = Blockly.Arduino.valueToCode( + this, "FREQUENCY", Blockly.Arduino.ORDER_ATOMIC) + if (freq < 31 || freq > 65535) { + this.setWarningText(Blockly.Msg.ARD_TONE_WARNING, 'io_tone'); + } else { + this.setWarningText(null, 'io_tone'); + } + }, + /** @return {!string} The type of input value for the block, an integer. */ + getBlockType: function () { + return Blockly.Types.NUMBER; + } +}; + +Blockly.Blocks['io_notone'] = { + init: function () { + this.appendDummyInput() + .appendField(Blockly.Msg.ARD_NOTONE) + .appendField(new Blockly.FieldDropdown( + selectedBoard().digitalPins), "TONEPIN"); + this.setPreviousStatement(true); + this.setNextStatement(true); + this.setColour(getColour().audio); + this.setTooltip(Blockly.Msg.ARD_NOTONE_TIP); + this.setHelpUrl('https://www.arduino.cc/en/Reference/noTone'); + }, + /** @return {!string} The type of input value for the block, an integer. */ + getBlockType: function () { + return Blockly.Types.NUMBER; + } +}; diff --git a/src/components/Blockly/blocks/index.js b/src/components/Blockly/blocks/index.js index 40770dd..5ba7a02 100644 --- a/src/components/Blockly/blocks/index.js +++ b/src/components/Blockly/blocks/index.js @@ -8,11 +8,14 @@ import './sensebox-web'; import './sensebox-display'; import './sensebox-lora'; import './sensebox-led'; +import './sensebox-sd'; +import './text'; import './io'; +import './audio'; import './math'; import './map'; import './procedures'; import './time'; - +import './variables'; import '../helpers/types' \ No newline at end of file diff --git a/src/components/Blockly/blocks/logic.js b/src/components/Blockly/blocks/logic.js index 6b17ee4..f80062a 100644 --- a/src/components/Blockly/blocks/logic.js +++ b/src/components/Blockly/blocks/logic.js @@ -1,6 +1,5 @@ import Blockly from 'blockly/core'; - - +import { getColour } from '../helpers/colour'; Blockly.defineBlocksWithJsonArray([ // BEGIN JSON EXTRACT @@ -232,4 +231,169 @@ Blockly.defineBlocksWithJsonArray([ // Mutator blocks. Do not extract. ]); +Blockly.Blocks['switch_case'] = { + init: function () { + this.setColour(getColour().logic); + this.setPreviousStatement(true); + this.setNextStatement(true); + this.appendValueInput('CONDITION') + .appendField(Blockly.Msg.cases_switch); + this.appendValueInput('CASECONDITION0') + .appendField(Blockly.Msg.cases_condition); + this.appendStatementInput('CASE0') + .appendField(Blockly.Msg.cases_do); + this.setMutator(new Blockly.Mutator(['case_incaseof', 'case_default'])); + this.setTooltip('Does something if the condition is true. If there isn\'t a matching case the default function will be executed.'); + this.caseCount_ = 0; + this.defaultCount_ = 0; + }, + mutationToDom: function () { + if (!this.caseCount_ && !this.defaultCount_) { + return null; + } + var container = document.createElement('mutation'); + if (this.caseCount_) { + container.setAttribute('case', this.caseCount_); + } + if (this.defaultCount_) { + container.setAttribute('default', 1); + } + return container; + }, + + domToMutation: function (xmlElement) { + this.caseCount_ = parseInt(xmlElement.getAttribute('case'), 10); + this.defaultCount_ = parseInt(xmlElement.getAttribute('default'), 10); + for (var x = 0; x <= this.caseCount_; x++) { + this.appendValueInput('CASECONDITION' + x) + .appendField(Blockly.Msg.cases_condition); + this.appendStatementInput('CASE' + x) + .appendField(Blockly.Msg.cases_do); + } + if (this.defaultCount_) { + this.appendStatementInput('ONDEFAULT') + .appendField('default'); + } + }, + + decompose: function (workspace) { + var containerBlock = workspace.newBlock('control_case'); + containerBlock.initSvg(); + var connection = containerBlock.getInput('STACK').connection; + for (var x = 1; x <= this.caseCount_; x++) { + var caseBlock = workspace.newBlock('case_incaseof'); + caseBlock.initSvg(); + connection.connect(caseBlock.previousConnection); + connection = caseBlock.nextConnection; + } + if (this.defaultCount_) { + var defaultBlock = Blockly.Block.obtain(workspace, 'case_default'); + defaultBlock.initSvg(); + connection.connect(defaultBlock.previousConnection); + } + return containerBlock; + }, + + compose: function (containerBlock) { + //Disconnect all input blocks and remove all inputs. + if (this.defaultCount_) { + this.removeInput('ONDEFAULT'); + } + this.defaultCount_ = 0; + for (var x = this.caseCount_; x > 0; x--) { + this.removeInput('CASECONDITION' + x); + this.removeInput('CASE' + x); + } + this.caseCount_ = 0; + var caseBlock = containerBlock.getInputTargetBlock('STACK'); + while (caseBlock) { + switch (caseBlock.type) { + case 'case_incaseof': + this.caseCount_++; + var caseconditionInput = this.appendValueInput('CASECONDITION' + this.caseCount_) + .appendField(Blockly.Msg.cases_condition); + var caseInput = this.appendStatementInput('CASE' + this.caseCount_) + .appendField(Blockly.Msg.cases_do); + if (caseBlock.valueConnection_) { + caseconditionInput.connection.connect(caseBlock.valueConnection_); + } + if (caseBlock.statementConnection_) { + caseInput.connection.connect(caseBlock.statementConnection_); + } + break; + case 'case_default': + this.defaultCount_++; + var defaultInput = this.appendStatementInput('ONDEFAULT') + .appendField('default'); + if (caseBlock.statementConnection_) { + defaultInput.connection.connect(caseBlock.statementConnection_); + } + break; + default: + throw 'Unknown block type.'; + } + caseBlock = caseBlock.nextConnection && + caseBlock.nextConnection.targetBlock(); + } + }, + + saveConnections: function (containerBlock) { + var caseBlock = containerBlock.getInputTargetBlock('STACK'); + var x = 1; + while (caseBlock) { + switch (caseBlock.type) { + case 'case_incaseof': + var caseconditionInput = this.getInput('CASECONDITION' + x); + var caseInput = this.getInput('CASE' + x); + caseBlock.valueConnection_ = caseconditionInput && caseconditionInput.connection.targetConnection; + caseBlock.statementConnection_ = caseInput && caseInput.connection.targetConnection; + x++; + break; + case 'case_default': + var defaultInput = this.getInput('ONDEFAULT'); + caseBlock.satementConnection_ = defaultInput && defaultInput.connection.targetConnection; + break; + default: + throw 'Unknown block type'; + } + caseBlock = caseBlock.nextConnection && + caseBlock.nextConnection.targetBlock(); + } + } +}; + +Blockly.Blocks['control_case'] = { + init: function () { + this.setColour(getColour().logic); + this.appendDummyInput() + .appendField(Blockly.Msg.cases_switch); + this.appendStatementInput('STACK'); + this.setTooltip('--Placeholder--'); + this.contextMenu = false; + } +}; + +Blockly.Blocks['case_incaseof'] = { + init: function () { + this.setColour(getColour().logic); + this.appendDummyInput() + .appendField(Blockly.Msg.cases_add); + this.setPreviousStatement(true); + this.setNextStatement(true); + this.setTooltip('--Placeholder--'); + this.contextMenu = false; + } +}; + +Blockly.Blocks['case_default'] = { + init: function () { + this.setColour(getColour().logic); + this.appendValueInput('default') + .appendField('default'); + this.setPreviousStatement(true); + this.setNextStatement(false); + this.setTooltip('This function will run if there aren\'t any matching cases.'); + this.contextMenu = false; + } +}; diff --git a/src/components/Blockly/blocks/sensebox-display.js b/src/components/Blockly/blocks/sensebox-display.js index 795f295..4b6220b 100644 --- a/src/components/Blockly/blocks/sensebox-display.js +++ b/src/components/Blockly/blocks/sensebox-display.js @@ -2,7 +2,6 @@ import * as Blockly from 'blockly/core'; import { getColour } from '../helpers/colour'; import * as Types from '../helpers/types' import { FieldSlider } from '@blockly/field-slider'; -import { Field } from '..'; Blockly.Blocks['sensebox_display_beginDisplay'] = { diff --git a/src/components/Blockly/blocks/sensebox-sd.js b/src/components/Blockly/blocks/sensebox-sd.js new file mode 100644 index 0000000..ed715f7 --- /dev/null +++ b/src/components/Blockly/blocks/sensebox-sd.js @@ -0,0 +1,80 @@ +import * as Blockly from 'blockly/core'; +import { getColour } from '../helpers/colour'; + + +Blockly.Blocks['sensebox_sd_open_file'] = { + init: function () { + this.appendDummyInput() + .appendField(Blockly.Msg.senseBox_sd_open_file) + .setAlign(Blockly.ALIGN_LEFT) + .appendField( + new Blockly.FieldTextInput('Data.txt'), + 'Filename'); + this.appendStatementInput('SD') + .setCheck(null); + this.setPreviousStatement(true, null); + this.setNextStatement(true, null); + this.setColour(getColour().sensebox); + this.setTooltip(Blockly.Msg.senseBox_output_safetosd_tip); + this.setHelpUrl('https://sensebox.de/books'); + } +}; + +Blockly.Blocks['sensebox_sd_create_file'] = { + init: function () { + this.appendDummyInput() + .appendField(Blockly.Msg.senseBox_sd_create_file) + .setAlign(Blockly.ALIGN_LEFT) + .appendField(Blockly.Msg.senseBox_output_filename) + .appendField( + new Blockly.FieldTextInput('Data.txt'), + 'Filename'); + this.setPreviousStatement(true, null); + this.setNextStatement(true, null); + this.setColour(getColour().sensebox); + this.setTooltip(Blockly.Msg.senseBox_output_safetosd_tip); + this.setHelpUrl('https://sensebox.de/books'); + } +}; + +Blockly.Blocks['sensebox_sd_write_file'] = { + init: function () { + this.appendDummyInput() + .appendField(Blockly.Msg.senseBox_sd_write_file) + .setAlign(Blockly.ALIGN_LEFT); + this.appendValueInput('DATA') + .setCheck(null); + this.appendDummyInput('CheckboxText') + .appendField(Blockly.Msg.senseBox_output_linebreak) + .appendField(new Blockly.FieldCheckbox('TRUE'), 'linebreak'); + this.setPreviousStatement(true, null); + this.setNextStatement(true, null); + this.setColour(getColour().sensebox); + this.setTooltip(Blockly.Msg.senseBox_output_safetosd_tip); + this.setHelpUrl('https://sensebox.de/books'); + }, + /** + * Called whenever anything on the workspace changes. + * Add warning if block is not nested inside a the correct loop. + * @param {!Blockly.Events.Abstract} e Change event. + * @this Blockly.Block + */ + onchange: function (e) { + var legal = false; + // Is the block nested in a loop? + var block = this; + do { + if (this.LOOP_TYPES.indexOf(block.type) != -1) { + legal = true; + break; + } + block = block.getSurroundParent(); + } while (block); + if (legal) { + this.setWarningText(null); + } else { + this.setWarningText(Blockly.Msg.CONTROLS_FLOW_STATEMENTS_WARNING); + } + }, + LOOP_TYPES: ['sensebox_sd_open_file'], +}; diff --git a/src/components/Blockly/blocks/text.js b/src/components/Blockly/blocks/text.js new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/src/components/Blockly/blocks/text.js @@ -0,0 +1 @@ + diff --git a/src/components/Blockly/blocks/variables.js b/src/components/Blockly/blocks/variables.js new file mode 100644 index 0000000..30ec057 --- /dev/null +++ b/src/components/Blockly/blocks/variables.js @@ -0,0 +1,167 @@ +import Blockly from 'blockly/core'; +import { getColour } from '../helpers/colour'; + +Blockly.defineBlocksWithJsonArray([ + // BEGIN JSON EXTRACT + { + type: 'variables_get_number', + message0: '= number variable %1', + args0: [ + { + type: 'field_variable', + name: 'VAR', + variable: null, + variableTypes: ['Number'], + defaultType: 'Number', + }, + ], + output: 'Number', + colour: getColour().variables, + tooltip: '', + helpUrl: '', + }, + { + type: 'variables_set_number', + message0: 'Number variable %1 = %2', + args0: [ + { + type: 'field_variable', + name: 'VAR', + variable: null, + variableTypes: ['Number'], + defaultType: 'Number', + createNewVariable: false, + }, + { + type: 'input_value', + name: 'VALUE', + check: 'Number', + }, + ], + previousStatement: null, + nextStatement: null, + colour: getColour().variables, + tooltip: '', + helpUrl: '', + }, + { + type: 'variables_get_colour', + message0: '= color variable %1', + args0: [ + { + type: 'field_variable', + name: 'VAR', + variable: null, + variableTypes: ['Colour'], + defaultType: 'Colour', + }, + ], + output: 'Colour', + colour: getColour().variables, + tooltip: '', + helpUrl: '', + }, + { + type: 'variables_set_colour', + message0: 'Color variable %1 = %2', + args0: [ + { + type: 'field_variable', + name: 'VAR', + variable: null, + variableTypes: ['Colour'], + defaultType: 'Colour', + }, + { + type: 'input_value', + name: 'VALUE', + check: 'Colour', + }, + ], + previousStatement: null, + nextStatement: null, + colour: getColour().variables, + tooltip: '', + helpUrl: '', + }, + { + type: 'variables_get_string', + message0: '= text variable %1', + args0: [ + { + type: 'field_variable', + name: 'VAR', + variable: null, + variableTypes: ['String'], + defaultType: 'String', + }, + ], + output: 'String', + colour: getColour().variables, + tooltip: '', + helpUrl: '', + }, + { + type: 'variables_set_string', + message0: 'Text variable %1 = %2', + args0: [ + { + type: 'field_variable', + name: 'VAR', + variable: null, + variableTypes: ['String'], + defaultType: 'String', + }, + { + type: 'input_value', + name: 'VALUE', + check: 'String', + }, + ], + previousStatement: null, + nextStatement: null, + colour: getColour().variables, + tooltip: '', + helpUrl: '', + }, + { + type: 'variables_get_boolean', + message0: '= boolean variable %1', + args0: [ + { + type: 'field_variable', + name: 'VAR', + variable: null, + variableTypes: ['Boolean'], + defaultType: 'Boolean', + }, + ], + output: 'Boolean', + colour: getColour().variables, + tooltip: '', + helpUrl: '', + }, + { + type: 'variables_set_boolean', + message0: 'Boolean variable %1 = %2', + args0: [ + { + type: 'field_variable', + name: 'VAR', + variable: null, + variableTypes: ['Boolean'], + defaultType: 'Boolean', + }, + { + type: 'input_value', + name: 'VALUE', + check: 'Boolean', + }, + ], + previousStatement: null, + nextStatement: null, + colour: getColour().variables, + tooltip: '', + helpUrl: '', + }, +]); // END JSON EXTRACT (Do not delete this comment.) \ No newline at end of file diff --git a/src/components/Blockly/generator/audio.js b/src/components/Blockly/generator/audio.js new file mode 100644 index 0000000..1b7b0e8 --- /dev/null +++ b/src/components/Blockly/generator/audio.js @@ -0,0 +1,25 @@ +import * as Blockly from 'blockly/core'; + + +/** + * Function for turning the tone library on on a given pin (X). + * Arduino code: setup { pinMode(X, OUTPUT) } + * loop { tone(X, frequency) } + * @param {!Blockly.Block} block Block to generate the code from. + * @return {array} Completed code with order of operation. + */ + +Blockly.Arduino['io_tone'] = function (block) { + var pin = block.getFieldValue('TONEPIN'); + var freq = Blockly.Arduino.valueToCode(block, 'FREQUENCY', Blockly.Arduino.ORDER_ATOMIC); + Blockly.Arduino.setupCode_['io_tone' + pin] = 'pinMode(' + pin + ', OUTPUT);\n'; + var code = 'tone(' + pin + ',' + freq + ');\n'; + return code; +}; + +Blockly.Arduino['io_notone'] = function (block) { + var pin = block.getFieldValue("TONEPIN"); + Blockly.Arduino.setupCode_['io_tone' + pin] = 'pinMode(' + pin + ', OUTPUT);\n'; + var code = 'noTone(' + pin + ');\n'; + return code; +}; diff --git a/src/components/Blockly/generator/index.js b/src/components/Blockly/generator/index.js index f4370fc..fd2c108 100644 --- a/src/components/Blockly/generator/index.js +++ b/src/components/Blockly/generator/index.js @@ -7,11 +7,15 @@ import './sensebox-web'; import './sensebox-display'; import './sensebox-lora'; import './sensebox-led'; +import './sensebox-sd'; import './logic'; +import './text'; import './math'; import './map'; import './io'; +import './audio'; import './procedures'; import './time'; +import './variables'; diff --git a/src/components/Blockly/generator/logic.js b/src/components/Blockly/generator/logic.js index 443b7b2..3ba41d3 100644 --- a/src/components/Blockly/generator/logic.js +++ b/src/components/Blockly/generator/logic.js @@ -86,7 +86,37 @@ Blockly.Arduino['controls_if'] = function (Block) { return code + '\n'; }; -Blockly.Arduino['controls_ifelse'] = Blockly.Arduino['control_if']; +Blockly.Arduino['controls_ifelse'] = function (Block) { + // If/elseif/else condition. + let n = 0; + let code = '', + branchCode, + conditionCode; + do { + conditionCode = + Blockly.Arduino.valueToCode( + Block, + 'IF' + n, + Blockly.Arduino.ORDER_NONE + ) || 'false'; + branchCode = Blockly.Arduino.statementToCode(Block, 'DO' + n); + code += + (n > 0 ? ' else ' : '') + + 'if (' + + conditionCode + + ') {\n' + + branchCode + + '}'; + + ++n; + } while (Block.getInput('IF' + n)); + + if (Block.getInput('ELSE')) { + branchCode = Blockly.Arduino.statementToCode(Block, 'ELSE'); + code += ' else {\n' + branchCode + '}'; + } + return code + '\n'; +} Blockly.Arduino['logic_negate'] = function (Block) { // Negation. @@ -95,3 +125,30 @@ Blockly.Arduino['logic_negate'] = function (Block) { const code = '!' + argument0; return [code, order]; }; + + + + + +Blockly.Arduino['switch_case'] = function (block) { + var n = 0; + var argument = Blockly.Arduino.valueToCode(this, 'CONDITION', + Blockly.Arduino.ORDER_NONE) || ''; + var branch = Blockly.Arduino.statementToCode(block, 'CASECONDITON0' + n); + var cases = ''; + var default_code = ''; + var DO = Blockly.Arduino.statementToCode(block, ('CASE' + n)); + for (n = 0; n <= block.caseCount_; n++) { + var DO = Blockly.Arduino.statementToCode(block, ('CASE' + n)); + var branch = Blockly.Arduino.valueToCode(block, ('CASECONDITION' + n), Blockly.Arduino.ORDER_NONE) || '0'; + cases += 'case ' + branch + ':\n'; + cases += DO + '\nbreak;\n'; + } + if (block.defaultCount_) { + var branch = Blockly.Arduino.statementToCode(block, 'ONDEFAULT'); + default_code = 'default: \n' + branch + '\n break;\n'; + } + var code = 'switch (' + argument + ') {\n' + cases + default_code + '}'; + return code + '\n'; +}; + diff --git a/src/components/Blockly/generator/sensebox-sd.js b/src/components/Blockly/generator/sensebox-sd.js new file mode 100644 index 0000000..f089864 --- /dev/null +++ b/src/components/Blockly/generator/sensebox-sd.js @@ -0,0 +1,53 @@ +import Blockly from 'blockly'; + + +/* SD-Card Blocks using the Standard SD Library*/ +/** + * Code generator for variable (X) getter. + * Arduino code: loop { X } + * @param {Blockly.Block} block Block to generate the code from. + * @return {array} Completed code with order of operation. + */ + +Blockly.Arduino.sensebox_sd_create_file = function (block) { + var filename = this.getFieldValue('Filename'); + var res = filename.slice(0, 4); + Blockly.Arduino.libraries_['library_spi'] = '#include '; + Blockly.Arduino.libraries_['library_sd'] = '#include '; + Blockly.Arduino.definitions_['define_' + filename] = 'File dataFile' + res + ';'; + Blockly.Arduino.setupCode_['sensebox_sd'] = 'SD.begin(28);'; + Blockly.Arduino.setupCode_['sensebox_sd' + filename] = 'dataFile' + res + ' = SD.open("' + filename + '", FILE_WRITE);\ndataFile' + res + '.close();\n'; + var code = ''; + return code; +}; + +Blockly.Arduino.sensebox_sd_open_file = function (block) { + var filename = this.getFieldValue('Filename'); + var res = filename.slice(0, 4); + var branch = Blockly.Arduino.statementToCode(block, 'SD'); + var code = 'dataFile' + res + ' = SD.open("' + filename + '", FILE_WRITE);\n' + code += branch; + code += 'dataFile' + res + '.close();\n' + return code; +}; + +Blockly.Arduino.sensebox_sd_write_file = function (block) { + var res = filename.slice(0, 4); + if (this.parentBlock_ != null) { + var filename = this.getSurroundParent().getFieldValue('Filename'); + } + var text = Blockly.Arduino.valueToCode(this, 'DATA', Blockly.Arduino.ORDER_ATOMIC) || '"Keine Eingabe"'; + var linebreak = this.getFieldValue('linebreak'); + if (linebreak == "TRUE") { + linebreak = "ln"; + } else { + linebreak = ""; + } + if (text == "gps.getLongitude()" || text == "gps.getLatitude()") { + var code = 'dataFile' + res + '.print' + linebreak + '(' + text + ',5);\n' + } + else { + var code = 'dataFile' + res + '.print' + linebreak + '(' + text + ');\n' + } + return code; +}; diff --git a/src/components/Blockly/generator/text.js b/src/components/Blockly/generator/text.js new file mode 100644 index 0000000..95fcc15 --- /dev/null +++ b/src/components/Blockly/generator/text.js @@ -0,0 +1,85 @@ +import * as Blockly from 'blockly/core'; + + +/** + * Code generator for a literal String (X). + * Arduino code: loop { "X" } + * @param {!Blockly.Block} block Block to generate the code from. + * @return {array} Completed code with order of operation. + */ +Blockly.Arduino['text'] = function (block) { + var code = Blockly.Arduino.quote_(block.getFieldValue('TEXT')); + return [code, Blockly.Arduino.ORDER_ATOMIC]; +}; + + +/** + * Code generator for a String concatenation (X...Y). This string can be made + * up of any number of elements of any type. + * This block uses a mutator. + * String construction info: http://arduino.cc/en/Reference/StringConstructor + * Arduino code: loop { "String(X)" + ... + "String(Y)" } + * @param {!Blockly.Block} block Block to generate the code from. + * @return {array} Completed code with order of operation. + */ +Blockly.Arduino['text_join'] = function (block) { + var code; + if (block.itemCount_ === 0) { + return ['""', Blockly.Arduino.ORDER_ATOMIC]; + } else if (block.itemCount_ === 1) { + var argument0 = Blockly.Arduino.valueToCode(block, 'ADD0', + Blockly.Arduino.ORDER_UNARY_POSTFIX) || '""'; + code = 'String(' + argument0 + ')'; + return [code, Blockly.Arduino.ORDER_UNARY_POSTFIX]; + } else { + var argument; + code = []; + for (var n = 0; n < block.itemCount_; n++) { + argument = Blockly.Arduino.valueToCode( + block, 'ADD' + n, Blockly.Arduino.ORDER_NONE); + if (argument === '') { + code[n] = '""'; + } else { + code[n] = 'String(' + argument + ')'; + } + } + code = code.join(' + '); + return [code, Blockly.Arduino.ORDER_UNARY_POSTFIX]; + } +}; + +/** + * Code generator for appending text (Y) to a variable in place (X). + * String constructor info: http://arduino.cc/en/Reference/StringConstructor + * Arduino code: loop { X += String(Y) } + * @param {!Blockly.Block} block Block to generate the code from. + * @return {string} Completed code. + */ +Blockly.Arduino['text_append'] = function (block) { + // Append to a variable in place. + var varName = Blockly.Arduino.variableDB_.getName( + block.getFieldValue('VAR'), Blockly.Variables.NAME_TYPE); + var argument0 = Blockly.Arduino.valueToCode(block, 'TEXT', + Blockly.Arduino.ORDER_UNARY_POSTFIX); + if (argument0 === '') { + argument0 = '""'; + } else { + argument0 = 'String(' + argument0 + ')'; + } + return varName + ' += ' + argument0 + ';\n'; +}; + +/** + * Code generator to get the length of a string (X). + * String length info: http://arduino.cc/en/Reference/StringLength + * Arduino code: loop { String(X).length() } + * @param {!Blockly.Block} block Block to generate the code from. + * @return {array} Completed code with order of operation. + */ +Blockly.Arduino['text_length'] = function (block) { + var argument0 = Blockly.Arduino.valueToCode(block, 'VALUE', + Blockly.Arduino.ORDER_UNARY_POSTFIX) || '""'; + var code = 'String(' + argument0 + ').length()'; + return [code, Blockly.Arduino.ORDER_UNARY_POSTFIX]; +}; + diff --git a/src/components/Blockly/generator/variables.js b/src/components/Blockly/generator/variables.js new file mode 100644 index 0000000..e5df679 --- /dev/null +++ b/src/components/Blockly/generator/variables.js @@ -0,0 +1,38 @@ +import Blockly from 'blockly'; + +const setVariableFunction = function (defaultValue) { + return function (block) { + const variableName = Blockly['Arduino'].variableDB_.getName( + block.getFieldValue('VAR'), + Blockly.Variables.NAME_TYPE + ); + const variableValue = Blockly['Arduino'].valueToCode( + block, + 'VALUE', + Blockly['Arduino'].ORDER_ATOMIC + ); + + return variableName + ' = ' + (variableValue || defaultValue) + ';\n'; + }; +}; + +const getVariableFunction = function (block) { + const variableName = Blockly['Arduino'].variableDB_.getName( + block.getFieldValue('VAR'), + Blockly.Variables.NAME_TYPE + ); + + return [variableName, Blockly['Arduino'].ORDER_ATOMIC]; +}; + +Blockly['Arduino']['variables_set_number'] = setVariableFunction(10); +Blockly['Arduino']['variables_set_boolean'] = setVariableFunction('true'); +Blockly['Arduino']['variables_set_string'] = setVariableFunction('" "'); +Blockly['Arduino']['variables_set_colour'] = setVariableFunction( + `{ 22, 0, 22}` +); + +Blockly['Arduino']['variables_get_number'] = getVariableFunction; +Blockly['Arduino']['variables_get_boolean'] = getVariableFunction; +Blockly['Arduino']['variables_get_string'] = getVariableFunction; +Blockly['Arduino']['variables_get_colour'] = getVariableFunction; \ No newline at end of file diff --git a/src/components/Blockly/helpers/colour.js b/src/components/Blockly/helpers/colour.js index d2f5c27..7aea8df 100644 --- a/src/components/Blockly/helpers/colour.js +++ b/src/components/Blockly/helpers/colour.js @@ -7,6 +7,9 @@ const colours = { io: 60, procedures: 290, time: 140, + text: 160, + variables: 330, + audio: 250, } diff --git a/src/components/Blockly/helpers/types.js b/src/components/Blockly/helpers/types.js index 72feab0..339d033 100644 --- a/src/components/Blockly/helpers/types.js +++ b/src/components/Blockly/helpers/types.js @@ -88,6 +88,9 @@ export const CHILD_BLOCK_MISSING = { compatibleTypes: [] } + +export const VARIABLE_TYPES = ['Number', 'String', 'Boolean', 'Colour']; + // /** // * Some Types have circular dependencies on their compatibilities, so add them // * after declaration. diff --git a/src/components/Blockly/toolbox/Toolbox.js b/src/components/Blockly/toolbox/Toolbox.js index db1fc3b..1d879e7 100644 --- a/src/components/Blockly/toolbox/Toolbox.js +++ b/src/components/Blockly/toolbox/Toolbox.js @@ -24,6 +24,11 @@ class Toolbox extends React.Component { + + + + + @@ -175,6 +180,7 @@ class Toolbox extends React.Component { + @@ -204,6 +210,17 @@ class Toolbox extends React.Component { + + + + + + + + + + + @@ -267,6 +284,17 @@ class Toolbox extends React.Component { + + + + + 220 + + + + + + `;