Maelstrom: Switched the loading screen over to XML, added a few new elements to support it.

From b582f82ab7a3fc1976038ad6da2de24c4b45b528 Mon Sep 17 00:00:00 2001
From: Sam Lantinga <[EMAIL REDACTED]>
Date: Sun, 23 Oct 2011 06:49:03 -0400
Subject: [PATCH] Switched the loading screen over to XML, added a few new
 elements to support it.

---
 Makefile.am                    |   2 +
 UI/UI.lst                      |   1 +
 UI/loading.xml                 |  68 ++++++++++++++++++++++
 UIElementLabel.cpp             | 100 +++++++++++++++++++++++++++++++++
 UIElementLabel.h               |  27 +++++++++
 UIElementTitle.cpp             |   1 +
 UIElements.cpp                 |  11 +++-
 init.cpp                       | 100 ++++++---------------------------
 maclib/Mac_FontServ.h          |   9 +++
 screenlib/Makefile.am          |   4 ++
 screenlib/UIArea.cpp           |  86 ++++++++++++++++------------
 screenlib/UIArea.h             |  18 ++++++
 screenlib/UIElement.cpp        |  31 ++++++++++
 screenlib/UIElement.h          |   3 +
 screenlib/UIElementLine.cpp    |  28 +++++++++
 screenlib/UIElementLine.h      |  20 +++++++
 screenlib/UIElementRect.cpp    |  43 ++++++++++++++
 screenlib/UIElementRect.h      |  21 +++++++
 screenlib/UIElementTexture.cpp |   4 ++
 screenlib/UIManager.cpp        |   9 +++
 screenlib/UIManager.h          |   1 +
 21 files changed, 467 insertions(+), 120 deletions(-)
 create mode 100644 UI/loading.xml
 create mode 100644 UIElementLabel.cpp
 create mode 100644 UIElementLabel.h
 create mode 100644 screenlib/UIElementLine.cpp
 create mode 100644 screenlib/UIElementLine.h
 create mode 100644 screenlib/UIElementRect.cpp
 create mode 100644 screenlib/UIElementRect.h

diff --git a/Makefile.am b/Makefile.am
index 502269ef..f2728669 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -29,6 +29,8 @@ Maelstrom_SOURCES =		\
 	rect.h			\
 	scores.cpp		\
 	scores.h		\
+	UIElementLabel.cpp	\
+	UIElementLabel.h	\
 	UIElementTitle.cpp	\
 	UIElementTitle.h	\
 	UIElements.cpp		\
diff --git a/UI/UI.lst b/UI/UI.lst
index 2534a7a6..4e69efcd 100644
--- a/UI/UI.lst
+++ b/UI/UI.lst
@@ -1 +1,2 @@
 # List of panels to load at startup
