Difference between revisions of "Dialog Configurations"

From CEGUI Wiki - Crazy Eddie's GUI System (Open Source)
Jump to: navigation, search
(Sample_Demo7)
(version 2: MultiColumnList support and specify what attributes to monitor)
Line 1: Line 1:
 
=== Introduction ===
 
=== Introduction ===
Dialogs (frame windows) can be moved around, resized, hidden, and rolled up while the application is running.  However closing and then restarting the application will reset these settings to their default values, possibly those specified within a .layout file. This code saves the dialog position, size, visibility and whether the dialog is rolled up into an XML file.  When the application restarts the contents of the XML file will be read and the dialogs will be restored to their last states.
+
Dialogs (frame windows) can be moved around, resized, hidden, and rolled up while the application is running.  MultiColumnLists can have their columns rearranged, resized, and a column can sort its content in ascending or descending order.  However closing and then restarting the application will reset these settings to their default values, those specified within a .layout file if one was use, or those specified in code.
 +
 
 +
This clases saves these attributes into an XML file.  When the application restarts the contents of the XML file will be read and the dialogs and MultiColumnLists will be restored to their last states.
  
 
=== Sample_Demo7 ===
 
=== Sample_Demo7 ===
Line 22: Line 24:
 
That's it!  From now on the 3 windows within that demo will "remember" their previous configurations.
 
That's it!  From now on the 3 windows within that demo will "remember" their previous configurations.
  
=== XML Position File ===
+
=== Configuration Attributes ===
The call to loadPositions() takes two parameters: the XML file to load and the schema definitionIf the XML file does not exist an exception will be thrownThis can be avoided by creating an empty XML file; the exception is thrown only when the file does not exist, not when it is empty.  Then you can either manually write the XML contents yourself or use a little trick to have it written automatically.
+
The XML configuration file is loaded by a call to loadConfigurations().  It silently ignores errors within that XML file.  The worst that will happen is that some dialogs and MultiColumnLists will revert to their initial values.
  
 
Calling addDialog() and passing the window name as parameter will register that dialog to have its configuration written to the XML file.  The next call to saveConfigurations() will write the configuration of that registered window such that the next time loadConfigurations() is called the window will be automatically registered.
 
Calling addDialog() and passing the window name as parameter will register that dialog to have its configuration written to the XML file.  The next call to saveConfigurations() will write the configuration of that registered window such that the next time loadConfigurations() is called the window will be automatically registered.
 +
 +
The second parameter of addDialog() allows you to specify which attributes to monitor.  By default every attribute is monitored.  However you can specify to monitor one or many of the following, separated by spaces:  Position, Visible, and RolledUp.
 +
 +
The addMultiColumnList() function behaves in a similar manner, allowing you to specify which MultiColumnLists which of their attributes to monitor.  Again the default is to monitor every attribute but you can also specify one or many of the following:  ColumnSequence, ColumnWidths, SortedColumn, and AscendingSort.
  
 
Warning: the Demo7Sample::cleanupSample() is never called when exiting the demo, despite what the comments might say.  A solution is presented on the  [http://www.cegui.org.uk/phpBB2/viewtopic.php?t=1550 message board].
 
Warning: the Demo7Sample::cleanupSample() is never called when exiting the demo, despite what the comments might say.  A solution is presented on the  [http://www.cegui.org.uk/phpBB2/viewtopic.php?t=1550 message board].
Line 35: Line 41:
 
==== DialogConfigurations.h ====
 
==== DialogConfigurations.h ====
 
<pre>
 
<pre>
#pragma once
+
#ifndef _DialogConfigurations_h_
 +
#define _DialogConfigurations_h_
  
 
#include "CEGUI.h"
 
#include "CEGUI.h"
Line 47: Line 54:
 
public:
 
public:
 
DialogConfigurations();
 
DialogConfigurations();
void setDefaults(const CEGUI::URect& position, const bool& visible, const bool& rolledup); // Set default values
+
void setDialogDefaults(const CEGUI::URect& position, const bool& visible, const bool& rolledup); // Set default values
bool loadConfigurations(const CEGUI::String& xmlFile, const CEGUI::String& schema); // Load the position of every stored dialog
+
void setDefaultDialogAttributesMonitored(const CEGUI::String& attributesMonitored);
 +
bool addDialog(const CEGUI::String& widget, const CEGUI::String& attributesMonitored = ""); // Add a dialog to be monitored
 +
const CEGUI::URect& getDialogSavedPosition(const CEGUI::String& dialog); // Return the position of the specified dialog
 +
const bool& getDialogSavedVisible(const CEGUI::String& dialog); // Return the visible/hidden state of the specified dialog
 +
const bool& getDialogSavedRolledup(const CEGUI::String& dialog); // Return the expansion state of the specified dialog
 +
 
 +
void setMultiColumnListDefaults(const std::vector<CEGUI::String>& columnSequence, const CEGUI::uint& sortedColumn, const bool& sortAscending, const std::vector<CEGUI::String>& columnWidths);
 +
void setDefaultMultiColumnListAttributesMonitored(const CEGUI::String& attributesMonitored);
 +
bool addMultiColumnList(const CEGUI::String& widget, const CEGUI::String& attributesMonitored = ""); // Add a MultiColumnList to be monitored
 +
 
 +
bool loadConfigurations(const CEGUI::String& xmlFile, const CEGUI::String& schema = ""); // Load the position of every stored dialog
 
bool saveConfigurations(); // Store the position of every dialogs
 
bool saveConfigurations(); // Store the position of every dialogs
bool addDialog(const CEGUI::String& dialog); // Add a dialog to be monitored
+
 
const CEGUI::URect& getSavedPosition(const CEGUI::String& dialog); // Return the position of the specified dialog
+
bool isMonitoringAttribute(const std::vector<CEGUI::String>& list, const CEGUI::String& attribute); // Whether a particular attribute is monitored
const bool& getSavedVisible(const CEGUI::String& dialog); // Return the visible/hidden state of the specified dialog
+
const bool& getSavedRolledup(const CEGUI::String& dialog); // Return the expansion state of the specified dialog
+
 
private:
 
private:
     void elementStart(const CEGUI::String& element, const CEGUI::XMLAttributes& attributes);
+
     void elementStart(const CEGUI::String& element, const CEGUI::XMLAttributes& xmlAttributes);
 
static const CEGUI::String m_DialogConfigurationElement; // Tag name for dialog positions element
 
static const CEGUI::String m_DialogConfigurationElement; // Tag name for dialog positions element
static const CEGUI::String m_configurationElement; // Tag name for position elements
+
static const CEGUI::String m_configurationElementDialog; // Tag name for position elements
 
static const char windowNameAttribute[]; // Attribute name that stores the name of the window
 
static const char windowNameAttribute[]; // Attribute name that stores the name of the window
 
static const char windowPosAttribute[]; // Attribute name that stores the position of the window
 
static const char windowPosAttribute[]; // Attribute name that stores the position of the window
 
static const char windowVisibleAttribute[]; // Attribute name that stores the visible state of the window
 
static const char windowVisibleAttribute[]; // Attribute name that stores the visible state of the window
 
static const char windowRolledupAttribute[]; // Attribute name that stores the rolledUp state of the window
 
static const char windowRolledupAttribute[]; // Attribute name that stores the rolledUp state of the window
 +
static const CEGUI::String m_configurationElementMultiColumnList; // Tag name of MultiColumnList elements
 +
static const char mclColumnSequenceAttribute[]; // Attribute name that stores the sequence of the columns
 +
static const char mclSortedColumnAttribute[]; // Attribute name that stores which column is sorted
 +
static const char mclAscendingSortAttribute[]; // Attribute name that stores the sort order direction
 +
static const char DialogConfigurations::mclColumnWidthAttribute[]; // Attribute name that stores the widths of the columns
 +
static const char DialogConfigurations::mclColumnWidthSeparator; // Separator for the column widths
 +
static const char monitoredAttributeAll[]; // Special attribute name
 +
static const char monitoredAttributeNone[]; // Special attribute name
 +
 
struct DialogConfig {
 
struct DialogConfig {
 
CEGUI::URect position;
 
CEGUI::URect position;
Line 68: Line 92:
 
};
 
};
 
std::map<CEGUI::String, DialogConfig> m_dialogConfigurations; // List of the dialog configurations
 
std::map<CEGUI::String, DialogConfig> m_dialogConfigurations; // List of the dialog configurations
CEGUI::String m_configFile; // File containing the positions
 
 
CEGUI::URect m_defaultPosition; // Default position, used by getSavedPosition()
 
CEGUI::URect m_defaultPosition; // Default position, used by getSavedPosition()
 
bool m_defaultVisible; // Default visible/hidden, used by getSavedVisible()
 
bool m_defaultVisible; // Default visible/hidden, used by getSavedVisible()
 
bool m_defaultRolledup; // Default rolled up/expanded, used by getSavedRolledup()
 
bool m_defaultRolledup; // Default rolled up/expanded, used by getSavedRolledup()
 +
void _setDialogAttributesMonitored(const CEGUI::String& dialog, const CEGUI::String& attributesMonitored); // Specify which attributes to monitor for this dialog
 +
std::map<CEGUI::String, std::vector<CEGUI::String>> m_attributesMonitoredDialog; // List of the attributes monitored per dialog
 +
 +
struct MultiColumnListConfig {
 +
std::vector<CEGUI::String> columnSequence;
 +
CEGUI::uint sortedColumn;
 +
bool sortAscending;
 +
std::vector<CEGUI::String> columnWidths;
 +
};
 +
std::map<CEGUI::String, MultiColumnListConfig> m_multiColumnListConfigurations;
 +
std::vector<CEGUI::String> m_defaultColumnSequence;
 +
CEGUI::uint m_defaultSortedColumn;
 +
bool m_defaultSortAscending;
 +
std::vector<CEGUI::String> m_defaultColumnWidths;
 +
void _setMultiColumnListAttributesMonitored(const CEGUI::String& multiColumnList, const CEGUI::String& attributesMonitored); // Specify which attributes to monitor for this dialog
 +
std::map<CEGUI::String, std::vector<CEGUI::String>> m_attributesMonitoredMultiColumnList; // List of the attributes monitored per MultiColumnList
 +
 +
CEGUI::String m_configFile; // File containing the positions
 +
static std::vector<CEGUI::String> m_attributeList; // List of the supported attributes
 
};
 
};
 +
 +
#endif // _DialogConfigurations_h_
 
</pre>
 
</pre>
  
Line 82: Line 126:
 
//Definition of XML elements and attributes
 
//Definition of XML elements and attributes
 
const CEGUI::String DialogConfigurations::m_DialogConfigurationElement( "DialogConfigurations" );
 
const CEGUI::String DialogConfigurations::m_DialogConfigurationElement( "DialogConfigurations" );
const CEGUI::String DialogConfigurations::m_configurationElement( "Configuration" );
+
const CEGUI::String DialogConfigurations::m_configurationElementDialog( "DialogConfiguration" );
 
const char DialogConfigurations::windowNameAttribute[] = "Name";
 
const char DialogConfigurations::windowNameAttribute[] = "Name";
 
const char DialogConfigurations::windowPosAttribute[] = "Position";
 
const char DialogConfigurations::windowPosAttribute[] = "Position";
 
const char DialogConfigurations::windowVisibleAttribute[] = "Visible";
 
const char DialogConfigurations::windowVisibleAttribute[] = "Visible";
 
const char DialogConfigurations::windowRolledupAttribute[] = "RolledUp";
 
const char DialogConfigurations::windowRolledupAttribute[] = "RolledUp";
 +
