123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574 |
- /**
- * @license
- * Visual Blocks Editor
- *
- * Copyright 2012 Google Inc.
- * https://developers.google.com/blockly/
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- /**
- * @fileoverview Variable blocks for Blockly.
- * @author fraser@google.com (Neil Fraser)
- */
- 'use strict';
- goog.provide('Blockly.Blocks.variables');
- goog.require('Blockly.Blocks');
- Blockly.Blocks['variables_get'] = {
- /**
- * Block for variable getter.
- * @this Blockly.Block
- */
- init: function() {
- // this.initialized_type = 0; // for blockscad - to keep onchange from churning
- this.setHelpUrl(Blockly.Msg.VARIABLES_GET_HELPURL);
- this.setColour(Blockscad.Toolbox.HEX_VARIABLE);
- this.appendDummyInput()
- .appendField(new Blockly.FieldVariable(
- Blockly.Msg.VARIABLES_DEFAULT_NAME), 'VAR');
- this.setOutput(true);
- this.setTooltip(Blockly.Msg.VARIABLES_GET_TOOLTIP);
- this.contextMenuMsg_ = Blockly.Msg.VARIABLES_GET_CREATE_SET;
- // get my "type" from my corresponding variables_set block
- var all_of_them = Blockly.Variables.getInstances(this.getFieldValue('VAR'), this.workspace);
- // console.log(all_of_them);
- var found_it = 0;
- for (var i = 0; i < all_of_them.length; i++) {
- if (all_of_them[i].type == 'variables_set') {
- this.outputConnection.setCheck(all_of_them[i].myType_);
- // console.log("vars_get " + this.id + " was initialized to " + all_of_them[i].myType_);
- found_it = 1;
- break;
- }
- if (all_of_them[i].type == 'controls_for' || all_of_them[i].type == 'controls_for_chainhull') {
- this.outputConnection.setCheck(null);
- found_it = 1;
- }
- }
- if (!found_it) {
- // this has no variables_set block... Could be from a procedure.
- // since I don't know it's type, set it to null.
- // console.log("is there a variable instance from a procedure here?");
- this.outputConnection.setCheck(null);
- }
- },
- contextMenuType_: 'variables_set',
- // /**
- // * Return all variables referenced by this block.
- // * @return {!Array.<string>} List of variable names.
- // * @this Blockly.Block
- // */
- // getVars: function() {
- // return [this.getFieldValue('VAR')];
- // },
- // /**
- // * Notification that a variable is renaming.
- // * If the name matches one of this block's variables, rename it.
- // * @param {string} oldName Previous name of variable.
- // * @param {string} newName Renamed variable.
- // * @this Blockly.Block
- // */
- // renameVar: function(oldName, newName) {
- // if (Blockly.Names.equals(oldName, this.getFieldValue('VAR'))) {
- // this.setFieldValue(newName, 'VAR');
- // }
- // },
- /**
- * onchange: happens on EVERY WORKSPACE CHANGE
- * because I need to type variables_get blocks before the user
- * has a chance to try plugging them in
- * - could I do this code during init? Would that make sense?
- */
- // onchange: function() {
- // if (this.initialized_type == 0) {
- // // console.log("initializing a new variables_get: id ", this.id);
- // this.initialized_type = 1;
- // // get my "type" from my corresponding variables_set block
- // var all_of_them = Blockly.Variables.getInstances(this.getFieldValue('VAR'), this.workspace);
- // var found_it = 0;
- // for (var i = 0; i < all_of_them.length; i++) {
- // if (all_of_them[i].type == 'variables_set') {
- // this.outputConnection.setCheck(all_of_them[i].myType_);
- // console.log("vars_get " + this.id + " was initialized to " + all_of_them[i].myType_);
- // found_it = 1;
- // break;
- // }
- // if (all_of_them[i].type == 'controls_for' || all_of_them[i].type == 'controls_for_chainhull') {
- // this.outputConnection.setCheck(null);
- // found_it = 1;
- // }
- // }
- // if (!found_it) {
- // // this has no variables_set block... Could be from a procedure.
- // // since I don't know it's type, set it to null.
- // // console.log("is there a variable instance from a procedure here?");
- // this.outputConnection.setCheck(null);
- // }
- // }
- // },
- /**
- * Add menu option to create getter/setter block for this setter/getter.
- * @param {!Array} options List of menu options to add to.
- * @this Blockly.Block
- */
- customContextMenu: function(options) {
- var option = {enabled: true};
- var name = this.getFieldValue('VAR');
- option.text = this.contextMenuMsg_.replace('%1', name);
- var xmlField = goog.dom.createDom('field', null, name);
- xmlField.setAttribute('name', 'VAR');
- var xmlBlock = goog.dom.createDom('block', null, xmlField);
- xmlBlock.setAttribute('type', this.contextMenuType_);
- option.callback = Blockly.ContextMenu.callbackFactory(this, xmlBlock);
- options.push(option);
-
- // for BlocksCAD,
- var option = {enabled: true};
- option.text = Blockscad.Msg.HIGHLIGHT_INSTANCES.replace("%1", name);
- var workspace = this.workspace;
- var thisVar = this;
- option.callback = function() {
- var instances = Blockly.Variables.getInstances(name,workspace);
- workspace.clearBacklight();
- thisVar.unselect();
- for (var i = 0; instances && i < instances.length; i++) {
- instances[i] && instances[i].backlight();
- // if caller block is in a collapsed parent, highlight collapsed parent too
- var others = instances[i].collapsedParents();
- if (others)
- for (var j=0; j < others.length; j++)
- others[j].backlight();
- }
- };
- options.push(option);
- }
- };
- Blockly.Blocks['variables_set'] = {
- /**
- * Block for variable setter.
- * @this Blockly.Block
- */
- init: function() {
- this.myType_ = null; // for blocksCAD
- this.backlightBlocks = []; // for blocksCAD
- this.jsonInit({
- "message0": Blockly.Msg.VARIABLES_SET,
- "args0": [
- {
- "type": "field_variable",
- "name": "VAR",
- "variable": Blockly.Msg.VARIABLES_DEFAULT_NAME
- },
- {
- "type": "input_value",
- "name": "VALUE"
- }
- ],
- "inputsInline": true
- });
- this.setHelpUrl(Blockly.Msg.VARIABLES_SET_HELPURL);
- this.setColour(Blockscad.Toolbox.HEX_VARIABLE);
- // this.setPreviousStatement(true,['VariableSet']);
- // this.setNextStatement(true, ['VariableSet','CAG','CSG']);
- this.setPreviousStatement(true);
- this.setNextStatement(true);
- this.setTooltip(Blockly.Msg.VARIABLES_SET_TOOLTIP);
- this.contextMenuMsg_ = Blockly.Msg.VARIABLES_SET_CREATE_GET;
- },
- contextMenuType_: 'variables_get',
- // g
- // * Return all variables referenced by this block.
- // * @return {!Array.<string>} List of variable names.
- // * @this Blockly.Block
-
- // getVars: function() {
- // return [this.getFieldValue('VAR')];
- // },
- /**
- * if this variable is set to a value, set the associated variable blocks to
- * the type of the value block.
- * @this Blockly.Block
- */
- // setType: function(type) { // for blocksCAD
- // console.log("in variable_set setType: old:" + this.myType_ + " and new:" + type);
- // if (!this.workspace) {
- // // Block has been deleted.
- // return;
- // }
- // if (this.myType_ == type) {
- // console.log("type didn't actually change. Returning without doing work.");
- // return;
- // }
- // var oldtype = this.myType_;
- // // var instances = this.getVars();
- // var instances = Blockly.Variables.getInstances(this.getFieldValue('VAR'), this.workspace);
- // var numBumped = [];
- // var parentAccepts;
- // // go through instances, pulling out the variables_get blocks.
- // // if the variables have a parent block, they might need to get bumped
- // // console.log("firing events now - something should have been bumped");
- // // lets get the group event
- // var eventGroup = true;
- // if (Blockscad.workspace.undoStack_.length)
- // eventGroup = Blockscad.workspace.undoStack_[Blockscad.workspace.undoStack_.length - 1].group;
- // // console.log("event group is: ", eventGroup);
- // Blockly.Events.setGroup(eventGroup);
- // if (instances.length > 0) {
- // for (var i = 0; i < instances.length; i++) {
- // // console.log("found an instance: ", instances[i].id , " ", instances[i].type);
- // if (instances[i].type != "variables_get")
- // continue;
- // var parent = instances[i].getParent();
- // if (type != null) {
- // // this is a variables_get block, so the parent is the block connected
- // // to the output connection. let's handle any bumpage that occurs.
- // if (parent) {
- // // console.log("found instance with parent: ", parent.type);
- // parentAccepts = instances[i].outputConnection.targetConnection.check_;
- // if (parentAccepts != null)
- // parentAccepts = parentAccepts[0];
- // // console.log("types parent accepts: ",parentAccepts);
- // // take care of bumps
- // if (parentAccepts != null && parentAccepts != type[0]) {
- // // I have a type mismatch with this variable. it is going to be bumped.
- // // console.log("block " + instances[i].id + " will be kicked out.");
- // numBumped.push(instances[i]);
- // // instances[i].backlight();
- // // this.backlightBlocks.push(instances[i].id);
- // // if the instance is in a collapsed stack, find collapsed parent and expand
- // var topBlock = instances[i].collapsedParents();
- // if (topBlock)
- // for (var j = 0; j < topBlock.length; j++)
- // topBlock[j].setCollapsed(false);
- // }
- // } // end if (parent)
- // } // end if type == null
- // // actually set the type here
- // // console.log("setting block :" + instances[i].id + " to type " + type);
- // instances[i].outputConnection.setCheck(type);
- // if (Blockly.Events.isEnabled() && numBumped.length) {
- // Blockly.Events.fire(new Blockly.Events.Typing(instances[i], oldtype,type));
- // }
- // // what if a parent is a variables_set of a different variable?
- // // then I want to call Blockscad.assignVarTypes for that parent.
- // if (parent && parent.type == "variables_set") {
- // // console.log("found a variables_set parent from inside variables code");
- // console.log("setting var_set type in loopable area");
- // this.myType_ = type;
- // Blockscad.assignVarTypes(parent);
- // }
- // } // end looping through instances
- // } // end if instances.length > 0
- // Blockly.Events.setGroup(false);
-
- // if (numBumped.length) {
- // // I've already changed the types, so bumping should have happened. Now do the
- // // backlighting and warning text.
- // for (var i = 0; i < numBumped.length; i++) {
- // numBumped[i].backlight();
- // this.backlightBlocks.push(numBumped[i].id);
- // }
- // var text = '';
- // // text += numBumped.length + " ";
- // // took out the name so I wouldn't have to deal with renaming the proc.
- // text += Blockscad.Msg.VARIABLES_BUMPED_ONE.replace("%1", numBumped.length) + '\n';
- // text += Blockscad.Msg.VARIABLES_BUMPED_TWO.replace("%1",this.getFieldValue('VAR')).replace("%2", parentAccepts).replace("%3", type[0]);
- // this.setWarningText(text);
- // }
- // else
- // this.setWarningText(null);
- // // set the variables_set type - important for stopping infinite typing loops
- // console.log("setting variable set type");
- // this.myType_ = type;
- // }, // end for blocksCAD
- setType: function(type) { // for blocksCAD
- if (!this.workspace) {
- // Block has been deleted.
- return;
- }
- if (type != null && !goog.isArray(type)) {
- type = [type];
- }
- // console.log("in variable_set setType: old:" + this.myType_ + " and new:" + type);
- if (Blockscad.arraysEqual(type, this.myType_)) {
- // console.log("type didn't actually change. Returning without doing work.");
- return;
- }
- var oldtype = this.myType_;
- // set the type of the setter.
- this.myType_ = type;
- var instances = Blockly.Variables.getInstances(this.getFieldValue('VAR'), this.workspace);
- var numBumped = [];
- var parentAccepts;
- // go through instances, pulling out the variables_get blocks.
- // if the variables have a parent block, they might need to get bumped
- // Group the events during bumping so undo will work as a unit.
- var eventGroup = true;
- if (Blockscad.workspace.undoStack_.length)
- eventGroup = Blockscad.workspace.undoStack_[Blockscad.workspace.undoStack_.length - 1].group;
- // console.log("event group is: ", eventGroup);
- Blockly.Events.setGroup(eventGroup);
- if (instances.length > 0) {
- for (var i = 0; i < instances.length; i++) {
- // console.log("found an instance: ", instances[i].id , " ", instances[i].type);
- if (instances[i].type != "variables_get")
- continue;
- var parent = instances[i].getParent();
- if (this.myType_ != null) {
- // this is a variables_get block, so the parent is the block connected
- // to the output connection. let's handle any bumpage that occurs.
- if (parent) {
- // console.log("found instance with parent: ", parent.type);
- parentAccepts = instances[i].outputConnection.targetConnection.check_;
- if (parentAccepts != null)
- parentAccepts = parentAccepts[0];
- // console.log("Test for bumping. types were: " + parentAccepts + " and " + type[0]);
- // take care of bumps
- if (parentAccepts != null && type != null && parentAccepts != type[0]) {
- // console.log(" variable block " + instances[i].id + " will be kicked out.");
- // console.log("parent accepts: " + parentAccepts + ", type is:", type);
- numBumped.push(instances[i]);
- // if the instance is in a collapsed stack, find collapsed parent and expand
- var topBlock = instances[i].collapsedParents();
- if (topBlock)
- for (var j = 0; j < topBlock.length; j++)
- topBlock[j].setCollapsed(false);
- }
- } // end if (parent)
- } // end if type == null
- // actually set the caller's type here
- // console.log("setting block :" + instances[i].id + " to type " + type);
- instances[i].outputConnection.setCheck(type);
- if (Blockly.Events.isEnabled() && numBumped.length) {
- Blockly.Events.fire(new Blockly.Events.Typing(instances[i], oldtype,type));
- }
- // console.log("trying to call hasParentOfType",callers[i]);
- // caller has a parent that is a setter - either a variable or a function definition.
- var setterParent = Blockscad.hasParentOfType(instances[i], "procedures_defreturn");
- if (!setterParent)
- setterParent = Blockscad.hasParentOfType(instances[i],"variables_set");
- // Be careful here. Even if you have a setter parent, if there is a ternary parent,
- // it will _change_ your type from boolean to number. Don't set your setter parent's
- // type to boolean!
- // of course, right now ternary typing is borked anyway, because it ALWAYS returns a number.
- // though you really should be able to have shapes, text, etc coming out of that.
- // but for now, I'm just going to ignore setting a type if a ternary parent is involved.
- var ternaryParent = Blockscad.hasParentOfType(instances[i], "logic_ternary");
- setTimeout(function() {
- // console.log("this caller function is inside a setter. Set its type to: ",type);
- if (setterParent && !ternaryParent) setterParent.setType(type);
- }, 0);
- } // end looping through instances
- } // end if instances.length > 0
- Blockly.Events.setGroup(false);
-
- if (numBumped.length) {
- // I've already changed the types, so bumping should have happened. Now do the
- // backlighting and warning text.
- for (var i = 0; i < numBumped.length; i++) {
- numBumped[i].backlight();
- this.backlightBlocks.push(numBumped[i].id);
- }
- var text = '';
- // text += numBumped.length + " ";
- // took out the name so I wouldn't have to deal with renaming the proc.
- text += Blockscad.Msg.VARIABLES_BUMPED_ONE.replace("%1", numBumped.length) + '\n';
- text += Blockscad.Msg.VARIABLES_BUMPED_TWO.replace("%1",this.getFieldValue('VAR')).replace("%2", parentAccepts).replace("%3", type);
- this.setWarningText(text);
- }
- else
- this.setWarningText(null);
- }, // end for blocksCAD
- // setType: function(type, drawMe) {
- // if (!this.workspace) {
- // // Block has been deleted.
- // return;
- // }
- // // // compare to see if type matches this.myType_
- // var oldtype = this.myType_;
- // var ret = this.getInput('RETURN');
- // // console.log("in setType for function. here is the input:",ret);
- // if (ret.connection.targetConnection) {
- // if (ret.connection.targetConnection.check_ == 'Number')
- // type = 'Number';
- // else if (ret.connection.targetConnection.check_ == 'Boolean')
- // type = 'Boolean';
- // else if (ret.connection.targetConnection.check_ == 'String')
- // type = 'String';
- // else
- // type = null;
- // }
- // else type = null;
- // // console.log("starting func ST with oldtype:" + this.myType_ + " and newtype:" + type);
- // if (this.myType_ == type) {
- // console.log("in func ST. returning because types didn't change.");
- // return;
- // }
- // // set the function def's type to what is now connected to its output
- // this.myType_ = type;
- // var callers = Blockly.Procedures.getCallers(this.getFieldValue('NAME'), this.workspace);
- // var numBumped = [];
- // var conType = null; // type of a caller's output connection
- // var parentAccepts;
- // // start grouping events in case some blocks are bumped out, so that undo will work easily.
- // var eventGroup = true;
- // if (Blockscad.workspace.undoStack_.length)
- // eventGroup = Blockscad.workspace.undoStack_[Blockscad.workspace.undoStack_.length - 1].group;
- // // console.log("event group is: ", eventGroup);
- // Blockly.Events.setGroup(eventGroup);
- // // now, set my caller block's types
- // if (callers.length) {
- // for (var i = 0; i < callers.length; i++) {
- // // the caller block only gets bumped if it has a parent.
- // var parent = callers[i].getParent();
- // // get caller's connection type here
- // if (parent) {
- // // console.log("found instance with parent: ", parent.type);
- // parentAccepts = callers[i].outputConnection.targetConnection.check_;
- // if (parentAccepts != null && goog.isArray(parentAccepts))
- // parentAccepts = parentAccepts[0];
- // var callerAccepts = callers[i].outputConnection.check_;
- // // take care of bumps
- // if (parentAccepts != null && this.myType_ != null && parentAccepts != this.myType_) {
- // // I have a type mismatch with this variable. it is going to be bumped.
- // // console.log("warning message! call block id", callers[i].id, "will be kicked out and backlit");
- // numBumped.push(callers[i]);
- // // instances[i].backlight();
- // // this.backlightBlocks.push(instances[i].id);
- // // if the instance is in a collapsed stack, find collapsed parent and expand
- // var topBlock = callers[i].collapsedParents();
- // if (topBlock)
- // for (var j = 0; j < topBlock.length; j++)
- // topBlock[j].setCollapsed(false);
- // }
- // } // end if (parent)
- // // change caller's type - this is the command that actually prompts Blockly to bump blocks out
- // // console.log("Set the caller's output check to ", this.myType_);
- // callers[i].outputConnection.setCheck(this.myType_);
- // if (this.myType_ == 'Number')
- // callers[i].category = 'NUMBER'
- // else if (this.myType_ == 'Boolean')
- // callers[i].category = 'BOOLEAN';
- // else if (this.myType_ == 'String')
- // callers[i].category == 'STRING';
- // else callers[i].category = 'UNKNOWN';
- // // console.log("tried to set caller type to ",this.myType_, callers[i]);
- // // if it was a bumping change, fire a typing event
- // if (Blockly.Events.isEnabled() && numBumped.length) {
- // Blockly.Events.fire(new Blockly.Events.Typing(callers[i], oldtype,type));
- // }
- // // if caller is inside of another setter block, that setter's type needs to be changed. Do so.
- // // note that this can lead to an infinite loop if procedures are circularly defined - that is why
- // // setType MUST exit immediately if it is called with the type not changing.
- // // what if a parent is a variables_set of a different variable?
- // // then I want to call Blockscad.assignVarTypes for that parent.
- // // console.log("trying to call hasParentOfType",callers[i]);
- // var setterParent = Blockscad.hasParentOfType(callers[i], "procedures_defreturn");
- // if (!setterParent)
- // setterParent = Blockscad.hasParentOfType(callers[i],"variables_set");
- // if (setterParent) {
- // setTimeout(function() {
- // console.log("this caller function is inside a setter. Set its type to: ",type);
- // setterParent.setType(type);
- // }, 0);
- // }
- // }
- // } // end of going through all callers to set their types.
- // // turn off event grouping
- // Blockly.Events.setGroup(false);
- // // handle backlighting and warning text - do this later so that
- // // the bumping process itself (which now selects and deselects the blocks) doesn't
- // // just immediately turn the backlighting off.
- // for (var k = 0; k < numBumped.length; k++) {
- // numBumped[k].backlight();
- // this.backlightBlocks.push(numBumped[k].id);
- // // finally, set a warning message on the procedure definition that counts how many callers were bumped.
- // var text = '';
- // text += Blockscad.Msg.BLOCKS_BUMPED_OUT_TYPES.replace("%1", numBumped.length).replace("%2", parentAccepts).replace("%3",type);
- // this.setWarningText(text);
- // }
- // },
- /**
- * Notification that a variable is renaming.
- * If the name matches one of this block's variables, rename it.
- * @param {string} oldName Previous name of variable.
- * @param {string} newName Renamed variable.
- * @this Blockly.Block
- */
- // renameVar: function(oldName, newName) {
- // if (Blockly.Names.equals(oldName, this.getFieldValue('VAR'))) {
- // this.setFieldValue(newName, 'VAR');
- // }
- // },
- customContextMenu: Blockly.Blocks['variables_get'].customContextMenu
- };
|