Jump to content
  • Advertisement
Sign in to follow this  
Valor Knight

Need help with building a gui system

This topic is 4457 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Over the past two weeks I have been stuck on this problem, sure I have done many other things, but everything seems to be stuck now until I figure out how to do this. I am making a gui management system, hardcoding all the values proved that I can render stuff, but now I have to use more than just quads with textures. So, initially I broke the gui into 3 "sections" a manager, objects and elements. The manager contains a std::vector of the gui objects. Each object is basically the container to build a window so, a element would be the accept button, images and text. I decided xml would be the best action right now to get the data into the program to define "templates" for each object. This is when the first problem was noticed (well, I knew it would be this was the first manifestation). When the xml reads in, it fills a object template (structure) which has a list of the elements (also a structure). Now the hard part. Different elements will have different attributes. Currently, I have relegated the structure to contain every type of information for both text and quads. Quads don’t need a text value and text doesn’t need a texture handle (there are more differences). Now I have gotten to actually working on the elements. My problem is I would like to make it as generic as possible, so how would i manipulate data in a quad element (stored in the list as a base element so text and quads can be together) and not have to bloat the base element class, or the other classes. Ideally, I would love to keep ALL the specific data in the according classes, and not experience bloatage, but how would I accomplish this? Any ideas on how to make a template so I dont have to store all related data for all the classes in it? here is some code to explain: (I know there are things missing, ect.. removed a lot to condense space and I just want something drawing again.) These structures are filled in from the xml file: as you can see in the elements, there is several fields that only pertain to one type of element. If I want to add a new element, then it has to be rewritten (not to mention the loader too). Any ideas how to sepererate the element type dependant stuff out?
struct PHOENIXGUI_DLL GuiElementTemplate
{
	std::wstring _ElementId;
	eElementType _ElementType;

	D3DXVECTOR2 _GUIPosition;

	long _MessagesToReceive; 
	std::wstring _LuaScript;//change to script handle from script resource manager

	//Renderable values (NOT ALWAYS NEEDED FOR ALL ELEMENTS)
	bool		_DefaultVisibility;
	D3DXCOLOR	_DefaultElementColor;

	//Text
	std::wstring _TextValue;
	std::wstring _Font;
	long _Formatting;

	//Image
	std::wstring _TextureFilename;
	float	_UVCoords[4][2];
};

struct PHOENIXGUI_DLL GuiObjectTemplate
{
	//ulong _ObjectID; //hash of the object name??
	std::wstring _ObjectName;
	D3DXVECTOR2 _GUIPosition;
	..removed other values
	std::vector<GuiElementTemplate*> _Elements;
};


Now the heart of the issue:
class PHOENIXGUI_DLL PhoenixGUIObject
{
private:
	std::wstring _ObjName;

	std::vector<PhoenixGUIElement*> _vecGUIElements;//< all elements contained here

public:

	// Element creation:
	//TODO: use handles
	PhoenixGUIElement* AddElement( eElementType type, const std::wstring& id );
	void RemoveElement( const std::wstring& id );
	PhoenixGUIElement* GetElement( const std::wstring& id );
};

class PHOENIXGUI_DLL PhoenixGUIQuad : public PhoenixGUIElement
{
private:
	SceneComponent *_pComponent;//not all elements will have this

	texHandle _Texture;
public:
	//needs to maipulate the texture, SetTexture, make VB according to size of the element
};

class PHOENIXGUI_DLL PhoenixGUIText : public PhoenixGUIElement
{
private: 
	SceneComponent *_pComponent;

	std::wstring _TextValue;
	fontHandle _Font;
public:
	//needs a function to change the textvalue
	//needs to manipulate the textvalue in a function that also re-creates the VB to the new string
};


Any ideas what I should do? Of course hard coding it is possible, when requested to instance it out for display, I can use a switch and new() the appropriate class and set all the values there, but that removes the easy plugin ability I am striving for and the instancer function would have to be updated for each new element type. Am I just striving for the impossible? Thanks.

Share this post


Link to post
Share on other sites
Advertisement
To a degree, you're striving for the impossible. Simply put, if you're having a common base class, that common base class needs to know about everything you're ever going to want to do through it. Personally, I don't need the image or the text elements when dealing with the base ui object.

Just a quick suggestion: you might want to make some of the common struct elements (color, position perhaps) into virtual functions. That more easily allows objects to also change the color/position of sub-objects, or for you to easily change behavior.

Share this post


Link to post
Share on other sites
If you only have a few types for your attribute, you could use enumerations and overloading:

enum attributeId
{
TEXT,
BASE_COLOR,
BORDER_COLOR,
TEXTURE
}
void setAttribute(int attributeid,Color color);
Color getAttributeColor(int attributeid);

void setAttribute(int id,textureHandle texture);


