Loading GUI Tabs from XML

You discovered a bug in the engine, and you are sure that it is not a problem of your code? Just post it in here. Please read the bug posting guidelines first.
chronologicaldot
Competition winner
Posts: 685
Joined: Mon Sep 10, 2012 8:51 am

Re: Loading GUI Tabs from XML

Post by chronologicaldot »

Oops. I almost forgot, I was going to post some testing code to save you some time if you wanted to check it out.

Code: Select all

 
#include <irrlicht.h>
 
using namespace irr;
using namespace core;
using namespace gui;
 
class EventRec : public IEventReceiver {
    IrrlichtDevice*  device;
 
public:
    EventRec( IrrlichtDevice* d )
        : device(d)
    {}
 
    virtual bool OnEvent(const SEvent&  event) {
        switch ( event.EventType ) {
        case EET_KEY_INPUT_EVENT:
            return OnKeyEvent(event.KeyInput);
        case EET_GUI_EVENT:
            return OnGUIEvent(event.GUIEvent);
        default:
            break;
        }
        return false;
    }
 
    bool OnKeyEvent(const SEvent::SKeyInput&  event) {
        switch( event.Key ) {
        case KEY_KEY_B:
            removeAllChildren( device->getGUIEnvironment()->getRootGUIElement() );
            buildGUI();
            return true;
 
        case KEY_KEY_L:
            removeAllChildren( device->getGUIEnvironment()->getRootGUIElement() );
            loadGUI();
            return true;
 
        case KEY_KEY_S:
            saveGUI();
            return true;
 
        case KEY_KEY_Q:
            device->closeDevice();
            return true;
 
        default: break;
        }
        return false;
    }
 
    bool OnGUIEvent(const SEvent::SGUIEvent&  event) {
        switch( event.EventType ) {
        case EGET_BUTTON_CLICKED:
            if ( event.Caller->getID() == 100 ) {
 
            }
            break;
 
        default:
            break;
        }
        return false;
    }
 
    void removeAllChildren( IGUIElement* e ) {
        list<IGUIElement*>::ConstIterator  kidIter = e->getChildren().begin();
        while ( e->getChildren().size() > 0 ) {
            e->removeChild(*kidIter);
            kidIter = e->getChildren().begin();
        }
    }
 
    void buildGUI() {
        IGUIEnvironment*  guiEnvironment = device->getGUIEnvironment();
        IGUITab*  tab = 0;
        recti  tabSize( 20,50,200,350 );
 
        // Generate
        recti  tabCtrlRect(100,50,400,550);
        IGUITabControl*  tabControl = guiEnvironment->addTabControl(tabCtrlRect, guiEnvironment->getRootGUIElement());
        tabControl->setAlignment(EGUIA_UPPERLEFT, EGUIA_UPPERLEFT, EGUIA_UPPERLEFT, EGUIA_LOWERRIGHT);
        tabControl->updateAbsolutePosition();
 
        tab = tabControl->addTab(L"DTab1", 10);
        tab->setBackgroundColor(video::SColor(0xffff2200));
        tab->setDrawBackground(true);
 
        tab = tabControl->addTab(L"DTab2", 11);
        tab->setBackgroundColor(video::SColor(0xff0000ff));
        tab->setDrawBackground(true);
 
        tab = guiEnvironment->addTab(tabSize, tabControl, -1);
        tab->setText(L"GreenTab");
        tab->setBackgroundColor(video::SColor(0xff00ff00));
        tab->setDrawBackground(true);
        //tab->setAlignment(EGUIA_UPPERLEFT, EGUIA_UPPERLEFT, EGUIA_UPPERLEFT, EGUIA_LOWERRIGHT);
        tabControl->addTab(tab);
 
        recti  buttonSize( 0,0,100,50 );
        IGUIButton*  button = guiEnvironment->addButton(buttonSize, tab, -1, L"Push");
        button->updateAbsolutePosition();
    }
 
    void loadGUI() {
        // Load from file
        device->getGUIEnvironment()->loadGUI("saved_gui.xml");
    }
 
    void saveGUI() {
        // Save to file
        device->getGUIEnvironment()->saveGUI("saved_gui.xml");
    }
};
 
int main() {
 
    dimension2du  screenSize(900,600);
    IrrlichtDevice*  device = createDevice(video::EDT_OPENGL, screenSize);
 
    if ( !device )
        return 1;
 
    video::IVideoDriver*  videoDriver = device->getVideoDriver();
    IGUIEnvironment*  guiEnvironment = device->getGUIEnvironment();
    EventRec  eventRec(device);
 
    device->setEventReceiver(&eventRec);
 
    while ( device->run() ) {
        videoDriver->beginScene();
        guiEnvironment->drawAll();
        videoDriver->endScene();
    }
 
    device->drop();
    return 0;
}
 
