Multiple registerToolboxCategoryCallback but only last one visible

122 views
Skip to first unread message

Licorne Magique

unread,
Apr 12, 2020, 9:11:21 AM4/12/20
to Blockly
Hi,
I tried to add typing variable, and after many hours of work (because it's really hard to understand all elements you have to create...even with documentation) I have something working BUT.....
When I create one button with a specific type (thanks to this example : https://groups.google.com/forum/#!msg/blockly/e83RlQbKo1c/PlVkddmPAQAJ), I have it on my toolbox but when I try to create 3, only the last one appears in the toolbox, and I have no error message in the console.

My blocks code :

'use strict';

goog
.provide('Blockly.Constants.variablesDyn');

goog
.require('Blockly.Blocks');
goog
.require('Blockly');

Blockly.Blocks['vars_set_int'] = {
  init
: function() {
   
this.appendValueInput("VALUE")
       
.appendField("set")
       
.appendField(new Blockly.FieldVariable("", null, ['varInt'], 'varInt'), "VAR_SET_INT")
       
.appendField("to");
   
this.setPreviousStatement(true, null);
   
this.setNextStatement(true, null);
   
this.setColour(230);
   
this.setTooltip("");
   
this.setHelpUrl("");
 
}
};

Blockly.Blocks['vars_get_int'] = {
  init
: function() {
   
this.appendDummyInput()
       
.appendField(new Blockly.FieldVariable("", null, ['varInt'], 'varInt'), "VAR_GET_INT");
   
this.setOutput(true, "varInt");
   
this.setColour(230);
   
this.setTooltip("");
   
this.setHelpUrl("");
 
}
};

Blockly.Blocks['vars_set_float'] = {
  init
: function() {
   
this.appendValueInput("VALUE")
       
.appendField("set")
       
.appendField(new Blockly.FieldVariable("", null, ['varFloat'], 'varFloat'), "VAR_SET_FLOAT")
       
.appendField("to");
   
this.setPreviousStatement(true, null);
   
this.setNextStatement(true, null);
   
this.setColour(230);
   
this.setTooltip("");
   
this.setHelpUrl("");
 
}
};

Blockly.Blocks['vars_get_float'] = {
  init
: function() {
   
this.appendDummyInput()
       
.appendField(new Blockly.FieldVariable("", null, ['varFloat'], 'varFloat'), "VAR_GET_FLOAT");
   
this.setOutput(true, "varFloat");
   
this.setColour(230);
   
this.setTooltip("");
   
this.setHelpUrl("");
 
}
};

My blocks generator :

'use strict';

goog
.provide('Blockly.Arduino.variablesDyn');

goog
.require('Blockly.Arduino');

Blockly.Arduino['vars_set_int'] = function(block) {
 
// Variable setter.
 
var argument0 = Blockly.Arduino.valueToCode(block, 'VALUE', Blockly.Arduino.ORDER_ASSIGNMENT) || '0';
 
var varName = Blockly.Arduino.variableDB_.getName(block.getFieldValue('VAR_SET_INT'), Blockly.Variables.NAME_TYPE);
 
return varName + ' = ' + argument0 + ';\n';
};

Blockly.Arduino['vars_get_int'] = function(block) {
 
// Variable getter.
 
var code = Blockly.Arduino.variableDB_.getName(block.getFieldValue('VAR_GET_INT'), Blockly.Variables.NAME_TYPE);
 
return [code, Blockly.Arduino.ORDER_ATOMIC];
};

Blockly.Arduino['vars_set_float'] = function(block) {
 
// Variable setter.
 
var argument0 = Blockly.Arduino.valueToCode(block, 'VALUE', Blockly.Arduino.ORDER_ASSIGNMENT) || '0';
 
var varName = Blockly.Arduino.variableDB_.getName(block.getFieldValue('VAR_SET_FLOAT'), Blockly.Variables.NAME_TYPE);
 
return varName + ' = ' + argument0 + ';\n';
};

Blockly.Arduino['vars_get_float'] = function(block) {
 
// Variable getter.
 
var code = Blockly.Arduino.variableDB_.getName(block.getFieldValue('VAR_GET_FLOAT'), Blockly.Variables.NAME_TYPE);
 
return [code, Blockly.Arduino.ORDER_ATOMIC];
};

And just after inject:
   
 Code.workspace.registerButtonCallback('createVarBtnInt', createVarBtnIntCallBack);  
   
Code.workspace.registerButtonCallback('createVarBtnFloat', createVarBtnFloatCallBack);
   
Code.workspace.registerButtonCallback('createVarBtnString', createVarBtnStringCallBack);
   
Code.workspace.registerToolboxCategoryCallback('VARIABLE_DYNAMIQUE', intVariablesCallBack);
   
Code.workspace.registerToolboxCategoryCallback('VARIABLE_DYNAMIQUE', floatVariablesCallBack);
   
Code.workspace.registerToolboxCategoryCallback('VARIABLE_DYNAMIQUE', stringVariablesCallBack);

Of course my toolbox contains:
<category name="Dynamic" categorystyle="variable_category" custom="VARIABLE_DYNAMIQUE"></category>


My functions are in another file :

var createVarBtnIntCallBack = function (button) {
   
Blockly.Variables.createVariableButtonHandler(button.getTargetWorkspace(), null, 'varInt');
};

var createVarBtnFloatCallBack = function (button) {
   
Blockly.Variables.createVariableButtonHandler(button.getTargetWorkspace(), null, 'varFloat');
};

var intVariablesCallBack = function (currWorkspace) {
   
var allIntVars = currWorkspace.getVariablesOfType('varInt');
   
var xmlList = [];
   
var createVarBtnXml = Blockly.Xml.textToDom('<xml><button text="Create Int Variable" callbackKey="createVarBtnInt">' +
           
'</button></xml>').firstChild;
    xmlList
.push(createVarBtnXml);
   
if (allIntVars.length > 0) {
       
if (Blockly.Blocks['vars_set_int']) {
           
var firstVariable = allIntVars[allIntVars.length - 1];
           
var gap = 24;
           
var blockText =
               
'<xml>' +
               
'<block type="vars_set_int" gap="' + gap + '">' +
               
'<field name="VAR_SET_INT" variabletype="varInt">' + firstVariable.name + '</field>' +
               
'</block>' +
               
'</xml>';
           
var block = Blockly.Xml.textToDom(blockText).firstChild;
            xmlList
.push(block);
       
}
       
if (Blockly.Blocks['vars_get_int']) {
            allIntVars
.sort(Blockly.VariableModel.compareByType);
           
for (var i = 0, variable; variable = allIntVars[i]; i++) {
               
var blockText =
                   
'<xml>' +
                   
'<block type="vars_get_int" gap="8">' +
                   
'<field name="VAR_GET_INT" variabletype="varInt">' + variable.name + '</field>' +
                   
'</block>' +
                   
'</xml>';
               
var block = Blockly.Xml.textToDom(blockText).firstChild;
                xmlList
.push(block);
           
}
       
}
   
}
   
return xmlList;
};

var floatVariablesCallBack = function (currWorkspace) {
   
var allFloatVars = currWorkspace.getVariablesOfType('varFloat');
   
var xmlList = [];
   
var createVarBtnXml = Blockly.Xml.textToDom('<xml><button text="Create Float Variable" callbackKey="createVarBtnFloat">' +
           
'</button></xml>').firstChild;
    xmlList
.push(createVarBtnXml);
   
if (allFloatVars.length > 0) {
       
if (Blockly.Blocks['vars_set_float']) {
           
var firstVariable = allFloatVars[allFloatVars.length - 1];
           
var gap = 24;
           
var blockText =
               
'<xml>' +
               
'<block type="vars_set_float" gap="' + gap + '">' +
               
'<field name="VAR_SET_FLOAT" variabletype="varFloat">' + firstVariable.name + '</field>' +
               
'</block>' +
               
'</xml>';
           
var block = Blockly.Xml.textToDom(blockText).firstChild;
            xmlList
.push(block);
       
}
       
if (Blockly.Blocks['vars_get_float']) {
            allFloatVars
.sort(Blockly.VariableModel.compareByType);
           
for (var i = 0, variable; variable = allFloatVars[i]; i++) {
               
var blockText =
                   
'<xml>' +
                   
'<block type="vars_get_float" gap="8">' +
                   
'<field name="VAR_GET_FLOAT" variabletype="varFloat">' + variable.name + '</field>' +
                   
'</block>' +
                   
'</xml>';
               
var block = Blockly.Xml.textToDom(blockText).firstChild;
                xmlList
.push(block);
           
}
       
}
   
}
   
return xmlList;
};

I'm crazy with it! I found nobody using it or any example on web, if someone could help me...
Many thanks.

Beka Westberg

unread,
Apr 12, 2020, 1:51:19 PM4/12/20
to Blockly
Hello,

So I believe what you want to do is declare /one/ dynamic category, but /multiple/ button handlers (one for each var type you want to support). Your single dynamic category will generate the XML for, and include, all three buttons.

There is actually a file in core called variables_dynamic.js which deals with typed variables. You can see the flyout this generates by adding the below to your toolbox XML:
<category name="Dynamic" categorystyle="variable_category" custom="VARIABLE_DYNAMIC"></category>

Here is the single dynamic category registration: workspace_svg.js
Here are the mutliple button callback registrations: variables_dynamic.js
Here is where the XML for the buttons is created: variables_dynamic.js

If I'm wrong and you want to have a different category for each kind of variable, you need to give them different names i.e. custom="VARIABLE_FLOAT", custom="VARIABLE_INT" etc.

I hope that helps! If you have any further questions please reply!
--Beka
Message has been deleted

Licorne Magique

unread,
Apr 12, 2020, 9:13:06 PM4/12/20
to Blockly
Thanks. So I tried with a copy of the variables_dynamic file, I tweaked it, I added my own variable category in toolbox, I created generators for my own set & get, and it works.
That was simple in fact...

But with this method I do not have to create my own blocks anymore, so how can I set the compatibility type?
Thanks.
Message has been deleted

Licorne Magique

unread,
Apr 16, 2020, 7:02:51 PM4/16/20
to Blockly
Hi,
could you explain why in the playground example, with typed variable, the getter has the right type?
What I understood is that setter has something like that:
"args0": [
   
{
     
"type": "field_variable",
     
"name": "VAR",
     
"variable": "%{BKY_VARIABLES_DEFAULT_NAME}",
     
"variableTypes": ["Panda", "toto", "lion"]
   
},

But where in variable_dynamic.js is the "variableTypes" declared?
Thanks.


Le dimanche 12 avril 2020 19:51:19 UTC+2, Beka Westberg a écrit :

Abby Schmiedt

unread,
Apr 17, 2020, 11:34:46 AM4/17/20
to Blockly
Hello! 

The type is set here in createVariableButtonHandler. For each button we pass the type that we want to createVariableButtonHandler. 

~Abby


Licorne Magique

unread,
Apr 17, 2020, 6:22:16 PM4/17/20
to Blockly
Thanks. What I mean is about compatibility.
With dynamic.js example, where could I add compatiblity between types?
You know, categorize types, like set_string cannot connect to get_number, but set_int and set_float could.

Coda Highland

unread,
Apr 17, 2020, 6:58:21 PM4/17/20
to blo...@googlegroups.com
You can pass an array of types instead of a single type name. The connection will pass if at least one type is shared by both sides of the connection.

/s/ Adam

--
You received this message because you are subscribed to the Google Groups "Blockly" group.
To unsubscribe from this group and stop receiving emails from it, send an email to blockly+u...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/blockly/e914a012-528a-4c65-b5d2-5be694f318c7%40googlegroups.com.

Beka Westberg

unread,
Apr 17, 2020, 7:08:23 PM4/17/20
to blo...@googlegroups.com
Hello again,

For the dynamic variable blocks compatibility isn't handled like normal. The "type checks" are set dynamically using an onchange listener (this is the spot - no clue why it's in such a weird hidden place). It's necessary to update the checks dynamically because the drop downs displays all of the variables (not just the variables for a given type). This is because there is no type information set here.

If you are defining your own blocks (one for each type of var), you could make the checks static instead, using the information you posted above, plus the info from here. It just depends on how you want to implement things.

I hope that helps! If you have any further questions just shout :D
--Beka

Licorne Magique

unread,
Apr 17, 2020, 7:44:32 PM4/17/20
to Blockly
Many thanks for your help!
Not easy at all...it was the most difficult thing to understand in Blockly because some information are in JSON only, some in JS, you must create manyt thnings from many doc, etc.
At last, my pb was just that the "registerToolboxCategoryCallback" must be unique for a category. I wanted to put in same category both 'int' and 'float', but now it's fixed because the creation of this blocks are in the same function because it's for the same category.

FIXED!
To unsubscribe from this group and stop receiving emails from it, send an email to blo...@googlegroups.com.
Reply all
Reply to author
Forward
0 new messages