Maelstrom: Switched over the main menu to the new UI system

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

From c79d7c2d1c0e8dd1f3143c42c2e79ef9cb09f96b Mon Sep 17 00:00:00 2001
From: Sam Lantinga <[EMAIL REDACTED]>
Date: Mon, 24 Oct 2011 21:03:04 -0400
Subject: [PATCH] Switched over the main menu to the new UI system

---
 Maelstrom.spec                 |   2 +-
 Maelstrom_Globals.h            |   5 +
 Makefile.am                    |   2 +
 UI/main.xml                    | 292 +++++++++++++++++++++
 UIElementKeyButton.cpp         |  48 ++++
 UIElementKeyButton.h           |  36 +++
 UIElementLabel.cpp             |  28 ++
 UIElementLabel.h               |  19 +-
 UIElementTitle.cpp             |   2 +
 UIElementTitle.h               |  15 ++
 UIElements.cpp                 |   6 +
 UIElements.h                   |   4 +-
 buttonlist.h                   |  66 -----
 configure.in                   |   2 +-
 init.cpp                       |   8 +-
 main.cpp                       | 460 +++++++++++++++------------------
 screenlib/Makefile.am          |   2 +
 screenlib/SDL_FrameBuf.cpp     |   2 +-
 screenlib/SDL_FrameBuf.h       |  10 +
 screenlib/UIElement.cpp        |   6 +-
 screenlib/UIElement.h          |  24 +-
 screenlib/UIElementButton.cpp  | 193 ++++++++++++++
 screenlib/UIElementButton.h    |  79 ++++++
 screenlib/UIElementLine.cpp    |   6 +
 screenlib/UIElementLine.h      |  15 ++
 screenlib/UIElementRect.cpp    |   3 +
 screenlib/UIElementRect.h      |  15 ++
 screenlib/UIElementTexture.cpp |   2 +
 screenlib/UIElementTexture.h   |  15 ++
 screenlib/UIPanel.h            |  15 +-
 30 files changed, 1045 insertions(+), 337 deletions(-)
 create mode 100644 UI/main.xml
 create mode 100644 UIElementKeyButton.cpp
 create mode 100644 UIElementKeyButton.h
 delete mode 100644 buttonlist.h
 create mode 100644 screenlib/UIElementButton.cpp
 create mode 100644 screenlib/UIElementButton.h

diff --git a/Maelstrom.spec b/Maelstrom.spec
index 3cdc3c70..36e2c6a8 100644
--- a/Maelstrom.spec
+++ b/Maelstrom.spec
@@ -1,6 +1,6 @@
 # Note that this is NOT a relocatable package
 %define name Maelstrom
-%define version 3.0.6
+%define version 4.0.0
 %define release 1
 %define prefix /usr
 
diff --git a/Maelstrom_Globals.h b/Maelstrom_Globals.h
index 62062bb4..89829976 100644
--- a/Maelstrom_Globals.h
+++ b/Maelstrom_Globals.h
@@ -5,6 +5,8 @@
 #include "Mac_FontServ.h"
 #include "Mac_Sound.h"
 #include "Mac_Compat.h"
+#include "UIManager.h"
+#include "UIPanel.h"
 
 #include "Maelstrom.h"
 
@@ -32,6 +34,9 @@ extern Sound *sound;
 // The SCREEN!! :)
 extern FrameBuf *screen;
 
+// The UI system
+extern UIManager *ui;
+
 /* Boolean type */
 typedef Uint8 Bool;
 #ifndef true
diff --git a/Makefile.am b/Makefile.am
index f2728669..732e7897 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -29,6 +29,8 @@ Maelstrom_SOURCES =		\
 	rect.h			\
 	scores.cpp		\
 	scores.h		\
+	UIElementKeyButton.cpp	\
+	UIElementKeyButton.h	\
 	UIElementLabel.cpp	\
 	UIElementLabel.h	\
 	UIElementTitle.cpp	\