CuteAlien
Admin
Posts: 9646
Joined: Mon Mar 06, 2006 2:25 pm
Location: Tübingen, Germany
Contact:

Re: Loading GUI Tabs from XML

Post by CuteAlien »

Thanks, I'll look at it. Not home this weekend, so will likely take 1-2 weeks until I get to it (or I find some evening, but with current temperatures above 30° I'm generally glad if I survive until evenings ^_^).
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
CuteAlien
Admin
Posts: 9646
Joined: Mon Mar 06, 2006 2:25 pm
Location: Tübingen, Germany
Contact:

Re: Loading GUI Tabs from XML

Post by CuteAlien »

Man, first patch for OverrideTextColorEnabled serialization actually broke it. What we both missed was that setTextColor has a side-effect: It sets OverrideTextColorEnabled to true.
We could have avoided serializing color (which is kinda undefined when OverrideTextColorEnabled is false), but doesn't matter. New fix should fix it all and serialize even the useless stuff.

Work on your patch ongoing. Takes a little bit to get into it and there are 2 patches in one (the other about refreshSkinColors() which looks OK. edit: applied that part).

The new function should likely be called insertTab (as the other addTab functions add to end while insertTab is the one with index). But need to find another evening to figure out if it all works and breaks nothing.

Minor note: your link to patch for header is gone (thought it's obvious, so no problem, I just hope rest of patch won't vanish as well by the time I get to it again).
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
chronologicaldot
Competition winner
Posts: 685
Joined: Mon Sep 10, 2012 8:51 am

Re: Loading GUI Tabs from XML

Post by chronologicaldot »

Missed your post 'cause I kept looking at the other thread we have going.

Sorry about the patch disappearing. It wasn't much.

Code: Select all

 
35,36c35
<       //! Returns number of this tab in tabcontrol. Can be accessed
<       //! later IGUITabControl::getTab() by this number.
---
>       //! Returns the desired index of this tab.
69c68
<       void refreshSkinColors();
---
>       _IRR_DEPRECATED_ void refreshSkinColors();
98c97
<       virtual void addTab(CGUITab* tab);
---
>       virtual void addTab(IGUITab* tab, s32 desiredIndex) _IRR_OVERRIDE_;
181c180
<       core::array<CGUITab*> Tabs; // CGUITab* because we need setNumber (which is certainly not nice)
---
>       core::array<IGUITab*> Tabs;
 
The function renamed as insertTab sounds better. I simply used the old name because that's what it was called when I changed it. If you rename it, however, note that you will have to change my patch line in the CGUITab::deserializeAttributes function:

Code: Select all

 
    if (Parent && Parent->getType() == EGUIET_TAB_CONTROL)
    {
        ((IGUITabControl*)Parent)->addTab(this, Number); // <-- CHANGE ME
        if (isVisible())
            ((IGUITabControl*)Parent)->setActiveTab(this);
    }
 
Thanks for doing all this, by the way.
CuteAlien
Admin
Posts: 9646
Joined: Mon Mar 06, 2006 2:25 pm
Location: Tübingen, Germany
Contact:

Re: Loading GUI Tabs from XML

Post by CuteAlien »

