Jump to content

  • Log In with Google      Sign In   
  • Create Account

FREE SOFTWARE GIVEAWAY

We have 4 x Pro Licences (valued at $59 each) for 2d modular animation software Spriter to give away in this Thursday's GDNet Direct email newsletter.


Read more in this forum topic or make sure you're signed up (from the right-hand sidebar on the homepage) and read Thursday's newsletter to get in the running!


Game engine gui design


Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.

  • You cannot reply to this topic
23 replies to this topic

#1 Juliean   GDNet+   -  Reputation: 2746

Like
0Likes
Like

Posted 21 August 2012 - 04:50 AM

Hello,

so I'm currently writing the gui for my 2d game engine, and though everything is working fine for now, I wonder if there is any better way of designing this?

So i think on the basic everyone should agree:

I have a EditorObject-class, and from this class I inherit EditorImage, EditorWindow, EditorButton, EditorScrollbar, EditorToolbar, and more to come.

But, my question is now, how do I put this together the right way?

Right now I'm having a window for the tilesets and tile selection, and one that displays the map and lets me draw tiles on it. I achieved this by inheriting the classes WindowTileset and WindowTilemap from the EditorWindow-class. I just need to overload the constructor and the virtual Draw() and (important) Update()-functions, so there is no doubled code from this. Things are working way more neat than I'd have expected, but..

.. is this the right approach? What would you guys do here? If I keep on doing this I'm going to inherit a hell of a lot from the EditorWindow-class for every window I need (WindowNewProject, WindowDatabase ..), which is working, but again, isn't this a little overuse of OOP? What other concepts are there available, and are they useful in my context?

Sponsor:

#2 Mussi   Crossbones+   -  Reputation: 2104

Like
1Likes
Like

Posted 21 August 2012 - 07:25 AM

I'd use an existing library instead of writing my own. Right now you're abusing OOP, I'd recommend you to look into composition. There is a great thread going on about this here.

#3 Radikalizm   Crossbones+   -  Reputation: 2992

Like
1Likes
Like

Posted 21 August 2012 - 08:15 AM

I agree with Mussi that you should look into 3rd party libraries, as GUI systems can get quite massive, but if you really insist on doing this yourself you're going to have to look into some other programming concepts, because you are in fact abusing OOP quite horribly.

You should look into the Observer pattern and the Model-View-Controller model so you can decouple the actual visual representation of your GUI elements from the data they represent, and so you can create a generic method of accessing and modifying data through a GUI.

Note that this can become a massive amount of work for an entire GUI library, so you'd really be off better with a 3rd party library.

I gets all your texture budgets!


#4 Juliean   GDNet+   -  Reputation: 2746

Like
0Likes
Like

Posted 21 August 2012 - 08:48 AM

Thanks to both of you,

I indeed insist on writing my own libary, so I'd just like to know more exactly when my OOP-abusion takes place.

Your talking about the derivations like WindowTileset, WindowTilemap, right? Or is my overlaying system bad, too? I've had a quick look at the observer-pattern and it seems like my base components like EditorImage, EditorSrollbar, just meet that criteria. EditorScrollbar e.g. holds three values, a minimum and a maximum, as well as a current one and manipulates that, without knowing what those values actually represent. Is this bad design, too? If yes, what benefits could I get from decoupling this?

Oh, not to forget, this gui right now is just being used for the game editor itself. Thats why I didn't want, though already reading into that other thread, to hijack it, as I thought this is a somewhat different topic. The editor itself is more static, so I quess graphics<->logic decoupling isn't that necessary.. right?

So in case just the "higher-level" derivations like WindowTileset that should be changed, how would I do that? Would I make a struct like this:

struct Tileset
{
EditorWindow* pWindow;
EditorImage* pTilesetImage;
EditorSelectRect* pSelectRect;
Update();
Draw();
}

Would this be sufficient? Or do I really need to go with a component based system, or a true observer-pattern / model-view-controller? What are the benefits of this? I feel like my current approach is really practical to work with, expect the over-use of OOP when inheriting from EditorWindow.

#5 CC Ricers   Members   -  Reputation: 804

Like
1Likes
Like

Posted 21 August 2012 - 09:25 AM

I agree that if you want to learn how to write a GUI system for yourself, apply composition well. Form objects can be usually be broken down into components intuitively. For instance, a clickable menu entry can be an aggregate of a TextEntry and a Button. Meaning, it's just a barebones class that contains objects of those two types. A scrollbar (just the bar itself, not the screen it scrolls) would be a Button and a Draggable entity with vertical/horizontal constraints added to it. Here, I've decoupled the components so that they will do very little (if at all) communication with each other. For a menu entry, the Button may just need to know the dimensions of the TextEntry so it can resize its "hot spot" accordingly. I'm not saying this is the best solution to go with, but it's a great improvement over using a large hierarchy of inherited classes.

I have written a older post in this topic that Mussi was pointing to, but it describes my experience with adding some basic UI elements and how I've gotten around to decompose its functions, so it might be worth a look. I'm writing my own UI because I do not need anything very complex for my game.
My development blog: Electronic Meteor

#6 Radikalizm   Crossbones+   -  Reputation: 2992

Like
1Likes
Like

Posted 21 August 2012 - 09:35 AM

Definitely take a look at MVC and study it in detail

With MVC there's no need for you to define different classes for different types of windows for example. You would just have your 'EditorWindow' class (which you should maybe generalize to represent any Window, whether it's part of your editor or not) which is only worried about representing itself correctly to the user (hence being a 'View'). The window object absolutely does not care about which data it is representing, that's what the 'Model' behind the window should be taking care of.

