GUI Coding Syntax

A place for Ogre users to discuss non-Ogre subjects with friends from the community.
User avatar
nullsquared
Old One
Posts: 3245
Joined: Tue Apr 24, 2007 8:23 pm
Location: NY, NY, USA
x 11

GUI Coding Syntax

Post by nullsquared »

To stop derailing this thread here: http://www.ogre3d.org/phpBB2/viewtopic.php?t=44833

On the topic of interesting GUI syntax, here's my contribution once again:

Code: Select all

        (*_sheet)
            ("size", vec2(_renderer->width(), _renderer->height()))
            // debug panels
            (widget_(window, "debug")
                (widget_(panel, "0")
                    ("texture", string("renderer_gbuffer_0"))
                    ("size", vec2(128, 128))
                    ("draggable", false)
                ,widget_(panel, "1")
                    ("texture", string("renderer_gbuffer_1"))
                    ("size", vec2(128, 128))
                    ("draggable", false)
                ,widget_(panel, "2")
                    ("texture", string("renderer_gbuffer_2"))
                    ("size", vec2(128, 128))
                    ("draggable", false)
                ,widget_(panel, "3")
                    ("texture", string("renderer_gbuffer_3"))
                    ("size", vec2(128, 128))
                    ("draggable", false)
                ,widget_(panel, "4")
                    ("texture", string("renderer_shade_texture"))
                    ("size", vec2(128, 128))
                    ("draggable", false)
                )
                ("size", vec2(5 * 128, 128))
                ("autoArrange")
                ["titlebar"]
                    ["text"]
                        ("text", string("debug"))
                    .up()
                .up()

            // add in scrollbar for time control
            ,widget_(window, "timeSpeedScrollbarWin")
                ("size", vec2(128, 16))
                ("closable", false)
                ("resizable", false)
                (widget_(scrollbar, "timeSpeedScrollbar")
                    ("points", vec4(0, 0, 112, 0))
                    ("position", vec2(112, 0))
                    (EVT_SCROLL, gui::bind(&editorState::_timeSpeedScroll, this, _1))
                )
                ["titlebar"]
                    ["text"]
                        ("text", string("time speed"))
                    .up()
                .up()
            );
It's actually very intuitive to program with, there's no widget casting or anything like that. Creating custom widgets is extremely simple, too, and defining their custom behaviour is as simple as overriding an update() function (and possible the companion 'getter' attrib() function). Thoughts?
User avatar
syd
Gnome
Posts: 362
Joined: Thu May 01, 2008 1:55 am
Location: Paris, France

Post by syd »

interresting. heavily operator oriented :wink:
I usualy prefer a scripted rather than hard coded layout.
The great advantage here is that you can bind events directly, with a script a mapping in the code would be required anyway.
what's inconvinient is that a designer won't be feasible with an hardcoded approach...
User avatar
nullsquared
Old One
Posts: 3245
Joined: Tue Apr 24, 2007 8:23 pm
Location: NY, NY, USA
x 11

Post by nullsquared »

syd wrote:interresting. heavily operator oriented :wink:
I usualy prefer a scripted rather than hard coded layout.
The great advantage here is that you can bind events directly, with a script a mapping in the code would be required anyway.
what's inconvinient is that a designer won't be feasible with an hardcoded approach...
Yeah, it can't be scripted. Would be nice if it could :D. Like you said, either way the even callbacks need to be in hard code (unless you script the callbacks, too, but then you're going very deeply into scripting).

What I like about this approach is that there is never any widget casting or any hardcoded functions like setPosition(), setClosable(), getTitlebar(), setThis(), getThat(), etc. It all Just Flows with a single update() function (operator() is a shortcut so you can chain the update calls).
User avatar
syd
Gnome
Posts: 362
Joined: Thu May 01, 2008 1:55 am
Location: Paris, France

Post by syd »

