How to implement simple +/- mutators

424 views
Skip to first unread message

Daniel Ehren

unread,
Mar 27, 2020, 8:02:26 AM3/27/20
to Blockly
Dear all,

I have seen a lot of great examples for mutators and extensions here. As far I have still understanding problems. I want to make +/- mutator for a block, it should follows these simple rules:

range : [x,y]
if NumberOfInputs == x
only +
if NumberOfInputs == y
only -
else +-

I dont want to use the mutator bubbles or more complex programming solutions. Is there a simple solution by the Mutator architecture? 

Thank You!



+-mutator.png

Coda Highland

unread,
Mar 27, 2020, 9:04:38 AM3/27/20
to blo...@googlegroups.com
There isn't... yet. We're working on it! That's what that other thread is. The result of that discussion should result in an extension that you can easily load up.

The max number is something we hadn't considered, though! That's useful input and we should definitely put that into the design. @Beka!

/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/6d4ab4d7-1bfe-476f-b1f6-e5cc0b4bd4b5%40googlegroups.com.

Daniel Ehren

unread,
Mar 27, 2020, 9:51:22 AM3/27/20
to Blockly
That are good news in bad news. I tried to get an overview about Beka's source code, but web development isnt my main emphasis so its hard to get.

So I will wait and focus on other features in that time. Can you tell me some background informations? How are you're relations to Blockly workgroup, will they implement it on github so I can just change my blockly_compressed.js? And how long does it take, are we talking about days/weeks/months? This would be interesting to know for planning my project.

Thank You!

Coda Highland

unread,
Mar 27, 2020, 10:12:21 AM3/27/20
to blo...@googlegroups.com
I'm just an independent developer building a child-and-parent-group focused game development toolkit. No relation to Blockly, though I have a contributor agreement on file because I've submitted a PR before.

This won't require modifying blockly_compressed at all. It'll be a separate script that you can just drop in, and then in your block's definition you put it in the list of extensions.

Beka's preliminary stuff is usable right now, but it's not reflective of how it'll end up when it's done. If she's feeling ambitious it's probably a few days to a couple weeks, but she should answer that herself.

/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.

Beka Westberg

unread,
Mar 27, 2020, 11:34:10 AM3/27/20
to Blockly
Hello,

There isn't... yet. We're working on it! That's what that other thread is. The result of that discussion should result in an extension that you can easily load up.

To be clear, the initial extension/package/thing will just result in +/- mutators for the built-in blocks that already have mutators (as per the issue). It will be /possible/ to create your own +/- mutators, but it won't be a fully fleshed out API. I just don't want to get anyones hopes up too high hehe.

 Is there a simple solution by the Mutator architecture? 

There's no /simple/ solution no. Here's an outline of the basic steps you would have to take:
1. Read the documentation on defining blocks and mutators, so that you have a solid foundation.
2. Download the field files from my branch, and get your project to load them.
3. Define a basic block using the info from step 1.
4. Add a .plus() callback that adds inputs.
5. Add a .minus() callback that removes inputs.
6. Add an updatePlusMinus() (or whatever you want to call it) function that adds and removes your plus and minus fields based on the range you defined. You will call this function from your plus() and minus() callbacks.

