Page 1 of 1

How do formspec coordinates work?

PostPosted: Thu Mar 10, 2016 18:27
by Wuzzy
How do formspec coordinates work?

I think I can kinda work with them but actually I don't have a clue what I am doing. I noticed that formspec coordinates of some formspec elements are not consistent and depend on the element type.
For instance, elements end up at different places for the same coordinates depending on whether it is a button or (text) field.

You can see an example of this in my mod “L-System Tree Utility”, you'll clearly notice the buttons and fields are not nicely aligned and I have no idea how to fix this. I have tried several offsets for the buttons but they just seem to make it worse, so I decided to leave it as it is now.
Image

The relevant code for this part of the formspec begins at line 272 in init.lua and is this:
Your phone or window isn't wide enough to display the code box. If it's a phone, try rotating it to landscape mode.
Code: Select all
   return ""..
   "field[0.2,-3.5;11,10;axiom;Axiom;"..s(fields.axiom).."]"..
   "button[11,0.2;1,1;edit_axiom;+]"..
   "tooltip[edit_axiom;Opens larger text field for Axiom]"..
   "field[0.2,-2.5;11,10;rules_a;Rules set A;"..s(fields.rules_a).."]"..
   "button[11,1.2;1,1;edit_rules_a;+]"..
   "tooltip[edit_rules_a;Opens larger text field for Rules set A]"..
   "field[0.2,-1.5;11,10;rules_b;Rules set B;"..s(fields.rules_b).."]"..
   "button[11,2.2;1,1;edit_rules_b;+]"..
   "tooltip[edit_rules_b;Opens larger text field for Rules set B]"..
   "field[0.2,-0.5;11,10;rules_c;Rules set C;"..s(fields.rules_c).."]"..
   "button[11,3.2;1,1;edit_rules_c;+]"..
   "tooltip[edit_rules_c;Opens larger text field for Rules set C]"..
   "field[0.2,0.5;11,10;rules_d;Rules set D;"..s(fields.rules_d).."]"..
   "button[11,4.2;1,1;edit_rules_d;+]"..
   "tooltip[edit_rules_d;Opens larger text field for Rules set D]"..

   "field[0.2,1.5;3,10;trunk;Trunk node name;"..s(fields.trunk).."]"..
   "field[3.2,1.5;3,10;leaves;Leaves node name;"..s(fields.leaves).."]"..
   "field[6.2,1.5;3,10;leaves2;Secondary leaves node name;"..s(fields.leaves2).."]"..
   "field[9.2,1.5;3,10;fruit;Fruit node name;"..s(fields.fruit).."]"..

   "field[0.2,2.5;3,10;trunk_type;Trunk type (single/double/crossed);"..s(fields.trunk_type).."]"..
   "tooltip[trunk_type;This field specifies the shape of the tree trunk. Possible values:\n- \"single\": trunk of size 1×1\n- \"double\": trunk of size 2×2\n- \"crossed\": trunk in cross shape (3×3).]"..
   "field[3.2,2.5;3,10;thin_branches;Thin branches? (true/false);"..s(fields.thin_branches).."]"..
   "tooltip[thin_branches;\"true\": All branches are just 1 node wide. \"false\": Branches can be larger.]"..
   "field[6.2,2.5;3,10;leaves2_chance;Secondary leaves chance (in percent);"..s(fields.leaves2_chance).."]"..
   "tooltip[leaves2_chance;Chance (in percent) to replace a leaves node by a secondary leaves node]"..
   "field[9.2,2.5;3,10;fruit_chance;Fruit chance (in percent);"..s(fields.fruit_chance).."]"..
   "tooltip[fruit_chance;Change (in percent) to replace a leaves node by a fruit node.]"..

   "field[0.2,3.5;3,10;iterations;Iterations;"..s(fields.iterations).."]"..
   "tooltip[iterations;Maximum number of iterations, usually between 2 and 5.]"..
   "field[3.2,3.5;3,10;random_level;Randomness level;"..s(fields.random_level).."]"..
   "tooltip[random_level;Factor to lower number of iterations, usually between 0 and 3.]"..
   "field[6.2,3.5;3,10;angle;Angle (in degrees);"..s(fields.angle).."]"..
   "field[9.2,3.5;3,10;name;Name;"..s(fields.name).."]"..
   "tooltip[name;An unique name for this tree, only used for convenience.]"..

   "button[3.5,8.5;3,1;edit_save;Save tree to database]"..
   "button[6.5,8.5;3,1;edit_clear;Clear fields]"