diff --git a/UI/main.xml b/UI/main.xml
new file mode 100644
index 00000000..9a66d696
--- /dev/null
+++ b/UI/main.xml
@@ -0,0 +1,292 @@
+<UIPanel>
+	<Elements>
+		<Title name="image" id="129">
+			<Anchor anchorFrom="TOPLEFT" anchorTo="CENTER" x="-251" y="-187"/>
+		</Title>
+
+		<!-- 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"/>
+			<Size w="1" h="384"/>
+			<Anchor anchorFrom="CENTER" anchorTo="CENTER" x="42"/>
+		</Line>
+		<Line name="hdivider_left">
+			<Color r="0x9C" g="0x9C" b="0xFF"/>
+			<Size w="298" h="1"/>
+			<Anchor anchorFrom="RIGHT" anchorTo="TOPLEFT" anchor="vertical_divider" y="153"/>
+		</Line>
+		<Line name="hdivider_right">
+			<Color r="0x9C" g="0x9C" b="0xFF"/>
+			<Size w="214" h="1"/>
+			<Anchor anchorFrom="LEFT" anchorTo="TOPRIGHT" anchor="vertical_divider" y="263"/>
+		</Line>
+
+		<!-- high scores -->
+		<Label name="name_header" fontName="New York" fontSize="18" fontStyle="UNDERLINE" text="Name">
+			<Color r="0xFF" g="0xFF" b="0x00"/>
+			<Anchor anchorFrom="BOTTOMLEFT" anchorTo="BOTTOMLEFT" anchor="hdivider_left" x="5" y="23"/>
+		</Label>
+		<Label name="score_header" fontName="New York" fontSize="18" fontStyle="UNDERLINE" text="Score">
+			<Color r="0xFF" g="0xFF" b="0x00"/>
+			<Anchor anchorFrom="BOTTOMLEFT" anchorTo="BOTTOMLEFT" anchor="hdivider_left" x="185" y="23"/>
+		</Label>
+		<Label name="wave_header" fontName="New York" fontSize="18" fontStyle="UNDERLINE" text="Wave">
+			<Color r="0xFF" g="0xFF" b="0x00"/>
+			<Anchor anchorFrom="BOTTOMLEFT" anchorTo="BOTTOMLEFT" anchor="hdivider_left" x="245" y="23"/>
+		</Label>
+
+		<Label name="name_0" fontName="New York" fontSize="14" fontStyle="BOLD">
+			<Color r="0x75" g="0x75" b="0x00"/>
+			<Anchor anchorFrom="TOPLEFT" anchorTo="TOPLEFT" anchor="name_header" y="24"/>
+		</Label>
+		<Label name="score_0" fontName="New York" fontSize="14" fontStyle="BOLD">
+			<Color r="0x75" g="0x75" b="0x00"/>
+			<Anchor anchorFrom="TOPRIGHT" anchorTo="TOPRIGHT" anchor="score_header" y="24"/>
+		</Label>
+		<Label name="wave_0" fontName="New York" fontSize="14" fontStyle="BOLD">
+			<Color r="0x75" g="0x75" b="0x00"/>
+			<Anchor anchorFrom="TOPRIGHT" anchorTo="TOPRIGHT" anchor="wave_header" x="-10" y="24"/>
+		</Label>
+		<Label name="name_1" fontName="New York" fontSize="14" fontStyle="BOLD">
+			<Color r="0x75" g="0x75" b="0x00"/>
+			<Anchor anchorFrom="TOPLEFT" anchorTo="TOPLEFT" anchor="name_0" y="18"/>
+		</Label>
+		<Label name="score_1" fontName="New York" fontSize="14" fontStyle="BOLD">
+			<Color r="0x75" g="0x75" b="0x00"/>
+			<Anchor anchorFrom="TOPRIGHT" anchorTo="TOPRIGHT" anchor="score_0" y="18"/>
+		</Label>
+		<Label name="wave_1" fontName="New York" fontSize="14" fontStyle="BOLD">
+			<Color r="0x75" g="0x75" b="0x00"/>
+			<Anchor anchorFrom="TOPRIGHT" anchorTo="TOPRIGHT" anchor="wave_0" y="18"/>
+		</Label>
+		<Label name="name_2" fontName="New York" fontSize="14" fontStyle="BOLD">
+			<Color r="0x75" g="0x75" b="0x00"/>
+			<Anchor anchorFrom="TOPLEFT" anchorTo="TOPLEFT" anchor="name_1" y="18"/>
+		</Label>
+		<Label name="score_2" fontName="New York" fontSize="14" fontStyle="BOLD">
+			<Color r="0x75" g="0x75" b="0x00"/>
+			<Anchor anchorFrom="TOPRIGHT" anchorTo="TOPRIGHT" anchor="score_1" y="18"/>
+		</Label>
+		<Label name="wave_2" fontName="New York" fontSize="14" fontStyle="BOLD">
+			<Color r="0x75" g="0x75" b="0x00"/>
+			<Anchor anchorFrom="TOPRIGHT" anchorTo="TOPRIGHT" anchor="wave_1" y="18"/>
+		</Label>
+		<Label name="name_3" fontName="New York" fontSize="14" fontStyle="BOLD">
+			<Color r="0x75" g="0x75" b="0x00"/>
+			<Anchor anchorFrom="TOPLEFT" anchorTo="TOPLEFT" anchor="name_2" y="18"/>
+		</Label>
+		<Label name="score_3" fontName="New York" fontSize="14" fontStyle="BOLD">
+			<Color r="0x75" g="0x75" b="0x00"/>
+			<Anchor anchorFrom="TOPRIGHT" anchorTo="TOPRIGHT" anchor="score_2" y="18"/>
+		</Label>
+		<Label name="wave_3" fontName="New York" fontSize="14" fontStyle="BOLD">
+			<Color r="0x75" g="0x75" b="0x00"/>
+			<Anchor anchorFrom="TOPRIGHT" anchorTo="TOPRIGHT" anchor="wave_2" y="18"/>
+		</Label>
+		<Label name="name_4" fontName="New York" fontSize="14" fontStyle="BOLD">
+			<Color r="0x75" g="0x75" b="0x00"/>
+			<Anchor anchorFrom="TOPLEFT" anchorTo="TOPLEFT" anchor="name_3" y="18"/>
+		</Label>
+		<Label name="score_4" fontName="New York" fontSize="14" fontStyle="BOLD">
+			<Color r="0x75" g="0x75" b="0x00"/>
+			<Anchor anchorFrom="TOPRIGHT" anchorTo="TOPRIGHT" anchor="score_3" y="18"/>
+		</Label>
+		<Label name="wave_4" fontName="New York" fontSize="14" fontStyle="BOLD">
+			<Color r="0x75" g="0x75" b="0x00"/>
+			<Anchor anchorFrom="TOPRIGHT" anchorTo="TOPRIGHT" anchor="wave_3" y="18"/>
+		</Label>
+		<Label name="name_5" fontName="New York" fontSize="14" fontStyle="BOLD">
+			<Color r="0x75" g="0x75" b="0x00"/>
+			<Anchor anchorFrom="TOPLEFT" anchorTo="TOPLEFT" anchor="name_4" y="18"/>
+		</Label>
+		<Label name="score_5" fontName="New York" fontSize="14" fontStyle="BOLD">
+			<Color r="0x75" g="0x75" b="0x00"/>
+			<Anchor anchorFrom="TOPRIGHT" anchorTo="TOPRIGHT" anchor="score_4" y="18"/>
+		</Label>
+		<Label name="wave_5" fontName="New York" fontSize="14" fontStyle="BOLD">
+			<Color r="0x75" g="0x75" b="0x00"/>
+			<Anchor anchorFrom="TOPRIGHT" anchorTo="TOPRIGHT" anchor="wave_4" y="18"/>
+		</Label>
+		<Label name="name_6" fontName="New York" fontSize="14" fontStyle="BOLD">
+			<Color r="0x75" g="0x75" b="0x00"/>
+			<Anchor anchorFrom="TOPLEFT" anchorTo="TOPLEFT" anchor="name_5" y="18"/>
+		</Label>
+		<Label name="score_6" fontName="New York" fontSize="14" fontStyle="BOLD">
+			<Color r="0x75" g="0x75" b="0x00"/>
+			<Anchor anchorFrom="TOPRIGHT" anchorTo="TOPRIGHT" anchor="score_5" y="18"/>
+		</Label>
+		<Label name="wave_6" fontName="New York" fontSize="14" fontStyle="BOLD">
+			<Color r="0x75" g="0x75" b="0x00"/>
+			<Anchor anchorFrom="TOPRIGHT" anchorTo="TOPRIGHT" anchor="wave_5" y="18"/>
+		</Label>
+		<Label name="name_7" fontName="New York" fontSize="14" fontStyle="BOLD">
+			<Color r="0x75" g="0x75" b="0x00"/>
+			<Anchor anchorFrom="TOPLEFT" anchorTo="TOPLEFT" anchor="name_6" y="18"/>
+		</Label>
+		<Label name="score_7" fontName="New York" fontSize="14" fontStyle="BOLD">
+			<Color r="0x75" g="0x75" b="0x00"/>
+			<Anchor anchorFrom="TOPRIGHT" anchorTo="TOPRIGHT" anchor="score_6" y="18"/>
+		</Label>
+		<Label name="wave_7" fontName="New York" fontSize="14" fontStyle="BOLD">
+			<Color r="0x75" g="0x75" b="0x00"/>
+			<Anchor anchorFrom="TOPRIGHT" anchorTo="TOPRIGHT" anchor="wave_6" y="18"/>
+		</Label>
+		<Label name="name_8" fontName="New York" fontSize="14" fontStyle="BOLD">
+			<Color r="0x75" g="0x75" b="0x00"/>
+			<Anchor anchorFrom="TOPLEFT" anchorTo="TOPLEFT" anchor="name_7" y="18"/>
+		</Label>
+		<Label name="score_8" fontName="New York" fontSize="14" fontStyle="BOLD">
+			<Color r="0x75" g="0x75" b="0x00"/>
+			<Anchor anchorFrom="TOPRIGHT" anchorTo="TOPRIGHT" anchor="score_7" y="18"/>
+		</Label>
+		<Label name="wave_8" fontName="New York" fontSize="14" fontStyle="BOLD">
+			<Color r="0x75" g="0x75" b="0x00"/>
+			<Anchor anchorFrom="TOPRIGHT" anchorTo="TOPRIGHT" anchor="wave_7" y="18"/>
+		</Label>
+		<Label name="name_9" fontName="New York" fontSize="14" fontStyle="BOLD">
+			<Color r="0x75" g="0x75" b="0x00"/>
+			<Anchor anchorFrom="TOPLEFT" anchorTo="TOPLEFT" anchor="name_8" y="18"/>
+		</Label>
+		<Label name="score_9" fontName="New York" fontSize="14" fontStyle="BOLD">
+			<Color r="0x75" g="0x75" b="0x00"/>
+			<Anchor anchorFrom="TOPRIGHT" anchorTo="TOPRIGHT" anchor="score_8" y="18"/>
+		</Label>
+		<Label name="wave_9" fontName="New York" fontSize="14" fontStyle="BOLD">
+			<Color r="0x75" g="0x75" b="0x00"/>
+			<Anchor anchorFrom="TOPRIGHT" anchorTo="TOPRIGHT" anchor="wave_8" y="18"/>
+		</Label>
+
+		<Label name="last_score_label" fontName="New York" fontSize="18" text="Last Score: ">
+			<Color r="0xFF" g="0xFF" b="0xFF"/>
+			<Anchor anchorFrom="BOTTOMLEFT" anchorTo="BOTTOMLEFT" anchor="hdivider_left" x="5" y="230"/>
+		</Label>
+		<Label name="last_score" fontName="New York" fontSize="18">
+			<Color r="0xFF" g="0xFF" b="0xFF"/>
+			<Anchor anchorFrom="LEFT" anchorTo="RIGHT" anchor="last_score_label"/>
+		</Label>
+
+		<!-- Instructions -->
+		<KeyButton name="PlayButton" hotkey="P">
+			<Anchor anchorFrom="TOPLEFT" anchorTo="TOPRIGHT" anchor="vertical_divider" x="9" y="10"/>
+		</KeyButton>
+		<Label fontName="Geneva" fontSize="9" fontStyle="BOLD" text=" Start playing Maelstrom">
+			<Color r="0xFF" g="0xFF" b="0x00"/>
+			<Anchor anchorFrom="BOTTOMLEFT" anchorTo="TOPRIGHT" anchor="PlayButton" x="3" y="21"/>
+		</Label>
+		<KeyButton name="ControlsButton" hotkey="C">
+			<Anchor anchorFrom="TOPLEFT" anchorTo="TOPLEFT" anchor="PlayButton" y="34"/>
+		</KeyButton>
+		<Label fontName="Geneva" fontSize="9" fontStyle="BOLD" text=" Configure the game controls">
+			<Color r="0xFF" g="0xFF" b="0x00"/>
+			<Anchor anchorFrom="BOTTOMLEFT" anchorTo="TOPRIGHT" anchor="ControlsButton" x="3" y="21"/>
+		</Label>
+		<KeyButton name="ZapButton" hotkey="Z">
+			<Anchor anchorFrom="TOPLEFT" anchorTo="TOPLEFT" anchor="ControlsButton" y="34"/>
+		</KeyButton>
+		<Label fontName="Geneva" fontSize="9" fontStyle="BOLD" text=" Zap the high scores">
+			<Color r="0xFF" g="0xFF" b="0x00"/>
+			<Anchor anchorFrom="BOTTOMLEFT" anchorTo="TOPRIGHT" anchor="ZapButton" x="3" y="21"/>
+		</Label>
+		<KeyButton name="AboutButton" hotkey="A">
+			<Anchor anchorFrom="TOPLEFT" anchorTo="TOPLEFT" anchor="ZapButton" y="34"/>
+		</KeyButton>
+		<Label fontName="Geneva" fontSize="9" fontStyle="BOLD" text=" About Maelstrom...">
+			<Color r="0xFF" g="0xFF" b="0x00"/>
+			<Anchor anchorFrom="BOTTOMLEFT" anchorTo="TOPRIGHT" anchor="AboutButton" x="3" y="21"/>
+		</Label>
+		<KeyButton name="QuitButton" hotkey="Q">
+			<Anchor anchorFrom="TOPLEFT" anchorTo="TOPLEFT" anchor="AboutButton" y="68"/>
+		</KeyButton>
+		<Label fontName="Geneva" fontSize="9" fontStyle="BOLD" text=" Quit Maelstrom">
+			<Color r="0xFF" g="0xFF" b="0x00"/>
+			<Anchor anchorFrom="BOTTOMLEFT" anchorTo="TOPRIGHT" anchor="QuitButton" x="3" y="21"/>
+		</Label>
+		<KeyButton name="VolumeDownButton" hotkey="0">
+			<Anchor anchorFrom="TOPLEFT" anchorTo="TOPLEFT" anchor="QuitButton" y="34"/>
+		</KeyButton>
+		<Label fontName="Geneva" fontSize="9" fontStyle="BOLD" text="-">
+			<Color r="0xFF" g="0xFF" b="0x00"/>
+			<Anchor anchorFrom="BOTTOMLEFT" anchorTo="TOPRIGHT" anchor="VolumeDownButton" x="3" y="21"/>
+		</Label>
+		<KeyButton name="VolumeUpButton" hotkey="8">
+			<Anchor anchorFrom="TOPLEFT" anchorTo="TOPLEFT" anchor="VolumeDownButton" x="40"/>
+		</KeyButton>
+		<Label fontName="Geneva" fontSize="9" fontStyle="BOLD" text=" Set Sound Volume">
+			<Color r="0xFF" g="0xFF" b="0x00"/>
+			<Anchor anchorFrom="BOTTOMLEFT" anchorTo="TOPRIGHT" anchor="VolumeUpButton" x="3" y="21"/>
+		</Label>
+
+		<!-- Hidden action buttons -->
+		<Button name="ToggleFullscreen" hotkey="ALT-Return"/>
+		<Button name="Cheat" hotkey="L"/>
+		<Button name="Special" hotkey="X"/>
+		<Button name="Screenshot" hotkey="F3"/>
+		<Button name="SetVolume0" hotkey="0"/>
+		<Button name="SetVolume1" hotkey="1"/>
+		<Button name="SetVolume2" hotkey="2"/>
+		<Button name="SetVolume3" hotkey="3"/>
+		<Button name="SetVolume4" hotkey="4"/>
+		<Button name="SetVolume5" hotkey="5"/>
+		<Button name="SetVolume6" hotkey="6"/>
+		<Button name="SetVolume7" hotkey="7"/>
+		<Button name="SetVolume8" hotkey="8"/>
+
+		<!-- Credits -->
+		<Label fontName="Geneva" fontSize="9" fontStyle="BOLD" text="Port to SDL by Sam Lantinga">
+			<Color r="0xFF" g="0xFF" b="0x00"/>
+			<Anchor anchorFrom="CENTER" anchorTo="CENTER" anchor="image" y="52"/>
+		</Label>
+		<Label fontName="Geneva" fontSize="9" fontStyle="BOLD" text="1992-4 Ambrosia Software, Inc.">
+	
+			<Color r="0xFF" g="0xFF" b="0xFF"/>
+			<Anchor anchorFrom="BOTTOMLEFT" anchorTo="TOPLEFT" anchor="hdivider_right" x="9" y="-2"/>
+		</Label>
+		<Label name="version" fontName="Geneva" fontSize="9">
+			<Color r="0xFF" g="0xFF" b="0xFF"/>
+			<Anchor anchorFrom="BOTTOMLEFT" anchorTo="TOPLEFT" anchor="image" x="15" y="148"/>
+		</Label>
+
+		<!-- Sound level -->
+		<Label name="volume" fontName="Geneva" fontSize="9" fontStyle="BOLD">
+			<Color r="0x75" g="0x75" b="0xFF"/>
+			<Anchor anchorFrom="BOTTOMLEFT" anchorTo="TOPLEFT" anchor="VolumeDownButton" x="-6" y="22"/>
+		</Label>
+	</Elements>
+</UIPanel>
diff --git a/UIElementKeyButton.cpp b/UIElementKeyButton.cpp
new file mode 100644
index 00000000..0182d55c
--- /dev/null
+++ b/UIElementKeyButton.cpp
@@ -0,0 +1,48 @@
+
+#include "UIElementKeyButton.h"
+#include "Maelstrom_Globals.h"
+
+UIElementType UIElementKeyButton::s_elementType;
+
+UIElementKeyButton::UIElementKeyButton(UIPanel *panel, const char *name) :
+	UIElementButton(panel, name)
+{
+	m_text = NULL;
+}
+
+UIElementKeyButton::~UIElementKeyButton()
+{
+	if (m_text) {
+		fontserv->FreeText(m_text);
+	}
+}
+
+bool
+UIElementKeyButton::Load(rapidxml::xml_node<> *node)
+{
+	m_rect.w = m_screen->GetImageWidth(gKeyIcon);
+	m_rect.h = m_screen->GetImageHeight(gKeyIcon);
+
+	if (!UIElementButton::Load(node)) {
+		return false;
+	}
+
+	if (m_hotkey != SDLK_UNKNOWN) {
+		m_text = fontserv->TextImage(SDL_GetKeyName(m_hotkey),
+				fonts[GENEVA_9], STYLE_BOLD, 0xFF, 0xFF, 0xFF);
+	}
+}
+
+void
+UIElementKeyButton::Draw()
+{
+	m_screen->QueueBlit(m_rect.x, m_rect.y, gKeyIcon, NOCLIP);
+#ifdef UI_DEBUG
+printf("KeyButton: %s at %d,%d\n", SDL_GetKeyName(m_hotkey), m_rect.x+14, m_rect.y+10);
+printf("KeyButton: %s at %d,%d\n", SDL_GetKeyName(m_hotkey), m_rect.x+13, m_rect.y+9);
+#endif
+	SDL_SetTextureColorMod(m_text, 0xFF, 0xFF, 0xFF);
+	m_screen->QueueBlit(m_rect.x+14, m_rect.y+10, m_text, NOCLIP);
+	SDL_SetTextureColorMod(m_text, 0x00, 0x00, 0x00);
+	m_screen->QueueBlit(m_rect.x+13, m_rect.y+9, m_text, NOCLIP);
+}
diff --git a/UIElementKeyButton.h b/UIElementKeyButton.h
new file mode 100644
index 00000000..157fe79e
--- /dev/null
+++ b/UIElementKeyButton.h
@@ -0,0 +1,36 @@
+#ifndef _UIElementKeyButton_h
+#define _UIElementKeyButton_h
+
+#include "screenlib/UIElementButton.h"
+
+
+class UIElementKeyButton : public UIElementButton
+{
+public:
+	UIElementKeyButton(UIPanel *panel, const char *name = "");
+	virtual ~UIElementKeyButton();
+
+	virtual bool IsA(UIElementType type) {
+		return UIElementButton::IsA(type) || type == GetType();
+	}
+
+	virtual bool Load(rapidxml::xml_node<> *node);
+
+	virtual void Draw();
+
+protected:
+	SDL_Texture *m_text;
+
+protected:
+	static UIElementType s_elementType;
+
+public:
+	static UIElementType GetType() {
+		if (!s_elementType) {
+			s_elementType = GenerateType();
+		}
+		return s_elementType;
+	}
+};
+
+#endif // _UIElementKeyButton_h
diff --git a/UIElementLabel.cpp b/UIElementLabel.cpp
index 83082259..e75c0bd3 100644
--- a/UIElementLabel.cpp
+++ b/UIElementLabel.cpp
@@ -2,6 +2,8 @@
 #include "UIElementLabel.h"
 #include "Maelstrom_Globals.h"
 