const char DialogConfigurations::monitoredAttributeAll[] = "All";
 +
const char DialogConfigurations::monitoredAttributeNone[] = "None";
 +
const CEGUI::String DialogConfigurations::m_configurationElementMultiColumnList( "MultiColumnListConfiguration" );
 +
const char DialogConfigurations::mclColumnSequenceAttribute[] = "ColumnSequence";
 +
const char DialogConfigurations::mclColumnWidthAttribute[] = "ColumnWidths";
 +
const char DialogConfigurations::mclSortedColumnAttribute[] = "SortedColumn";
 +
const char DialogConfigurations::mclAscendingSortAttribute[]= "AscendingSort";
 +
const char DialogConfigurations::mclColumnWidthSeparator = ';';
 +
 +
// List of the supported attributes
 +
// Each attribute is enclosed within spaces
 +
//const CEGUI::String DialogConfigurations::m_attributeList = " All None Position Visible RolledUp MCLWidths MCLSequence MCLSort ";
 +
std::vector<CEGUI::String> DialogConfigurations::m_attributeList;
 +
 +
 +
void Tokenize(const CEGUI::String& str, std::vector<CEGUI::String>& tokens, const char delimiters = ' ')
 +
{
 +
// Break a sentence into multiple words separated by delimiters
 +
// Does not handle words within double-quotes: One "2 &2" three, four
 +
 +
    // Skip delimiters at beginning
 +
CEGUI::String::size_type lastPos = str.find_first_not_of(delimiters, 0);
 +
 +
    // Find first "non-delimiter"
 +
CEGUI::String::size_type pos = str.find_first_of(delimiters, lastPos);
 +
 +
CEGUI::String::size_type length = str.length();
 +
while (str.npos != pos || str.npos != lastPos)
 +
    {
 +
// Cap the position to the length of the string
 +
if(pos == str.npos)
 +
pos = length;
 +
if(lastPos == str.npos)
 +
lastPos = length;
 +
 +
        // Found a token, add it to the vector
 +
        tokens.push_back(str.substr(lastPos, pos - lastPos));
 +
 +
        // Skip delimiters
 +
        lastPos = str.find_first_not_of(delimiters, pos);
 +
 +
        // Find next "non-delimiter"
 +
        pos = str.find_first_of(delimiters, lastPos);
 +
    }
 +
}
  
 
DialogConfigurations::DialogConfigurations()
 
DialogConfigurations::DialogConfigurations()
 
{
 
{
setDefaults(CEGUI::URect(CEGUI::UDim(0.0f, 0.0f), CEGUI::UDim(0.0f, 0.0f),
+
setDialogDefaults(CEGUI::URect( CEGUI::UDim(0.0f, 0.0f),
CEGUI::UDim(0.5f, 0.0f), CEGUI::UDim(0.5f, 0.0f)),
+
CEGUI::UDim(0.0f, 0.0f),
true,
+
CEGUI::UDim(0.5f, 0.0f),
true);
+
CEGUI::UDim(0.5f, 0.0f)),
 +
true,
 +
true);
 +
 
 +
// setMultiColumnListDefaults()
 +
m_defaultSortedColumn  = 0;
 +
m_defaultSortAscending = true;
 +
 
 +
if(m_attributeList.empty())
 +
{
 +
// This is a static variable, only initialize once
 +
m_attributeList.push_back(monitoredAttributeAll);
 +
m_attributeList.push_back(monitoredAttributeNone);
 +
m_attributeList.push_back(windowPosAttribute);
 +
m_attributeList.push_back(windowVisibleAttribute);
 +
m_attributeList.push_back(windowRolledupAttribute);
 +
m_attributeList.push_back(mclColumnSequenceAttribute);
 +
m_attributeList.push_back(mclSortedColumnAttribute);
 +
m_attributeList.push_back(mclAscendingSortAttribute);
 +
m_attributeList.push_back(mclColumnWidthAttribute);
 +
}
 +
 
 +
// The default is to monitor every attribute
 +
_setDialogAttributesMonitored("", monitoredAttributeAll);
 +
_setMultiColumnListAttributesMonitored("", monitoredAttributeAll);
 
}
 
}
  
void DialogConfigurations::setDefaults(const CEGUI::URect& position, const bool& visible, const bool& rolledup)
+
void DialogConfigurations::setDialogDefaults(const CEGUI::URect& position, const bool& visible, const bool& rolledup)
 
{
 
{
 
// Set default values
 
// Set default values
Line 103: Line 216:
 
m_defaultVisible = visible;
 
m_defaultVisible = visible;
 
m_defaultRolledup = rolledup;
 
m_defaultRolledup = rolledup;
 +
}
 +
 +
void DialogConfigurations::setDefaultDialogAttributesMonitored(const CEGUI::String& attributesMonitored)
 +
{
 +
_setDialogAttributesMonitored("", attributesMonitored);
 +
}
 +
 +
bool DialogConfigurations::addDialog(const CEGUI::String& widget, const CEGUI::String& attributesMonitored)
 +
{
 +
// Add a dialog to be monitored
 +
// This can be used to automatically write the contents of the initial XML file
 +
//  rather than editing it by hand.
 +
assert(!widget.empty() && "You must pass a dialog name to addDialog()");
 +
 +
if(!attributesMonitored.empty())
 +
_setDialogAttributesMonitored(widget, attributesMonitored);
 +
 +
std::map<CEGUI::String, DialogConfig>::iterator itConfig;
 +
itConfig = m_dialogConfigurations.find(widget);
 +
if(itConfig != m_dialogConfigurations.end())
 +
return false; // This dialog is already added
 +
 +
CEGUI::Window* window = CEGUI::WindowManager::getSingleton().getWindow(widget);
 +
DialogConfig config;
 +
config.position = window->getWindowArea();
 +
config.visible = window->isVisible();
 +
if( window->testClassName("FrameWindow") )
 +
config.rolledup = static_cast<CEGUI::FrameWindow*>(window)->isRolledup();
 +
else
 +
config.rolledup = m_defaultRolledup; // Not really needed, unless this window inherits from FrameWindow after being loaded
 +
 +
m_dialogConfigurations[widget] = config;
 +
return true;
 +
}
 +
 +
const CEGUI::URect& DialogConfigurations::getDialogSavedPosition(const CEGUI::String& dialog)
 +
{
 +
// Return the position of the specified dialog
 +
std::map<CEGUI::String, DialogConfig>::iterator itConfig;
 +
itConfig = m_dialogConfigurations.find(dialog);
 +
return itConfig == m_dialogConfigurations.end() ? m_defaultPosition : (*itConfig).second.position;
 +
}
 +
 +
const bool& DialogConfigurations::getDialogSavedVisible(const CEGUI::String& dialog)
 +
{
 +
// Return the visible/hidden state of the specified dialog
 +
std::map<CEGUI::String, DialogConfig>::iterator itConfig;
 +
itConfig = m_dialogConfigurations.find(dialog);
 +
return itConfig == m_dialogConfigurations.end() ? m_defaultVisible : (*itConfig).second.visible;
 +
}
 +
 +
const bool& DialogConfigurations::getDialogSavedRolledup(const CEGUI::String& dialog)
 +
{
 +
// Return the expansion state of the specified dialog
 +
std::map<CEGUI::String, DialogConfig>::iterator itConfig;
 +
itConfig = m_dialogConfigurations.find(dialog);
 +
return itConfig == m_dialogConfigurations.end() ? m_defaultRolledup : (*itConfig).second.rolledup;
 +
}
 +
 +
void DialogConfigurations::setMultiColumnListDefaults(const std::vector<CEGUI::String>& columnSequence, const CEGUI::uint& sortedColumn, const bool& sortAscending, const std::vector<CEGUI::String>& columnWidths)
 +
{
 +
// Set default values
 +
// Should validate what's being passed as parameters
 +
m_defaultColumnSequence = columnSequence;
 +
m_defaultSortedColumn = sortedColumn;
 +
m_defaultSortAscending = sortAscending;
 +
m_defaultColumnWidths = columnWidths;
 +
}
 +
 +
void DialogConfigurations::setDefaultMultiColumnListAttributesMonitored(const CEGUI::String& attributesMonitored)
 +
{
 +
_setMultiColumnListAttributesMonitored("", attributesMonitored);
 +
}
 +
 +
bool DialogConfigurations::addMultiColumnList(const CEGUI::String& widget, const CEGUI::String& attributesMonitored)
 +
{
 +
// Add a MultiColumnList to be monitored
 +
// This can be used to automatically write the contents of the initial XML file
 +
//  rather than editing it by hand.
 +
assert(!widget.empty() && "You must pass a multiColumnList name to addMultiColumnList()");
 +
 +
if(!attributesMonitored.empty())
 +
_setMultiColumnListAttributesMonitored(widget, attributesMonitored);
 +
 +
std::map<CEGUI::String, MultiColumnListConfig>::iterator itConfig;
 +
itConfig = m_multiColumnListConfigurations.find(widget);
 +
if(itConfig != m_multiColumnListConfigurations.end())
 +
return false; // This MultiColumnList is already added
 +
 +
MultiColumnListConfig config;
 +
CEGUI::MultiColumnList* multiColumnList = static_cast<CEGUI::MultiColumnList*>(CEGUI::WindowManager::getSingleton().getWindow(widget));
 +
for(CEGUI::uint columnIndex = 0; columnIndex < multiColumnList->getColumnCount(); ++columnIndex)
 +
{
 +
config.columnSequence.push_back(CEGUI::PropertyHelper::uintToString(multiColumnList->getColumnID(columnIndex)));
 +
config.columnWidths.push_back(CEGUI::PropertyHelper::udimToString(multiColumnList->getColumnHeaderWidth(columnIndex)));
 +
}
 +
config.sortedColumn  = multiColumnList->getSortColumn();
 +
config.sortAscending = multiColumnList->getSortDirection() != CEGUI::ListHeaderSegment::Descending;
 +
 +
m_multiColumnListConfigurations[widget] = config;
 +
return true;
 
}
 
}
  
Line 114: Line 328:
 
CEGUI::System::getSingleton().getXMLParser()->parseXMLFile(*this, m_configFile, schema, "");
 
CEGUI::System::getSingleton().getXMLParser()->parseXMLFile(*this, m_configFile, schema, "");
 
}
 
}
catch(CEGUI::GenericException& )
+
catch(...)
 
{
 
{
 
// File is empty or parse error
 
// File is empty or parse error
 +
// Silently ignore; we'll create a new file when saving
 
}
 
}
 
return true;
 
return true;
Line 145: Line 360:
  
 
// Write each dialog's configuration
 
// Write each dialog's configuration
DialogConfig config;
+
DialogConfig dialogConfig;
 
CEGUI::WindowManager& winMgr = CEGUI::WindowManager::getSingleton();
 
CEGUI::WindowManager& winMgr = CEGUI::WindowManager::getSingleton();
std::map<CEGUI::String, DialogConfig>::iterator itConfig;
+
std::map<CEGUI::String, DialogConfig>::iterator itDialogConfig;
CEGUI::Window* widget;
+
std::map<CEGUI::String, std::vector<CEGUI::String>>::iterator itAttributesMonitored;
for(itConfig = m_dialogConfigurations.begin(); itConfig != m_dialogConfigurations.end(); ++itConfig)
+
std::vector<CEGUI::String> attributesMonitored;
 +
CEGUI::Window* window;
 +
for(itDialogConfig = m_dialogConfigurations.begin(); itDialogConfig != m_dialogConfigurations.end(); ++itDialogConfig)
 
