Skip to main content
GameDev.net gamedev.net
🔒 Locked

GUI class layout

Started by Bezben Dec 10, 2005 at 2:45 PM 11 replies 1.4k views
Original Post
Bezben
Bezben
Designing a GUI library of my own, I'm wondering about how best to arrange the widget components for reuse. How do you use your GUIs? I've been considering several designs really: Standard inheritance:

class my_button : public button
{
public:
    void    on_click( void )
    {
        // do stuff
    }
};
Functor based:

void on_click( void )
{
    // do stuff
}

button b;
b.set_click( on_click );

Callback based:

void event_callback( std::string control, std::string message )
{
    if ( control == "button" && message == "on_click" )
    {
        // do stuff
    }
}

Thoughts? Comments? Suggestions?
Bezben
Bezben
I have ideas for what to do, I was more curious as to what style other people prefered and for what reasons.
Flimflam
Flimflam
I use a callback method, myself.

I have a shell, inside I have panels (windows), from there I set a basic callback function that takes three ints and returns an int. It's set like Panel::SetCallback(function_name);

Structured like so:

// panelid: id of panel object// controlid: id of control which triggered event// eventtype: event that was triggeredint UiCallback(int panelid, int controlid, int eventtype) {   switch(controlid) {      case 0x1000:          // do something if control with id 0x1000 was triggered         return 0;         break;   }   return 0;}


All my UI elements inherit from Control (an abstract class). And Control is the class that has SetCallback, so essentially each and every control can be given it's own individual function for it's event processing.

This is how I personally designed mine. and it's worked wonders.
Flimflam
Flimflam
Quote:
Original post by Anonymous Poster
You do not have to keep track of control id's in DWinLib, that is one reason I prefer it over the callback method in the above post. (That is one idea for you, and you might want to delve into the guts of DWinLib just to see how that is implemented.)


As I said in my previous post though, any control can override the callback. So each control could be given it's own callback and control id's would become pointless. :) It woul dmake it somewhat functor based.

For instance:

// callbackint btn_OnEvent(int a, int b, int event) {   if(event == EVENT_CLICK) {      // do something if the particular button was clicked   }}...// in codeButton *btn = new Button(x, y, width, height, "caption");btn->SetCallback(btn_OnEvent);


Setting a global callback for a panel would generally be the result of laziness :)
Flimflam
Flimflam
Quote:
Original post by Anonymous Poster
Quote:
Original post by Flimflam
...So each control could be given it's own callback and control id's would become pointless.


In Windows, control ID's are never pointless. Using DWinLib, control IDs are assigned automatically. I wrote the above post because it appeared that you are having to manually assign control ids with that method.

Use whatever method you want - I was just trying to help. There are some other things in DWinLib that are 'interesting', and worth a look. Feel free to reinvent everything yourself, though. Over a year has gone into DWinLib, so I was hoping it would save you some of that time.

David


Oh I wasn't trying to invalidate your post :) Personally I find more joy in doing things myself, however. Reinventing the wheel or not, it's good thing to learn first hand how things work. In my (WIP) system's defense, you don't need to specify Id's either. If you don't specify one, it's auto-generated. Since it passes the pointer to the control itself, you don't need to pull up Id's, but it helps to specify one (or a name, you can also use string based names) - so you can modify stuff directly without events.

In either case, I was merely saying.
Stevieboy
Stevieboy
Flimflam, where are the graphics for your buttons/panels etc coming from, or where are they stored? Are they stored int he button items themselves?
My gui is a bit of a mess, I'm mainly stuck with the same callback thngs you are at the moment, I don't know what to do either.

My storage is all done with one struct array, this struct cantains pointers to all the various types, and you just initialise the type you want. I've avoided inheritance because I've heard there are some difficulties with this and stl, -freeing pointers etc, I use the stl locally per function or process though, to do things like storing pointers (to the array), for things like showables etc.


Scourage
Scourage
My GUI is done a little differently. I use OpenGL for my drawing code and SDL for my event handling. My GUI that I'm designing is using an inheritance type design. Everything is derived from a UI_element which has a function (virtual) called process_event(event &e). As events are generated, they are passed to the UI_screen. The UI_screen contains UI_areas. Each UI_area has UI_element, some are composite (made of of other UI_elements) others are atomic. Based on the position of the mouse, each UI_element's MOUSE_OVER flag is set. Then each UI_element's process_event(event &e) is recursively called to handle the events. Most done't need to do anything because the mouse is not over them, but if they have a persisitant state, they handle the current action and then call thier children's process_event(event &e). You can check out the source at the sourceforge Positron project CVS (http://sourceforge.net/projects/positron)

I would highly recommend studying the "gang of four's" Design Patterns. Chapter 2 is an example of a GUI design that I found very helpful.

cheers,

Bob

[size="3"]Halfway down the trail to Hell...
CrazyCdn
CrazyCdn
I'm currently making my own wrapper (I like making wheels...). I'm going to spend the rest of the weekend scanning over the DWinLib code. But I auto generate ID's (or they can be assigned), all buttons require a custom function for them (I only have basic buttons in so far) and you can take over window messages for each window if you like. So if you want to have all your buttons added when WM_CREATE is sent to the window it can, your function gets called (this will later lead to things being loaded from xml files).

I'll see if I change anything after checking out the DWinLib stuff. Thanks for the link :)

Mike
"Those who would give up essential liberty to purchase a little temporary safety deserve neither liberty nor safety." --Benjamin Franklin
Flimflam
Flimflam
Quote:
Original post by Stevieboy
Flimflam, where are the graphics for your buttons/panels etc coming from, or where are they stored? Are they stored int he button items themselves?
My gui is a bit of a mess, I'm mainly stuck with the same callback thngs you are at the moment, I don't know what to do either.

My storage is all done with one struct array, this struct cantains pointers to all the various types, and you just initialise the type you want. I've avoided inheritance because I've heard there are some difficulties with this and stl, -freeing pointers etc, I use the stl locally per function or process though, to do things like storing pointers (to the array), for things like showables etc.


Inside the Shell class (the one that holds EVERYTHING), I have a texture object that is used for all the graphics. The Control abstract class has a Render function that has a value passed, which is the sprite object I use to render the controls. I basicly just give the coords of the texture graphic inside the render function, and draw.

Basicly, the only difference between every object is render function, and the extra functions I add for things such as listboxes (AddItem, etc).

The way I manage all the objects is through vectors and maps. (vector is used for number id's, map is used if I search for a control by name rather than id)
luasitdown
luasitdown
Quote:
Original post by Scourage
My GUI is done a little differently. I use OpenGL for my drawing code and SDL for my event handling. My GUI that I'm designing is using an inheritance type design. Everything is derived from a UI_element which has a function (virtual) called process_event(event &e). As events are generated, they are passed to the UI_screen. The UI_screen contains UI_areas. Each UI_area has UI_element, some are composite (made of of other UI_elements) others are atomic. Based on the position of the mouse, each UI_element's MOUSE_OVER flag is set. Then each UI_element's process_event(event &e) is recursively called to handle the events. Most done't need to do anything because the mouse is not over them, but if they have a persisitant state, they handle the current action and then call thier children's process_event(event &e). You can check out the source at the sourceforge Positron project CVS (http://sourceforge.net/projects/positron)

I would highly recommend studying the "gang of four's" Design Patterns. Chapter 2 is an example of a GUI design that I found very helpful.

cheers,

Bob


what is gang of four design patterns??

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.