yep that's an interesting approach, and actually it could be easily scripted.
see, you define attributes such as "size" using a string; this is already a scripting philisophy. then it wouldn't be hard implementing a serialize() /deserialize() methods using Ogre's script compiler :wink:
about callbacks, well even with the most advanced script, it's not possible to script any callback without a mapping in the c++ side, since you can't reference any c++ function/method from a text file.
User avatar
betajaen
OGRE Moderator
OGRE Moderator
Posts: 3447
Joined: Mon Jul 18, 2005 4:15 pm
Location: Wales, UK
x 58
Contact:

Post by betajaen »

syd wrote:about callbacks, well even with the most advanced script, it's not possible to script any callback without a mapping in the c++ side, since you can't reference any c++ function/method from a text file.
I came up with a solution for that. Your widgets don't use callbacks, they cause events; an event can be a string or an integer. Events are less "GUI-y" and actually mean something; start-processing, new-camera-position and so on. Events can carry some information; usually an attribute of the thing causing the event to happen.

It was demonstrated in the Chocolate code I posted; in the thread nullSquared linked to.
User avatar
nullsquared
Old One
Posts: 3245
Joined: Tue Apr 24, 2007 8:23 pm
Location: NY, NY, USA
x 11

Post by nullsquared »

This thread gave me the great idea of scripting my GUI with Lua :D
User avatar
syd
Gnome
Posts: 362
Joined: Thu May 01, 2008 1:55 am
Location: Paris, France

Post by syd »

what I meant is that any type of event; a function callback, event delegates or event messages; at one point you have to associate it manually to some c++ routine.
This thread gave me the great idea of scripting my GUI with Lua Very Happy
that would be nice ;)
i heard squirel is faster though
User avatar
nullsquared
Old One
Posts: 3245
Joined: Tue Apr 24, 2007 8:23 pm
Location: NY, NY, USA
x 11

Post by nullsquared »

syd wrote:
This thread gave me the great idea of scripting my GUI with Lua Very Happy
that would be nice ;)
i heard squirel is faster though
Meh, Lua is already fully integrated into the project, no need for squirrel.
User avatar
nullsquared
Old One
Posts: 3245
Joined: Tue Apr 24, 2007 8:23 pm
Location: NY, NY, USA
x 11

Post by nullsquared »

Comes out quite ugly in Lua. But it works:

Code: Select all

function createGUI(sheet)
    win = sheet:child(gui.window("debugWin"))
    win
        :child(gui.panel("0"))
            :update("texture", "renderer_gbuffer_0")
            :update("size", vec2(128, 128))
            :update("draggable", false)
    win
        :child(gui.panel("1"))
            :update("texture", "renderer_gbuffer_1")
            :update("size", vec2(128, 128))
            :update("draggable", false)
    win
        :child(gui.panel("2"))
            :update("texture", "renderer_gbuffer_2")
            :update("size", vec2(128, 128))
            :update("draggable", false)
    win
        :child(gui.panel("3"))
            :update("texture", "renderer_gbuffer_3")
            :update("size", vec2(128, 128))
            :update("draggable", false)
    win
        :child(gui.panel("4"))
            :update("texture", "renderer_shade_texture")
            :update("size", vec2(128, 128))
            :update("draggable", false)
    win
        :update("size", vec2(5 * 128, 128))
        :update("autoArrange")
        :child("titlebar")
            :child("text")
                :update("text", "debug")

    win = sheet:child(gui.window("timeSpeedScrollbarWin"))
    win
        :update("size", vec2(128, 16))
        :update("resizable", false)
        :update("closable", false)
        :child("titlebar")
            :child("text")
                :update("text", "time speed")
    win
        :child(gui.scrollbar("timeSpeedScrollbar"))
            :update("points", vec4(0, 0, 112, 0))
            :update("position", vec2(112, 0))

    win = sheet:child(gui.window("toolboxWin"))
    win
        :update("size", vec2(256, 128))
        :update("resizable", false)
        :child("titlebar")
            :child("text")
                :update("text", "toolbox")

    win = sheet:child(gui.window("objectPropertiesWin"))
    win
        :update("size", vec2(256, 512))
        :update("resizable", false)
        :child("titlebar")
            :child("text")
                :update("text", "object properties")
end

C++:

Code: Select all