{
 
{
widget = winMgr.getWindow(itConfig->first);
+
itAttributesMonitored = m_attributesMonitoredDialog.find(itDialogConfig->first);
config.position = widget->getWindowArea();
+
if(itAttributesMonitored != m_attributesMonitoredDialog.end())
config.visible = widget->isVisible();
+
attributesMonitored = (*itAttributesMonitored).second; // Dialog has specified attributes
if( widget->testClassName("FrameWindow") )
+
config.rolledup = static_cast<CEGUI::FrameWindow*>(widget)->isRolledup();
+
 
else
 
else
config.rolledup = false;
+
{
fileSave << "  <" << m_configurationElement.c_str() << " "
+
// Use default attributes
<< windowNameAttribute << "=\"" << itConfig->first << "\" "
+
itAttributesMonitored = m_attributesMonitoredDialog.find("");
<< windowPosAttribute << "=\"" << CEGUI::PropertyHelper::urectToString(config.position) << "\" "
+
if(itAttributesMonitored != m_attributesMonitoredDialog.end())
<< windowVisibleAttribute << "=\"" << config.visible << "\" "
+
attributesMonitored = (*itAttributesMonitored).second;
<< windowRolledupAttribute << "=\"" << config.rolledup << "\" "
+
}
<< "/>" << std::endl;
+
 
 +
window = winMgr.getWindow(itDialogConfig->first);
 +
dialogConfig.position = window->getWindowArea();
 +
dialogConfig.visible = window->isVisible();
 +
if( window->testClassName("FrameWindow") )
 +
dialogConfig.rolledup = static_cast<CEGUI::FrameWindow*>(window)->isRolledup();
 +
else
 +
dialogConfig.rolledup = false;
 +
fileSave << "  <" << m_configurationElementDialog.c_str() << " "
 +
<< windowNameAttribute << "=\"" << itDialogConfig->first << "\" ";
 +
if(isMonitoringAttribute(attributesMonitored, windowPosAttribute))
 +
fileSave << windowPosAttribute << "=\"" << CEGUI::PropertyHelper::urectToString(dialogConfig.position) << "\" ";
 +
if(isMonitoringAttribute(attributesMonitored, windowVisibleAttribute))
 +
fileSave << windowVisibleAttribute << "=\"" << dialogConfig.visible << "\" ";
 +
if(isMonitoringAttribute(attributesMonitored, windowRolledupAttribute))
 +
fileSave << windowRolledupAttribute << "=\"" << dialogConfig.rolledup << "\" ";
 +
fileSave << "/>" << std::endl;
 
}
 
}
 +
 +
 +
// Write each MultiColumnList's configuration
 +
std::map<CEGUI::String, MultiColumnListConfig>::iterator itMultiColumnListConfig;
 +
attributesMonitored.clear();
 +
CEGUI::MultiColumnList* multiColumnList;
 +
for(itMultiColumnListConfig = m_multiColumnListConfigurations.begin(); itMultiColumnListConfig != m_multiColumnListConfigurations.end(); ++itMultiColumnListConfig)
 +
{
 +
itAttributesMonitored = m_attributesMonitoredMultiColumnList.find(itMultiColumnListConfig->first);
 +
if(itAttributesMonitored != m_attributesMonitoredMultiColumnList.end())
 +
attributesMonitored = (*itAttributesMonitored).second; // Dialog has specified attributes
 +
else
 +
{
 +
// Use default attributes
 +
itAttributesMonitored = m_attributesMonitoredMultiColumnList.find("");
 +
if(itAttributesMonitored != m_attributesMonitoredMultiColumnList.end())
 +
attributesMonitored = (*itAttributesMonitored).second;
 +
}
 +
 +
multiColumnList = static_cast<CEGUI::MultiColumnList*>(winMgr.getWindow(itMultiColumnListConfig->first));
 +
fileSave << "  <" << m_configurationElementMultiColumnList.c_str() << " "
 +
<< windowNameAttribute << "=\"" << itMultiColumnListConfig->first << "\" ";
 +
if(isMonitoringAttribute(attributesMonitored, mclColumnSequenceAttribute) && multiColumnList->getColumnCount())
 +
{
 +
fileSave << mclColumnSequenceAttribute << "=\"";
 +
for(CEGUI::uint columnIndex = 0; columnIndex < multiColumnList->getColumnCount(); ++columnIndex)
 +
{
 +
if(columnIndex)
 +
fileSave << ",";
 +
fileSave << multiColumnList->getColumnID(columnIndex);
 +
}
 +
fileSave << "\" ";
 +
}
 +
if(isMonitoringAttribute(attributesMonitored, mclColumnWidthAttribute) && multiColumnList->getColumnCount())
 +
{
 +
fileSave << mclColumnWidthAttribute << "=\"";
 +
for(CEGUI::uint columnIndex = 0; columnIndex < multiColumnList->getColumnCount(); ++columnIndex)
 +
{
 +
if(columnIndex)
 +
fileSave << mclColumnWidthSeparator;
 +
fileSave << CEGUI::PropertyHelper::udimToString(multiColumnList->getColumnHeaderWidth(columnIndex));
 +
}
 +
fileSave << "\" ";
 +
}
 +
if(isMonitoringAttribute(attributesMonitored, mclSortedColumnAttribute))
 +
fileSave << mclSortedColumnAttribute << "=\"" << multiColumnList->getColumnID(multiColumnList->getSortColumn()) << "\" ";
 +
if(isMonitoringAttribute(attributesMonitored, mclAscendingSortAttribute))
 +
fileSave << mclAscendingSortAttribute << "=\"" << (multiColumnList->getSortDirection() != CEGUI::ListHeaderSegment::Descending) << "\" ";
 +
fileSave << "/>" << std::endl;
 +
}
 +
  
 
// Write the footer
 
// Write the footer
Line 172: Line 454:
 
}
 
}
  
bool DialogConfigurations::addDialog(const CEGUI::String& dialog)
+
bool DialogConfigurations::isMonitoringAttribute(const std::vector<CEGUI::String>& list, const CEGUI::String& attribute)
 
{
 
{
// Add a dialog to be monitored
+
std::vector<CEGUI::String>::const_iterator itList;
// This can be used to automatically write the contents of the initial XML file
+
for(itList = list.begin(); itList != list.end(); itList++)
//  rather than editing it by hand.  The XML file passed to loadConfigurations() MUST
+
{
//  exist but it can be empty
+
if(!(*itList).compare(attribute))
std::map<CEGUI::String, DialogConfig>::iterator itConfig;
+
return true;
itConfig = m_dialogConfigurations.find(dialog);
+
}
if(itConfig != m_dialogConfigurations.end())
+
return false;
return false; // This dialog is already added
+
 
+
CEGUI::Window* widget = CEGUI::WindowManager::getSingleton().getWindow(dialog);
+
DialogConfig config;
+
config.position = widget->getWindowArea();
+
config.visible = widget->isVisible();
+
if( widget->testClassName("FrameWindow") )
+
config.rolledup = static_cast<CEGUI::FrameWindow*>(widget)->isRolledup();
+
else
+
config.rolledup = m_defaultRolledup; // Not really needed, unless this window inherits from FrameWindow after being loaded
+
 
+
m_dialogConfigurations[dialog] = config;
+
return true;
+
 
}
 
}
  
const CEGUI::URect& DialogConfigurations::getSavedPosition(const CEGUI::String& dialog)
+
void DialogConfigurations::elementStart(const CEGUI::String& element, const CEGUI::XMLAttributes& xmlAttributes)
 
{
 
{
// Return the position of the specified dialog
+
// Performs the actual load every stored dialog
std::map<CEGUI::String, DialogConfig>::iterator itConfig;
+
if (element == m_configurationElementDialog)
itConfig = m_dialogConfigurations.find(dialog);
+
    {
return itConfig == m_dialogConfigurations.end() ? m_defaultPosition : (*itConfig).second.position;
+
DialogConfig config;
 +
config.position = m_defaultPosition;
 +
config.visible  = m_defaultVisible;
 +
config.rolledup = m_defaultRolledup;
 +
CEGUI::String name;
 +
CEGUI::WindowManager& winMgr = CEGUI::WindowManager::getSingleton();
 +
 
 +
name = xmlAttributes.getValueAsString(windowNameAttribute);
 +
CEGUI::Window* window = winMgr.getWindow(name);
 +
 
 +
std::vector<CEGUI::String> attributesMonitored;
 +
std::map<CEGUI::String, std::vector<CEGUI::String>>::iterator itAttributesMonitored;
 +
itAttributesMonitored = m_attributesMonitoredDialog.find(name);
 +
if(itAttributesMonitored != m_attributesMonitoredDialog.end())
 +
attributesMonitored = (*itAttributesMonitored).second; // Dialog has specified attributes
 +
else
 +
{
 +
// Use default attributes
 +
itAttributesMonitored = m_attributesMonitoredDialog.find("");
 +
if(itAttributesMonitored != m_attributesMonitoredDialog.end())
 +
attributesMonitored = (*itAttributesMonitored).second;
 +
}
 +
 
 +
if(xmlAttributes.exists(windowPosAttribute) && isMonitoringAttribute(attributesMonitored, windowPosAttribute))
 +
{
 +
config.position = CEGUI::PropertyHelper::stringToURect(xmlAttributes.getValueAsString(windowPosAttribute));
 +
window->setWindowArea(config.position);
 +
}
 +
if(xmlAttributes.exists(windowVisibleAttribute) && isMonitoringAttribute(attributesMonitored, windowVisibleAttribute))
 +
{
 +
config.visible = xmlAttributes.getValueAsBool(windowVisibleAttribute);
 +
window->setVisible(config.visible);
 +
}
 +
if(xmlAttributes.exists(windowRolledupAttribute) && isMonitoringAttribute(attributesMonitored, windowRolledupAttribute))
 +
{
 +
config.rolledup = xmlAttributes.getValueAsBool(windowRolledupAttribute);
 +
if( winMgr.getWindow(name)->testClassName("FrameWindow") )
 +
{
 +
//CEGUI::MultiColumnList* mcl;
 +
CEGUI::FrameWindow* frameWindow = static_cast<CEGUI::FrameWindow*>(window);
 +
if(frameWindow->isRolledup() != config.rolledup)
 +
frameWindow->toggleRollup();
 +
}
 +
}
 +
 
 +
m_dialogConfigurations[name] = config;
 +
}
 +
else if (element == m_configurationElementMultiColumnList)
 +
    {
 +
MultiColumnListConfig config;
 +
config.sortedColumn  = m_defaultSortedColumn;
 +
config.sortAscending = m_defaultSortAscending;
 +
CEGUI::String name;
 +
CEGUI::WindowManager& winMgr = CEGUI::WindowManager::getSingleton();
 +
 
 +
name = xmlAttributes.getValueAsString(windowNameAttribute);
 +
CEGUI::MultiColumnList* multiColumnList = static_cast<CEGUI::MultiColumnList*>(winMgr.getWindow(name));
 +
 
 +
std::vector<CEGUI::String> attributesMonitored;
 +
std::map<CEGUI::String, std::vector<CEGUI::String>>::iterator itAttributesMonitored;
 +
itAttributesMonitored = m_attributesMonitoredMultiColumnList.find(name);
 +
if(itAttributesMonitored != m_attributesMonitoredMultiColumnList.end())
 +
attributesMonitored = (*itAttributesMonitored).second; // Dialog has specified attributes
 +
else
 +
{
 +
// Use default attributes
 +
itAttributesMonitored = m_attributesMonitoredMultiColumnList.find("");
 +
if(itAttributesMonitored != m_attributesMonitoredMultiColumnList.end())
 +
attributesMonitored = (*itAttributesMonitored).second;
 +
}
 +
 
 +
if(xmlAttributes.exists(mclColumnSequenceAttribute) && isMonitoringAttribute(attributesMonitored, mclColumnSequenceAttribute))
 +
{
 +
CEGUI::String columnSequence = xmlAttributes.getValueAsString(mclColumnSequenceAttribute);
 +
Tokenize(columnSequence, config.columnSequence, ',');
 +
for(CEGUI::uint columnIndex = 0; columnIndex < multiColumnList->getColumnCount() && columnIndex < config.columnSequence.size(); ++columnIndex)
 +
{
 +
multiColumnList->moveColumn(multiColumnList->getColumnWithID(CEGUI::PropertyHelper::stringToUint(config.columnSequence.at(columnIndex))),
 +
columnIndex);
 +
}
 +
}
 +
if(xmlAttributes.exists(mclColumnWidthAttribute) && isMonitoringAttribute(attributesMonitored, mclColumnWidthAttribute))
 +
{
 +
CEGUI::String columnWidths = xmlAttributes.getValueAsString(mclColumnWidthAttribute);
 +
Tokenize(columnWidths, config.columnWidths, mclColumnWidthSeparator);
 +
CEGUI::UDim width;
 +
for(CEGUI::uint columnIndex = 0; columnIndex < multiColumnList->getColumnCount() && columnIndex < config.columnWidths.size(); ++columnIndex)
 +
{
 +
width = CEGUI::PropertyHelper::stringToUDim(config.columnWidths.at(columnIndex));
 +
multiColumnList->setColumnHeaderWidth(columnIndex, width);
 +
}
 +
}
 +
if(xmlAttributes.exists(mclSortedColumnAttribute) && isMonitoringAttribute(attributesMonitored, mclSortedColumnAttribute))
 +
{
 +
config.sortedColumn = xmlAttributes.getValueAsInteger(mclSortedColumnAttribute);
 +
multiColumnList->setSortColumn( multiColumnList->getColumnWithID(config.sortedColumn) );
 +
}
 +
if(xmlAttributes.exists(mclAscendingSortAttribute) && isMonitoringAttribute(attributesMonitored, mclAscendingSortAttribute))
 +
{
 +
config.sortAscending = xmlAttributes.getValueAsBool(mclAscendingSortAttribute);
 +
multiColumnList->setSortDirection( config.sortAscending ? CEGUI::ListHeaderSegment::Ascending
 +
: CEGUI::ListHeaderSegment::Descending);
 +
}
 +
 
 +
m_multiColumnListConfigurations[name] = config;
 +
}
 
}
 
}
  