+UIElementType UIElementLabel::s_elementType;
+
 
 UIElementLabel::UIElementLabel(UIPanel *panel, const char *name) :
 	UIElement(panel, name)
@@ -10,6 +12,9 @@ UIElementLabel::UIElementLabel(UIPanel *panel, const char *name) :
 	m_style = STYLE_NORM;
 	m_color = m_screen->MapRGB(0xFF, 0xFF, 0xFF);
 	m_texture = NULL;
+#ifdef UI_DEBUG
+m_text = NULL;
+#endif
 }
 
 UIElementLabel::~UIElementLabel()
@@ -76,7 +81,14 @@ UIElementLabel::Load(rapidxml::xml_node<> *node)
 		SetText(attr->value());
 	}
 
+#ifdef UI_DEBUG
+	bool value = UIElement::Load(node);
+if (m_text)
+printf("Label: '%s' %d,%d\n", m_text, m_rect.x, m_rect.y);
+	return value;
+#else
 	return UIElement::Load(node);
+#endif
 }
 
 void
@@ -86,10 +98,26 @@ UIElementLabel::SetText(const char *text)
 		fontserv->FreeText(m_texture);
 	}
 
+#ifdef UI_DEBUG
+m_text = strdup(text);
+#endif
 	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();
+#ifdef UI_DEBUG
+if (m_rect.x)
+printf("Label: '%s' %d,%d\n", m_text, m_rect.x, m_rect.y);
+#endif
+}
+
+void
+UIElementLabel::SetTextColor(Uint8 R, Uint8 G, Uint8 B)
+{
+	if (m_texture) {
+		SDL_SetTextureColorMod(m_texture, R, G, B);
+	}
+	m_color = m_screen->MapRGB(R, G, B);
 }
 
 void