try
        {
            luabind::call_function<void>(_lua, "createGUI", boost::shared_static_cast<widget>(_sheet));
        }
        catch(const luabind::error &e)
        {
            engine::log(e.what());
            engine::log(_lua.error());
        }

        _sheet->childInFamily("timeSpeedScrollbar")
            (EVT_SCROLL, gui::bind(&editorState::_timeSpeedScroll, this, _1));
User avatar
nullsquared
Old One
Posts: 3245
Joined: Tue Apr 24, 2007 8:23 pm
Location: NY, NY, USA
x 11

Post by nullsquared »

Fixed up the syntax in Lua:

Code: Select all

function createGUI(sheet)
    sheet
        :update(
            gui.window("debugWin")
                :update(
                    gui.panel("0")
                        :update("texture", "renderer_gbuffer_0")
                        :update("size", vec2(128, 128))
                        :update("draggable", false)

                    ,gui.panel("1")
                        :update("texture", "renderer_gbuffer_1")
                        :update("size", vec2(128, 128))
                        :update("draggable", false)

                    ,gui.panel("2")
                        :update("texture", "renderer_gbuffer_2")
                        :update("size", vec2(128, 128))
                        :update("draggable", false)

                    ,gui.panel("3")
                        :update("texture", "renderer_gbuffer_3")
                        :update("size", vec2(128, 128))
                        :update("draggable", false)

                    ,gui.panel("4")
                        :update("texture", "renderer_shade_texture")
                        :update("size", vec2(128, 128))
                        :update("draggable", false)
                ) -- end debugWin children
                :update("size", vec2(5 * 128, 128))
                :update("autoArrange")
                :update("title", "debug")

            ,gui.window("timeSpeedScrollbarWin")
                :update("size", vec2(128, 16))
                :update("resizable", false)
                :update("closable", false)
                :update("title", "time speed")
                :update(
                    gui.scrollbar("timeSpeedScrollbar")
                        :update("points", vec4(0, 0, 112, 0))
                        :update("position", vec2(112, 0))
                ) -- end timeSpeedScrollbarWin children

            ,gui.window("toolboxWin")
                :update("size", vec2(256, 128))
                :update("resizable", false)
                :update("title", "toolbox")

            ,gui.window("objectPropertiesWin")
                :update("size", vec2(256, 512))
                :update("resizable", false)
                :update("title", "object properties")
    ) -- end sheet children
end
Now it resembles its C++ counterpart, except it's fully scriptable :D (don't even ask me how much of a hack the binding code is :oops: - but, hey, it works :D )

C++ equivalent:

Code: Select all

(*_sheet)
            ("size", vec2(_renderer->width(), _renderer->height()));
            ( // debug panels
                widget_(window, "debugWin")
                    ("visible", false)
                    (
                        widget_(panel, "0")
                            ("texture", string("renderer_gbuffer_0"))
                            ("size", vec2(128, 128))
                            ("draggable", false)
                        ,widget_(panel, "1")
                            ("texture", string("renderer_gbuffer_1"))
                            ("size", vec2(128, 128))
                            ("draggable", false)
                        ,widget_(panel, "2")
                            ("texture", string("renderer_gbuffer_2"))
                            ("size", vec2(128, 128))
                            ("draggable", false)
                        ,widget_(panel, "3")
                            ("texture", string("renderer_gbuffer_3"))
                            ("size", vec2(128, 128))
                            ("draggable", false)
                        ,widget_(panel, "4")
                            ("texture", string("renderer_shade_texture"))
                            ("size", vec2(128, 128))
                            ("draggable", false)
                    )
                    ("size", vec2(5 * 128, 128))
                    ("autoArrange")
                    ("title", string("debug"))

                // add in scrollbar for time control
                ,widget_(window, "timeSpeedScrollbarWin")
                    ("size", vec2(128, 16))
                    //("position", vec2(0, 0))
                    ("closable", false)
                    ("resizable", false)
                    (
                        widget_(scrollbar, "timeSpeedScrollbar")
                            ("points", vec4(0, 0, 112, 0))
                            ("position", vec2(112, 0))
                            (EVT_SCROLL, gui::bind(&editorState::_timeSpeedScroll, this, _1))
                    )
                    ("title", string("time speed"))

                ,widget_(window, "toolboxWin")
                    ("size", vec2(256, 128))
                    ("resizable", false)
                    ("title", string("toolbox"))

                ,widget_(window, "objectPropertiesWin")
                    ("size", vec2(256, 512))
                    ("resizable", false)
                    ("title", string("object properties"))
            );