const bool& DialogConfigurations::getSavedVisible(const CEGUI::String& dialog)
+
void DialogConfigurations::_setDialogAttributesMonitored(const CEGUI::String& dialog, const CEGUI::String& attributesMonitored)
 
{
 
{
// Return the visible/hidden state of the specified dialog
+
// Validate the attributes to be monitored
std::map<CEGUI::String, DialogConfig>::iterator itConfig;
+
std::vector<CEGUI::String> newAttributes;
itConfig = m_dialogConfigurations.find(dialog);
+
std::vector<CEGUI::String> listAttributesMonitored;
return itConfig == m_dialogConfigurations.end() ? m_defaultVisible : (*itConfig).second.visible;
+
Tokenize(attributesMonitored, listAttributesMonitored); // Convert attributesMonitored into a vector
 +
std::vector<CEGUI::String>::iterator itToken;
 +
for(itToken = listAttributesMonitored.begin(); itToken != listAttributesMonitored.end(); itToken++)
 +
{
 +
if(!(*itToken).compare(monitoredAttributeAll))
 +
{
 +
newAttributes.push_back(windowPosAttribute);
 +
newAttributes.push_back(windowVisibleAttribute);
 +
newAttributes.push_back(windowRolledupAttribute);
 +
}
 +
else if(!(*itToken).compare(monitoredAttributeNone))
 +
{
 +
newAttributes.clear();
 +
}
 +
else if(!(*itToken).compare(windowPosAttribute))
 +
newAttributes.push_back(windowPosAttribute);
 +
else if(!(*itToken).compare(windowVisibleAttribute))
 +
newAttributes.push_back(windowVisibleAttribute);
 +
else if(!(*itToken).compare(windowRolledupAttribute))
 +
newAttributes.push_back(windowRolledupAttribute);
 +
else
 +
{
 +
// Attribute is not supported
 +
assert(false && "Unsupported attribute specified for a dialog");
 +
CEGUI::Logger::getSingleton().logEvent("The attribute \""
 +
+ (*itToken)
 +
+ "\" is unsupported for dialogs.",
 +
CEGUI::Errors);
 +
}
 +
}
 +
 
 +
// Store the attributes to be monitored
 +
m_attributesMonitoredDialog[dialog] = newAttributes;
 
}
 
}
  
const bool& DialogConfigurations::getSavedRolledup(const CEGUI::String& dialog)
+
void DialogConfigurations::_setMultiColumnListAttributesMonitored(const CEGUI::String& multiColumnList, const CEGUI::String& attributesMonitored)
 
{
 
{
// Return the expansion state of the specified dialog
+
// Validate the attributes to be monitored
std::map<CEGUI::String, DialogConfig>::iterator itConfig;
+
std::vector<CEGUI::String> newAttributes;
itConfig = m_dialogConfigurations.find(dialog);
+
std::vector<CEGUI::String> listAttributesMonitored;
return itConfig == m_dialogConfigurations.end() ? m_defaultRolledup : (*itConfig).second.rolledup;
+
Tokenize(attributesMonitored, listAttributesMonitored); // Convert attributesMonitored into a vector
 +
std::vector<CEGUI::String>::iterator itToken;
 +
for(itToken = listAttributesMonitored.begin(); itToken != listAttributesMonitored.end(); itToken++)
 +
{
 +
if(!(*itToken).compare(monitoredAttributeAll))
 +
{
 +
newAttributes.push_back(mclColumnSequenceAttribute);
 +
newAttributes.push_back(mclSortedColumnAttribute);
 +
newAttributes.push_back(mclAscendingSortAttribute);
 +
newAttributes.push_back(mclColumnWidthAttribute);
 +
}
 +
else if(!(*itToken).compare(monitoredAttributeNone))
 +
{
 +
newAttributes.clear();
 +
}
 +
else if(!(*itToken).compare(mclColumnSequenceAttribute))
 +
newAttributes.push_back(mclColumnSequenceAttribute);
 +
else if(!(*itToken).compare(mclSortedColumnAttribute))
 +
newAttributes.push_back(mclSortedColumnAttribute);
 +
else if(!(*itToken).compare(mclAscendingSortAttribute))
 +
newAttributes.push_back(mclAscendingSortAttribute);
 +
else if(!(*itToken).compare(mclColumnWidthAttribute))
 +
newAttributes.push_back(mclColumnWidthAttribute);
 +
else
 +
{
 +
// Attribute is not supported
 +
assert(false && "Unsupported attribute specified for a MultiColumnList");
 +
CEGUI::Logger::getSingleton().logEvent("The attribute \""
 +
+ (*itToken)
 +
+ "\" is unsupported for MultiColumnLists.",
 +
CEGUI::Errors);
 +
}
 +
}
 +
 
 +
// Store the attributes to be monitored
 +
m_attributesMonitoredMultiColumnList[multiColumnList] = newAttributes;
 
}
 
}
 +
</pre>
  
void DialogConfigurations::elementStart(const CEGUI::String& element, const CEGUI::XMLAttributes& attributes)
+
==== DialogConfigurationsDemo.h ====
 +
<pre>
 +
#ifndef _DialogConfigurationsDemo_h_
 +
#define _DialogConfigurationsDemo_h_
 +
 
 +
#include "CEGuiSample.h"
 +
#include "CEGUI.h"
 +
#include "DialogConfigurations.h"
 +
 
 +
class DemoSample : public CEGuiSample
 
{
 
{
// Parse the <Configuration> elements
+
public:
DialogConfig config;
+
    bool initialiseSample()
CEGUI::String name;
+
{
CEGUI::WindowManager& winMgr = CEGUI::WindowManager::getSingleton();
+
using namespace CEGUI;
if (element == m_configurationElement)
+
try
    {
+
{
        name = attributes.getValueAsString(windowNameAttribute);
+
// Retrieve the window manager
config.position = CEGUI::PropertyHelper::stringToURect(attributes.getValueAsString(windowPosAttribute));
+
WindowManager& winMgr = WindowManager::getSingleton();
config.visible = attributes.getValueAsBool(windowVisibleAttribute);
+
config.rolledup = attributes.getValueAsBool(windowRolledupAttribute);
+
  
// Set the configuration of the dialog
+
// Load the TaharezLook scheme and set up the default mouse cursor and font
CEGUI::Window* widget = winMgr.getWindow(name);
+
SchemeManager::getSingleton().loadScheme("TaharezLookSkin.scheme");
widget->setWindowArea(config.position);
+
System::getSingleton().setDefaultMouseCursor("TaharezLook", "MouseArrow");
widget->setVisible(config.visible);
+
FontManager::getSingleton().createFont("Commonwealth-10.font");
if( winMgr.getWindow(name)->testClassName("FrameWindow") )
+
 
 +
// Set the GUI Sheet
 +
Window* sheet = winMgr.createWindow("DefaultWindow", "root_wnd");
 +
System::getSingleton().setGUISheet(sheet);
 +
 
 +
// Load a layout
 +
Window* guiLayout = winMgr.loadWindowLayout("DialogConfigurations.layout");
 +
sheet->addChildWindow(guiLayout);
 +
 
 +
// Configure the toolbar
 +
winMgr.getWindow("DialogConfigurations/Toolbar/ShowA")->subscribeEvent(PushButton::EventClicked, Event::Subscriber(&DemoSample::showA, this));
 +
winMgr.getWindow("DialogConfigurations/Toolbar/ShowC")->subscribeEvent(PushButton::EventClicked, Event::Subscriber(&DemoSample::showC, this));
 +
winMgr.getWindow("DialogConfigurations/Toolbar/ShowD")->subscribeEvent(PushButton::EventClicked, Event::Subscriber(&DemoSample::showD, this));
 +
 
 +
// Activate the close buttons
 +
winMgr.getWindow("DialogConfigurations/Window_A")->subscribeEvent(FrameWindow::EventCloseClicked, Event::Subscriber(&DemoSample::closeA, this));
 +
winMgr.getWindow("DialogConfigurations/Window_B")->subscribeEvent(FrameWindow::EventCloseClicked, Event::Subscriber(&DemoSample::closeB, this));
 +
winMgr.getWindow("DialogConfigurations/Window_C")->subscribeEvent(FrameWindow::EventCloseClicked, Event::Subscriber(&DemoSample::closeC, this));
 +
winMgr.getWindow("DialogConfigurations/Window_D")->subscribeEvent(FrameWindow::EventCloseClicked, Event::Subscriber(&DemoSample::closeD, this));
 +
 
 +
// Add columns to the MultiColumnList
 +
MultiColumnList* multiColumnList = static_cast<MultiColumnList*>(winMgr.getWindow("DialogConfigurations/Window_D/MultiColumnList"));
 +
multiColumnList->addColumn("Col A", 0, UDim(0.32f, 0));
 +
multiColumnList->addColumn("Col B", 1, UDim(0.32f, 0));
 +
multiColumnList->addColumn("Col C", 2, UDim(0.32f, 0));
 +
 
 +
// Add rows
 +
multiColumnList->addRow();
 +
multiColumnList->setItem(new ListboxTextItem("1", 101), 0, 0); // ColumnID, RowID
 +
multiColumnList->setItem(new ListboxTextItem("4", 102), 1, 0);
 +
multiColumnList->setItem(new ListboxTextItem("7", 103), 2, 0);
 +
multiColumnList->addRow();
 +
multiColumnList->setItem(new ListboxTextItem("4", 201), 0, 1);
 +
multiColumnList->setItem(new ListboxTextItem("7", 202), 1, 1);
 +
multiColumnList->setItem(new ListboxTextItem("1", 203), 2, 1);
 +
multiColumnList->addRow();
 +
multiColumnList->setItem(new ListboxTextItem("7", 301), 0, 2);
 +
multiColumnList->setItem(new ListboxTextItem("1", 302), 1, 2);
 +
multiColumnList->setItem(new ListboxTextItem("4", 303), 2, 2);
 +
 
 +
 
 +
// Activate dialog configurations
 +
m_DialogConfigurations.loadConfigurations("DialogConfigurations.xml");
 +
m_DialogConfigurations.addDialog("DialogConfigurations/Window_A", "Position Visible");
 +
m_DialogConfigurations.addDialog("DialogConfigurations/Window_B", "Position RolledUp");
 +
m_DialogConfigurations.addDialog("DialogConfigurations/Window_C", "Visible RolledUp");
 +
m_DialogConfigurations.addDialog("DialogConfigurations/Window_D"); // Saves every attribute: Position, Visible, and RolledUp
 +
m_DialogConfigurations.addMultiColumnList("DialogConfigurations/Window_D/MultiColumnList"); // Saves every attribute: ColumnSequence, ColumnWidths, SortedColumn, and AscendingSort
 +
}
 +
catch(Exception &e)
 
{
 
{
CEGUI::FrameWindow* frameWindow = static_cast<CEGUI::FrameWindow*>(widget);
+
#if defined( __WIN32__ ) || defined( _WIN32 )
if(frameWindow->isRolledup() != config.rolledup)
+
MessageBox(NULL, e.getMessage().c_str(), "Error initializing the demo", MB_OK | MB_ICONERROR | MB_TASKMODAL);
frameWindow->toggleRollup();
+
#else
 +
std::cerr << "Error initializing the demo:" << e.getMessage().c_str() << "\n";
 +
#endif
 
}
 
}
m_dialogConfigurations[name] = config;
+
 
 +
return true;
 
}
 
}
}
+
 
