Maelstrom: The UI system has been refactored so that elements can have elements as children.

https://github.com/libsdl-org/Maelstrom/commit/a24dcf58d06dfbec049d4ba33e87420ad3e4f01a

From a24dcf58d06dfbec049d4ba33e87420ad3e4f01a Mon Sep 17 00:00:00 2001
From: Sam Lantinga <[EMAIL REDACTED]>
Date: Fri, 28 Oct 2011 21:50:39 -0400
Subject: [PATCH] The UI system has been refactored so that elements can have
 elements as children.

---
 MaelstromUI.cpp                |  16 ++--
 MaelstromUI.h                  |   2 +-
 UIDialogLabel.cpp              |   4 +-
 UIDialogLabel.h                |   2 +-
 UIElementIcon.cpp              |   4 +-
 UIElementIcon.h                |   2 +-
 UIElementKeyButton.cpp         |   4 +-
 UIElementKeyButton.h           |   2 +-
 UIElementSprite.cpp            |   4 +-
 UIElementSprite.h              |   2 +-
 UIElementTitle.cpp             |   4 +-
 UIElementTitle.h               |   2 +-
 netlogic/game.cpp              |   6 --
 screenlib/Makefile.am          |   2 +
 screenlib/UIBaseElement.cpp    | 143 +++++++++++++++++++++++++++++++++
 screenlib/UIBaseElement.h      | 117 +++++++++++++++++++++++++++
 screenlib/UIElement.cpp        |  58 ++++---------
 screenlib/UIElement.h          |  39 ++-------
 screenlib/UIElementButton.cpp  |   8 +-
 screenlib/UIElementButton.h    |   2 +-
 screenlib/UIElementLabel.cpp   |  14 ++--
 screenlib/UIElementLabel.h     |  24 +++++-
 screenlib/UIElementLine.cpp    |   4 +-
 screenlib/UIElementLine.h      |  24 +++++-
 screenlib/UIElementRect.cpp    |   4 +-
 screenlib/UIElementRect.h      |  24 +++++-
 screenlib/UIElementTexture.cpp |   4 +-
 screenlib/UIElementTexture.h   |  24 +++++-
 screenlib/UIManager.cpp        |   8 +-
 screenlib/UIManager.h          |   3 +-
 screenlib/UIPanel.cpp          |  92 +++------------------
 screenlib/UIPanel.h            |  38 +--------
 32 files changed, 437 insertions(+), 249 deletions(-)
 create mode 100644 screenlib/UIBaseElement.cpp
 create mode 100644 screenlib/UIBaseElement.h

diff --git a/MaelstromUI.cpp b/MaelstromUI.cpp
index 0afbc831..c8586a0f 100644
--- a/MaelstromUI.cpp
+++ b/MaelstromUI.cpp
@@ -155,20 +155,20 @@ MaelstromUI::CreatePanelDelegate(UIPanel *panel, const char *delegate)
 }
 
 UIElement *
-MaelstromUI::CreateElement(UIPanel *panel, const char *type)
+MaelstromUI::CreateElement(UIBaseElement *parent, const char *type)
 {
 	if (strcasecmp(type, "Label") == 0) {
-		return new UIElementLabel(panel);
+		return new UIElementLabel(parent);
 	} else if (strcasecmp(type, "DialogLabel") == 0) {
-		return new UIDialogLabel(panel);
+		return new UIDialogLabel(parent);
 	} else if (strcasecmp(type, "KeyButton") == 0) {
-		return new UIElementKeyButton(panel);
+		return new UIElementKeyButton(parent);
 	} else if (strcasecmp(type, "Icon") == 0) {
-		return new UIElementIcon(panel);
+		return new UIElementIcon(parent);
 	} else if (strcasecmp(type, "Sprite") == 0) {
-		return new UIElementSprite(panel);
+		return new UIElementSprite(parent);
 	} else if (strcasecmp(type, "Title") == 0) {
-		return new UIElementTitle(panel);
+		return new UIElementTitle(parent);
 	}
-	return UIManager::CreateElement(panel, type);;
+	return UIManager::CreateElement(parent, type);;
 }
diff --git a/MaelstromUI.h b/MaelstromUI.h
index 401e6947..68562299 100644
--- a/MaelstromUI.h
+++ b/MaelstromUI.h
@@ -25,7 +25,7 @@ class MaelstromUI : public UIManager
 	//
 	virtual UIPanel *CreatePanel(const char *type, const char *name);
 	virtual UIPanelDelegate *CreatePanelDelegate(UIPanel *panel, const char *delegate);