diff --git a/UIElementLabel.h b/UIElementLabel.h
index 62362ce6..81abc33a 100644
--- a/UIElementLabel.h
+++ b/UIElementLabel.h
@@ -11,9 +11,14 @@ class UIElementLabel : public UIElement
 	UIElementLabel(UIPanel *panel, const char *name = "");
 	virtual ~UIElementLabel();
 
+	virtual bool IsA(UIElementType type) {
+		return UIElement::IsA(type) || type == GetType();
+	}
+
 	virtual bool Load(rapidxml::xml_node<> *node);
 
-	virtual void SetText(const char *text);
+	void SetText(const char *text);
+	void SetTextColor(Uint8 R, Uint8 G, Uint8 B);
 
 	virtual void Draw();
 
@@ -22,6 +27,18 @@ class UIElementLabel : public UIElement
 	Uint8 m_style;
 	Uint32 m_color;
 	SDL_Texture *m_texture;
+char *m_text;
+
+protected:
+	static UIElementType s_elementType;
+
+public:
+	static UIElementType GetType() {
+		if (!s_elementType) {
+			s_elementType = GenerateType();
+		}
+		return s_elementType;
+	}
 };
 
 #endif // _UIElementLabel_h
diff --git a/UIElementTitle.cpp b/UIElementTitle.cpp
index 85236694..19d2a61c 100644
--- a/UIElementTitle.cpp
+++ b/UIElementTitle.cpp
@@ -2,6 +2,8 @@
 #include "UIElementTitle.h"
 #include "load.h"
 
