Page 1 of 2

[Mod] Smart Formspecs - OO builder + binding [1.1][smartfs]

Posted: Mon Oct 28, 2013 15:33
by rubenwardy
Image

This mod provides a 2nd generation way of creating forms - this means that the modder does not need to worry about complex formspec strings*
  • Expandable: you can register your own elements to use on the form.
  • Easy event handling: use binding to handle events.
  • New elements: includes a toggle button
  • Inventories: add pages to smart inventories, without worrying about which mod is installed.
No longer do you have to use fiddly formspec strings and receive field functions, instead you use code like this:
+ Spoiler
License: CC0

To install this library, install it as a mod and depend on it,
or if you do not like doing that then place the smartfs.lua file in your mod and then include it (dofile).
There is an example.lua file in the download that shows you how to use this library.

Download / GitHub Page

* it is possible to insert custom formspec strings

Posted: Mon Oct 28, 2013 19:04
by fairiestoy
Hey Ruben,
first of all, nice idea to add kind of a wrapper for that formspec strings. But one tip for handling this:
Better use it as standalone mod. This way, several modders will not have the same file and can access your
wrapper if they put it into their dependency file. Would make life easier of modders and keeps the data size
smaller due to only one folder with this files.


Greetings

Posted: Mon Oct 28, 2013 19:07
by rubenwardy
But nobody likes depending on mods, so they will just not use it.

I have added that.

Posted: Mon Oct 28, 2013 19:13
by fairiestoy
Tell me if im wrong, but there are a few libraries that are used as dependency because they are helpful like plantlife. Also the amount of mods with dependencies and without are imo very averaged. But it was just a suggestion, maybe keep it optional :P

Posted: Tue Oct 29, 2013 00:05
by LionsDen
Or maybe shoot to get it included as part of the minetest download. Maybe part of the default files/mod or something.

Posted: Tue Oct 29, 2013 09:57
by PilzAdam
The main problem with formspec strings is not the format, but rather the positioning. It was designed for inventory lists, so creating whole GUIs with it is a PITA.

Posted: Tue Oct 29, 2013 11:08
by jojoa1997
I agree. I have made my own inventory before and the hardest is the positioning. I remember reloading the game at least 50 times. Now if there was a way to see formspecs changed real time then that would be helpful.

Posted: Tue Oct 29, 2013 14:51
by rubenwardy
I could make it so you can give positions in pixels from the top left corner, but that could be hacky, and people WILL get confused.

I started work on a Formspec GUI Editor, but I got distracted. There is only a main class in that project so far, no real code at all.

You could make a mod the shows formspecs in game, but it would not have an editor.

Posted: Tue Oct 29, 2013 15:15
by rubenwardy
Unfortunately state:close() does not currently work as there is no way to do this in the api.

Posted: Tue Nov 05, 2013 13:20
by cHyper
rubenwardy wrote:Unfortunately state:close() does not currently work as there is no way to do this in the api.
how can i close a GUI by button anyway?
how can i activate a function by enabling a button in a formspec?

Posted: Tue Nov 05, 2013 13:25
by rubenwardy
This element has not been added yet.

https://github.com/minetest/minetest/bl ... i.txt#L990

Code: Select all

btn:onClick(function(self,state)
    print("Button clicked!")
    self.setText("Hello")
    state:close()
end)

Posted: Tue Nov 05, 2013 13:30
by rubenwardy
Added the element

Code: Select all

local btn = state:button(0,3,2,1,"btn","Click Me")
btn:setClose(true)
btn:onClick(function(self,state)
    --run on close
end)

Posted: Tue Nov 05, 2013 13:41
by cHyper
rubenwardy wrote:This element has not been added yet.

https://github.com/minetest/minetest/bl ... i.txt#L990

Code: Select all

btn:onClick(function(self,state)
        print("Button clicked!")
        self.setText("Hello")
        state:close()
    end)
you can add an exit button by default to close the formspec.
does this help?

Posted: Tue Nov 05, 2013 14:58
by rubenwardy
Please read all my responses.
rubenwardy wrote: Added the element

Code: Select all

local btn = state:button(0,3,2,1,"btn","Click Me")
btn:setClose(true)
btn:onClick(function(self,state)
    --run on close
end)
EDIT: Do you mean the proceed button?

Posted: Mon Feb 17, 2014 11:52
by rubenwardy
Bump :P

Posted: Thu Feb 20, 2014 20:37
by rubenwardy

Update!

I have added a wrapper for advanced inventories.

This means that you can add your formspec easily to smart inventories, such as inventory_plus and unified_inventory, without caring which one is installed. You don't have to modify your code for each one.

Adding to the inventory is as simple as:

Code: Select all

smartfs.add_to_inventory(myform, "icon.png", "MyFormLabel")
It works, but is quite buggy at this stage.

Any suggestions?

Have you got any suggestions, such as new elements?

I may be adding a page element (ie: start, back, 1, 2, 3, next, end)
to display stuff.

Posted: Thu Feb 20, 2014 22:42
by domtron vox
Great Mod! I am going to try and use it for my mod.

I do have a question though. It seems like the height value has no effect on the button. Is this a problem with smartfs or is it an engine limitation(I was trying to make a square button)?