-	virtual UIElement *CreateElement(UIPanel *panel, const char *type);
+	virtual UIElement *CreateElement(UIBaseElement *parent, const char *type);
 
 protected:
 	HashTable *m_fonts;
diff --git a/UIDialogLabel.cpp b/UIDialogLabel.cpp
index 5e53b14c..75867aae 100644
--- a/UIDialogLabel.cpp
+++ b/UIDialogLabel.cpp
@@ -5,8 +5,8 @@
 UIElementType UIDialogLabel::s_elementType;
 
 
-UIDialogLabel::UIDialogLabel(UIPanel *panel, const char *name) :
-	UIElementLabel(panel, name)
+UIDialogLabel::UIDialogLabel(UIBaseElement *parent, const char *name) :
+	UIElementLabel(parent, name)
 {
 	m_fontName = SDL_strdup("Chicago");
 	m_fontSize = 12;
diff --git a/UIDialogLabel.h b/UIDialogLabel.h
index 3f0ba8dd..eba42599 100644
--- a/UIDialogLabel.h
+++ b/UIDialogLabel.h
@@ -6,7 +6,7 @@
 class UIDialogLabel : public UIElementLabel
 {
 public:
-	UIDialogLabel(UIPanel *panel, const char *name = "");
+	UIDialogLabel(UIBaseElement *parent, const char *name = "");
 
 	virtual bool IsA(UIElementType type) {
 		return UIElementLabel::IsA(type) || type == GetType();
diff --git a/UIElementIcon.cpp b/UIElementIcon.cpp
index be2f5e28..ebc38ac3 100644
--- a/UIElementIcon.cpp
+++ b/UIElementIcon.cpp
@@ -5,8 +5,8 @@
 UIElementType UIElementIcon::s_elementType;
 
 
-UIElementIcon::UIElementIcon(UIPanel *panel, const char *name) :
-	UIElementTexture(panel, name)
+UIElementIcon::UIElementIcon(UIBaseElement *parent, const char *name) :
+	UIElementTexture(parent, name)
 {
 }
 
diff --git a/UIElementIcon.h b/UIElementIcon.h
index 21850e30..44bc34c3 100644
--- a/UIElementIcon.h
+++ b/UIElementIcon.h
@@ -7,7 +7,7 @@
 class UIElementIcon : public UIElementTexture
 {
 public:
-	UIElementIcon(UIPanel *panel, const char *name = "");
+	UIElementIcon(UIBaseElement *parent, const char *name = "");
 
 	virtual bool IsA(UIElementType type) {
 		return UIElementTexture::IsA(type) || type == GetType();
diff --git a/UIElementKeyButton.cpp b/UIElementKeyButton.cpp
index 7bb5bd47..4724135d 100644
--- a/UIElementKeyButton.cpp
+++ b/UIElementKeyButton.cpp
@@ -4,8 +4,8 @@
 
 UIElementType UIElementKeyButton::s_elementType;
 
-UIElementKeyButton::UIElementKeyButton(UIPanel *panel, const char *name) :
-	UIElementButton(panel, name)
+UIElementKeyButton::UIElementKeyButton(UIBaseElement *parent, const char *name) :
+	UIElementButton(parent, name)
 {
 	m_text = NULL;
 	m_textShadow = NULL;
diff --git a/UIElementKeyButton.h b/UIElementKeyButton.h
index 1871f6fd..3b867362 100644
--- a/UIElementKeyButton.h
+++ b/UIElementKeyButton.h
@@ -7,7 +7,7 @@
 class UIElementKeyButton : public UIElementButton
 {
 public:
-	UIElementKeyButton(UIPanel *panel, const char *name = "");
+	UIElementKeyButton(UIBaseElement *parent, const char *name = "");
 	virtual ~UIElementKeyButton();
 
 	virtual bool IsA(UIElementType type) {
diff --git a/UIElementSprite.cpp b/UIElementSprite.cpp
index 42ea147c..0c15b9f8 100644
--- a/UIElementSprite.cpp
+++ b/UIElementSprite.cpp
@@ -5,8 +5,8 @@
 UIElementType UIElementSprite::s_elementType;
 
 
-UIElementSprite::UIElementSprite(UIPanel *panel, const char *name) :
-	UIElementTexture(panel, name)
+UIElementSprite::UIElementSprite(UIBaseElement *parent, const char *name) :
+	UIElementTexture(parent, name)
 {
 }
 
diff --git a/UIElementSprite.h b/UIElementSprite.h
index ea658916..f158c05d 100644
--- a/UIElementSprite.h
+++ b/UIElementSprite.h
@@ -7,7 +7,7 @@
 class UIElementSprite : public UIElementTexture
 {
 public:
-	UIElementSprite(UIPanel *panel, const char *name = "");
+	UIElementSprite(UIBaseElement *parent, const char *name = "");
 
 	virtual bool IsA(UIElementType type) {
 		return UIElementTexture::IsA(type) || type == GetType();
diff --git a/UIElementTitle.cpp b/UIElementTitle.cpp
index a6f185fc..0f15c95a 100644
--- a/UIElementTitle.cpp
+++ b/UIElementTitle.cpp
@@ -5,8 +5,8 @@
 UIElementType UIElementTitle::s_elementType;
 
 
-UIElementTitle::UIElementTitle(UIPanel *panel, const char *name) :
-	UIElementTexture(panel, name)
+UIElementTitle::UIElementTitle(UIBaseElement *parent, const char *name) :
+	UIElementTexture(parent, name)
 {
 }
 
diff --git a/UIElementTitle.h b/UIElementTitle.h
index dbd80a7a..7cb95e7f 100644
--- a/UIElementTitle.h
+++ b/UIElementTitle.h
@@ -7,7 +7,7 @@
 class UIElementTitle : public UIElementTexture
 {
 public:
-	UIElementTitle(UIPanel *panel, const char *name = "");
+	UIElementTitle(UIBaseElement *parent, const char *name = "");
 
 	virtual bool IsA(UIElementType type) {
 		return UIElementTexture::IsA(type) || type == GetType();
diff --git a/netlogic/game.cpp b/netlogic/game.cpp
index 6d338dcf..6ff1e1f6 100644
--- a/netlogic/game.cpp
+++ b/netlogic/game.cpp
@@ -117,9 +117,6 @@ int	gFreezeTime;
 Object *gEnemySprite;
 int	gWhenEnemy;
 
-// Local global variables;
-static MFont *geneva;
-
 // Local functions used in the game module of Maelstrom
 static void DoGameOver(void);
 static void DoBonus(void);
@@ -176,9 +173,6 @@ GamePanelDelegate::OnLoad()
 	int i;
 	char name[32];
 
-	/* Load the font and colors we use everywhere */
-	geneva = fonts[GENEVA_9];
-
 	m_showingBonus = false;
 
 	/* Initialize our panel variables */
diff --git a/screenlib/Makefile.am b/screenlib/Makefile.am
index adb6dfb9..2d8f79d9 100644
--- a/screenlib/Makefile.am
+++ b/screenlib/Makefile.am
@@ -7,6 +7,8 @@ libSDLscreen_a_SOURCES =	\
 	SDL_FrameBuf.h		\
 	UIArea.cpp		\
 	UIArea.h		\
+	UIBaseElement.cpp	\
+	UIBaseElement.h		\
 	UIElement.cpp		\
 	UIElement.h		\
 	UIElementButton.cpp	\
diff --git a/screenlib/UIBaseElement.cpp b/screenlib/UIBaseElement.cpp
new file mode 100644
index 00000000..363bea0f
--- /dev/null
+++ b/screenlib/UIBaseElement.cpp
@@ -0,0 +1,143 @@
+/*
+    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 "SDL.h"
+#include "UIBaseElement.h"
+#include "UIManager.h"
+#include "UIElement.h"
+#include "UITemplates.h"
+
+
+UIElementType UIBaseElement::s_elementTypeIndex;
+UIElementType UIBaseElement::s_elementType;
+
+
+UIBaseElement::UIBaseElement(UIManager *ui, const char *name) :
+	UIArea(ui->GetScreen())
+{
+	m_ui = ui;
+	m_parent = NULL;
+	m_name = SDL_strdup(name);
+}
+
+UIBaseElement::UIBaseElement(UIBaseElement *parent, const char *name) :
+	UIArea(parent->GetScreen())
+{
+	m_ui = parent->GetUI();
+	m_parent = parent;
+	m_name = SDL_strdup(name);
+}
+
+UIBaseElement::~UIBaseElement()
+{
+	SDL_free(m_name);
+
+	for (unsigned i = 0; i < m_elements.length(); ++i) {
+		delete m_elements[i];
+	}
+}
+
+bool
+UIBaseElement::Load(rapidxml::xml_node<> *node, const UITemplates *templates)
+{
+	rapidxml::xml_node<> *child;
+
+	child = templates->GetTemplateFor(node);
+	if (child) {
+		if (!Load(child, templates)) {
+			return false;
+		}
+	}
+
+	if (!UIArea::Load(node)) {
+		return false;
+	}
+
+	child = node->first_node("elements", 0, false);
+	if (child) {
+		if (!LoadElements(child, templates)) {
+			return false;
+		}
+	}
+
+	return true;
+}
+
+void
+UIBaseElement::Draw()
+{
+	for (unsigned i = 0; i < m_elements.length(); ++i) {
+		if (m_elements[i]->IsShown()) {
+			m_elements[i]->Draw();
+		}
+	}
+}
+
+bool
+UIBaseElement::HandleEvent(const SDL_Event &event)
+{
+	for (unsigned i = m_elements.length(); i--; ) {
+		if (m_elements[i]->HandleEvent(event)) {
+			return true;
+		}
+	}
+	return false;
+}
+
+UIBaseElement *
+UIBaseElement::GetElement(const char *name)
+{
+	for (unsigned i = 0; i < m_elements.length(); ++i) {
+		if (strcmp(name, m_elements[i]->GetName()) == 0) {
+			return m_elements[i];
+		}
+	}
+	return NULL;
+}
+
+UIBaseElement *
+UIBaseElement::CreateElement(const char *name)
+{
+	return GetUI()->CreateElement(this, name);
+}
+
+
+bool
+UIBaseElement::LoadElements(rapidxml::xml_node<> *node, const UITemplates *templates)
+{
+	for (node = node->first_node(); node; node = node->next_sibling()) {
+		UIBaseElement *element = CreateElement(node->name());
+		if (!element) {
+			fprintf(stderr, "Warning: Couldn't find handler for element %s\n", node->name());
+			continue;
+		}
+
+		if (!element->Load(node, templates) ||
+		    !element->FinishLoading()) {
+			fprintf(stderr, "Warning: Couldn't load element %s: %s\n", node->name(), element->Error());
+			delete element;
+		} else {
+			AddElement(element);
+		}
+	}
+	return true;
+}
diff --git a/screenlib/UIBaseElement.h b/screenlib/UIBaseElement.h
new file mode 100644
index 00000000..843a4206
--- /dev/null
+++ b/screenlib/UIBaseElement.h
@@ -0,0 +1,117 @@
+/*
+    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 _UIBaseElement_h
+#define _UIBaseElement_h
+
+#include "../utils/array.h"
+#include "../utils/rapidxml.h"
+
+#include "SDL.h"
+#include "UIArea.h"
+
+class UIManager;
+class UITemplates;
+
+typedef int UIElementType;
+
+class UIBaseElement : public UIArea
+{
+public:
+	UIBaseElement(UIManager *ui, const char *name = "");
+	UIBaseElement(UIBaseElement *parent, const char *name = "");
+	virtual ~UIBaseElement();
+
+	/* This is used for type-safe casting */
+	virtual bool IsA(UIElementType type) {
+		return type == GetType();
+	}
+
+	UIManager *GetUI() {
+		return m_ui;
+	}
+	UIBaseElement *GetParent() {
+		return m_parent;
+	}
+	const char *GetName() const {
+		return m_name;
+	}
+
+	virtual bool Load(rapidxml::xml_node<> *node, const UITemplates *templates);
+	virtual bool FinishLoading() {
+		return true;
+	}
+
+	virtual UIArea *GetAnchorElement(const char *name) {
+		if (!name) {
+			return m_parent;
+		}
+		return m_parent->GetElement(name);
+	}
+
+	void AddElement(UIBaseElement *element) {
+		m_elements.add(element);
+	}
+	template <typename T>
+	T *GetElement(const char *name) {
+		UIBaseElement *element = GetElement(name);
+		if (element && element->IsA(T::GetType())) {
+			return (T*)element;
+		}
+		return NULL;
+	}
+	void RemoveElement(UIBaseElement *element) {
+		m_elements.remove(element);
+	}
+
+	virtual void Draw();
+	virtual bool HandleEvent(const SDL_Event &event);
+
+protected:
+	UIManager *m_ui;
+	UIBaseElement *m_parent;
+	char *m_name;
+	array<UIBaseElement *> m_elements;
+
+protected:
+	UIBaseElement *GetElement(const char *name);
+	UIBaseElement *CreateElement(const char *type);
+
+	bool LoadElements(rapidxml::xml_node<> *node, const UITemplates *templates);
+
+protected:
+	static UIElementType s_elementTypeIndex;
+	static UIElementType s_elementType;
+
+	static UIElementType GenerateType() {
+		return ++s_elementTypeIndex;
+	}
+public:
+	static UIElementType GetType() {
+		if (!s_elementType) {
+			s_elementType = GenerateType();
+		}
+		return s_elementType;
+	}
+};
+
+#endif // _UIBaseElement_h
diff --git a/screenlib/UIElement.cpp b/screenlib/UIElement.cpp
index 41091317..6a3edf8d 100644
--- a/screenlib/UIElement.cpp
+++ b/screenlib/UIElement.cpp
@@ -23,23 +23,31 @@
 #include "SDL_FrameBuf.h"
 #include "UIPanel.h"
 #include "UIElement.h"
-#include "UITemplates.h"
 
-UIElementType UIElement::s_elementTypeIndex;
 UIElementType UIElement::s_elementType;
 
 
-UIElement::UIElement(UIPanel *panel, const char *name) : UIArea(panel->GetScreen())
+UIElement::UIElement(UIBaseElement *parent, const char *name) :
+	UIBaseElement(parent, name)
 {
-	m_name = new char[strlen(name)+1];
-	strcpy(m_name, name);
-
-	m_panel = panel;
 }
 
-UIElement::~UIElement()
+bool
+UIElement::Load(rapidxml::xml_node<> *node, const UITemplates *templates)
 {
-	delete[] m_name;
+	rapidxml::xml_attribute<> *attr;
+
+	if (!UIBaseElement::Load(node, templates)) {
+		return false;
+	}
+
+	attr = node->first_attribute("name", 0, false);
+	if (attr) {
+		SDL_free(m_name);
+		m_name = SDL_strdup(attr->value());
+	}
+
+	return true;
 }
 
 Uint32
@@ -62,35 +70,3 @@ UIElement::LoadColor(rapidxml::xml_node<> *node) const
 	}
 	return m_screen->MapRGB(r, g, b);
 }
-
-bool
-UIElement::Load(rapidxml::xml_node<> *node, const UITemplates *templates)
-{
-	rapidxml::xml_node<> *child;
-	rapidxml::xml_attribute<> *attr;
-
-	child = templates->GetTemplateFor(node);
-	if (child) {
-		if (!Load(child, templates)) {
-			return false;
-		}
-	}
-
-	attr = node->first_attribute("name", 0, false);
-	if (attr) {
-		delete[] m_name;
-		m_name = new char[strlen(attr->value())+1];
-		strcpy(m_name, attr->value());
-	}
-
-	return UIArea::Load(node);
-}
-
-UIArea *
-UIElement::GetAnchorElement(const char *name)
-{
-	if (!name) {
-		return m_panel;
-	}
-	return m_panel->GetElement<UIElement>(name);
-}
diff --git a/screenlib/UIElement.h b/screenlib/UIElement.h
index d8d1faa4..71e5567d 100644
--- a/screenlib/UIElement.h
+++ b/screenlib/UIElement.h
@@ -23,55 +23,28 @@
 #ifndef _UIElement_h
 #define _UIElement_h
 
-#include "SDL.h"
+#include "UIBaseElement.h"
 
-#include "../utils/rapidxml.h"
-
-#include "UIArea.h"
-
-class FrameBuf;
 class UIPanel;
-class UITemplates;
-
-typedef int UIElementType;
+class UIManager;
 
-class UIElement : public UIArea
+class UIElement : public UIBaseElement
 {
 public:
-	UIElement(UIPanel *panel, const char *name = "");
-	virtual ~UIElement();
+	UIElement(UIBaseElement *parent, const char *name = "");
 
-	/* This is used for type-safe casting */
 	virtual bool IsA(UIElementType type) {
-		return type == GetType();
-	}
-
-	const char *GetName() const {
-		return m_name;
+		return UIBaseElement::IsA(type) || type == GetType();
 	}
 
 	virtual bool Load(rapidxml::xml_node<> *node, const UITemplates *templates);
-	virtual bool FinishLoading() { return true; }
-
-	virtual UIArea *GetAnchorElement(const char *name);
-
-	virtual void Draw() { }
-	virtual bool HandleEvent(const SDL_Event &event) { return false; }
 
 protected:
 	Uint32 LoadColor(rapidxml::xml_node<> *node) const;
 
 protected:
-	char *m_name;
-	UIPanel *m_panel;
-
-protected:
-	static UIElementType s_elementTypeIndex;
 	static UIElementType s_elementType;
 
-	static UIElementType GenerateType() {
-		return ++s_elementTypeIndex;
-	}
 public:
 	static UIElementType GetType() {
 		if (!s_elementType) {
@@ -81,4 +54,6 @@ class UIElement : public UIArea
 	}
 };
 
+Uint32 LoadColor(rapidxml::xml_node<> *node);
+
 #endif // _UIElement_h
diff --git a/screenlib/UIElementButton.cpp b/screenlib/UIElementButton.cpp
index 6a552c10..776e0587 100644
--- a/screenlib/UIElementButton.cpp
+++ b/screenlib/UIElementButton.cpp
@@ -43,8 +43,8 @@ class SimpleButtonDelegate : public UIButtonDelegate
 UIElementType UIElementButton::s_elementType;
 
 
-UIElementButton::UIElementButton(UIPanel *panel, const char *name) :
-	UIElement(panel, name)
+UIElementButton::UIElementButton(UIBaseElement *parent, const char *name) :
+	UIElement(parent, name)
 {
 	m_hotkey = SDLK_UNKNOWN;
 	m_hotkeyMod = KMOD_NONE;
@@ -211,10 +211,10 @@ void
 UIElementButton::OnClick()
 {
 	if (m_clickSound) {
-		m_panel->GetUI()->PlaySound(m_clickSound);
+		GetUI()->PlaySound(m_clickSound);
 	}
 	if (m_clickPanel) {
-		m_panel->GetUI()->ShowPanel(m_clickPanel);
+		GetUI()->ShowPanel(m_clickPanel);
 	}
 	if (m_delegate) {
 		m_delegate->OnClick();
diff --git a/screenlib/UIElementButton.h b/screenlib/UIElementButton.h
index ba06933a..0a199f75 100644
--- a/screenlib/UIElementButton.h
+++ b/screenlib/UIElementButton.h
@@ -34,7 +34,7 @@ class UIButtonDelegate
 class UIElementButton : public UIElement
 {
 public:
-	UIElementButton(UIPanel *panel, const char *name = "");
+	UIElementButton(UIBaseElement *parent, const char *name = "");
 	virtual ~UIElementButton();
 
 	virtual bool IsA(UIElementType type) {
diff --git a/screenlib/UIElementLabel.cpp b/screenlib/UIElementLabel.cpp
index 1f2726ea..572943fb 100644
--- a/screenlib/UIElementLabel.cpp
+++ b/screenlib/UIElementLabel.cpp
@@ -5,8 +5,8 @@
 UIElementType UIElementLabel::s_elementType;
 
 
-UIElementLabel::UIElementLabel(UIPanel *panel, const char *name) :
-	UIElement(panel, name)
+UIElementLabel::UIElementLabel(UIBaseElement *parent, const char *name) :
+	UIElement(parent, name)
 {
 	m_fontName = NULL;
 	m_fontSize = 0;
@@ -25,7 +25,7 @@ UIElementLabel::~UIElementLabel()
 		SDL_free(m_text);
 	}
 	if (m_texture) {
-		m_panel->GetUI()->FreeText(m_texture);
+		GetUI()->FreeText(m_texture);
 	}
 }
 
@@ -100,11 +100,11 @@ UIElementLabel::SetText(const char *text)
 		SDL_free(m_text);
 	}
 	if (m_texture) {
-		m_panel->GetUI()->FreeText(m_texture);
+		GetUI()->FreeText(m_texture);
 	}
 
 	m_text = SDL_strdup(text);
-	m_texture = m_panel->GetUI()->CreateText(m_text, m_fontName, m_fontSize, m_fontStyle, m_color);
+	m_texture = GetUI()->CreateText(m_text, m_fontName, m_fontSize, m_fontStyle, m_color);
 
 	m_rect.w = m_screen->GetImageWidth(m_texture);
 	m_rect.h = m_screen->GetImageHeight(m_texture);
@@ -124,9 +124,9 @@ UIElementLabel::SetTextColor(Uint8 R, Uint8 G, Uint8 B)
 
 	if (m_text) {
 		if (m_texture) {
-			m_panel->GetUI()->FreeText(m_texture);
+			GetUI()->FreeText(m_texture);
 		}
-		m_texture = m_panel->GetUI()->CreateText(m_text, m_fontName, m_fontSize, m_fontStyle, m_color);
+		m_texture = GetUI()->CreateText(m_text, m_fontName, m_fontSize, m_fontStyle, m_color);
 	}
 }
 
diff --git a/screenlib/UIElementLabel.h b/screenlib/UIElementLabel.h
index 9ddd574d..6c53e874 100644
--- a/screenlib/UIElementLabel.h
+++ b/screenlib/UIElementLabel.h
@@ -1,3 +1,25 @@
+/*
+    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 _UIElementLabel_h
 #define _UIElementLabel_h
 
@@ -8,7 +30,7 @@
 class UIElementLabel : public UIElement
 {
 public:
-	UIElementLabel(UIPanel *panel, const char *name = "");
+	UIElementLabel(UIBaseElement *parent, const char *name = "");
 	virtual ~UIElementLabel();
 
 	virtual bool IsA(UIElementType type) {
diff --git a/screenlib/UIElementLine.cpp b/screenlib/UIElementLine.cpp
index 3d327cd1..94ef032b 100644
--- a/screenlib/UIElementLine.cpp
+++ b/screenlib/UIElementLine.cpp
@@ -5,8 +5,8 @@
 UIElementType UIElementLine::s_elementType;
 
 
-UIElementLine::UIElementLine(UIPanel *panel, const char *name) :
-	UIElement(panel, name)
+UIElementLine::UIElementLine(UIBaseElement *parent, const char *name) :
+	UIElement(parent, name)
 {
 	m_color = m_screen->MapRGB(0xFF, 0xFF, 0xFF);
 }
diff --git a/screenlib/UIElementLine.h b/screenlib/UIElementLine.h
index 1e3dd2c3..b2ae2237 100644
--- a/screenlib/UIElementLine.h
+++ b/screenlib/UIElementLine.h
@@ -1,3 +1,25 @@
+/*
+    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 _UIElementLine_h
 #define _UIElementLine_h
 
@@ -7,7 +29,7 @@
 class UIElementLine : public UIElement
 {
 public:
-	UIElementLine(UIPanel *panel, const char *name = "");
+	UIElementLine(UIBaseElement *parent, const char *name = "");
 
 	virtual bool IsA(UIElementType type) {
 		return UIElement::IsA(type) || type == GetType();
diff --git a/screenlib/UIElementRect.cpp b/screenlib/UIElementRect.cpp
index ecc32b02..5ae4b5b0 100644
--- a/screenlib/UIElementRect.cpp
+++ b/screenlib/UIElementRect.cpp
@@ -5,8 +5,8 @@
 UIElementType UIElementRect::s_elementType;
 
 
-UIElementRect::UIElementRect(UIPanel *panel, const char *name) :
-	UIElement(panel, name)
+UIElementRect::UIElementRect(UIBaseElement *parent, const char *name) :
+	UIElement(parent, name)
 {
 	m_fill = false;
 	m_color = m_screen->MapRGB(0xFF, 0xFF, 0xFF);
diff --git a/screenlib/UIElementRect.h b/screenlib/UIElementRect.h
index a03c20c0..5c2dce0c 100644
--- a/screenlib/UIElementRect.h
+++ b/screenlib/UIElementRect.h
@@ -1,3 +1,25 @@
+/*
+    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 _UIElementRect_h
 #define _UIElementRect_h
 
@@ -7,7 +29,7 @@
 class UIElementRect : public UIElement
 {
 public:
-	UIElementRect(UIPanel *panel, const char *name = "");
+	UIElementRect(UIBaseElement *parent, const char *name = "");
 
 	virtual bool IsA(UIElementType type) {
 		return UIElement::IsA(type) || type == GetType();
diff --git a/screenlib/UIElementTexture.cpp b/screenlib/UIElementTexture.cpp
index a74be9ea..ccc944b8 100644
--- a/screenlib/UIElementTexture.cpp
+++ b/screenlib/UIElementTexture.cpp
@@ -5,8 +5,8 @@
 UIElementType UIElementTexture::s_elementType;
 
 
-UIElementTexture::UIElementTexture(UIPanel *panel, const char *name) :
-	UIElement(panel, name)
+UIElementTexture::UIElementTexture(UIBaseElement *parent, const char *name) :
+	UIElement(parent, name)
 {
 	m_texture = NULL;
 }
diff --git a/screenlib/UIElementTexture.h b/screenlib/UIElementTexture.h
index c4d6d87a..d89e0cdc 100644
--- a/screenlib/UIElementTexture.h
+++ b/screenlib/UIElementTexture.h
@@ -1,3 +1,25 @@
+/*
+    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 _UIElementTexture_h
 #define _UIElementTexture_h
 
@@ -7,7 +29,7 @@
 class UIElementTexture : public UIElement
 {
 public:
-	UIElementTexture(UIPanel *panel, const char *name = "");
+	UIElementTexture(UIBaseElement *parent, const char *name = "");
 	virtual ~UIElementTexture();
 
 	virtual bool IsA(UIElementType type) {
diff --git a/screenlib/UIManager.cpp b/screenlib/UIManager.cpp
index ae573f0f..6693825a 100644
--- a/screenlib/UIManager.cpp
+++ b/screenlib/UIManager.cpp
@@ -282,14 +282,14 @@ UIManager::CreatePanelDelegate(UIPanel *panel, const char *delegate)
 }
 
 UIElement *
-UIManager::CreateElement(UIPanel *panel, const char *type)
+UIManager::CreateElement(UIBaseElement *parent, const char *type)
 {
 	if (strcasecmp(type, "Line") == 0) {
-		return new UIElementLine(panel);
+		return new UIElementLine(parent);
 	} else if (strcasecmp(type, "Rectangle") == 0) {
-		return new UIElementRect(panel);
+		return new UIElementRect(parent);
 	} else if (strcasecmp(type, "Button") == 0) {
-		return new UIElementButton(panel);
+		return new UIElementButton(parent);
 	}
 	return NULL;
 }
diff --git a/screenlib/UIManager.h b/screenlib/UIManager.h
index fe38d54a..806fd42c 100644
--- a/screenlib/UIManager.h
+++ b/screenlib/UIManager.h
@@ -31,6 +31,7 @@
 #include "UITemplates.h"
 
 class FrameBuf;
+class UIBaseElement;
 class UIPanel;
 class UIPanelDelegate;
 class UIElement;
@@ -84,7 +85,7 @@ class UIManager : public UIArea, public UIFontInterface, public UISoundInterface
 public:
 	virtual UIPanel *CreatePanel(const char *type, const char *name);
 	virtual UIPanelDelegate *CreatePanelDelegate(UIPanel *panel, const char *delegate);
-	virtual UIElement *CreateElement(UIPanel *panel, const char *type);
+	virtual UIElement *CreateElement(UIBaseElement *parent, const char *type);
 
 protected:
 	char *m_loadPath;
diff --git a/screenlib/UIPanel.cpp b/screenlib/UIPanel.cpp
index 074f3127..48bd01b9 100644
--- a/screenlib/UIPanel.cpp
+++ b/screenlib/UIPanel.cpp
@@ -27,12 +27,9 @@
 #include "UITemplates.h"
 
 
-UIPanel::UIPanel(UIManager *ui, const char *name) : UIArea(ui->GetScreen())
+UIPanel::UIPanel(UIManager *ui, const char *name) :
+	UIBaseElement(ui, name)
 {
-	m_ui = ui;
-	m_name = new char[strlen(name)+1];
-	strcpy(m_name, name);
-
 	m_rect.w = m_screen->Width();
 	m_rect.h = m_screen->Height();
 	m_shown = false;
@@ -51,25 +48,15 @@ UIPanel::~UIPanel()
 	m_ui->RemovePanel(this);
 
 	SetPanelDelegate(NULL);
-
-	delete[] m_name;
-
-	for (unsigned i = 0; i < m_elements.length(); ++i) {
-		delete m_elements[i];
-	}
 }
 
 bool
 UIPanel::Load(rapidxml::xml_node<> *node, const UITemplates *templates)
 {
-	rapidxml::xml_node<> *child;
 	rapidxml::xml_attribute<> *attr;
 
-	child = templates->GetTemplateFor(node);
-	if (child) {
-		if (!Load(child, templates)) {
-			return false;
-		}
+	if (!UIBaseElement::Load(node, templates)) {
+		return false;
 	}
 
 	attr = node->first_attribute("fullscreen", 0, false);
@@ -98,15 +85,6 @@ UIPanel::Load(rapidxml::xml_node<> *node, const UITemplates *templates)
 	if (attr) {
 		m_leaveSound = atoi(attr->value());
 	}
-	if (!UIArea::Load(node)) {
-		return false;
-	}
-	chi

(Patch may be truncated, please check the link at the top of this post.)