 +
    void cleanupSample(void)
 +
{
 +
m_DialogConfigurations.saveConfigurations();
 +
}
 +
 
 +
bool showA(const CEGUI::EventArgs& e)
 +
{
 +
CEGUI::WindowManager::getSingleton().getWindow("DialogConfigurations/Window_A")->setVisible(true);
 +
return true;
 +
}
 +
 
 +
bool showC(const CEGUI::EventArgs& e)
 +
{
 +
CEGUI::WindowManager::getSingleton().getWindow("DialogConfigurations/Window_C")->setVisible(true);
 +
return true;
 +
}
 +
 
 +
bool showD(const CEGUI::EventArgs& e)
 +
{
 +
CEGUI::WindowManager::getSingleton().getWindow("DialogConfigurations/Window_D")->setVisible(true);
 +
return true;
 +
}
 +
 
 +
bool closeA(const CEGUI::EventArgs& e)
 +
{
 +
CEGUI::WindowManager::getSingleton().getWindow("DialogConfigurations/Window_A")->setVisible(false);
 +
return true;
 +
}
 +
 
 +
bool closeB(const CEGUI::EventArgs& e)
 +
{
 +
CEGUI::WindowManager::getSingleton().getWindow("DialogConfigurations/Window_B")->setVisible(false);
 +
return true;
 +
}
 +
 
 +
bool closeC(const CEGUI::EventArgs& e)
 +
{
 +
CEGUI::WindowManager::getSingleton().getWindow("DialogConfigurations/Window_C")->setVisible(false);
 +
return true;
 +
}
 +
 
 +
bool closeD(const CEGUI::EventArgs& e)
 +
{
 +
CEGUI::WindowManager::getSingleton().getWindow("DialogConfigurations/Window_D")->setVisible(false);
 +
return true;
 +
}
 +
private:
 +
DialogConfigurations m_DialogConfigurations;
 +
};
 +
 
 +
#endif // _DialogConfigurationsDemo_h_
 
</pre>
 
</pre>
  
==== DialogConfigurations.xsd ====
+
==== main.cpp ====
 
<pre>
 
<pre>
<?xml version="1.0"?>
+
#if defined( __WIN32__ ) || defined( _WIN32 )
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified">
+
#define WIN32_LEAN_AND_MEAN
 +
#define NOMINMAX
 +
#include "windows.h"
 +
#endif
  
<xsd:element name="DialogConfiguration" type="DialogConfigurationType"/>
+
#include "DialogConfigurationsDemo.h"
  
<xsd:complexType name="DialogConfigurationType">
+
#if defined( __WIN32__ ) || defined( _WIN32 )
<xsd:sequence>
+
int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine,int nCmdShow)
<xsd:element name="Configuration" type="ConfigurationType" maxOccurs="unbounded"/>
+
#else
</xsd:sequence>
+
int main(int argc, char *argv[])
</xsd:complexType>
+
#endif
 
+
{
<xsd:complexType name="ConfigurationType">
+
    DemoSample app;
<xsd:attribute name="Name"     type="xsd:string"  use="required"/>
+
     return app.run();
<xsd:attribute name="Position" type="xsd:string"  use="required"/>
+
}
<xsd:attribute name="Visible"  type="xsd:boolean" use="required"/>
+
<xsd:attribute name="RolledUp" type="xsd:boolean" use="required"/>
+
</xsd:complexType>
+
+
</xsd:schema>
+
 
</pre>
 
</pre>

Revision as of 19:07, 9 July 2006

Introduction

Dialogs (frame windows) can be moved around, resized, hidden, and rolled up while the application is running. MultiColumnLists can have their columns rearranged, resized, and a column can sort its content in ascending or descending order. However closing and then restarting the application will reset these settings to their default values, those specified within a .layout file if one was use, or those specified in code.

This clases saves these attributes into an XML file. When the application restarts the contents of the XML file will be read and the dialogs and MultiColumnLists will be restored to their last states.

Sample_Demo7

This demo contains 3 dialogs. Let's store their configurations.

Add DialogConfigurations.cpp to the Sample_Demo7 project.

Edit Sample_Demo7.h:

  • add #include "DialogConfigurations.h"
  • add within the protected section: DialogConfigurations m_dialogConfigurations;

Edit Sample_Demo7.cpp to add the following at the end of the Demo7Sample::initialiseSample() function, between initDemoEventWiring(); and return true;:

 m_dialogConfigurations.loadConfigurations("../datafiles/configs/Sample_Demo7.xml", "../datafiles/configs/DialogConfigurations.xsd");
 m_dialogConfigurations.addDialog("Demo7/Window1");
 m_dialogConfigurations.addDialog("Demo7/Window2");
 m_dialogConfigurations.addDialog("Demo7/Window3");

Add the following to Demo7Sample::cleanupSample()

 m_dialogConfigurations.saveConfigurations();

That's it! From now on the 3 windows within that demo will "remember" their previous configurations.

Configuration Attributes

The XML configuration file is loaded by a call to loadConfigurations(). It silently ignores errors within that XML file. The worst that will happen is that some dialogs and MultiColumnLists will revert to their initial values.

Calling addDialog() and passing the window name as parameter will register that dialog to have its configuration written to the XML file. The next call to saveConfigurations() will write the configuration of that registered window such that the next time loadConfigurations() is called the window will be automatically registered.

The second parameter of addDialog() allows you to specify which attributes to monitor. By default every attribute is monitored. However you can specify to monitor one or many of the following, separated by spaces: Position, Visible, and RolledUp.

The addMultiColumnList() function behaves in a similar manner, allowing you to specify which MultiColumnLists which of their attributes to monitor. Again the default is to monitor every attribute but you can also specify one or many of the following: ColumnSequence, ColumnWidths, SortedColumn, and AscendingSort.

Warning: the Demo7Sample::cleanupSample() is never called when exiting the demo, despite what the comments might say. A solution is presented on the message board.

Please discuss this snippet in the Storing Dialog Configurations thread on the message board.

Files

DialogConfigurations.h

#ifndef _DialogConfigurations_h_
#define _DialogConfigurations_h_

#include "CEGUI.h"
#include "CEGUIXMLHandler.h"
#include "CEGUIXMLParser.h"
#include "CEGUIXMLAttributes.h"
#include <map>

class DialogConfigurations : public CEGUI::XMLHandler
{
public:
	DialogConfigurations();
	void setDialogDefaults(const CEGUI::URect& position, const bool& visible, const bool& rolledup); // Set default values
	void setDefaultDialogAttributesMonitored(const CEGUI::String& attributesMonitored);
	bool addDialog(const CEGUI::String& widget, const CEGUI::String& attributesMonitored = ""); // Add a dialog to be monitored
	const CEGUI::URect& getDialogSavedPosition(const CEGUI::String& dialog); // Return the position of the specified dialog
	const bool& getDialogSavedVisible(const CEGUI::String& dialog); // Return the visible/hidden state of the specified dialog
	const bool& getDialogSavedRolledup(const CEGUI::String& dialog); // Return the expansion state of the specified dialog

	void setMultiColumnListDefaults(const std::vector<CEGUI::String>& columnSequence, const CEGUI::uint& sortedColumn, const bool& sortAscending, const std::vector<CEGUI::String>& columnWidths);
	void setDefaultMultiColumnListAttributesMonitored(const CEGUI::String& attributesMonitored);
	bool addMultiColumnList(const CEGUI::String& widget, const CEGUI::String& attributesMonitored = ""); // Add a MultiColumnList to be monitored

	bool loadConfigurations(const CEGUI::String& xmlFile, const CEGUI::String& schema = ""); // Load the position of every stored dialog
	bool saveConfigurations(); // Store the position of every dialogs

	bool isMonitoringAttribute(const std::vector<CEGUI::String>& list, const CEGUI::String& attribute); // Whether a particular attribute is monitored
private:
    void elementStart(const CEGUI::String& element, const CEGUI::XMLAttributes& xmlAttributes);
	static const CEGUI::String m_DialogConfigurationElement; // Tag name for dialog positions element
	static const CEGUI::String m_configurationElementDialog; // Tag name for position elements
	static const char windowNameAttribute[]; // Attribute name that stores the name of the window
	static const char windowPosAttribute[]; // Attribute name that stores the position of the window
	static const char windowVisibleAttribute[]; // Attribute name that stores the visible state of the window
	static const char windowRolledupAttribute[]; // Attribute name that stores the rolledUp state of the window
	static const CEGUI::String m_configurationElementMultiColumnList; // Tag name of MultiColumnList elements
	static const char mclColumnSequenceAttribute[]; // Attribute name that stores the sequence of the columns
	static const char mclSortedColumnAttribute[]; // Attribute name that stores which column is sorted
	static const char mclAscendingSortAttribute[]; // Attribute name that stores the sort order direction
	static const char DialogConfigurations::mclColumnWidthAttribute[]; // Attribute name that stores the widths of the columns
	static const char DialogConfigurations::mclColumnWidthSeparator; // Separator for the column widths
	static const char monitoredAttributeAll[]; // Special attribute name
	static const char monitoredAttributeNone[]; // Special attribute name