This way you avoid unneeded inheritance for every single use case you might have, and allows for a much simpler, cleaner and easier to maintain GUI system.

Composition is also a crucial point of course when designing a GUI library, but the problem of designing your widgets/elements themselves well is still something different than designing the interaction between widgets and the use cases they occur in and the data they're supposed to represent.

If you want to see some examples of the MVC model you should take a look at Qt, which uses this extensively

I gets all your texture budgets!


#7 Juliean   GDNet+   -  Reputation: 2746

Like
0Likes
Like

Posted 21 August 2012 - 10:05 AM

@CC Ricers:

For instance, a clickable menu entry can be an aggregate of a TextEntry and a Button


A scrollbar (just the bar itself, not the screen it scrolls) would be a Button and a Draggable entity with vertical/horizontal constraints added to it


Thats just how I was planning to handle things, except that my scrollbar still inherits from EditorObject, because, after all, isn't this a "base object" too? This drastically reduces the amount of code needed as well. Maybe I should show you what EditorObject looks like:
#pragma once
#include <Windows.h>
#include <vector>
#include "Input.h"
#include "Sprite.h"
using namespace std;
class EditorObject
{
public:
EditorObject(void);
virtual ~EditorObject(void);
void Setup(int iID, int iX, int iY, float fZ, int iWidth, int iHeight, Sprite* pSprite);
virtual bool Over(Vector2 vMousePosition); //mouse is pointing at this object?
virtual void Draw(float fZ);
virtual EditorObject* Check(Vector2 vMousePos); //return object at which the mouse is pointing
virtual bool Update(void);
virtual void UpdateSuper(int iOffX = 0, int iOffY = 0);
void SetX(int iX);
void SetY(int iY);
void SetSuperX(int iX);
void SetSuperY(int iY);
int GetID(void);
int GetX(void);
int GetY(void);
int GetWidth(void);
int GetHeight(void);
Sprite* GetSprite(void);
protected:
bool Activate(bool bActive, int iStateID = 0);
bool IsActive(int iStateID = -1, int iStateException = -1);
bool m_bActive;
int m_iActiveState;
int m_iX, m_iY, m_iOffsetX, m_iOffsetY, m_iSuperX, m_iSuperY;
int m_iWidth, m_iHeight;
float m_fZ;
Sprite* m_pSprite;
int m_iID;

Vector2 ProjectPosition(Vector2 vMousePos, bool bCap=true); //project a given point to object space
};

So EditorObject describes a general object with variables that apply to every gui element. (position,size, a sprite object). The whole Super-thingy is for traversion, it spares me having to pass the holding objects x/y-coordinates all the time. ProjectPosition() is a helper function that outputs the mouse coordinates relative to the objects position, saves me a lot of math.

So I quess everyone would agree that I should at least inherit these classes from that:

EditorImage
EditorButton

If not, why?

If yes, why shouldn't I, example given, also inherit the Scrollbar from this?

The scrollbar, while being basically a composition of three buttons and a background-image, does have its own coordinates, destinctive size, needs to be drawn in relation to other objects, etc.. so whats exactly wrong about that or, better said: What are the benefits of composition here? What is such a huge improvement from having an extern controller handling the scrollbars usage to just having the Update() method do it? This is what, for example, the inherited scrollbar-class looks like:
#pragma once
#include "EditorButton.h"
#include "Timer.h"
class EditorScrollBar :
public EditorObject
{
public:
EditorScrollBar(void);
virtual ~EditorScrollBar(void);
void Setup(Sprite* pSprite, Texture* pFrame, int iID, int iX, int iY, float fZ, int iLength, bool bVertical);
void SetButtons(EditorButton* pUpperButton, EditorButton* pLowerButton, EditorButton* pMidButton);
void SetValues(int iMinVal, int iMaxVal);
void SetNowValue(int iNewValue);
int GetNowValue(void);
void Draw(float fZ);
bool Update(void);
void UpdateSuper(int iOffX = 0, int iOffY = 0);
private:
int m_iMinVal,m_iMaxVal,m_iNowVal;
Vector2 m_vTemp;
Timer m_cTimer;
EditorButton* m_pUpperButton, *m_pLowerButton, *m_pMidButton;
};

Except that Setup() and SetButtons() could/should be moved to the constructor: Again, why would I want to composite instead of inherit here? The scrollbar class uses everything from its super-class, and just extents it. Do I really have such a misunderstanding of OOP-basics or is it some matter of opinion whether you see a scrollbar a base object here?

So I know that my EditorWindow->WindowTileset/WindowTilemap-classes are bad and I'll going to replace that with some composited objects here, but I really see to fail the point for such a basic objects as a scrollbar.

PS: Sry for bad spacing, code-tags killed it..

@Radikalizm:

Ok, that makes more sense to me for the window class, I'll aplly that to replace my WindowTileset etc.. inherited classes. Still, I don't see why I would want to do this to e.g. the scrollbar, or a button. Well maybe things will get more clear if I implement it for those said classes first.

Edited by The King2, 21 August 2012 - 10:28 AM.


#8 Radikalizm   Crossbones+   -  Reputation: 2992

Like
1Likes
Like

Posted 21 August 2012 - 11:05 AM

Any GUI element/widget should inherit from a common Widget base class (EditorObject in your case), you're right about that since every widget will hold a set of similar data (position, id, rotation, etc.). So yes, the scrollbar should be inherited from your EditorObject class.