+UIElementType UIElementTitle::s_elementType;
+
 
 UIElementTitle::UIElementTitle(UIPanel *panel, const char *name) :
 	UIElementTexture(panel, name)
diff --git a/UIElementTitle.h b/UIElementTitle.h
index f095d74a..491d1987 100644
--- a/UIElementTitle.h
+++ b/UIElementTitle.h
@@ -9,7 +9,22 @@ class UIElementTitle : public UIElementTexture
 public:
 	UIElementTitle(UIPanel *panel, const char *name = "");
 
+	virtual bool IsA(UIElementType type) {
+		return UIElementTexture::IsA(type) || type == GetType();
+	}
+
 	virtual bool Load(rapidxml::xml_node<> *node);
+
+protected:
+	static UIElementType s_elementType;
+
+public:
+	static UIElementType GetType() {
+		if (!s_elementType) {
+			s_elementType = GenerateType();
+		}
+		return s_elementType;
+	}
 };
 
 #endif // _UIElementTitle_h
diff --git a/UIElements.cpp b/UIElements.cpp
index e23da483..cbfa0af5 100644
--- a/UIElements.cpp
+++ b/UIElements.cpp
@@ -1,7 +1,9 @@
 
 #include "UIElements.h"
+#include "screenlib/UIElementButton.h"
 #include "screenlib/UIElementLine.h"
 #include "screenlib/UIElementRect.h"