As you can see, the Y coordinates of buttons and fields are very different but they appear in kinda the same height. I have not yet managed to align buttons and fields perfectly.

So can anyone please give me an explanation of the formspec coordinate system and how it works now, especially with regards to fields vs buttons? Also, are there even more coordinates for other formspec elements?

Note this is not a support request for that particular mod but a general question since getting formspec coordinates right is pretty important.

Re: How do formspec coordinates work?

PostPosted: Thu Mar 10, 2016 18:32
by everamzah
This isn't a solution but my personal experience: Take a screenshot and quit minetest, load the picture up and nudge the formspec buttons by small values. Go back into minetest, load the formspec and take another picture. Keep the picture up so you can look at it while you adjust the numbers.

I have no idea why they don't align, but lua_api.txt does mention that some elements use inventory sizes for X, Y.

Re: How do formspec coordinates work?

PostPosted: Thu Mar 10, 2016 19:03
by rubenwardy
It's witchcraft and black magic

Re: How do formspec coordinates work?

PostPosted: Fri Mar 11, 2016 00:21
by Dragonop
Test and error, after a while you get used to it and "know" the dimensions and somehow where it will end up. Try lowering everything else instead of the buttons, and that might work, heh.
Can't say I know what I'm talking about, formspecs are hell for me.

Re: How do formspec coordinates work?

PostPosted: Fri Mar 11, 2016 08:19
by addi
yeah formspecs are realy magic! But there are 2 "magic" numbers that might help:
0 and -0.3

The 0 (zero) is needed for the elements heights (4th number):
Your phone or window isn't wide enough to display the code box. If it's a phone, try rotating it to landscape mode.
Code: Select all
"field[0.2,-3.5;11,0;axiom;Axiom;"..s(fields.axiom).."]"..
   "button[11,0.2;1,0;edit_axiom;+]"..

