Create GUI out of XML files

A forum to store posts deemed exceptionally wise and useful
eXodus
Posts: 320
Joined: Tue Jan 04, 2005 10:07 am
Location: Canada
Contact:

Create GUI out of XML files

Post by eXodus »

I didn't want to hard-code my GUIs so I created this simple function.

So far only Buttons, Images and Windows are supported but it would be very simple to add support for other elements.

A nice feature is its support for "containers". You can add elements as child of other elements. The parent-child link is unlimited.

Here's the code :

Code: Select all

void CBlackNebula::showGUI(stringc gui)
{
	IGUIEnvironment * mygui = CDeviceFactory::s_gui;
	array<IGUIElement *> parents;

	gui.append(".xml");

	IXMLReader * xml = CDeviceFactory::s_device->getFileSystem()->createXMLReader(gui.c_str());
	while(xml && xml->read())
	{
		switch(xml->getNodeType())
		{
		case EXN_ELEMENT:
			{
				int x1, y1, x2, y2, id;
				x1 = xml->getAttributeValueAsInt(L"x1");
				y1 = xml->getAttributeValueAsInt(L"y1");
				x2 = xml->getAttributeValueAsInt(L"x2");
				y2 = xml->getAttributeValueAsInt(L"y2");
				id = xml->getAttributeValueAsInt(L"id");

				if(stringw("button") == xml->getNodeName())
				{
					stringw text(xml->getAttributeValueSafe(L"text"));

					mygui->addButton(rect<s32>(x1, y1, x2, y2), parents.getLast(), id, text.c_str());
				}

				if(stringw("image") == xml->getNodeName())
				{
					stringc texture(xml->getAttributeValueSafe(L"texture"));
					ITexture * image = CDeviceFactory::s_driver->getTexture(texture.c_str());

					IGUIImage * bg = mygui->addImage(rect<s32>(x1, y1, x2, y2), parents.getLast(), id);
					bg->setImage(image);
				}

				if(stringw("root") == xml->getNodeName())
				{
					parents.push_back(mygui->getRootGUIElement());
				}

				if(stringw("window") == xml->getNodeName())
				{
					bool closable = stringw("true") == xml->getAttributeValueSafe(L"closable") ? true : false;
					bool modal = stringw("true") == xml->getAttributeValueSafe(L"modal") ? true : false;
					stringw text(xml->getAttributeValueSafe(L"text"));

					IGUIWindow * window = mygui->addWindow(rect<s32>(x1, y1, x2, y2), modal, text.c_str(), parents.getLast());
					window->getCloseButton()->setEnabled(closable);

					parents.push_back(window);
				}
			}
			break;
			case EXN_ELEMENT_END:
			{
				if(stringw("root") == xml->getNodeName())
				{
					parents.erase(parents.size() - 1);
				}

				if(stringw("window") == xml->getNodeName())
				{
					parents.erase(parents.size() - 1);
				}
			}
			break;
		}
	}
	if(xml)
		xml->drop();
}
Obviously you have to adapt it to your code. You must call this function with the name of the file you want to load i.e. showGUI("main");

The XML file should be similar to this :

Code: Select all

<root>
	<image x1="0" y1="0" x2="800" y2="600" id="-1" texture="background.jpg"/>

	<window x1="300" y1="200" x2="500" y2="400" id="-1" modal="false" text="Main" closable="false">
		<button x1="16" y1="40" x2="184" y2="64" id="100" text="New Game"/>
		<button x1="16" y1="80" x2="184" y2="104" id="101" text="Load Game"/>
		<button x1="16" y1="120" x2="184" y2="144" id="102" text="Options"/>
		<button x1="16" y1="160" x2="184" y2="184" id="103" text="Exit"/>
	</window>
</root>
The only restrictions are the presence of the <root> tag and the ending tags for containers. The root tag must be present.

Feel free to critisize and post your changes!

BTW in the EXN_ELEMENT_END case, the root and window if blocks are identical. I didn't merge them both as I plan to do some changes in the future.
saigumi
Posts: 921
Joined: Fri Aug 22, 2003 11:31 am
Location: St. Louis, MO USA
Contact:

Post by saigumi »

This would be like something I wrote a long time ago but didn't upkeep. Feel free to yank whatever you want out of it to use in your own.