+#include "UIElementKeyButton.h"
 #include "UIElementLabel.h"
 #include "UIElementTitle.h"
 
@@ -15,8 +17,12 @@ CreateMaelstromUIElement(UIPanel *panel, const char *name)
 		return new UIElementRect(panel);
 	} else if (strcasecmp(name, "Label") == 0) {
 		return new UIElementLabel(panel);
+	} else if (strcasecmp(name, "Button") == 0) {
+		return new UIElementButton(panel);
 	} else if (strcasecmp(name, "Title") == 0) {
 		return new UIElementTitle(panel);
+	} else if (strcasecmp(name, "KeyButton") == 0) {
+		return new UIElementKeyButton(panel);
 	}
 	return NULL;
 }
diff --git a/UIElements.h b/UIElements.h
index 7347f2f6..d721dae9 100644
--- a/UIElements.h
+++ b/UIElements.h
@@ -1,8 +1,8 @@
 #ifndef _UIElements_h
 #define _UIElements_h
 
-#include "screenlib/UIManager.h"
-#include "screenlib/UIPanel.h"
+class UIPanel;
+class UIElement;
 
 UIElement *CreateMaelstromUIElement(UIPanel *panel, const char *name);
 
diff --git a/buttonlist.h b/buttonlist.h
deleted file mode 100644
index 3a17f78c..00000000
--- a/buttonlist.h
+++ /dev/null
@@ -1,66 +0,0 @@
-
-/*  A simple menu button class -- only handles mouse input */
-
-#include "SDL_types.h"
-
-
-class ButtonList {
-
-public:
-	ButtonList() {
-		button_list.next = NULL;
-	}
-	~ButtonList() {
-		Delete_Buttons();
-	}
-
-	void Add_Button(Uint16 x, Uint16 y, Uint16 width, Uint16 height, 
-						void (*callback)(void)) {
-		struct button *belem;
-		
-		for ( belem=&button_list; belem->next; belem=belem->next );
-		belem->next = new button;
-		belem = belem->next;
-		belem->x1 = x;
-		belem->y1 = y;
-		belem->x2 = x+width;
-		belem->y2 = y+height;
-		belem->callback = callback;
-		belem->next = NULL;
-	}
-
-	void Activate_Button(Uint16 x, Uint16 y) {
-		struct button *belem;
-
-		for ( belem=button_list.next; belem; belem=belem->next ) {
-			if ( (x >= belem->x1) && (x <= belem->x2) &&
-			     (y >= belem->y1) && (y <= belem->y2) ) {
-				if ( belem->callback ) {
-					(*belem->callback)();
-					return;
-				}
-			}
-		}
-	}
-
-	void Delete_Buttons(void) {
-		struct button *belem, *btemp;
-
-		for ( belem=button_list.next; belem; ) {
-			btemp = belem;
-			belem = belem->next;
-			delete btemp;
-		};
-		button_list.next = NULL;
-	}
-	
-private:
-	typedef struct button {
-		/* Sensitive area */
-		Uint16 x1, y1;
-		Uint16 x2, y2;
-		void (*callback)(void);
-		struct button *next;
-	} button;
-	button button_list;
-};
diff --git a/configure.in b/configure.in
index 8511cc95..a4a8e7eb 100644
--- a/configure.in
+++ b/configure.in
@@ -6,7 +6,7 @@ AC_CANONICAL_HOST
 AC_CANONICAL_TARGET
 
 dnl Setup for automake