	struct DialogConfig {
		CEGUI::URect position;
		bool visible;
		bool rolledup;
	};
	std::map<CEGUI::String, DialogConfig> m_dialogConfigurations; // List of the dialog configurations
	CEGUI::URect m_defaultPosition; // Default position, used by getSavedPosition()
	bool m_defaultVisible; // Default visible/hidden, used by getSavedVisible()
	bool m_defaultRolledup; // Default rolled up/expanded, used by getSavedRolledup()
	void _setDialogAttributesMonitored(const CEGUI::String& dialog, const CEGUI::String& attributesMonitored); // Specify which attributes to monitor for this dialog
	std::map<CEGUI::String, std::vector<CEGUI::String>> m_attributesMonitoredDialog; // List of the attributes monitored per dialog

	struct MultiColumnListConfig {
		std::vector<CEGUI::String> columnSequence;
		CEGUI::uint sortedColumn;
		bool sortAscending;
		std::vector<CEGUI::String> columnWidths;
	};
	std::map<CEGUI::String, MultiColumnListConfig> m_multiColumnListConfigurations;
	std::vector<CEGUI::String> m_defaultColumnSequence;
	CEGUI::uint m_defaultSortedColumn;
	bool m_defaultSortAscending;
	std::vector<CEGUI::String> m_defaultColumnWidths;
	void _setMultiColumnListAttributesMonitored(const CEGUI::String& multiColumnList, const CEGUI::String& attributesMonitored); // Specify which attributes to monitor for this dialog
	std::map<CEGUI::String, std::vector<CEGUI::String>> m_attributesMonitoredMultiColumnList; // List of the attributes monitored per MultiColumnList

	CEGUI::String m_configFile; // File containing the positions
	static std::vector<CEGUI::String> m_attributeList; // List of the supported attributes
};

#endif // _DialogConfigurations_h_

DialogConfigurations.cpp

#include "DialogConfigurations.h"
#include "CEGUIPropertyHelper.h"

//Definition of XML elements and attributes
const CEGUI::String DialogConfigurations::m_DialogConfigurationElement( "DialogConfigurations" );
const CEGUI::String DialogConfigurations::m_configurationElementDialog( "DialogConfiguration" );
const char DialogConfigurations::windowNameAttribute[]		= "Name";
const char DialogConfigurations::windowPosAttribute[]		= "Position";
const char DialogConfigurations::windowVisibleAttribute[]	= "Visible";
const char DialogConfigurations::windowRolledupAttribute[]	= "RolledUp";
const char DialogConfigurations::monitoredAttributeAll[]	= "All";
const char DialogConfigurations::monitoredAttributeNone[]	= "None";
const CEGUI::String DialogConfigurations::m_configurationElementMultiColumnList( "MultiColumnListConfiguration" );
const char DialogConfigurations::mclColumnSequenceAttribute[]	= "ColumnSequence";
const char DialogConfigurations::mclColumnWidthAttribute[]	= "ColumnWidths";
const char DialogConfigurations::mclSortedColumnAttribute[]	= "SortedColumn";
const char DialogConfigurations::mclAscendingSortAttribute[]= "AscendingSort";
const char DialogConfigurations::mclColumnWidthSeparator	= ';';

// List of the supported attributes
// Each attribute is enclosed within spaces
//const CEGUI::String DialogConfigurations::m_attributeList = " All None Position Visible RolledUp MCLWidths MCLSequence MCLSort ";
std::vector<CEGUI::String> DialogConfigurations::m_attributeList;


void Tokenize(const CEGUI::String& str, std::vector<CEGUI::String>& tokens, const char delimiters = ' ')
{
	// Break a sentence into multiple words separated by delimiters
	// Does not handle words within double-quotes: One "2 &2" three, four

    // Skip delimiters at beginning
	CEGUI::String::size_type lastPos = str.find_first_not_of(delimiters, 0);

    // Find first "non-delimiter"
	CEGUI::String::size_type pos = str.find_first_of(delimiters, lastPos);

	CEGUI::String::size_type length = str.length();
	while (str.npos != pos || str.npos != lastPos)
    {
		// Cap the position to the length of the string
		if(pos == str.npos)
			pos = length;
		if(lastPos == str.npos)
			lastPos = length;

        // Found a token, add it to the vector
        tokens.push_back(str.substr(lastPos, pos - lastPos));

        // Skip delimiters
        lastPos = str.find_first_not_of(delimiters, pos);

        // Find next "non-delimiter"
        pos = str.find_first_of(delimiters, lastPos);
    }
}

DialogConfigurations::DialogConfigurations()
{
	setDialogDefaults(CEGUI::URect( CEGUI::UDim(0.0f, 0.0f),
									CEGUI::UDim(0.0f, 0.0f),
									CEGUI::UDim(0.5f, 0.0f),
									CEGUI::UDim(0.5f, 0.0f)),
					true,
					true);

	// setMultiColumnListDefaults()
	m_defaultSortedColumn  = 0;
	m_defaultSortAscending = true;

	if(m_attributeList.empty())
	{
		// This is a static variable, only initialize once
		m_attributeList.push_back(monitoredAttributeAll);
		m_attributeList.push_back(monitoredAttributeNone);
		m_attributeList.push_back(windowPosAttribute);
		m_attributeList.push_back(windowVisibleAttribute);
		m_attributeList.push_back(windowRolledupAttribute);
		m_attributeList.push_back(mclColumnSequenceAttribute);
		m_attributeList.push_back(mclSortedColumnAttribute);
		m_attributeList.push_back(mclAscendingSortAttribute);
		m_attributeList.push_back(mclColumnWidthAttribute);
	}

	// The default is to monitor every attribute
	_setDialogAttributesMonitored("", monitoredAttributeAll);
	_setMultiColumnListAttributesMonitored("", monitoredAttributeAll);
}

void DialogConfigurations::setDialogDefaults(const CEGUI::URect& position, const bool& visible, const bool& rolledup)
{
	// Set default values
	// Should validate what's being passed as parameters
	m_defaultPosition	= position;
	m_defaultVisible	= visible;
	m_defaultRolledup	= rolledup;
}

void DialogConfigurations::setDefaultDialogAttributesMonitored(const CEGUI::String& attributesMonitored)
{
	_setDialogAttributesMonitored("", attributesMonitored);
}

bool DialogConfigurations::addDialog(const CEGUI::String& widget, const CEGUI::String& attributesMonitored)
{
	// Add a dialog to be monitored
	// This can be used to automatically write the contents of the initial XML file
	//   rather than editing it by hand.
	assert(!widget.empty() && "You must pass a dialog name to addDialog()");

	if(!attributesMonitored.empty())
		_setDialogAttributesMonitored(widget, attributesMonitored);

	std::map<CEGUI::String, DialogConfig>::iterator itConfig;
	itConfig = m_dialogConfigurations.find(widget);
	if(itConfig != m_dialogConfigurations.end())
		return false; // This dialog is already added

	CEGUI::Window* window = CEGUI::WindowManager::getSingleton().getWindow(widget);
	DialogConfig config;
	config.position = window->getWindowArea();
	config.visible	= window->isVisible();
	if( window->testClassName("FrameWindow") )
		config.rolledup = static_cast<CEGUI::FrameWindow*>(window)->isRolledup();
	else
		config.rolledup = m_defaultRolledup; // Not really needed, unless this window inherits from FrameWindow after being loaded

	m_dialogConfigurations[widget] = config;
	return true;
}

const CEGUI::URect& DialogConfigurations::getDialogSavedPosition(const CEGUI::String& dialog)
{
	// Return the position of the specified dialog
	std::map<CEGUI::String, DialogConfig>::iterator itConfig;
	itConfig = m_dialogConfigurations.find(dialog);
	return itConfig == m_dialogConfigurations.end() ? m_defaultPosition : (*itConfig).second.position;
}

const bool& DialogConfigurations::getDialogSavedVisible(const CEGUI::String& dialog)
{
	// Return the visible/hidden state of the specified dialog
	std::map<CEGUI::String, DialogConfig>::iterator itConfig;
	itConfig = m_dialogConfigurations.find(dialog);
	return itConfig == m_dialogConfigurations.end() ? m_defaultVisible : (*itConfig).second.visible;
}

const bool& DialogConfigurations::getDialogSavedRolledup(const CEGUI::String& dialog)
{
	// Return the expansion state of the specified dialog
	std::map<CEGUI::String, DialogConfig>::iterator itConfig;
	itConfig = m_dialogConfigurations.find(dialog);
	return itConfig == m_dialogConfigurations.end() ? m_defaultRolledup : (*itConfig).second.rolledup;
}

void DialogConfigurations::setMultiColumnListDefaults(const std::vector<CEGUI::String>& columnSequence, const CEGUI::uint& sortedColumn, const bool& sortAscending, const std::vector<CEGUI::String>& columnWidths)
{
	// Set default values
	// Should validate what's being passed as parameters
	m_defaultColumnSequence = columnSequence;
	m_defaultSortedColumn	= sortedColumn;
	m_defaultSortAscending	= sortAscending;
	m_defaultColumnWidths	= columnWidths;
}

void DialogConfigurations::setDefaultMultiColumnListAttributesMonitored(const CEGUI::String& attributesMonitored)
{
	_setMultiColumnListAttributesMonitored("", attributesMonitored);
}

bool DialogConfigurations::addMultiColumnList(const CEGUI::String& widget, const CEGUI::String& attributesMonitored)
{
	// Add a MultiColumnList to be monitored
	// This can be used to automatically write the contents of the initial XML file
	//   rather than editing it by hand.
	assert(!widget.empty() && "You must pass a multiColumnList name to addMultiColumnList()");

	if(!attributesMonitored.empty())
		_setMultiColumnListAttributesMonitored(widget, attributesMonitored);

	std::map<CEGUI::String, MultiColumnListConfig>::iterator itConfig;
	itConfig = m_multiColumnListConfigurations.find(widget);
	if(itConfig != m_multiColumnListConfigurations.end())
		return false; // This MultiColumnList is already added

	MultiColumnListConfig config;
	CEGUI::MultiColumnList* multiColumnList = static_cast<CEGUI::MultiColumnList*>(CEGUI::WindowManager::getSingleton().getWindow(widget));
	for(CEGUI::uint columnIndex = 0; columnIndex < multiColumnList->getColumnCount(); ++columnIndex)
	{
		config.columnSequence.push_back(CEGUI::PropertyHelper::uintToString(multiColumnList->getColumnID(columnIndex)));
		config.columnWidths.push_back(CEGUI::PropertyHelper::udimToString(multiColumnList->getColumnHeaderWidth(columnIndex)));
	}
	config.sortedColumn  = multiColumnList->getSortColumn();
	config.sortAscending = multiColumnList->getSortDirection() != CEGUI::ListHeaderSegment::Descending;

	m_multiColumnListConfigurations[widget] = config;
	return true;
}

bool DialogConfigurations::loadConfigurations(const CEGUI::String& xmlFile, const CEGUI::String& schema)
{
	// Load the config of every stored dialog
	assert(!xmlFile.empty() && "You must specify an xml file to loadConfigurations()");
	m_configFile = xmlFile;
	try
	{
		CEGUI::System::getSingleton().getXMLParser()->parseXMLFile(*this, m_configFile, schema, "");
	}
	catch(...)
	{
		// File is empty or parse error
		// Silently ignore; we'll create a new file when saving
	}
	return true;
}