http://irrlicht.sourceforge.net/phpBB2/ ... ndler#7560
Crud, how do I do this again?
eXodus
Posts: 320
Joined: Tue Jan 04, 2005 10:07 am
Location: Canada
Contact:

Post by eXodus »

I like the <element> tag with the "type" attribute. Gives me some ideas :idea:
TheRLG
Posts: 372
Joined: Thu Oct 07, 2004 11:20 pm

Post by TheRLG »

Maybe you should team up with those GUI editor guys and create an Irrlicht gui xml standard :D

*cough* .igx *cough*

*more coughing* loadGUI("mainmenu.igx"); showGUI("mainmenu"); *more coughing*


:P
dracflamloc
Posts: 142
Joined: Sat Dec 11, 2004 8:13 am
Contact:

Post by dracflamloc »

Yea that'd be a good idea. I can easily create a DLL to support output in a XML format. When you've got your format finalized PM or email me, and I'll make an exporter.
Magnus
Posts: 79
Joined: Sun Jan 16, 2005 5:53 pm
Location: Georgia, USA
Contact:

Post by Magnus »

This is a really good idea! if i ever learn xml (:P) ill use it :lol:
Image
Image
eXodus
Posts: 320
Joined: Tue Jan 04, 2005 10:07 am
Location: Canada
Contact:

Post by eXodus »

If I was to create an extension to Irrlicht in order to load/show GUI out of XML files, would someone find it useful?

It might be a first step towards GUI standards, as said by RabidLockerGnome!
TheRLG
Posts: 372
Joined: Thu Oct 07, 2004 11:20 pm

Post by TheRLG »

I would use it, just make it easy to use and understand.
Would also need event handling too, ex:

<control type="button" name="OK_1" onClick="closemenu".......

Ya understand what I mean, just something that wont be too hard for you too code with, (I mean for you and for us) but will be versatile enough to handle our GUI needs.
Guest

Post by Guest »

I don't think this will go as far as event-handling. XML isnt the type of file to use for that. Event handling couldn't be easier as it is in C++. I believe we are just talking about layout and design.
dracflamloc
Posts: 142
Joined: Sat Dec 11, 2004 8:13 am
Contact:

Post by dracflamloc »

ffs, that above post was mine.

/me slaps stupid autologin
TheRLG
Posts: 372
Joined: Thu Oct 07, 2004 11:20 pm

Post by TheRLG »

Nah, I mean you specify what it does, and create a special class or something cool for event handling lol
eXodus
Posts: 320
Joined: Tue Jan 04, 2005 10:07 am
Location: Canada
Contact:

Post by eXodus »

The actual Irrlicht's system for event handling is to give IDs to component and react according to them. The only difference between IDs and a string description of the event would be human readability.

dracflamloc is right when talking about layout and design. I'm thinking about pre-loading and showing GUIs. Also making use of an HashTable, which isn't already present in Irrlicht...Niko :idea:
TheRLG
Posts: 372
Joined: Thu Oct 07, 2004 11:20 pm

Post by TheRLG »

HashTable? whats that?

:lol: LOL about the other stuff, I know what ur after, but I like talking about the future :P
eXodus
Posts: 320
Joined: Tue Jan 04, 2005 10:07 am
Location: Canada
Contact:

Post by eXodus »

When pre-loading a certain amount of interfaces before the game starts, I will have to store their root element somewhere for future use. There are different ways to store and retreive data from an array, list etc. You could do a linear search looping through all elements. There comes the binary search to cut the search in half.

But to further improve the search time, you can compute a value (hash) using a certain input ie. a GUI path. This value lets you store and retreive data in no time.

**Sorry if its not that clear...must...sleep :|
saigumi
Posts: 921
Joined: Fri Aug 22, 2003 11:31 am
Location: St. Louis, MO USA
Contact:

Post by saigumi »

RabidLockerGnome wrote:Maybe you should team up with those GUI editor guys and create an Irrlicht gui xml standard :D

*cough* .igx *cough*

*more coughing* loadGUI("mainmenu.igx"); showGUI("mainmenu"); *more coughing*


:P
Actually, that's about how GUIHandler worked

One call to initialize the class, and one to load the xml:

GUIHandler* GH = new GUIHandler(device);
GH->LoadGUI("mygui.xml", "inventory");

I'm actually working on it again as I need it for a project.
Crud, how do I do this again?
Post Reply