Set the last coordinates always to 0 this makes handling easier.
the -0.3 is needed for the buttons then.
Example if your field starts at (0.2, 1) make the button start -0.3 above. E.g. (0.2, 1-0.3) = (0.2, 0.7)
Finished aligned code:
Your phone or window isn't wide enough to display the code box. If it's a phone, try rotating it to landscape mode.
Code: Select all
     return ""..
    "field[0.2,1;11,0;axiom;Axiom;"..s(fields.axiom).."]"..
    "button[11,0.7;1,0;edit_axiom;+]"..
    "tooltip[edit_axiom;Opens larger text field for Axiom]"..
    "field[0.2,2;11,0;rules_a;Rules set A;"..s(fields.rules_a).."]"..
    "button[11,1.7;1,0;edit_rules_a;+]"..
    "tooltip[edit_rules_a;Opens larger text field for Rules set A]"..
    "field[0.2,3;11,0;rules_b;Rules set B;"..s(fields.rules_b).."]"..
    "button[11,2.7;1,0;edit_rules_b;+]"..
    "tooltip[edit_rules_b;Opens larger text field for Rules set B]"..
    "field[0.2,4;11,0;rules_c;Rules set C;"..s(fields.rules_c).."]"..
    "button[11,3.7;1,0;edit_rules_c;+]"..
    "tooltip[edit_rules_c;Opens larger text field for Rules set C]"..
    "field[0.2,5;11,0;rules_d;Rules set D;"..s(fields.rules_d).."]"..
    "button[11,4.7;1,0;edit_rules_d;+]"..
    "tooltip[edit_rules_d;Opens larger text field for Rules set D]"..

    "field[0.2,6;3,0;trunk;Trunk node name;"..s(fields.trunk).."]"..
    "field[3.2,6;3,0;leaves;Leaves node name;"..s(fields.leaves).."]"..
    "field[6.2,6;3,0;leaves2;Secondary leaves node name;"..s(fields.leaves2).."]"..
    "field[9.2,6;3,0;fruit;Fruit node name;"..s(fields.fruit).."]"..

    "field[0.2,7;3,0;trunk_type;Trunk type (single/double/crossed);"..s(fields.trunk_type).."]"..
    "tooltip[trunk_type;This field specifies the shape of the tree trunk. Possible values:\n- "single": trunk of size 1×1\n- "double": trunk of size 2×2\n- "crossed": trunk in cross shape (3×3).]"..
    "field[3.2,7;3,0;thin_branches;Thin branches? (true/false);"..s(fields.thin_branches).."]"..
    "tooltip[thin_branches;"true": All branches are just 1 node wide. "false": Branches can be larger.]"..
    "field[6.2,7;3,0;leaves2_chance;Secondary leaves chance (in percent);"..s(fields.leaves2_chance).."]"..
    "tooltip[leaves2_chance;Chance (in percent) to replace a leaves node by a secondary leaves node]"..
    "field[9.2,7;3,0;fruit_chance;Fruit chance (in percent);"..s(fields.fruit_chance).."]"..
    "tooltip[fruit_chance;Change (in percent) to replace a leaves node by a fruit node.]"..

    "field[0.2,8;3,0;iterations;Iterations;"..s(fields.iterations).."]"..
    "tooltip[iterations;Maximum number of iterations, usually between 2 and 5.]"..
    "field[3.2,8;3,0;random_level;Randomness level;"..s(fields.random_level).."]"..
    "tooltip[random_level;Factor to lower number of iterations, usually between 0 and 3.]"..
    "field[6.2,8;3,0;angle;Angle (in degrees);"..s(fields.angle).."]"..
    "field[9.2,8;3,0;name;Name;"..s(fields.name).."]"..
    "tooltip[name;An unique name for this tree, only used for convenience.]"..

    "button[3.5,8.7;3,0;edit_save;Save tree to database]"..
    "button[6.5,8.7;3,0;edit_clear;Clear fields]" 

Re: How do formspec coordinates work?

PostPosted: Fri Mar 11, 2016 10:05
by Wuzzy
Thanks, addi, it really works, I am surprised! But this begs the question: What the fuck?
Those numbers don't make any sense. Why are buttons offset by 0.3? Why do I have to set the height to 0?

Also, why is nothing of this documented?

Re: How do formspec coordinates work?

PostPosted: Fri Mar 11, 2016 12:54
by oleastre
I just had quick look at the code.
If I'm not mislead, the formspec is a simple layer around irrlicht ui elements that does some automatic scaling.
So, the number are not fixed on an easy grid, but rather raw elements sizes and positions as it is defined in the gui toolkit.
Maybe lack of documentation can be solved with a simple formspec generator (could be done as an inkscape plugin for example)

Re: How do formspec coordinates work?

PostPosted: Fri Mar 11, 2016 17:24
by addi
Wuzzy wrote:Thanks, addi, it really works, I am surprised! But this begs the question: What the fuck?
Those numbers don't make any sense. Why are buttons offset by 0.3? Why do I have to set the height to 0?

Also, why is nothing of this documented?

This is why I called it "magic" :-)

As far I could find out, the height is something special, if you place some elements with height they getting an offset.
have a look at this screen shot:
Image
I does not understand why it have such a behaviour. but as you see some elements have to be adjusted about 0.2 some about 0.3 and some does fit the grid

if someone thinks its usefull:

