summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authormrwastl <mrwastl@users.sourceforge.net>2010-04-17 19:16:26 +0200
committermrwastl <mrwastl@users.sourceforge.net>2010-04-17 19:16:26 +0200
commit68ac6628a31cb1472275b5282c5cf9a971d9bddd (patch)
tree0ef788b563efab6688b0381cedd43baaefbc66cc
parent1011961a8af0615ee25b79d2bbd7e6820b851556 (diff)
downloadgraphlcd-base-68ac6628a31cb1472275b5282c5cf9a971d9bddd.tar.gz
graphlcd-base-68ac6628a31cb1472275b5282c5cf9a971d9bddd.tar.bz2
backport of skin-support from 0.2.x to 0.1.x, changes for gcc 4.3 conformity
-rw-r--r--Makefile14
-rw-r--r--glcdskin/1__THIS_IS_WORK_IN_PROGRESS1
-rw-r--r--glcdskin/2__IT_WILL_NOT_WORK_AS_YOU_MIGHT_EXPECT1
-rw-r--r--glcdskin/Makefile60
-rw-r--r--glcdskin/TODO8
-rw-r--r--glcdskin/cache.c177
-rw-r--r--glcdskin/cache.h60
-rw-r--r--glcdskin/config.c42
-rw-r--r--glcdskin/config.h42
-rw-r--r--glcdskin/display.c46
-rw-r--r--glcdskin/display.h57
-rw-r--r--glcdskin/font.c119
-rw-r--r--glcdskin/font.h73
-rw-r--r--glcdskin/function.c454
-rw-r--r--glcdskin/function.h112
-rw-r--r--glcdskin/object.c444
-rw-r--r--glcdskin/object.h152
-rw-r--r--glcdskin/parser.c389
-rw-r--r--glcdskin/parser.h29
-rw-r--r--glcdskin/skin.c82
-rw-r--r--glcdskin/skin.h68
-rw-r--r--glcdskin/string.c232
-rw-r--r--glcdskin/string.h125
-rw-r--r--glcdskin/type.c18
-rw-r--r--glcdskin/type.h140
-rw-r--r--glcdskin/variable.c74
-rw-r--r--glcdskin/variable.h61
-rw-r--r--glcdskin/xml.c441
-rw-r--r--glcdskin/xml.h71
29 files changed, 3592 insertions, 0 deletions
diff --git a/Makefile b/Makefile
index ff1db52..a659568 100644
--- a/Makefile
+++ b/Makefile
@@ -8,27 +8,41 @@ ARCHIVE = $(PROJECT)-$(VERSION)
PACKAGE = $(ARCHIVE)
TMPDIR = /tmp
+INCLUDE_SKINS=1
+
### Targets:
all:
@$(MAKE) -C glcdgraphics all
@$(MAKE) -C glcddrivers all
+ifdef INCLUDE_SKINS
+ @$(MAKE) -C glcdskin all
+endif
@$(MAKE) -C tools all
install:
@$(MAKE) -C glcdgraphics install
@$(MAKE) -C glcddrivers install
+ifdef INCLUDE_SKINS
+ @$(MAKE) -C glcdskin install
+endif
@$(MAKE) -C tools install
uninstall:
@$(MAKE) -C glcdgraphics uninstall
@$(MAKE) -C glcddrivers uninstall
+ifdef INCLUDE_SKINS
+ @$(MAKE) -C glcdskin uninstall
+endif
@$(MAKE) -C tools uninstall
clean:
@-rm -f *.tgz
@$(MAKE) -C glcdgraphics clean
@$(MAKE) -C glcddrivers clean
+ifdef INCLUDE_SKINS
+ @$(MAKE) -C glcdskin clean
+endif
@$(MAKE) -C tools clean
dist: clean
diff --git a/glcdskin/1__THIS_IS_WORK_IN_PROGRESS b/glcdskin/1__THIS_IS_WORK_IN_PROGRESS
new file mode 100644
index 0000000..8d1c8b6
--- /dev/null
+++ b/glcdskin/1__THIS_IS_WORK_IN_PROGRESS
@@ -0,0 +1 @@
+
diff --git a/glcdskin/2__IT_WILL_NOT_WORK_AS_YOU_MIGHT_EXPECT b/glcdskin/2__IT_WILL_NOT_WORK_AS_YOU_MIGHT_EXPECT
new file mode 100644
index 0000000..8d1c8b6
--- /dev/null
+++ b/glcdskin/2__IT_WILL_NOT_WORK_AS_YOU_MIGHT_EXPECT
@@ -0,0 +1 @@
+
diff --git a/glcdskin/Makefile b/glcdskin/Makefile
new file mode 100644
index 0000000..c67582c
--- /dev/null
+++ b/glcdskin/Makefile
@@ -0,0 +1,60 @@
+#
+# Makefile for the GraphLCD skin library
+#
+
+-include ../Make.config
+
+
+CXXFLAGS += -fPIC
+
+VERMAJOR = 1
+VERMINOR = 0
+VERMICRO = 0
+
+BASENAME = libglcdskin.so
+
+LIBNAME = $(BASENAME).$(VERMAJOR).$(VERMINOR).$(VERMICRO)
+
+OBJS = cache.o config.o display.o font.o function.o object.o parser.o skin.o string.o type.o variable.o xml.o
+
+HEADERS = cache.h config.h display.h font.h function.h object.h parser.h skin.h string.h type.h variable.h xml.h
+
+### Implicit rules:
+
+%.o: %.c
+ $(CXX) $(CXXFLAGS) -I.. -c $(DEFINES) $(INCLUDES) $<
+
+# Dependencies:
+
+MAKEDEP = g++ -MM -MG
+DEPFILE = .dependencies
+$(DEPFILE): Makefile
+ @$(MAKEDEP) $(DEFINES) $(INCLUDES) $(OBJS:%.o=%.c) > $@
+
+-include $(DEPFILE)
+
+### Targets:
+
+all: $(LIBNAME)
+
+$(LIBNAME): $(OBJS)
+ $(CXX) $(CXXFLAGS) -shared $(OBJS) $(LIBS) -Wl,-soname="$(BASENAME).$(VERMAJOR)" -o $@
+ ln -sf $(LIBNAME) $(BASENAME)
+
+install: all
+ install -d $(LIBDIR)
+ install -m 755 $(LIBNAME) $(LIBDIR)/
+ install -d $(INCDIR)/glcdskin
+ install -m 644 $(HEADERS) $(INCDIR)/glcdskin/
+ ( cd $(LIBDIR); ln -sf $(LIBNAME) $(BASENAME).$(VERMAJOR); ln -sf $(LIBNAME) $(BASENAME) )
+
+uninstall:
+ rm -f $(LIBDIR)/$(BASENAME)
+ rm -f $(LIBDIR)/$(BASENAME).$(VERMAJOR)
+ rm -f $(LIBDIR)/$(LIBNAME)
+ (for i in $(HEADERS); do rm -f $(INCDIR)/glcdskin/$$i; done)
+ rmdir $(INCDIR)/glcdskin
+
+clean:
+ rm -f $(OBJS) $(DEPFILE) $(LIBNAME) $(BASENAME) *~
+
diff --git a/glcdskin/TODO b/glcdskin/TODO
new file mode 100644
index 0000000..f410a98
--- /dev/null
+++ b/glcdskin/TODO
@@ -0,0 +1,8 @@
+- add missing objects like textbox, scrollbar
+- add dynamic behaviour to objects like scrolling and blinking
+- add special objects for external data so that other plugins can draw text and bitmaps on an area of the display that will be defined in the skin. This could be used p.e. for a spectrum analyzer or displaying id3 tags.
+- add service interface for external data objects
+- make skin variables more dynamic, p.e. evaluate positions while displaying, not only during skin loading. This should make it easier to support several display sizes with one skin.
+- DOCUMENTATION, DOCUMENTATION, DOCUMENTATION
+- fix all the small bugs that were introduced
+- all the stuff I forgot :-)
diff --git a/glcdskin/cache.c b/glcdskin/cache.c
new file mode 100644
index 0000000..83629a0
--- /dev/null
+++ b/glcdskin/cache.c
@@ -0,0 +1,177 @@
+/*
+ * GraphLCD skin library
+ *
+ * cache.c - image cache
+ *
+ * This file is released under the GNU General Public License. Refer
+ * to the COPYING file distributed with this package.
+ *
+ */
+
+#include <glcdgraphics/bitmap.h>
+#include <glcdgraphics/image.h>
+#include <glcdgraphics/glcd.h>
+#include <glcdgraphics/pbm.h>
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "cache.h"
+#include "skin.h"
+
+namespace GLCD
+{
+
+cImageItem::cImageItem(const std::string & path, cImage * image)
+: path(path),
+ counter(0),
+ image(image)
+{
+}
+
+cImageItem::~cImageItem()
+{
+ delete image;
+}
+
+
+cImageCache::cImageCache(cSkin * Parent, int Size)
+: skin(Parent),
+ size(Size)
+{
+}
+
+cImageCache::~cImageCache()
+{
+ for (unsigned int i = 0; i < images.size(); i++)
+ {
+ delete images[i];
+ }
+ images.clear();
+}
+
+cImage * cImageCache::Get(const std::string & path)
+{
+ std::vector <cImageItem *>::iterator it;
+ cImageItem * item;
+ uint64_t maxCounter;
+ std::vector <cImageItem *>::iterator oldest;
+
+ maxCounter = 0;
+ item = NULL;
+ for (it = images.begin(); it != images.end(); it++)
+ {
+ if (item == NULL && path == (*it)->Path())
+ {
+ (*it)->ResetCounter();
+ item = (*it);
+ }
+ else
+ {
+ (*it)->IncCounter();
+ if ((*it)->Counter() > maxCounter)
+ {
+ maxCounter = (*it)->Counter();
+ oldest = it;
+ }
+ }
+ }
+ if (item)
+ {
+ return item->Image();
+ }
+
+ item = LoadImage(path);
+ if (item)
+ {
+ if (images.size() == size)
+ {
+ images.erase(oldest);
+ }
+ images.push_back(item);
+ return item->Image();
+ }
+ return NULL;
+}
+
+cImageItem * cImageCache::LoadImage(const std::string & path)
+{
+ cImageItem * item;
+ cImage * image;
+ char str[8];
+ int i;
+ int j;
+ std::string file;
+
+ i = path.length() - 1;
+ j = 0;
+ while (i >= 0 && j < 6)
+ {
+ if (path[i] == '.')
+ break;
+ i--;
+ j++;
+ }
+ i++;
+ j = 0;
+ while (i < (int) path.length())
+ {
+ str[j] = toupper((unsigned) path[i]);
+ i++;
+ j++;
+ }
+ str[j] = 0;
+
+ image = new cImage();
+ if (!image)
+ return NULL;
+
+ if (path[0] == '/' || path.find("./") == 0 || path.find("../") == 0)
+ file = path;
+ else
+ {
+ file = skin->Config().SkinPath();
+ if (file.length() > 0)
+ {
+ if (file[file.length() - 1] != '/')
+ file += '/';
+ }
+ file += path;
+ }
+ if (strcmp(str, "PBM") == 0)
+ {
+ cPBMFile pbm;
+
+ if (pbm.Load(*image, file) == false)
+ {
+ delete image;
+ return NULL;
+ }
+ }
+ else if (strcmp(str, "GLCD") == 0)
+ {
+ cGLCDFile glcd;
+
+ if (glcd.Load(*image, file) == false)
+ {
+ delete image;
+ return NULL;
+ }
+ }
+ else
+ {
+ delete image;
+ return NULL;
+ }
+
+ item = new cImageItem(path, image);
+ if (!item)
+ {
+ delete image;
+ return NULL;
+ }
+ return item;
+}
+
+} // end of namespace
+
diff --git a/glcdskin/cache.h b/glcdskin/cache.h
new file mode 100644
index 0000000..925ebcc
--- /dev/null
+++ b/glcdskin/cache.h
@@ -0,0 +1,60 @@
+/*
+ * GraphLCD skin library
+ *
+ * cache.h - image cache
+ *
+ * This file is released under the GNU General Public License. Refer
+ * to the COPYING file distributed with this package.
+ *
+ */
+
+#ifndef _GLCDSKIN_CACHE_H_
+#define _GLCDSKIN_CACHE_H_
+
+#include <stdint.h>
+
+#include <string>
+#include <vector>
+
+#include <glcdgraphics/image.h>
+
+namespace GLCD
+{
+
+class cSkin;
+
+class cImageItem
+{
+private:
+ std::string path;
+ uint64_t counter;
+ cImage * image;
+public:
+ cImageItem(const std::string & path, cImage * image);
+ ~cImageItem();
+
+ const std::string & Path() const { return path; }
+ uint64_t Counter() const { return counter; }
+ cImage * Image() { return image; }
+ void ResetCounter() { counter = 0; }
+ void IncCounter() { counter += 1; }
+};
+
+class cImageCache
+{
+private:
+ cSkin * skin;
+ size_t size;
+ std::vector <cImageItem *> images;
+
+ cImageItem * LoadImage(const std::string & path);
+public:
+ cImageCache(cSkin * Parent, int Size);
+ ~cImageCache();
+
+ cImage * Get(const std::string & path);
+};
+
+} // end of namespace
+
+#endif
diff --git a/glcdskin/config.c b/glcdskin/config.c
new file mode 100644
index 0000000..518218e
--- /dev/null
+++ b/glcdskin/config.c
@@ -0,0 +1,42 @@
+#include "config.h"
+#include "type.h"
+
+namespace GLCD
+{
+
+std::string cSkinConfig::SkinPath(void)
+{
+ return ".";
+}
+
+std::string cSkinConfig::FontPath(void)
+{
+ return ".";
+}
+
+std::string cSkinConfig::CharSet(void)
+{
+ return "iso-8859-15";
+}
+
+std::string cSkinConfig::Translate(const std::string & Text)
+{
+ return Text;
+}
+
+cType cSkinConfig::GetToken(const tSkinToken & Token)
+{
+ return "";
+}
+
+int cSkinConfig::GetTokenId(const std::string & Name)
+{
+ return 0;
+}
+
+int cSkinConfig::GetTabPosition(int Index, int MaxWidth, const cFont & Font)
+{
+ return 0;
+}
+
+} // end of namespace
diff --git a/glcdskin/config.h b/glcdskin/config.h
new file mode 100644
index 0000000..f6c8af9
--- /dev/null
+++ b/glcdskin/config.h
@@ -0,0 +1,42 @@
+/*
+ * GraphLCD skin library
+ *
+ * config.h - config class
+ *
+ * This file is released under the GNU General Public License. Refer
+ * to the COPYING file distributed with this package.
+ *
+ * based on text2skin
+ *
+ */
+
+#ifndef _GLCDSKIN_CONFIG_H_
+#define _GLCDSKIN_CONFIG_H_
+
+#include <string>
+
+
+namespace GLCD
+{
+
+class cType;
+class cFont;
+struct tSkinToken;
+
+class cSkinConfig
+{
+public:
+ virtual ~cSkinConfig() {};
+
+ virtual std::string SkinPath(void);
+ virtual std::string FontPath(void);
+ virtual std::string CharSet(void);
+ virtual std::string Translate(const std::string & Text);
+ virtual cType GetToken(const tSkinToken & Token);
+ virtual int GetTokenId(const std::string & Name);
+ virtual int GetTabPosition(int Index, int MaxWidth, const cFont & Font);
+};
+
+} // end of namespace
+
+#endif
diff --git a/glcdskin/display.c b/glcdskin/display.c
new file mode 100644
index 0000000..b92fea5
--- /dev/null
+++ b/glcdskin/display.c
@@ -0,0 +1,46 @@
+/*
+ * GraphLCD skin library
+ *
+ * display.c - display class
+ *
+ * This file is released under the GNU General Public License. Refer
+ * to the COPYING file distributed with this package.
+ *
+ * based on text2skin
+ *
+ */
+
+#include "display.h"
+
+namespace GLCD
+{
+
+cSkinDisplay::cSkinDisplay(cSkin * parent)
+: mSkin(parent),
+ mId("")
+{
+}
+
+void cSkinDisplay::Render(cBitmap * screen)
+{
+ for (uint32_t i = 0; i < NumObjects(); ++i)
+ GetObject(i)->Render(screen);
+}
+
+
+cSkinDisplays::cSkinDisplays(void)
+{
+}
+
+cSkinDisplays::~cSkinDisplays()
+{
+ iterator it = begin();
+ while (it != end())
+ {
+ delete (*it);
+ it++;
+ }
+}
+
+} // end of namespace
+
diff --git a/glcdskin/display.h b/glcdskin/display.h
new file mode 100644
index 0000000..af50179
--- /dev/null
+++ b/glcdskin/display.h
@@ -0,0 +1,57 @@
+/*
+ * GraphLCD skin library
+ *
+ * display.h - display class
+ *
+ * This file is released under the GNU General Public License. Refer
+ * to the COPYING file distributed with this package.
+ *
+ * based on text2skin
+ *
+ */
+
+#ifndef _GLCDSKIN_DISPLAY_H_
+#define _GLCDSKIN_DISPLAY_H_
+
+#include <string>
+#include <vector>
+
+#include "object.h"
+
+namespace GLCD
+{
+
+class cSkin;
+
+class cSkinDisplay
+{
+ friend bool StartElem(const std::string &name, std::map<std::string,std::string> &attrs);
+ friend bool EndElem(const std::string &name);
+
+private:
+ cSkin * mSkin;
+ std::string mId;
+ cSkinObjects mObjects;
+
+public:
+ cSkinDisplay(cSkin * Parent);
+
+ cSkin * Skin(void) const { return mSkin; }
+ const std::string & Id(void) const { return mId; }
+
+ uint32_t NumObjects(void) const { return mObjects.size(); }
+ cSkinObject * GetObject(uint32_t n) const { return mObjects[n]; }
+
+ void Render(cBitmap * screen);
+};
+
+class cSkinDisplays: public std::vector<cSkinDisplay *>
+{
+public:
+ cSkinDisplays(void);
+ ~cSkinDisplays(void);
+};
+
+} // end of namespace
+
+#endif
diff --git a/glcdskin/font.c b/glcdskin/font.c
new file mode 100644
index 0000000..731b1fa
--- /dev/null
+++ b/glcdskin/font.c
@@ -0,0 +1,119 @@
+#include <syslog.h>
+
+#include <fstream>
+
+#include "font.h"
+#include "skin.h"
+#include "function.h"
+
+namespace GLCD
+{
+
+cSkinFont::cSkinFont(cSkin * Parent)
+: mSkin(Parent),
+ mCondition(NULL),
+ mDummyDisplay(mSkin),
+ mDummyObject(&mDummyDisplay)
+{
+}
+
+bool cSkinFont::ParseUrl(const std::string & url)
+{
+ std::string::size_type count = std::string::npos;
+
+ if (url.find("fnt:") == 0)
+ {
+ mType = ftFNT;
+ mSize = 0;
+ }
+ else if (url.find("ft2:") == 0)
+ {
+ mType = ftFT2;
+ std::string::size_type pos = url.find(":", 4);
+ if (pos == std::string::npos)
+ {
+ syslog(LOG_ERR, "cFontElement::Load(): No font size specified in %s\n", url.c_str());
+ return false;
+ }
+ std::string tmp = url.substr(pos + 1);
+ mSize = atoi(tmp.c_str());
+ count = pos - 4;
+ }
+ else
+ {
+ syslog(LOG_ERR, "cSkinFont::ParseUrl(): Unknown font type in %s\n", url.c_str());
+ return false;
+ }
+
+ if (url[4] == '/' || url.find("./") == 4 || url.find("../") == 4)
+ mFile = url.substr(4, count);
+ else
+ {
+ // first try skin's font dir
+ mFile = mSkin->Config().SkinPath();
+ if (mFile.length() > 0)
+ {
+ if (mFile[mFile.length() - 1] != '/')
+ mFile += '/';
+ }
+ mFile += "fonts/";
+ mFile += url.substr(4, count);
+#if (__GNUC__ < 3)
+ std::ifstream f(mFile.c_str(), std::ios::in | std::ios::binary);
+#else
+ std::ifstream f(mFile.c_str(), std::ios_base::in | std::ios_base::binary);
+#endif
+ if (f.is_open())
+ {
+ f.close();
+ }
+ else
+ {
+ // then try generic font dir
+ mFile = mSkin->Config().FontPath();
+ if (mFile.length() > 0)
+ {
+ if (mFile[mFile.length() - 1] != '/')
+ mFile += '/';
+ }
+ mFile += url.substr(4, count);
+ }
+ }
+
+ if (mType == ftFNT)
+ {
+ return mFont.LoadFNT(mFile);
+ }
+ else
+ {
+ return mFont.LoadFT2(mFile, mSkin->Config().CharSet(), mSize);
+ }
+}
+
+bool cSkinFont::ParseCondition(const std::string & Text)
+{
+ cSkinFunction *result = new cSkinFunction(&mDummyObject);
+ if (result->Parse(Text))
+ {
+ delete mCondition;
+ mCondition = result;
+ return true;
+ }
+ return false;
+}
+
+cSkinFonts::cSkinFonts(void)
+{
+}
+
+cSkinFonts::~cSkinFonts()
+{
+ iterator it = begin();
+ while (it != end())
+ {
+ delete (*it);
+ it++;
+ }
+}
+
+} // end of namespace
diff --git a/glcdskin/font.h b/glcdskin/font.h
new file mode 100644
index 0000000..d11fa50
--- /dev/null
+++ b/glcdskin/font.h
@@ -0,0 +1,73 @@
+/*
+ * GraphLCD skin library
+ *
+ * font.h - font class
+ *
+ * This file is released under the GNU General Public License. Refer
+ * to the COPYING file distributed with this package.
+ *
+ * based on text2skin
+ *
+ */
+
+#ifndef _GLCDSKIN_FONT_H_
+#define _GLCDSKIN_FONT_H_
+
+#include <string>
+#include <vector>
+
+#include <glcdgraphics/font.h>
+
+#include "display.h"
+#include "object.h"
+
+namespace GLCD
+{
+
+class cSkin;
+
+class cSkinFont
+{
+ friend bool StartElem(const std::string &name, std::map<std::string,std::string> &attrs);
+ friend bool EndElem(const std::string &name);
+
+public:
+ enum eType
+ {
+ ftFNT,
+ ftFT2
+ };
+
+private:
+ cSkin * mSkin;
+ std::string mId;
+ eType mType;
+ std::string mFile;
+ int mSize;
+ cFont mFont;
+ cSkinFunction * mCondition;
+ cSkinDisplay mDummyDisplay;
+ cSkinObject mDummyObject;
+
+public:
+ cSkinFont(cSkin * Parent);
+
+ bool ParseUrl(const std::string & Text);
+ bool ParseCondition(const std::string & Text);
+
+ cSkin * Skin(void) const { return mSkin; }
+ const std::string & Id(void) const { return mId; }
+ const cFont * Font(void) const { return &mFont; }
+ cSkinFunction * Condition(void) const { return mCondition; }
+};
+
+class cSkinFonts: public std::vector<cSkinFont *>
+{
+public:
+ cSkinFonts(void);
+ ~cSkinFonts(void);
+};
+
+} // end of namespace
+
+#endif
diff --git a/glcdskin/function.c b/glcdskin/function.c
new file mode 100644
index 0000000..8582ad5
--- /dev/null
+++ b/glcdskin/function.c
@@ -0,0 +1,454 @@
+/*
+ * GraphLCD skin library
+ *
+ * function.c - skin functions class
+ *
+ * This file is released under the GNU General Public License. Refer
+ * to the COPYING file distributed with this package.
+ *
+ * based on text2skin
+ *
+ */
+
+#include <syslog.h>
+
+#include <string.h>
+
+#include "skin.h"
+#include "function.h"
+
+namespace GLCD
+{
+
+static const char * Internals[] =
+{
+ "not", "and", "or", "equal", "gt", "lt", "ge", "le", "ne", "file", "trans",
+ "add", "sub", "mul", "div",
+ "FontTotalWidth",
+ "FontTotalHeight",
+ "FontTotalAscent",
+ "FontSpaceBetween",
+ "FontLineHeight",
+ "FontTextWidth",
+ "FontTextHeight",
+ "ImageWidth",
+ "ImageHeight",
+ NULL
+};
+
+cSkinFunction::cSkinFunction(cSkinObject *Parent)
+: mObject(Parent),
+ mSkin(Parent->Skin()),
+ mType(string),
+ mString(mObject, false),
+ mNumber(0),
+ mNumParams(0)
+{
+}
+
+cSkinFunction::cSkinFunction(const cSkinString & String)
+: mObject(String.Object()),
+ mSkin(String.Skin()),
+ mType(string),
+ mString(String),
+ mNumber(0),
+ mNumParams(0)
+{
+}
+
+cSkinFunction::cSkinFunction(const cSkinFunction & Src)
+: mObject(Src.mObject),
+ mSkin(Src.mSkin),
+ mType(Src.mType),
+ mString(Src.mString),
+ mNumber(Src.mNumber),
+ mNumParams(Src.mNumParams)
+{
+ for (uint32_t i = 0; i < mNumParams; ++i)
+ mParams[i] = new cSkinFunction(*Src.mParams[i]);
+}
+
+cSkinFunction::~cSkinFunction()
+{
+ for (uint32_t i = 0; i < mNumParams; ++i)
+ delete mParams[i];
+}
+
+bool cSkinFunction::Parse(const std::string & Text)
+{
+ const char *text = Text.c_str();
+ const char *ptr = text, *last = text;
+ eType type = undefined_function;
+ int inExpr = 0;
+ cSkinFunction *expr;
+
+ if (*ptr == '\'' || *ptr == '{')
+ {
+ // must be string
+ if (strlen(ptr) < 2
+ || (*ptr == '\'' && *(ptr + strlen(ptr) - 1) != '\'')
+ || (*ptr == '{' && *(ptr + strlen(ptr) - 1) != '}'))
+ {
+ syslog(LOG_ERR, "ERROR: Unmatched string end\n");
+ return false;
+ }
+
+ std::string temp;
+ if (*ptr == '\'')
+ temp.assign(ptr + 1, strlen(ptr) - 2);
+ else
+ temp.assign(ptr);
+
+ int pos = -1;
+ while ((pos = temp.find("\\'", pos + 1)) != -1)
+ temp.replace(pos, 2, "'");
+
+ if (!mString.Parse(temp))
+ return false;
+
+ mType = string;
+ }
+ if (*ptr == '#')
+ {
+ // must be a variable id
+ if (strlen(ptr) < 2)
+ {
+ syslog(LOG_ERR, "ERROR: No variable id given\n");
+ return false;
+ }
+
+ mVariableId.assign(ptr + 1);
+ mType = variable;
+ }
+ else if ((*ptr >= '0' && *ptr <= '9') || *ptr == '-' || *ptr == '+')
+ {
+ // must be number
+ char *end;
+ int num = strtol(ptr, &end, 10);
+ if (end == ptr || *end != '\0')
+ {
+ syslog(LOG_ERR, "ERROR: Invalid numeric value\n");
+ return false;
+ }
+
+ mNumber = num;
+ mType = number;
+ }
+ else
+ {
+ // expression
+ for (; *ptr; ++ptr)
+ {
+ if (*ptr == '(')
+ {
+ if (inExpr++ == 0)
+ {
+ int i;
+ for (i = 0; Internals[i] != NULL; ++i)
+ {
+ if ((size_t)(ptr - last) == strlen(Internals[i])
+ && memcmp(last, Internals[i], ptr - last) == 0)
+ {
+ type = (eType)(INTERNAL + i);
+ break;
+ }
+ }
+
+ if (Internals[i] == NULL)
+ {
+ syslog(LOG_ERR, "ERROR: Unknown function %.*s", (int)(ptr - last), last);
+ return false;
+ }
+ last = ptr + 1;
+ }
+ }
+ else if (*ptr == ',' || *ptr == ')')
+ {
+ if (inExpr == 0)
+ {
+ syslog(LOG_ERR, "ERROR: Unmatched '%c' in expression", *ptr);
+ return false;
+ }
+
+ if (inExpr == 1)
+ {
+ expr = new cSkinFunction(mObject);
+ if (!expr->Parse(std::string(last, ptr - last)))
+ {
+ delete expr;
+ return false;
+ }
+
+ if (mNumParams == MAXPARAMETERS)
+ {
+ syslog(LOG_ERR, "ERROR: Too many parameters to function, maximum is %d",
+ MAXPARAMETERS);
+ return false;
+ }
+
+ mType = type;
+ mParams[mNumParams++] = expr;
+ last = ptr + 1;
+ }
+
+ if (*ptr == ')')
+ {
+ if (inExpr == 1)
+ {
+ int params = 0;
+
+ switch (mType)
+ {
+ case fun_and:
+ case fun_or:
+ params = -1;
+ break;
+
+ case fun_eq:
+ case fun_ne:
+ case fun_gt:
+ case fun_lt:
+ case fun_ge:
+ case fun_le:
+ params = 2;
+ break;
+
+ case fun_not:
+ case fun_trans:
+ case fun_file:
+ params = 1;
+ break;
+
+ case funAdd:
+ case funSub:
+ case funMul:
+ params = -1;
+ break;
+
+ case funDiv:
+ params = 2;
+ break;
+
+ case funFontTotalWidth:
+ case funFontTotalHeight:
+ case funFontTotalAscent:
+ case funFontSpaceBetween:
+ case funFontLineHeight:
+ params = 1;
+ break;
+
+ case funFontTextWidth:
+ case funFontTextHeight:
+ params = 2;
+ break;
+
+ case funImageWidth:
+ case funImageHeight:
+ params = 1;
+ break;
+
+ default:
+ break;
+ }
+
+ if (params != -1 && mNumParams != (uint32_t) params)
+ {
+ syslog(LOG_ERR, "ERROR: Text2Skin: Wrong number of parameters to %s, "
+ "expecting %d", Internals[mType - INTERNAL], params);
+ return false;
+ }
+ }
+
+ --inExpr;
+ }
+ }
+ }
+
+ if (inExpr > 0)
+ {
+ syslog(LOG_ERR, "ERROR: Expecting ')' in expression");
+ return false;
+ }
+ }
+
+ return true;
+}
+
+cType cSkinFunction::FunFile(const cType & Param) const
+{
+ cImageCache * cache = mSkin->ImageCache();
+ GLCD::cImage * image = cache->Get(Param);
+ return image ? (cType) Param : (cType) false;
+}
+
+cType cSkinFunction::FunFont(eType Function, const cType &Param1, const cType &Param2) const
+{
+ cSkinFont * skinFont = mSkin->GetFont(Param1);
+ if (!skinFont)
+ return false;
+
+ const cFont * font = skinFont->Font();
+ if (!font)
+ return false;
+ switch (Function)
+ {
+ case funFontTotalWidth:
+ return font->TotalWidth();
+ case funFontTotalHeight:
+ return font->TotalHeight();
+ case funFontTotalAscent:
+ return font->TotalAscent();
+ case funFontSpaceBetween:
+ return font->SpaceBetween();
+ case funFontLineHeight:
+ return font->LineHeight();
+ case funFontTextWidth:
+ return font->Width((const std::string) Param2);
+ case funFontTextHeight:
+ return font->Height((const std::string) Param2);
+ default:
+ break;
+ }
+ return false;
+}
+
+cType cSkinFunction::FunImage(eType Function, const cType &Param) const
+{
+ cImageCache * cache = mSkin->ImageCache();
+ GLCD::cImage * image = cache->Get(Param);
+
+ if (!image)
+ return false;
+
+ switch (Function)
+ {
+ case funImageWidth:
+ return (int) image->Width();
+ case funImageHeight:
+ return (int) image->Height();
+ default:
+ break;
+ }
+ return false;
+}
+
+cType cSkinFunction::Evaluate(void) const
+{
+ switch (mType)
+ {
+ case string:
+ return mString.Evaluate();
+
+ case number:
+ return mNumber;
+
+ case variable:
+ {
+ cSkinVariable * variable = mSkin->GetVariable(mVariableId);
+ if (variable)
+ return variable->Value();
+ return false;
+ }
+
+ case fun_not:
+ return !mParams[0]->Evaluate();
+
+ case fun_and:
+ for (uint32_t i = 0; i < mNumParams; ++i)
+ {
+ if (!mParams[i]->Evaluate())
+ return false;
+ }
+ return true;
+
+ case fun_or:
+ for (uint32_t i = 0; i < mNumParams; ++i)
+ {
+ if (mParams[i]->Evaluate())
+ return true;
+ }
+ return false;
+
+ case fun_eq:
+ return mParams[0]->Evaluate() == mParams[1]->Evaluate();
+
+ case fun_ne:
+ return mParams[0]->Evaluate() != mParams[1]->Evaluate();
+
+ case fun_gt:
+ return mParams[0]->Evaluate() > mParams[1]->Evaluate();
+
+ case fun_lt:
+ return mParams[0]->Evaluate() < mParams[1]->Evaluate();
+
+ case fun_ge:
+ return mParams[0]->Evaluate() >= mParams[1]->Evaluate();
+
+ case fun_le:
+ return mParams[0]->Evaluate() <= mParams[1]->Evaluate();
+
+ case fun_file:
+ return FunFile(mParams[0]->Evaluate());
+
+ case fun_trans:
+ return mSkin->Config().Translate(mParams[0]->Evaluate());
+
+ case funAdd:
+ {
+ int result = 0;
+ for (uint32_t i = 0; i < mNumParams; ++i)
+ {
+ result += (int) mParams[i]->Evaluate();
+ }
+ return result;
+ }
+
+ case funSub:
+ if (mNumParams > 0)
+ {
+ int result = (int) mParams[0]->Evaluate();
+ for (uint32_t i = 1; i < mNumParams; ++i)
+ {
+ result -= (int) mParams[i]->Evaluate();
+ }
+ return result;
+ }
+ return 0;
+
+ case funMul:
+ {
+ int result = 1;
+ for (uint32_t i = 0; i < mNumParams; ++i)
+ {
+ result *= (int) mParams[i]->Evaluate();
+ }
+ return result;
+ }
+
+ case funDiv:
+ return ((int) mParams[0]->Evaluate() / (int) mParams[1]->Evaluate());
+
+ case funFontTotalWidth:
+ case funFontTotalHeight:
+ case funFontTotalAscent:
+ case funFontSpaceBetween:
+ case funFontLineHeight:
+ return FunFont(mType, mParams[0]->Evaluate(), "");
+
+ case funFontTextWidth:
+ case funFontTextHeight:
+ return FunFont(mType, mParams[0]->Evaluate(), mParams[1]->Evaluate());
+
+ case funImageWidth:
+ case funImageHeight:
+ return FunImage(mType, mParams[0]->Evaluate());
+
+ default:
+ //Dprintf("unknown function code\n");
+ syslog(LOG_ERR, "ERROR: Unknown function code called (this shouldn't happen)");
+ break;
+ }
+ return false;
+}
+
+} // end of namespace
diff --git a/glcdskin/function.h b/glcdskin/function.h
new file mode 100644
index 0000000..4b3732f
--- /dev/null
+++ b/glcdskin/function.h
@@ -0,0 +1,112 @@
+/*
+ * GraphLCD skin library
+ *
+ * function.h - skin functions class
+ *
+ * This file is released under the GNU General Public License. Refer
+ * to the COPYING file distributed with this package.
+ *
+ * based on text2skin
+ *
+ */
+
+#ifndef _GLCDSKIN_FUNCTION_H_
+#define _GLCDSKIN_FUNCTION_H_
+
+#include <stdint.h>
+
+#include <string>
+
+#include "type.h"
+#include "string.h"
+
+namespace GLCD
+{
+
+#define STRING 0x01000000
+#define NUMBER 0x02000000
+#define INTERNAL 0x04000000
+#define VARIABLE 0x08000000
+
+#define MAXPARAMETERS 512
+
+class cSkinObject;
+class cSkin;
+
+class cSkinFunction
+{
+public:
+ enum eType
+ {
+ undefined_function,
+
+ string = STRING,
+ number = NUMBER,
+ variable = VARIABLE,
+
+ fun_not = INTERNAL,
+ fun_and,
+ fun_or,
+ fun_eq,
+ fun_gt,
+ fun_lt,
+ fun_ge,
+ fun_le,
+ fun_ne,
+ fun_file,
+ fun_trans,
+
+ funAdd,
+ funSub,
+ funMul,
+ funDiv,
+
+ funFontTotalWidth,
+ funFontTotalHeight,
+ funFontTotalAscent,
+ funFontSpaceBetween,
+ funFontLineHeight,
+ funFontTextWidth,
+ funFontTextHeight,
+
+ funImageWidth,
+ funImageHeight
+ };
+
+private:
+ cSkinObject * mObject;
+ cSkin * mSkin;
+ eType mType;
+ cSkinString mString;
+ int mNumber;
+ std::string mVariableId;
+ cSkinFunction * mParams[MAXPARAMETERS];
+ uint32_t mNumParams;
+
+protected:
+ cType FunFile (const cType &Param) const;
+ cType FunPlugin(const cType &Param) const;
+ cType FunFont (eType Function, const cType &Param1, const cType &Param2) const;
+ cType FunImage (eType Function, const cType &Param) const;
+public:
+ cSkinFunction(cSkinObject *Parent);
+ cSkinFunction(const cSkinString &String);
+ cSkinFunction(const cSkinFunction &Src);
+ ~cSkinFunction();
+
+ bool Parse(const std::string &Text);
+ cType Evaluate(void) const;
+
+ void SetListIndex(int MaxItems, int Index);
+};
+
+inline void cSkinFunction::SetListIndex(int MaxItems, int Index)
+{
+ mString.SetListIndex(MaxItems, Index);
+ for (uint32_t i = 0; i < mNumParams; i++)
+ mParams[i]->SetListIndex(MaxItems, Index);
+}
+
+} // end of namespace
+
+#endif
diff --git a/glcdskin/object.c b/glcdskin/object.c
new file mode 100644
index 0000000..c79fa59
--- /dev/null
+++ b/glcdskin/object.c
@@ -0,0 +1,444 @@
+#include "display.h"
+#include "object.h"
+#include "skin.h"
+#include "cache.h"
+#include "function.h"
+
+namespace GLCD
+{
+
+static const std::string ObjectNames[] =
+{
+ "pixel",
+ "line",
+ "rectangle",
+ "ellipse",
+ "slope",
+ "image",
+ "progress",
+ "text",
+ "scrolltext",
+ "scrollbar",
+ "block",
+ "list",
+ "item"
+};
+
+cSkinObject::cSkinObject(cSkinDisplay * Parent)
+: mDisplay(Parent),
+ mSkin(Parent->Skin()),
+ mType((eType) __COUNT_OBJECT__),
+ mPos1(0, 0),
+ mPos2(-1, -1),
+ mColor(GLCD::clrBlack),
+ mFilled(false),
+ mRadius(0),
+ mArc(0),
+ mDirection(0),
+ mAlign(taLeft),
+ mMultiline(false),
+ mPath(this, false),
+ mCurrent(this, false),
+ mTotal(this, false),
+ mFont(this, false),
+ mText(this, false),
+ mCondition(NULL),
+ mObjects(NULL)
+{
+}
+
+cSkinObject::cSkinObject(const cSkinObject & Src)
+: mDisplay(Src.mDisplay),
+ mSkin(Src.mSkin),
+ mType(Src.mType),
+ mPos1(Src.mPos1),
+ mPos2(Src.mPos2),
+ mColor(Src.mColor),
+ mFilled(Src.mFilled),
+ mRadius(Src.mRadius),
+ mArc(Src.mArc),
+ mDirection(Src.mDirection),
+ mAlign(Src.mAlign),
+ mMultiline(Src.mMultiline),
+ mPath(Src.mPath),
+ mCurrent(Src.mCurrent),
+ mTotal(Src.mTotal),
+ mFont(Src.mFont),
+ mText(Src.mText),
+ mCondition(Src.mCondition),
+ mObjects(NULL)
+{
+ if (Src.mObjects)
+ mObjects = new cSkinObjects(*Src.mObjects);
+}
+
+cSkinObject::~cSkinObject()
+{
+ delete mObjects;
+}
+
+bool cSkinObject::ParseType(const std::string & Text)
+{
+ for (int i = 0; i < (int) __COUNT_OBJECT__; ++i)
+ {
+ if (ObjectNames[i] == Text)
+ {
+ mType = (eType) i;
+ return true;
+ }
+ }
+ return false;
+}
+
+bool cSkinObject::ParseColor(const std::string & Text)
+{
+ if (Text == "white")
+ mColor = GLCD::clrWhite;
+ else if (Text == "black")
+ mColor = GLCD::clrBlack;
+ else
+ return false;
+ return true;
+}
+
+bool cSkinObject::ParseCondition(const std::string & Text)
+{
+ cSkinFunction *result = new cSkinFunction(this);
+ if (result->Parse(Text))
+ {
+ delete mCondition;
+ mCondition = result;
+ return true;
+ }
+ return false;
+}
+
+bool cSkinObject::ParseAlignment(const std::string & Text)
+{
+ if (Text == "left")
+ mAlign = taLeft;
+ else if (Text == "right")
+ mAlign = taRight;
+ else if (Text == "center")
+ mAlign = taCenter;
+ else
+ return false;
+ return true;
+}
+
+bool cSkinObject::ParseIntParam(const std::string &Text, int & Param)
+{
+ if (isalpha(Text[0]) || Text[0] == '#')
+ {
+ cSkinFunction * func = new cSkinFunction(this);
+ if (func->Parse(Text))
+ {
+ Param = (int) func->Evaluate();
+ delete func;
+ return true;
+ }
+ delete func;
+ }
+ char * e;
+ const char * t = Text.c_str();
+ long l = strtol(t, &e, 10);
+ if (e ==t || *e != '\0')
+ {
+ return false;
+ }
+ Param = l;
+ return true;
+}
+
+bool cSkinObject::ParseWidth(const std::string &Text)
+{
+ int w;
+ if (!ParseIntParam(Text, w))
+ return false;
+ if (w > 0)
+ {
+ mPos2.x = mPos1.x + w - 1;
+ return true;
+ }
+ return false;
+}
+
+bool cSkinObject::ParseHeight(const std::string &Text)
+{
+ int h;
+ if (!ParseIntParam(Text, h))
+ return false;
+ if (h > 0)
+ {
+ mPos2.y = mPos1.y + h - 1;
+ return true;
+ }
+ return false;
+}
+
+bool cSkinObject::ParseFontFace(const std::string & Text)
+{
+ return mFont.Parse(Text);
+}
+
+void cSkinObject::SetListIndex(int MaxItems, int Index)
+{
+ mText.SetListIndex(MaxItems, Index);
+ mPath.SetListIndex(MaxItems, Index);
+ if (mCondition != NULL)
+ mCondition->SetListIndex(MaxItems, Index);
+}
+
+const std::string & cSkinObject::TypeName(void) const
+{
+ return ObjectNames[mType];
+}
+
+tPoint cSkinObject::Pos(void) const
+{
+ return tPoint(mPos1.x < 0 ? mSkin->BaseSize().w + mPos1.x : mPos1.x,
+ mPos1.y < 0 ? mSkin->BaseSize().h + mPos1.y : mPos1.y);
+}
+
+tSize cSkinObject::Size(void) const
+{
+ tPoint p1(mPos1.x < 0 ? mSkin->BaseSize().w + mPos1.x : mPos1.x,
+ mPos1.y < 0 ? mSkin->BaseSize().h + mPos1.y : mPos1.y);
+ tPoint p2(mPos2.x < 0 ? mSkin->BaseSize().w + mPos2.x : mPos2.x,
+ mPos2.y < 0 ? mSkin->BaseSize().h + mPos2.y : mPos2.y);
+ return tSize(p2.x - p1.x + 1, p2.y - p1.y + 1);
+}
+
+void cSkinObject::Render(GLCD::cBitmap * screen)
+{
+ if (mCondition != NULL && !mCondition->Evaluate())
+ return;
+
+ switch (Type())
+ {
+ case cSkinObject::image:
+ {
+ cImageCache * cache = mSkin->ImageCache();
+ GLCD::cImage * image = cache->Get(mPath.Evaluate());
+ if (image)
+ {
+ const GLCD::cBitmap * bitmap = image->GetBitmap();
+ if (bitmap)
+ {
+ screen->DrawBitmap(Pos().x, Pos().y, *bitmap, mColor);
+ }
+ }
+ break;
+ }
+
+ case cSkinObject::pixel:
+ screen->DrawPixel(Pos().x, Pos().y, mColor);
+ break;
+
+ case cSkinObject::line:
+ {
+ int x1 = Pos().x;
+ int x2 = Pos().x + Size().w - 1;
+ int y1 = Pos().y;
+ int y2 = Pos().y + Size().h - 1;
+ if (x1 == x2)
+ screen->DrawVLine(x1, y1, y2, mColor);
+ else if (y1 == y2)
+ screen->DrawHLine(x1, y1, x2, mColor);
+ else
+ screen->DrawLine(x1, y1, x2, y2, mColor);
+ break;
+ }
+
+ case cSkinObject::rectangle:
+ if (mRadius == 0)
+ screen->DrawRectangle(Pos().x, Pos().y, Pos().x + Size().w - 1, Pos().y + Size().h - 1, mColor, mFilled);
+ else
+ screen->DrawRoundRectangle(Pos().x, Pos().y, Pos().x + Size().w - 1, Pos().y + Size().h - 1, mColor, mFilled, mRadius);
+ break;
+
+ case cSkinObject::ellipse:
+ screen->DrawEllipse(Pos().x, Pos().y, Pos().x + Size().w - 1, Pos().y + Size().h - 1, mColor, mFilled, mArc);
+ break;
+
+ case cSkinObject::slope:
+ screen->DrawSlope(Pos().x, Pos().y, Pos().x + Size().w - 1, Pos().y + Size().h - 1, mColor, mArc);
+ break;
+
+ case cSkinObject::progress:
+ {
+ int current = mCurrent.Evaluate();
+ int total = mTotal.Evaluate();
+ if (total == 0)
+ total = 1;
+ if (current > total)
+ current = total;
+ if (mDirection == 0)
+ {
+ int w = Size().w * current / total;
+ if (w > 0)
+ screen->DrawRectangle(Pos().x, Pos().y, Pos().x + w - 1, Pos().y + Size().h - 1, mColor, true);
+ }
+ else if (mDirection == 1)
+ {
+ int h = Size().h * current / total;
+ if (h > 0)
+ screen->DrawRectangle(Pos().x, Pos().y, Pos().x + Size().w - 1, Pos().y + h - 1, mColor, true);
+ }
+ else if (mDirection == 2)
+ {
+ int w = Size().w * current / total;
+ if (w > 0)
+ screen->DrawRectangle(Pos().x + Size().w - w, Pos().y, Pos().x + Size().w - 1, Pos().y + Size().h - 1, mColor, true);
+ }
+ else if (mDirection == 3)
+ {
+ int h = Size().h * current / total;
+ if (h > 0)
+ screen->DrawRectangle(Pos().x, Pos().y + Size().h - h, Pos().x + Size().w - 1, Pos().y + Size().h - 1, mColor, true);
+ }
+ break;
+ }
+
+ case cSkinObject::text:
+ {
+ cSkinFont * skinFont = mSkin->GetFont(mFont.Evaluate());
+ if (skinFont)
+ {
+ const cFont * font = skinFont->Font();
+ std::string text = mText.Evaluate();
+ if (mMultiline)
+ {
+ std::vector <std::string> lines;
+ font->WrapText(Size().w, Size().h, text, lines);
+ for (size_t i = 0; i < lines.size(); i++)
+ {
+ int w = font->Width(lines[i]);
+ int x = Pos().x;
+ if (w < Size().w)
+ {
+ if (mAlign == taRight)
+ {
+ x += Size().w - w;
+ }
+ else if (mAlign == taCenter)
+ {
+ x += (Size().w - w) / 2;
+ }
+ }
+ screen->DrawText(x, Pos().y + i * font->LineHeight(), x + Size().w - 1, lines[i], font, mColor);
+ }
+ }
+ else
+ {
+ if (text.find('\t') != std::string::npos
+ && mSkin->Config().GetTabPosition(0, Size().w, *font) > 0)
+ {
+ std::string::size_type pos1;
+ std::string::size_type pos2;
+ std::string str;
+ int x = Pos().x;
+ int w = Size().w;
+ int tab = 0;
+ int tabWidth;
+
+ pos1 = 0;
+ pos2 = text.find('\t');
+ while (pos1 != std::string::npos && pos2 != std::string::npos)
+ {
+ str = text.substr(pos1, pos2 - pos1);
+ tabWidth = mSkin->Config().GetTabPosition(tab, Size().w, *font);
+ screen->DrawText(x, Pos().y, x + tabWidth - 1, str, font, mColor);
+ pos1 = pos2 + 1;
+ pos2 = text.find('\t', pos1);
+ tabWidth += font->Width(' ');
+ x += tabWidth;
+ w -= tabWidth;
+ tab++;
+ }
+ str = text.substr(pos1);
+ screen->DrawText(x, Pos().y, x + w - 1, str, font, mColor);
+ }
+ else
+ {
+ int w = font->Width(text);
+ int x = Pos().x;
+ if (w < Size().w)
+ {
+ if (mAlign == taRight)
+ {
+ x += Size().w - w;
+ }
+ else if (mAlign == taCenter)
+ {
+ x += (Size().w - w) / 2;
+ }
+ }
+ screen->DrawText(x, Pos().y, x + Size().w - 1, text, font, mColor);
+ }
+ }
+ }
+ break;
+ }
+
+ case cSkinObject::scrolltext:
+ //DrawScrolltext(Object->Pos(), Object->Size(), Object->Fg(), Object->Text(), Object->Font(),
+ // Object->Align());
+ break;
+
+ case cSkinObject::scrollbar:
+ //DrawScrollbar(Object->Pos(), Object->Size(), Object->Bg(), Object->Fg());
+ break;
+
+ case cSkinObject::block:
+ for (uint32_t i = 0; i < NumObjects(); i++)
+ GetObject(i)->Render(screen);
+ break;
+
+ case cSkinObject::list:
+ {
+ const cSkinObject * item = GetObject(0);
+ if (item && item->Type() == cSkinObject::item)
+ {
+ int itemheight = item->Size().h;
+ int maxitems = Size().h / itemheight;
+ int yoffset = 0;
+
+ for (int i = 0; i < maxitems; i++)
+ {
+ for (int j = 1; j < (int) NumObjects(); j++)
+ {
+ const cSkinObject * o = GetObject(j);
+ cSkinObject obj(*o);
+ obj.SetListIndex(maxitems, i);
+ if (obj.Condition() != NULL && !obj.Condition()->Evaluate())
+ continue;
+ obj.mPos1.x += mPos1.x;
+ obj.mPos1.y += mPos1.y + yoffset;
+ obj.mPos2.y += mPos1.y + yoffset;
+ obj.Render(screen);
+ }
+ yoffset += itemheight;
+ }
+ }
+ break;
+ }
+
+ case cSkinObject::item:
+ // ignore
+ break;
+ }
+}
+
+cSkinObjects::cSkinObjects(void)
+{
+}
+
+cSkinObjects::~cSkinObjects()
+{
+ for (uint32_t i = 0; i < size(); i++)
+ delete operator[](i);
+}
+
+} // end of namespace
+
diff --git a/glcdskin/object.h b/glcdskin/object.h
new file mode 100644
index 0000000..f164747
--- /dev/null
+++ b/glcdskin/object.h
@@ -0,0 +1,152 @@
+/*
+ * GraphLCD skin library
+ *
+ * object.h - skin object class
+ *
+ * This file is released under the GNU General Public License. Refer
+ * to the COPYING file distributed with this package.
+ *
+ * based on text2skin
+ *
+ */
+
+#ifndef _GLCDSKIN_OBJECT_H_
+#define _GLCDSKIN_OBJECT_H_
+
+#include <stdint.h>
+
+#include <vector>
+#include <string>
+#include <map>
+
+#include <glcdgraphics/bitmap.h>
+
+#include "type.h"
+#include "string.h"
+
+namespace GLCD
+{
+
+class cSkin;
+class cSkinDisplay;
+class cSkinObjects;
+class cSkinFunction;
+
+struct tPoint
+{
+ int x, y;
+ tPoint(int _x = 0, int _y = 0) { x = _x; y = _y; }
+};
+
+struct tSize
+{
+ int w, h;
+ tSize(int _w = 0, int _h = 0) { w = _w; h = _h; }
+};
+
+enum eTextAlignment
+{
+ taCenter,
+ taLeft,
+ taRight
+};
+
+class cSkinObject
+{
+ friend bool StartElem(const std::string & name, std::map<std::string,std::string> & attrs);
+ friend bool CharData(const std::string & text);
+ friend bool EndElem(const std::string & name);
+
+public:
+ enum eType
+ {
+ pixel,
+ line,
+ rectangle,
+ ellipse,
+ slope,
+ image,
+ progress,
+ text,
+ scrolltext,
+ scrollbar,
+ block,
+ list,
+ item,
+#define __COUNT_OBJECT__ (item + 1)
+ };
+
+private:
+ cSkinDisplay * mDisplay;
+ cSkin * mSkin;
+ eType mType;
+ tPoint mPos1;
+ tPoint mPos2;
+ eColor mColor;
+ bool mFilled;
+ int mRadius;
+ int mArc;
+ int mDirection;
+ eTextAlignment mAlign;
+ bool mMultiline;
+ cSkinString mPath;
+ cSkinString mCurrent;
+ cSkinString mTotal;
+ cSkinString mFont;
+ cSkinString mText;
+ cSkinFunction * mCondition;
+
+ cSkinObjects * mObjects; // used for block objects such as <list>
+
+public:
+ cSkinObject(cSkinDisplay * parent);
+ cSkinObject(const cSkinObject & Src);
+ ~cSkinObject();
+
+ bool ParseType(const std::string &Text);
+ bool ParseColor(const std::string &Text);
+ bool ParseCondition(const std::string &Text);
+ bool ParseAlignment(const std::string &Text);
+ bool ParseFontFace(const std::string &Text);
+ bool ParseIntParam(const std::string &Text, int & Param);
+ bool ParseWidth(const std::string &Text);
+ bool ParseHeight(const std::string &Text);
+
+ void SetListIndex(int MaxItems, int Index);
+
+ eType Type(void) const { return mType; }
+ cSkinFunction * Condition(void) const { return mCondition; }
+ cSkinDisplay * Display(void) const { return mDisplay; }
+ cSkin * Skin(void) const { return mSkin; }
+
+ const std::string & TypeName(void) const;
+ tPoint Pos(void) const;
+ tSize Size(void) const;
+
+ uint32_t NumObjects(void) const;
+ cSkinObject * GetObject(uint32_t Index) const;
+
+ void Render(cBitmap * screen);
+};
+
+class cSkinObjects: public std::vector<cSkinObject *>
+{
+public:
+ cSkinObjects(void);
+ ~cSkinObjects();
+};
+
+// recursive dependancy
+inline uint32_t cSkinObject::NumObjects(void) const
+{
+ return mObjects ? mObjects->size() : 0;
+}
+
+inline cSkinObject * cSkinObject::GetObject(uint32_t Index) const
+{
+ return mObjects ? (*mObjects)[Index] : NULL;
+}
+
+} // end of namespace
+
+#endif
diff --git a/glcdskin/parser.c b/glcdskin/parser.c
new file mode 100644
index 0000000..b137a5f
--- /dev/null
+++ b/glcdskin/parser.c
@@ -0,0 +1,389 @@
+/*
+ * GraphLCD skin library
+ *
+ * parser.c - xml parsing
+ *
+ * This file is released under the GNU General Public License. Refer
+ * to the COPYING file distributed with this package.
+ *
+ * based on text2skin
+ *
+ */
+
+#include <stdio.h>
+#include <syslog.h>
+
+#include <vector>
+#include <string>
+
+#include "parser.h"
+#include "xml.h"
+#include "skin.h"
+
+namespace GLCD
+{
+
+#define TAG_ERR_REMAIN(_context) do { \
+ syslog(LOG_ERR, "ERROR: Text2Skin: Unexpected tag %s within %s", \
+ name.c_str(), _context); \
+ return false; \
+ } while (0)
+
+#define TAG_ERR_CHILD(_context) do { \
+ syslog(LOG_ERR, "ERROR: Text2Skin: No child tag %s expected within %s", \
+ name.c_str(), _context); \
+ return false; \
+ } while (0)
+
+#define TAG_ERR_END(_context) do { \
+ syslog(LOG_ERR, "ERROR: Text2Skin: Unexpected closing tag for %s within %s", \
+ name.c_str(), _context); \
+ return false; \
+ } while (0)
+
+#define ATTRIB_OPT_STRING(_attr,_target) \
+ if (attrs.find(_attr) != attrs.end()) { \
+ _target = attrs[_attr]; \
+ }
+
+#define ATTRIB_MAN_STRING(_attr,_target) \
+ ATTRIB_OPT_STRING(_attr,_target) \
+ else { \
+ syslog(LOG_ERR, "ERROR: Text2Skin: Mandatory attribute %s missing in tag %s", \
+ _attr, name.c_str()); \
+ return false; \
+ }
+
+#define ATTRIB_OPT_NUMBER(_attr,_target) \
+ if (attrs.find(_attr) != attrs.end()) { \
+ char *_e; const char *_t = attrs[_attr].c_str(); \
+ long _l = strtol(_t, &_e, 10); \
+ if (_e ==_t || *_e != '\0') { \
+ syslog(LOG_ERR, "ERROR: Text2Skin: Invalid numeric value \"%s\" in attribute %s", \
+ _t, _attr); \
+ return false; \
+ } else \
+ _target = _l; \
+ }
+
+#define ATTRIB_MAN_NUMBER(_attr,_target) \
+ ATTRIB_OPT_NUMBER(_attr,_target) \
+ else { \
+ syslog(LOG_ERR, "ERROR: Text2Skin: Mandatory attribute %s missing in tag %s", \
+ _attr, name.c_str()); \
+ return false; \
+ }
+
+#define ATTRIB_OPT_BOOL(_attr,_target) \
+ if (attrs.find(_attr) != attrs.end()) { \
+ if (attrs[_attr] == "yes") \
+ _target = true; \
+ else if (attrs[_attr] == "no") \
+ _target = false; \
+ else { \
+ syslog(LOG_ERR, "ERROR: Text2Skin: Invalid boolean value \"%s\" in attribute %s", \
+ attrs[_attr].c_str(), _attr); \
+ return false; \
+ } \
+ }
+
+#define ATTRIB_MAN_BOOL(_attr,_target) \
+ ATTRIB_OPT_BOOL(_attr,_target) \
+ else { \
+ syslog(LOG_ERR, "ERROR: Text2Skin: Mandatory attribute %s missing in tag %s", \
+ _attr, name.c_str()); \
+ return false; \
+ }
+
+#define ATTRIB_OPT_FUNC(_attr,_func) \
+ if (attrs.find(_attr) != attrs.end()) { \
+ if (!_func(attrs[_attr])) { \
+ syslog(LOG_ERR, "ERROR: Text2Skin: Unexpected value %s for attribute %s", \
+ attrs[_attr].c_str(), _attr); \
+ return false; \
+ } \
+ }
+
+#define ATTRIB_MAN_FUNC(_attr,_func) \
+ ATTRIB_OPT_FUNC(_attr,_func) \
+ else { \
+ syslog(LOG_ERR, "ERROR: Text2Skin: Mandatory attribute %s missing in tag %s", \
+ _attr, name.c_str()); \
+ return false; \
+ }
+
+#define ATTRIB_OPT_FUNC_PARAM(_attr,_func,_param) \
+ if (attrs.find(_attr) != attrs.end()) { \
+ if (!_func(attrs[_attr],_param)) { \
+ syslog(LOG_ERR, "ERROR: Text2Skin: Unexpected value %s for attribute %s", \
+ attrs[_attr].c_str(), _attr); \
+ return false; \
+ } \
+ }
+
+#define ATTRIB_MAN_FUNC_PARAM(_attr,_func,_param) \
+ ATTRIB_OPT_FUNC_PARAM(_attr,_func,_param) \
+ else { \
+ syslog(LOG_ERR, "ERROR: Text2Skin: Mandatory attribute %s missing in tag %s", \
+ _attr, name.c_str()); \
+ return false; \
+ }
+
+static std::vector<std::string> context;
+static cSkin * skin = NULL;
+static cSkinFont * font = NULL;
+static cSkinVariable * variable = NULL;
+static cSkinDisplay * display = NULL;
+static std::vector <cSkinObject *> parents;
+static cSkinObject * object = NULL;
+static uint32_t oindex = 0;
+
+bool StartElem(const std::string & name, std::map<std::string,std::string> & attrs)
+{
+ //printf("start element: %s\n", name.c_str());
+
+ if (context.size() == 0)
+ {
+ if (name == "skin")
+ {
+ ATTRIB_MAN_STRING("version", skin->version);
+ ATTRIB_MAN_STRING("name", skin->title);
+ }
+ else
+ TAG_ERR_REMAIN("document");
+ }
+ else if (name == "variable")
+ {
+ variable = new cSkinVariable(skin);
+ ATTRIB_MAN_STRING("id", variable->mId);
+ ATTRIB_MAN_FUNC("value", variable->ParseValue);
+ ATTRIB_OPT_FUNC("condition", variable->ParseCondition);
+ }
+ else if (context[context.size() - 1] == "skin")
+ {
+ if (name == "font")
+ {
+ font = new cSkinFont(skin);
+ ATTRIB_MAN_STRING("id", font->mId);
+ ATTRIB_MAN_FUNC("url", font->ParseUrl);
+ ATTRIB_OPT_FUNC("condition", font->ParseCondition);
+ }
+ else if (name == "display")
+ {
+ display = new cSkinDisplay(skin);
+ ATTRIB_MAN_STRING("id", display->mId);
+ }
+ else
+ TAG_ERR_REMAIN("skin");
+ }
+ else if (context[context.size() - 1] == "display"
+ || context[context.size() - 1] == "list"
+ || context[context.size() - 1] == "block")
+ {
+ if (object != NULL)
+ {
+ parents.push_back(object);
+ object = NULL;
+ }
+
+ object = new cSkinObject(display);
+ if (object->ParseType(name))
+ {
+ ATTRIB_OPT_FUNC_PARAM("x1", object->ParseIntParam, object->mPos1.x);
+ ATTRIB_OPT_FUNC_PARAM("y1", object->ParseIntParam, object->mPos1.y);
+ ATTRIB_OPT_FUNC_PARAM("x2", object->ParseIntParam, object->mPos2.x);
+ ATTRIB_OPT_FUNC_PARAM("y2", object->ParseIntParam, object->mPos2.y);
+ ATTRIB_OPT_FUNC("width", object->ParseWidth);
+ ATTRIB_OPT_FUNC("height", object->ParseHeight);
+ ATTRIB_OPT_FUNC("condition", object->ParseCondition);
+
+ if (name == "image")
+ {
+ ATTRIB_OPT_FUNC_PARAM("x", object->ParseIntParam, object->mPos1.x);
+ ATTRIB_OPT_FUNC_PARAM("y", object->ParseIntParam, object->mPos1.y);
+ ATTRIB_OPT_FUNC_PARAM("x", object->ParseIntParam, object->mPos2.x);
+ ATTRIB_OPT_FUNC_PARAM("y", object->ParseIntParam, object->mPos2.y);
+ ATTRIB_OPT_FUNC("color", object->ParseColor);
+ ATTRIB_MAN_FUNC("path", object->mPath.Parse);
+ }
+ else if (name == "text"
+ || name == "scrolltext")
+ {
+ ATTRIB_OPT_FUNC("color", object->ParseColor);
+ ATTRIB_OPT_FUNC("align", object->ParseAlignment);
+ ATTRIB_OPT_FUNC("font", object->ParseFontFace);
+ ATTRIB_OPT_BOOL("multiline", object->mMultiline);
+#if 0
+ if (name == "blink")
+ {
+ ATTRIB_OPT_NUMBER("delay", object->mDelay);
+
+ if (object->mDelay == 0)
+ object->mDelay = 1000;
+ }
+ else if (name == "marquee")
+ {
+ ATTRIB_OPT_NUMBER("delay", object->mDelay);
+
+ if (object->mDelay == 0)
+ object->mDelay = 500;
+ }
+#endif
+ }
+ else if (name == "pixel")
+ {
+ ATTRIB_OPT_FUNC("color", object->ParseColor);
+ }
+ else if (name == "line")
+ {
+ ATTRIB_OPT_FUNC("color", object->ParseColor);
+ }
+ else if (name == "rectangle")
+ {
+ ATTRIB_OPT_FUNC("color", object->ParseColor);
+ ATTRIB_OPT_BOOL("filled", object->mFilled);
+ ATTRIB_OPT_NUMBER("radius", object->mRadius);
+ }
+ else if (name == "ellipse" || name == "slope")
+ {
+ ATTRIB_OPT_FUNC("color", object->ParseColor);
+ ATTRIB_OPT_BOOL("filled", object->mFilled);
+ ATTRIB_OPT_NUMBER("arc", object->mArc);
+ }
+ else if (name == "progress"
+ || name == "scrollbar")
+ {
+ ATTRIB_OPT_FUNC("color", object->ParseColor);
+ ATTRIB_OPT_NUMBER("direction", object->mDirection);
+ ATTRIB_OPT_FUNC("current", object->mCurrent.Parse);
+ ATTRIB_OPT_FUNC("total", object->mTotal.Parse);
+ }
+#if 0
+ else if (name == "item") {
+ ATTRIB_MAN_NUMBER("height", object->mPos2.y);
+ --object->mPos2.y;
+ }
+#endif
+ }
+ else
+ TAG_ERR_REMAIN(context[context.size() - 1].c_str());
+ }
+ else
+ TAG_ERR_CHILD(context[context.size() - 1].c_str());
+ context.push_back(name);
+ return true;
+}
+
+bool CharData(const std::string & text)
+{
+ if (text.length() == 0)
+ return true;
+ if (context.size() == 0)
+ return true;
+ //printf("char data : %s\n", text.c_str());
+
+ //printf("context: %s\n", context[context.size() - 1].c_str());
+ if (context[context.size() - 1] == "text"
+ || context[context.size() - 1] == "scrolltext")
+ {
+ if (!object->mText.Parse(text))
+ return false;
+ }
+ else
+ syslog(LOG_ERR, "ERROR: Bad character data");
+ return true;
+}
+
+bool EndElem(const std::string & name)
+{
+ //Dprintf("end element: %s\n", name.c_str());
+ if (context[context.size() - 1] == name)
+ {
+ if (name == "font")
+ {
+ skin->fonts.push_back(font);
+ font = NULL;
+ }
+ else if (name == "variable")
+ {
+ skin->mVariables.push_back(variable);
+ variable = NULL;
+ }
+ else if (name == "display")
+ {
+ //display->mNumMarquees = mindex;
+ skin->displays.push_back(display);
+ display = NULL;
+ oindex = 0;
+ }
+ else if (object != NULL || parents.size() > 0)
+ {
+ if (object == NULL)
+ {
+ printf("rotating parent to object\n");
+ object = parents[parents.size() - 1];
+ parents.pop_back();
+ }
+#if 0
+ if (object->mCondition == NULL)
+ {
+ switch (object->mType)
+ {
+ case cSkinObject::text:
+ case cSkinObject::scrolltext:
+ object->mCondition = new cxFunction(object->mText);
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ object->mIndex = oindex++;
+#endif
+ if (parents.size() > 0)
+ {
+ printf("pushing to parent\n");
+ cSkinObject *parent = parents[parents.size() - 1];
+ if (parent->mObjects == NULL)
+ parent->mObjects = new cSkinObjects();
+ parent->mObjects->push_back(object);
+ }
+ else
+ display->mObjects.push_back(object);
+ object = NULL;
+ }
+ context.pop_back();
+ }
+ else
+ TAG_ERR_END(context[context.size() - 1].c_str());
+ return true;
+}
+
+cSkin * XmlParse(cSkinConfig & Config, const std::string & Name, const std::string & fileName)
+{
+ skin = new cSkin(Config, Name);
+ context.clear();
+
+ cXML xml(fileName);
+ xml.SetNodeStartCB(StartElem);
+ xml.SetNodeEndCB(EndElem);
+ xml.SetCDataCB(CharData);
+ if (xml.Parse() != 0)
+ {
+ syslog(LOG_ERR, "ERROR: Text2Skin: Parse error in %s, line %d", fileName.c_str(), xml.LineNr());
+ delete skin;
+ skin = NULL;
+ delete display;
+ display = NULL;
+ delete object;
+ object = NULL;
+ return NULL;
+ }
+
+ cSkin * result = skin;
+ skin = NULL;
+ return result;
+}
+
+} // end of namespace
diff --git a/glcdskin/parser.h b/glcdskin/parser.h
new file mode 100644
index 0000000..d7d7f63
--- /dev/null
+++ b/glcdskin/parser.h
@@ -0,0 +1,29 @@
+/*
+ * GraphLCD skin library
+ *
+ * parser.h - xml parsing
+ *
+ * This file is released under the GNU General Public License. Refer
+ * to the COPYING file distributed with this package.
+ *
+ * based on text2skin
+ *
+ */
+
+#ifndef _GLCDSKIN_PARSER_H_
+#define _GLCDSKIN_PARSER_H_
+
+
+#include <string>
+
+namespace GLCD
+{
+
+class cSkin;
+class cSkinConfig;
+
+cSkin * XmlParse(cSkinConfig & Config, const std::string & name, const std::string & fileName);
+
+} // end of namespace
+
+#endif
diff --git a/glcdskin/skin.c b/glcdskin/skin.c
new file mode 100644
index 0000000..a7facdd
--- /dev/null
+++ b/glcdskin/skin.c
@@ -0,0 +1,82 @@
+/*
+ * GraphLCD skin library
+ *
+ * skin.c - skin class
+ *
+ * This file is released under the GNU General Public License. Refer
+ * to the COPYING file distributed with this package.
+ *
+ * based on text2skin
+ *
+ */
+
+#include "skin.h"
+#include "function.h"
+
+namespace GLCD
+{
+
+cSkin::cSkin(cSkinConfig & Config, const std::string & Name)
+: config(Config),
+ name(Name)
+{
+ mImageCache = new cImageCache(this, 100);
+}
+
+cSkin::~cSkin(void)
+{
+ delete mImageCache;
+}
+
+void cSkin::SetBaseSize(int width, int height)
+{
+ baseSize.w = width;
+ baseSize.h = height;
+}
+
+cSkinFont * cSkin::GetFont(const std::string & Id)
+{
+ cSkinFonts::iterator it = fonts.begin();
+ while (it != fonts.end())
+ {
+ if ((*it)->Id() == Id)
+ {
+ if ((*it)->Condition() == NULL || (*it)->Condition()->Evaluate())
+ return (*it);
+ }
+ it++;
+ }
+ return NULL;
+}
+
+cSkinDisplay * cSkin::GetDisplay(const std::string & Id)
+{
+ cSkinDisplays::iterator it = displays.begin();
+ while (it != displays.end())
+ {
+ if ((*it)->Id() == Id)
+ {
+ return (*it);
+ }
+ it++;
+ }
+ return NULL;
+}
+
+cSkinVariable * cSkin::GetVariable(const std::string & Id)
+{
+ cSkinVariables::iterator it = mVariables.begin();
+ while (it != mVariables.end())
+ {
+ if ((*it)->Id() == Id)
+ {
+ if ((*it)->Condition() == NULL || (*it)->Condition()->Evaluate())
+ return (*it);
+ }
+ it++;
+ }
+ return NULL;
+}
+
+
+} // end of namespace
diff --git a/glcdskin/skin.h b/glcdskin/skin.h
new file mode 100644
index 0000000..b2d8496
--- /dev/null
+++ b/glcdskin/skin.h
@@ -0,0 +1,68 @@
+/*
+ * GraphLCD skin library
+ *
+ * skin.h - skin class
+ *
+ * This file is released under the GNU General Public License. Refer
+ * to the COPYING file distributed with this package.
+ *
+ * based on text2skin
+ *
+ */
+
+#ifndef _GLCDSKIN_SKIN_H_
+#define _GLCDSKIN_SKIN_H_
+
+#include <string>
+
+#include "display.h"
+#include "font.h"
+#include "type.h"
+#include "string.h"
+#include "cache.h"
+#include "config.h"
+#include "variable.h"
+
+
+namespace GLCD
+{
+
+class cSkin
+{
+ friend bool StartElem(const std::string & name, std::map<std::string,std::string> & attrs);
+ friend bool EndElem(const std::string & name);
+
+private:
+ cSkinConfig & config;
+ std::string name;
+ std::string title;
+ std::string version;
+ tSize baseSize;
+
+ cSkinFonts fonts;
+ cSkinDisplays displays;
+ cSkinVariables mVariables;
+ cImageCache * mImageCache;
+
+public:
+ cSkin(cSkinConfig & Config, const std::string & Name);
+ ~cSkin(void);
+
+ void SetBaseSize(int width, int height);
+
+ cSkinFont * GetFont(const std::string & Id);
+ cSkinDisplay * GetDisplay(const std::string & Id);
+ cSkinVariable * GetVariable(const std::string & Id);
+
+ cSkinConfig & Config(void) { return config; }
+ const std::string & Name(void) const { return name; }
+ const std::string & Title(void) const { return title; }
+ const std::string & Version(void) const { return version; }
+ const tSize & BaseSize(void) const { return baseSize; }
+
+ cImageCache * ImageCache(void) { return mImageCache; }
+};
+
+} // end of namespace
+
+#endif
diff --git a/glcdskin/string.c b/glcdskin/string.c
new file mode 100644
index 0000000..dc9d9dc
--- /dev/null
+++ b/glcdskin/string.c
@@ -0,0 +1,232 @@
+/*
+ * GraphLCD skin library
+ *
+ * string.h - skin string class
+ *
+ * This file is released under the GNU General Public License. Refer
+ * to the COPYING file distributed with this package.
+ *
+ * based on text2skin
+ *
+ */
+
+#include <syslog.h>
+
+#include "skin.h"
+#include "object.h"
+#include "string.h"
+
+namespace GLCD
+{
+
+tSkinToken::tSkinToken(void)
+: Index(-1)
+{
+}
+
+tSkinToken::tSkinToken(int id, std::string n, uint32_t o, const std::string & a)
+: Id(id),
+ Name(n),
+ Offset(o),
+ Attrib(a),
+ MaxItems(-1),
+ Index(-1)
+{
+}
+
+bool operator< (const tSkinToken & A, const tSkinToken & B)
+{
+ return A.Id == B.Id
+ ? A.Name == B.Name
+ ? A.Attrib == B.Attrib
+ ? A.Index < B.Index
+ : A.Attrib < B.Attrib
+ : A.Name < B.Name
+ : A.Id < B.Id;
+}
+
+std::string tSkinToken::Token(const tSkinToken & Token)
+{
+ std::string result = (std::string) "{" + Token.Name;
+ //if (Token.Attrib.length() > 0)
+ // result += ":" + Token.Attrib;
+ result += "}";
+
+ return result;
+}
+
+cSkinString::tStringList cSkinString::mStrings;
+
+cSkinString::cSkinString(cSkinObject *Parent, bool Translate)
+: mObject(Parent),
+ mSkin(Parent->Skin()),
+ mTranslate(Translate)
+{
+ mStrings.push_back(this);
+}
+
+cSkinString::~cSkinString()
+{
+ tStringList::iterator it = mStrings.begin();
+ for (; it != mStrings.end(); ++it) {
+ if ((*it) == this) {
+ mStrings.erase(it);
+ break;
+ }
+ }
+}
+
+void cSkinString::Reparse(void)
+{
+ tStringList::iterator it = mStrings.begin();
+ for (; it != mStrings.end(); ++it) {
+ if ((*it)->mTranslate && (*it)->mText.length() > 0)
+ (*it)->Parse((*it)->mOriginal, true);
+ }
+}
+
+bool cSkinString::Parse(const std::string & Text, bool Translate)
+{
+ std::string trans = Translate ? mSkin->Config().Translate(Text) : Text;
+ const char * ptr, * last;
+ bool inToken = false;
+ bool inAttrib = false;
+ int offset = 0;
+
+ if (trans[0] == '#')
+ {
+ cSkinVariable * variable = mSkin->GetVariable(trans.substr(1));
+ if (variable)
+ {
+ trans = (std::string) variable->Value();
+ syslog(LOG_ERR, "string variable %s", trans.c_str());
+ }
+ }
+
+ //Dprintf("parsing: %s\n", Text.c_str());
+ mOriginal = Text;
+ mText = "";
+ mTokens.clear();
+
+ ptr = trans.c_str();
+ last = trans.c_str();
+ for (; *ptr; ++ptr) {
+ if (inToken && *ptr == '\\') {
+ if (*(ptr + 1) == '\0') {
+ syslog(LOG_ERR, "ERROR: Stray \\ in token attribute\n");
+ return false;
+ }
+
+ ++ptr;
+ continue;
+ }
+ else if (*ptr == '{') {
+ if (inToken) {
+ syslog(LOG_ERR, "ERROR: Unexpected '{' in token");
+ return false;
+ }
+
+ mText.append(last, ptr - last);
+ last = ptr + 1;
+ inToken = true;
+ }
+ else if (*ptr == '}' || (inToken && *ptr == ':')) {
+ if (!inToken) {
+ syslog(LOG_ERR, "ERROR: Unexpected '}' outside of token");
+ return false;
+ }
+
+ if (inAttrib) {
+ if (*ptr == ':') {
+ syslog(LOG_ERR, "ERROR: Unexpected ':' inside of token attribute");
+ return false;
+ }
+
+ int pos = -1;
+ std::string attr;
+ attr.assign(last, ptr - last);
+ while ((pos = attr.find('\\', pos + 1)) != -1) {
+ switch (attr[pos + 1]) {
+ case 'n':
+ attr.replace(pos, 2, "\n");
+ break;
+
+ default:
+ attr.erase(pos, 1);
+ }
+ }
+
+ tSkinToken &lastToken = mTokens[mTokens.size() - 1];
+ if (attr == "clean")
+ lastToken.Attrib = aClean;
+ else if (attr == "rest")
+ lastToken.Attrib = aRest;
+ else {
+ char *end;
+ int n = strtol(attr.c_str(), &end, 10);
+ //Dprintf("attr: %s, n: %d, end: |%s|\n", attr.c_str(), n, end);
+ if (end != attr.c_str() && *end == '\0') {
+ //Dprintf("a number\n");
+ lastToken.Attrib = n;
+ } else
+ lastToken.Attrib = attr;
+ }
+
+ inAttrib = false;
+ inToken = false;
+ } else {
+ if (true)
+ {
+ std::string tmp;
+ tmp.assign(last, ptr - last);
+ tSkinToken token(mSkin->Config().GetTokenId(tmp), tmp, offset, "");
+ mTokens.push_back(token);
+ }
+ else
+ {
+ syslog(LOG_ERR, "ERROR: Unexpected token {%.*s}", (int)(ptr - last), last);
+ return false;
+ }
+
+ if (*ptr == ':')
+ inAttrib = true;
+ else
+ inToken = false;
+ }
+
+ last = ptr + 1;
+ }
+ else if (!inToken)
+ ++offset;
+ }
+
+ if (inToken) {
+ syslog(LOG_ERR, "ERROR: Expecting '}' in token");
+ return false;
+ }
+
+ mText.append(last, ptr - last);
+
+ if (mTranslate && !Translate && mText.length() > 0)
+ Parse(Text, true);
+ return true;
+}
+
+cType cSkinString::Evaluate(void) const
+{
+ std::string result;
+ int offset = 0;
+
+ if (mText.length() == 0 && mTokens.size() == 1)
+ return mSkin->Config().GetToken(mTokens[0]);
+
+ for (uint32_t i = 0; i < mTokens.size(); ++i) {
+ result.append(mText.c_str() + offset, mTokens[i].Offset - offset);
+ result.append(mSkin->Config().GetToken(mTokens[i]));
+ offset = mTokens[i].Offset;
+ }
+ result.append(mText.c_str() + offset);
+ return result;
+}
+
+} // end of namespace
diff --git a/glcdskin/string.h b/glcdskin/string.h
new file mode 100644
index 0000000..b75fa11
--- /dev/null
+++ b/glcdskin/string.h
@@ -0,0 +1,125 @@
+/*
+ * GraphLCD skin library
+ *
+ * string.h - skin string class
+ *
+ * This file is released under the GNU General Public License. Refer
+ * to the COPYING file distributed with this package.
+ *
+ * based on text2skin
+ *
+ */
+
+#ifndef _GLCDSKIN_STRING_H_
+#define _GLCDSKIN_STRING_H_
+
+#include <string>
+#include <vector>
+
+#include "type.h"
+
+namespace GLCD
+{
+
+enum eSkinAttrib
+{
+ aNone,
+ aNumber,
+ aString,
+ aClean,
+ aRest
+
+#define __COUNT_ATTRIB__ (aRest + 1)
+};
+
+struct tSkinAttrib
+{
+ eSkinAttrib Type;
+ std::string Text;
+ int Number;
+
+ tSkinAttrib(const std::string & a): Type(aString), Text(a), Number(0) {}
+ tSkinAttrib(int n): Type(aNumber), Text(""), Number(n) {}
+ tSkinAttrib(eSkinAttrib t): Type(t), Text(""), Number(0) {}
+ tSkinAttrib(void): Type(aNone), Text(""), Number(0) {}
+
+ friend bool operator== (const tSkinAttrib & A, const tSkinAttrib & B);
+ friend bool operator< (const tSkinAttrib & A, const tSkinAttrib & B);
+};
+
+inline bool operator== (const tSkinAttrib & A, const tSkinAttrib & B)
+{
+ return A.Type == B.Type
+ && A.Text == B.Text
+ && A.Number == B.Number;
+}
+
+inline bool operator< (const tSkinAttrib & A, const tSkinAttrib & B)
+{
+ return A.Type == B.Type
+ ? A.Text == B.Text
+ ? A.Number < B.Number
+ : A.Text < B.Text
+ : A.Type < B.Type;
+}
+
+struct tSkinToken
+{
+ int Id;
+ std::string Name;
+ uint32_t Offset;
+ tSkinAttrib Attrib;
+ int MaxItems;
+ int Index;
+
+ tSkinToken(void);
+ tSkinToken(int id, std::string n, uint32_t o, const std::string & a);
+
+ friend bool operator< (const tSkinToken & A, const tSkinToken & B);
+
+ static std::string Token(const tSkinToken & Token);
+};
+
+class cSkinObject;
+class cSkin;
+
+class cSkinString
+{
+private:
+ typedef std::vector<cSkinString*> tStringList;
+ static tStringList mStrings;
+
+ cSkinObject * mObject;
+ cSkin * mSkin;
+ std::string mText;
+ std::string mOriginal;
+ std::vector<tSkinToken> mTokens;
+ bool mTranslate;
+
+public:
+ static void Reparse(void);
+
+ cSkinString(cSkinObject *Parent, bool Translate);
+ ~cSkinString();
+
+ bool Parse(const std::string & Text, bool Translate = false);
+ cType Evaluate(void) const;
+
+ void SetListIndex(int MaxItems, int Index);
+
+ cSkinObject * Object(void) const { return mObject; }
+ cSkin * Skin(void) const { return mSkin; }
+};
+
+inline void cSkinString::SetListIndex(int MaxItems, int Index)
+{
+ for (uint32_t i = 0; i < mTokens.size(); ++i)
+ {
+ mTokens[i].MaxItems = MaxItems;
+ mTokens[i].Index = Index;
+ }
+}
+
+} // end of namespace
+
+#endif
diff --git a/glcdskin/type.c b/glcdskin/type.c
new file mode 100644
index 0000000..56130e4
--- /dev/null
+++ b/glcdskin/type.c
@@ -0,0 +1,18 @@
+/*
+ * GraphLCD skin library
+ *
+ * type.c - skin type class
+ *
+ * This file is released under the GNU General Public License. Refer
+ * to the COPYING file distributed with this package.
+ *
+ * based on text2skin
+ *
+ */
+
+#include "type.h"
+
+namespace GLCD
+{
+
+} // end of namespace
diff --git a/glcdskin/type.h b/glcdskin/type.h
new file mode 100644
index 0000000..ad02a15
--- /dev/null
+++ b/glcdskin/type.h
@@ -0,0 +1,140 @@
+/*
+ * GraphLCD skin library
+ *
+ * type.h - skin type class
+ *
+ * This file is released under the GNU General Public License. Refer
+ * to the COPYING file distributed with this package.
+ *
+ * based on text2skin
+ *
+ */
+
+#ifndef _GLCDSKIN_TYPE_H_
+#define _GLCDSKIN_TYPE_H_
+
+#include <string>
+#include <stdio.h>
+
+#include <stdint.h>
+#include <stdlib.h>
+
+namespace GLCD
+{
+
+class cType
+{
+public:
+ enum eType
+ {
+ string,
+ number,
+ boolean
+ };
+
+ //friend class cxFunction;
+
+private:
+ eType mType;
+ std::string mString;
+ int mNumber;
+ uint32_t mUpdateIn;
+
+public:
+ cType(void): mType(boolean), mNumber(0), mUpdateIn(0) {}
+ cType(const char *String): mType(string), mString(String ?: ""), mUpdateIn(0) {}
+ cType(std::string String): mType(string), mString(String), mUpdateIn(0) {}
+ cType(int Number): mType(number), mNumber(Number), mUpdateIn(0) {}
+ cType(time_t Number): mType(number), mNumber(Number), mUpdateIn(0) {}
+ cType(bool Value): mType(boolean), mNumber(Value ? 1 : 0), mUpdateIn(0) {}
+
+ std::string String(void) const;
+ int Number(void) const { return mType == number ? mNumber : atoi(mString.c_str()); }
+
+ void SetUpdate(uint32_t UpdateIn) { mUpdateIn = UpdateIn; }
+ uint32_t UpdateIn(void) const { return mUpdateIn; }
+
+ operator std::string () const { return String(); }
+ operator int () const { return Number(); }
+ operator bool () const;
+
+ friend bool operator== (const cType &a, const cType &b);
+ friend bool operator!= (const cType &a, const cType &b);
+ friend bool operator< (const cType &a, const cType &b);
+ friend bool operator> (const cType &a, const cType &b);
+ friend bool operator<= (const cType &a, const cType &b);
+ friend bool operator>= (const cType &a, const cType &b);
+};
+
+inline std::string cType::String(void) const
+{
+ char str[16];
+
+ switch (mType)
+ {
+ case number:
+ sprintf(str, "%d", mNumber);
+ return str;
+ case boolean:
+ return mNumber != 0 ? "1" : "";
+ default:
+ return mString;
+ }
+}
+
+inline cType::operator bool () const
+{
+ switch (mType)
+ {
+ case string:
+ return mString != "";
+ default:
+ return mNumber != 0;
+ }
+}
+
+inline bool operator== (const cType &a, const cType &b)
+{
+ if (a.mType == cType::string || b.mType == cType::string)
+ return a.String() == b.String();
+ return a.mNumber == b.mNumber;
+}
+
+inline bool operator!= (const cType &a, const cType &b)
+{
+ if (a.mType == cType::string || b.mType == cType::string)
+ return a.String() != b.String();
+ return a.mNumber != b.mNumber;
+}
+
+inline bool operator< (const cType &a, const cType &b)
+{
+ if (a.mType == cType::string || b.mType == cType::string)
+ return a.String() < b.String();
+ return a.mNumber < b.mNumber;
+}
+
+inline bool operator> (const cType &a, const cType &b)
+{
+ if (a.mType == cType::string || b.mType == cType::string)
+ return a.String() > b.String();
+ return a.mNumber > b.mNumber;
+}
+
+inline bool operator<= (const cType &a, const cType &b)
+{
+ if (a.mType == cType::string || b.mType == cType::string)
+ return a.String() <= b.String();
+ return a.mNumber <= b.mNumber;
+}
+
+inline bool operator>= (const cType &a, const cType &b)
+{
+ if (a.mType == cType::string || b.mType == cType::string)
+ return a.String() >= b.String();
+ return a.mNumber >= b.mNumber;
+}
+
+} // end of namespace
+
+#endif
diff --git a/glcdskin/variable.c b/glcdskin/variable.c
new file mode 100644
index 0000000..b07773a
--- /dev/null
+++ b/glcdskin/variable.c
@@ -0,0 +1,74 @@
+#include <syslog.h>
+
+#include "variable.h"
+#include "skin.h"
+#include "function.h"
+
+namespace GLCD
+{
+
+cSkinVariable::cSkinVariable(cSkin * Parent)
+: mSkin(Parent),
+ mValue(0),
+ mCondition(NULL),
+ mDummyDisplay(mSkin),
+ mDummyObject(&mDummyDisplay)
+{
+}
+
+bool cSkinVariable::ParseValue(const std::string & Text)
+{
+ if (isalpha(Text[0]) || Text[0] == '#')
+ {
+ cSkinFunction * func = new cSkinFunction(&mDummyObject);
+ if (func->Parse(Text))
+ {
+ mValue = func->Evaluate();
+ delete func;
+ return true;
+ }
+ delete func;
+ }
+ else if (Text[0] == '\'')
+ {
+ mValue = Text.substr(1, Text.length() - 2);
+ return true;
+ }
+ char * e;
+ const char * t = Text.c_str();
+ long l = strtol(t, &e, 10);
+ if (e == t || *e != '\0')
+ {
+ return false;
+ }
+ mValue = l;
+ return true;
+}
+
+bool cSkinVariable::ParseCondition(const std::string & Text)
+{
+ cSkinFunction *result = new cSkinFunction(&mDummyObject);
+ if (result->Parse(Text))
+ {
+ delete mCondition;
+ mCondition = result;
+ return true;
+ }
+ return false;
+}
+
+cSkinVariables::cSkinVariables(void)
+{
+}
+
+cSkinVariables::~cSkinVariables()
+{
+ iterator it = begin();
+ while (it != end())
+ {
+ delete (*it);
+ it++;
+ }
+}
+
+} // end of namespace
diff --git a/glcdskin/variable.h b/glcdskin/variable.h
new file mode 100644
index 0000000..449f6b0
--- /dev/null
+++ b/glcdskin/variable.h
@@ -0,0 +1,61 @@
+/*
+ * GraphLCD skin library
+ *
+ * variable.h - variable class
+ *
+ * This file is released under the GNU General Public License. Refer
+ * to the COPYING file distributed with this package.
+ *
+ * based on text2skin
+ *
+ */
+
+#ifndef _GLCDSKIN_VARIABLE_H_
+#define _GLCDSKIN_VARIABLE_H_
+
+#include <string>
+#include <vector>
+
+#include "display.h"
+#include "object.h"
+
+namespace GLCD
+{
+
+class cSkin;
+
+class cSkinVariable
+{
+ friend bool StartElem(const std::string &name, std::map<std::string,std::string> &attrs);
+ friend bool EndElem(const std::string &name);
+
+private:
+ cSkin * mSkin;
+ std::string mId;
+ cType mValue;
+ cSkinFunction * mCondition;
+ cSkinDisplay mDummyDisplay;
+ cSkinObject mDummyObject;
+
+public:
+ cSkinVariable(cSkin * Parent);
+
+ bool ParseValue(const std::string & Text);
+ bool ParseCondition(const std::string & Text);
+
+ cSkin * Skin(void) const { return mSkin; }
+ const std::string & Id(void) const { return mId; }
+ const cType & Value(void) const { return mValue; }
+ cSkinFunction * Condition(void) const { return mCondition; }
+};
+
+class cSkinVariables: public std::vector <cSkinVariable *>
+{
+public:
+ cSkinVariables(void);
+ ~cSkinVariables(void);
+};
+
+} // end of namespace
+
+#endif
diff --git a/glcdskin/xml.c b/glcdskin/xml.c
new file mode 100644
index 0000000..ed29d11
--- /dev/null
+++ b/glcdskin/xml.c
@@ -0,0 +1,441 @@
+/*
+ * GraphLCD skin library
+ *
+ * xml.c - xml parser class
+ *
+ * This file is released under the GNU General Public License. Refer
+ * to the COPYING file distributed with this package.
+ *
+ * This module was kindly provided by Clemens Kirchgatterer
+ */
+
+#include <ctype.h>
+#include <syslog.h>
+
+#include <iostream>
+#include <fstream>
+
+#include "xml.h"
+
+namespace GLCD
+{
+
+std::string trim(const std::string & s)
+{
+ std::string::size_type start, end;
+
+ start = 0;
+ while (start < s.length())
+ {
+ if (!isspace(s[start]))
+ break;
+ start++;
+ }
+ end = s.length() - 1;
+ while (end >= 0)
+ {
+ if (!isspace(s[end]))
+ break;
+ end--;
+ }
+ return s.substr(start, end - start + 1);
+}
+
+enum {
+ LOOK4START, // looking for first element start
+ LOOK4TAG, // looking for element tag
+ INTAG, // reading tag
+ INCOMMENT, // reading comment
+ LOOK4CEND1, // looking for second '-' in -->
+ LOOK4CEND2, // looking for '>' in -->
+ LOOK4ATTRN, // looking for attr name, > or /
+ INATTRN, // reading attr name
+ LOOK4ATTRV, // looking for attr value
+ SAWSLASH, // saw / in element opening
+ INATTRV, // in attr value
+ LOOK4CLOSETAG, // looking for closing tag after <
+ INCLOSETAG, // reading closing tag
+};
+
+cXML::cXML(const std::string & file)
+: nodestartcb(NULL),
+ nodeendcb(NULL),
+ cdatacb(NULL),
+ parseerrorcb(NULL),
+ progresscb(NULL)
+{
+ char * buffer;
+ long size;
+
+#if (__GNUC__ < 3)
+ std::ifstream f(file.c_str(), std::ios::in | std::ios::binary | std::ios::ate);
+#else
+ std::ifstream f(file.c_str(), std::ios_base::in | std::ios_base::binary | std::ios_base::ate);
+#endif
+ if (!f.is_open())
+ {
+ syslog(LOG_ERR, "ERROR: skin file %s not found\n", file.c_str());
+ }
+ size = f.tellg();
+#if (__GNUC__ < 3)
+ f.seekg(0, std::ios::beg);
+#else
+ f.seekg(0, std::ios_base::beg);
+#endif
+ buffer = new char[size];
+ f.read(buffer, size);
+ f.close();
+ data.assign(buffer, size);
+ delete[] buffer;
+}
+
+cXML::cXML(const char * mem, unsigned int len)
+: nodestartcb(NULL),
+ nodeendcb(NULL),
+ cdatacb(NULL),
+ parseerrorcb(NULL),
+ progresscb(NULL)
+{
+ data.assign(mem, len);
+}
+
+void cXML::SetNodeStartCB(XML_NODE_START_CB(cb))
+{
+ nodestartcb = cb;
+}
+
+void cXML::SetNodeEndCB(XML_NODE_END_CB(cb))
+{
+ nodeendcb = cb;
+}
+
+void cXML::SetCDataCB(XML_CDATA_CB(cb))
+{
+ cdatacb = cb;
+}
+
+void cXML::SetParseErrorCB(XML_PARSE_ERROR_CB(cb))
+{
+ parseerrorcb = cb;
+}
+
+void cXML::SetProgressCB(XML_PROGRESS_CB(cb))
+{
+ progresscb = cb;
+}
+
+int cXML::Parse(void)
+{
+ int percent = 0;
+ int last = 0;
+ std::string::size_type len;
+
+ state = LOOK4START;
+ linenr = 1;
+ skipping = false;
+ len = data.length();
+ for (std::string::size_type i = 0; i < len; i++)
+ {
+ if (ReadChar(data[i]) != 0)
+ return -1;
+ if (progresscb)
+ {
+ percent = i * 100 / len;
+ if (percent > last)
+ {
+ progresscb(percent);
+ last = percent;
+ }
+ }
+ }
+ return 0;
+}
+
+bool cXML::IsTokenChar(bool start, int c)
+{
+ return isalpha(c) || c == '_' || (!start && isdigit(c));
+}
+
+int cXML::ReadChar(int c)
+{
+ // new line?
+ if (c == '\n')
+ linenr++;
+
+ switch (state)
+ {
+ // looking for element start
+ case LOOK4START:
+ if (c == '<')
+ {
+ if (cdatacb)
+ {
+ std::string::size_type pos = 0;
+ while ((pos = cdata.find('&', pos)) != std::string::npos)
+ {
+ if (cdata.substr(pos, 4) == "&lt;")
+ cdata.replace(pos, 4, "<");
+ else if (cdata.substr(pos, 4) == "&gt;")
+ cdata.replace(pos, 4, ">");
+ else if (cdata.substr(pos, 5) == "&amp;")
+ cdata.replace(pos, 5, "&");
+ pos++;
+ }
+ if (!cdatacb(trim(cdata)))
+ return -1;
+ }
+ cdata = "";
+ attr.clear();
+ tag = "";
+ state = LOOK4TAG;
+ }
+ else
+ cdata += c;
+ // silently ignore until resync
+ break;
+
+ // looking for element tag
+ case LOOK4TAG:
+ // skip comments and declarations.
+ if (skipping)
+ {
+ if (c == '>')
+ {
+ skipping = false;
+ state = LOOK4START;
+ }
+ break;
+ }
+ else
+ {
+ if (c == '?')
+ {
+ skipping = true;
+ break;
+ }
+ }
+ if (IsTokenChar(true, c))
+ {
+ tag += c;
+ state = INTAG;
+ }
+ else if (c == '/')
+ {
+ state = LOOK4CLOSETAG;
+ }
+ else if (c == '!')
+ {
+ state = INCOMMENT;
+ }
+ else if (!isspace(c))
+ {
+ if (parseerrorcb)
+ {
+ parseerrorcb(linenr, "Bogus tag char", c);
+ }
+ return -1;
+ }
+ break;
+
+ // reading tag
+ case INTAG:
+ if (IsTokenChar(false, c))
+ {
+ tag += c;
+ }
+ else if (c == '>')
+ {
+ if (nodestartcb)
+ if (!nodestartcb(tag, attr))
+ return -1;
+ state = LOOK4START;
+ }
+ else if (c == '/')
+ {
+ state = SAWSLASH;
+ }
+ else
+ {
+ state = LOOK4ATTRN;
+ }
+ break;
+
+ // reading comment
+ case INCOMMENT:
+ if (c == '-')
+ {
+ state = LOOK4CEND1;
+ }
+ break;
+
+ // looking for second '-' in "-->"
+ case LOOK4CEND1:
+ if (c == '-')
+ {
+ state = LOOK4CEND2;
+ }
+ else
+ {
+ state = INCOMMENT;
+ }
+ break;
+
+ // looking for '>' in "-->"
+ case LOOK4CEND2:
+ if (c == '>')
+ {
+ state = LOOK4START;
+ }
+ else if (c != '-')
+ {
+ state = INCOMMENT;
+ }
+ break;
+
+ // looking for attr name, > or /
+ case LOOK4ATTRN:
+ if (c == '>')
+ {
+ if (nodestartcb)
+ if (!nodestartcb(tag, attr))
+ return -1;
+ state = LOOK4START;
+ }
+ else if (c == '/')
+ {
+ state = SAWSLASH;
+ }
+ else if (IsTokenChar(true, c))
+ {
+ attrn = "";
+ attrn += c;
+ state = INATTRN;
+ }
+ else if (!isspace(c))
+ {
+ if (parseerrorcb)
+ {
+ parseerrorcb(linenr, "Bogus 1st attr name char", c);
+ }
+ return -2;
+ }
+ break;
+
+ // saw / in element opening
+ case SAWSLASH:
+ if (c == '>')
+ {
+ if (nodestartcb)
+ if (!nodestartcb(tag, attr))
+ return -1;
+ if (nodeendcb)
+ if (!nodeendcb(tag))
+ return -1;
+ state = LOOK4START;
+ }
+ else
+ {
+ if (parseerrorcb)
+ {
+ parseerrorcb(linenr, "Bogus char before >", c);
+ }
+ return -3;
+ }
+ break;
+
+ // reading attr name
+ case INATTRN:
+ if (IsTokenChar(false, c))
+ {
+ attrn += c;
+ }
+ else if (isspace(c) || c == '=')
+ {
+ state = LOOK4ATTRV;
+ }
+ else
+ {
+ if (parseerrorcb)
+ {
+ parseerrorcb(linenr, "Bogus attr name char", c);
+ }
+ return -4;
+ }
+ break;
+
+ // looking for attr value
+ case LOOK4ATTRV:
+ if (c == '\'' || c == '"')
+ {
+ delim = c;
+ attrv = "";
+ state = INATTRV;
+ }
+ else if (!(isspace(c) || c == '='))
+ {
+ if (parseerrorcb)
+ {
+ parseerrorcb(linenr, "No attribute value", c);
+ }
+ return -5;
+ }
+ break;
+
+ // in attr value
+ case INATTRV:
+ if (c == delim)
+ {
+ attr[attrn] = attrv;
+ state = LOOK4ATTRN;
+ }
+ else if (!iscntrl(c))
+ {
+ attrv += c;
+ }
+ break;
+
+ // looking for closing tag after <
+ case LOOK4CLOSETAG:
+ if (IsTokenChar(true, c))
+ {
+ tag += c;
+ state = INCLOSETAG;
+ }
+ else if (!isspace(c))
+ {
+ if (parseerrorcb)
+ {
+ parseerrorcb(linenr, "Bogus preend tag char", c);
+ }
+ return -6;
+ }
+ break;
+
+ // reading closing tag
+ case INCLOSETAG:
+ if (IsTokenChar(false, c))
+ {
+ tag += c;
+ }
+ else if (c == '>')
+ {
+ if (nodeendcb)
+ if (!nodeendcb(tag))
+ return 0;//XXX is that right? there was false before
+ state = LOOK4START;
+ }
+ else if (!isspace(c))
+ {
+ if (parseerrorcb)
+ {
+ parseerrorcb(linenr, "Bogus end tag char", c);
+ }
+ return -7;
+ }
+ break;
+ }
+
+ return 0;
+}
+
+} // end of namespace
diff --git a/glcdskin/xml.h b/glcdskin/xml.h
new file mode 100644
index 0000000..009679c
--- /dev/null
+++ b/glcdskin/xml.h
@@ -0,0 +1,71 @@
+/*
+ * GraphLCD skin library
+ *
+ * xml.h - xml parser class
+ *
+ * This file is released under the GNU General Public License. Refer
+ * to the COPYING file distributed with this package.
+ *
+ * based on text2skin xml parser
+ *
+ */
+
+#ifndef _GLCDSKIN_XML_H_
+#define _GLCDSKIN_XML_H_
+
+#include <string>
+#include <map>
+
+namespace GLCD
+{
+
+#define XML_NODE_START_CB(CB) \
+bool (*CB)(const std::string &tag, std::map<std::string, std::string> &attr)
+#define XML_NODE_END_CB(CB) \
+bool (*CB)(const std::string &tag)
+#define XML_CDATA_CB(CB) \
+bool (*CB)(const std::string &text)
+#define XML_PARSE_ERROR_CB(CB) \
+void (*CB)(int line, const char *txt, char c)
+#define XML_PROGRESS_CB(CB) \
+void (*CB)(int percent)
+
+class cXML
+{
+private:
+ bool skipping;
+ int state;
+ int linenr;
+ int delim;
+
+ std::string data, cdata, tag, attrn, attrv;
+ std::map<std::string, std::string> attr;
+
+ XML_NODE_START_CB(nodestartcb);
+ XML_NODE_END_CB(nodeendcb);
+ XML_CDATA_CB(cdatacb);
+ XML_PARSE_ERROR_CB(parseerrorcb);
+ XML_PROGRESS_CB(progresscb);
+
+protected:
+ bool IsTokenChar(bool start, int c);
+ int ReadChar(int c);
+
+public:
+ cXML(const std::string & file);
+ cXML(const char * mem, unsigned int len);
+
+ void SetNodeStartCB(XML_NODE_START_CB(cb));
+ void SetNodeEndCB(XML_NODE_END_CB(cb));
+ void SetCDataCB(XML_CDATA_CB(cb));
+ void SetParseErrorCB(XML_PARSE_ERROR_CB(cb));
+ void SetProgressCB(XML_PROGRESS_CB(cb));
+
+ int Parse(void);
+
+ int LineNr(void) const { return linenr; }
+};
+
+} // end of namespace
+
+#endif