User avatar
syd
Gnome
Posts: 362
Joined: Thu May 01, 2008 1:55 am
Location: Paris, France

Post by syd »

man you made it quickly =)
the second version looks indeed better, but in lua it looks like you kept the c++ constraints. I think it would have been better if the script was more "descriptive" oriented. I would look at things such as XAML or XUL, maybe the good old Ogre scripting style ;)

I think it would be great to implement a XUL parser for major Ogre's Gui libs, just my 2 cents :)
User avatar
_tommo_
Gnoll
Posts: 677
Joined: Tue Sep 19, 2006 6:09 pm
x 5
Contact:

Post by _tommo_ »

syd wrote:man you made it quickly =)
the second version looks indeed better, but in lua it looks like you kept the c++ constraints. I think it would have been better if the script was more "descriptive" oriented. I would look at things such as XAML or XUL, maybe the good old Ogre scripting style ;)

I think it would be great to implement a XUL parser for major Ogre's Gui libs, just my 2 cents :)
I quote... Lua has a feature wich makes useless all that C++ like mess :D
You can use tables to have a really much clearer code:

For example, this (not really easy to read))

Code: Select all

sheet 
        :update( 
            gui.window("debugWin") 
                :update( 
                    gui.panel("0") 
                        :update("texture", "renderer_gbuffer_0") 
                        :update("size", vec2(128, 128)) 
                        :update("draggable", false) 
Could become like

Code: Select all

sheet  = {
    gui = {
        guiPanel = {
            number = 0, 
            texture = "render_gbuffer_0",
            size = {128, 128 },
            draggable = false },
        --other panels
    }
      --other GUIs    
}

 application.createSheet( sheet )
   
This would be much easier to read and write, and on top of that, you could also declare pieces of your Sheet alone, like you do now with vertex_program_defs in Ogre:

Code: Select all

defaultPanel = {...}

defaultGUI = { a = defaultPanel,  b =defaultPanel }

defaultSheet = {...}
This way you could easily define and reuse gui components without need of rewriting everything :D
OverMindGames Blog
IndieVault.it: Il nuovo portale italiano su Game Dev & Indie Games
User avatar
KungFooMasta
OGRE Contributor
OGRE Contributor
Posts: 2087
Joined: Thu Mar 03, 2005 7:11 am
Location: WA, USA
x 16
Contact:

Post by KungFooMasta »

What I like about this approach is that there is never any widget casting or any hardcoded functions like setPosition(), setClosable(), getTitlebar(), setThis(), getThat(), etc. It all Just Flows with a single update() function (operator() is a shortcut so you can chain the update calls).
Not sure why you feel the get/set methods are undesirable, they add to the visibility of what can be done, and don't require mastery of the API, such as memorizing what strings are valid in certain context. What happens if I execute this line?

Code: Select all

:update("size", false)
I guess if you're into scripting GUI in code this might be a fun library, but it seems to be very error prone by default. Adding in code to check validity of input from a user would require a lot of maintenance when adding functionality.

I guess this is the difference of 2 philosophies: In one case, the API is extremely flexible and allows for various inputs, and all the rules are not defined (easy to get unwanted behavior), and in the other the input and rules are very defined, but require use of the given APIs. (restricted in some regards)
Creator of QuickGUI!
User avatar
nullsquared
Old One
Posts: 3245
Joined: Tue Apr 24, 2007 8:23 pm
Location: NY, NY, USA
x 11

Post by nullsquared »

KungFooMasta wrote:
What I like about this approach is that there is never any widget casting or any hardcoded functions like setPosition(), setClosable(), getTitlebar(), setThis(), getThat(), etc. It all Just Flows with a single update() function (operator() is a shortcut so you can chain the update calls).
Not sure why you feel the get/set methods are undesirable, they add to the visibility of what can be done, and don't require mastery of the API, such as memorizing what strings are valid in certain context.
You don't have to memorize, there can be (there is) a guide.
What happens if I execute this line?

Code: Select all

:update("size", false)

Code: Select all

/* in the log file */
*-*-* boost::bad_any_cast: failed conversion using boost::any_cast
        in D:\programming\portalized\trunk\src\gui\widget.cpp
        in virtual engine::gui::widget& engine::gui::widget::update(const engine
::string&, const boost::any&)
        at line 331

Code: Select all

/* 331 */
_size = SAFE_ANY_CAST(vec2, val);
Not that useful to a regular user, I know. But if you're coding, then you'll have access to widget.cpp. And if you're scripting, then ... well, you'll find it easy enough when you see 'false' for size :). Besides, I don't like stuff ever crashing, even on error, so this is nice and useful.
Adding in code to check validity of input from a user would require a lot of maintenance when adding functionality.
Not really. It's all about remembering to use SAFE_ANY_CAST over boost::any_cast. Besides, the script is no less safe than the C++ code - it, too, only has a single update() function.
I guess this is the difference of 2 philosophies: In one case, the API is extremely flexible and allows for various inputs, and all the rules are not defined (easy to get unwanted behavior), and in the other the input and rules are very defined, but require use of the given APIs. (restricted in some regards)
It's not that either one is restricted, its just that one flows syntax-wise and the other one looks cumbersome. At least in my opinion.
User avatar
nullsquared
Old One
Posts: 3245
Joined: Tue Apr 24, 2007 8:23 pm
Location: NY, NY, USA
x 11

Post by nullsquared »

@ better use of Lua:

1) I suck at Lua, and yes there are better ways of doing it :)