What I don't see here in your implementation is a widget hierarchy. The lack of this hierarchy is causing some of the problems you're having here I believe, and it makes you resort to some quite hacky and non OO implementations. Those "super" functions are some very obvious warning signals here -to be honest with you I have no idea what these are supposed to do, but from your description I can pretty much assume they are a hack-, just like that "check" function you have in your EditorObject class.

With a hierarchy you define a root widget which has all the widgets in your editor as children. Each of these widgets can have children of themselves as well, and the position of these children now becomes relative to their parents. The absolute position of a widget now becomes: relative position to parent + absolute position of parent.

If you look at the scrollbar example now you'll have the Scrollbar class which inherits the EditorObject class, and which is composed of 3 buttons which are all children of the scrollbar.

Sticking all of your behavioral code inside an update function of a widget instead of using MVC for example will force you to create a new class which inherits your scrollbar for each use case you might ever have, which will result in a huge amount of redundant code. I already explained this in my previous post.
Also, say you were to create a new class for every use case you ever encounter, and later on you need to make some changes to your base class declaration (your scrollbar for example). You'll now have to go back to every use case class of your scrollbar and update their declarations as well, which is just a huge time-waster.

Maybe it wouldn't be a bad idea to review your OO basics, since you're making some other violations against proper object-oriented design:

- Violation of the Single Responsibility Principle (SRP). Stick with SRP at all costs and make sure one class always is responsible for doing one and only one task. Returning the widget which the mouse is pointing to is not the responsibility of a widget!
- Improper constructor usage. 2-step initialization like you're applying here can be a dangerous practice as your class invariant is violated until you call the setup function in your EditorObject class. You only need to forget to call the setup class once after creating an EditorObject and you get sent straight to undefined-behaviour-land, which is not the happiest of places.

I gets all your texture budgets!


#9 Juliean   GDNet+   -  Reputation: 2746

Like
0Likes
Like

Posted 21 August 2012 - 11:33 AM

What I don't see here in your implementation is a widget hierarchy. The lack of this hierarchy is causing some of the problems you're having here I believe, and it makes you resort to some quite hacky and non OO implementations. Those "super" functions are some very obvious warning signals here -to be honest with you I have no idea what these are supposed to do, but from your description I can pretty much assume they are a hack-, just like that "check" function you have in your EditorObject class.


Well those "super"-functions are basically my scene hierachy, Take, as example the scrollbar:

The scrollbar, upon drawing, will call SetSuperX() and SetSuperY() for its buttons. On drawing, these variables are taking into account for the position where the button is drawn to. Same applies to the scrollbar itself, probably hold by a window, which is hold by the main frame. I actually adapted this from a project using an rpg-maker, that obviously lacked much of c++ functionality. Still, it is working, and except for having to overload the UpdateSuper()-method for every base object an making sure it is called for the parent-widget, its easy to use. However I'd still be glad to know about any better variante for handling a scene hierachie..?

With a hierarchy you define a root widget which has all the widgets in your editor as children. Each of these widgets can have children of themselves as well, and the position of these children now becomes relative to their parents. The absolute position of a widget now becomes: relative position to parent + absolute position of parent.


Like i said, "super" basically does exactely that, but if there is an easier way, I'd like to know..

Sticking all of your behavioral code inside an update function of a widget instead of using MVC for example will force you to create a new class which inherits your scrollbar for each use case you might ever have, which will result in a huge amount of redundant code. I already explained this in my previous post.


Thats a point I cannot follow. Ok, I've read up about normal widget/gui design and since most, if not all of them seem to use some sort of event - slot/signal - system, I've made a fundamental flaw right there. But in my application, I can use the scrollbar just as it is without rewriting it for each use case. From what I've experienced every toolbar is the same: You can click on the outer two buttons to scroll the bar up and down, or drag the middle button, or click anywhere else on the bar. And thats what my update-method does. It also sets the m_NowValue-variable between m_MinValue and m_MaxValue. Later on, I can access these values and do whatever it takes, whether its a bad oop-derived window-class, or a composited class using MVC. So while it is not the best oop-use, it still doesn't produce any redundand code or makes it hard to use, does it?

- Violation of the Single Responsibility Principle (SRP). Stick with SRP at all costs and make sure one class always is responsible for doing one and only one task. Returning the widget which the mouse is pointing to is not the responsibility of a widget!


How else would I handle this? It seemed logical to me that a widget should have the ability to return the widget it was pointing to, only including itself and its childern..

- Improper constructor usage. 2-step initialization like you're applying here can be a dangerous practice as your class invariant is violated until you call the setup function in your EditorObject class. You only need to forget to call the setup class once after creating an EditorObject and you get sent straight to undefined-behaviour-land, which is not the happiest of places.

Ok, this is totally clear to me, its a bad habbit of mine. It does work well too because I'm using a factory class right now which stuffs all that together, but I'll remove it anyway.

#10 Radikalizm   Crossbones+   -  Reputation: 2992

Like
1Likes
Like

Posted 21 August 2012 - 12:26 PM

If you were to add an addChild() method to your EditorObject class which accepts another EditorObject, and if you were to maintain an actual list of children inside an EditorObject you could easily update your entire gui with only a single update call on the root widget. Within each update call in a widget you would traverse the list of children and do an update call on each of them individually, which gives you a nice recursive way of updating the gui.

Managing your gui in such a tree structure also makes your gui much easier to traverse from a programmer's point of view, as having access to a parent widget means having access to the entire subtree which that parent is root of.
I remain with my statement that using those super-methods is pretty much a hack.