+loading
diff --git a/UI/loading.xml b/UI/loading.xml
new file mode 100644
index 00000000..d52a9357
--- /dev/null
+++ b/UI/loading.xml
@@ -0,0 +1,68 @@
+<UIPanel>
+	<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"/>
+		</Label>
+
+		<!-- Loading Bar -->
+		<Rectangle name="loadingBar">
+			<Color r="0x00" g="0x00" b="0x00"/>
+			<Size w="200" h="10"/>
+			<Anchor anchorFrom="CENTER" anchorTo="CENTER" y="185"/>
+		</Rectangle>
+		<Rectangle>
+			<Color r="0xFF" g="0xFF" b="0xFF"/>
+			<Size w="198" h="8"/>
+			<Anchor anchorFrom="CENTER" anchorTo="CENTER" y="185"/>
+		</Rectangle>
+		<Rectangle fill="true">
+			<Color r="0x8F" g="0x8F" b="0xFF"/>
+			<Size w="196" h="6"/>
+			<Anchor anchorFrom="CENTER" anchorTo="CENTER" y="185"/>
+		</Rectangle>
+		<Rectangle name="progress" fill="true">
+			<Color r="0x6F" g="0x6F" b="0xFF"/>
+			<Size w="0" h="6"/>
+			<Anchor anchorFrom="LEFT" anchorTo="CENTER" x="-98" y="185"/>
+		</Rectangle>
+	</Elements>
+</UIPanel>
diff --git a/UIElementLabel.cpp b/UIElementLabel.cpp
new file mode 100644
index 00000000..06153d83
--- /dev/null
+++ b/UIElementLabel.cpp
@@ -0,0 +1,100 @@
+
+#include "UIElementLabel.h"
+#include "Maelstrom_Globals.h"
+
+
+UIElementLabel::UIElementLabel(UIPanel *panel, const char *name) :
+	UIElement(panel, name)
+{
+	m_font = NULL;
+	m_style = STYLE_NORM;
+	m_color = m_screen->MapRGB(0xFF, 0xFF, 0xFF);
+	m_texture = NULL;
+}
+
+UIElementLabel::~UIElementLabel()
+{
+	if (m_texture) {
+		fontserv->FreeText(m_texture);
+	}
+}
+
+static Uint8 ParseStyle(const char *text)
+{
+	Uint8 style = STYLE_NORM;
+
+	if (strcasecmp(text, "bold") == 0) {
+		style = STYLE_BOLD;
+	} else if (strcasecmp(text, "underline") == 0) {
+		style = STYLE_ULINE;
+	} else if (strcasecmp(text, "italic") == 0) {
+		style = STYLE_ITALIC;
+	}
+}
+
+bool
+UIElementLabel::Load(rapidxml::xml_node<> *node)
+{
+	rapidxml::xml_node<> *child;
+	rapidxml::xml_attribute<> *attr;
+	const char *fontName;
+	int fontSize;
+
+	attr = node->first_attribute("fontName", 0, false);
+	if (!attr) {
+		SetError("Element 'Label' missing attribute 'font'");
+		return false;
+	}
+	fontName = attr->value();
+
+	attr = node->first_attribute("fontSize", 0, false);
+	if (!attr) {
+		SetError("Element 'Label' missing attribute 'fontSize'");
+		return false;
+	}
+	fontSize = SDL_atoi(attr->value());
+
+	m_font = fontserv->NewFont(fontName, fontSize);
+	if (!m_font) {
+		SetError("Element 'Label' couldn't find font %s:%d", fontName, fontSize);
+		return false;
+	}
+
+	attr = node->first_attribute("fontStyle", 0, false);
+	if (attr) {
+		m_style = ParseStyle(attr->value());
+	}
+
+	child = node->first_node("color", 0, false);
+	if (child) {
+		m_color = LoadColor(child);
+	}
+
+	attr = node->first_attribute("text", 0, false);
+	if (attr) {
+		SetText(attr->value());
+	}
+
+	return UIElement::Load(node);
+}
+
+void
+UIElementLabel::SetText(const char *text)
+{
+	if (m_texture) {
+		fontserv->FreeText(m_texture);
+	}
+
+	m_texture = fontserv->TextImage(text, m_font, m_style, m_color);
+	m_rect.w = m_screen->GetImageWidth(m_texture);
+	m_rect.h = m_screen->GetImageHeight(m_texture);
+	CalculateAnchor();
+}
+
+void
+UIElementLabel::Draw()
+{
+	if (m_texture) {
+		m_screen->QueueBlit(m_rect.x, m_rect.y, m_texture, NOCLIP);
+	}
+}
diff --git a/UIElementLabel.h b/UIElementLabel.h
new file mode 100644
index 00000000..62362ce6
--- /dev/null
+++ b/UIElementLabel.h
@@ -0,0 +1,27 @@
+#ifndef _UIElementLabel_h
+#define _UIElementLabel_h
+
+#include "screenlib/UIElement.h"
+
+class MFont;
+
+class UIElementLabel : public UIElement
+{
+public:
+	UIElementLabel(UIPanel *panel, const char *name = "");
+	virtual ~UIElementLabel();
+
+	virtual bool Load(rapidxml::xml_node<> *node);
+
+	virtual void SetText(const char *text);
+
+	virtual void Draw();
+
+protected:
+	MFont *m_font;
+	Uint8 m_style;
+	Uint32 m_color;
+	SDL_Texture *m_texture;
+};
+
+#endif // _UIElementLabel_h
diff --git a/UIElementTitle.cpp b/UIElementTitle.cpp
index de815249..85236694 100644
--- a/UIElementTitle.cpp
+++ b/UIElementTitle.cpp
@@ -2,6 +2,7 @@
 #include "UIElementTitle.h"
 #include "load.h"
 