2) using tables will add lots and lots of Lua-interfacing code, which I'm not too fond of, but will add if point 3 wasn't here

3) using tables will make it deferred - I don't want a deferred approach. I don't want any createSheet() or updateSheet() calls, or updateWidget() or anything like that.
User avatar
syd
Gnome
Posts: 362
Joined: Thu May 01, 2008 1:55 am
Location: Paris, France

Post by syd »

1 :)

I'd go with an xml based script, it would be a lot more intuitive.
have a look at this xul sample (firefox only): http://www.faser.net/mab/chrome/content/mab.xul
efficient, elegant script...
User avatar
_tommo_
Gnoll
Posts: 677
Joined: Tue Sep 19, 2006 6:09 pm
x 5
Contact:

Post by _tommo_ »

nullsquared wrote:@ better use of Lua:

1) I suck at Lua, and yes there are better ways of doing it :)

2) using tables will add lots and lots of Lua-interfacing code, which I'm not too fond of, but will add if point 3 wasn't here

3) using tables will make it deferred - I don't want a deferred approach. I don't want any createSheet() or updateSheet() calls, or updateWidget() or anything like that.
Yeah but... for me an important objective in scripting is ease of use and clarity... so, if you are only to have an 1:1 port of C++ code, the scripting is pretty much a performance hog, with the only advantage being that you don't need to recompile...
IMHO deferring the thing is adviced, because this way you can have a much more effective scripting...
BTW, what do you mean with createSheet() or updateSheet() calls, or updateWidget() calls?
OverMindGames Blog
IndieVault.it: Il nuovo portale italiano su Game Dev & Indie Games
User avatar
jacmoe
OGRE Retired Moderator
OGRE Retired Moderator
Posts: 20570
Joined: Thu Jan 22, 2004 10:13 am
Location: Denmark
x 179
Contact:

Post by jacmoe »

How about basing it on SimKin? It's some sort of scripted XML. :)

Or, maybe Jim (a tiny TCL derivative) ?
What's cool about TCL is that everything is a command.
TCL lends itself particularly well to init and config scripts. :wink:
/* Less noise. More signal. */
Ogitor Scenebuilder - powered by Ogre, presented by Qt, fueled by Passion.
OgreAddons - the Ogre code suppository.
User avatar
betajaen
OGRE Moderator
OGRE Moderator
Posts: 3447
Joined: Mon Jul 18, 2005 4:15 pm
Location: Wales, UK
x 58
Contact:

