Page 1 of 2

Create GUI out of XML files

Posted: Thu Feb 03, 2005 4:26 pm
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.

Posted: Fri Feb 04, 2005 2:36 pm
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

Posted: Fri Feb 04, 2005 3:48 pm
by eXodus
I like the <element> tag with the "type" attribute. Gives me some ideas :idea:

Posted: Fri Feb 04, 2005 9:31 pm
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

Posted: Fri Feb 04, 2005 11:27 pm
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.

Posted: Sat Feb 05, 2005 3:50 am
by Magnus
This is a really good idea! if i ever learn xml (:P) ill use it :lol:

Posted: Sat Feb 05, 2005 5:21 am
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!

Posted: Sat Feb 05, 2005 5:25 am
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.

Posted: Sat Feb 05, 2005 5:47 am
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.

Posted: Sat Feb 05, 2005 5:48 am
by dracflamloc
ffs, that above post was mine.

/me slaps stupid autologin

Posted: Sat Feb 05, 2005 5:54 am
by TheRLG
Nah, I mean you specify what it does, and create a special class or something cool for event handling lol

Posted: Sat Feb 05, 2005 6:08 am
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:

Posted: Sat Feb 05, 2005 6:11 am
by TheRLG
HashTable? whats that?

:lol: LOL about the other stuff, I know what ur after, but I like talking about the future :P

Posted: Sat Feb 05, 2005 6:45 am
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 :|

Posted: Mon Feb 14, 2005 12:03 am
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.