Maybe I'm misinterpreting the way you use your update function in your gui elements, if that's the case just let me know. Right now, since I don't see any other way how you're updating your actual logic to manipulate your back-end data (eg. how does your scrollable window know that your scrollbar has been updated?), I'm assuming you're doing this in your update function.

The scrollbar example might not be the best example to explain the MVC principle, sorry for that. Let me try to explain it with a different example:
Let's take the simple example of a button. A button is both a visual representation of some dataset, and can manipulate a controller. Let's say you have a button on your GUI, and when you click this button a value gets added to an array you defined somewhere in your code for example. This array is of a fixed size however, and when this array reaches its limit the button should not be clickable anymore.

We separate this situation into a model, a view and a controller. The model is the array, which in our case can have 2 states: "Able to accept values" and "Not able to accept values". The view is our button, and depending on which state the model is in it can change state between "Enabled/Clickable" and "Disabled/Not-clickable". The controller is assigned to our button and it can manipulate our model (the array) by telling it that it should add a value to itself.

Now let's look at what happens when our button is clicked:
-The system managing your GUI gets a mouse-click event and checks whether the mouse position at the time of the click event was over a GUI element, and if so it sends an onClick message to said element. In our case we clicked the button, so our button will receive this message.
- Since the button received the onClick message it has to notify all its associated controllers, among them the controller for our array. The controller for the array sends a message to the model that it should be manipulated, and the model adds a value to the array.
- A value is added to the array, and the state of the array is evaluated. If a state change is triggered (ie. the array has reached its limit) it sends a message to all its views informing them of this state change.
- The button receives this state change message from the model and acts out its role as view. The button sets its state to disabled since no more values can be added to our array.


If you wanted to do all of this purely with inheritance you'd have to create a button class which would handle this entire process in its update system. Also, if you wanted your button to be able to control and represent multiple sets of data at once you'd have to create a separate case for that as well, whereas MVC allows a single controller to manipulate and a single view to represent/observe multiple models.
The update function for you GUI elements should only be responsible for making sure it is correctly represented in your GUI at all times, and should refrain from doing any actual logic manipulating your back-end data.



--- End example ---

On to your other questions:

Returning the gui element your mouse is pointing to should be the responsibility of the system managing your GUI. It is perfectly fine for a gui element to have a function which determines whether a point is inside its area (and that point could be the mouse position), but it's up to the system maintaining the GUI to determine which element(s) has/have been clicked, and to return that element to the system which requires it.

Edited by Radikalizm, 21 August 2012 - 12:29 PM.

I gets all your texture budgets!


#11 Juliean   GDNet+   -  Reputation: 2746

Like
0Likes
Like

Posted 21 August 2012 - 01:38 PM

Ok, things are much more clear to me now. Lets go through it:

f you were to add an addChild() method to your EditorObject class which accepts another EditorObject, and if you were to maintain an actual list of children inside an EditorObject you could easily update your entire gui with only a single update call on the root widget. Within each update call in a widget you would traverse the list of children and do an update call on each of them individually, which gives you a nice recursive way of updating the gui.
Managing your gui in such a tree structure also makes your gui much easier to traverse from a programmer's point of view, as having access to a parent widget means having access to the entire subtree which that parent is root of.
I remain with my statement that using those super-methods is pretty much a hack.


I actually have a vector<EditorObject*> included to the EditorObject-class that I can add child objects too. I still felt like hardcoding certain consistant elements like the three buttons for the scrollbar makes things easier to work with. I'll have to overload the UpdateSuper()-method, but thats not a huge problem, since there is not such a huge amount of base objects derived from EditorObjects anymore after I got rid of the redundand ones..

Oh, by the way, I figured that what you mean that my update-method does is indeed the Update_Super-method, except I'm not passing the parents coordinates to the update-method but with SetSuperX() and SetSuperY(). Update_Super would just do the same thing for the (hard-coded) children.

Maybe I'm misinterpreting the way you use your update function in your gui elements, if that's the case just let me know. Right now, since I don't see any other way how you're updating your actual logic to manipulate your back-end data (eg. how does your scrollable window know that your scrollbar has been updated?), I'm assuming you're doing this in your update function.


My windows knows about it from the return of Update(). If its true, it has been updated, So if m_pScrollbar()->Update() returns true, it calls m_pScrollbar->GetNowValue() to get the actual value and adjusts the content to that. It does that by setting the m_iOffSetX or Y variable, that is used in UpdateSuper() to set the according contents position.


If you wanted to do all of this purely with inheritance you'd have to create a button class which would handle this entire process in its update system. Also, if you wanted your button to be able to control and represent multiple sets of data at once you'd have to create a separate case for that as well, whereas MVC allows a single controller to manipulate and a single view to represent/observer multiple models.


Well not quite, at least in my system. The Update()-method of the button determines its state: clicked, hold, hold+over, released, released+over (=activated). it returns true if any of these states apply, and the holding object then decides what to do with that, by checking if it has been activated. The object holding it might then call Down() to fix the button, Up() to release it and SetActive(bool) to make it unclickable/clickable. This is, example given, how I handle my tileset-toolbar right now:

EditorButton* pButton = m_pToolbar->GetActiveButton();
if(pButton == NULL || !pButton->Pressed() || !pButton->Over(Input::GetMousePos()))
  return false;