here ist the "grid" code:
Your phone or window isn't wide enough to display the code box. If it's a phone, try rotating it to landscape mode.
Code: Select all
box[0,0;1,1;#FFFFFF]box[2,0;1,1;#FFFFFF]box[4,0;1,1;#FFFFFF]box[6,0;1,1;#FFFFFF]box[8,0;1,1;#FFFFFF]box[10,0;1,1;#FFFFFF]
box[1,1;1,1;#FFFFFF]box[3,1;1,1;#FFFFFF]box[5,1;1,1;#FFFFFF]box[7,1;1,1;#FFFFFF]box[9,1;1,1;#FFFFFF]
box[0,2;1,1;#FFFFFF]box[2,2;1,1;#FFFFFF]box[4,2;1,1;#FFFFFF]box[6,2;1,1;#FFFFFF]box[8,2;1,1;#FFFFFF]box[10,2;1,1;#FFFFFF]
box[1,3;1,1;#FFFFFF]box[3,3;1,1;#FFFFFF]box[5,3;1,1;#FFFFFF]box[7,3;1,1;#FFFFFF]box[9,3;1,1;#FFFFFF]
box[0,4;1,1;#FFFFFF]box[2,4;1,1;#FFFFFF]box[4,4;1,1;#FFFFFF]box[6,4;1,1;#FFFFFF]box[8,4;1,1;#FFFFFF]box[10,4;1,1;#FFFFFF]
box[1,5;1,1;#FFFFFF]box[3,5;1,1;#FFFFFF]box[5,5;1,1;#FFFFFF]box[7,5;1,1;#FFFFFF]box[9,5;1,1;#FFFFFF]
box[0,6;1,1;#FFFFFF]box[2,6;1,1;#FFFFFF]box[4,6;1,1;#FFFFFF]box[6,6;1,1;#FFFFFF]box[8,6;1,1;#FFFFFF]box[10,6;1,1;#FFFFFF]
box[1,7;1,1;#FFFFFF]box[3,7;1,1;#FFFFFF]box[5,7;1,1;#FFFFFF]box[7,7;1,1;#FFFFFF]box[9,7;1,1;#FFFFFF]
box[0,8;1,1;#FFFFFF]box[2,8;1,1;#FFFFFF]box[4,8;1,1;#FFFFFF]box[6,8;1,1;#FFFFFF]box[8,8;1,1;#FFFFFF]box[10,8;1,1;#FFFFFF]
box[1,9;1,1;#FFFFFF]box[3,9;1,1;#FFFFFF]box[5,9;1,1;#FFFFFF]box[7,9;1,1;#FFFFFF]box[9,9;1,1;#FFFFFF]

This helps pretty much if you want to find out the offsets.

Here is the code used in the screeshot:
Your phone or window isn't wide enough to display the code box. If it's a phone, try rotating it to landscape mode.
Code: Select all
size[10,10]
field[0,1;4,0;random_level;Field 0,1 height 0;]
field[4,1;4,1;random_level;Field 4,1 height 1;]
button[0,2;4,0;random_level;Button 0,1 height 0]
button[4,2;4,1;random_level;Button 4,1 height 1]
textarea[0,3;4,0;name;Textarea 0,3 height 0;]
textarea[4,3;4,1;name;Textarea 4,3 height 1;]
dropdown[0,4;4,0;name;dropdown 0/4 height 0,item2,item3...;1]
dropdown[4,4;4,1;name;dropdown 0/4 height 1,item2,item3...;1]
list[current_player;main;0,5;4,0;List (0/5) height 0]
list[current_player;main;4,5;4,1;List (0/5) height 1]
box[0,0;1,1;#FFFFFF]box[2,0;1,1;#FFFFFF]box[4,0;1,1;#FFFFFF]box[6,0;1,1;#FFFFFF]box[8,0;1,1;#FFFFFF]box[10,0;1,1;#FFFFFF]
box[1,1;1,1;#FFFFFF]box[3,1;1,1;#FFFFFF]box[5,1;1,1;#FFFFFF]box[7,1;1,1;#FFFFFF]box[9,1;1,1;#FFFFFF]
box[0,2;1,1;#FFFFFF]box[2,2;1,1;#FFFFFF]box[4,2;1,1;#FFFFFF]box[6,2;1,1;#FFFFFF]box[8,2;1,1;#FFFFFF]box[10,2;1,1;#FFFFFF]
box[1,3;1,1;#FFFFFF]box[3,3;1,1;#FFFFFF]box[5,3;1,1;#FFFFFF]box[7,3;1,1;#FFFFFF]box[9,3;1,1;#FFFFFF]
box[0,4;1,1;#FFFFFF]box[2,4;1,1;#FFFFFF]box[4,4;1,1;#FFFFFF]box[6,4;1,1;#FFFFFF]box[8,4;1,1;#FFFFFF]box[10,4;1,1;#FFFFFF]
box[1,5;1,1;#FFFFFF]box[3,5;1,1;#FFFFFF]box[5,5;1,1;#FFFFFF]box[7,5;1,1;#FFFFFF]box[9,5;1,1;#FFFFFF]
box[0,6;1,1;#FFFFFF]box[2,6;1,1;#FFFFFF]box[4,6;1,1;#FFFFFF]box[6,6;1,1;#FFFFFF]box[8,6;1,1;#FFFFFF]box[10,6;1,1;#FFFFFF]
box[1,7;1,1;#FFFFFF]box[3,7;1,1;#FFFFFF]box[5,7;1,1;#FFFFFF]box[7,7;1,1;#FFFFFF]box[9,7;1,1;#FFFFFF]
box[0,8;1,1;#FFFFFF]box[2,8;1,1;#FFFFFF]box[4,8;1,1;#FFFFFF]box[6,8;1,1;#FFFFFF]box[8,8;1,1;#FFFFFF]box[10,8;1,1;#FFFFFF]
box[1,9;1,1;#FFFFFF]box[3,9;1,1;#FFFFFF]box[5,9;1,1;#FFFFFF]box[7,9;1,1;#FFFFFF]box[9,9;1,1;#FFFFFF]


oleastre wrote:I just had quick look at the code.
If I'm not mislead, the formspec is a simple layer around irrlicht ui elements that does some automatic scaling.
So, the number are not fixed on an easy grid, but rather raw elements sizes and positions as it is defined in the gui toolkit.
Maybe lack of documentation can be solved with a simple formspec generator (could be done as an inkscape plugin for example)


If someone could write such a plug-in it would be great, But in my opinion the whole formspec stuff needs to be rewritten.

Re: How do formspec coordinates work?

PostPosted: Fri Mar 11, 2016 17:29
by Wuzzy
But in my opinion the whole formspec stuff needs to be rewritten.

Yes, I fully agree. I don't care if this might break compability with existing formspecs, compability was broken quite a few times in the past anyways, so modders should expect this. A consistent formspec API is more important.
Writing some tools would be a nice-to-have, but they are no excuse for a poor API.

I am still baffled about the fact with the height 0 thing. Out of curiosity, what if I need to set the height explicitly? Then I can't use height 0.

Re: How do formspec coordinates work?

PostPosted: Fri Mar 11, 2016 18:36
by kaadmy
@Wuzzy: try increasing the size coordinates by this: https://github.com/minetest/minetest/bl ... .cpp#L1987

Re: How do formspec coordinates work?

PostPosted: Fri Mar 11, 2016 19:10
by twoelk
I remember well when Sapier rewrote the formspec code in its current form and was pretty frustrated with the system he had to use. He questioned several times wether all the work he invested was really worth it or wether not some other system should be used. He asked many times for help but except for suggestions as to how the things should look ingame nobody came up with more than a vague idea of how to code it differently. There are other games and applications based on Irrlicht, how do they do it? Do they have easier to use systems? Do they use some better libraries for rendering the GUI?

In the spoiler you will find some code and pics of my latest battles with formspec

+ Adding borders based on images to a formspec


So yeah the current formspec system is difficult to handle but until somebody comes up with some better working code we are stuck with it and just like all others I wish somebody else than me would start documenting it for dummies.

Re: How do formspec coordinates work?

PostPosted: Thu Mar 17, 2016 01:51
by Sokomine
Oh yes, formspecs. Arranging them so that they look halfway acceptable is very tricky. One of the things I fight with most is the placement of text. Buttons and input fields usually work more or less fine after some experimentation, but longer texts are hard to get well done. Something similar to HTML would be nice. Sadly, that's far too complicated and does rely on a lot of additional factors as well.