-AM_INIT_AUTOMAKE(Maelstrom, 3.0.6)
+AM_INIT_AUTOMAKE(Maelstrom, 4.0.0)
 
 dnl Check for tools
 
diff --git a/init.cpp b/init.cpp
index 4412c3d1..d093d017 100644
--- a/init.cpp
+++ b/init.cpp
@@ -71,11 +71,15 @@ void DoSplash(void)
 
 static void DrawLoadBar(int stage)
 {
-	UIElement *progress;
+	UIPanel *panel;
+	UIElement *progress = NULL;
 	int fact;
 	const int FULL_WIDTH = 196;
 
-	progress = ui->GetCurrentPanel()->GetElement("progress");
+	panel = ui->GetCurrentPanel();
+	if (panel) {
+		progress = panel->GetElement<UIElement>("progress");
+	}
 	if (progress) {
 		fact = (FULL_WIDTH * stage) / MAX_BAR;
 		progress->SetWidth(fact);
diff --git a/main.cpp b/main.cpp
index 0810fffc..ab61b262 100644
--- a/main.cpp
+++ b/main.cpp
@@ -16,6 +16,9 @@
 #include "fastrand.h"
 #include "checksum.h"
 
+#include "UIElementLabel.h"
+#include "UIElementKeyButton.h"
+
 /* External functions used in this file */
 extern int DoInitializations(Uint32 window_flags, Uint32 render_flags);	/* init.cpp */
 extern void CleanUp(void);
@@ -30,13 +33,9 @@ Bool	gUpdateBuffer;
 Bool	gRunning;
 int	gNoDelay;
 
-// Local variables in this file...
-static ButtonList buttons;
-
 // Local functions in this file...
-static void DrawMainScreen(bool fade);
-static void DrawSoundLevel(void);
-static void DrawKey(MPoint *pt, const char *ch, const char *str, void (*callback)(void));
+static void SetupMainScreen(void);
+static void DrawMainScreen(void);
 
 // Main Menu actions:
 static void RunDoAbout(void)
@@ -60,7 +59,6 @@ static void RunPlayGame(void)
 	sound->PlaySound(gNewLife, 5);
 	Delay(SOUND_DELAY);
 	NewGame();
-	Message(NULL);		/* Clear any messages */
 }
 static void RunQuitGame(void)
 {
@@ -77,7 +75,7 @@ static void IncrementSound(void)
 		sound->PlaySound(gNewLife, 5);
 
 		/* -- Draw the new sound level */
-		DrawMainScreen(false);
+		gUpdateBuffer = true;
 	}
 }
 static void DecrementSound(void)
@@ -87,7 +85,7 @@ static void DecrementSound(void)
 		sound->PlaySound(gNewLife, 5);
 
 		/* -- Draw the new sound level */
-		DrawMainScreen(false);
+		gUpdateBuffer = true;
 	}
 }
 static void SetSoundLevel(int volume)
@@ -100,9 +98,8 @@ static void SetSoundLevel(int volume)
 	sound->PlaySound(gNewLife, 5);
 
 	/* -- Draw the new sound level */
-	DrawMainScreen(false);
+	gUpdateBuffer = true;
 }
-
 static void RunZapScores(void)
 {
 	Delay(SOUND_DELAY);
@@ -115,6 +112,44 @@ static void RunZapScores(void)
 		gUpdateBuffer = true;
 	}
 }