switch(pButton->GetID())
{
case 0:
  (*m_ppBrush)->SetErase();
  break;
case 1:
  {
   pButton->Down();
   PencilBrush* pPencilBrush = new PencilBrush(**m_ppBrush);
   delete *m_ppBrush;
   *m_ppBrush = pPencilBrush;
   m_pToolbar->GetButton(2)->Up();
   m_pToolbar->GetButton(3)->Up();
   break;
  }
case 2:
  {
   pButton->Down();
   RectBrush* pRectBrush = new RectBrush(**m_ppBrush);
   delete *m_ppBrush;
   *m_ppBrush = pRectBrush;
   m_pToolbar->GetButton(1)->Up();
   m_pToolbar->GetButton(3)->Up();
   break;
  }
case 3:
  {
   pButton->Down();
   BucketBrush* pBucketBrush = new BucketBrush(**m_ppBrush);
   delete *m_ppBrush;
   *m_ppBrush = pBucketBrush;
   m_pToolbar->GetButton(1)->Up();
   m_pToolbar->GetButton(2)->Up();
   break;
  }
}

So other then having that a case-statement and knowing the button by ID (it's not a big deal), I can just call new Toolbar, push back a few new buttons, and that code above is all I need to get it to work.

--- MVC-explanation ---

Ok, so I've read what you explained, and MVC definately sounds like a concept that does fit perfecly here. I don't know how I'd go about implementing it right now but thats maybe because I haven't worked with messaging-systems at all until now. But, before I go ahead and screw my current approach, I'd like to ask once again: Do I really get that much advantage of using it? Sorry, I don't mean to be annoying or anything, I just like to question things. There are many worst-case-scenarios you described, which happend to me in my first try on writing a map editor years ago. I've overused OOP to an extent that it wasn't workable with, like you described, and the whole thing wasn't even working well. It didn't have the featureset I already have by this time, though the older one took much longer to develop. Maybe I didn't emphasise that enough, but the current system works flawlessly, so I'm not asking for an alternative because my current approach is unworkable, no, it works so well that I'm looking for a way of making things even easier to work with. So, in a nutshell, here is how the whole update-routine works (or will work after I got rid of the EditorWindow-derived classes):

- Main frame calls Update() on all of its widgets
- Update() first sets traversal coordinates for all its children by calling UpdateSuper() (sry, I just realized how confiusing this may appeal. I'll try to improve it)
- next, Update()- all of the children
- If widget without children is hit: perform a self-update (e.g. button deciding what state is in)
- If widget was activated, return true, else false
- If Update()-returns true: set children as active, perform destinctive actions (eg. set offset variable when scrollbar has changed), skip other children and self-update, else proceed

So now at this point I'm not sure how to proceed. Thinking about it, isn't that almost what MVC tells? Except that I don't let an extern controller regulate the basic actions like a button being clicked, but.. whats the point here? Every button will work the same so why would I want an extern button-controller when I can simply let the button handle itself? And again, I'm not talking about how the button manipulates that data, I'm just talking about the buttons states. But hold onm a second. Say if I where to make my widgets able of registering a controller, to that the button sends the information that it was activated, and let that controller decide how to manipulate the back-end data. Wouldn't that be almost what you were talking about? That would be my plan for now, composing the destinctive windows (tileset,tilemap), out of one or more widgets, having a controller, registering that controller to the widget and having it send information back to the controller. How does that sound, in combination with my above update procedure?

Edited by The King2, 21 August 2012 - 01:51 PM.


#12 Radikalizm   Crossbones+   -  Reputation: 2992

Like
1Likes
Like

Posted 21 August 2012 - 02:10 PM

Say if I where to make my widgets able of registering a controller, to that the button sends the information that it was activated, and let that controller decide how to manipulate the back-end data.


That's basically the concept of using a controller yes, the button does not need to know what kind of controller it's maintaining, only that it is a controller, so any type of controller which could control any kind of model could be assigned to this button.

My windows knows about it from the return of Update(). If its true, it has been updated, So if m_pScrollbar()->Update() returns true, it calls m_pScrollbar->GetNowValue() to get the actual value and adjusts the content to that. It does that by setting the m_iOffSetX or Y variable, that is used in UpdateSuper() to set the according contents position.


In this case a window must explicitly know that it has a scrollbar which is manipulating it, which is not something you want in a flexible gui. What if you wanted to add a button to your window which scrolled down to a certain piece of content? With this method the window object would now also have to poll this button on each update to see whether it was clicked and update itself accordingly. Doesn't sound all too flexible, does it?
The same applies for the toolbar example you gave. Adding a button to the toolbar would require you to go in and edit the toolbar code to allow this new button to perform a certain task. With MVC you can add any generic button to any generic toolbar, and you can register a specific controller to that new button which completely defines its behaviour. No need to go in and edit your classes each time you want to add a certain bit of functionality for a specific use case.
The result of not having to go in and modify your code for widget behaviour is that you basically create a very simple environment where you can just compose your GUI by using completely generic widgets (buttons, scrollbars, images, windows, etc.), after which you assign models to them so they display the data they need to display and controllers so they can manipulate data. If you really wanted to you could do this entirely in a visual editor without once having to touch any piece of code.

I stepped away from this to hard-code the objects and overload the UpdateSuper()-method. This was most definately unevadable due to my design, since without any messaging system, I pretty much depend on specific objects to being certain methods called on directly.


This is a design flaw, and hardcoding everything in and making these objects which are supposed to be decoupled from one another explicitly know about eachother is not a solution. In the case of a bad design you should modify your design to something that is extensible and which works without hacks instead of adding more hacks to make the original design work.
Some form of messaging will be required eventually in a GUI system, so better to design it properly now instead of having to go back and adjust your design later on. MVC can provide a solution here since broadcasting of state changes and events is automatically implied as soon as one occurs.

Your current system might work now, but I can guarantee you that extending it and adding complex interactions to it will become a huge pain, both to implement and maintain.

I gets all your texture budgets!


#13 Juliean   GDNet+   -  Reputation: 2746

Like
0Likes
Like

Posted 21 August 2012 - 02:40 PM

Ok, I've almost got it.

That's basically the concept of using a controller yes, the button does not need to know what kind of controller it's maintaining, only that it is a controller, so any type of controller which could control any kind of model could be assigned to this button.


So I'd design a generic controller interface, but how would I go about sending messages to it? My first intuitive would be to write different generic message-method like button_clicked, scrollbar_moved, and overload these, but it sounds again a little messy. Maybe a general send_message()-method where I pass information on what type of object sent it? Or anything completely different? Before stepping ahead and starting implenting it, I want to make sure. And I do inherit from the generic controller for the certain use purposes, right, or is there still something different to it?

In this case a window must explicitly know that it has a scrollbar which is manipulating it, which is not something you want in a flexible gui. What if you wanted to add a button to your window which scrolled down to a certain piece of content? With this method the window object would now also have to poll this button on each update to see whether it was clicked and update itself accordingly. Doesn't sound all too flexible, does it?



Flexibility wasn't my main purpose. Aside of my design flaws, I just made some deliberate simplifications as e.g. every window has two scrollbars (which might there or not) and a toolbar, etc.. well while I'm at it I might make it more flexible as well.

The same applies for the toolbar example you gave. Adding a button to the toolbar would require you to go in and edit the toolbar code to allow this new button to perform a certain task. With MVC you can add any generic button to any generic toolbar, and you can register a specific controller to that new button which completely defines its behaviour. No need to go in and edit your classes each time you want to add a certain bit of functionality for a specific use case.



Not quite, as in the code I posted above (it's in the redundand WindowTileset-class but still) the button actions are handled, and my toolbar stores a vector<EditorButton*>, so all I'd really have to do is change that type of code. But since I might want to add other objects to the toolbar as well, I should make it more general, too.

This is a design flaw, and hardcoding everything in and making these objects which are supposed to be decoupled from one another explicitly know about eachother is not a solution. In the case of a bad design you should modify your design to something that is extensible and which works without hacks instead of adding more hacks to make the original design work.
Some form of messaging will be required eventually in a GUI system, so better to design it properly now instead of having to go back and adjust your design later on. MVC can provide a solution here since broadcasting of state changes and events is automatically implied as soon as one occurs.


Ah, I slowly realize how much neater to work such a generic system was. Ok, so what if I made this:

- First, i call MainFrame->Update(). Update() now doesn't do anything more than traverse all the child objects, and so on.
- If the main controller receives any event (mouse-move, mouse-click) it will check recursively if an widget is underneath the mouse OR marked active (if I e.g. clicked on a button and hold the mouse, I don't want anything else happen unless the mouse is released, and even if it is, the release-message should still be sent to the button original held. Do I really need to keep like a extra pointer if an object is active and check that first, or is there any way to automatice that?) and send a message to the widget, like onClick(). (By the way, can I just send messages as a method, so therefore call m_vObjects[X].onClick() or do I need to use some more abstrusive design?)
- The object, eg. button does all self-management it needs (changing texture to represent pressed state, etc..) and then sents the controller an onClick()-message -> see question at the top.

Sounds good, at least to me. Well I'd be glad if you could explain to me how I should communicate with the controller, other than that I think I'll go that route, shouldn't I?

#14 CC Ricers   Members   -  Reputation: 804

Like
1Likes
Like

Posted 21 August 2012 - 02:52 PM

Radikalizm went through a lot on showing you MVC examples to maintain a graphical interface and its parts, so I will tell you why it would make sense to move more towards components and avoid overuse of inheritance.

@CC Ricers:

For instance, a clickable menu entry can be an aggregate of a TextEntry and a Button


A scrollbar (just the bar itself, not the screen it scrolls) would be a Button and a Draggable entity with vertical/horizontal constraints added to it


Thats just how I was planning to handle things, except that my scrollbar still inherits from EditorObject, because, after all, isn't this a "base object" too? This drastically reduces the amount of code needed as well. Maybe I should show you what EditorObject looks like:

*snip*

So EditorObject describes a general object with variables that apply to every gui element. (position,size, a sprite object). The whole Super-thingy is for traversion, it spares me having to pass the holding objects x/y-coordinates all the time. ProjectPosition() is a helper function that outputs the mouse coordinates relative to the objects position, saves me a lot of math.

So I quess everyone would agree that I should at least inherit these classes from that:

EditorImage
EditorButton

If not, why?

If yes, why shouldn't I, example given, also inherit the Scrollbar from this?

The scrollbar, while being basically a composition of three buttons and a background-image, does have its own coordinates, destinctive size, needs to be drawn in relation to other objects, etc.. so whats exactly wrong about that or, better said: What are the benefits of composition here? What is such a huge improvement from having an extern controller handling the scrollbars usage to just having the Update() method do it? This is what, for example, the inherited scrollbar-class looks like:

*snip*

Except that Setup() and SetButtons() could/should be moved to the constructor: Again, why would I want to composite instead of inherit here? The scrollbar class uses everything from its super-class, and just extents it. Do I really have such a misunderstanding of OOP-basics or is it some matter of opinion whether you see a scrollbar a base object here?

So I know that my EditorWindow->WindowTileset/WindowTilemap-classes are bad and I'll going to replace that with some composited objects here, but I really see to fail the point for such a basic objects as a scrollbar.


It's true that eventually all your widgets need to have a base class in common- if the intent is to have a separate GUI system go through all the widgets and draw/update them each time, the system needs to know what counts as a widget, and be able to register objects of the Widget type.

What I don't favor is putting bunch of variables that are sprawling over the place inside the Widget class, when they can be split up and contained in their own classes or structures, which you can then use with more flexibility. For example, width, height and X and Y position can be stored in a Rectangle structure. The extent to how you define the visual appearance is up to you. Do you want the UI system to use one skin, or maybe give the ability to mix several skins, with some taking priority over the "default" skin? Whatever the case may be, this should be separate from the classes that define behavior.

Also, you have to see what makes each widget fundamentally unique. What makes a button a button? It's certainly not its size and position because all widgets have those. A button, like all other UI elements, is defined by its behavior. The Button class need not know it's position, just whether it's been clicked on, or not, and if clicked, trigger an event that would be passed up to the UI system to get the proper response.

The inheritance to a base object would exist simply to make it possible to queue all widgets, extract necessary information that a particular subsystem would need (like a sound player or graphics renderer), and have those subsystems do whatever they need with the information. The rendering system should not care what kind of widget the Button is, or even that it's a widget. You should just pass along to it the UI skin parameters to tell it what the element looks like and the Rectangle object to tell it where to draw the element.

As I mentioned before, I'm not making a terribly complex UI- all I need are some short menus, and a couple of buttons and dialog boxes here and there. But they all share a common objects through composition (Buttons, TextEntries and Backgrounds), and share a skin object that resides in the UI/screen manager, for a more consistent look throughout the game. Also, admittedly they take care of drawing themselves for now, so that's a big "don't do" on my part that I have to fix. But If I needed something more complex (and I was designing it myself), I would design a more elegant solution.
My development blog: Electronic Meteor

#15 Radikalizm   Crossbones+   -  Reputation: 2992

Like
1Likes
Like

Posted 21 August 2012 - 02:55 PM

It does indeed sound like you have the hang of it Posted Image

One example of communicating with a controller is letting a widget maintain a list of controllers. When an onClick event occurs (so your button's onClick() method is called) for example you could iterate over your list of controllers and notify each of them that they should perform their designated action. This will automatically start the chain reaction of updating both model and view.

The Qt library does this in a slightly different way which you already mentioned in some previous post I believe. They use the signal-slot mechanism to connect certain triggers or signals from a widget to a function or slot. This does of course require their own meta-object compiler with some custom C++ extensions, so unless you're ok with providing a quite advanced pre-compilation step for your project this isn't really an option.

In C# something similar is implemented with delegates which can be linked to events. Something similar could probably be built in C++, but I'd need to do some research on that before I could give you any details.

Edited by Radikalizm, 21 August 2012 - 03:05 PM.

I gets all your texture budgets!


#16 Juliean   GDNet+   -  Reputation: 2746

Like
0Likes
Like

Posted 21 August 2012 - 03:42 PM

@CC Ricers:

What I don't favor is putting bunch of variables that are sprawling over the place inside the Widget class, when they can be split up and contained in their own classes or structures, which you can then use with more flexibility. For example, width, height and X and Y position can be stored in a Rectangle structure. The extent to how you define the visual appearance is up to you. Do you want the UI system to use one skin, or maybe give the ability to mix several skins, with some taking priority over the "default" skin? Whatever the case may be, this should be separate from the classes that define behavior.


Ok, I agree, I might want to put x, y, width and height into some sort of structure. Talking about the skin, I was just passing a texture pointer to the element, that represented the skin. Having the UI system itself handling the skins seems like a good idea, though. Didn't think about that.

Also, you have to see what makes each widget fundamentally unique. What makes a button a button? It's certainly not its size and position because all widgets have those. A button, like all other UI elements, is defined by its behavior. The Button class need not know it's position, just whether it's been clicked on, or not, and if clicked, trigger an event that would be passed up to the UI system to get the proper response.


So you are talking about the button as being just the controller talking about MVC, right? Ah, I think I get it. Does that mean I'd have my baseclass EditorObject, which acts as a view, and can hold various amounts of controllers as well as the model. It accepts user inputs, but only redirects them to the controllers, which themself change the data in the model. So a button would be a normal Widget with a special controller that handles the button-specific tasks. Right? My head slowly starts to ache :(

One thing that I, however, really don't understand, is what the model exactly is. Is it some sort of template, or a certain data type that i define for each widget? Or is it like the buttons back-texture and image/text?

@Radikalizm:

One example of communicating with a controller is letting a widget maintain a list of controllers. When an onClick event occurs (so your button's onClick() method is called) for example you could iterate over your list of controllers and notify each of them that they should perform their designated action. This will automatically start the chain reaction of updating both model and view.


Ok, that seems legit, but what I meant more specifically is how exactly do I tell the controller what exactly happend? Should I maintain a notify function for all widgets possible actions, like onButtonClick()?


At that point, though I think I still need a bit more, I want to thank you guys already for your help. I'll wait for your next answers, in the meanwhile I'll try to pseudo-code what I think this should look like..

#17 Radikalizm   Crossbones+   -  Reputation: 2992

Like
0Likes
Like

Posted 21 August 2012 - 04:13 PM

Should I maintain a notify function for all widgets possible actions, like onButtonClick()?


I wouldn't do that since you'd have to update your code in 2 locations whenever you want to add a definition for a widget, which could become quite a mess after a while, and which goes against the principle of self-containment in OOD.

Solving this problem can indeed be tricky, but it mostly depends on personal preference as there are many ways to solve it. You could design your controllers to accept a generic message structure which contains event arguments as a parameter for their update function (or whatever you want to call it). The burden of parsing this message and translating it into something which makes sense would then be on the controller.
Pressing or releasing a button could for example pass on a message containing a boolean value with the pressed state of the button. If the controller which receives this message can work with a single boolean value it can continue on happily, if it can't however you could let it print an error message, or you could just let it ignore the message.

I gets all your texture budgets!


#18 Juliean   GDNet+   -  Reputation: 2746

Like
0Likes
Like

Posted 21 August 2012 - 04:33 PM

Ok, thanks, I'll try figure out what fits best once I've gotten that far.

So I gave it a try to somewhat code it out on a basic level, and that what I've gotten (I actually tried to cover the real MVC-pattern this time, if it doesn't work out that well, I'll go back to my old pattern):

class View
{
public:
View(Model* pModel);
virtual ~View(void);

void OnClick(void);
void OnOver(void);
void OnRelease(void);

void AddChild(Widget* pWidget);
void AddController(Controller*);

void Update(int x, int y); // traversiallyupdate childs
virtual void Draw(void);

protected:

vector<Controller*> m_vControllers
vector<View*> m_vChilds;
Model* m_pModel;
};

So I'd have my widget some generic events like OnClick, an Update() and Draw()-method, a number of controllers, as well as some childs and the model its holding. I'm still confused about the model part, but I'll come to that later. Here is the controller:

class Controller
{
public:

Controller(Model* pModel);
virtual ~Controller(void);

virtual void SendMessage(wstring lpString);

protected:

Model* m_pModel;
}


Well this basically knows that model it is holding, and has a method of sending a message to it. Thats all I need, if I understand that right. Now to the model

class Model
{
public:

Model();//??
virtual ~Model(void);

protected:
//??
}


I've got no idea how to design the model in a generic pattern. Really, I can't even come up with any example. How would I design this in a way that I don't have to inherit from this class for every set of data I want to display, and not have to inherit widget accordingly? This would kill the whole purpose, I belive.

Some more questions:

- Where does the position/size goes to? The view, or the model?
- Do I inherit my Widgets from View, or do I really compose them out of views,models and controllers (by having a seperate widget class from which I inherit) or it the View actually the Widget?

My main problem however is the model. I can't figure that part out. I know what it basically is, but I don't know how I can code it.

Edited by The King2, 21 August 2012 - 04:36 PM.


#19 Bluefirehawk   Crossbones+   -  Reputation: 1232

Like
1Likes
Like

Posted 22 August 2012 - 01:38 AM

e: did misread much, edit post

class View
{
...
void AddController(Controller*);
...
}
I wouldn't do that, generally the view allows the controller to register "events", the view doesn't know about the controller directly.

I've got no idea how to design the model in a generic pattern. Really, I can't even come up with any example. How would I design this in a way that I don't have to inherit from this class for every set of data I want to display, and not have to inherit widget accordingly? This would kill the whole purpose, I belive.

Well, I think what you want to do is build your own gui framework. This means you build templates for the View. Templates for any controller / model is not a task of the windowing library afaik.
This means for the windowing library you need a class design for your gui elements and a messaging system, implementing the MVC pattern is not up to the library.

What do you want to do exactly, build a map editor? build a Settings- / Gamemenu build an in-game HUD?

If possible, use a windowing library, what you are doing here is trying to reinvent the wheel.


What I don't favor is putting bunch of variables that are sprawling over the place inside the Widget class, when they can be split up and contained in their own classes or structures, which you can then use with more flexibility

While I agree that it makes sense to put that in a structure, I don't agree that it gives you more flexibilty. What should be so more flexible about this approach?

Edited by Bluefirehawk, 22 August 2012 - 02:21 AM.

Project: Project
Setting fire to these damn cows one entry at a time!

#20 Juliean   GDNet+   -  Reputation: 2746

Like
0Likes
Like

Posted 22 August 2012 - 04:43 AM

Thank you,

but you misread what the main purpose was. Totally understandable, given that wall of posts, I'll tell you what I want to have. The main purpose of this is to bouilt a game editor. No only map, I would call it that. I decided to go the other way round this time and instead of implement the game and build the editor afterwards, making testing hard at first. I'd built the game editor first and only write the the pieces of game the editor is able to display/alter.

I wouldn't do that, generally the view allows the controller to register "events", the view doesn't know about the controller directly.


How would I do that? I can think about it using function pointers, but this whole topic is new to me so I'd rather go with registering the controller directely, unless there is some huge drawback.

If possible, use a windowing library, what you are doing here is trying to reinvent the wheel.


I really don't want to do that, as I'd like to get an understanding of how things work under the hood. You may call it a waste of time but I've learned quite a much only the last 24 hours, which might become usefull again later on.

Well, I think what you want to do is build your own gui framework. This means you build templates for the View. Templates for any controller / model is not a task of the windowing library afaik.
This means for the windowing library you need a class design for your gui elements and a messaging system, implementing the MVC pattern is not up to the library.


Still, I need some basic implentation of a model, right? I've implemented the basics of this, and it really is much easier and cleaner then my last approach, but.. what about the model? Is it really a class like this:

class Model
{
Model();
virtual ~Model();

protected:
int m_X, m_Y, m_Width, m_iHeight;
}

That like here holds the position and size of the widget, and from which I inherit in every special use case? Please, I'd really need an answer here. I've searched high and low but couldn't find a single example mentioning a concrete example of the model for that use case.




Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.



PARTNERS