bool DialogConfigurations::saveConfigurations()
{
	// Store the configuration of every registered dialog, either within
	// the loaded XML file or those manually registered via addDialog() 
	assert(!m_configFile.empty() && "You must specify an xml file by calling loadConfigurations() before saveConfigurations()");

	// Try to open the XML file in writing mode
    std::ofstream fileSave;
	fileSave.open(m_configFile.c_str(), std::ios::out) ;
    if( !fileSave.is_open() )
    {
		CEGUI::Logger::getSingleton().logEvent("Could not write to dialog configuration file ("
												+ m_configFile
												+ ").  Is it read-only?",
												CEGUI::Errors);
        return false;
    }

	// Write the header
	fileSave << "<?xml version=\"1.0\" ?>" << std::endl
			<< "<" << m_DialogConfigurationElement << ">"
			<< std::endl;

	// Write each dialog's configuration
	DialogConfig dialogConfig;
	CEGUI::WindowManager& winMgr = CEGUI::WindowManager::getSingleton();
	std::map<CEGUI::String, DialogConfig>::iterator itDialogConfig;
	std::map<CEGUI::String, std::vector<CEGUI::String>>::iterator itAttributesMonitored;
	std::vector<CEGUI::String> attributesMonitored;
	CEGUI::Window* window;
	for(itDialogConfig = m_dialogConfigurations.begin(); itDialogConfig != m_dialogConfigurations.end(); ++itDialogConfig)
	{
		itAttributesMonitored = m_attributesMonitoredDialog.find(itDialogConfig->first);
		if(itAttributesMonitored != m_attributesMonitoredDialog.end())
			attributesMonitored = (*itAttributesMonitored).second; // Dialog has specified attributes
		else
		{
			// Use default attributes
			itAttributesMonitored = m_attributesMonitoredDialog.find("");
			if(itAttributesMonitored != m_attributesMonitoredDialog.end())
				attributesMonitored = (*itAttributesMonitored).second;
		}

		window = winMgr.getWindow(itDialogConfig->first);
		dialogConfig.position = window->getWindowArea();
		dialogConfig.visible	= window->isVisible();
		if( window->testClassName("FrameWindow") )
			dialogConfig.rolledup = static_cast<CEGUI::FrameWindow*>(window)->isRolledup();
		else
			dialogConfig.rolledup = false;
		fileSave << "  <" << m_configurationElementDialog.c_str() << " "
			<< windowNameAttribute		<< "=\"" << itDialogConfig->first	<< "\" ";
		if(isMonitoringAttribute(attributesMonitored, windowPosAttribute))
			fileSave << windowPosAttribute		<< "=\"" << CEGUI::PropertyHelper::urectToString(dialogConfig.position)	<< "\" ";
		if(isMonitoringAttribute(attributesMonitored, windowVisibleAttribute))
			fileSave << windowVisibleAttribute	<< "=\"" << dialogConfig.visible	<< "\" ";
		if(isMonitoringAttribute(attributesMonitored, windowRolledupAttribute))
			fileSave << windowRolledupAttribute	<< "=\"" << dialogConfig.rolledup	<< "\" ";
		fileSave << "/>" << std::endl;
	}


	// Write each MultiColumnList's configuration
	std::map<CEGUI::String, MultiColumnListConfig>::iterator itMultiColumnListConfig;
	attributesMonitored.clear();
	CEGUI::MultiColumnList* multiColumnList;
	for(itMultiColumnListConfig = m_multiColumnListConfigurations.begin(); itMultiColumnListConfig != m_multiColumnListConfigurations.end(); ++itMultiColumnListConfig)
	{
		itAttributesMonitored = m_attributesMonitoredMultiColumnList.find(itMultiColumnListConfig->first);
		if(itAttributesMonitored != m_attributesMonitoredMultiColumnList.end())
			attributesMonitored = (*itAttributesMonitored).second; // Dialog has specified attributes
		else
		{
			// Use default attributes
			itAttributesMonitored = m_attributesMonitoredMultiColumnList.find("");
			if(itAttributesMonitored != m_attributesMonitoredMultiColumnList.end())
				attributesMonitored = (*itAttributesMonitored).second;
		}

		multiColumnList = static_cast<CEGUI::MultiColumnList*>(winMgr.getWindow(itMultiColumnListConfig->first));
		fileSave << "  <" << m_configurationElementMultiColumnList.c_str() << " "
			<< windowNameAttribute		<< "=\"" << itMultiColumnListConfig->first	<< "\" ";
		if(isMonitoringAttribute(attributesMonitored, mclColumnSequenceAttribute) && multiColumnList->getColumnCount())
		{
			fileSave << mclColumnSequenceAttribute << "=\"";
			for(CEGUI::uint columnIndex = 0; columnIndex < multiColumnList->getColumnCount(); ++columnIndex)
			{
				if(columnIndex)
					fileSave << ",";
				fileSave << multiColumnList->getColumnID(columnIndex);
			}
			fileSave << "\" ";
		}
		if(isMonitoringAttribute(attributesMonitored, mclColumnWidthAttribute) && multiColumnList->getColumnCount())
		{
			fileSave << mclColumnWidthAttribute << "=\"";
			for(CEGUI::uint columnIndex = 0; columnIndex < multiColumnList->getColumnCount(); ++columnIndex)
			{
				if(columnIndex)
					fileSave << mclColumnWidthSeparator;
				fileSave << CEGUI::PropertyHelper::udimToString(multiColumnList->getColumnHeaderWidth(columnIndex));
			}
			fileSave << "\" ";
		}
		if(isMonitoringAttribute(attributesMonitored, mclSortedColumnAttribute))
			fileSave << mclSortedColumnAttribute	<< "=\"" << multiColumnList->getColumnID(multiColumnList->getSortColumn()) << "\" ";
		if(isMonitoringAttribute(attributesMonitored, mclAscendingSortAttribute))
			fileSave << mclAscendingSortAttribute << "=\"" << (multiColumnList->getSortDirection() != CEGUI::ListHeaderSegment::Descending) << "\" ";
		fileSave << "/>" << std::endl;
	}


	// Write the footer
	fileSave << "</" << m_DialogConfigurationElement << ">" << std::endl;
	fileSave.close();
	return true;
}

bool DialogConfigurations::isMonitoringAttribute(const std::vector<CEGUI::String>& list, const CEGUI::String& attribute)
{
	std::vector<CEGUI::String>::const_iterator itList;
	for(itList = list.begin(); itList != list.end(); itList++)
	{
		if(!(*itList).compare(attribute))
			return true;
	}
	return false;
}

void DialogConfigurations::elementStart(const CEGUI::String& element, const CEGUI::XMLAttributes& xmlAttributes)
{
	// Performs the actual load every stored dialog
	if (element == m_configurationElementDialog)
    {
		DialogConfig config;
		config.position = m_defaultPosition;
		config.visible  = m_defaultVisible;
		config.rolledup = m_defaultRolledup;
		CEGUI::String name;
		CEGUI::WindowManager& winMgr = CEGUI::WindowManager::getSingleton();

		name = xmlAttributes.getValueAsString(windowNameAttribute);
		CEGUI::Window* window = winMgr.getWindow(name);

		std::vector<CEGUI::String> attributesMonitored;
		std::map<CEGUI::String, std::vector<CEGUI::String>>::iterator itAttributesMonitored;
		itAttributesMonitored = m_attributesMonitoredDialog.find(name);
		if(itAttributesMonitored != m_attributesMonitoredDialog.end())
			attributesMonitored = (*itAttributesMonitored).second; // Dialog has specified attributes
		else
		{
			// Use default attributes
			itAttributesMonitored = m_attributesMonitoredDialog.find("");
			if(itAttributesMonitored != m_attributesMonitoredDialog.end())
				attributesMonitored = (*itAttributesMonitored).second;
		}

		if(xmlAttributes.exists(windowPosAttribute) && isMonitoringAttribute(attributesMonitored, windowPosAttribute))
		{
			config.position	= CEGUI::PropertyHelper::stringToURect(xmlAttributes.getValueAsString(windowPosAttribute));
			window->setWindowArea(config.position);
		}
		if(xmlAttributes.exists(windowVisibleAttribute) && isMonitoringAttribute(attributesMonitored, windowVisibleAttribute))
		{
			config.visible = xmlAttributes.getValueAsBool(windowVisibleAttribute);
			window->setVisible(config.visible);
		}
		if(xmlAttributes.exists(windowRolledupAttribute) && isMonitoringAttribute(attributesMonitored, windowRolledupAttribute))
		{
			config.rolledup	= xmlAttributes.getValueAsBool(windowRolledupAttribute);
			if( winMgr.getWindow(name)->testClassName("FrameWindow") )
			{
				//CEGUI::MultiColumnList* mcl;
				CEGUI::FrameWindow* frameWindow = static_cast<CEGUI::FrameWindow*>(window);
				if(frameWindow->isRolledup() != config.rolledup)
					frameWindow->toggleRollup();
			}
		}

		m_dialogConfigurations[name] = config;
	}
	else if (element == m_configurationElementMultiColumnList)
    {
		MultiColumnListConfig config;
		config.sortedColumn  = m_defaultSortedColumn;
		config.sortAscending = m_defaultSortAscending;
		CEGUI::String name;
		CEGUI::WindowManager& winMgr = CEGUI::WindowManager::getSingleton();

		name = xmlAttributes.getValueAsString(windowNameAttribute);
		CEGUI::MultiColumnList* multiColumnList = static_cast<CEGUI::MultiColumnList*>(winMgr.getWindow(name));

		std::vector<CEGUI::String> attributesMonitored;
		std::map<CEGUI::String, std::vector<CEGUI::String>>::iterator itAttributesMonitored;
		itAttributesMonitored = m_attributesMonitoredMultiColumnList.find(name);
		if(itAttributesMonitored != m_attributesMonitoredMultiColumnList.end())
			attributesMonitored = (*itAttributesMonitored).second; // Dialog has specified attributes
		else
		{
			// Use default attributes
			itAttributesMonitored = m_attributesMonitoredMultiColumnList.find("");
			if(itAttributesMonitored != m_attributesMonitoredMultiColumnList.end())
				attributesMonitored = (*itAttributesMonitored).second;
		}

		if(xmlAttributes.exists(mclColumnSequenceAttribute) && isMonitoringAttribute(attributesMonitored, mclColumnSequenceAttribute))
		{
			CEGUI::String columnSequence = xmlAttributes.getValueAsString(mclColumnSequenceAttribute);
			Tokenize(columnSequence, config.columnSequence, ',');
			for(CEGUI::uint columnIndex = 0; columnIndex < multiColumnList->getColumnCount() && columnIndex < config.columnSequence.size(); ++columnIndex)
			{
				multiColumnList->moveColumn(multiColumnList->getColumnWithID(CEGUI::PropertyHelper::stringToUint(config.columnSequence.at(columnIndex))),
											columnIndex);
			}
		}
		if(xmlAttributes.exists(mclColumnWidthAttribute) && isMonitoringAttribute(attributesMonitored, mclColumnWidthAttribute))
		{
			CEGUI::String columnWidths = xmlAttributes.getValueAsString(mclColumnWidthAttribute);
			Tokenize(columnWidths, config.columnWidths, mclColumnWidthSeparator);
			CEGUI::UDim width;
			for(CEGUI::uint columnIndex = 0; columnIndex < multiColumnList->getColumnCount() && columnIndex < config.columnWidths.size(); ++columnIndex)
			{
				width = CEGUI::PropertyHelper::stringToUDim(config.columnWidths.at(columnIndex));
				multiColumnList->setColumnHeaderWidth(columnIndex, width);
			}
		}
		if(xmlAttributes.exists(mclSortedColumnAttribute) && isMonitoringAttribute(attributesMonitored, mclSortedColumnAttribute))
		{
			config.sortedColumn = xmlAttributes.getValueAsInteger(mclSortedColumnAttribute);
			multiColumnList->setSortColumn( multiColumnList->getColumnWithID(config.sortedColumn) );
		}
		if(xmlAttributes.exists(mclAscendingSortAttribute) && isMonitoringAttribute(attributesMonitored, mclAscendingSortAttribute))
		{
			config.sortAscending = xmlAttributes.getValueAsBool(mclAscendingSortAttribute);
			multiColumnList->setSortDirection( config.sortAscending ? CEGUI::ListHeaderSegment::Ascending
																	: CEGUI::ListHeaderSegment::Descending);
		}

		m_multiColumnListConfigurations[name] = config;
	}
}