+static void RunToggleFullscreen(void)
+{
+	screen->ToggleFullScreen();
+}
+static void RunCheat(void)
+{
+	Delay(SOUND_DELAY);
+	sound->PlaySound(gLuckySound, 5);
+	gStartLevel = GetStartLevel();
+	if ( gStartLevel > 0 ) {
+		Delay(SOUND_DELAY);
+		sound->PlaySound(gNewLife, 5);
+		Delay(SOUND_DELAY);
+		NewGame();
+	}
+}
+static void RunSpecial(void)
+{
+	Delay(SOUND_DELAY);
+	sound->PlaySound(gEnemyAppears, 5);
+	ShowDawn();
+}
+static void RunScreenshot(void)
+{
+	screen->ScreenDump("ScoreDump", 64, 48, 298, 384);
+}
+
+class SetVolumeCallback : public UIButtonCallback
+{
+public:
+	SetVolumeCallback(int volume) : m_volume(volume) { }
+
+	virtual void OnClick() {
+		SetSoundLevel(m_volume);
+	}
+private:
+	int m_volume;
+};
 
 /* ----------------------------------------------------------------- */
 /* -- Run a graphics speed test.                                     */
@@ -300,98 +335,31 @@ int main(int argc, char *argv[])
 		exit(0);
 	}
 
+	SetupMainScreen();
+
 	gRunning = true;
 	sound->PlaySound(gNovaBoom, 5);
 	Delay(SOUND_DELAY);
-	gUpdateBuffer = true;
 	while ( sound->Playing() )
 		Delay(SOUND_DELAY);
+	ui->ShowPanel(PANEL_MAIN);
 
 	while ( gRunning ) {
 		
 		/* Update the screen if necessary */
 		if ( gUpdateBuffer )
-			DrawMainScreen(true);
+			DrawMainScreen();
 
 		/* -- Get an event */
 		screen->WaitEvent(&event);
 
+		if ( ui->HandleEvent(event) )
+			continue;
+
 		/* -- Handle it! */
 		if ( event.type == SDL_KEYDOWN ) {
 			switch (event.key.keysym.sym) {
 
-				/* -- Toggle fullscreen */
-				case SDLK_RETURN:
-					if ( event.key.keysym.mod & KMOD_ALT )
-						screen->ToggleFullScreen();
-					break;
-
-				/* -- About the game...*/
-				case SDLK_a:
-					RunDoAbout();
-					break;
-
-				/* -- Configure the controls */
-				case SDLK_c:
-					RunConfigureControls();
-					break;
-
-				/* -- Start the game */
-				case SDLK_p:
-					RunPlayGame();
-					break;
-
-				/* -- Start the game */
-				case SDLK_l:
-					Delay(SOUND_DELAY);
-					sound->PlaySound(gLuckySound, 5);
-					gStartLevel = GetStartLevel();
-					if ( gStartLevel > 0 ) {
-						Delay(SOUND_DELAY);
-						sound->PlaySound(gNewLife, 5);
-						Delay(SOUND_DELAY);
-						NewGame();
-					}
-					break;
-
-				/* -- Let them leave */
-				case SDLK_q:
-					RunQuitGame();
-					break;
-
-				/* -- Set the volume */
-				/* (SDLK_0 - SDLK_8 are contiguous) */
-				case SDLK_0:
-				case SDLK_1:
-				case SDLK_2:
-				case SDLK_3:
-				case SDLK_4:
-				case SDLK_5:
-				case SDLK_6:
-				case SDLK_7:
-				case SDLK_8:
-					SetSoundLevel(event.key.keysym.sym
-								- SDLK_0);
-					break;
-
-				/* -- Give 'em a little taste of the peppers */
-				case SDLK_x:
-					Delay(SOUND_DELAY);
-					sound->PlaySound(gEnemyAppears, 5);
-					ShowDawn();
-					break;
-
-				/* -- Zap the high scores */
-				case SDLK_z:
-					RunZapScores();
-					break;
-						
-				/* -- Create a screen dump of high scores */
-				case SDLK_F3:
-					screen->ScreenDump("ScoreDump",
-							64, 48, 298, 384);
-					break;
-
 				// Ignore Shift, Ctrl, Alt keys
 				case SDLK_LSHIFT:
 				case SDLK_RSHIFT:
@@ -408,11 +376,6 @@ int main(int argc, char *argv[])
 					break;
 			}
 		} else
-		/* -- Handle mouse clicks */
-		if ( event.type == SDL_MOUSEBUTTONDOWN ) {
-			buttons.Activate_Button(event.button.x, 
-						event.button.y);
-		} else
 		/* -- Handle window close requests */
 		if ( event.type == SDL_QUIT ) {
 			RunQuitGame();
@@ -434,6 +397,9 @@ int DrawText(int x, int y, const char *text, MFont *font, Uint8 style,
 	if ( textimage == NULL ) {
 		width = 0;
 	} else {
+#ifdef UI_DEBUG
+printf("DrawText: %d,%d '%s'\n", x, y-screen->GetImageHeight(textimage)+2, text);
+#endif
 		screen->QueueBlit(x, y-screen->GetImageHeight(textimage)+2, textimage, NOCLIP);
 		width = screen->GetImageWidth(textimage);
 		fontserv->FreeText(textimage);
@@ -443,93 +409,128 @@ int DrawText(int x, int y, const char *text, MFont *font, Uint8 style,
 
 
 /* ----------------------------------------------------------------- */
-/* -- Draw the current sound volume */
-static void DrawSoundLevel(void)
+/

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