Here is an example of what the code from step 6 might look like:

  updateMinus_: function() {
   
var count = this.inputCount;  // The variable you use to track the number of inputs.
   
if (count == MIN_COUNT) {
     
if (this.getField('MINUS') {
       
this.inputList[0].removeField('MINUS');
     
}
     
if (!this.getField('PLUS') {
       
this.inputList[0].insertFieldAt(0, new FieldPlus(), 'PLUS');
     
}
   
} else if (count == MAX_COUNT) {
       
if (this.getField('PLUS') {
       
this.inputList[0].removeField('PLUS');
     
}
     
if (!this.getField('MINUS') {
       
this.inputList[0].insertFieldAt(0, new FieldMinus(), 'MINUS');
     
}
   
} else {
     
if (!this.getField('PLUS') {
       
this.inputList[0].insertFieldAt(0, new FieldPlus(), 'PLUS');
     
}
     
if (!this.getField('MINUS') {
       
this.inputList[0].insertFieldAt(1, new FieldMinus(), 'MINUS');
     
}
   
}
 
}


The above is untested.

And how long does it take, are we talking about days/weeks/months?

As Adam said, the code is usable right now (although it may not be the prettiest hehe). I don't have a specific timeline for this project, because I have some other (non-blockly) projects that I have to give priority right now. You can however follow my progress on my punchlist.

I hope that helps!
--Beka 

P.S. Thanks for the @ Adam!
 

Coda Highland

unread,
Mar 27, 2020, 12:59:15 PM3/27/20
to blo...@googlegroups.com
On Fri, Mar 27, 2020 at 10:34 AM Beka Westberg <bekawe...@gmail.com> wrote:
Hello,

There isn't... yet. We're working on it! That's what that other thread is. The result of that discussion should result in an extension that you can easily load up.

To be clear, the initial extension/package/thing will just result in +/- mutators for the built-in blocks that already have mutators (as per the issue). It will be /possible/ to create your own +/- mutators, but it won't be a fully fleshed out API. I just don't want to get anyones hopes up too high hehe.

I mean, if we do it the way I'm thinking we'd do it, it shouldn't be TOO terribly difficult. I'll submit the PR myself if I have to. XD

And how long does it take, are we talking about days/weeks/months?

As Adam said, the code is usable right now (although it may not be the prettiest hehe). I don't have a specific timeline for this project, because I have some other (non-blockly) projects that I have to give priority right now. You can however follow my progress on my punchlist.

If this ends up taking a while, I might jump in and help. I'm backlogged myself at the moment, but this is something I've had on my own plate since last year as well (I've still got that ticket open in a tab somewhere!) so once I get bigger fish properly fried I can contribute.
 
P.S. Thanks for the @ Adam!

Happy to oblige.

/s/ Adam 

Daniel Ehren

unread,
Mar 27, 2020, 2:32:12 PM3/27/20
to Blockly
Hello,

thank you for your help. Unfortunately I cant even get the plus/minus field to load, because of the media, imports etc.. It costs a lot of time learning Blockly without a good knowledge about JS/HTML/JSON, and that is not my target with regard to the other languages I usually use for programming. So it takes too much time writing syntactly correct code. Im going to try making a bunch of blocks with a different numbers of input and then Im going to overthink the implementation with Blockly.

Its bad that the Blockly Developers didnt implement an easy way to make these features. There is a lot of very good work done for this in all the years, but I think, that this feature is very important for this kind of software. The blocks should help the users to understand the semantic of mathematical operations and functions. The ability to use a operator multiple times, no matter how the order of the values is, is very important in my view. Especially for my project its a fundamental aspect to show the associativity of the logical operands.

Coda Highland

unread,
Mar 27, 2020, 3:26:54 PM3/27/20
to blo...@googlegroups.com
Well, on the one hand, they did implement a way to make these features. The fact that there's a mutator framework at all is evidence of that. It wouldn't be possible at all without it.

But yes, it's well known that the mutator framework is really hard to work with. That's why we're trying to come up with something to make the common use case easier to work with. 

For lists, there's another way you go about it. I mentioned in another thread that I had something working in my own project that automatically extends the create list block if it's full... unfortunately, that's a half-truth, as I discovered when I went digging for it. It turns out that I deleted it because I ended up going for a different approach. I'm kind of kicking myself for deleting the code. I didn't even commit it to my git repo before refactoring it away! Still, it's not too hard. You might find it easier to try implementing something like that. I'm happy to help if you need pointers.

/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.

Daniel Ehren

unread,
Mar 28, 2020, 7:27:21 AM3/28/20
to Blockly
Im happy to say, that Im pretty sure to correct both of you. I implemented just a FieldImage and got the functionality so far. Only putting inputs broke the whole programm. If I understand the situation correctly, I only need to add working mutationToDom Functions and then it should be nearby a one liner. So it should take only some hours for the results, I try to share it as fast as possible. 

Beka Westberg

unread,
Mar 28, 2020, 10:32:51 AM3/28/20
to Blockly
Hello again,

You are correct that the basic implementation is pretty simple! And you can see that the plus and minus fields do inherit from FieldImage, so I'm glad we're on the same page there.

The reason it takes longer to make an extension is that there is a lot of extra stuff you need to get working.
  • Events need to fire correctly.
  • Undo and Redo needs to work correctly.
  • You need to test that XML serializes and deserializes.
  • People should be able to switch between these mutators and the old mutators (XML needs to be identical - mutation and inputs)
Then you need to write unit tests to cover all of the above (and more). Write documentation. Get it ready to publish (in whatever form that may be) etc etc.

So I'm gad you've got something working! And I'd love to see what you come up with; any ideas are much appreciated hehe

I just wanted to say that it /probably/ doesn't mean anything "official" is going to get published any sooner.

Thank you for your reply!
--Beka

Daniel Ehren

unread,
Mar 28, 2020, 12:45:41 PM3/28/20
to Blockly
First of all: Blockly Developers made an awesome job! Its just about understanding their concepts.

I think, that we are working on the same problem, but for different results. My target is very simple and I reached it (hopefully, maybe Im going into trouble at some other point). But so far I can say, that there is a simple solution for this problem! :)


RANGE_MIN = 2;
RANGE_MAX = 5;

Blockly.Blocks['foo'] = {
  init: function() {
  
var inputsC = RANGE_MIN;  
  
    this.setOutput(true, 'FOO');
this.setColour(100);
this.setInputsInline(true);
this.appendValueInput('in1')
this.appendValueInput('in2')
        .appendField('foo')
  },
  
    mutationToDom: function () {
    var container = Blockly.utils.xml.createElement('mutation');
        container.setAttribute('inputCount', this.inputsC);
        return container;
    },
 
    domToMutation: function (xmlElement) {
this.inputsC = parseInt(xmlElement.getAttribute('inputCount'), 10) || RANGE_MIN;
        this.updateShape_();
    },
  
    updateShape_: function() {
this.removeInput('in1');
if(this.inputsC == RANGE_MIN){
this.appendValueInput('in1')
            .appendField(new Blockly.FieldImage(
                15,
                15,
            "*", function() {
            this.getSourceBlock().plus_();
            } ));
}
else if(this.inputsC == RANGE_MAX){
this.appendValueInput('in1')
.appendField(new Blockly.FieldImage(
                15,
                15,
            "*", function() {
            this.getSourceBlock().minus_();
            } ));
}
else{
this.appendValueInput('in1')
.appendField(new Blockly.FieldImage(
                15,
                15,
            "*", function() {
            this.getSourceBlock().minus_();
            } ))
            .appendField(new Blockly.FieldImage(
                15,
                15,
            "*", function() {
            this.getSourceBlock().plus_();
            } ));
}
        var i = 2;
        while (this.getInput('in' + i)) {
           this.removeInput('in' + i);
        i++;
        }
  
    for (var x = 2; x <= this.inputsC; x++) {
       this.appendValueInput('in' + x)
       .appendField('foo')
        }
    },
 
 
    plus_: function (){
    this.inputsC = (this.inputsC + 1);
    this.updateShape_();
    },
  
    minus_: function (){
    this.inputsC = (this.inputsC - 1);
    this.updateShape_();
    }
};

  
(This code is only a prototype)


Reply all
Reply to author
Forward
0 new messages