https://github.com/libsdl-org/Maelstrom/commit/16dc59b09e8078273bed62297999a7cab97ef63e
From 16dc59b09e8078273bed62297999a7cab97ef63e Mon Sep 17 00:00:00 2001
From: Sam Lantinga <[EMAIL REDACTED]>
Date: Thu, 27 Oct 2011 22:08:32 -0400
Subject: [PATCH] Added a UI template system to reduce the amount of duplicated
XML in the UI.
---
UI/about_credits.xml | 37 +-------
UI/about_game.xml | 37 +-------
UI/about_story.xml | 37 +-------
UI/loading.xml | 37 +-------
UI/main.xml | 39 +--------
init.cpp | 1 +
screenlib/Makefile.am | 4 +-
screenlib/SDL_FrameBuf.cpp | 2 +-
screenlib/UIElement.h | 1 +
screenlib/UIManager.cpp | 17 +++-
screenlib/UIManager.h | 6 ++
screenlib/UIPanel.cpp | 15 +++-
screenlib/UIPanel.h | 3 +-
screenlib/UITemplates.cpp | 167 +++++++++++++++++++++++++++++++++++++
screenlib/UITemplates.h | 55 ++++++++++++
15 files changed, 271 insertions(+), 187 deletions(-)
create mode 100644 screenlib/UITemplates.cpp
create mode 100644 screenlib/UITemplates.h
diff --git a/UI/about_credits.xml b/UI/about_credits.xml
index e0eb06f3..8cf624b2 100644
--- a/UI/about_credits.xml
+++ b/UI/about_credits.xml
@@ -1,43 +1,8 @@
-<UIPanel>
+<UIPanel template="FramedPanel">
<Elements>
<Title name="image" id="135">
<Anchor anchorFrom="CENTER" anchorTo="CENTER"/>
</Title>
- <Rectangle>
- <Color r="0x75" g="0x75" b="0xFF"/>
- <Size w="514" h="386"/>
- <Anchor anchorFrom="CENTER" anchorTo="CENTER"/>
- </Rectangle>
- <Rectangle>
- <Color r="0x75" g="0x75" b="0xFF"/>
- <Size w="516" h="388"/>
- <Anchor anchorFrom="CENTER" anchorTo="CENTER"/>
- </Rectangle>
- <Rectangle>
- <Color r="0x9C" g="0x9C" b="0xFF"/>
- <Size w="518" h="390"/>
- <Anchor anchorFrom="CENTER" anchorTo="CENTER"/>
- </Rectangle>
- <Rectangle>
- <Color r="0x9C" g="0x9C" b="0xFF"/>
- <Size w="520" h="392"/>
- <Anchor anchorFrom="CENTER" anchorTo="CENTER"/>
- </Rectangle>
- <Rectangle>
- <Color r="0xC3" g="0xC3" b="0xFF"/>
- <Size w="522" h="394"/>
- <Anchor anchorFrom="CENTER" anchorTo="CENTER"/>
- </Rectangle>
- <Rectangle>
- <Color r="0x9C" g="0x9C" b="0xFF"/>
- <Size w="524" h="396"/>
- <Anchor anchorFrom="CENTER" anchorTo="CENTER"/>
- </Rectangle>
- <Rectangle>
- <Color r="0x75" g="0x75" b="0xFF"/>
- <Size w="526" h="398"/>
- <Anchor anchorFrom="CENTER" anchorTo="CENTER"/>
- </Rectangle>
<!-- Porting credits -->
<Rectangle fill="true">
diff --git a/UI/about_game.xml b/UI/about_game.xml
index 71d74682..249ae89c 100644
--- a/UI/about_game.xml
+++ b/UI/about_game.xml
@@ -1,43 +1,8 @@
-<UIPanel delegate="AboutPanel">
+<UIPanel template="FramedPanel" delegate="AboutPanel">
<Elements>
<Title name="image" id="134">
<Anchor anchorFrom="CENTER" anchorTo="CENTER"/>
</Title>
- <Rectangle>
- <Color r="0x75" g="0x75" b="0xFF"/>
- <Size w="514" h="386"/>
- <Anchor anchorFrom="CENTER" anchorTo="CENTER"/>
- </Rectangle>
- <Rectangle>
- <Color r="0x75" g="0x75" b="0xFF"/>
- <Size w="516" h="388"/>
- <Anchor anchorFrom="CENTER" anchorTo="CENTER"/>
- </Rectangle>
- <Rectangle>
- <Color r="0x9C" g="0x9C" b="0xFF"/>
- <Size w="518" h="390"/>
- <Anchor anchorFrom="CENTER" anchorTo="CENTER"/>
- </Rectangle>
- <Rectangle>
- <Color r="0x9C" g="0x9C" b="0xFF"/>
- <Size w="520" h="392"/>
- <Anchor anchorFrom="CENTER" anchorTo="CENTER"/>
- </Rectangle>
- <Rectangle>
- <Color r="0xC3" g="0xC3" b="0xFF"/>
- <Size w="522" h="394"/>
- <Anchor anchorFrom="CENTER" anchorTo="CENTER"/>
- </Rectangle>
- <Rectangle>
- <Color r="0x9C" g="0x9C" b="0xFF"/>
- <Size w="524" h="396"/>
- <Anchor anchorFrom="CENTER" anchorTo="CENTER"/>
- </Rectangle>
- <Rectangle>
- <Color r="0x75" g="0x75" b="0xFF"/>
- <Size w="526" h="398"/>
- <Anchor anchorFrom="CENTER" anchorTo="CENTER"/>
- </Rectangle>
<!-- Shield icon -->
<Icon id="137">
diff --git a/UI/about_story.xml b/UI/about_story.xml
index 7b7c59a0..e6ef9ea0 100644
--- a/UI/about_story.xml
+++ b/UI/about_story.xml
@@ -1,43 +1,8 @@
-<UIPanel>
+<UIPanel template="FramedPanel">
<Elements>
<Title name="image" id="133">
<Anchor anchorFrom="CENTER" anchorTo="CENTER"/>
</Title>
- <Rectangle>
- <Color r="0x75" g="0x75" b="0xFF"/>
- <Size w="514" h="386"/>
- <Anchor anchorFrom="CENTER" anchorTo="CENTER"/>
- </Rectangle>
- <Rectangle>
- <Color r="0x75" g="0x75" b="0xFF"/>
- <Size w="516" h="388"/>
- <Anchor anchorFrom="CENTER" anchorTo="CENTER"/>
- </Rectangle>
- <Rectangle>
- <Color r="0x9C" g="0x9C" b="0xFF"/>
- <Size w="518" h="390"/>
- <Anchor anchorFrom="CENTER" anchorTo="CENTER"/>
- </Rectangle>
- <Rectangle>
- <Color r="0x9C" g="0x9C" b="0xFF"/>
- <Size w="520" h="392"/>
- <Anchor anchorFrom="CENTER" anchorTo="CENTER"/>
- </Rectangle>
- <Rectangle>
- <Color r="0xC3" g="0xC3" b="0xFF"/>
- <Size w="522" h="394"/>
- <Anchor anchorFrom="CENTER" anchorTo="CENTER"/>
- </Rectangle>
- <Rectangle>
- <Color r="0x9C" g="0x9C" b="0xFF"/>
- <Size w="524" h="396"/>
- <Anchor anchorFrom="CENTER" anchorTo="CENTER"/>
- </Rectangle>
- <Rectangle>
- <Color r="0x75" g="0x75" b="0xFF"/>
- <Size w="526" h="398"/>
- <Anchor anchorFrom="CENTER" anchorTo="CENTER"/>
- </Rectangle>
<!-- Buttons -->
<Button hotkey="any" clickPanel="main" clickSound="106"/>
diff --git a/UI/loading.xml b/UI/loading.xml
index 902f5c77..f5e46d4a 100644
--- a/UI/loading.xml
+++ b/UI/loading.xml
@@ -1,43 +1,8 @@
-<UIPanel enterSound="111" leaveSound="123">
+<UIPanel template="FramedPanel" enterSound="111" leaveSound="123">
<Elements>
<Title name="image" id="130">
<Anchor anchorFrom="CENTER" anchorTo="CENTER"/>
</Title>
- <Rectangle>
- <Color r="0x75" g="0x75" b="0xFF"/>
- <Size w="514" h="386"/>
- <Anchor anchorFrom="CENTER" anchorTo="CENTER"/>
- </Rectangle>
- <Rectangle>
- <Color r="0x75" g="0x75" b="0xFF"/>
- <Size w="516" h="388"/>
- <Anchor anchorFrom="CENTER" anchorTo="CENTER"/>
- </Rectangle>
- <Rectangle>
- <Color r="0x9C" g="0x9C" b="0xFF"/>
- <Size w="518" h="390"/>
- <Anchor anchorFrom="CENTER" anchorTo="CENTER"/>
- </Rectangle>
- <Rectangle>
- <Color r="0x9C" g="0x9C" b="0xFF"/>
- <Size w="520" h="392"/>
- <Anchor anchorFrom="CENTER" anchorTo="CENTER"/>
- </Rectangle>
- <Rectangle>
- <Color r="0xC3" g="0xC3" b="0xFF"/>
- <Size w="522" h="394"/>
- <Anchor anchorFrom="CENTER" anchorTo="CENTER"/>
- </Rectangle>
- <Rectangle>
- <Color r="0x9C" g="0x9C" b="0xFF"/>
- <Size w="524" h="396"/>
- <Anchor anchorFrom="CENTER" anchorTo="CENTER"/>
- </Rectangle>
- <Rectangle>
- <Color r="0x75" g="0x75" b="0xFF"/>
- <Size w="526" h="398"/>
- <Anchor anchorFrom="CENTER" anchorTo="CENTER"/>
- </Rectangle>
<Label fontName="Geneva" fontSize="9" fontStyle="BOLD" text="Loading...">
<Color r="0xFF" g="0xFF" b="0x00"/>
<Anchor anchorFrom="CENTER" anchorTo="BOTTOM" anchor="image" y="20"/>
diff --git a/UI/main.xml b/UI/main.xml
index 6500104d..94f5a28e 100644
--- a/UI/main.xml
+++ b/UI/main.xml
@@ -1,4 +1,4 @@
-<UIPanel delegate="MainPanel">
+<UIPanel template="FramedPanel" delegate="MainPanel">
<Elements>
<Title name="image" id="129">
<Anchor anchorFrom="TOPLEFT" anchorTo="CENTER" x="-251" y="-187"/>
@@ -7,43 +7,6 @@
<!-- Catch-all button to bonk when a key is pressed -->
<Button hotkey="any" clickSound="108"/>
- <!-- screen frame -->
- <Rectangle>
- <Color r="0x75" g="0x75" b="0xFF"/>
- <Size w="514" h="386"/>
- <Anchor anchorFrom="CENTER" anchorTo="CENTER"/>
- </Rectangle>
- <Rectangle>
- <Color r="0x75" g="0x75" b="0xFF"/>
- <Size w="516" h="388"/>
- <Anchor anchorFrom="CENTER" anchorTo="CENTER"/>
- </Rectangle>
- <Rectangle>
- <Color r="0x9C" g="0x9C" b="0xFF"/>
- <Size w="518" h="390"/>
- <Anchor anchorFrom="CENTER" anchorTo="CENTER"/>
- </Rectangle>
- <Rectangle>
- <Color r="0x9C" g="0x9C" b="0xFF"/>
- <Size w="520" h="392"/>
- <Anchor anchorFrom="CENTER" anchorTo="CENTER"/>
- </Rectangle>
- <Rectangle>
- <Color r="0xC3" g="0xC3" b="0xFF"/>
- <Size w="522" h="394"/>
- <Anchor anchorFrom="CENTER" anchorTo="CENTER"/>
- </Rectangle>
- <Rectangle>
- <Color r="0x9C" g="0x9C" b="0xFF"/>
- <Size w="524" h="396"/>
- <Anchor anchorFrom="CENTER" anchorTo="CENTER"/>
- </Rectangle>
- <Rectangle>
- <Color r="0x75" g="0x75" b="0xFF"/>
- <Size w="526" h="398"/>
- <Anchor anchorFrom="CENTER" anchorTo="CENTER"/>
- </Rectangle>
-
<!-- dividers -->
<Line name="vertical_divider">
<Color r="0x9C" g="0x9C" b="0xFF"/>
diff --git a/init.cpp b/init.cpp
index f92abb98..cc70ce2a 100644
--- a/init.cpp
+++ b/init.cpp
@@ -730,6 +730,7 @@ int DoInitializations(Uint32 window_flags, Uint32 render_flags)
ui = new UIManager(screen, CreateMaelstromUIPanel, CreateMaelstromUIElement);
ui->SetSoundCallback(PlayUISound, NULL);
ui->SetLoadPath("UI");
+ ui->LoadTemplates("UITemplates.xml");
/* Load the Sound Server and initialize sound */
sound = new Sound("Maelstrom Sounds", gSoundLevel);
diff --git a/screenlib/Makefile.am b/screenlib/Makefile.am
index 61028b82..3eb44741 100644
--- a/screenlib/Makefile.am
+++ b/screenlib/Makefile.am
@@ -20,4 +20,6 @@ libSDLscreen_a_SOURCES = \
UIManager.cpp \
UIManager.h \
UIPanel.cpp \
- UIPanel.h
+ UIPanel.h \
+ UITemplates.cpp \
+ UITemplates.h
diff --git a/screenlib/SDL_FrameBuf.cpp b/screenlib/SDL_FrameBuf.cpp
index a190e6c9..9e6f1b05 100644
--- a/screenlib/SDL_FrameBuf.cpp
+++ b/screenlib/SDL_FrameBuf.cpp
@@ -131,7 +131,7 @@ void
FrameBuf:: Fade(void)
{
// Temporary for development
-//return;
+return;
const int max = 32;
Uint16 ramp[256];
diff --git a/screenlib/UIElement.h b/screenlib/UIElement.h
index 6e1a8672..9c2a2bb0 100644
--- a/screenlib/UIElement.h
+++ b/screenlib/UIElement.h
@@ -50,6 +50,7 @@ class UIElement : public UIArea
}
virtual bool Load(rapidxml::xml_node<> *node);
+ virtual bool FinishLoading() { return true; }
virtual UIArea *GetAnchorElement(const char *name);
diff --git a/screenlib/UIManager.cpp b/screenlib/UIManager.cpp
index 500105d4..c2a35f46 100644
--- a/screenlib/UIManager.cpp
+++ b/screenlib/UIManager.cpp
@@ -43,6 +43,7 @@ UIManager::~UIManager()
while (m_panels.length() > 0) {
delete m_panels[m_panels.length()-1];
}
+ delete[] m_loadPath;
}
void
@@ -53,6 +54,15 @@ UIManager::SetLoadPath(const char *path)
strcpy(m_loadPath, path);
}
+bool
+UIManager::LoadTemplates(const char *file)
+{
+ char path[1024];
+
+ sprintf(path, "%s/%s", m_loadPath, file);
+ return m_templates.Load(path);
+}
+
static const char *GetLine(char *&text)
{
while (*text == '\r' || *text == '\n') {
@@ -128,7 +138,12 @@ UIManager::LoadPanel(const char *name)
attr = node->first_attribute("delegate", 0, false);
panel = (GetPanelFactory())(this, node->name(), name, attr ? attr->value() : NULL);
if (panel) {
- if (!panel->Load(node)) {
+ rapidxml::xml_node<> *templateNode;
+
+ templateNode = GetTemplateFor(node);
+ if ((templateNode && !panel->Load(templateNode)) ||
+ !panel->Load(node) ||
+ !panel->FinishLoading()) {
fprintf(stderr, "Warning: Couldn't load %s: %s\n",
file, panel->Error());
delete[] buffer;
diff --git a/screenlib/UIManager.h b/screenlib/UIManager.h
index ff28c601..d891a389 100644
--- a/screenlib/UIManager.h
+++ b/screenlib/UIManager.h
@@ -26,6 +26,7 @@
#include "SDL.h"
#include "../utils/array.h"
#include "UIArea.h"
+#include "UITemplates.h"
class FrameBuf;
class UIManager;
@@ -51,8 +52,12 @@ class UIManager : public UIArea
UIElementFactory GetElementFactory() const {
return m_elementFactory;
}
+ rapidxml::xml_node<> *GetTemplateFor(rapidxml::xml_node<> *node) const {
+ return m_templates.GetTemplateFor(node);
+ }
void SetLoadPath(const char *path);
+ bool LoadTemplates(const char *file);
UIPanel *LoadPanel(const char *name);
UIPanel *GetPanel(const char *name, bool allowLoad = true);
UIPanel *GetCurrentPanel();
@@ -100,6 +105,7 @@ class UIManager : public UIArea
UISoundCallback m_soundCallback;
void *m_soundCallbackParam;
char *m_loadPath;
+ UITemplates m_templates;
array<UIPanel *> m_panels;
array<UIPanel *> m_visible;
};
diff --git a/screenlib/UIPanel.cpp b/screenlib/UIPanel.cpp
index 9136f00c..09a27bab 100644
--- a/screenlib/UIPanel.cpp
+++ b/screenlib/UIPanel.cpp
@@ -96,6 +96,12 @@ UIPanel::Load(rapidxml::xml_node<> *node)
}
}
+ return true;
+}
+
+bool
+UIPanel::FinishLoading()
+{
if (m_delegate) {
return m_delegate->OnLoad();
} else {
@@ -106,12 +112,19 @@ UIPanel::Load(rapidxml::xml_node<> *node)
bool
UIPanel::LoadElements(rapidxml::xml_node<> *node)
{
+ rapidxml::xml_node<> *templateNode;
+
for (node = node->first_node(); node; node = node->next_sibling()) {
UIElement *element = (m_ui->GetElementFactory())(this, node->name());
if (!element) {
fprintf(stderr, "Warning: Couldn't find handler for element %s\n", node->name());
}
- if (!element->Load(node)) {
+
+
+ templateNode = m_ui->GetTemplateFor(node);
+ if ((templateNode && !element->Load(templateNode)) ||
+ !element->Load(node) ||
+ !element->FinishLoading()) {
fprintf(stderr, "Warning: Couldn't load element %s: %s\n", node->name(), element->Error());
delete element;
}
diff --git a/screenlib/UIPanel.h b/screenlib/UIPanel.h
index 301ad18f..b060456b 100644
--- a/screenlib/UIPanel.h
+++ b/screenlib/UIPanel.h
@@ -69,7 +69,8 @@ class UIPanel : public UIArea
return m_cursorVisible;
}
- bool Load(rapidxml::xml_node<> *node);
+ virtual bool Load(rapidxml::xml_node<> *node);
+ virtual bool FinishLoading();
virtual UIArea *GetAnchorElement(const char *name);
diff --git a/screenlib/UITemplates.cpp b/screenlib/UITemplates.cpp
new file mode 100644
index 00000000..de6226a2
--- /dev/null
+++ b/screenlib/UITemplates.cpp
@@ -0,0 +1,167 @@
+/*
+ SCREENLIB: A framebuffer library based on the SDL library
+ Copyright (C) 1997 Sam Lantinga
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+ Sam Lantinga
+ slouken@libsdl.org
+*/
+
+#include <stdio.h>
+#include <strings.h>
+#include <physfs.h>
+
+#include "UITemplates.h"
+
+
+UITemplates::UITemplates()
+{
+ m_data = NULL;
+ m_hashTable = NULL;
+}
+
+UITemplates::~UITemplates()
+{
+ if (m_hashTable) {
+ hash_destroy(m_hashTable);
+ }
+ if (m_data) {
+ delete[] m_data;
+ }
+}
+
+bool
+UITemplates::Load(const char *file)
+{
+ PHYSFS_File *fp;
+ PHYSFS_sint64 size;
+ rapidxml::xml_node<> *node;
+ rapidxml::xml_attribute<> *attr;
+
+ fp = PHYSFS_openRead(file);
+ if (!fp) {
+ fprintf(stderr, "Warning: Couldn't open %s: %s\n",
+ file, PHYSFS_getLastError());
+ return false;
+ }
+
+ size = PHYSFS_fileLength(fp);
+ m_data = new char[size+1];
+ if (PHYSFS_readBytes(fp, m_data, size) != size) {
+ fprintf(stderr, "Warning: Couldn't read from %s: %s\n",
+ file, PHYSFS_getLastError());
+ PHYSFS_close(fp);
+ delete[] m_data;
+ m_data = NULL;
+ return false;
+ }
+ m_data[size] = '\0';
+ PHYSFS_close(fp);
+
+ try {
+ m_doc.parse<0>(m_data);
+ } catch (rapidxml::parse_error e) {
+ fprintf(stderr, "Warning: Couldn't parse %s: error: %s\n",
+ file, e.what());
+ delete[] m_data;
+ m_data = NULL;
+ return false;
+ }
+
+
+ m_hashTable = hash_create(NULL, HashTable_Hash,
+ HashTable_KeyMatch,
+ HashTable_Nuke);
+
+ node = m_doc.first_node();
+ for (node = node->first_node(); node; node = node->next_sibling()) {
+ attr = node->first_attribute("templateName", 0, false);
+ if (attr) {
+ HashKey *key = new HashKey;
+ key->type = node->name();
+ key->name = attr->value();
+ hash_insert(m_hashTable, key, node);
+ } else {
+ fprintf(stderr, "Warning: UITemplate %s missing 'templateName'\n", node->name());
+ }
+ }
+ return true;
+}
+
+rapidxml::xml_node<> *
+UITemplates::GetTemplateFor(rapidxml::xml_node<> *node) const
+{
+ rapidxml::xml_attribute<> *attr;
+
+ attr = node->first_attribute("template", 0, false);
+ if (!attr) {
+ return NULL;
+ }
+ return GetTemplate(node->name(), attr->value());
+}
+
+rapidxml::xml_node<> *
+UITemplates::GetTemplate(const char *type, const char *name) const
+{
+ HashKey key;
+ rapidxml::xml_node<> *templateNode;
+
+ if (!m_hashTable) {
+ return NULL;
+ }
+
+ key.type = type;
+ key.name = name;
+ if (hash_find(m_hashTable, &key, (const void **)&templateNode)) {
+ return templateNode;
+ }
+ return NULL;
+}
+
+// this is djb's xor hashing function.
+unsigned
+UITemplates::HashTable_Hash(const void *_key, void *data)
+{
+ const HashKey *key = static_cast<const HashKey *>(_key);
+ const char *p;
+ register unsigned hash = 5381;
+
+ p = key->type;
+ while (*p) {
+ hash = ((hash << 5) + hash) ^ *(p++);
+ }
+ p = key->name;
+ while (*p) {
+ hash = ((hash << 5) + hash) ^ *(p++);
+ }
+ return hash;
+}
+
+int
+UITemplates::HashTable_KeyMatch(const void *_a, const void *_b, void *data)
+{
+ const HashKey *a = static_cast<const HashKey *>(_a);
+ const HashKey *b = static_cast<const HashKey *>(_a);
+
+ return strcmp(a->type, b->type) == 0 && strcmp(a->name, b->name) == 0;
+}
+
+void
+UITemplates::HashTable_Nuke(const void *_key, const void *value, void *data)
+{
+ HashKey *key = (HashKey *)_key;
+ delete key;
+}
diff --git a/screenlib/UITemplates.h b/screenlib/UITemplates.h
new file mode 100644
index 00000000..6e251ba2
--- /dev/null
+++ b/screenlib/UITemplates.h
@@ -0,0 +1,55 @@
+/*
+ SCREENLIB: A framebuffer library based on the SDL library
+ Copyright (C) 1997 Sam Lantinga
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+ Sam Lantinga
+ slouken@libsdl.org
+*/
+
+#ifndef _UITemplates_h
+#define _UITemplates_h
+
+#include "../utils/hashtable.h"
+#include "../utils/rapidxml.h"
+
+class UITemplates
+{
+public:
+ UITemplates();
+ ~UITemplates();
+
+ bool Load(const char *file);
+
+ rapidxml::xml_node<> *GetTemplateFor(rapidxml::xml_node<> *node) const;
+ rapidxml::xml_node<> *GetTemplate(const char *type, const char *name) const;
+
+protected:
+ char *m_data;
+ rapidxml::xml_document<> m_doc;
+ struct HashKey {
+ const char *type;
+ const char *name;
+ };
+ HashTable *m_hashTable;
+
+protected:
+ static unsigned HashTable_Hash(const void *key, void *data);
+ static int HashTable_KeyMatch(const void *a, const void *b, void *data);
+ static void HashTable_Nuke(const void *key, const void *value, void *data);
+};
+
+#endif // _UITemplates_h