EDIT:
I'm using the smartfs.lua as a library. I got the following error. Is using "throw" a mistake or did I do something to cause the error? I replaced all "throw"s with "print" and it worked.

Code: Select all

18:31:27: ERROR[main]: ServerError: ...on/games/minetest/bin/../mods/mod_manuel/smartfs.lua:19: attempt to call global 'throw' (a nil value)
18:31:27: ERROR[main]: stack traceback:
18:31:27: ERROR[main]:     ...on/games/minetest/bin/../mods/mod_manuel/smartfs.lua:19: in function 'create'

Posted: Fri Feb 21, 2014 17:00
by rubenwardy
Lua is stupid.

It uses error instead of throw. Fixed.

Also, if you look at the error:

Form <name> already exists!

You have tried making the same form twice.

eg: you made two forms called foo:bar


As for button heights, it should work.

Posted: Fri Feb 21, 2014 19:27
by domtron vox
rubenwardy wrote:Fixed.
Always a nice thing to hear.
rubenwardy wrote:You have tried making the same form twice.
Yep, I understood since your error is quite clear. I was just referring to the throw vs. error thing.
rubenwardy wrote:As for button heights, it should work.
Then I have no clue what I'm doing wrong. :/


I'm interested in eventually using tables for my mod. I think tables were added after last stable release. If so: are you planning on implementing tables or are you aiming for compatibility with the current minetest stable?

Anyway, don't be rushed on my account. At this stage labels are working quite nicely and your library is exactly what I need. Thanks for making it.

Posted: Thu Feb 27, 2014 21:44
by domtron vox
Hi, I did some documentation for you. Use it, lose it, or shred it. It is yours to do with as you please. I'll write up a section on creating new elements once I get around to trying it out. ;)

I'm not 100% sure how accurate it is.

If you don't use it I would like to point out that some of your function descriptions of the label and field elements refer to button instead of label/field.
Label
...
  • element:setText( text ) - set the caption of the button
Edit: For some reason the file wouldn't upload so I put it in a spoiler:
+ Spoiler

Posted: Fri Feb 28, 2014 11:39
by webdesigner97
Would this allow to run function on button click like this one:

Code: Select all

button:onlick(callAFunction(withButtonRelatedParam))
I hope you understand what I mean: I have a formspec with let's say 10 buttons. Whenever one of these buttons gets clicked, it should run a function with a parameter based on its e.g. label text.

Posted: Fri Feb 28, 2014 11:40
by rubenwardy
Look good!

I will add this later. Good work!

Posted: Fri Feb 28, 2014 19:56
by domtron vox
webdesigner97 wrote:Would this allow to run function on button click like this one:

Code: Select all

button:onlick(callAFunction(withButtonRelatedParam))
if button is a variable that points to an element. For example if button is set using either

Code: Select all

local button = state:button(0,0, 1,4, "btn","a button")
or

Code: Select all

local button = state:get("btn")--if the button you want to get is called "btn"
in a form creation callback function(the function you pass to smartfs.create) then

Code: Select all

button:onlick(callAFunction(withButtonRelatedParam))
would work.

Here is a working example. Each time either button is pressed it adds a label to the form underneath it:

EDIT:I tweaked the code since rubenwardy said this would crash if multiple players joined a game. I tested it with a local host server and two clients.

Code: Select all

dofile(minetest.get_modpath(minetest.get_current_modname()).."/smartfs.lua")

minetest.register_on_joinplayer(function(player)

    local form = smartfs.create("test@"..player:get_player_name(),
                   function(state)

                       state:size(8,8)

                       --set variable using creation assignment
                       local button1 = state:button(0,0, 2,1, "btn1","A button")
                  
                       --set variable using state:get
                       state:button(2,0, 3,1, "btn2","Another button")
                       local button2 = state:get("btn2")

                       --incremented so each new label is in the right spot
                       local ypos1 = 2
                       local ypos2 = 2
                       
                       --button one on clicked function
                       state:get("btn1"):onClick(function(self, state)
                           state:label(0,ypos1, "lable1"..ypos1, "A label!")
                           ypos1 = ypos1 + 1
                       end)

                       --button two on clicked function
                       button2:onClick(function(self, state)
                           state:label(2,ypos2, "lable2"..ypos2, "A label!")
                           ypos2 = ypos2 + 1
                       end)                       


                   end)

    form:show(player:get_player_name())

end)
So far I haven't found a way to edit the elements of a form after creation all editing needs to be defined inside the creation callback.

Posted: Fri Feb 28, 2014 20:15
by domtron vox
And since I took the time to figure that out here are the docs on it. I put them after showing forms:
+ Spoiler
Again it is in .md format and yours to do with as you please.

Posted: Fri Feb 28, 2014 22:51
by rubenwardy
You could edit stuff outside of the callbacks, by getting the stored states.

Code: Select all

state = smartfs.opened[name]
-- gets the open state or null.

inv = smartfs.inv[name]
-- gets the open inventory smartfs, if set.
You could then do

Code: Select all

Btn = state:get("name")
Btn:setText("new")

State:_show_()
I will add a function for this, in the future, so you don't call a private function.