Post by betajaen »

I have been considering using the JSON format to serialize a Chocolate GUI. A JSON document is easy to create and has a few C/C++ readers. JSONcpp being my favorite.

At least then someone can design a GUI builder in as a web page (which Chocolate is inspired by), or even embed a Javascript interpreter.

[Edit]

Just looking at Spidermonkey by Mozilla.

It gave me an idea. Not only a JSON format can be used to define a GUI, it can be also be used to handle logic and events. JSON is basically a collection of associate arrays, there is no reason why it can't use functions in the middle of it. :)
Last edited by betajaen on Mon Nov 17, 2008 11:03 pm, edited 2 times in total.
User avatar
syd
Gnome
Posts: 362
Joined: Thu May 01, 2008 1:55 am
Location: Paris, France

Post by syd »

BTW, what do you mean with createSheet() or updateSheet() calls, or updateWidget() calls?
i think it means scripts would be able to react to events, and modify the layout, call routines... it'd be some interpreted language layer...
that's a nice idea, it goes far.
User avatar
nullsquared
Old One
Posts: 3245
Joined: Tue Apr 24, 2007 8:23 pm
Location: NY, NY, USA
x 11

Post by nullsquared »

_tommo_ wrote: BTW, what do you mean with createSheet() or updateSheet() calls, or updateWidget() calls?
There's no way for C++ to know that you've created a proper table that's ready for the GUI. You need to tell it - once you make the GUI, you'd need a create() or update() call. Which actually isn't so bad, now that I think about it - I can have a single update() call, definitely. Good ideas!
User avatar
nullsquared
Old One
Posts: 3245
Joined: Tue Apr 24, 2007 8:23 pm
Location: NY, NY, USA
x 11

Post by nullsquared »

_tommo_ wrote:
syd wrote:man you made it quickly =)
the second version looks indeed better, but in lua it looks like you kept the c++ constraints. I think it would have been better if the script was more "descriptive" oriented. I would look at things such as XAML or XUL, maybe the good old Ogre scripting style ;)

I think it would be great to implement a XUL parser for major Ogre's Gui libs, just my 2 cents :)
I quote... Lua has a feature wich makes useless all that C++ like mess :D
You can use tables to have a really much clearer code:

For example, this (not really easy to read))

Code: Select all

