This is just using Lua for loading the table from/to file into std::map with semi nice syntax for accessing, iterating and modifying. I wrote it before I decided to use XML for data storage too.
A hand made API would make more sense, but it'd be a lot of typing for everything. I don't really like automatic binders and such, many people say that they make worse job than humans even, because of how different c++ and Lua are it's impossible to do it well programmaticaly, binding c++ to Lua is art.
It's hard as hell and makes your brain turn upside down after a while.
I gave it a bit of thought(I'm not going to do it, it's not worth it at this point, SFG lacks too much IMO) in the past and it's a bit complicated and long write to explain it.
1. each callback has unique id from 0 to numcallbacks-1, every single one, even ones like ontext(from entry) and ontoggle(from togglebutton) can't overlap
2. have a way to turn string name of signal into number in that range(lua has support function for that actually so its just 1 call and one const char array), make const char arrays for all enums when youre at it
3. make metatables for each widget type, also they must have functions that go: asBase, where base is one of the bases, so toggle button has asButton and asWidget, window has asContainer and asWidget, etc. there are for downcasting
4. make global functions like ones in point 3, these will be for upcasting, one per each type of widget
5. make callback class that has ALL possible callbacks as void() functions and array of ints that is numcallbacks in size, init them all to LUA_NOREF
Creating new widget:
create full user data and new in it a struct that consists of right type of widget ptr and one int(can be template struct),
Create() the widget(optionally getting params from stack), create new user data sizeof callback class from 5., and new callback class in it, store that in registry, put the ref into the int in the first struct, return the first user data, done
Casing up(ie. button->widget, done in metamethods so we know type):
create full user data, new in right struct, fetch ptr and int from struct passed in as self, now set the ptr, fetch the reference and make new one to that user data you just fetched, and store it in the struct you just new'd, return it, done
Casting down(ie. widget -> container, done in global functions so we always use widget):
if sfg::DynamicPtrCast fails just return, if not, create full user data, new in right struct, etc. , set ptr and int in struct like before in up cast, done
Callbacks:
use that function from 2. to get right index of callback that you assigned in 1., then using self struct's int, get full user data, now in that user data array of ints, look up the index you just got using function from 2., if its NOREF or REFNIL create new metatable in registry and then store ref in that index, if not just fetch that table, in both cases, add the function as reference in that table, return that reference as number of full user data(to prevent changes) so it can later be used for disconnecting
Disconnecting:
similar, self struct to get user data callback class in registry, then just get the table via reference and free the passed in reference from it
This ends up with nice way to do literally everything:
button = sfg.Button.Create"blablautf-8str";
box = sfg.Box.Create"Vertical";
box:Pack(button:asWidget(),true,false);--up cast
hehe = button:ConnectCallback("OnLeftClick",function() print"hehe" end);--connecting signal
button:DisconnectCallback("OnLeftClick",hehe);--disconnecting signal
box2 = asBox(button:getParent():asWidget());--down cast
(Sorry for mixing two naming conventions in this small snippet
)
When all instances of one widget, in all pointers die, then widget will die too, and it'll free callback class which will free all the tables with callbacks which in turn frees these functions
I of course left out small details like ctors, dtors, __gc meta methods themselves etc. but they are very obvious, just tedious to write.
For strings in unicode you can use UTF-8, Lua will pass them around no problem and then you can conver them to sf::String on c++ side.
Also, you should probably recompile your Lua as c++, or you're in for nasty surprises when things start leaking because Lua C default errors/'exceptions' don't call destructors.
This is kind of complicated but it's really good IMO - it allows connecting and disconnecting many signals and supports polymorphism and up and down casts. This also has nice effect that you can connect any callback to even widget and it'll work 100% well if it's there and just get silently ignore if it's not there.
Pretty much any other binding I thought of so far will have pitfalls with signals or up and down casts or something. Of course this is assuming faithful binding, not just extension of functionality.
That was long...
You need good understanding of Lua, tables, references, pseudo indices and user data to do all that.
I could actually help with Lua part if you were to try and bind entire of SFG to Lua, but it'd be really asymetric partnership(me=fun Lua API manipulations, you = writting most of tedious C wrappers for SFG methods) and you might not be happy with that.
If you just want
some Lua GUI you might look at lua users wiki or at cegui.
It probably wouldn't be too hard, honestly with two or three alright c++ and/or Lua programmers cooperating irl it could be done overnight, that's one of strengths of Lua flexibility and small but powerful C API, any C or c++ library can easily become Lua one.
You can PM me if interested in that way of binding or in making that binding together.