1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474 |
- /**
- * @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 Procedure blocks for Blockly.
- * @author fraser@google.com (Neil Fraser)
- */
- 'use strict';
- goog.provide('Blockly.Blocks.procedures');
- goog.require('Blockly.Blocks');
- Blockly.Blocks['procedures_defnoreturn'] = {
- /**
- * Block for defining a procedure with no return value.
- * @this Blockly.Block
- */
- init: function() {
- this.category = 'PROCEDURE'; // for blocksCAD
- this.myType_ = ['CSG','CAG']; // for blocksCAD
- this.backlightBlocks = []; // for blocksCAD
- var nameField = new Blockly.FieldTextInput(
- Blockly.Msg.PROCEDURES_DEFNORETURN_PROCEDURE,
- Blockly.Procedures.rename);
- nameField.setSpellcheck(false);
- this.appendDummyInput()
- .appendField(Blockly.Msg.PROCEDURES_DEFNORETURN_TITLE)
- .appendField(nameField, 'NAME')
- .appendField('', 'PARAMS');
- this.setMutator(new Blockly.Mutator(['procedures_mutatorarg']));
- this.setHelpUrl(Blockly.Msg.PROCEDURES_DEFNORETURN_HELPURL);
- this.setColour(Blockscad.Toolbox.HEX_PROCEDURE);
- this.setTooltip(Blockly.Msg.PROCEDURES_DEFNORETURN_TOOLTIP);
- this.arguments_ = [];
- this.setStatements_(true, 'VariableSet');
- this.statementConnection_ = null;
- },
- /**
- * if this procedure has statements, use them to determine the
- * type of this procedure, then update types of any callers..
- * @this Blockly.Block
- */
- // setType: function(type,drawMe) { // for blocksCAD
- // if (!this.workspace) {
- // // Block has been deleted.
- // return;
- // }
- // console.log("starting proc ST with oldtype:" + this.myType_ + " and newtype:" + type);
- // if (this.myType_ == type)
- // return;
- // console.log("in modules's setType");
- // var oldtype = this.myType_;
- // var callers = Blockly.Procedures.getCallers(this.getFieldValue('NAME'), this.workspace);
- // var numBumped = [];
- // var notBumped = [];
- // // I need to find out what my caller stacks think their types are.
- // if (callers.length) {
- // for (var i = 0; i < callers.length; i++) {
- // var areaType = Blockscad.findBlockType(callers[i],callers);
- // //console.log("caller area type is",areaType);
- // //console.log("caller category is", callers[i].category);
- // // console.log("parent type is changing to",type);
- // if (!goog.isArray(type) && areaType != 'EITHER' && areaType != type) {
- // // call blocks are going to be kicked out.
- // // console.log("warning message! call block id", callers[i].id, "will be kicked out and backlit");
- // numBumped.push(callers[i]);
- // // If the call block is in a collapsed stack, find the collapsed parent and expand them.
- // var topBlock = callers[i].collapsedParents();
- // if (topBlock)
- // for (var j=0; j < topBlock.length; j++)
- // topBlock[j].setCollapsed(false);
- // }
- // else notBumped.push(callers[i]);
- // }
- // }
- // if (numBumped.length) {
- // var text = '';
- // // text += numBumped.length + " ";
- // // took out the name so I wouldn't have to deal with renaming the proc.
- // //text += this.getFieldValue('NAME') + " ";
- // text += Blockscad.Msg.BLOCKS_BUMPED_OUT_DIMENSIONS.replace("%1", numBumped.length);
- // this.setWarningText(text);
- // }
- // this.myType_ = type;
- // // some of my callers don't need to be bumped. I'll set their category to "BLAH"
- // // temporarily (note this is NOT a valid category),
- // // reset the types of the blocks around them, then set them to their new type.
- // // this should prevent them getting bumped out incorrectly.
- // // if (notBumped.length) {
- // // for (var j = 0; j < notBumped.length; j++) {
- // // notBumped[j].category = 'BLAH';
- // // notBumped[j].previousConnection.setCheck(['CSG','CAG']);
- // // }
- // // for (j = 0; j < notBumped.length; j++) {
- // // console.log("in proc set_type, calling assignBT with BLAH");
- // // this.myType_ = type;
- // // Blockscad.assignBlockTypes([notBumped[j]]);
- // // }
- // // }
- // // this section actually re-sets the type that triggers the bumping. This needs to be done before backlighting.
- // // to make undo work, I need to set the group of the next events.
- // if (numBumped.length) {
- // // 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 (callers.length > 0) {
- // for (var i = 0; i < callers.length; i++) {
- // callers[i].previousConnection.setCheck(type);
- // // if I'm bumping something, I need to put the typing event into the undoStack_
- // // so that on undo the caller doesn't get immediately bumped out again!
- // // So first I set the check (which will prompt the bump) THEN fire the type event
- // // so that when it is run backwards I untype first then move back into place.
- // if (Blockly.Events.isEnabled() && numBumped.length) {
- // Blockly.Events.fire(new Blockly.Events.Typing(callers[i], oldtype,type));
- // }
- // if (type == 'CSG')
- // callers[i].category = 'PRIMITIVE_CSG'
- // else if (type == 'CAG')
- // callers[i].category = 'PRIMITIVE_CAG';
- // else callers[i].category = 'UNKNOWN';
- // // if the top block isn't the procedure definition (recursion!), then assign their types
- // var topBlock = callers[i].getRootBlock();
- // if (!(topBlock.category && topBlock.category == 'PROCEDURE')) {
- // console.log("calling assignBlockTypes from proc ST (this is prob the bad one");
- // this.myType_ = type;
- // Blockscad.assignBlockTypes([callers[i]]);
- // }
- // }
- // }
- // // // the system will be done now with unplugging all the blocks that need it.
- // // set the backlighting and warning message here (with a delay) so that the events that occur during the
- // // bumping don't overwrite the backlighting of the caller blocks.
- // for (var k = 0; k < numBumped.length; k++) {
- // numBumped[k].backlight();
- // this.backlightBlocks.push(numBumped[k].id);
- // }
- // if (numBumped.length) {
- // // Blockly.Events.Filter
- // Blockly.Events.setGroup(false);
- // }
- // // events aren't all getting the group setting. Walk back through the undoStack_ and make sure the group is set.
- // // for (var i = Blockscad.workspace.undoStack_.length - 1; i > 0; i--) {
- // // if
- // // }
- // this.myType_ = type;
- // }, // end for blocksCAD
- // // for BlocksCAD - check to see if my callers are still backlight?
- // onchange: function() {
- // var found_it;
- // // go through my backlight id list, see if I have any blocks on it that are not on
- // // the general backlight list (they must have been unhighlighted!)
- // for (var i=0; i < this.backlightBlocks.length; i++) {
- // found_it = 0;
- // for (var j=0; j<Blockly.backlight.length; j++) {
- // if (this.backlightBlocks[i] === Blockly.backlight[j]) {
- // found_it = 1;
- // break;
- // }
- // }
- // if (!found_it) { // this block needs to come off our list
- // this.backlightBlocks.splice(i,1);
- // }
- // }
- // if (!this.backlightBlocks.length) {
- // // console.log("turning off warning text");
- // this.setWarningText(null);
- // }
- // },
- // second stab at setType.
- setType: function(type, drawMe) {
- if (!this.workspace) {
- // Block has been deleted.
- return;
- }
- // console.log("starting proc ST with oldtype:" + this.myType_ + " and newtype:" + type);
- // console.log("arrays: " + goog.isArray(this.myType_) + ', ' + goog.isArray(type));
- if (!goog.isArray(type))
- type = [type];
- // compare to see if type matches this.myType_
- if (Blockscad.arraysEqual(type, this.myType_))
- return;
- // console.log("in modules's setType");
- var oldtype = this.myType_;
- var callers = Blockly.Procedures.getCallers(this.getFieldValue('NAME'), this.workspace);
- var numBumped = [];
- // first, set my type (the module definition's type)
- this.myType_ = type;
- // 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++) {
- // find what the type is of the stack the caller is in.
- var areaType = Blockscad.findBlockType(callers[i],callers);
- // if the stack's type doesn't match the caller's new type, bumpage!
- // mark that block that will be bumped
- if (areaType != 'EITHER' && areaType != type[0]) {
- // console.log("warning message! call block id", callers[i].id, "will be kicked out and backlit");
- // console.log("parent accepts: " + parentAccepts + ", type is:", type[0]);
- numBumped.push(callers[i]);
- // If the call block is in a collapsed stack, find the collapsed parent and expand them.
- var topBlock = callers[i].collapsedParents();
- if (topBlock)
- for (var j=0; j < topBlock.length; j++)
- topBlock[j].setCollapsed(false);
- }
- // change caller's type - this is the command that actually prompts Blockly to bump blocks out
- callers[i].previousConnection.setCheck(type);
- // 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));
- }
- // procedure callers also have a "category" because once typed they are a shape
- // CSG, CAG, or UNKNOWN.
- if (type[0] == 'CSG' && type.length == 1)
- callers[i].category = 'PRIMITIVE_CSG'
- else if (type[0] == 'CAG')
- callers[i].category = 'PRIMITIVE_CAG';
- else callers[i].category = 'UNKNOWN';
- // 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.
- var setterParent = Blockscad.hasParentOfType(callers[i], "procedures_defnoreturn");
- if (setterParent) {
- setTimeout(function() {
- // console.log("this caller is inside a setter: ", setterParent.id);
- if (setterParent) setterParent.setType(type);
- }, 0);
- }
- // if the caller was inside a non setter, I still want to type that parent.
- var parent = callers[i].getParent();
- if (parent) {
- Blockscad.assignBlockTypes(parent)
- }
- }
- } // 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++) {
- // console.log("backlighting a block:", numBumped[k].id);
- 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_DIMENSIONS.replace("%1", numBumped.length);
- this.setWarningText(text);
- }
- },
- /**
- * Add or remove the statement block from this function definition.
- * @param {boolean} hasStatements True if a statement block is needed.
- * @this Blockly.Block
- */
- setStatements_: function(hasStatements) {
- if (this.hasStatements_ === hasStatements) {
- return;
- }
- if (hasStatements) {
- this.appendStatementInput('STACK')
- .appendField(Blockly.Msg.PROCEDURES_DEFNORETURN_DO);
- if (this.getInput('RETURN')) {
- this.moveInputBefore('STACK', 'RETURN');
- }
- } else {
- this.removeInput('STACK', true);
- }
- this.hasStatements_ = hasStatements;
- },
- /**
- * Update the display of parameters for this procedure definition block.
- * Display a warning if there are duplicately named parameters.
- * @private
- * @this Blockly.Block
- */
- updateParams_: function() {
- // Check for duplicated arguments.
- var badArg = false;
- var hash = {};
- for (var i = 0; i < this.arguments_.length; i++) {
- if (hash['arg_' + this.arguments_[i].toLowerCase()]) {
- badArg = true;
- break;
- }
- hash['arg_' + this.arguments_[i].toLowerCase()] = true;
- }
- if (badArg) {
- this.setWarningText(Blockly.Msg.PROCEDURES_DEF_DUPLICATE_WARNING);
- } else {
- this.setWarningText(null);
- }
- // Merge the arguments into a human-readable list.
- var paramString = '';
- if (this.arguments_.length) {
- paramString = Blockly.Msg.PROCEDURES_BEFORE_PARAMS +
- ' ' + this.arguments_.join(', ');
- }
- // The params field is deterministic based on the mutation,
- // no need to fire a change event.
- Blockly.Events.disable();
- try {
- this.setFieldValue(paramString, 'PARAMS');
- } finally {
- Blockly.Events.enable();
- }
- },
- /**
- * Create XML to represent the argument inputs.
- * @param {=boolean} opt_paramIds If true include the IDs of the parameter
- * quarks. Used by Blockly.Procedures.mutateCallers for reconnection.
- * @return {!Element} XML storage element.
- * @this Blockly.Block
- */
- mutationToDom: function(opt_paramIds) {
- var container = document.createElement('mutation');
- if (opt_paramIds) {
- container.setAttribute('name', this.getFieldValue('NAME'));
- }
- for (var i = 0; i < this.arguments_.length; i++) {
- var parameter = document.createElement('arg');
- parameter.setAttribute('name', this.arguments_[i]);
- if (opt_paramIds && this.paramIds_) {
- parameter.setAttribute('paramId', this.paramIds_[i]);
- }
- container.appendChild(parameter);
- }
- // Save whether the statement input is visible.
- if (!this.hasStatements_) {
- container.setAttribute('statements', 'false');
- }
- return container;
- },
- /**
- * Parse XML to restore the argument inputs.
- * @param {!Element} xmlElement XML storage element.
- * @this Blockly.Block
- */
- domToMutation: function(xmlElement) {
- this.arguments_ = [];
- for (var i = 0, childNode; childNode = xmlElement.childNodes[i]; i++) {
- if (childNode.nodeName.toLowerCase() == 'arg') {
- this.arguments_.push(childNode.getAttribute('name'));
- }
- }
- this.updateParams_();
- Blockly.Procedures.mutateCallers(this);
- // Show or hide the statement input.
- this.setStatements_(xmlElement.getAttribute('statements') !== 'false');
- },
- /**
- * Populate the mutator's dialog with this block's components.
- * @param {!Blockly.Workspace} workspace Mutator's workspace.
- * @return {!Blockly.Block} Root block in mutator.
- * @this Blockly.Block
- */
- decompose: function(workspace) {
- var containerBlock = workspace.newBlock('procedures_mutatorcontainer');
- containerBlock.initSvg();
- // Check/uncheck the allow statement box.
- // for blocksCAD - take out the if statements here so that we always don't show the
- // statement checkbox in the mutator. both statements required.
- containerBlock.setFieldValue(this.hasStatements_ ? 'TRUE' : 'FALSE',
- 'STATEMENTS');
- containerBlock.getInput('STATEMENT_INPUT').setVisible(false);
- // Parameter list.
- var connection = containerBlock.getInput('STACK').connection;
- for (var i = 0; i < this.arguments_.length; i++) {
- var paramBlock = workspace.newBlock('procedures_mutatorarg');
- paramBlock.initSvg();
- paramBlock.setFieldValue(this.arguments_[i], 'NAME');
- // Store the old location.
- paramBlock.oldLocation = i;
- connection.connect(paramBlock.previousConnection);
- connection = paramBlock.nextConnection;
- }
- // Initialize procedure's callers with blank IDs.
- Blockly.Procedures.mutateCallers(this);
- return containerBlock;
- },
- /**
- * Reconfigure this block based on the mutator dialog's components.
- * @param {!Blockly.Block} containerBlock Root block in mutator.
- * @this Blockly.Block
- */
- compose: function(containerBlock) {
- // Parameter list.
- this.arguments_ = [];
- this.paramIds_ = [];
- var paramBlock = containerBlock.getInputTargetBlock('STACK');
- while (paramBlock) {
- this.arguments_.push(paramBlock.getFieldValue('NAME'));
- this.paramIds_.push(paramBlock.id);
- paramBlock = paramBlock.nextConnection &&
- paramBlock.nextConnection.targetBlock();
- }
- this.updateParams_();
- Blockly.Procedures.mutateCallers(this);
- // Show/hide the statement input.
- var hasStatements = containerBlock.getFieldValue('STATEMENTS');
- if (hasStatements !== null) {
- hasStatements = hasStatements == 'TRUE';
- if (this.hasStatements_ != hasStatements) {
- if (hasStatements) {
- this.setStatements_(true);
- // Restore the stack, if one was saved.
- Blockly.Mutator.reconnect(this.statementConnection_, this, 'STACK');
- this.statementConnection_ = null;
- } else {
- // Save the stack, then disconnect it.
- var stackConnection = this.getInput('STACK').connection;
- this.statementConnection_ = stackConnection.targetConnection;
- if (this.statementConnection_) {
- var stackBlock = stackConnection.targetBlock();
- stackBlock.unplug();
- stackBlock.bumpNeighbours_();
- }
- this.setStatements_(false);
- }
- }
- }
- },
- /**
- * Return the signature of this procedure definition.
- * @return {!Array} Tuple containing three elements:
- * - the name of the defined procedure,
- * - a list of all its arguments,
- * - that it DOES NOT have a return value.
- * @this Blockly.Block
- */
- getProcedureDef: function() {
- // console.log("in getProcedureDef for noreturn for:",this.getFieldValue('NAME'));
- return [this.getFieldValue('NAME'), this.arguments_, false];
- },
- /**
- * Return all variables referenced by this block.
- * @return {!Array.<string>} List of variable names.
- * @this Blockly.Block
- */
- getVars: function() {
- return this.arguments_;
- },
- /**
- * 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) {
- var change = false;
- for (var i = 0; i < this.arguments_.length; i++) {
- if (Blockly.Names.equals(oldName, this.arguments_[i])) {
- this.arguments_[i] = newName;
- change = true;
- }
- }
- if (change) {
- this.updateParams_();
- // Update the mutator's variables if the mutator is open.
- if (this.mutator.isVisible()) {
- var blocks = this.mutator.workspace_.getAllBlocks();
- for (var i = 0, block; block = blocks[i]; i++) {
- if (block.type == 'procedures_mutatorarg' &&
- Blockly.Names.equals(oldName, block.getFieldValue('NAME'))) {
- block.setFieldValue(newName, 'NAME');
- }
- }
- }
- }
- },
- /**
- * Add custom menu options to this block's context menu.
- * @param {!Array} options List of menu options to add to.
- * @this Blockly.Block
- */
- customContextMenu: function(options) {
- // Add option to create caller.
- var option = {enabled: true};
- var name = this.getFieldValue('NAME');
- option.text = Blockly.Msg.PROCEDURES_CREATE_DO.replace('%1', name);
- var xmlMutation = goog.dom.createDom('mutation');
- xmlMutation.setAttribute('name', name);
- for (var i = 0; i < this.arguments_.length; i++) {
- var xmlArg = goog.dom.createDom('arg');
- xmlArg.setAttribute('name', this.arguments_[i]);
- xmlMutation.appendChild(xmlArg);
- }
- var xmlBlock = goog.dom.createDom('block', null, xmlMutation);
- xmlBlock.setAttribute('type', this.callType_);
- option.callback = Blockly.ContextMenu.callbackFactory(this, xmlBlock);
- options.push(option);
- // Add options to create getters for each parameter.
- if (!this.isCollapsed()) {
- for (var i = 0; i < this.arguments_.length; i++) {
- var option = {enabled: true};
- var name = this.arguments_[i];
- option.text = Blockly.Msg.VARIABLES_SET_CREATE_GET.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', 'variables_get');
- option.callback = Blockly.ContextMenu.callbackFactory(this, xmlBlock);
- options.push(option);
- }
- }
- // for BlocksCAD,
- var option = {enabled: true};
- var name = this.getFieldValue('NAME');
- option.text = Blockscad.Msg.HIGHLIGHT_INSTANCES.replace("%1", name);
- var workspace = this.workspace;
- option.callback = function() {
- var def = Blockly.Procedures.getDefinition(name, workspace);
- if (def) {
- var callers = Blockly.Procedures.getCallers(name, workspace);
- workspace.clearBacklight();
- Blockly.selected.unselect();
- for (var i = 0; callers && i < callers.length; i++) {
- callers[i] && callers[i].backlight();
- // if caller block is in a collapsed parent, highlight collapsed parent too
- var others = callers[i].collapsedParents();
- if (others)
- for (var j=0; j < others.length; j++)
- others[j].backlight();
- }
- }
- };
- options.push(option);
- },
- callType_: 'procedures_callnoreturn'
- };
- Blockly.Blocks['procedures_defreturn'] = {
- /**
- * Block for a blockSCAD function: no statements, a return value.
- *
- * @this Blockly.Block
- */
- init: function() {
- this.category = 'PROCEDURE'; // for blockscad
- this.myType_ = null; // for blocksCAD
- this.backlightBlocks = []; // for blocksCAD
- var nameField = new Blockly.FieldTextInput(
- Blockly.Msg.PROCEDURES_DEFRETURN_PROCEDURE,
- Blockly.Procedures.rename);
- nameField.setSpellcheck(false);
- this.appendDummyInput()
- .appendField(Blockly.Msg.PROCEDURES_DEFRETURN_TITLE)
- .appendField(nameField, 'NAME')
- .appendField('', 'PARAMS');
- this.appendValueInput('RETURN')
- .setAlign(Blockly.ALIGN_RIGHT)
- .appendField(Blockly.Msg.PROCEDURES_DEFRETURN_RETURN);
- this.setMutator(new Blockly.Mutator(['procedures_mutatorarg']));
- this.setColour(Blockscad.Toolbox.HEX_PROCEDURE);
- this.setTooltip(Blockly.Msg.PROCEDURES_DEFRETURN_TOOLTIP);
- this.setHelpUrl(Blockly.Msg.PROCEDURES_DEFRETURN_HELPURL);
- this.arguments_ = [];
- this.setStatements_(false); // set false for blockscad - jayod
- this.statementConnection_ = null;
- },
- /**
- * if this procedure has statements, use them to determine the
- * type of this procedure, then update types of any callers..
- * @this Blockly.Block
- */
- // setType: function(type,drawMe) { // for blocksCAD
- // if (!this.workspace) {
- // // Block has been deleted.
- // return;
- // }
- // 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')
- // this.myType_ = ret.connection.check_ = 'Number';
- // else if (ret.connection.targetConnection.check_ == 'Boolean')
- // this.myType_ = ret.connection.check_ = 'Boolean';
- // }
- // else this.myType_ = ret.connection.check_ = null;
- // var callers = Blockly.Procedures.getCallers(this.getFieldValue('NAME'), this.workspace);
- // var numBumped = [];
- // var conType = null;
- // // I need to find out what my caller stacks think their types are.
- // if (callers.length) {
- // for (var i = 0; i < callers.length; i++) {
- // // console.log("callers.length is:",callers.length);
- // // get caller's connection type here
- // if (callers[i].outputConnection.targetConnection)
- // conType = callers[i].outputConnection.targetConnection.check_;
- // if (!goog.isArray(conType)) conType = [conType];
- // // conType is an array.
- // // console.log("caller type is",conType);
- // // console.log(this.myType_);
- // if (this.myType_ && conType && conType.indexOf(this.myType_) == -1) {
- // // call blocks are going to be kicked out.
- // console.log("warning message! call block id", callers[i].id, "will be kicked out");
- // // there is a bug here - if we add to the numBumped stack, then we get an infinite loop. ???
- // // if (numBumped[numBumped.length] != callers[i])
- // // numBumped.push(callers[i]);
- // // If the call block is in a collapsed stack, find the collapsed parent and expand them.
- // var topBlock = callers[i].collapsedParents();
- // if (topBlock)
- // for (var j=0; j < topBlock.length; j++)
- // topBlock[j].setCollapsed(false);
- // }
- // }
- // }
- // if (numBumped.length) {
- // // console.log("blah");
- // var text = '';
- // // text += numBumped.length + " ";
- // // text += this.getFieldValue('NAME') + " ";
- // text += Blockscad.Msg.BLOCKS_BUMPED_OUT_TYPES.replace("%1", numBumped.length + " " + this.getFieldValue('NAME'));
- // this.setWarningText(text);
- // }
- // if (callers.length > 0) {
- // for (var i = 0; i < callers.length; i++) {
- // callers[i].outputConnection.setCheck(this.myType_);
- // if (this.myType_ == 'Number')
- // callers[i].category = 'NUMBER'
- // else if (this.myType_ == 'Boolean')
- // callers[i].category = 'BOOLEAN';
- // else callers[i].category = 'UNKNOWN';
- // // console.log("tried to set caller type to ",this.myType_, callers[i]);
- // }
- // }
- // // the system will be done now with unplugging all the blocks that need it.
- // // Time to fire a workspaceChanged() so our list of parentIDs will be current.
- // if (numBumped.length)
- // Blockscad.workspaceChanged();
- // }, // end for blocksCAD
- // second stab at setType.
- 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.connection);
- 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++) {
- if (!callers[i])
- continue;
- // 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_;
- // console.log(parentAccepts);
- // make sure that parentAccepts is an array so that we can check for a match
- if (parentAccepts && !(goog.isArray(parentAccepts)))
- parentAccepts = [parentAccepts];
- if (parentAccepts) {
- var found_match = 0;
- // check to see if my type matches any type accepted by the parent - if so, it will bump.
- for (var j = 0; j < parentAccepts.length; j++) {
- if (parentAccepts[j] == this.myType_) {
- found_match = 1;
- }
- }
- if (!found_match) {
- // 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");
- // console.log("parent accepts: " + parentAccepts + ", type is:", this.myType_);
- 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_);
- if (callers[i]) {
- 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("function caller with type 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.
- 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);
- }
- else {
- // if the caller was inside a non setter, I still want to type that parent.
- var parent = false;
- if (callers[i])
- parent = callers[i].getParent();
- if (parent) {
- Blockscad.assignBlockTypes(parent)
- }
- }
- }
- } // 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);
- }
- },
- setStatements_: Blockly.Blocks['procedures_defnoreturn'].setStatements_,
- updateParams_: Blockly.Blocks['procedures_defnoreturn'].updateParams_,
- mutationToDom: Blockly.Blocks['procedures_defnoreturn'].mutationToDom,
- domToMutation: Blockly.Blocks['procedures_defnoreturn'].domToMutation,
- decompose: Blockly.Blocks['procedures_defnoreturn'].decompose,
- compose: Blockly.Blocks['procedures_defnoreturn'].compose,
- /**
- * Return the signature of this procedure definition.
- * @return {!Array} Tuple containing three elements:
- * - the name of the defined procedure,
- * - a list of all its arguments,
- * - that it DOES have a return value.
- * @this Blockly.Block
- */
- getProcedureDef: function() {
- return [this.getFieldValue('NAME'), this.arguments_, true];
- },
- getVars: Blockly.Blocks['procedures_defnoreturn'].getVars,
- renameVar: Blockly.Blocks['procedures_defnoreturn'].renameVar,
- customContextMenu: Blockly.Blocks['procedures_defnoreturn'].customContextMenu,
- callType_: 'procedures_callreturn'
- };
- Blockly.Blocks['procedures_mutatorcontainer'] = {
- /**
- * Mutator block for procedure container.
- * @this Blockly.Block
- */
- init: function() {
- this.setColour(Blockscad.Toolbox.HEX_PROCEDURE);
- this.appendDummyInput()
- .appendField(Blockly.Msg.PROCEDURES_MUTATORCONTAINER_TITLE);
- this.appendStatementInput('STACK');
- this.appendDummyInput('STATEMENT_INPUT')
- .appendField(Blockly.Msg.PROCEDURES_ALLOW_STATEMENTS)
- .appendField(new Blockly.FieldCheckbox('TRUE'), 'STATEMENTS');
- this.setTooltip(Blockly.Msg.PROCEDURES_MUTATORCONTAINER_TOOLTIP);
- this.contextMenu = false;
- }
- };
- Blockly.Blocks['procedures_mutatorarg'] = {
- /**
- * Mutator block for procedure argument.
- * @this Blockly.Block
- */
- init: function() {
- this.setColour(Blockscad.Toolbox.HEX_PROCEDURE);
- this.appendDummyInput()
- .appendField(Blockly.Msg.PROCEDURES_MUTATORARG_TITLE)
- .appendField(new Blockly.FieldTextInput('x', this.validator_), 'NAME');
- this.setPreviousStatement(true);
- this.setNextStatement(true);
- this.setTooltip(Blockly.Msg.PROCEDURES_MUTATORARG_TOOLTIP);
- this.contextMenu = false;
- },
- /**
- * Obtain a valid name for the procedure.
- * Merge runs of whitespace. Strip leading and trailing whitespace.
- * Beyond this, all names are legal.
- * @param {string} newVar User-supplied name.
- * @return {?string} Valid name, or null if a name was not specified.
- * @private
- * @this Blockly.Block
- */
- validator_: function(newVar) {
- newVar = newVar.replace(/[\s\xa0]+/g, ' ').replace(/^ | $/g, '');
- return newVar || null;
- }
- };
- Blockly.Blocks['procedures_callnoreturn'] = {
- /**
- * Block for calling a procedure with no return value.
- * @this Blockly.Block
- */
- init: function() {
- this.category = 'UNKNOWN'; // for blocksCAD
- this.setHelpUrl(Blockly.Msg.PROCEDURES_CALLNORETURN_HELPURL);
- this.setColour(Blockscad.Toolbox.HEX_PROCEDURE);
- this.appendDummyInput('TOPROW')
- .appendField(this.id, 'NAME');
- this.setPreviousStatement(true);
- //this.setNextStatement(true); // for Blockscad, we don't want this to have a next. Breaks difference.
- // Tooltip is set in domToMutation.
- this.arguments_ = [];
- this.quarkConnections_ = {};
- this.quarkIds_ = null;
- this.setType();
- },
- /**
- * on being added, this will be called to set the parent procedure type for BlocksCAD
- */
- setType: function() { // for blockscad - jayod
- var parent = Blockly.Procedures.getDefinition(this.getProcedureCall(),this.workspace);
- // console.log("in caller's setType func. defined by: ",parent);
- if (parent) {
- var myType = parent.myType_;
- // console.log("found a parent procedure with type: ",parent.myType_);
- if (myType) {
- this.previousConnection.setCheck(myType);
- //this.nextConnection.setCheck(myType); // no more next connection
- if (myType == 'CSG' || myType == ['CSG'])
- this.category = 'PRIMITIVE_CSG'
- else if (myType == 'CAG' || myType == ['CAG'])
- this.category = 'PRIMITIVE_CAG';
- else this.category = 'UNKNOWN';
- }
- }
- },
- /**
- * Returns the name of the procedure this block calls.
- * @return {string} Procedure name.
- * @this Blockly.Block
- */
- getProcedureCall: function() {
- // The NAME field is guaranteed to exist, null will never be returned.
- return /** @type {string} */ (this.getFieldValue('NAME'));
- },
- /**
- * Notification that a procedure is renaming.
- * If the name matches this block's procedure, rename it.
- * @param {string} oldName Previous name of procedure.
- * @param {string} newName Renamed procedure.
- * @this Blockly.Block
- */
- renameProcedure: function(oldName, newName) {
- if (Blockly.Names.equals(oldName, this.getProcedureCall())) {
- this.setFieldValue(newName, 'NAME');
- this.setTooltip(
- (this.outputConnection ? Blockly.Msg.PROCEDURES_CALLRETURN_TOOLTIP :
- Blockly.Msg.PROCEDURES_CALLNORETURN_TOOLTIP)
- .replace('%1', newName));
- }
- },
- /**
- * Notification that the procedure's parameters have changed.
- * @param {!Array.<string>} paramNames New param names, e.g. ['x', 'y', 'z'].
- * @param {!Array.<string>} paramIds IDs of params (consistent for each
- * parameter through the life of a mutator, regardless of param renaming),
- * e.g. ['piua', 'f8b_', 'oi.o'].
- * @private
- * @this Blockly.Block
- */
- setProcedureParameters_: function(paramNames, paramIds) {
- // Data structures:
- // this.arguments = ['x', 'y']
- // Existing param names.
- // this.quarkConnections_ {piua: null, f8b_: Blockly.Connection}
- // Look-up of paramIds to connections plugged into the call block.
- // this.quarkIds_ = ['piua', 'f8b_']
- // Existing param IDs.
- // Note that quarkConnections_ may include IDs that no longer exist, but
- // which might reappear if a param is reattached in the mutator.
- var defBlock = Blockly.Procedures.getDefinition(this.getProcedureCall(),
- this.workspace);
- var mutatorOpen = defBlock && defBlock.mutator &&
- defBlock.mutator.isVisible();
- if (!mutatorOpen) {
- this.quarkConnections_ = {};
- this.quarkIds_ = null;
- }
- if (!paramIds) {
- // Reset the quarks (a mutator is about to open).
- return;
- }
- if (goog.array.equals(this.arguments_, paramNames)) {
- // No change.
- this.quarkIds_ = paramIds;
- return;
- }
- if (paramIds.length != paramNames.length) {
- throw 'Error: paramNames and paramIds must be the same length.';
- }
- this.setCollapsed(false);
- if (!this.quarkIds_) {
- // Initialize tracking for this block.
- this.quarkConnections_ = {};
- if (paramNames.join('\n') == this.arguments_.join('\n')) {
- // No change to the parameters, allow quarkConnections_ to be
- // populated with the existing connections.
- this.quarkIds_ = paramIds;
- } else {
- this.quarkIds_ = [];
- }
- }
- // Switch off rendering while the block is rebuilt.
- var savedRendered = this.rendered;
- this.rendered = false;
- // Update the quarkConnections_ with existing connections.
- for (var i = 0; i < this.arguments_.length; i++) {
- var input = this.getInput('ARG' + i);
- if (input) {
- var connection = input.connection.targetConnection;
- this.quarkConnections_[this.quarkIds_[i]] = connection;
- if (mutatorOpen && connection &&
- paramIds.indexOf(this.quarkIds_[i]) == -1) {
- // This connection should no longer be attached to this block.
- connection.disconnect();
- connection.getSourceBlock().bumpNeighbours_();
- }
- }
- }
- // Rebuild the block's arguments.
- this.arguments_ = [].concat(paramNames);
- this.updateShape_();
- this.quarkIds_ = paramIds;
- // Reconnect any child blocks.
- if (this.quarkIds_) {
- for (var i = 0; i < this.arguments_.length; i++) {
- var quarkId = this.quarkIds_[i];
- if (quarkId in this.quarkConnections_) {
- var connection = this.quarkConnections_[quarkId];
- if (!Blockly.Mutator.reconnect(connection, this, 'ARG' + i)) {
- // Block no longer exists or has been attached elsewhere.
- delete this.quarkConnections_[quarkId];
- }
- }
- }
- }
- // Restore rendering and show the changes.
- this.rendered = savedRendered;
- if (this.rendered) {
- this.render();
- }
- },
- /**
- * Modify this block to have the correct number of arguments.
- * @private
- * @this Blockly.Block
- */
- updateShape_: function() {
- for (var i = 0; i < this.arguments_.length; i++) {
- var field = this.getField('ARGNAME' + i);
- if (field) {
- // Ensure argument name is up to date.
- // The argument name field is deterministic based on the mutation,
- // no need to fire a change event.
- Blockly.Events.disable();
- try {
- field.setValue(this.arguments_[i]);
- } finally {
- Blockly.Events.enable();
- }
- } else {
- // Add new input.
- field = new Blockly.FieldLabel(this.arguments_[i]);
- var input = this.appendValueInput('ARG' + i)
- .setAlign(Blockly.ALIGN_RIGHT)
- .appendField(field, 'ARGNAME' + i);
- input.init();
- }
- }
- // Remove deleted inputs.
- while (this.getInput('ARG' + i)) {
- this.removeInput('ARG' + i);
- i++;
- }
- // Add 'with:' if there are parameters, remove otherwise.
- var topRow = this.getInput('TOPROW');
- if (topRow) {
- if (this.arguments_.length) {
- if (!this.getField('WITH')) {
- topRow.appendField(Blockly.Msg.PROCEDURES_CALL_BEFORE_PARAMS, 'WITH');
- topRow.init();
- }
- } else {
- if (this.getField('WITH')) {
- topRow.removeField('WITH');
- }
- }
- }
- },
- /**
- * Create XML to represent the (non-editable) name and arguments.
- * @return {!Element} XML storage element.
- * @this Blockly.Block
- */
- mutationToDom: function() {
- var container = document.createElement('mutation');
- container.setAttribute('name', this.getProcedureCall());
- for (var i = 0; i < this.arguments_.length; i++) {
- var parameter = document.createElement('arg');
- parameter.setAttribute('name', this.arguments_[i]);
- container.appendChild(parameter);
- }
- return container;
- },
- /**
- * Parse XML to restore the (non-editable) name and parameters.
- * @param {!Element} xmlElement XML storage element.
- * @this Blockly.Block
- */
- domToMutation: function(xmlElement) {
- var name = xmlElement.getAttribute('name');
- this.renameProcedure(this.getProcedureCall(), name);
- var args = [];
- var paramIds = [];
- for (var i = 0, childNode; childNode = xmlElement.childNodes[i]; i++) {
- if (childNode.nodeName.toLowerCase() == 'arg') {
- args.push(childNode.getAttribute('name'));
- paramIds.push(childNode.getAttribute('paramId'));
- }
- }
- this.setProcedureParameters_(args, paramIds);
- },
- /**
- * 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) {
- for (var i = 0; i < this.arguments_.length; i++) {
- if (Blockly.Names.equals(oldName, this.arguments_[i])) {
- this.arguments_[i] = newName;
- this.getField('ARGNAME' + i).setValue(newName);
- }
- }
- },
- /**
- * Procedure calls cannot exist without the corresponding procedure
- * definition. Enforce this link whenever an event is fired.
- * @this Blockly.Block
- */
- onchange: function(event) {
- if (!this.workspace || this.workspace.isFlyout) {
- // Block is deleted or is in a flyout.
- return;
- }
- if (event.type == Blockly.Events.CREATE &&
- event.ids.indexOf(this.id) != -1) {
- // Look for the case where a procedure call was created (usually through
- // paste) and there is no matching definition. In this case, create
- // an empty definition block with the correct signature.
- var name = this.getProcedureCall();
- var def = Blockly.Procedures.getDefinition(name, this.workspace);
- if (def && (def.type != this.defType_ ||
- JSON.stringify(def.arguments_) != JSON.stringify(this.arguments_))) {
- // The signatures don't match.
- def = null;
- }
- if (!def) {
- Blockly.Events.setGroup(event.group);
- /**
- * Create matching definition block.
- * <xml>
- * <block type="procedures_defreturn" x="10" y="20">
- * <mutation name="test">
- * <arg name="x"></arg>
- * </mutation>
- * <field name="NAME">test</field>
- * </block>
- * </xml>
- */
- var xml = goog.dom.createDom('xml');
- var block = goog.dom.createDom('block');
- block.setAttribute('type', this.defType_);
- var xy = this.getRelativeToSurfaceXY();
- var x = xy.x + Blockly.SNAP_RADIUS * (this.RTL ? -1 : 1);
- var y = xy.y + Blockly.SNAP_RADIUS * 2;
- block.setAttribute('x', x);
- block.setAttribute('y', y);
- var mutation = this.mutationToDom();
- block.appendChild(mutation);
- var field = goog.dom.createDom('field');
- field.setAttribute('name', 'NAME');
- field.appendChild(document.createTextNode(this.getProcedureCall()));
- block.appendChild(field);
- xml.appendChild(block);
- Blockly.Xml.domToWorkspace(xml, this.workspace);
- Blockly.Events.setGroup(false);
- }
- } else if (event.type == Blockly.Events.DELETE) {
- // Look for the case where a procedure definition has been deleted,
- // leaving this block (a procedure call) orphaned. In this case, delete
- // the orphan.
- var name = this.getProcedureCall();
- var def = Blockly.Procedures.getDefinition(name, this.workspace);
- if (!def) {
- Blockly.Events.setGroup(event.group);
- this.dispose(true, false);
- Blockly.Events.setGroup(false);
- }
- }
- },
- /**
- * Add menu option to find the definition block for this call.
- * @param {!Array} options List of menu options to add to.
- * @this Blockly.Block
- */
- customContextMenu: function(options) {
- var option = {enabled: true};
- option.text = Blockly.Msg.PROCEDURES_HIGHLIGHT_DEF;
- var name = this.getProcedureCall();
- var workspace = this.workspace;
- option.callback = function() {
- var def = Blockly.Procedures.getDefinition(name, workspace);
- workspace.clearBacklight();
- // def && def.backlight();
- def && def.select();
- };
- options.push(option);
- // for BlocksCAD,
- var option = {enabled: true};
- var name = this.getProcedureCall();
- option.text = Blockscad.Msg.HIGHLIGHT_INSTANCES.replace("%1", name);
- var workspace = this.workspace;
- option.callback = function() {
- var def = Blockly.Procedures.getDefinition(name, workspace);
- if (def) {
- var callers = Blockly.Procedures.getCallers(name, workspace);
- workspace.clearBacklight();
- Blockly.selected.unselect();
- for (var i = 0; callers && i < callers.length; i++) {
- callers[i] && callers[i].backlight();
- // if caller block is in a collapsed parent, highlight collapsed parent too
- var others = callers[i].collapsedParents();
- if (others)
- for (var j=0; j < others.length; j++)
- others[j].backlight();
- }
- }
- };
- options.push(option);
- },
- defType_: 'procedures_defnoreturn'
- };
- Blockly.Blocks['procedures_callreturn'] = {
- /**
- * Block for calling a procedure with a return value.
- * @this Blockly.Block
- */
- init: function() {
- this.category = 'UNKNOWN'; // for blockscad - jayod
- this.setHelpUrl(Blockly.Msg.PROCEDURES_CALLRETURN_HELPURL);
- this.setColour(Blockscad.Toolbox.HEX_PROCEDURE);
- this.appendDummyInput('TOPROW')
- .appendField('', 'NAME');
- this.setOutput(true);
- // Tooltip is set in domToMutation.
- this.arguments_ = [];
- this.quarkConnections_ = {};
- this.quarkIds_ = null;
- // set the initial type.
- this.setType();
- },
- /**
- * on being added, this will be called to get the parent procedure type for BlocksCAD
- */
- setType: function() { // for blockscad - jayod
- var parent = Blockly.Procedures.getDefinition(this.getFieldValue('NAME'),this.workspace);
- if (parent) {
- var myType = parent.myType_;
- if (myType) {
- // console.log("setting type for new function caller to:",myType);
- this.outputConnection.setCheck(myType);
- if (myType == 'Number')
- this.category = 'NUMBER'
- else if (myType == 'Boolean')
- this.category = 'BOOLEAN';
- else this.category = 'UNKNOWN';
- }
- }
- },
- getProcedureCall: Blockly.Blocks['procedures_callnoreturn'].getProcedureCall,
- renameProcedure: Blockly.Blocks['procedures_callnoreturn'].renameProcedure,
- setProcedureParameters_:
- Blockly.Blocks['procedures_callnoreturn'].setProcedureParameters_,
- updateShape_: Blockly.Blocks['procedures_callnoreturn'].updateShape_,
- mutationToDom: Blockly.Blocks['procedures_callnoreturn'].mutationToDom,
- domToMutation: Blockly.Blocks['procedures_callnoreturn'].domToMutation,
- renameVar: Blockly.Blocks['procedures_callnoreturn'].renameVar,
- onchange: Blockly.Blocks['procedures_callnoreturn'].onchange,
- /**
- * Add menu option to find the definition block for this call.
- * @param {!Array} options List of menu options to add to.
- * @this Blockly.Block
- */
- customContextMenu: function(options) {
- var option = {enabled: true};
- option.text = Blockly.Msg.PROCEDURES_HIGHLIGHT_DEF;
- var name = this.getProcedureCall();
- var workspace = this.workspace;
- option.callback = function() {
- var def = Blockly.Procedures.getDefinition(name, workspace);
- workspace.clearBacklight();
- def && def.backlight();
- };
- options.push(option);
- // for BlocksCAD,
- var name = this.getProcedureCall();
- var option = {enabled: true};
- option.text = Blockscad.Msg.HIGHLIGHT_INSTANCES.replace("%1",name);
- var workspace = this.workspace;
- option.callback = function() {
- var def = Blockly.Procedures.getDefinition(name, workspace);
- if (def) {
- var callers = Blockly.Procedures.getCallers(name, workspace);
- workspace.clearBacklight();
- Blockly.selected.unselect();
- for (var i = 0; callers && i < callers.length; i++) {
- callers[i] && callers[i].backlight();
- // if caller block is in a collapsed parent, highlight collapsed parent too
- var others = callers[i].collapsedParents();
- if (others)
- for (var j=0; j < others.length; j++)
- others[j].backlight();
- }
- }
- };
- options.push(option);
- },
- defType_: 'procedures_defreturn'
- };
- // Blockly.Blocks['procedures_ifreturn'] = { // commented out for Blockscad
- // /**
- // * Block for conditionally returning a value from a procedure.
- // * @this Blockly.Block
- // */
- // init: function() {
- // this.setHelpUrl('http://c2.com/cgi/wiki?GuardClause');
- // this.setColour(290);
- // this.appendValueInput('CONDITION')
- // .setCheck('Boolean')
- // .appendField(Blockly.Msg.CONTROLS_IF_MSG_IF);
- // this.appendValueInput('VALUE')
- // .appendField(Blockly.Msg.PROCEDURES_DEFRETURN_RETURN);
- // this.setInputsInline(true);
- // this.setPreviousStatement(true);
- // this.setNextStatement(true);
- // this.setTooltip(Blockly.Msg.PROCEDURES_IFRETURN_TOOLTIP);
- // this.hasReturnValue_ = true;
- // },
- // /**
- // * Create XML to represent whether this block has a return value.
- // * @return {Element} XML storage element.
- // * @this Blockly.Block
- // */
- // mutationToDom: function() {
- // var container = document.createElement('mutation');
- // container.setAttribute('value', Number(this.hasReturnValue_));
- // return container;
- // },
- // /**
- // * Parse XML to restore whether this block has a return value.
- // * @param {!Element} xmlElement XML storage element.
- // * @this Blockly.Block
- // */
- // domToMutation: function(xmlElement) {
- // var value = xmlElement.getAttribute('value');
- // this.hasReturnValue_ = (value == 1);
- // if (!this.hasReturnValue_) {
- // this.removeInput('VALUE');
- // this.appendDummyInput('VALUE')
- // .appendField(Blockly.Msg.PROCEDURES_DEFRETURN_RETURN);
- // }
- // },
- // /**
- // * Called whenever anything on the workspace changes.
- // * Add warning if this flow block is not nested inside a loop.
- // * @this Blockly.Block
- // */
- // onchange: function() {
- // if (!this.workspace) {
- // // Block has been deleted.
- // return;
- // }
- // var legal = false;
- // // Is the block nested in a procedure?
- // var block = this;
- // do {
- // if (block.type == 'procedures_defnoreturn' ||
- // block.type == 'procedures_defreturn') {
- // legal = true;
- // break;
- // }
- // block = block.getSurroundParent();
- // } while (block);
- // if (legal) {
- // // If needed, toggle whether this block has a return value.
- // if (block.type == 'procedures_defnoreturn' && this.hasReturnValue_) {
- // this.removeInput('VALUE');
- // this.appendDummyInput('VALUE')
- // .appendField(Blockly.Msg.PROCEDURES_DEFRETURN_RETURN);
- // this.hasReturnValue_ = false;
- // } else if (block.type == 'procedures_defreturn' &&
- // !this.hasReturnValue_) {
- // this.removeInput('VALUE');
- // this.appendValueInput('VALUE')
- // .appendField(Blockly.Msg.PROCEDURES_DEFRETURN_RETURN);
- // this.hasReturnValue_ = true;
- // }
- // this.setWarningText(null);
- // } else {
- // this.setWarningText(Blockly.Msg.PROCEDURES_IFRETURN_WARNING);
- // }
- // }
- // };
|