sheet 
        :update( 
            gui.window("debugWin") 
                :update( 
                    gui.panel("0") 
                        :update("texture", "renderer_gbuffer_0") 
                        :update("size", vec2(128, 128)) 
                        :update("draggable", false) 
Could become like

Code: Select all

sheet  = {
    gui = {
        guiPanel = {
            number = 0, 
            texture = "render_gbuffer_0",
            size = {128, 128 },
            draggable = false },
        --other panels
    }
      --other GUIs    
}

 application.createSheet( sheet )
   
This would be much easier to read and write, and on top of that, you could also declare pieces of your Sheet alone, like you do now with vertex_program_defs in Ogre:

Code: Select all

defaultPanel = {...}

defaultGUI = { a = defaultPanel,  b =defaultPanel }

defaultSheet = {...}
This way you could easily define and reuse gui components without need of rewriting everything :D
Great advice!

New beginnings!

Code: Select all

sheet:update({
        debugWin = {
            type = "window",
            title = "debug",
            size = vec2(5 * 128, 128),
            panel0 = {
                type = "panel",
                size = vec2(128, 128),
                draggable = false,
                texture = "renderer_gbuffer_0"
            },
            panel1 = {
                type = "panel",
                size = vec2(128, 128),
                draggable = false,
                texture = "renderer_gbuffer_1"
            },
            panel2 = {
                type = "panel",
                size = vec2(128, 128),
                draggable = false,
                texture = "renderer_gbuffer_2"
            },
            panel3 = {
                type = "panel",
                size = vec2(128, 128),
                draggable = false,
                texture = "renderer_gbuffer_3"
            },
            panel4 = {
                type = "panel",
                size = vec2(128, 128),
                draggable = false,
                texture = "renderer_shade_texture"
            },
            autoArrange = nil
        }
    })
:D

Now, considering those panels are equal except for the texture, how would I create a 'template' panel table and reuse it, but change the texture?

(the Lua interfacing code actually isn't too bad, Luabind makes it a piece of cake :D)
User avatar
_tommo_
Gnoll
Posts: 677
Joined: Tue Sep 19, 2006 6:09 pm
x 5
Contact:

Post by _tommo_ »

Wow you changed your mind quite suddenly :P

To have a template panel you could do just like this:

Code: Select all

panelDefault = { 
                type = "panel", 
                size = vec2(128, 128), 
                draggable = false, 
                texture = "UNDEFINED" 
            }, 
--then, in the code, you could "inherit" the default panel:

myPanel = defaultPanel

--you are actually copying the whole structure of defaultPanel.
--so, you can easily override some members, like the texture, doing

myPanel.texture = "overridenTexture"

--this is exactly as overriding super class members in C++, except it's at runtime
It's not that fast, because it has to copy the whole table data, but anyway, speed isn't the point in scripting :wink:
OverMindGames Blog
IndieVault.it: Il nuovo portale italiano su Game Dev & Indie Games
User avatar
volca
Gnome
Posts: 393
Joined: Thu Dec 08, 2005 9:57 pm
x 1
Contact:

Post by volca »

betajaen wrote:
syd wrote:about callbacks, well even with the most advanced script, it's not possible to script any callback without a mapping in the c++ side, since you can't reference any c++ function/method from a text file.
I came up with a solution for that. Your widgets don't use callbacks, they cause events; an event can be a string or an integer. Events are less "GUI-y" and actually mean something; start-processing, new-camera-position and so on. Events can carry some information; usually an attribute of the thing causing the event to happen.

It was demonstrated in the Chocolate code I posted; in the thread nullSquared linked to.
Is this about complexity of bindings or consistency? I tend to think that using named slots per component would solve the latter - with signal name->functor map. The problems seem to be how to transfer parameters of the event to the functor and how to guarantee that the particular component will have a handler.

The consistency checks seem to be useful if the gui is specified in a data file:

Code: Select all

 // pseudocode
GUIWindow* myWindow = GUIManager->createWindow("MY Window");
myWindow->addSignalHandler("OkPressed", new Functor(this, &ThisClass::onOKPressed)); // signal slot handler
// Also possible: component constraint: We need name edit box present
myWindow->addConstraint(new ComponentNeededConstraint("NameEditBox"));
myWindow->loadLayout("myWindow.window"); // at the end, this will check both code slots not in data file and in reverse, and verify all constraints are satisfied
This obviously is not about coding style :)

As for the signal handler's parameters - I tend to think Variant class implementation could be used as a universal parameter, or a map of those. I'm still unsure here.
Image
User avatar
nullsquared
Old One
Posts: 3245
Joined: Tue Apr 24, 2007 8:23 pm
Location: NY, NY, USA
x 11

Post by nullsquared »

I also just realized that I could make the GUI allow scripted callbacks if it wants!

I bet I could create a proxy C++ function as so:

Code: Select all

void _callback(const gui::event &e,  const luabind::object &callback)
{
    callback(e.caller);
}

void _registerScriptedCallback(gui::widget &_this, const luabind::object &callback, const string & id)
{
    _this.callback(id, boost::bind(&_callback, _1, callback));
}

// traversing the widget update table
if (type(*i) == LUA_TFUNCTION)
{
    _registerScriptedCallback(_this, *i, object_cast<string>(key))
}

// in-lua
someWidget:update({
    onClick = (function(caller) print("clicked " .. caller:name()) end)
})
// actually I'm not sure if the syntax is right, but the functions would be possible :D
Thus, I don't see why more libraries don't do this type of boost requirement - it's not really saving anyone considering boost will be std:: soon enough (it already is in tr1, std::tr1:: )
Post Reply