etc.
this way, you can add new attributes without touching the base class. these getter and setter functions must be made virtual. For your template classes, I would suggest the factory pattern (an abstract GuiElementFactory, with a createGuiElement() function, and have subclasses for every type of gui element)

Share this post


Link to post
Share on other sites
What I did when designing my GUI system was to go with the Window paradigm. This basically means that each GUI object is treated as a Window, and manages the memory for all its subwindows. You can then derive more specific classes from a Window class (like a text box, push button, etc.) and have some pure virtual functions (like a render function) that are all implemented by a specific subclass.

The tricky part is, of course, figuring out how to read in attributes, which it looks like your having trouble with. You basically have a couple options. First off, you could decide to just have a specific subclass define functions that it needs, and call those according to whatever scripting method you use to read in data for the GUI. Of course, this leads to a pretty verbose and inflexible scripting system. The other option is to do something similar to the scripting system for MS Window GUIs, which basically consists of calling a Set function with two string arguments (like Set("SIZE", "640 480")), and parsing them inside the GUI object. The issue here is that you might have to deal with getting improper data - but that's a tradeoff you're going to have to make no matter what.

If you opt to initialze and set attributes via parsed strings, you could set up an object factory that creates specific kinds of windows according to a type identification of some sort, and initializes their attributes as I just described. Then, there wouldn't be any real bloat in the base class, and you wouldn't have to have a plethora of different initialization functions for each different kind of subclass. The only thing you have to deal with is string parsing and dealing with bad data.

I hope this answered your question somewhat. If you need clarification, let me know. Maybe someone else will give a better explanation :)

Share this post


Link to post
Share on other sites

Quote:
Original post by Telastyn
Just a quick suggestion: you might want to make some of the common struct elements (color, position perhaps) into virtual functions. That more easily allows objects to also change the color/position of sub-objects, or for you to easily change behavior.


Thats what im doing, just with fonts and textures currently i know one dosnt need the other
Quote:
Original post by DrakeSlayer
If you only have a few types for your attribute, you could use enumerations and overloading:

enum attributeId
{
TEXT,
BASE_COLOR,
BORDER_COLOR,
TEXTURE
}
void setAttribute(int attributeid,Color color);
Color getAttributeColor(int attributeid);

void setAttribute(int id,textureHandle texture);


etc.
this way, you can add new attributes without touching the base class. these getter and setter functions must be made virtual. For your template classes, I would suggest the factory pattern (an abstract GuiElementFactory, with a createGuiElement() function, and have subclasses for every type of gui element)


wont you have to overload it in the base class for each type of data you can get in? or is there a way to overload it w/o defining a overload in the base class

newElement->SetData(GUI_DATA_COLOR, 10); <- works when int defined in base class
newElement->SetData(GUI_DATA_COLOR, "test"); <-cant overload in derived class

base element class function:
virtual void SetData( eDataType type, int ) = 0; //int allows the int set to work

in derived class:
void SetData( eDataType type, int test );
void SetData( eDataType type, std::wstring& test ); .. they display a message when called

::SetData' : cannot convert parameter 2 from 'const char [2]' to 'int'

so it looks like i have to define a virtual for each type I can get in, not to mention out?


Quote:
Original post by silverphyre673
The tricky part is, of course, figuring out how to read in attributes, which it looks like your having trouble with. You basically have a couple options. First off, you could decide to just have a specific subclass define functions that it needs, and call those according to whatever scripting method you use to read in data for the GUI. Of course, this leads to a pretty verbose and inflexible scripting system. The other option is to do something similar to the scripting system for MS Window GUIs, which basically consists of calling a Set function with two string arguments (like Set("SIZE", "640 480")), and parsing them inside the GUI object. The issue here is that you might have to deal with getting improper data - but that's a tradeoff you're going to have to make no matter what.


Started to do it this way and then reality set in that maybe it isnt a good idea to give that much freedom.


Could this be done with a template? I have not had any experiance with templates? I know templates dont have to define a type, but havnt ever used them before.

Thanks for the ideas/info

Share this post


Link to post
Share on other sites
You could dynamically register a separate "creation function" for each subclass, like this:


typedef PhoenixGuiElement* (*ElementMaker)(GuiObjectTemplate*);

std::map<eElementType, ElementMaker> elementMakers;

PhoenixGuiElement* makeGuiElement(GuiObjectTemplate* templ) {
/* error checking, etc. */
return elementMakers[templ->_ElementType](templ);
}
.
.
PhoenixGuiElement* TextMaker(GuiObjectTemplate* templ) {
PhoenixGuiText* element = new PhoenixGuiText();
element.setTextValue(templ->_TextValue)
/* etc */
return element;
}
.
.
elementMakers[TEXT_TYPE] = &TextMaker;
elementMakers[QUAD_TYPE] = &QuadMaker;



Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!