void DialogConfigurations::_setDialogAttributesMonitored(const CEGUI::String& dialog, const CEGUI::String& attributesMonitored)
{
	// Validate the attributes to be monitored
	std::vector<CEGUI::String> newAttributes;
	std::vector<CEGUI::String> listAttributesMonitored;
	Tokenize(attributesMonitored, listAttributesMonitored); // Convert attributesMonitored into a vector
	std::vector<CEGUI::String>::iterator itToken;
	for(itToken = listAttributesMonitored.begin(); itToken != listAttributesMonitored.end(); itToken++)
	{
		if(!(*itToken).compare(monitoredAttributeAll))
		{
			newAttributes.push_back(windowPosAttribute);
			newAttributes.push_back(windowVisibleAttribute);
			newAttributes.push_back(windowRolledupAttribute);
		}
		else if(!(*itToken).compare(monitoredAttributeNone))
		{
			newAttributes.clear();
		}
		else if(!(*itToken).compare(windowPosAttribute))
			newAttributes.push_back(windowPosAttribute);
		else if(!(*itToken).compare(windowVisibleAttribute))
			newAttributes.push_back(windowVisibleAttribute);
		else if(!(*itToken).compare(windowRolledupAttribute))
			newAttributes.push_back(windowRolledupAttribute);
		else
		{
			// Attribute is not supported
			assert(false && "Unsupported attribute specified for a dialog");
			CEGUI::Logger::getSingleton().logEvent("The attribute \""
													+ (*itToken)
													+ "\" is unsupported for dialogs.",
													CEGUI::Errors);
		}
	}

	// Store the attributes to be monitored
	m_attributesMonitoredDialog[dialog] = newAttributes;
}

void DialogConfigurations::_setMultiColumnListAttributesMonitored(const CEGUI::String& multiColumnList, const CEGUI::String& attributesMonitored)
{
	// Validate the attributes to be monitored
	std::vector<CEGUI::String> newAttributes;
	std::vector<CEGUI::String> listAttributesMonitored;
	Tokenize(attributesMonitored, listAttributesMonitored); // Convert attributesMonitored into a vector
	std::vector<CEGUI::String>::iterator itToken;
	for(itToken = listAttributesMonitored.begin(); itToken != listAttributesMonitored.end(); itToken++)
	{
		if(!(*itToken).compare(monitoredAttributeAll))
		{
			newAttributes.push_back(mclColumnSequenceAttribute);
			newAttributes.push_back(mclSortedColumnAttribute);
			newAttributes.push_back(mclAscendingSortAttribute);
			newAttributes.push_back(mclColumnWidthAttribute);
		}
		else if(!(*itToken).compare(monitoredAttributeNone))
		{
			newAttributes.clear();
		}
		else if(!(*itToken).compare(mclColumnSequenceAttribute))
			newAttributes.push_back(mclColumnSequenceAttribute);
		else if(!(*itToken).compare(mclSortedColumnAttribute))
			newAttributes.push_back(mclSortedColumnAttribute);
		else if(!(*itToken).compare(mclAscendingSortAttribute))
			newAttributes.push_back(mclAscendingSortAttribute);
		else if(!(*itToken).compare(mclColumnWidthAttribute))
			newAttributes.push_back(mclColumnWidthAttribute);
		else
		{
			// Attribute is not supported
			assert(false && "Unsupported attribute specified for a MultiColumnList");
			CEGUI::Logger::getSingleton().logEvent("The attribute \""
													+ (*itToken)
													+ "\" is unsupported for MultiColumnLists.",
													CEGUI::Errors);
		}
	}

	// Store the attributes to be monitored
	m_attributesMonitoredMultiColumnList[multiColumnList] = newAttributes;
}

DialogConfigurationsDemo.h

#ifndef _DialogConfigurationsDemo_h_
#define _DialogConfigurationsDemo_h_

#include "CEGuiSample.h"
#include "CEGUI.h"
#include "DialogConfigurations.h"

class DemoSample : public CEGuiSample
{
public:
    bool initialiseSample()
	{
		using namespace CEGUI;
		try
		{
			// Retrieve the window manager
			WindowManager& winMgr = WindowManager::getSingleton();

			// Load the TaharezLook scheme and set up the default mouse cursor and font
			SchemeManager::getSingleton().loadScheme("TaharezLookSkin.scheme");
			System::getSingleton().setDefaultMouseCursor("TaharezLook", "MouseArrow");
			FontManager::getSingleton().createFont("Commonwealth-10.font");

			// Set the GUI Sheet
			Window* sheet = winMgr.createWindow("DefaultWindow", "root_wnd");
			System::getSingleton().setGUISheet(sheet);

			// Load a layout
			Window* guiLayout = winMgr.loadWindowLayout("DialogConfigurations.layout");
			sheet->addChildWindow(guiLayout);

			// Configure the toolbar
			winMgr.getWindow("DialogConfigurations/Toolbar/ShowA")->subscribeEvent(PushButton::EventClicked, Event::Subscriber(&DemoSample::showA, this));
			winMgr.getWindow("DialogConfigurations/Toolbar/ShowC")->subscribeEvent(PushButton::EventClicked, Event::Subscriber(&DemoSample::showC, this));
			winMgr.getWindow("DialogConfigurations/Toolbar/ShowD")->subscribeEvent(PushButton::EventClicked, Event::Subscriber(&DemoSample::showD, this));

			// Activate the close buttons
			winMgr.getWindow("DialogConfigurations/Window_A")->subscribeEvent(FrameWindow::EventCloseClicked, Event::Subscriber(&DemoSample::closeA, this));
			winMgr.getWindow("DialogConfigurations/Window_B")->subscribeEvent(FrameWindow::EventCloseClicked, Event::Subscriber(&DemoSample::closeB, this));
			winMgr.getWindow("DialogConfigurations/Window_C")->subscribeEvent(FrameWindow::EventCloseClicked, Event::Subscriber(&DemoSample::closeC, this));
			winMgr.getWindow("DialogConfigurations/Window_D")->subscribeEvent(FrameWindow::EventCloseClicked, Event::Subscriber(&DemoSample::closeD, this));

			// Add columns to the MultiColumnList
			MultiColumnList* multiColumnList = static_cast<MultiColumnList*>(winMgr.getWindow("DialogConfigurations/Window_D/MultiColumnList"));
			multiColumnList->addColumn("Col A", 0, UDim(0.32f, 0));
			multiColumnList->addColumn("Col B", 1, UDim(0.32f, 0));
			multiColumnList->addColumn("Col C", 2, UDim(0.32f, 0));

			// Add rows
			multiColumnList->addRow();
			multiColumnList->setItem(new ListboxTextItem("1", 101), 0, 0); // ColumnID, RowID
			multiColumnList->setItem(new ListboxTextItem("4", 102), 1, 0);
			multiColumnList->setItem(new ListboxTextItem("7", 103), 2, 0);
			multiColumnList->addRow();
			multiColumnList->setItem(new ListboxTextItem("4", 201), 0, 1);
			multiColumnList->setItem(new ListboxTextItem("7", 202), 1, 1);
			multiColumnList->setItem(new ListboxTextItem("1", 203), 2, 1);
			multiColumnList->addRow();
			multiColumnList->setItem(new ListboxTextItem("7", 301), 0, 2);
			multiColumnList->setItem(new ListboxTextItem("1", 302), 1, 2);
			multiColumnList->setItem(new ListboxTextItem("4", 303), 2, 2);


			// Activate dialog configurations
			m_DialogConfigurations.loadConfigurations("DialogConfigurations.xml");
			m_DialogConfigurations.addDialog("DialogConfigurations/Window_A", "Position Visible");
			m_DialogConfigurations.addDialog("DialogConfigurations/Window_B", "Position RolledUp");
			m_DialogConfigurations.addDialog("DialogConfigurations/Window_C", "Visible RolledUp");
			m_DialogConfigurations.addDialog("DialogConfigurations/Window_D"); // Saves every attribute: Position, Visible, and RolledUp
			m_DialogConfigurations.addMultiColumnList("DialogConfigurations/Window_D/MultiColumnList"); // Saves every attribute: ColumnSequence, ColumnWidths, SortedColumn, and AscendingSort
		}
		catch(Exception &e)
		{
			#if defined( __WIN32__ ) || defined( _WIN32 )
				MessageBox(NULL, e.getMessage().c_str(), "Error initializing the demo", MB_OK | MB_ICONERROR | MB_TASKMODAL);
			#else
				std::cerr << "Error initializing the demo:" << e.getMessage().c_str() << "\n";
			#endif
		}

		return true;
	}

    void cleanupSample(void)
	{
		m_DialogConfigurations.saveConfigurations();
	}

	bool showA(const CEGUI::EventArgs& e)
	{
		CEGUI::WindowManager::getSingleton().getWindow("DialogConfigurations/Window_A")->setVisible(true);
		return true;
	}

	bool showC(const CEGUI::EventArgs& e)
	{
		CEGUI::WindowManager::getSingleton().getWindow("DialogConfigurations/Window_C")->setVisible(true);
		return true;
	}

	bool showD(const CEGUI::EventArgs& e)
	{
		CEGUI::WindowManager::getSingleton().getWindow("DialogConfigurations/Window_D")->setVisible(true);
		return true;
	}

	bool closeA(const CEGUI::EventArgs& e)
	{
		CEGUI::WindowManager::getSingleton().getWindow("DialogConfigurations/Window_A")->setVisible(false);
		return true;
	}

	bool closeB(const CEGUI::EventArgs& e)
	{
		CEGUI::WindowManager::getSingleton().getWindow("DialogConfigurations/Window_B")->setVisible(false);
		return true;
	}

	bool closeC(const CEGUI::EventArgs& e)
	{
		CEGUI::WindowManager::getSingleton().getWindow("DialogConfigurations/Window_C")->setVisible(false);
		return true;
	}

	bool closeD(const CEGUI::EventArgs& e)
	{
		CEGUI::WindowManager::getSingleton().getWindow("DialogConfigurations/Window_D")->setVisible(false);
		return true;
	}
private:
	DialogConfigurations m_DialogConfigurations;
};

#endif // _DialogConfigurationsDemo_h_

main.cpp

#if defined( __WIN32__ ) || defined( _WIN32 )
	#define WIN32_LEAN_AND_MEAN
	#define NOMINMAX
	#include "windows.h"
#endif

#include "DialogConfigurationsDemo.h"

#if defined( __WIN32__ ) || defined( _WIN32 )
int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine,int nCmdShow)
#else
int main(int argc, char *argv[])
#endif
{
    DemoSample app;
    return app.run();
}