+
 UIElementTitle::UIElementTitle(UIPanel *panel, const char *name) :
 	UIElementTexture(panel, name)
 {
diff --git a/UIElements.cpp b/UIElements.cpp
index 0f8843bf..e23da483 100644
--- a/UIElements.cpp
+++ b/UIElements.cpp
@@ -1,12 +1,21 @@
 
 #include "UIElements.h"
+#include "screenlib/UIElementLine.h"
+#include "screenlib/UIElementRect.h"
+#include "UIElementLabel.h"
 #include "UIElementTitle.h"
 
 
 UIElement *
 CreateMaelstromUIElement(UIPanel *panel, const char *name)
 {
-	if (strcasecmp(name, "Title") == 0) {
+	if (strcasecmp(name, "Line") == 0) {
+		return new UIElementLine(panel);
+	} else if (strcasecmp(name, "Rectangle") == 0) {
+		return new UIElementRect(panel);
+	} else if (strcasecmp(name, "Label") == 0) {
+		return new UIElementLabel(panel);
+	} else if (strcasecmp(name, "Title") == 0) {
 		return new UIElementTitle(panel);
 	}
 	return NULL;
diff --git a/init.cpp b/init.cpp
index 3ac6fdff..ac2a9ca7 100644
--- a/init.cpp
+++ b/init.cpp
@@ -9,6 +9,7 @@
 #include "colortable.h"
 #include "fastrand.h"
 #include "UIElements.h"
+#include "screenlib/UIElement.h"
 
 
 // Global variables set in this file...
@@ -46,9 +47,6 @@ SDL_Texture *gAutoFireIcon, *gAirBrakesIcon, *gMult2Icon, *gMult3Icon;
 SDL_Texture *gMult4Icon, *gMult5Icon, *gLuckOfTheIrishIcon, *gLongFireIcon;
 SDL_Texture *gTripleFireIcon, *gKeyIcon, *gShieldIcon;
 
-// Local variables set in this file...
-static SDL_Texture *intro;
-
 // Local functions used in this file.
 static void DrawLoadBar(int stage);
 static int InitSprites(void);
@@ -97,55 +95,6 @@ void DoSplash(void)
 	}
 }
 
-/* ----------------------------------------------------------------- */
-/* -- Put up our intro splash screen */
-
-void DoIntroScreen(int first)
-{
-	SDL_Texture *text;
-	Uint16  Yoff, Xoff;
-	Uint32  clr, ltClr, ltrClr;
-	int introW, introH;
-
-	DropEvents();
-
-	// -- Draw a border
-	clr = screen->MapRGB(30000>>8, 30000>>8, 0xFF);
-	ltClr = screen->MapRGB(40000>>8, 40000>>8, 0xFF);
-	ltrClr = screen->MapRGB(50000>>8, 50000>>8, 0xFF);
-
-	screen->Clear();
-	introW = screen->GetImageWidth(intro);
-	introH = screen->GetImageHeight(intro);
-	Xoff = (SCREEN_WIDTH-introW)/2;
-	Yoff = (SCREEN_HEIGHT-introH)/2;
-	screen->DrawRect(Xoff-1, Yoff-1, introW+2, introH+2, clr);
-	screen->DrawRect(Xoff-2, Yoff-2, introW+4, introH+4, clr);
-	screen->DrawRect(Xoff-3, Yoff-3, introW+6, introH+6, ltClr);
-	screen->DrawRect(Xoff-4, Yoff-4, introW+8, introH+8, ltClr);
-	screen->DrawRect(Xoff-5, Yoff-5, introW+10, introH+10, ltrClr);
-	screen->DrawRect(Xoff-6, Yoff-6, introW+12, introH+12, ltClr);
-	screen->DrawRect(Xoff-7, Yoff-7, introW+14, introH+14, clr);
-	Yoff += introH;
-	screen->QueueBlit(SCREEN_WIDTH/2-introW/2, SCREEN_HEIGHT/2-introH/2,
-								intro, NOCLIP);
-
-/* -- Draw the loading message */
-
-	text = fontserv->TextImage("Loading...", fonts[GENEVA_9], STYLE_BOLD,
-						0xFF, 0xFF, 0x00);
-	if ( text ) {
-		screen->QueueBlit(SCREEN_WIDTH/2-screen->GetImageWidth(text)/2,
-				Yoff+20-screen->GetImageHeight(text)/2, text, NOCLIP);
-		fontserv->FreeText(text);
-	}
-
-	if (first) {
-		screen->Update();
-	}
-}	// -- DoIntroScreen
-
-
 /* ----------------------------------------------------------------- */
 /* -- Draw a loading status bar */
 
@@ -153,26 +102,18 @@ void DoIntroScreen(int first)
 
 static void DrawLoadBar(int stage)
 {
-	Uint32 black, clr;
+	UIElement *progress;
 	int fact;
+	const int FULL_WIDTH = 196;
+
+	progress = ui->GetCurrentPanel()->GetElement("progress");
+	if (progress) {
+		fact = (FULL_WIDTH * stage) / MAX_BAR;
+		progress->SetWidth(fact);
+	}
 
-	DoIntroScreen(0);
-
-	black = screen->MapRGB(0x00, 0x00, 0x00);
-	screen->DrawRect((SCREEN_WIDTH-200)/2, 
-			   ((SCREEN_HEIGHT-10)/2)+185, 200, 10, black);
-	clr = screen->MapRGB(0xFF, 0xFF, 0xFF);
-	screen->DrawRect(((SCREEN_WIDTH-200)/2)+1, 
-			   ((SCREEN_HEIGHT-10)/2)+185+1, 
-						200-2, 10-2, clr);
-	clr = screen->MapRGB(0x8F, 0x8F, 0xFF);
-	screen->FillRect(((SCREEN_WIDTH-200)/2)+1+1, 
-			   ((SCREEN_HEIGHT-10)/2)+185+1+1, 
-						200-2-2, 10-2-2, clr);
-	clr = screen->MapRGB(0x6F, 0x6F, 0xFF);
-	fact = ((200-2-2) * stage) / MAX_BAR;
-	screen->FillRect(((SCREEN_WIDTH-200)/2)+1+1, 
-			 ((SCREEN_HEIGHT-10)/2)+185+1+1, fact, 10-2-2, clr);
+	screen->Clear();
+	ui->Draw();
 	screen->Update();
 }	/* -- DrawLoadBar */
 
@@ -715,11 +656,7 @@ void CleanUp(void)
 		ui = NULL;
 	}
 	if ( fontserv ) {
-		for ( i = 0; i < NUM_FONTS; ++i ) {
-			if ( fonts[i] ) {
-				fontserv->FreeFont(fonts[i]);
-			}
-		}
+		/* This will free the allocated fonts */
 		delete fontserv;
 		fontserv = NULL;
 	}
