I'm trying to create a GUI XML file. My problem is that I want to have some static text and some buttons be a child of an invisible parent object that encases them. However, none of the GUI elements that I can see in the API are pure container classes.
At the moment, I plan on using a staticText box with no text in it as the parent class, but this is a hack. Is there a better way of containing a set of XML GUI elements in a root element that I can then manipulate when loaded? Or does this functionality not yet exist.
For those of you wondering why someone would want to do this, its very simple: if you create an XML for say, the Health/MP bar portion of a game HUD, you can load the XML file and move the root of it to different portions of the screen depending on where you actually want to place it (instead of having to move each element individually).
Is there a Gui collection object?
Is there a Gui collection object?
a screen cap is worth 0x100000 DWORDS
I actually ran into this with my program as well. Instead of text though I used an image that I set its colour to completely transparent. The image is usually something like a single black pixel gif or so.
It's something like the following:
It's still a bit of a hack, but I think it's a bit more elegant compared to the text node.
Of course, you could just write your own GUI element that is simply a rectangle and just draws any children in it. Takes a bit more code to setup (since you need to make a CGUIContainer.cpp, etc), but is probably the best solution if you don't mind a bit more code.
It's something like the following:
Code: Select all
IGUIImage* container = driver->environment->addImage(rectangle);
container->setScaleImage(true);
container->setImage(driver->getTexture("smallblackgraphic"));
container->setColor(video::SColor(0,255,255,255));
Of course, you could just write your own GUI element that is simply a rectangle and just draws any children in it. Takes a bit more code to setup (since you need to make a CGUIContainer.cpp, etc), but is probably the best solution if you don't mind a bit more code.
That's also one of my feature wishes for the next irrlicht version :-)
Like the empty scene node we need an empty gui element.
At the moment I create a class for that myself. But there are a few things you have to care about when you need it for serialization. First you need to use a guifactory for it, otherwise you can't load it.
Then you should overwrite CGUIEmptyElement::isPointInside and return false in it (that's why I don't use a static or image). And I think the last problem is unfortunately not solvable that way: You still will have clipping for that empty scene node. My only solution for that so far is to make it either very large or as large as the biggest element. Which has it's own problems as alignment will no longer function as expected (this element should be ignored in alignment).
Like the empty scene node we need an empty gui element.
At the moment I create a class for that myself. But there are a few things you have to care about when you need it for serialization. First you need to use a guifactory for it, otherwise you can't load it.
Then you should overwrite CGUIEmptyElement::isPointInside and return false in it (that's why I don't use a static or image). And I think the last problem is unfortunately not solvable that way: You still will have clipping for that empty scene node. My only solution for that so far is to make it either very large or as large as the biggest element. Which has it's own problems as alignment will no longer function as expected (this element should be ignored in alignment).
IRC: #irrlicht on irc.libera.chat
Code snippet repository: https://github.com/mzeilfelder/irr-playground-micha
Free racer made with Irrlicht: http://www.irrgheist.com/hcraftsource.htm
Code snippet repository: https://github.com/mzeilfelder/irr-playground-micha
Free racer made with Irrlicht: http://www.irrgheist.com/hcraftsource.htm
Using the gui editor its easy to set the size of the area for a staticText element that encompasses all of its children (the gui editor will even render its children cut off if they go out of bounds) so its fairly easy to make sure it encompasses them using that tool.
I agree; I look forward to having an empty gui container element like the empty scene node. Here's hoping its in the next version.
I agree; I look forward to having an empty gui container element like the empty scene node. Here's hoping its in the next version.
a screen cap is worth 0x100000 DWORDS
I was going to suggest that, but I haven't had a chance to look over the changes to the gui stuff since you added the gui serialization and positioning code. If there are no pure virtuals, that would be the way to go.I'm sure I saw Travis do that in an example post once
If there are, then you can write a very thin wrapper around IGUIElement and then define the necessary serialization hooks so that the serialization framework will work with it. The only additional requirement would be that the gui editor allow you to create any node type that is supported by the gui element factory.
Ha. Thanks for the compliment. You should see all the mistakes I make at my day job. :)and he's rarely (if ever) wrong
Travis
Taking the thread in a slightly different (but still parallel) direction:
I'm trying to switch to a sub-state where I have a window pop up, and then switch back. The window that pops up does _not_ remove the gui elements behind it. Both the previous state's elements AND the sub-state's window are loaded using guienv->loadGUI( xxx, guienv->getRootGUIElement());
This seems to cause the sub-state's gui elements to clobber the previous elements. What I think I'm realizing is that both the guienv->loadGUI() and smgr->loadScene() are hacks to load the current scene/gui with the assumption that it is empty to begin with. Furthermore, there is no way to cull a portion of a scene/gui tree without writing your own recursive ->remove() function.
IMO these should be generalized to load a scene/gui heirarchy and return the root node of that heirarchy. That root node can then be manipulated appropriately.
For example: say you have a complex 'mini-scene' that represents a the sun, earth and moon, in their orbits. It consists of 1 root node, 3 textured sphere nodes, 2 rotation animators, and possibly a light source. You save this to file. (I'm not actually trying to do this, but its a good example of the robust functionality I'm talking about with the GUI stuff)
Lets say you then want to load that 'mini-scene' and use it somewhere in your game-- you should be able to do something like:
Of course you can argue that the mini-universe thing should just be a real animation/mesh file and you may be right. But the idea still applies to the GUI elements: you should be able to do something like:
Of course I could load every single gui element the app will have and simply toggle visible/active on them as I need, but thats a waste of memory and a hack. I should be able to load/unload portions from a file and attach/unattach them from the scene as needed.
I'm trying to switch to a sub-state where I have a window pop up, and then switch back. The window that pops up does _not_ remove the gui elements behind it. Both the previous state's elements AND the sub-state's window are loaded using guienv->loadGUI( xxx, guienv->getRootGUIElement());
This seems to cause the sub-state's gui elements to clobber the previous elements. What I think I'm realizing is that both the guienv->loadGUI() and smgr->loadScene() are hacks to load the current scene/gui with the assumption that it is empty to begin with. Furthermore, there is no way to cull a portion of a scene/gui tree without writing your own recursive ->remove() function.
IMO these should be generalized to load a scene/gui heirarchy and return the root node of that heirarchy. That root node can then be manipulated appropriately.
For example: say you have a complex 'mini-scene' that represents a the sun, earth and moon, in their orbits. It consists of 1 root node, 3 textured sphere nodes, 2 rotation animators, and possibly a light source. You save this to file. (I'm not actually trying to do this, but its a good example of the robust functionality I'm talking about with the GUI stuff)
Lets say you then want to load that 'mini-scene' and use it somewhere in your game-- you should be able to do something like:
Code: Select all
ISceneNode* snUniverse = smgr->loadSceneNodes(/*path*/"miniUniverse1.xml", /*node to attach to, current root node by default*/ -1);
sn_starwarsHologramProjector->addChild( snUniverse ); //set the currently loaded universe to represent a projected hologram
Code: Select all
//on app initialization
guienv->loadGUInodes("mainMenu.xml", guienv->getRootGUIElement());
//user selects 'sound options' from menu
gui_VidOptsWindow = loadGUInodes("soundOptions.xml", guienv->getRootGUIElement());
//user quits/applies sound options
gui_VidOptsWindow->removeRecursive(); //remove this and its children
a screen cap is worth 0x100000 DWORDS
A call to remove for gui elements should be recursive. As long as you did not grab() the children additionally they will all get dropped in the destructor of the parent element.
Loading a new window while keeping parts of the background gui is possible, though a little tricky. The way I'm doing it is that I use the knowledge which top element the loaded xml's do have. I create first a dummy element as parent. Then after loading I know (but certainly still check it to be sure) the type of my first child. Each of my dialogs always has one topElement of this type. So now I set this child as new topElement. Before doing so I remember certainly the parent of my old topElement so my dialogs can have parents (and be subdialogs that way).
Btw. - once I loaded a guidialog I usually keep it in memory. Loading times for complex dialogs can get so large that they are noticeable. And the memory usage doesn't really matter too much (but this certainly depends on your dialogs).
Can't tell much about a good way to handle scenenodes. My solution in H-Craft sucked. I couldn't release scenenodes anymore and after doing some calculations I found out that the memory usage after loading all levels was bearable (but hardly...) so I did ignore that. Will have to think of that some more this time.
Loading a new window while keeping parts of the background gui is possible, though a little tricky. The way I'm doing it is that I use the knowledge which top element the loaded xml's do have. I create first a dummy element as parent. Then after loading I know (but certainly still check it to be sure) the type of my first child. Each of my dialogs always has one topElement of this type. So now I set this child as new topElement. Before doing so I remember certainly the parent of my old topElement so my dialogs can have parents (and be subdialogs that way).
Btw. - once I loaded a guidialog I usually keep it in memory. Loading times for complex dialogs can get so large that they are noticeable. And the memory usage doesn't really matter too much (but this certainly depends on your dialogs).
Can't tell much about a good way to handle scenenodes. My solution in H-Craft sucked. I couldn't release scenenodes anymore and after doing some calculations I found out that the memory usage after loading all levels was bearable (but hardly...) so I did ignore that. Will have to think of that some more this time.
IRC: #irrlicht on irc.libera.chat
Code snippet repository: https://github.com/mzeilfelder/irr-playground-micha
Free racer made with Irrlicht: http://www.irrgheist.com/hcraftsource.htm
Code snippet repository: https://github.com/mzeilfelder/irr-playground-micha
Free racer made with Irrlicht: http://www.irrgheist.com/hcraftsource.htm