Uhm, yeah, sorry - this todo got pushed down a few times on my list by other stuff :-(
Partly because it turned out to be a bit more tricky than expected and I run into some other problems when I tried to fix this.

Turns out there actually was a reason for the setNumber stuff. Just a badly named function (seriously... setNumber?). The reason it was necessary is that Tabs can have a different order than Children. For example if you insert a tab in the middle it's still the last child. So on deserializing you might have to add tab's which have a higher index than the current size of Tabs would allow.

I also only found this out after I already kicked it out. So I used a different interface - adding insertTab and addTab functions which take an IGUITab. But the insertTab has an additional parameter to set for serialization where it simply behaves different.

I hope this works for you. I didn't test it yet with custom IGUITab implementations, but in theory it should work.

Changed in r5976.

Thanks for your test-case, it helped a lot! I adapted it a bit (in case you are still around and want to test it as well):

Code: Select all

 
#include <irrlicht.h>
 
#ifdef _MSC_VER
#pragma comment(lib, "Irrlicht.lib")
#endif
 
using namespace irr;
using namespace core;
using namespace gui;
 
 
class EventRec : public IEventReceiver {
    IrrlichtDevice*  device;
 
public:
    EventRec( IrrlichtDevice* d )
        : device(d), tabControl(0)
    {}
 
    virtual bool OnEvent(const SEvent&  event) {
        switch ( event.EventType ) {
        case EET_KEY_INPUT_EVENT:
            return OnKeyEvent(event.KeyInput);
        case EET_GUI_EVENT:
            return OnGUIEvent(event.GUIEvent);
        default:
            break;
        }
        return false;
    }
 
    bool OnKeyEvent(const SEvent::SKeyInput&  event) {
 
        if ( !event.PressedDown )
            return true;
 
        switch( event.Key ) {
        case KEY_KEY_B:
            removeAllChildren( device->getGUIEnvironment()->getRootGUIElement() );
            buildGUI();
            return true;
 
        case KEY_KEY_L:
            removeAllChildren( device->getGUIEnvironment()->getRootGUIElement() );
            loadGUI();
            return true;
 
        case KEY_KEY_S:
            saveGUI();
            return true;
 
        case KEY_KEY_A:
            if ( tabControl)
            {
                int idx = tabControl->getTabCount() ? (rand() % tabControl->getTabCount()) : 0;
                irr::core::stringw label(L"add");
                label += idx;
                tabControl->insertTab(idx, label.c_str());
            }
            return true;
        case KEY_KEY_R:
            if ( tabControl )
                tabControl->removeTab( tabControl->getActiveTab() );
            return true;
        case KEY_KEY_C:
            if ( tabControl )
                tabControl->clear();
            return true;
 
        case KEY_KEY_Q:
            device->closeDevice();
            return true;
 
        default: break;
        }
        return false;
    }
 
    bool OnGUIEvent(const SEvent::SGUIEvent&  event) {
        switch( event.EventType ) {
        case EGET_BUTTON_CLICKED:
            if ( event.Caller->getID() == 100 ) {
 
            }
            break;
 
        default:
            break;
        }
        return false;
    }
 
    void removeAllChildren( IGUIElement* e ) {
        tabControl = 0;
        list<IGUIElement*>::ConstIterator  kidIter = e->getChildren().begin();
        while ( e->getChildren().size() > 0 ) {
            e->removeChild(*kidIter);
            kidIter = e->getChildren().begin();
        }
    }
 
    void buildGUI() {
        IGUIEnvironment*  guiEnvironment = device->getGUIEnvironment();
        IGUITab*  tab = 0;
        recti  tabSize( 20,50,200,350 );
  
        // Generate
        recti  tabCtrlRect(100,50,400,550);
        tabControl = guiEnvironment->addTabControl(tabCtrlRect, guiEnvironment->getRootGUIElement());
        tabControl->setAlignment(EGUIA_UPPERLEFT, EGUIA_UPPERLEFT, EGUIA_UPPERLEFT, EGUIA_LOWERRIGHT);
        tabControl->updateAbsolutePosition();
 
        IGUITab* delaytab = guiEnvironment->addTab(tabSize, tabControl, -1);
        delaytab->setText(L"delayed");
        delaytab->setBackgroundColor(video::SColor(0xffaaff44));
        delaytab->setDrawBackground(true);
 
        tab = tabControl->addTab(L"DTab1", 10);
        tab->setBackgroundColor(video::SColor(0xffff2200));
        tab->setDrawBackground(true);
 
        tab = tabControl->addTab(L"DTab2", 11);
        tab->setBackgroundColor(video::SColor(0xff0000ff));
        tab->setDrawBackground(true);
 
        tab = guiEnvironment->addTab(tabSize, tabControl, -1);
        tab->setText(L"GreenTab");
        tab->setBackgroundColor(video::SColor(0xff00ff00));
        tab->setDrawBackground(true);
        //tab->setAlignment(EGUIA_UPPERLEFT, EGUIA_UPPERLEFT, EGUIA_UPPERLEFT, EGUIA_LOWERRIGHT);
        tabControl->addTab(tab);
 
        tabControl->addTab(delaytab);
        
        recti  buttonSize( 0,0,100,50 );
        IGUIButton*  button = guiEnvironment->addButton(buttonSize, tab, -1, L"Push");
        button->updateAbsolutePosition();
    }
 
    void loadGUI() {
        // Load from file
        device->getGUIEnvironment()->loadGUI("saved_gui.xml");
    }
 
    void saveGUI() {
        // Save to file
        device->getGUIEnvironment()->saveGUI("saved_gui.xml");
    }
 
    IGUITabControl*  tabControl;
};
 
int main() {
 
    dimension2du  screenSize(900,600);
    IrrlichtDevice*  device = createDevice(video::EDT_OPENGL, screenSize);
 
    if ( !device )
        return 1;
 
    device->setWindowCaption(L"(b)uild (s)ave (l)oad (a)dd (r)emove (c)lear");
 
    video::IVideoDriver*  videoDriver = device->getVideoDriver();
    IGUIEnvironment*  guiEnvironment = device->getGUIEnvironment();
    EventRec  eventRec(device);
 
    device->setEventReceiver(&eventRec);
 
    while ( device->run() ) {
        videoDriver->beginScene();
        guiEnvironment->drawAll();
        videoDriver->endScene();
    }
 
    device->drop();
    return 0;
}
 
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
Post Reply