From c5cbf2bf7d8c6fc349ec776a85ec93afbc09ac62 Mon Sep 17 00:00:00 2001
From: Sam Lantinga <[EMAIL REDACTED]>
Date: Sat, 22 Oct 2011 17:15:45 -0400
Subject: [PATCH] Beginnings of a data driven UI system
---
Makefile.am | 4 +-
UIElements.cpp | 8 +
UIElements.h | 9 +
init.cpp | 3 +
screenlib/ErrorBase.h | 66 +
screenlib/Makefile.am | 11 +-
screenlib/SDL_FrameBuf.cpp | 12 +-
screenlib/SDL_FrameBuf.h | 37 +-
screenlib/UIArea.cpp | 170 +++
screenlib/UIArea.h | 95 ++
screenlib/UIElement.cpp | 52 +
screenlib/UIElement.h | 58 +
screenlib/UIManager.cpp | 55 +
screenlib/UIManager.h | 51 +
screenlib/UIPanel.cpp | 174 +++
screenlib/UIPanel.h | 81 ++
utils/array.h | 67 +
utils/rapidxml.h | 17 +
utils/rapidxml.hpp | 2617 ++++++++++++++++++++++++++++++++++++
19 files changed, 3546 insertions(+), 41 deletions(-)
create mode 100644 UIElements.cpp
create mode 100644 UIElements.h
create mode 100644 screenlib/ErrorBase.h
create mode 100644 screenlib/UIArea.cpp
create mode 100644 screenlib/UIArea.h
create mode 100644 screenlib/UIElement.cpp
create mode 100644 screenlib/UIElement.h
create mode 100644 screenlib/UIManager.cpp
create mode 100644 screenlib/UIManager.h
create mode 100644 screenlib/UIPanel.cpp
create mode 100644 screenlib/UIPanel.h
create mode 100644 utils/array.h
create mode 100644 utils/rapidxml.h
create mode 100755 utils/rapidxml.hpp
diff --git a/Makefile.am b/Makefile.am
index 32691048..8c541214 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -28,7 +28,9 @@ Maelstrom_SOURCES = \
rect.cpp \
rect.h \
scores.cpp \
- scores.h
+ scores.h \
+ UIElements.cpp \
+ UIElements.h
LOGIC = netlogic
diff --git a/UIElements.cpp b/UIElements.cpp
new file mode 100644
index 00000000..7079d8a9
--- /dev/null
+++ b/UIElements.cpp
@@ -0,0 +1,8 @@
+
+#include "UIElements.h"
+
+UIElement *
+CreateMaelstromUIElement(UIPanel *panel, const char *name)
+{
+ return NULL;
+}
diff --git a/UIElements.h b/UIElements.h
new file mode 100644
index 00000000..7347f2f6
--- /dev/null
+++ b/UIElements.h
@@ -0,0 +1,9 @@
+#ifndef _UIElements_h
+#define _UIElements_h
+
+#include "screenlib/UIManager.h"
+#include "screenlib/UIPanel.h"
+
+UIElement *CreateMaelstromUIElement(UIPanel *panel, const char *name);
+
+#endif // _UIElements_h
diff --git a/init.cpp b/init.cpp
index c7a67c23..5e112af2 100644
--- a/init.cpp
+++ b/init.cpp
@@ -8,6 +8,7 @@
#include "load.h"
#include "colortable.h"
#include "fastrand.h"
+#include "UIElements.h"
// Global variables set in this file...
@@ -15,6 +16,7 @@ Sound *sound = NULL;
FontServ *fontserv = NULL;
MFont *fonts[NUM_FONTS];
FrameBuf *screen = NULL;
+UIManager ui;
Sint32 gLastHigh;
Uint32 gLastDrawn;
@@ -782,6 +784,7 @@ int DoInitializations(Uint32 window_flags, Uint32 render_flags)
return(-1);
}
}
+ UIPanel::SetElementFactory(CreateMaelstromUIElement);
/* Load the Sound Server and initialize sound */
sound = new Sound("Maelstrom Sounds", gSoundLevel);
diff --git a/screenlib/ErrorBase.h b/screenlib/ErrorBase.h
new file mode 100644
index 00000000..6491eb55
--- /dev/null
+++ b/screenlib/ErrorBase.h
@@ -0,0 +1,66 @@
+/*
+ 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 _ErrorBase_h
+#define _ErrorBase_h
+
+#include <string.h>
+#include <stdarg.h>
+
+#define ERRORBASE_ERRSIZ 1024
+
+class ErrorBase {
+
+public:
+ ErrorBase() : errstr(NULL) { }
+ virtual ~ErrorBase() {
+ ClearError();
+ }
+
+ /* Error message routine */
+ char *Error(void) {
+ return(errstr);
+ }
+
+ void ClearError() {
+ if (errstr) {
+ delete[] errstr;
+ }
+ errstr = NULL;
+ }
+
+protected:
+ /* Error message */
+ void SetError(const char *fmt, ...) {
+ va_list ap;
+
+ va_start(ap, fmt);
+ if (!errstr) {
+ errstr = new char[ERRORBASE_ERRSIZ];
+ }
+ vsnprintf(errstr, ERRORBASE_ERRSIZ, fmt, ap);
+ va_end(ap);
+ }
+ char *errstr;
+};
+
+#endif /* _ErrorBase_h */
diff --git a/screenlib/Makefile.am b/screenlib/Makefile.am
index 3c5ce620..55b629de 100644
--- a/screenlib/Makefile.am
+++ b/screenlib/Makefile.am
@@ -2,5 +2,14 @@
noinst_LIBRARIES = libSDLscreen.a
libSDLscreen_a_SOURCES = \
+ ErrorBase.h \
SDL_FrameBuf.cpp \
- SDL_FrameBuf.h
+ SDL_FrameBuf.h \
+ UIArea.cpp \
+ UIArea.h \
+ UIElement.cpp \
+ UIElement.h \
+ UIManager.cpp \
+ UIManager.h \
+ UIPanel.cpp \
+ UIPanel.h
diff --git a/screenlib/SDL_FrameBuf.cpp b/screenlib/SDL_FrameBuf.cpp
index b5e3d9a5..9e97ba20 100644
--- a/screenlib/SDL_FrameBuf.cpp
+++ b/screenlib/SDL_FrameBuf.cpp
@@ -33,12 +33,11 @@
#define MAX(A, B) ((A > B) ? A : B)
/* Constructors cannot fail. :-/ */
-FrameBuf:: FrameBuf()
+FrameBuf:: FrameBuf() : UIArea()
{
/* Initialize various variables to null state */
window = NULL;
renderer = NULL;
- errstr = NULL;
faded = 0;
}
@@ -64,11 +63,12 @@ FrameBuf:: Init(int width, int height, Uint32 window_flags, Uint32 render_flags,
SDL_SetWindowIcon(window, icon);
}
+ /* Set the UI area */
+ m_rect.w = width;
+ m_rect.h = height;
+
/* Set the blit clipping rectangle */
- clip.x = 0;
- clip.y = 0;
- clip.w = width;
- clip.h = height;
+ clip = m_rect;
/* Copy the image colormap */
if ( colors ) {
diff --git a/screenlib/SDL_FrameBuf.h b/screenlib/SDL_FrameBuf.h
index 6f2d2bf5..4b2667d4 100644
--- a/screenlib/SDL_FrameBuf.h
+++ b/screenlib/SDL_FrameBuf.h
@@ -30,23 +30,23 @@
*/
#include <stdio.h>
-#include <string.h>
-#include <stdarg.h>
#include "SDL.h"
+#include "ErrorBase.h"
+#include "UIArea.h"
typedef enum {
DOCLIP,
NOCLIP
} clipval;
-class FrameBuf {
+class FrameBuf : public UIArea {
public:
FrameBuf();
int Init(int width, int height, Uint32 window_flags, Uint32 render_flags,
SDL_Color *colors = NULL, SDL_Surface *icon = NULL);
- ~FrameBuf();
+ virtual ~FrameBuf();
/* Setup routines */
/* Set the image palette -- 256 entries */
@@ -88,18 +88,6 @@ class FrameBuf {
}
void Fade(void); /* Fade screen out, then in */
- /* Informational routines */
- int Width(void) {
- int w, h;
- SDL_GetWindowSize(window, &w, &h);
- return w;
- }
- int Height(void) {
- int w, h;
- SDL_GetWindowSize(window, &w, &h);
- return h;
- }
-
/* Drawing routines */
void Clear(int x, int y, int w, int h) {
FillRect(x, y, w, h, 0);
@@ -166,11 +154,6 @@ class FrameBuf {
SDL_SetWindowTitle(window, caption);
}
- /* Error message routine */
- char *Error(void) {
- return(errstr);
- }
-
private:
/* The current display */
SDL_Window *window;
@@ -186,18 +169,6 @@ class FrameBuf {
b = (color >> 0) & 0xFF;
SDL_SetRenderDrawColor(renderer, r, g, b, 0xFF);
}
-
- /* Error message */
- void SetError(const char *fmt, ...) {
- va_list ap;
-
- va_start(ap, fmt);
- vsprintf(errbuf, fmt, ap);
- va_end(ap);
- errstr = errbuf;
- }
- char *errstr;
- char errbuf[1024];
};
#endif /* _SDL_FrameBuf_h */
diff --git a/screenlib/UIArea.cpp b/screenlib/UIArea.cpp
new file mode 100644
index 00000000..bae27d11
--- /dev/null
+++ b/screenlib/UIArea.cpp
@@ -0,0 +1,170 @@
+/*
+ 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 "UIArea.h"
+
+
+static AnchorLocation ParseAnchorLocation(const char *text)
+{
+ AnchorLocation value = TOPLEFT;
+
+ if (strcasecmp(text, "TOPLEFT") == 0) {
+ value = TOPLEFT;
+ } else if (strcasecmp(text, "TOP") == 0) {
+ value = TOP;
+ } else if (strcasecmp(text, "TOPRIGHT") == 0) {
+ value = TOPRIGHT;
+ } else if (strcasecmp(text, "LEFT") == 0) {
+ value = LEFT;
+ } else if (strcasecmp(text, "CENTER") == 0) {
+ value = CENTER;
+ } else if (strcasecmp(text, "RIGHT") == 0) {
+ value = RIGHT;
+ } else if (strcasecmp(text, "BOTTOMLEFT") == 0) {
+ value = BOTTOMLEFT;
+ } else if (strcasecmp(text, "BOTTOM") == 0) {
+ value = BOTTOM;
+ } else if (strcasecmp(text, "BOTTOMRIGHT") == 0) {
+ value = BOTTOMRIGHT;
+ }
+ return value;
+
+}
+
+UIArea::UIArea() : ErrorBase()
+{
+ m_rect.x = 0;
+ m_rect.y = 0;
+ m_rect.w = 0;
+ m_rect.h = 0;
+}
+
+bool
+UIArea::Load(rapidxml::xml_node<> *node)
+{
+ rapidxml::xml_node<> *child;
+ rapidxml::xml_attribute<> *attr;
+
+ child = node->first_node("size", 0, false);
+ if (child) {
+ attr = child->first_attribute("w", 0, false);
+ if (attr) {
+ m_rect.w = atoi(attr->value());
+ }
+ attr = child->first_attribute("h", 0, false);
+ if (attr) {
+ m_rect.h = atoi(attr->value());
+ }
+ }
+
+ child = node->first_node("anchor", 0, false);
+ if (child) {
+ UIArea *anchorElement;
+ AnchorLocation anchorFrom = TOPLEFT;
+ AnchorLocation anchorTo = TOPLEFT;
+ int x, y;
+
+ attr = node->first_attribute("anchorElement", 0, false);
+ anchorElement = GetAnchorElement(attr ? attr->value() : NULL);
+ if (!anchorElement) {
+ SetError("Element 'anchor' couldn't find anchor element %s",
+ attr ? attr->value() : "NULL");
+ return false;
+ }
+
+ attr = node->first_attribute("anchorFrom", 0, false);
+ if (attr) {
+ anchorFrom = ParseAnchorLocation(attr->value());
+ }
+ attr = node->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;
+ }
+
+ attr = child->first_attribute("x", 0, false);
+ if (attr) {
+ x += atoi(attr->value());
+ }
+ attr = child->first_attribute("y", 0, false);
+ if (attr) {
+ y += atoi(attr->value());
+ }
+
+ m_rect.x = x;
+ m_rect.y = y;
+ }
+
+ return true;
+}
+
+void
+UIArea::GetAnchorLocation(AnchorLocation spot, int *x, int *y) const
+{
+ switch (spot & X_MASK) {
+ case X_LEFT:
+ *x = m_rect.x;
+ break;
+ case X_CENTER:
+ *x = m_rect.x + m_rect.w/2;
+ break;
+ case X_RIGHT:
+ *x = m_rect.x + m_rect.w;
+ break;
+ default:
+ assert(0);
+ }
+ switch (spot & Y_MASK) {
+ case Y_TOP:
+ *y = m_rect.y;
+ break;
+ case Y_CENTER:
+ *y = m_rect.y + m_rect.h/2;
+ break;
+ case Y_BOTTOM:
+ *y = m_rect.y + m_rect.h;
+ break;
+ default:
+ assert(0);
+ }
+}
diff --git a/screenlib/UIArea.h b/screenlib/UIArea.h
new file mode 100644
index 00000000..93a55d8c
--- /dev/null
+++ b/screenlib/UIArea.h
@@ -0,0 +1,95 @@
+/*
+ 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 _UIArea_h
+#define _UIArea_h
+
+#include "SDL_rect.h"
+
+#include "../utils/rapidxml.h"
+
+#include "ErrorBase.h"
+
+enum {
+ X_LEFT = 0x01,
+ X_CENTER = 0x02,
+ X_RIGHT = 0x4,
+ X_MASK = (X_LEFT|X_CENTER|X_RIGHT),
+ Y_TOP = 0x10,
+ Y_CENTER = 0x20,
+ Y_BOTTOM = 0x40,
+ Y_MASK = (Y_TOP|Y_CENTER|Y_BOTTOM)
+};
+enum AnchorLocation {
+ TOPLEFT = (Y_TOP|X_LEFT),
+ TOP = (Y_TOP|X_CENTER),
+ TOPRIGHT = (Y_TOP|X_RIGHT),
+ LEFT = (Y_CENTER|X_LEFT),
+ CENTER = (Y_CENTER|X_CENTER),
+ RIGHT = (Y_CENTER|X_RIGHT),
+ BOTTOMLEFT = (Y_BOTTOM|X_LEFT),
+ BOTTOM = (Y_BOTTOM|X_CENTER),
+ BOTTOMRIGHT = (Y_BOTTOM|X_RIGHT)
+};
+
+class UIArea : public ErrorBase
+{
+public:
+ UIArea();
+
+ bool Load(rapidxml::xml_node<> *node);
+
+ // This function returns anchor areas by name
+ virtual UIArea *GetAnchorElement(const char *name) {
+ return NULL;
+ }
+
+ void SetPosition(int x, int y) {
+ m_rect.x = x;
+ m_rect.y = y;
+ }
+ void SetSize(int w, int h) {
+ m_rect.w = w;
+ m_rect.h = h;
+ }
+ const SDL_Rect *GetRect() const {
+ return &m_rect;
+ }
+ int X() const {
+ return m_rect.x;
+ }
+ int Y() const {
+ return m_rect.y;
+ }
+ int Width() const {
+ return m_rect.w;
+ }
+ int Height() const {
+ return m_rect.h;
+ }
+ void GetAnchorLocation(AnchorLocation spot, int *x, int *y) const;
+
+protected:
+ SDL_Rect m_rect;
+};
+
+#endif // _UIArea_h
diff --git a/screenlib/UIElement.cpp b/screenlib/UIElement.cpp
new file mode 100644
index 00000000..9417d8f1
--- /dev/null
+++ b/screenlib/UIElement.cpp
@@ -0,0 +1,52 @@
+/*
+ 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 "UIPanel.h"
+#include "UIElement.h"
+
+UIElement::UIElement(UIPanel *panel, const char *name) : UIArea()
+{
+ m_name = new char[strlen(name)+1];
+ strcpy(m_name, name);
+
+ m_panel = panel;
+}
+
+UIElement::~UIElement()
+{
+ delete[] m_name;
+}
+
+bool
+UIElement::Load(rapidxml::xml_node<> *node)
+{
+ return UIArea::Load(node);
+}
+
+UIArea *
+UIElement::GetAnchorElement(const char *name)
+{
+ if (!name) {
+ return m_panel;
+ }
+ return m_panel->GetElement(name);
+}
diff --git a/screenlib/UIElement.h b/screenlib/UIElement.h
new file mode 100644
index 00000000..6719c7e8
--- /dev/null
+++ b/screenlib/UIElement.h
@@ -0,0 +1,58 @@
+/*
+ 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 _UIElement_h
+#define _UIElement_h
+
+#include "SDL.h"
+
+#include "../utils/rapidxml.h"
+
+#include "ErrorBase.h"
+#include "UIArea.h"
+
+class FrameBuf;
+class UIPanel;
+
+class UIElement : public UIArea
+{
+public:
+ UIElement(UIPanel *panel, const char *name = "");
+ virtual ~UIElement();
+
+ const char *GetName() const {
+ return m_name;
+ }
+
+ bool Load(rapidxml::xml_node<> *node);
+
+ virtual UIArea *GetAnchorElement(const char *name);
+
+ virtual void Draw(FrameBuf *) { }
+ virtual bool HandleEvent(const SDL_Event &event) { return false; }
+
+protected:
+ char *m_name;
+ UIPanel *m_panel;
+};
+
+#endif // _UIElement_h
diff --git a/screenlib/UIManager.cpp b/screenlib/UIManager.cpp
new file mode 100644
index 00000000..ab6068f6
--- /dev/null
+++ b/screenlib/UIManager.cpp
@@ -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
+*/
+
+#include "UIManager.h"
+#include "UIPanel.h"
+
+
+UIPanel *
+UIManager::GetPanel(const char *name)
+{
+ for (unsigned i = 0; i < m_panels.length(); ++i) {
+ if (strcmp(name, m_panels[i]->GetName()) == 0) {
+ return m_panels[i];
+ }
+ }
+ return NULL;
+}
+
+void
+UIManager::Draw()
+{
+ for (unsigned i = 0; i < m_panels.length(); ++i) {
+ m_panels[i]->Draw();
+ }
+}
+
+bool
+UIManager::HandleEvent(const SDL_Event &event)
+{
+ for (unsigned i = m_panels.length(); i--; ) {
+ if (m_panels[i]->HandleEvent(event)) {
+ return true;
+ }
+ }
+ return false;
+}
diff --git a/screenlib/UIManager.h b/screenlib/UIManager.h
new file mode 100644
index 00000000..40567352
--- /dev/null
+++ b/screenlib/UIManager.h
@@ -0,0 +1,51 @@
+/*
+ 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 _UIManager_h
+#define _UIManager_h
+
+#include "SDL.h"
+#include "array.h"
+
+class UIPanel;
+
+class UIManager
+{
+public:
+ UIManager() { }
+
+ void AddPanel(UIPanel *panel) {
+ m_panels.add(panel);
+ }
+ UIPanel *GetPanel(const char *name);
+ void RemovePanel(UIPanel *panel) {
+ m_panels.remove(panel);
+ }
+
+ void Draw();
+ bool HandleEvent(const SDL_Event &event);
+
+protected:
+ array<UIPanel *> m_panels;
+};
+
+#endif // _UIManager_h
diff --git a/screenlib/UIPanel.cpp b/screenlib/UIPanel.cpp
new file mode 100644
index 00000000..395a6a6b
--- /dev/null
+++ b/screenlib/UIPanel.cpp
@@ -0,0 +1,174 @@
+/*
+ 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 <physfs.h>
+
+#include "SDL_FrameBuf.h"
+#include "UIPanel.h"
+#include "UIElement.h"
+
+UIElementFactory UIPanel::s_elementFactory;
+
+UIPanel::UIPanel(FrameBuf *screen, const char *name) : UIArea()
+{
+ m_screen = screen;
+ m_name = new char[strlen(name)+1];
+ strcpy(m_name, name);
+
+ m_rect.w = screen->Width();
+ m_rect.h = screen->Height();
+}
+
+UIPanel::~UIPanel()
+{
+ delete[] m_name;
+
+ for (unsigned i = 0; i < m_elements.length(); ++i) {
+ delete m_elements[i];
+ }
+}
+
+bool
+UIPanel::Load(const char *file)
+{
+ PHYSFS_File *fp;
+ PHYSFS_sint64 size;
+ char *buffer;
+
+ ClearError();
+
+ if (!s_elementFactory) {
+ SetError("No panel element factory set");
+ return false;
+ }
+
+ fp = PHYSFS_openRead(file);
+ if (!fp) {
+ SetError("Couldn't open %s: %s", file, PHYSFS_getLastError());
+ return false;
+ }
+
+ size = PHYSFS_fileLength(fp);
+ buffer = new char[size+1];
+ if (PHYSFS_readBytes(fp, buffer, size) != size) {
+ SetError("Couldn't read from %s: %s", file, PHYSFS_getLastError());
+ PHYSFS_close(fp);
+ delete[] buffer;
+ return false;
+ }
+ buffer[size] = '\0';
+ PHYSFS_close(fp);
+
+ rapidxml::xml_document<> doc;
+ try {
+ doc.parse<0>(buffer);
+ } catch (rapidxml::parse_error e) {
+ SetError("Parse error: %s", e.what());
+ delete[] buffer;
+ return false;
+ }
+
+ rapidxml::xml_node<> *node = doc.first_node();
+ rapidxml::xml_node<> *child;
+ if (strcmp(node->name(), "UIPanel") != 0) {
+ SetError("Parse error: UIPanel root element expected");
+ delete[] buffer;
+ return false;
+ }
+ child = node->first_node("name", 0, false);
+ if (child) {
+ const char *name = node->value();
+ delete[] m_name;
+ m_name = new char[strlen(name)+1];
+ strcpy(m_name, name);
+ }
+ if (!UIArea::Load(node)) {
+ delete[] buffer;
+ return false;
+ }
+ child = node->first_node("elements", 0, false);
+ if (child) {
+ if (!LoadElements(child)) {
+ delete[] buffer;
+ return false;
+ }
+ }
+ delete[] buffer;
+ return true;
+}
+
+bool
+UIPanel::LoadElements(rapidxml::xml_node<> *node)
+{
+ for (node = node->first_node(); node; node = node->next_sibling()) {
+ UIElement *element = s_elementFactory(this, node->name());
+ if (!element) {
+ SetError("Couldn't find handler for element %s", node->name());
+ return false;
+ }
+ if (!element->Load(node)) {
+ SetError("Couldn't load element %s: %s", node->name(), element->Error());
+ delete element;
+ return false;
+ }
+ AddElement(element);
+ }
+}
+
+UIArea *
+UIPanel::GetAnchorElement(const char *name)
+{
+ if (!name) {
+ return m_screen;
+ }
+ return NULL;
+}
+
+UIElement *
+UIPanel::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;
+}
+
+void
+UIPanel::Draw()
+{
+ for (unsigned i = 0; i < m_elements.length(); ++i) {
+ m_elements[i]->Draw(m_screen);
+ }
+}
+
+bool
+UIPanel::HandleEvent(const SDL_Event &event)
+{
+ for (unsigned i = m_elements.length(); i--; ) {
+ if (m_elements[i]->HandleEvent(event)) {
+ return true;
+ }
+ }
+ return false;
+}
diff --git a/screenlib/UIPanel.h b/screenlib/UIPanel.h
new file mode 100644
index 00000000..9624c22a
--- /dev/null
+++ b/screenlib/UIPanel.h
@@ -0,0 +1,81 @@
+/*
+ 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 _UIPanel_h
+#define _UIPanel_h
+
+#include "SDL.h"
+
+#include "../utils/rapidxml.h"
+#include "../utils/array.h"
+
+#include "ErrorBase.h"
+#include "UIArea.h"
+
+class FrameBuf;
+class UIElement;
+class UIPanel;
+
+typedef UIElement *(*UIElementFactory)(UIPanel *panel, const char *name);
+
+class UIPanel : public UIArea
+{
+public:
+ static void SetElementFactory(UIElementFactory function) {
+ s_elementFactory = function;
+ }
+
+public:
+ UIPanel(FrameBuf *screen, const char *name = "");
+ virtual ~UIPanel();
+
+ const char *GetName() const {
+ return m_name;
+ }
+
+ bool Load(const char *file);
+
+ virtual UIArea *GetAnchorElement(const char *name);
+
+ void AddElement(UIElement *element) {
+ m_elements.add(element);
+ }
+ UIElement *GetElement(const char *name);
+ void RemoveElement(UIElement *element) {
+ m_elements.remove(element);
+ }
+
+ void Draw();
+ bool HandleEvent(const SDL_Event &event);
+
+protected:
+ FrameBuf *m_screen;
+ char *m_name;
+ array<UIElement *> m_elements;
+
+ bool LoadElements(rapidxml::xml_node<> *node);
+
+protected:
+ static UIElementFactory s_elementFactory;
+};
+
+#endif // _UIPanel_h
diff --git a/utils/array.h b/utils/array.h
new file mode 100644
index 00000000..0d273307
--- /dev/null
+++ b/utils/array.h
@@ -0,0 +1,67 @@
+
+/* Simple array class for use with Maelstrom.
+ *
+ * The types in the array are POD types, without constructors or destructors.
+ */
+#ifndef _array_h
+#define _array_h
+
+#include <stdlib.h>
+#include <assert.h>
+
+template <typename T>
+class array
+{
+public:
+ array() : m_len(0), m_max(1), m_data((T*)malloc(sizeof(T))) { }
+ ~array() { free(m_data); }
+
+ void add(const T& item) {
+ resize(m_len+1);
+ m_data[m_len++] = item;
+ }
+ void insert(const T& item, unsigned index) {
+ if (index == m_len) {
+ add(item);
+ return;
+ }
+ resize(m_len+1);
+ for (unsigned i = m_len; i >= index; --i) {
+ m_data[i] = m_data[i-1];
+ }
+ m_data[index] = item;
+ ++m_len;
+ }
+ bool remove(const T& item) {
+ for (unsigned i = 0; i < m_len; ++i) {
+ if (m_data[i] == item) {
+ memcpy(&m_data[i], &m_data[i+1], (m_len-i-1)*sizeof(T));
+ --m_len;
+ return true;
+ }
+ }
+ return false;
+ }
+ int length() const {
+ return m_len;
+ }
+ T operator[](unsigned index) {
+ assert(index < m_len);
+ return m_data[index];
+ }
+
+protected:
+ unsigned m_len;
+ unsigned m_max;
+ T *m_data;
+
+ void resize(unsigned len) {
+ if (len > m_max) {
+ while (m_max < len)
+ m_max *= 2;
+ m_data = (T*)realloc(m_data, m_max*sizeof(T));
+ }
+ }
+};
+
+#endif // _array_h
diff --git a/utils/rapidxml.h b/utils/rapidxml.h
new file mode 100644
index 00000000..fe6e23de
--- /dev/null
+++ b/utils/rapidxml.h
@@ -0,0 +1,17 @@
+#ifndef _rapidxml_h
+#define _rapidxml_h
+
+#define RAPIDXML_NO_STDLIB
+
+#include <assert.h>
+
+namespace std
+{
+ typedef ::size_t size_t;
+}
+
+extern inline void * operator new (size_t, void * p) throw() { return p ; }
+
+#include "rapidxml.hpp"
+
+#endif // _rapidxml_h
diff --git a/utils/rapidxml.hpp b/utils/rapidxml.hpp
new file mode 100755
index 00000000..4f840ce0
--- /dev/null
+++ b/utils/rapidxml.hpp
@@ -0,0 +1,2617 @@
+#ifndef RAPIDXML_HPP_INCLUDED
+#define RAPIDXML_HPP_INCLUDED
+
+/*
+Copyright (c) 2006, 2007 Marcin Kalicinski
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+of the Software, and to permit persons to whom the Software is furnished to do so,
+subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+IN THE SOFTWARE.
+*/
+// Copyright (C) 2006, 2009 Marcin Kalicinski
+// Version 1.13
+// Revision $DateTime: 2009/05/13 01:46:17 $
+//! \file rapidxml.hpp This file contains rapidxml parser and DOM implementation
+
+// If standard library is disabled, user must provide implementations of required functions and typedefs
+#if !defined(RAPIDXML_NO_STDLIB)
+ #include <cstdlib> // For std::size_t
+ #include <cassert> // For assert
+ #include <new> // For placement new
+#endif
+
+// On MSVC, disable "conditional expression is constant" warning (level 4).
+// This warning is almost impossible to avoid with certain types of templated code
+#ifdef _MSC_VER
+ #pragma warning(push)
+ #pragma warning(disable:4127) // Conditional expression is constant
+#endif
+
+///////////////////////////////////////////////////////////////////////////
+// RAPIDXML_PARSE_ERROR
+
+#if defined(RAPIDXML_NO_EXCEPTIONS)
+
+#define RAPIDXML_PARSE_ERROR(what, where) { parse_error_handler(what, where); assert(0); }
+
+namespace rapidxml
+{
+ //! When exceptions are disabled by defining RAPIDXML_NO_EXCEPTIONS,
+ //! this function is called to notify user about the error.
+ //! It must be defined by the user.
+ //! <br><br>
+ //! This function cannot
(Patch may be truncated, please check the link at the top of this post.)