@@ -838,14 +775,11 @@ int DoInitializations(Uint32 window_flags, Uint32 render_flags)
 	DoSplash();
 
 	/* -- Throw up our intro screen */
-	intro = Load_Title(screen, 130);
-	if ( intro == NULL ) {
-		error("Can't load intro title! (ID=%d)\n", 130);
-		return(-1);
-	}
-	DoIntroScreen(1);
+	ui->ShowPanel(PANEL_LOADING);
 	sound->PlaySound(gPrizeAppears, 1);
-	screen->FadeIn();
+	screen->Clear();
+	ui->Draw();
+	screen->Update();
 
 	/* -- Load in our sprites and other needed resources */
 	{
@@ -877,7 +811,7 @@ int DoInitializations(Uint32 window_flags, Uint32 render_flags)
 	/* -- Set up the velocity tables */
 	BuildVelocityTable();
 
-	screen->FreeImage(intro);
+	ui->DeletePanel(PANEL_LOADING);
 
 	return(0);
 }	/* -- DoInitializations */
diff --git a/maclib/Mac_FontServ.h b/maclib/Mac_FontServ.h
index cd3bd994..f81936ee 100644
--- a/maclib/Mac_FontServ.h
+++ b/maclib/Mac_FontServ.h
@@ -109,6 +109,15 @@ class FontServ {
 	 */
 	SDL_Texture *TextImage(const char *text, MFont *font, Uint8 style,
 						SDL_Color foreground);
+	SDL_Texture *TextImage(const char *text, MFont *font, Uint8 style,
+						Uint32 rgb) {
+		SDL_Color foreground;
+
+		foreground.r = (rgb >> 16) & 0xFF;
+		foreground.g = (rgb >>  8) & 0xFF;
+		foreground.b = (rgb >>  0) & 0xFF;
+		return(TextImage(text, font, style, foreground));
+	}
 	SDL_Texture *TextImage(const char *text, MFont *font, Uint8 style,
 						Uint8 R, Uint8 G, Uint8 B) {
 		SDL_Color foreground;
diff --git a/screenlib/Makefile.am b/screenlib/Makefile.am
index 02e7b18b..a018af41 100644
--- a/screenlib/Makefile.am
+++ b/screenlib/Makefile.am
@@ -9,6 +9,10 @@ libSDLscreen_a_SOURCES =	\
 	UIArea.h		\
 	UIElement.cpp		\
 	UIElement.h		\
+	UIElementLine.cpp	\
+	UIElementLine.h		\
+	UIElementRect.cpp	\
+	UIElementRect.h		\
 	UIElementTexture.cpp	\
 	UIElementTexture.h	\
 	UIManager.cpp		\
diff --git a/screenlib/UIArea.cpp b/screenlib/UIArea.cpp
index f0ac4ef4..1666c371 100644
--- a/screenlib/UIArea.cpp
+++ b/screenlib/UIArea.cpp
@@ -53,6 +53,11 @@ static AnchorLocation ParseAnchorLocation(const char *text)
 UIArea::UIArea(FrameBuf *screen) : ErrorBase()
 {
 	m_screen = screen;
+	m_anchor.element = NULL;
+	m_anchor.anchorFrom = TOPLEFT;
+	m_anchor.anchorTo = TOPLEFT;
+	m_anchor.offsetX = 0;
+	m_anchor.offsetY = 0;
 	m_rect.x = 0;
 	m_rect.y = 0;
 	m_rect.w = 0;
@@ -80,24 +85,21 @@ UIArea::Load(rapidxml::xml_node<> *node)
 	if (child) {
 		attr = child->first_attribute("w", 0, false);
 		if (attr) {
-			m_rect.w = atoi(attr->value());
+			m_rect.w = SDL_atoi(attr->value());
 		}
 		attr = child->first_attribute("h", 0, false);
 		if (attr) {
-			m_rect.h = atoi(attr->value());
+			m_rect.h = SDL_atoi(attr->value());
 		}
 	}
 
 	child = node->first_node("anchor", 0, false);
 	if (child) {
-		UIArea *anchorElement;
-		AnchorLocation anchorFrom = TOPLEFT;
-		AnchorLocation anchorTo = TOPLEFT;
 		int x, y;
 
-		attr = child->first_attribute("anchorElement", 0, false);
-		anchorElement = GetAnchorElement(attr ? attr->value() : NULL);
-		if (!anchorElement) {
+		attr = child->first_attribute("anchor", 0, false);
+		m_anchor.element = GetAnchorElement(attr ? attr->value() : NULL);
+		if (!m_anchor.element) {
 			SetError("Element 'anchor' couldn't find anchor element %s",
 				attr ? attr->value() : "NULL");
 			return false;
@@ -105,46 +107,23 @@ UIArea::Load(rapidxml::xml_node<> *node)
 
 		attr = child->first_attribute("anchorFrom", 0, false);
 		if (attr) {
-			anchorFrom = ParseAnchorLocation(attr->value());
+			m_anchor.anchorFrom = ParseAnchorLocation(attr->value());
 		}
 		attr = child->first_attribute("anchorTo", 0, false);
 		if (attr) {
-			anchorTo = ParseAnchorLocation(attr->value());
-		}
-		anchorElement->GetAnchorLocation(anchorTo, &x, &y);
-
-		switch (anchorFrom & X_MASK) {
-			case X_CENTER:
-				x -= Width() / 2;
-				break;
-			case X_RIGHT:
-				x -= Width();
-				break;
-			default:
-				break;
-		}
-		switch (anchorFrom & Y_MASK) {
-			case Y_CENTER:
-				y -= Height() / 2;
-				break;
-			case Y_BOTTOM:
-				y -= Height();
-				break;
-			default:
-				break;
+			m_anchor.anchorTo = ParseAnchorLocation(attr->value());
 		}
 
 		attr = child->first_attribute("x", 0, false);
 		if (attr) {
-			x += atoi(attr->value());
+			m_anchor.offsetX = SDL_atoi(attr->value());
 		}
 		attr = child->first_attribute("y", 0, false);
 		if (attr) {
-			y += atoi(attr->value());
+			m_anchor.offsetY = SDL_atoi(attr->value());
 		}
 
-		m_rect.x = x;
-		m_rect.y = y;
+		CalculateAnchor();
 	}
 
 	return true;
@@ -180,3 +159,38 @@ UIArea::GetAnchorLocation(AnchorLocation spot, int *x, int *y) const
 			assert(0);
 	}
 }
+
+void
+UIArea::CalculateAnchor()
+{
+	int x, y;
+
+	if (!m_anchor.element) {
+		return;
+	}
+	m_anchor.element->GetAnchorLocation(m_anchor.anchorTo, &x, &y);
+
+	switch (m_anchor.anchorFrom & X_MASK) {
+		case X_CENTER:
+			x -= Width() / 2;
+			break;
+		case X_RIGHT:
+			x -= Width();
+			break;
+		default:
+			break;
+	}
+	switch (m_anchor.anchorFrom & Y_MASK) {
+		case Y_CENTER:
+			y -= Height() / 2;
+			break;
+		case Y_BOTTOM:
+			y -= Height();
+			break;
+		default:
+			break;
+	}
+
+	m_rect.x = x + m_anchor.offsetX;
+	m_rect.y = y + m_anchor.offsetY;
+}
diff --git a/screenlib/UIArea.h b/screenlib/UIArea.h
index f592a2c4..b1fe7348 100644
--- a/screenlib/UIArea.h
+++ b/screenlib/UIArea.h
@@ -70,6 +70,15 @@ class UIArea : public ErrorBase
 	void SetSize(int w, int h) {
 		m_rect.w = w;
 		m_rect.h = h;
+		CalculateAnchor();
+	}
+	void SetWidth(int w) {
+		m_rect.w = w;
+		CalculateAnchor();
+	}
+	void SetHeight(int h) {
+		m_rect.h = h;
+		CalculateAnchor();
 	}
 
 	FrameBuf *GetScreen() const {
@@ -102,8 +111,17 @@ class UIArea : public ErrorBase
 		return m_shown;
 	}
 
+protected:
+	void CalculateAnchor();
+
 protected:
 	FrameBuf *m_screen;
+	struct {
+		UIArea *element;
+		AnchorLocation anchorFrom;
+		AnchorLocation anchorTo;
+		int offsetX, offsetY;
+	} m_anchor;
 	SDL_Rect m_rect;
 	bool m_shown;
 };
diff --git a/screenlib/UIElement.cpp b/screenlib/UIElement.cpp
index 0280be16..bc5a1622 100644
--- a/screenlib/UIElement.cpp
+++ b/screenlib/UIElement.cpp
@@ -20,6 +20,7 @@
     slouken@libsdl.org
 */
 
+#include "SDL_FrameBuf.h"
 #include "UIPanel.h"
 #include "UIElement.h"
 
@@ -36,9 +37,39 @@ UIElement::~UIElement()
 	delete[] m_name;
 }
 
+Uint32
+UIElement::LoadColor(rapidxml::xml_node<> *node) const
+{
+	Uint8 r, g, b;
+	rapidxml::xml_attribute<> *attr;
+
+	attr = node->first_attribute("r", 0, false);
+	if (attr) {
+		r = (Uint8)strtol(attr->value(), NULL, 0);
+	}
+	attr = node->first_attribute("g", 0, false);
+	if (attr) {
+		g = (Uint8)strtol(attr->value(), NULL, 0);
+	}
+	attr = node->first_attribute("b", 0, false);
+	if (attr) {
+		b = (Uint8)strtol(attr->value(), NULL, 0);
+	}
+	return m_screen->MapRGB(r, g, b);
+}
+
 bool
 UIElement::Load(rapidxml::xml_node<> *node)
 {
+	rapidxml::xml_attribute<> *attr;
+
+	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);
 }
 
