Demonstrates loading and saving of configurations via XML
- Author
- Y.M. Bosman <yoran.nosp@m..bos.nosp@m.man@g.nosp@m.mail.nosp@m..com>
This demo features a fully usable system for configuration handling. The code can easily be integrated into own apps.
#include <irrlicht.h>
using namespace irr;
using namespace core;
using namespace scene;
using namespace video;
using namespace io;
using namespace gui;
#ifdef _IRR_WINDOWS_
#pragma comment(lib, "Irrlicht.lib")
#endif
SettingManager class.
This class loads and writes the settings and manages the options.
The class makes use of irrMap which is a an associative arrays using a red-black tree it allows easy mapping of a key to a value, along the way there is some information on how to use it.
class SettingManager
{
public:
SettingManager(const stringw& settings_file): SettingsFile(settings_file), NullDevice(0)
{
NullDevice = irr::createDevice(irr::video::EDT_NULL);
DriverOptions.insert(L"Software", EDT_SOFTWARE);
DriverOptions.insert(L"OpenGL", EDT_OPENGL);
DriverOptions.insert(L"Direct3D9", EDT_DIRECT3D9);
ResolutionOptions.insert(L"640x480", dimension2du(640,480));
ResolutionOptions.insert(L"800x600", dimension2du(800,600));
ResolutionOptions.insert(L"1024x768", dimension2du(1024,768));
SettingMap.insert(L"driver", L"Direct3D9");
SettingMap.insert(L"resolution", L"640x480");
SettingMap.insert(L"fullscreen", L"0");
}
~SettingManager()
{
if (NullDevice)
{
NullDevice->closeDevice();
NullDevice->drop();
}
};
Load xml from disk, overwrite default settings The xml we are trying to load has the following structure settings nested in sections nested in the root node, like:
<pre>
<?xml version="1.0"?>
<mygame>
<video>
<setting name="driver" value="Direct3D9" />
<setting name="fullscreen" value="0" />
<setting name="resolution" value="1024x768" />
</video>
</mygame>
</pre>
bool load()
{
if (!NullDevice)
return false;
irr::io::IXMLReader* xml = NullDevice->getFileSystem()->createXMLReader(SettingsFile);
if (!xml)
return false;
const stringw settingTag(L"setting");
stringw currentSection;
const stringw videoTag(L"video");
while (xml->read())
{
switch (xml->getNodeType())
{
case irr::io::EXN_ELEMENT:
{
if (currentSection.empty() && videoTag.equals_ignore_case(xml->getNodeName()))
{
currentSection = videoTag;
}
else if (currentSection.equals_ignore_case(videoTag) && settingTag.equals_ignore_case(xml->getNodeName() ))
{
stringw key = xml->getAttributeValueSafe(L"name");
if (!key.empty())
{
SettingMap[key] = xml->getAttributeValueSafe(L"value");
}
}
}
break;
case irr::io::EXN_ELEMENT_END:
currentSection=L"";
break;
}
}
xml->drop();
return true;
}
bool save()
{
if (!NullDevice)
return false;
irr::io::IXMLWriter* xwriter = NullDevice->getFileSystem()->createXMLWriter( SettingsFile );
if (!xwriter)
return false;
xwriter->writeXMLHeader();
xwriter->writeElement(L"mygame");
xwriter->writeLineBreak();
xwriter->writeElement(L"video");
xwriter->writeLineBreak();
map<stringw, stringw>::Iterator i = SettingMap.getIterator();
for(; !i.atEnd(); i++)
{
xwriter->writeElement(L"setting",true, L"name", i->getKey().c_str(), L"value",i->getValue().c_str() );
xwriter->writeLineBreak();
}
xwriter->writeLineBreak();
xwriter->writeClosingTag(L"video");
xwriter->writeLineBreak();
xwriter->writeClosingTag(L"mygame");
xwriter->drop();
return true;
}
void setSetting(const stringw& name, const stringw& value)
{
SettingMap[name]=value;
}
void setSetting(const stringw& name, s32 value)
{
SettingMap[name]=stringw(value);
}
stringw getSetting(const stringw& key) const
{
map<stringw, stringw>::Node* n = SettingMap.find(key);
if (n)
return n->getValue();
else
return L"";
}
bool getSettingAsBoolean(const stringw& key ) const
{
stringw s = getSetting(key);
if (s.empty())
return false;
return s.equals_ignore_case(L"1");
}
s32 getSettingAsInteger(const stringw& key) const
{
const stringc s = getSetting(key);
if (s.empty())
return 0;
return strtol10(s.c_str());
}
public:
map<stringw, s32> DriverOptions;
map<stringw, dimension2du> ResolutionOptions;
private:
SettingManager(const SettingManager& other);
SettingManager& operator=(const SettingManager& other);
map<stringw, stringw> SettingMap;
stringw SettingsFile;
irr::IrrlichtDevice* NullDevice;
};
Application context for global variables
struct SAppContext
{
SAppContext()
: Device(0),Gui(0), Driver(0), Settings(0), ShouldQuit(false),
ButtonSave(0), ButtonExit(0), ListboxDriver(0),
ListboxResolution(0), CheckboxFullscreen(0)
{
}
~SAppContext()
{
if (Settings)
delete Settings;
if (Device)
{
Device->closeDevice();
Device->drop();
}
}
IrrlichtDevice* Device;
IGUIEnvironment* Gui;
IVideoDriver* Driver;
SettingManager* Settings;
bool ShouldQuit;
IGUIButton* ButtonSave;
IGUIButton* ButtonExit;
IGUIListBox* ListboxDriver;
IGUIListBox* ListboxResolution;
IGUICheckBox* CheckboxFullscreen;
};
A typical event receiver.
class MyEventReceiver : public IEventReceiver
{
public:
MyEventReceiver(SAppContext & a) : App(a) { }
virtual bool OnEvent(const SEvent& event)
{
if (event.EventType == EET_GUI_EVENT )
{
switch ( event.GUIEvent.EventType )
{
case EGET_BUTTON_CLICKED:
{
if ( event.GUIEvent.Caller == App.ButtonSave )
{
if ( App.ListboxDriver->getSelected() != -1)
App.Settings->setSetting(L"driver", App.ListboxDriver->getListItem(App.ListboxDriver->getSelected()));
if ( App.ListboxResolution->getSelected() != -1)
App.Settings->setSetting(L"resolution", App.ListboxResolution->getListItem(App.ListboxResolution->getSelected()));
App.Settings->setSetting(L"fullscreen", App.CheckboxFullscreen->isChecked());
if (App.Settings->save())
{
App.Gui->addMessageBox(L"settings save",L"settings saved, please restart for settings to change effect","",true);
}
}
else if ( event.GUIEvent.Caller == App.ButtonExit)
{
App.ShouldQuit = true;
}
}
break;
}
}
return false;
}
private:
SAppContext & App;
};
Function to create a video settings dialog This dialog shows the current settings from the configuration xml and allows them to be changed
void createSettingsDialog(SAppContext& app)
{
for (irr::s32 i=0; i<irr::gui::EGDC_COUNT ; ++i)
{
irr::video::SColor col = app.Gui->getSkin()->getColor((irr::gui::EGUI_DEFAULT_COLOR)i);
col.setAlpha(255);
app.Gui->getSkin()->setColor((irr::gui::EGUI_DEFAULT_COLOR)i, col);
}
gui::IGUIWindow* windowSettings = app.Gui->addWindow(rect<s32>(10,10,400,400),true,L"Videosettings");
app.Gui->addStaticText (L"Select your desired video settings", rect< s32 >(10,20, 200, 40), false, true, windowSettings);
app.Gui->addStaticText (L"Driver", rect< s32 >(10,50, 200, 60), false, true, windowSettings);
app.ListboxDriver = app.Gui->addListBox(rect<s32>(10,60,220,120), windowSettings, 1,true);
map<stringw, s32>::Iterator i = app.Settings->DriverOptions.getIterator();
for(; !i.atEnd(); i++)
app.ListboxDriver->addItem(i->getKey().c_str());
app.ListboxDriver->setSelected(app.Settings->getSetting("driver").c_str());
app.Gui->addStaticText (L"Resolution", rect< s32 >(10,130, 200, 140), false, true, windowSettings);
app.ListboxResolution = app.Gui->addListBox(rect<s32>(10,140,220,200), windowSettings, 1,true);
map<stringw, dimension2du>::Iterator ri = app.Settings->ResolutionOptions.getIterator();
for(; !ri.atEnd(); ri++)
app.ListboxResolution->addItem(ri->getKey().c_str());
app.ListboxResolution->setSelected(app.Settings->getSetting("resolution").c_str());
app.CheckboxFullscreen = app.Gui->addCheckBox(
app.Settings->getSettingAsBoolean("fullscreen"),
rect<s32>(10,220,220,240), windowSettings, -1,
L"Fullscreen");
app.ButtonSave = app.Gui->addButton(
rect<s32>(80,250,150,270), windowSettings, 2,
L"Save video settings");
app.ButtonExit = app.Gui->addButton(
rect<s32>(160,250,240,270), windowSettings, 2,
L"Cancel and exit");
}
The main function. Creates all objects and does the XML handling.
int main()
{
SAppContext app;
SIrrlichtCreationParameters param;
param.DriverType = EDT_SOFTWARE;
param.WindowSize.set(640,480);
app.Settings = new SettingManager("../../media/settings.xml");
if ( !app.Settings->load() )
{
}
else
{
map<stringw, s32>::Node* driver = app.Settings->DriverOptions.find( app.Settings->getSetting("driver") );
if (driver)
{
if ( irr::IrrlichtDevice::isDriverSupported( static_cast<E_DRIVER_TYPE>( driver->getValue() )))
{
param.DriverType = static_cast<E_DRIVER_TYPE>( driver->getValue());
}
}
map<stringw, dimension2du>::Node* res = app.Settings->ResolutionOptions.find( app.Settings->getSetting("resolution") );
if (res)
{
param.WindowSize = res->getValue();
}
param.Fullscreen = app.Settings->getSettingAsBoolean("fullscreen");
}
app.Device = createDeviceEx(param);
if (app.Device == 0)
{
exit(0);
}
app.Device->setWindowCaption(L"Xmlhandling - Irrlicht engine tutorial");
app.Driver = app.Device->getVideoDriver();
app.Gui = app.Device->getGUIEnvironment();
createSettingsDialog(app);
MyEventReceiver receiver(app);
app.Device->setEventReceiver(&receiver);
while (!app.ShouldQuit && app.Device->run())
{
if (app.Device->isWindowActive())
{
app.Driver->beginScene(true, true, SColor(0,200,200,200));
app.Gui->drawAll();
app.Driver->endScene();
}
app.Device->sleep(10);
}
return 0;
}