diff --git a/screenlib/UIElement.h b/screenlib/UIElement.h
index 1572d9b2..06683156 100644
--- a/screenlib/UIElement.h
+++ b/screenlib/UIElement.h
@@ -51,6 +51,9 @@ class UIElement : public UIArea
 	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;
diff --git a/screenlib/UIElementLine.cpp b/screenlib/UIElementLine.cpp
new file mode 100644
index 00000000..c059a3cb
--- /dev/null
+++ b/screenlib/UIElementLine.cpp
@@ -0,0 +1,28 @@
+
+#include "SDL_FrameBuf.h"
+#include "UIElementLine.h"
+
+UIElementLine::UIElementLine(UIPanel *panel, const char *name) :
+	UIElement(panel, name)
+{
+	m_color = m_screen->MapRGB(0xFF, 0xFF, 0xFF);
+}
+
+bool
+UIElementLine::Load(rapidxml::xml_node<> *node)
+{
+	rapidxml::xml_node<> *child;
+
+	child = node->first_node("color", 0, false);
+	if (child) {
+		m_color = LoadColor(child);
+	}
+
+	return UIElement::Load(node);
+}
+
+void
+UIElementLine::Draw()
+{
+	m_screen->DrawLine(m_rect.x, m_rect.y, m_rect.x+m_rect.w, m_rect.y+m_rect.h, m_color);
+}
diff --git a/screenlib/UIElementLine.h b/screenlib/UIElementLine.h
new file mode 100644
index 00000000..12eb771b
--- /dev/null
+++ b/screenlib/UIElementLine.h
@@ -0,0 +1,20 @@
+#ifndef _UIElementLine_h
+#define _UIElementLine_h
+
+#include "screenlib/UIElement.h"
+
+
+class UIElementLine : public UIElement
+{
+public:
+	UIElementLine(UIPanel *panel, const char *name = "");
+
+	virtual bool Load(rapidxml::xml_node<> *node);
+
+	virtual void Draw();
+
+private:
+	Uint32 m_color;
+};
+
+#endif // _UIElementLine_h
diff --git a/screenlib/UIElementRect.cpp b/screenlib/UIElementRect.cpp
new file mode 100644
index 00000000..7a2bd978
--- /dev/null
+++ b/screenlib/UIElementRect.cpp
@@ -0,0 +1,43 @@
+
+#include "SDL_FrameBuf.h"
+#include "UIElementRect.h"
+
+UIElementRect::UIElementRect(UIPanel *panel, const char *name) :
+	UIElement(panel, name)
+{
+	m_fill = false;
+	m_color = m_screen->MapRGB(0xFF, 0xFF, 0xFF);
+}
+
+bool
+UIElementRect::Load(rapidxml::xml_node<> *node)
+{
+	rapidxml::xml_node<> *child;
+	rapidxml::xml_attribute<> *attr;
+
+	attr = node->first_attribute("fill", 0, false);
+	if (attr) {
+		const char *value = attr->value();
+
+		if (*value == '1' || *value == 't' || *value == 'T') {
+			m_fill = true;
+		}
+	}
+
+	child = node->first_node("color", 0, false);
+	if (child) {
+		m_color = LoadColor(child);
+	}
+
+	return UIElement::Load(node);
+}
+
+void
+UIElementRect::Draw()
+{
+	if (m_fill) {
+		m_screen->FillRect(m_rect.x, m_rect.y, m_rect.w, m_rect.h, m_color);
+	} else {
+		m_screen->DrawRect(m_rect.x, m_rect.y, m_rect.w, m_rect.h, m_color);
+	}
+}
diff --git a/screenlib/UIElementRect.h b/screenlib/UIElementRect.h
new file mode 100644
index 00000000..69e70c1c
--- /dev/null
+++ b/screenlib/UIElementRect.h
@@ -0,0 +1,21 @@
+#ifndef _UIElementRect_h
+#define _UIElementRect_h
+
+#include "screenlib/UIElement.h"
+
+
+class UIElementRect : public UIElement
+{
+public:
+	UIElementRect(UIPanel *panel, const char *name = "");
+
+	virtual bool Load(rapidxml::xml_node<> *node);
+
+	virtual void Draw();
+
+private:
+	bool m_fill;
+	Uint32 m_color;
+};
+
+#endif // _UIElementRect_h
diff --git a/screenlib/UIElementTexture.cpp b/screenlib/UIElementTexture.cpp
index 89a61f19..676af419 100644
--- a/screenlib/UIElementTexture.cpp
+++ b/screenlib/UIElementTexture.cpp
@@ -19,9 +19,13 @@ UIElementTexture::~UIElementTexture()
 void
 UIElementTexture::SetTexture(SDL_Texture *texture)
 {
+	if (m_texture) {
+		m_screen->FreeImage(m_texture);
+	}
 	m_texture = texture;
 	m_rect.w = m_screen->GetImageWidth(texture);
 	m_rect.h = m_screen->GetImageHeight(texture);
+	CalculateAnchor();
 }
 
 void
diff --git a/screenlib/UIManager.cpp b/screenlib/UIManager.cpp
index 924d9ece..01ef1fa2 100644
--- a/screenlib/UIManager.cpp
+++ b/screenlib/UIManager.cpp
@@ -138,6 +138,15 @@ UIManager::GetPanel(const char *name)
 	return NULL;
 }
 
+UIPanel *
+UIManager::GetCurrentPanel()
+{
+	if (m_visible.length() > 0) {
+		return m_visible[m_visible.length()-1];
+	}
+	return NULL;
+}
+
 void
 UIManager::ShowPanel(UIPanel *panel)
 {
diff --git a/screenlib/UIManager.h b/screenlib/UIManager.h
index ce765678..6578345b 100644
--- a/screenlib/UIManager.h
+++ b/screenlib/UIManager.h
@@ -50,6 +50,7 @@ class UIManager : public UIArea
 	bool LoadPanels();
 	UIPanel *LoadPanel(const char *name);
 	UIPanel *GetPanel(const char *name);
+	UIPanel *GetCurrentPanel();
 
 	/* These are called by the UIPanel class */
 	void AddPanel(UIPanel *panel) {