Add wpseditor, the Google Summer of Code 2008 project of Rostislav Chekan. Closes FS#9327


git-svn-id: svn://svn.rockbox.org/rockbox/trunk@18362 a1c6a512-1295-4272-9138-f99709370657
diff --git a/apps/gui/wps_debug.c b/apps/gui/wps_debug.c
index 4e6af38..f843b98 100644
--- a/apps/gui/wps_debug.c
+++ b/apps/gui/wps_debug.c
@@ -25,7 +25,11 @@
 #include <string.h>
 #include "gwps.h"
 #ifdef __PCTOOL__
+#ifdef WPSEDITOR
+#include "proxy.h"
+#else
 #define DEBUGF printf
+#endif
 #else
 #include "debug.h"
 #endif
@@ -589,18 +593,18 @@
     {
         char buf[64];
 
-        DEBUGF("Failed parsing on line %d : ", line);
+        DEBUGF("ERR: Failed parsing on line %d : ", line);
         switch (fail)
         {
             case PARSE_OK:
                 break;
                 
             case PARSE_FAIL_UNCLOSED_COND:
-                DEBUGF("Unclosed conditional");
+                DEBUGF("ERR: Unclosed conditional");
                 break;
 
             case PARSE_FAIL_INVALID_CHAR:
-                DEBUGF("unexpected conditional char after token %d: \"%s\"",
+                DEBUGF("ERR: Unexpected conditional char after token %d: \"%s\"",
                        data->num_tokens-1,
                        get_token_desc(&data->tokens[data->num_tokens-1], data,
                                       buf, sizeof(buf))
@@ -608,7 +612,7 @@
                 break;
 
             case PARSE_FAIL_COND_SYNTAX_ERROR:
-                DEBUGF("Conditional syntax error after token %d: \"%s\"",
+                DEBUGF("ERR: Conditional syntax error after token %d: \"%s\"",
                        data->num_tokens-1,
                        get_token_desc(&data->tokens[data->num_tokens-1], data,
                                       buf, sizeof(buf))
@@ -616,7 +620,7 @@
                 break;
 
             case PARSE_FAIL_COND_INVALID_PARAM:
-                DEBUGF("Invalid parameter list for token %d: \"%s\"",
+                DEBUGF("ERR: Invalid parameter list for token %d: \"%s\"",
                        data->num_tokens,
                        get_token_desc(&data->tokens[data->num_tokens], data,
                                       buf, sizeof(buf))
@@ -624,7 +628,7 @@
                 break;
                 
             case PARSE_FAIL_LIMITS_EXCEEDED:
-                DEBUGF("Limits exceeded");
+                DEBUGF("ERR: Limits exceeded");
                 break;
         }
         DEBUGF("\n");
diff --git a/apps/gui/wps_parser.c b/apps/gui/wps_parser.c
index 714c419..b2baddd 100644
--- a/apps/gui/wps_parser.c
+++ b/apps/gui/wps_parser.c
@@ -28,14 +28,25 @@
 #include "plugin.h"
 
 #ifdef __PCTOOL__
+#ifdef WPSEDITOR
+#include "proxy.h"
+#include "settings.h"
+#include "sysfont.h"
+#include "gwps.h"
+#include "font.h"
+#include "bmp.h" 
+#include "backdrop.h" 
+#include "ctype.h" 
+#else
+#include "checkwps.h"
+#define SYSFONT_HEIGHT 8
 #define DEBUGF printf
+#endif /*WPSEDITOR*/
 #define FONT_SYSFIXED 0
 #define FONT_UI 1
-#define SYSFONT_HEIGHT 8
-#include "checkwps.h"
 #else
 #include "debug.h"
-#endif
+#endif /*__PCTOOL__*/
 
 #ifndef __PCTOOL__
 #include <ctype.h>
diff --git a/apps/misc.c b/apps/misc.c
index f3a937f..cd59dbc 100644
--- a/apps/misc.c
+++ b/apps/misc.c
@@ -27,7 +27,10 @@
 #ifdef __PCTOOL__
 #include <stdint.h>
 #include <stdarg.h>
-#include <unistd.h>
+#include <stdio.h>
+#ifdef WPSEDITOR
+#include "string.h"
+#endif
 #else
 #include "sprintf.h"
 #include "lang.h"
@@ -196,26 +199,6 @@
     return buffer;
 }
 
-/* Format time into buf.
- *
- * buf      - buffer to format to.
- * buf_size - size of buffer.
- * t        - time to format, in milliseconds.
- */
-void format_time(char* buf, int buf_size, long t)
-{
-    if ( t < 3600000 ) 
-    {
-      snprintf(buf, buf_size, "%d:%02d",
-               (int) (t / 60000), (int) (t % 60000 / 1000));
-    } 
-    else
-    {
-      snprintf(buf, buf_size, "%d:%02d:%02d",
-               (int) (t / 3600000), (int) (t % 3600000 / 60000),
-               (int) (t % 60000 / 1000));
-    }
-}
 
 #if CONFIG_RTC
 /* Create a filename with a date+time part.
@@ -1179,6 +1162,28 @@
 }
 #endif /* !defined(__PCTOOL__) */
 
+/* Format time into buf.
+ *
+ * buf      - buffer to format to.
+ * buf_size - size of buffer.
+ * t        - time to format, in milliseconds.
+ */
+void format_time(char* buf, int buf_size, long t)
+{
+    if ( t < 3600000 ) 
+    {
+      snprintf(buf, buf_size, "%d:%02d",
+               (int) (t / 60000), (int) (t % 60000 / 1000));
+    } 
+    else
+    {
+      snprintf(buf, buf_size, "%d:%02d:%02d",
+               (int) (t / 3600000), (int) (t % 3600000 / 60000),
+               (int) (t % 60000 / 1000));
+    }
+}
+
+
 /** Open a UTF-8 file and set file descriptor to first byte after BOM.
  *  If no BOM is present this behaves like open().
  *  If the file is opened for writing and O_TRUNC is set, write a BOM to
diff --git a/apps/settings.h b/apps/settings.h
index e90b1a8..9ef8323 100644
--- a/apps/settings.h
+++ b/apps/settings.h
@@ -51,6 +51,9 @@
 /* name of directory where configuration, fonts and other data
  * files are stored */
 #ifdef __PCTOOL__
+#undef ROCKBOX_DIR
+#undef ROCKBOX_DIR_LEN
+#undef WPS_DIR
 #define ROCKBOX_DIR "."
 #define ROCKBOX_DIR_LEN 1
 #else
diff --git a/docs/CREDITS b/docs/CREDITS
index f9bacd5..2d73b63 100644
--- a/docs/CREDITS
+++ b/docs/CREDITS
@@ -413,6 +413,7 @@
 Clément Pit-Claudel
 Jelle Geerts
 Tadeusz Pyś
+Rostislav Chekan
 
 The libmad team
 The wavpack team
diff --git a/firmware/font.c b/firmware/font.c
index 03e1891..465cec2 100644
--- a/firmware/font.c
+++ b/firmware/font.c
@@ -522,9 +522,11 @@
 {
 
     if (fnt_file >= 0) {
-
+#ifdef WPSEDITOR
+        glyph_file = open(GLYPH_CACHE_FILE, O_WRONLY|O_CREAT|O_TRUNC);
+#else
         glyph_file = creat(GLYPH_CACHE_FILE);
-
+#endif
         if (glyph_file < 0) return;
 
         lru_traverse(&font_cache_ui._lru, glyph_file_write);
diff --git a/firmware/include/inttypes.h b/firmware/include/inttypes.h
index 1697f69..f7f5099 100644
--- a/firmware/include/inttypes.h
+++ b/firmware/include/inttypes.h
@@ -22,6 +22,8 @@
 #ifndef __INTTYPES_H__
 #define __INTTYPES_H__
 
+#ifndef WPSEDITOR
+
 #include <limits.h>
 
 /* 8 bit */
@@ -103,5 +105,8 @@
 #define uint64_t    unsigned long long
 
 #endif
+#else
+#include <stdint.h>
+#endif /* !WPSEDITOR*/
 
 #endif /* __INTTYPES_H__ */
diff --git a/firmware/include/time.h b/firmware/include/time.h
index 23f72fd..9200e82 100644
--- a/firmware/include/time.h
+++ b/firmware/include/time.h
@@ -7,6 +7,11 @@
 #ifndef _TIME_H_
 #define _TIME_H_
 
+#ifdef WPSEDITOR
+#include <sys/types.h>
+#include <time.h>
+#endif
+
 struct tm
 {
   int	tm_sec;
@@ -34,3 +39,4 @@
 
 #endif /* _TIME_H_ */
 
+
diff --git a/firmware/mp3data.c b/firmware/mp3data.c
index 25e40f8..80870cd 100644
--- a/firmware/mp3data.c
+++ b/firmware/mp3data.c
@@ -550,6 +550,7 @@
     return bytecount;
 }
 
+#ifndef __PCTOOL__
 static void long2bytes(unsigned char *buf, long val)
 {
     buf[0] = (val >> 24) & 0xff;
@@ -558,7 +559,6 @@
     buf[3] = val & 0xff;
 }
 
-#ifndef __PCTOOL__
 int count_mp3_frames(int fd, int startpos, int filesize,
                      void (*progressfunc)(int))
 {
diff --git a/utils/wpseditor/README b/utils/wpseditor/README
new file mode 100644
index 0000000..3a8b87c
--- /dev/null
+++ b/utils/wpseditor/README
@@ -0,0 +1,21 @@
+               __________               __   ___.
+     Open      \______   \ ____   ____ |  | _\_ |__   _______  ___
+     Source     |       _//  _ \_/ ___\|  |/ /| __ \ /  _ \  \/  /
+     Jukebox    |    |   (  <_> )  \___|    < | \_\ (  <_> > <  <
+     Firmware   |____|_  /\____/ \___  >__|_ \|___  /\____/__/\_ \
+                       \/            \/     \/    \/            \/
+
+Installation 
+
+Windows:
+
+ * be sure that you have properly installed mingw, QT > 4.3.* 
+ * if you want to debug wpseditor, you'll have to build Qt debug libraries
+ * cd to rockbox/utils/wpseditor/ from Qt command promt and run qmake and then make
+ * >gui\bin\wpseditor.exe
+
+Linux:
+
+ * Make sure you have libqt4-dev installed and you have a working Rockbox environment
+ * cd to utils/wpseditor/ and do 'qmake-qt4 && make'
+ * cd to gui/bin/ and start WPS editor with './wpseditord'
diff --git a/utils/wpseditor/TODO b/utils/wpseditor/TODO
new file mode 100644
index 0000000..28f5591
--- /dev/null
+++ b/utils/wpseditor/TODO
@@ -0,0 +1,7 @@
+* Enable ability in gui to load different targets on the fly
+* Enable animation(timers,sliding lines, etc)
+* Test on Mac OS
+* Redesign GUI for more usability
+* Replace checkwps functionality
+* Include 'screenshot utility' functionality
+* Make editing via gui
diff --git a/utils/wpseditor/gui/gui.pro b/utils/wpseditor/gui/gui.pro
new file mode 100644
index 0000000..db7cfa1
--- /dev/null
+++ b/utils/wpseditor/gui/gui.pro
@@ -0,0 +1,40 @@
+TEMPLATE = app
+TARGET =
+DEPENDPATH += . build src ui
+INCLUDEPATH += . src/QPropertyEditor ../libwps/src
+DESTDIR = bin
+OBJECTS_DIR = build
+MOC_DIR = build
+UI_DIR = build
+QMAKE_LIBDIR += lib
+QT = gui core
+CONFIG += qt warn_on console debug_and_release
+libwps.commands += $(MAKE) -C ../libwps shared
+QMAKE_EXTRA_TARGETS += libwps
+PRE_TARGETDEPS += libwps
+HEADERS += ../libwps/src/api.h \
+ ../libwps/src/defs.h \
+ src/slider.h \
+ src/qtrackstate.h \
+ src/qwpsstate.h \
+ src/qwpseditorwindow.h \
+ src/utils.h \
+ src/qwpsdrawer.h
+FORMS += ui/mainwindow.ui ui/slider.ui
+SOURCES += src/main.cpp \
+ src/slider.cpp \
+ src/qtrackstate.cpp \
+ src/qwpsstate.cpp \
+ src/qwpseditorwindow.cpp \
+ src/utils.cpp \
+ src/qwpsdrawer.cpp \
+ src/qwpsdrawer_static.cpp
+LIBS += -Lbin
+CONFIG(debug, debug|release) {
+ LIBS +=  -lQPropertyEditord
+ TARGET =  wpseditord
+}
+CONFIG(release, debug|release) {
+ LIBS +=  -lQPropertyEditor
+ TARGET =  wpseditor
+}
diff --git a/utils/wpseditor/gui/src/QPropertyEditor/ColorCombo.cpp b/utils/wpseditor/gui/src/QPropertyEditor/ColorCombo.cpp
new file mode 100644
index 0000000..f5eeb03
--- /dev/null
+++ b/utils/wpseditor/gui/src/QPropertyEditor/ColorCombo.cpp
@@ -0,0 +1,73 @@
+// *************************************************************************************************
+//
+// QPropertyEditor v 0.1
+//
+// --------------------------------------
+// Copyright (C) 2007 Volker Wiendl
+//
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or any later version.
+//
+// This library 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
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+//
+//
+// This class is based on the Color Editor Factory Example by Trolltech
+//
+// *************************************************************************************************
+
+#include "ColorCombo.h"
+
+#include <Qt/qcolordialog.h>
+
+ColorCombo::ColorCombo(QWidget* parent /*= 0*/) : QComboBox(parent) {
+    QStringList colorNames = QColor::colorNames();
+    for (int i = 0; i < colorNames.size(); ++i) {
+        QColor color(colorNames[i]);
+        insertItem(i, colorNames[i]);
+        setItemData(i, color, Qt::DecorationRole);
+    }
+    addItem(tr("Custom"), QVariant((int)QVariant::UserType));
+    connect(this, SIGNAL(currentIndexChanged(int)), this, SLOT(currentChanged(int)));
+}
+
+
+ColorCombo::~ColorCombo() {}
+
+
+QColor ColorCombo::color() const {
+    return qVariantValue<QColor>(itemData(currentIndex(), Qt::DecorationRole));
+}
+
+void ColorCombo::setColor(QColor color) {
+    m_init = color;
+    setCurrentIndex(findData(color, int(Qt::DecorationRole)));
+    if (currentIndex() == -1) {
+        addItem(color.name());
+        setItemData(count()-1, color, Qt::DecorationRole);
+        setCurrentIndex(count()-1);
+    }
+}
+
+void ColorCombo::currentChanged(int index) {
+    if (itemData(index).isValid() && itemData(index) == QVariant((int)QVariant::UserType)) {
+        QColor color = QColorDialog::getColor(m_init, this);
+        if (color.isValid()) {
+            if (findData(color, int(Qt::DecorationRole)) == -1) {
+                addItem(color.name());
+                setItemData(count()-1, color, Qt::DecorationRole);
+            }
+            setCurrentIndex(findData(color, int(Qt::DecorationRole)));
+        } else
+            setCurrentIndex(findData(m_init));
+    }
+}
diff --git a/utils/wpseditor/gui/src/QPropertyEditor/ColorCombo.h b/utils/wpseditor/gui/src/QPropertyEditor/ColorCombo.h
new file mode 100644
index 0000000..530b05b
--- /dev/null
+++ b/utils/wpseditor/gui/src/QPropertyEditor/ColorCombo.h
@@ -0,0 +1,49 @@
+// *************************************************************************************************
+//
+// QPropertyEditor v 0.1
+//
+// --------------------------------------
+// Copyright (C) 2007 Volker Wiendl
+//
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or any later version.
+//
+// This library 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
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+//
+//
+// This class is based on the Color Editor Factory Example by Trolltech
+//
+// *************************************************************************************************
+
+#ifndef COLORCOMBO_H_
+#define COLORCOMBO_H_
+
+#include <Qt/qcombobox.h>
+
+class ColorCombo : public QComboBox {
+    Q_OBJECT
+public:
+    ColorCombo(QWidget* parent = 0);
+    virtual ~ColorCombo();
+
+    QColor color() const;
+    void setColor(QColor c);
+
+private slots:
+    void currentChanged(int index);
+
+private:
+    QColor m_init;
+
+};
+#endif
diff --git a/utils/wpseditor/gui/src/QPropertyEditor/Property.cpp b/utils/wpseditor/gui/src/QPropertyEditor/Property.cpp
new file mode 100644
index 0000000..0746d15
--- /dev/null
+++ b/utils/wpseditor/gui/src/QPropertyEditor/Property.cpp
@@ -0,0 +1,136 @@
+// ****************************************************************************************
+//
+// QPropertyEditor Library
+// --------------------------------------
+// Copyright (C) 2007 Volker Wiendl
+//
+// This file is part of the Horde3D Scene Editor.
+//
+// The QPropertyEditor Library 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 version 3 of the License
+//
+// The Horde3D Scene Editor 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, see <http://www.gnu.org/licenses/>.
+//
+// ****************************************************************************************
+
+#include "Property.h"
+#include "ColorCombo.h"
+
+#include <Qt/qmetaobject.h>
+#include <Qt/qspinbox.h>
+
+#include <limits.h>
+
+Property::Property(const QString& name /*= QString()*/, QObject* propertyObject /*= 0*/, QObject* parent /*= 0*/) : QObject(parent),
+        m_propertyObject(propertyObject) {
+    setObjectName(name);
+}
+
+QVariant Property::value(int /*role = Qt::UserRole*/) const {
+    if (m_propertyObject)
+        return m_propertyObject->property(qPrintable(objectName()));
+    else
+        return QVariant();
+}
+
+void Property::setValue(const QVariant &value) {
+    if (m_propertyObject)
+        m_propertyObject->setProperty(qPrintable(objectName()), value);
+}
+
+bool Property::isReadOnly() {
+    if (m_propertyObject && m_propertyObject->metaObject()->property(m_propertyObject->metaObject()->indexOfProperty(qPrintable(objectName()))).isWritable())
+        return false;
+    else
+        return true;
+}
+
+QWidget* Property::createEditor(QWidget *parent, const QStyleOptionViewItem &option) {
+    (void)option;
+    QWidget* editor = 0;
+    switch (value().type()) {
+    case QVariant::Color:
+        editor = new ColorCombo(parent);
+        break;
+    case QVariant::Int:
+        editor = new QSpinBox(parent);
+        editor->setProperty("minimum", -INT_MAX);
+        editor->setProperty("maximum", INT_MAX);
+        connect(editor, SIGNAL(valueChanged(int)), this, SLOT(setValue(int)));
+        break;
+    case QMetaType::Float:
+    case QVariant::Double:
+        editor = new QDoubleSpinBox(parent);
+        editor->setProperty("minimum", -INT_MAX);
+        editor->setProperty("maximum", INT_MAX);
+        connect(editor, SIGNAL(valueChanged(double)), this, SLOT(setValue(double)));
+        break;
+    default:
+        return editor;
+    }
+    return editor;
+}
+
+bool Property::setEditorData(QWidget *editor, const QVariant &data) {
+    switch (value().type()) {
+    case QVariant::Color:
+        static_cast<ColorCombo*>(editor)->setColor(data.value<QColor>());
+        return true;
+        ;
+    case QVariant::Int:
+        editor->blockSignals(true);
+        static_cast<QSpinBox*>(editor)->setValue(data.toInt());
+        editor->blockSignals(false);
+        return true;
+    case QMetaType::Float:
+    case QVariant::Double:
+        editor->blockSignals(true);
+        static_cast<QDoubleSpinBox*>(editor)->setValue(data.toDouble());
+        editor->blockSignals(false);
+        return true;
+    default:
+        return false;
+    }
+    return false;
+}
+
+QVariant Property::editorData(QWidget *editor) {
+    switch (value().type()) {
+    case QVariant::Color:
+        return QVariant::fromValue(static_cast<ColorCombo*>(editor)->color());
+    case QVariant::Int:
+        return QVariant(static_cast<QSpinBox*>(editor)->value());
+    case QMetaType::Float:
+    case QVariant::Double:
+        return QVariant(static_cast<QDoubleSpinBox*>(editor)->value());
+        break;
+    default:
+        return QVariant();
+    }
+}
+
+Property* Property::findPropertyObject(QObject* propertyObject) {
+    if (m_propertyObject == propertyObject)
+        return this;
+    for (int i=0; i<children().size(); ++i) {
+        Property* child = static_cast<Property*>(children()[i])->findPropertyObject(propertyObject);
+        if (child)
+            return child;
+    }
+    return 0;
+}
+
+void Property::setValue(double value) {
+    setValue(QVariant(value));
+}
+
+void Property::setValue(int value) {
+    setValue(QVariant(value));
+}
diff --git a/utils/wpseditor/gui/src/QPropertyEditor/Property.h b/utils/wpseditor/gui/src/QPropertyEditor/Property.h
new file mode 100644
index 0000000..52d6842
--- /dev/null
+++ b/utils/wpseditor/gui/src/QPropertyEditor/Property.h
@@ -0,0 +1,157 @@
+// *************************************************************************************************
+//
+// QPropertyEditor v 0.1
+//
+// --------------------------------------
+// Copyright (C) 2007 Volker Wiendl
+//
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or any later version.
+//
+// This library 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
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+//
+// *************************************************************************************************
+
+#ifndef PROPERTY_H_
+#define PROPERTY_H_
+
+#include <Qt/qwidget.h>
+#include <Qt/qstyleoption.h>
+#include <Qt/qvariant.h>
+
+/**
+ * The Property class is the base class for all properties in the QPropertyEditor
+ * You can implement custom properties inherited from this class to further enhence the
+ * functionality of the QPropertyEditor
+ */
+class Property : public QObject {
+    Q_OBJECT
+
+public:
+
+    /**
+     * Constructor
+     *
+     * @param name the name of the property within the propertyObject (will be used in the QPropertyEditorWidget view too)
+     * @param propertyObject the object that contains the property
+     * @param parent optional parent object 
+     */
+    Property(const QString& name = QString(), QObject* propertyObject = 0, QObject* parent = 0);
+
+    /**
+     * The value stored by this property
+     * @return QVariant the data converted to a QVariant
+     */
+    virtual QVariant value(int role = Qt::UserRole) const;
+    /**
+     * Sets the value stored by this property
+     * @param value the data converted to a QVariant
+     */
+    virtual void setValue(const QVariant& value);
+
+    /**
+     * Returns the QObject which contains the property managed by this instance
+     * @return QObject* pointer to the QObject that contains user defined properties
+     */
+    QObject* propertyObject() {
+        return m_propertyObject;
+    }
+
+    /**
+     * Flag if property is used for indicating a group or really manages a property
+     * @return bool true if this property is only used to display a category in the QPropertyEditorWidget
+     */
+    bool isRoot() {
+        return m_propertyObject == 0;
+    }
+
+    /**
+     * Flag if the property can be set
+     * @return bool true if this property has no set method
+     */
+    bool isReadOnly();
+
+    /**
+     * Returns the row of this instance within the QPropertyModel
+     * @return int row within the QPropertyModel
+     */
+    int row() {
+        return parent()->children().indexOf(this);
+    }
+
+    /**
+     * returns optional settings for the editor widget that is used to manipulate the properties value
+     * @return QString a string that contains property settings for the editor widget (e.g. "minimum=1.0;maximum=10.0;")
+     */
+    QString editorHints() {
+        return m_hints;
+    }
+
+    /**
+     * Sets properties for the editor widget that is used to manipulate the data value managed by this instance
+     * @param hints a string containing property settings for the editor widget that manipulates this property
+     */
+    virtual void setEditorHints(const QString& hints) {
+        m_hints = hints;
+    }
+
+    /**
+     * Creates an editor for the data managed by this instance
+     * @param parent widget the newly created editor widget will be child of
+     * @param option currently not used
+     * @return QWidget* pointer to the editor widget
+     */
+    virtual QWidget* createEditor(QWidget* parent, const QStyleOptionViewItem& option);
+
+    /**
+     * Returns the data of the editor widget used to manipulate this instance
+     * @return QVariant the data converted to a QVariant
+     */
+    virtual QVariant editorData(QWidget *editor);
+
+    /**
+     * Changes the editor widget's data to a specific value
+     * @param editor the editor widget
+     * @param data the data to set in the editor widget
+     * @return bool true if editor widget was set to the given data successfully, false if the data can not be set in the editor (e.g. wrong datatype)
+     */
+    virtual bool setEditorData(QWidget *editor, const QVariant& data);
+
+    /**
+     * Tries to find the first property that manages the given propertyObject
+     * @param propertyObject
+     * @return Property
+     */
+    Property* findPropertyObject(QObject* propertyObject);
+
+private slots:
+    /**
+     * This slot is used to immediately set the properties when the editor widget's value of a double or float 
+     * property has changed
+     * @param value the new value
+     */
+    void setValue(double value);
+    /**
+     * This slot is used to immediately set the properties when the editor widget's value of an integer
+     * property has changed
+     * @param value the new value
+     */
+    void setValue(int value);
+
+private:
+    QObject* m_propertyObject;
+    QString  m_hints;
+
+};
+
+#endif
diff --git a/utils/wpseditor/gui/src/QPropertyEditor/QPropertyEditor.pro b/utils/wpseditor/gui/src/QPropertyEditor/QPropertyEditor.pro
new file mode 100644
index 0000000..85fd29e
--- /dev/null
+++ b/utils/wpseditor/gui/src/QPropertyEditor/QPropertyEditor.pro
@@ -0,0 +1,26 @@
+TEMPLATE = lib
+CONFIG += staticlib debug_and_release
+SOURCES = ColorCombo.cpp \
+ Property.cpp \
+ QPropertyEditorWidget.cpp \
+ QPropertyModel.cpp \
+ QVariantDelegate.cpp
+HEADERS = ColorCombo.h \
+ Property.h \
+ QPropertyEditorWidget.h \
+ QPropertyModel.h \
+ QVariantDelegate.h
+INCLUDEPATH += .
+DESTDIR = ../../lib
+UI_DIR = .
+CONFIG(debug, debug|release) {
+ TARGET =  QPropertyEditord
+ OBJECTS_DIR =  ../../build/QPropertyEditor/debug
+ MOC_DIR =  ../../build/QPropertyEditor/debug
+}
+CONFIG(release, debug|release) {
+ TARGET =  QPropertyEditor
+ OBJECTS_DIR =  ../../build/QPropertyEditor/release
+ MOC_DIR =  ../../build/QPropertyEditor/release
+ DEFINES +=  QT_NO_DEBUG
+}
diff --git a/utils/wpseditor/gui/src/QPropertyEditor/QPropertyEditorWidget.cpp b/utils/wpseditor/gui/src/QPropertyEditor/QPropertyEditorWidget.cpp
new file mode 100644
index 0000000..fc4b90c
--- /dev/null
+++ b/utils/wpseditor/gui/src/QPropertyEditor/QPropertyEditorWidget.cpp
@@ -0,0 +1,56 @@
+// *************************************************************************************************
+//
+// QPropertyEditor v 0.1
+//
+// --------------------------------------
+// Copyright (C) 2007 Volker Wiendl
+//
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or any later version.
+//
+// This library 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
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+//
+// *************************************************************************************************
+
+#include "QPropertyEditorWidget.h"
+#include "QPropertyModel.h"
+#include "QVariantDelegate.h"
+#include "Property.h"
+
+QPropertyEditorWidget::QPropertyEditorWidget(QWidget* parent /*= 0*/) : QTreeView(parent) {
+    m_model = new QPropertyModel(this);
+    setModel(m_model);
+    setItemDelegate(new QVariantDelegate(this));
+}
+
+
+QPropertyEditorWidget::~QPropertyEditorWidget() {}
+
+void QPropertyEditorWidget::addObject(QObject* propertyObject) {
+    m_model->addItem(propertyObject);
+    expandToDepth(0);
+}
+
+void QPropertyEditorWidget::setObject(QObject* propertyObject) {
+    m_model->clear();
+    if (propertyObject)
+        addObject(propertyObject);
+}
+
+void QPropertyEditorWidget::updateObject(QObject* propertyObject) {
+    m_model->updateItem(propertyObject);
+}
+
+void QPropertyEditorWidget::setCustomPropertyCB(UserTypeCB callback) {
+    m_model->setCustomPropertyCB(callback);
+}
diff --git a/utils/wpseditor/gui/src/QPropertyEditor/QPropertyEditorWidget.h b/utils/wpseditor/gui/src/QPropertyEditor/QPropertyEditorWidget.h
new file mode 100644
index 0000000..2dab877
--- /dev/null
+++ b/utils/wpseditor/gui/src/QPropertyEditor/QPropertyEditorWidget.h
@@ -0,0 +1,113 @@
+// *************************************************************************************************
+//
+// QPropertyEditor v 0.1
+//
+// --------------------------------------
+// Copyright (C) 2007 Volker Wiendl
+//
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or any later version.
+//
+// This library 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
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+//
+// *************************************************************************************************
+
+#ifndef QPROPERTYEDITORWIDGET_H_
+#define QPROPERTYEDITORWIDGET_H_
+
+#include <Qt/qtreeview.h>
+
+class QPropertyModel;
+class Property;
+
+/**
+ * \mainpage QPropertyEditor
+ *
+ * \section intro_sec Introduction
+ *
+ * The main purpose for the QPropertyEditor is the visualization and manipulation of properties defined via the Q_PROPERTY macro in
+ * QObject based classes.
+ */
+
+/**
+ * \brief The QPropertyEditorWidget offers an easy to use mechanism to visualize properties of a class inherited from QObject.
+ *
+ * Qt provides a nice way to define class properties by using the Q_PROPERTY macro. The purpose of the QPropertyEditor
+ * is to visualize these properties in an easy way.
+ *
+ * To use the property editor, all you have to do is to create a class that defines it's properties by using Q_PROPERTY
+ * and to add this class by using the addObject() method of this QPropertyEditorWidget class.
+ * The QPropertyEditorWidget is inherited from QTreeView and will display the properties in a tree with two columns: Name and Value
+ *
+ * For basic data types the build in editor widgets of Qt will be used. The QPropertyEditor itself only defines an additional
+ * editor for QColor (based on the Color Editor Factory Example from Trolltech). But it can easily be extended by yourself
+ * either within the library or for special datatypes also outside of the library in your application.
+ */
+class QPropertyEditorWidget : public QTreeView {
+    Q_OBJECT
+public:
+
+    /**
+     * A typedef for a callback used to create user defined properties for custom datatypes
+     */
+    typedef Property* (*UserTypeCB)(const QString& name, QObject* propertyObject, Property* parent);
+
+    /**
+     * \brief Constructor 
+     *
+     * Creates a new editor widget based on QTreeView
+     * @param parent optional parent widget
+     */
+    QPropertyEditorWidget(QWidget* parent = 0);
+
+    /// Destructor
+    virtual ~QPropertyEditorWidget();
+
+    /**
+     * Adds the user properties of the given class to the QPropertyModel associated with this view
+     * 
+     * @param propertyObject the class inherited from QObject that contains user properties that should be 
+     *        managed by the QPropertyModel associated with this view
+     */
+    void addObject(QObject* propertyObject);
+
+    /**
+     * Similar to the addObject() method this method adds the properties of the given class to the QPropertyModel
+     * associated with this view. But in contrast to addObject() it will clear the model before, removing all
+     * previously added objects.
+     * 
+     * @param propertyObject  the class inherited from QObject that contains user properties that should be 
+     *        managed by the QPropertyModel associated with this view
+     */
+    void setObject(QObject* propertyObject);
+
+    /**
+     * Updates the view for the given object. This can be usefull if a property was changed programmatically instead
+     * of using the view. In this case the view normally will display the new property values only after the user clicked
+     * on it. To overcome this problem you can call updateObject with the object whose property was changed.
+     */
+    void updateObject(QObject* propertyObject);
+
+    /**
+     * If you define custom datatypes outside of this library the QPropertyModel will check if you
+     * also defined a callback that is responsible to create custom property classes inherited from Property to handle 
+     * these datatypes. With this method you can set such a callback that will create custom properties for custom datatypes.
+     */
+    void setCustomPropertyCB(UserTypeCB callback);
+
+private:
+    /// The Model for this view
+    QPropertyModel*   m_model;
+
+};
+#endif
diff --git a/utils/wpseditor/gui/src/QPropertyEditor/QPropertyModel.cpp b/utils/wpseditor/gui/src/QPropertyEditor/QPropertyModel.cpp
new file mode 100644
index 0000000..b147cd0
--- /dev/null
+++ b/utils/wpseditor/gui/src/QPropertyEditor/QPropertyModel.cpp
@@ -0,0 +1,236 @@
+// *************************************************************************************************
+//
+// QPropertyEditor v 0.1
+//
+// --------------------------------------
+// Copyright (C) 2007 Volker Wiendl
+//
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or any later version.
+//
+// This library 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
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+//
+// *************************************************************************************************
+
+#include "QPropertyModel.h"
+
+#include "Property.h"
+
+#include <Qt/qapplication.h>
+#include <Qt/qmetaobject.h>
+#include <Qt/qitemeditorfactory.h>
+
+struct PropertyPair {
+    PropertyPair(const QMetaObject* obj, QMetaProperty property) : Property(property), Object(obj) {}
+
+    QMetaProperty    Property;
+    const QMetaObject* Object;
+
+    bool operator==(const PropertyPair& other) const {
+        return QString(other.Property.name()) == QString(Property.name());
+    }
+};
+
+
+QPropertyModel::QPropertyModel(QObject* parent /*= 0*/) : QAbstractItemModel(parent), m_userCallback(0) {
+    m_rootItem = new Property("Root",0, this);
+}
+
+
+QPropertyModel::~QPropertyModel() {}
+
+QModelIndex QPropertyModel::index ( int row, int column, const QModelIndex & parent /*= QModelIndex()*/ ) const {
+    Property *parentItem = m_rootItem;
+    if (parent.isValid())
+        parentItem = static_cast<Property*>(parent.internalPointer());
+    if (row >= parentItem->children().size())
+        return QModelIndex();
+    return createIndex(row, column, parentItem->children().at(row));
+
+}
+
+QModelIndex QPropertyModel::parent ( const QModelIndex & index ) const {
+    if (!index.isValid())
+        return QModelIndex();
+
+    Property *childItem = static_cast<Property*>(index.internalPointer());
+    Property *parentItem = qobject_cast<Property*>(childItem->parent());
+
+    if (!parentItem || parentItem == m_rootItem)
+        return QModelIndex();
+
+    return createIndex(parentItem->row(), 0, parentItem);
+}
+
+int QPropertyModel::rowCount ( const QModelIndex & parent /*= QModelIndex()*/ ) const {
+    Property *parentItem = m_rootItem;
+    if (parent.isValid())
+        parentItem = static_cast<Property*>(parent.internalPointer());
+    return parentItem->children().size();
+}
+
+int QPropertyModel::columnCount ( const QModelIndex & parent /*= QModelIndex()*/ ) const {
+    (void)parent;
+    return 2;
+}
+
+QVariant QPropertyModel::data ( const QModelIndex & index, int role /*= Qt::DisplayRole*/ ) const {
+    if (!index.isValid())
+        return QVariant();
+
+    Property *item = static_cast<Property*>(index.internalPointer());
+    switch (role) {
+    case Qt::ToolTipRole:
+    case Qt::DecorationRole:
+    case Qt::DisplayRole:
+    case Qt::EditRole:
+        if (index.column() == 0)
+            return item->objectName();
+        if (index.column() == 1)
+            return item->value(role);
+    case Qt::BackgroundRole:
+        if (item->isRoot()) return QApplication::palette("QTreeView").brush(QPalette::Normal, QPalette::Button).color();
+        break;
+    };
+    return QVariant();
+}
+
+// edit methods
+bool QPropertyModel::setData ( const QModelIndex & index, const QVariant & value, int role /*= Qt::EditRole*/ ) {
+    if (index.isValid() && role == Qt::EditRole) {
+        Property *item = static_cast<Property*>(index.internalPointer());
+        item->setValue(value);
+        emit dataChanged(index, index);
+        return true;
+    }
+    return false;
+}
+
+Qt::ItemFlags QPropertyModel::flags ( const QModelIndex & index ) const {
+    if (!index.isValid())
+        return Qt::ItemIsEnabled;
+    Property *item = static_cast<Property*>(index.internalPointer());
+    // only allow change of value attribute
+    if (item->isRoot())
+        return Qt::ItemIsEnabled;
+    else if (item->isReadOnly())
+        return Qt::ItemIsDragEnabled | Qt::ItemIsSelectable;
+    else
+        return Qt::ItemIsDragEnabled | Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsEditable;
+}
+
+
+QVariant QPropertyModel::headerData ( int section, Qt::Orientation orientation, int role /*= Qt::DisplayRole*/ ) const {
+    if (orientation == Qt::Horizontal && role == Qt::DisplayRole) {
+        switch (section) {
+        case 0:
+            return tr("Name");
+        case 1:
+            return tr("Value");
+        }
+    }
+    return QVariant();
+}
+
+QModelIndex QPropertyModel::buddy ( const QModelIndex & index ) const {
+    if (index.isValid() && index.column() == 0)
+        return createIndex(index.row(), 1, index.internalPointer());
+    return index;
+}
+
+void QPropertyModel::addItem(QObject *propertyObject) {
+    // first create property <-> class hierarchy
+    QList<PropertyPair> propertyMap;
+    QList<const QMetaObject*> classList;
+    const QMetaObject* metaObject = propertyObject->metaObject();
+    do {
+        int count = metaObject->propertyCount();
+        for (int i=0; i<count; ++i) {
+            QMetaProperty property = metaObject->property(i);
+            if (property.isUser()) // Hide Qt specific properties
+            {
+                PropertyPair pair(metaObject, property);
+                int index = propertyMap.indexOf(pair);
+                if (index != -1)
+                    propertyMap[index] = pair;
+                else
+                    propertyMap.push_back(pair);
+            }
+        }
+        classList.push_front(metaObject);
+    } while ((metaObject = metaObject->superClass())!=0);
+
+    QList<const QMetaObject*> finalClassList;
+    // remove empty classes from hierarchy list
+    foreach(const QMetaObject* obj, classList) {
+        bool keep = false;
+        foreach(PropertyPair pair, propertyMap) {
+            if (pair.Object == obj) {
+                keep = true;
+                break;
+            }
+        }
+        if (keep)
+            finalClassList.push_back(obj);
+    }
+
+    // finally insert properties for classes containing them
+    int i=rowCount();
+    beginInsertRows(QModelIndex(), i, i + finalClassList.count());
+    foreach(const QMetaObject* metaObject, finalClassList) {
+        // Set default name of the hierarchy property to the class name
+        QString name = metaObject->className();
+        // Check if there is a special name for the class
+        int index = metaObject->indexOfClassInfo(qPrintable(name));
+        if (index != -1)
+            name = metaObject->classInfo(index).value();
+        // Create Property Item for class node
+        Property* propertyItem = new Property(name, 0, m_rootItem);
+        foreach(PropertyPair pair, propertyMap) {
+            // Check if the property is associated with the current class from the finalClassList
+            if (pair.Object == metaObject) {
+                QMetaProperty property(pair.Property);
+                Property* p = 0;
+                if (property.type() == QVariant::UserType && m_userCallback)
+                    p = m_userCallback(property.name(), propertyObject, propertyItem);
+                else
+                    p = new Property(property.name(), propertyObject, propertyItem);
+                int index = metaObject->indexOfClassInfo(property.name());
+                if (index != -1)
+                    p->setEditorHints(metaObject->classInfo(index).value());
+            }
+        }
+    }
+    endInsertRows();
+}
+
+void QPropertyModel::updateItem ( QObject* propertyObject, const QModelIndex& parent /*= QModelIndex() */ ) {
+    Property *parentItem = m_rootItem;
+    if (parent.isValid())
+        parentItem = static_cast<Property*>(parent.internalPointer());
+    if (parentItem->propertyObject() != propertyObject)
+        parentItem = parentItem->findPropertyObject(propertyObject);
+    if (parentItem) // Indicate view that the data for the indices have changed
+        dataChanged(createIndex(parentItem->row(), 0, static_cast<Property*>(parentItem)), createIndex(parentItem->row(), 1, static_cast<Property*>(parentItem)));
+}
+
+void QPropertyModel::clear() {
+    beginRemoveRows(QModelIndex(), 0, rowCount());
+    delete m_rootItem;
+    m_rootItem = new Property("Root",0, this);
+    endRemoveRows();
+}
+
+void QPropertyModel::setCustomPropertyCB(QPropertyEditorWidget::UserTypeCB callback) {
+    m_userCallback = callback;
+}
diff --git a/utils/wpseditor/gui/src/QPropertyEditor/QPropertyModel.h b/utils/wpseditor/gui/src/QPropertyEditor/QPropertyModel.h
new file mode 100644
index 0000000..8a52bbe
--- /dev/null
+++ b/utils/wpseditor/gui/src/QPropertyEditor/QPropertyModel.h
@@ -0,0 +1,105 @@
+// *************************************************************************************************
+//
+// QPropertyEditor v 0.1
+//
+// --------------------------------------
+// Copyright (C) 2007 Volker Wiendl
+//
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or any later version.
+//
+// This library 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
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+//
+// *************************************************************************************************
+#ifndef QPROPERTYMODEL_H_
+#define QPROPERTYMODEL_H_
+
+#include <Qt/qabstractitemmodel.h>
+#include <Qt/qmap.h>
+
+#include "QPropertyEditorWidget.h"
+
+class Property;
+
+/**
+ * The QPropertyModel handles the user defined properties of QObjects
+ */
+class QPropertyModel : public QAbstractItemModel {
+    Q_OBJECT
+public:
+    /**
+     * Constructor
+     * @param parent optional parent object
+     */
+    QPropertyModel(QObject* parent = 0);
+    /// Destructor
+    virtual ~QPropertyModel();
+
+    /// QAbstractItemModel implementation
+    QModelIndex index ( int row, int column, const QModelIndex & parent = QModelIndex() ) const;
+
+    /// QAbstractItemModel implementation
+    QModelIndex parent ( const QModelIndex & index ) const;
+    /// QAbstractItemModel implementation
+    int rowCount ( const QModelIndex & parent = QModelIndex() ) const;
+    /// QAbstractItemModel implementation
+    int columnCount ( const QModelIndex & parent = QModelIndex() ) const;
+    /// QAbstractItemModel implementation
+    QVariant data ( const QModelIndex & index, int role = Qt::DisplayRole ) const;
+
+    /// QAbstractItemModel implementation
+    bool setData ( const QModelIndex & index, const QVariant & value, int role = Qt::EditRole );
+    /// QAbstractItemModel implementation
+    Qt::ItemFlags flags ( const QModelIndex & index ) const;
+
+    /// QAbstractItemModel implementation
+    QVariant headerData ( int section, Qt::Orientation orientation, int role = Qt::DisplayRole ) const;
+
+    /// QAbstractItemModel implementation
+    QModelIndex buddy ( const QModelIndex & index ) const;
+
+    /**
+     * Adds the user properties of the given class to the QPropertyModel instance
+     * 
+     * @param propertyObject the class inherited from QObject that contains user properties that should be 
+     *        managed by this instance
+     */
+    void addItem(QObject* propertyObject);
+
+    /**
+     * Creates a dataChanged signal for the given object
+     * @param propertyObject the instance of a QObject based class that should be updated 
+     * @param parent optional model index the propertyObject is child of
+     */
+    void updateItem ( QObject* propertyObject, const QModelIndex& parent = QModelIndex() ) ;
+
+    /**
+     * Removes all objects from the model
+     */
+    void clear();
+
+    /**
+     * Sets custom callback that will be used to create Property instances for custom datatypes
+     */
+    void setCustomPropertyCB(QPropertyEditorWidget::UserTypeCB callback);
+
+private:
+
+    /// The Root Property for all objects
+    Property*       m_rootItem;
+
+    /// Custom callback
+    QPropertyEditorWidget::UserTypeCB m_userCallback;
+
+};
+#endif
diff --git a/utils/wpseditor/gui/src/QPropertyEditor/QVariantDelegate.cpp b/utils/wpseditor/gui/src/QPropertyEditor/QVariantDelegate.cpp
new file mode 100644
index 0000000..ebda9b2
--- /dev/null
+++ b/utils/wpseditor/gui/src/QPropertyEditor/QVariantDelegate.cpp
@@ -0,0 +1,105 @@
+// *************************************************************************************************
+//
+// QPropertyEditor v 0.1
+//
+// --------------------------------------
+// Copyright (C) 2007 Volker Wiendl
+//
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or any later version.
+//
+// This library 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
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+//
+// *************************************************************************************************
+
+#include "QVariantDelegate.h"
+
+#include "Property.h"
+
+#include <Qt/qabstractitemview.h>
+
+
+QVariantDelegate::QVariantDelegate(QObject* parent) : QItemDelegate(parent) {}
+
+
+QVariantDelegate::~QVariantDelegate() {}
+
+QWidget *QVariantDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem& option , const QModelIndex & index ) const {
+    QWidget* editor = 0;
+    Property* p = static_cast<Property*>(index.internalPointer());
+    switch (p->value().type()) {
+    case QVariant::Color:
+    case QVariant::Int:
+    case QMetaType::Float:
+    case QVariant::Double:
+    case QVariant::UserType:
+        editor = p->createEditor(parent, option);
+        if (editor) break; // if no editor could be created take default case
+    default:
+        editor = QItemDelegate::createEditor(parent, option, index);
+    }
+    parseEditorHints(editor, p->editorHints());
+    return editor;
+}
+
+void QVariantDelegate::setEditorData(QWidget *editor, const QModelIndex &index) const {
+    QVariant data = index.model()->data(index, Qt::EditRole);
+    switch (data.type()) {
+    case QVariant::Color:
+    case QMetaType::Double:
+    case QMetaType::Float:
+    case QVariant::UserType:
+        if (static_cast<Property*>(index.internalPointer())->setEditorData(editor, data)) // if editor couldn't be recognized use default
+            break;
+    default:
+        QItemDelegate::setEditorData(editor, index);
+        break;
+    }
+}
+
+void QVariantDelegate::setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const {
+    QVariant data = index.model()->data(index, Qt::EditRole);
+    switch (data.type()) {
+    case QVariant::Color:
+    case QMetaType::Double:
+    case QMetaType::Float:
+    case QVariant::UserType: {
+            QVariant data = static_cast<Property*>(index.internalPointer())->editorData(editor);
+            if (data.isValid()) {
+                model->setData(index, data , Qt::EditRole);
+                break;
+            }
+        }
+    default:
+        QItemDelegate::setModelData(editor, model, index);
+        break;
+    }
+}
+
+void QVariantDelegate::updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option, const QModelIndex& index ) const {
+    return QItemDelegate::updateEditorGeometry(editor, option, index);
+}
+
+void QVariantDelegate::parseEditorHints(QWidget* editor, const QString& editorHints) const {
+    if (editor && !editorHints.isEmpty()) {
+        // Parse for property values
+        QRegExp rx("(.*)(=\\s*)(.*)(;{1})");
+        rx.setMinimal(true);
+        int pos = 0;
+        while ((pos = rx.indexIn(editorHints, pos)) != -1) {
+            qDebug("Setting %s to %s", qPrintable(rx.cap(1)), qPrintable(rx.cap(3)));
+            editor->setProperty(qPrintable(rx.cap(1).trimmed()), rx.cap(3).trimmed());
+            pos += rx.matchedLength();
+        }
+    }
+}
diff --git a/utils/wpseditor/gui/src/QPropertyEditor/QVariantDelegate.h b/utils/wpseditor/gui/src/QPropertyEditor/QVariantDelegate.h
new file mode 100644
index 0000000..e06265a
--- /dev/null
+++ b/utils/wpseditor/gui/src/QPropertyEditor/QVariantDelegate.h
@@ -0,0 +1,78 @@
+// *************************************************************************************************
+//
+// QPropertyEditor v 0.1
+//
+// --------------------------------------
+// Copyright (C) 2007 Volker Wiendl
+//
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or any later version.
+//
+// This library 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
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+//
+// *************************************************************************************************
+
+#ifndef COLORSELECTIONBUTTON_H_
+#define COLORSELECTIONBUTTON_H_
+
+#include <Qt/qitemdelegate.h>
+
+
+/**
+ * This class is used to create the editor widgets for datatypes encapsulated in QVariant variables
+ */
+class QVariantDelegate : public QItemDelegate {
+    Q_OBJECT
+
+public:
+    /**
+     * Constructor 
+     * @param parent optional parent object
+     */
+    QVariantDelegate(QObject* parent = 0);
+    /// Destructor
+    virtual ~QVariantDelegate();
+
+    /**
+     * Creates an editor widget as child of a given widget for a specific QModelIndex
+     * 
+     * @param parent the parent widget for the editor
+     * @param option some style options that the editor should use
+     * @param index the index of the item the editor will be created for
+     * @return QWidget the editor widget
+     */
+    QWidget *createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const;
+
+    /**
+     * Tries to set the editor data based on the value stored at a specific QModelIndex
+     * @param editor the editor widget
+     * @param index the model index of the value that should be used in the editor
+     */
+    virtual void setEditorData(QWidget *editor, const QModelIndex &index) const;
+
+    /**
+     * Sets the data of a specific QModelIndex to tha value of the editor widget
+     * @param editor the editor widget that contains the new value
+     * @param model the model that contains the index
+     * @param index the index within the model whose data value should be set to the data value of the editor
+     */
+    virtual void setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const;
+
+    /// QItemDelegate implementation
+    virtual void updateEditorGeometry(QWidget *editor,  const QStyleOptionViewItem &option, const QModelIndex &index) const;
+
+protected:
+    void parseEditorHints(QWidget* editor, const QString& editorHints) const;
+
+};
+#endif
diff --git a/utils/wpseditor/gui/src/main.cpp b/utils/wpseditor/gui/src/main.cpp
new file mode 100644
index 0000000..0ba22c9
--- /dev/null
+++ b/utils/wpseditor/gui/src/main.cpp
@@ -0,0 +1,16 @@
+#include <QApplication>
+#include "qwpseditorwindow.h"
+#include "utils.h"
+#include <QPointer>
+
+QPointer<QWpsEditorWindow> win;
+
+int main(int argc, char ** argv) {
+    QApplication app( argc, argv );
+
+    win = new QWpsEditorWindow;
+    win->show();
+    app.connect( &app, SIGNAL( lastWindowClosed() ), &app, SLOT( quit() ) );
+
+    return app.exec();
+}
diff --git a/utils/wpseditor/gui/src/qtrackstate.cpp b/utils/wpseditor/gui/src/qtrackstate.cpp
new file mode 100644
index 0000000..dad2f9a
--- /dev/null
+++ b/utils/wpseditor/gui/src/qtrackstate.cpp
@@ -0,0 +1,41 @@
+#include "qtrackstate.h"
+#include <stdlib.h>
+
+//
+QTrackState::QTrackState(  )
+        : QObject() {
+    memset(&state,0,sizeof(state));
+    state.title = (char*)"title";
+    state.artist = (char*)"artist";
+    state.album = (char*)"album";
+    state.length = 100;
+    state.elapsed = 50;
+}
+
+void QTrackState::setTitle(const QString& name) {
+    state.title = new char[name.length()];
+    strcpy(state.title,name.toAscii());
+    emit stateChanged(state);
+}
+
+void QTrackState::setArtist(const QString& name) {
+    state.artist = new char[name.length()];
+    strcpy(state.artist,name.toAscii());
+    emit stateChanged(state);
+}
+
+void QTrackState::setAlbum(const QString& name) {
+    state.album = new char[name.length()];
+    strcpy(state.album,name.toAscii());
+    emit stateChanged(state);
+}
+
+void QTrackState::setLength(int le) {
+    state.length = le;
+    emit stateChanged(state);
+}
+
+void QTrackState::setElapsed(int le) {
+    state.elapsed = le;
+    emit stateChanged(state);
+}
diff --git a/utils/wpseditor/gui/src/qtrackstate.h b/utils/wpseditor/gui/src/qtrackstate.h
new file mode 100644
index 0000000..b57f7a8
--- /dev/null
+++ b/utils/wpseditor/gui/src/qtrackstate.h
@@ -0,0 +1,57 @@
+#ifndef __QTRACKSTATE_H__
+#define __QTRACKSTATE_H__
+
+#include "wpsstate.h"
+#include <QObject>
+
+class QWpsState;
+
+class QTrackState : public QObject {
+    Q_OBJECT
+    Q_CLASSINFO ( "QTrackState", "Mp3 State" );
+    Q_PROPERTY ( QString Title READ title WRITE setTitle DESIGNABLE true USER true )
+    Q_PROPERTY ( QString Artist READ artist WRITE setArtist DESIGNABLE true USER true )
+    Q_PROPERTY ( QString Album READ album WRITE setAlbum DESIGNABLE true USER true )
+    Q_PROPERTY ( int Length READ length WRITE setLength DESIGNABLE true USER true )
+    Q_CLASSINFO("Length", "readOnly=true;value=100");
+    Q_PROPERTY ( int Elapsed READ elapsed WRITE setElapsed DESIGNABLE true USER true )
+    Q_CLASSINFO("Elapsed", "minimum=0;maximum=100;value=50");
+
+
+    trackstate state;
+
+public:
+    QTrackState();
+
+public slots:
+    QString title() const {
+        return state.title;
+    }
+    void setTitle ( const QString& name );
+
+    QString artist() const {
+        return state.artist;
+    }
+    void setArtist ( const QString& name );
+
+    QString album() const {
+        return state.album;
+    }
+    void setAlbum ( const QString& name );
+
+    int length() const {
+        return state.length;
+    }
+    void setLength ( int l );
+
+    int elapsed() const {
+        return state.elapsed;
+    }
+    void setElapsed ( int l );
+
+signals:
+    void stateChanged ( trackstate state );
+
+};
+
+#endif // __QTRACKSTATE_H__
diff --git a/utils/wpseditor/gui/src/qwpsdrawer.cpp b/utils/wpseditor/gui/src/qwpsdrawer.cpp
new file mode 100644
index 0000000..ab8a4b3
--- /dev/null
+++ b/utils/wpseditor/gui/src/qwpsdrawer.cpp
@@ -0,0 +1,200 @@
+#include "qwpsdrawer.h"
+#include "slider.h"
+#include "utils.h"
+#include <QtGui>
+#include <QLibrary>
+#include <stdarg.h>
+//
+
+
+QPointer<QWpsDrawer> drawer;
+QPixmap   *QWpsDrawer::pix = NULL;
+QString   QWpsDrawer::mTmpWpsString;
+QImage    QWpsDrawer::backdrop;
+proxy_api QWpsDrawer::api;
+
+QWpsDrawer::QWpsDrawer( QWpsState *ws,QTrackState *ms, QWidget *parent )
+        : QWidget(parent),wpsState(ws),trackState(ms),showGrid(false),mTargetLibName("libwps") {
+
+    tryResolve();
+    memset(&api,0,sizeof(struct proxy_api));
+
+    api.verbose = 2;
+    api.putsxy =                    &QWpsDrawer::putsxy;
+    api.transparent_bitmap_part =   &QWpsDrawer::transparent_bitmap_part;
+    api.bitmap_part =               &QWpsDrawer::bitmap_part;
+    api.drawpixel =                 &QWpsDrawer::drawpixel;
+    api.fillrect =                  &QWpsDrawer::fillrect;
+    api.hline =                     &QWpsDrawer::hline;
+    api.vline =                     &QWpsDrawer::vline;
+    api.clear_viewport =            &QWpsDrawer::clear_viewport;
+    api.load_wps_backdrop =         &QWpsDrawer::load_wps_backdrop;
+    api.read_bmp_file =             &QWpsDrawer::read_bmp_file;
+    api.debugf =                    &qlogger;
+    newTempWps();
+}
+
+bool QWpsDrawer::tryResolve() {
+    QLibrary lib(qApp->applicationDirPath()+"/"+mTargetLibName);
+    wps_init = (pfwps_init)lib.resolve("wps_init");
+    wps_display = (pfwps_display)lib.resolve("wps_display");
+    wps_refresh = (pfwps_refresh)lib.resolve("wps_refresh");
+    mResolved = wps_init && wps_display && wps_refresh;
+    if (!mResolved)
+        DEBUGF1(tr("ERR: Failed to resolve funcs!"));
+    return mResolved;
+}
+QWpsDrawer::~QWpsDrawer() {
+    qDebug()<<"QWpsDrawer::~QWpsDrawer()";
+    cleanTemp();
+}
+
+void QWpsDrawer::mouseReleaseEvent ( QMouseEvent * event ) {
+    Q_UNUSED(event);
+    /*int x = event->x() - (this->width()-pix->width())/2,
+            y = event->y() - (this->height()-pix->height())/2;
+    DEBUGF1("x=%d,y=%d",x,y);*/
+}
+void QWpsDrawer::newTempWps() {
+    QTemporaryFile    tmpWps;
+    tmpWps.setAutoRemove(false);
+    tmpWps.setFileTemplate(QDir::tempPath()+"/XXXXXXXXXX.wps");
+    if (tmpWps.open()) {
+        QString tmpDir = tmpWps.fileName().left(tmpWps.fileName().length()-4);
+        if (QDir::temp().mkpath(tmpDir)) {
+            mTmpWpsString = tmpDir;
+            DEBUGF1(mTmpWpsString);
+        }
+    }
+}
+
+void QWpsDrawer::WpsInit(QString buffer, bool isFile) {
+
+    if (!mResolved)
+        if (!tryResolve())
+            return;
+    if (isFile) {
+        cleanTemp();
+        DEBUGF1( tr("Loading %1").arg(buffer));
+        QFile file(buffer);
+        if (file.open(QIODevice::ReadOnly | QIODevice::Text))
+            mWpsString = file.readAll();
+        newTempWps();
+    } else
+        mWpsString = buffer;
+    {
+        QFile tfile(mTmpWpsString+".wps");
+        if (tfile.open(QIODevice::WriteOnly | QIODevice::Text))
+            tfile.write(mWpsString.toAscii(),mWpsString.length());
+    }
+
+    if (isFile)
+        wps_init(buffer.toAscii(), &api, isFile);
+    else
+        wps_init(QString(mTmpWpsString+".wps").toAscii(), &api, true);
+    pix = new QPixmap(api.getwidth(),api.getheight());
+
+    drawBackdrop();
+
+    setMinimumWidth(api.getwidth());
+    setMinimumHeight(api.getheight());
+
+    update();
+}
+
+void QWpsDrawer::paintEvent(QPaintEvent * event) {
+    if (!mResolved)
+        return;
+    if (pix==NULL)
+        return;
+    QPainter p(this);
+    QRect rect = event->rect();
+
+    drawBackdrop();
+    wps_refresh();
+
+    if (showGrid) {
+        QPainter g(pix);
+        viewport_api avp;
+        api.get_current_vp(&avp);
+
+        g.setPen(Qt::green);
+
+        for (int i=0;i*avp.fontheight/1.5<avp.width ;i++) {
+            g.drawLine(int(i*avp.fontheight/1.5), 0, int(i*avp.fontheight/1.5), avp.height);
+        }
+        for (int j=0;j*avp.fontheight<avp.height; j++) {
+            g.drawLine(0,j*avp.fontheight,avp.width,j*avp.fontheight);
+        }
+    }
+
+    p.drawPixmap((rect.width()-pix->width())/2,(rect.height()-pix->height())/2,*pix);
+
+}
+
+void QWpsDrawer::clear_viewport(int x,int y,int w,int h, int color) {
+    DEBUGF2("clear_viewport(int x=%d,int y=%d,int w=%d,int h=%d, int color)",x,y,w,h);
+    QPainter p(pix);
+    //p.setOpacity(0.1);
+    //QImage img = backdrop.copy(x,y,w,h);
+    //p.drawImage(x,y,img);
+}
+
+void QWpsDrawer::slotSetVolume() {
+    Slider *slider = new Slider(this, tr("Volume"),-74,10);
+    slider->show();
+    connect(slider, SIGNAL(valueChanged(int)), wpsState, SLOT(setVolume(int)));
+    connect(this, SIGNAL(destroyed()),slider, SLOT(close()));
+}
+
+void QWpsDrawer::slotSetProgress() {
+    Slider *slider = new Slider(this,tr("Progress"),0,100);
+    slider->show();
+    connect(slider, SIGNAL(valueChanged(int)), trackState, SLOT(setElapsed(int)));
+    connect(this, SIGNAL(destroyed()),slider, SLOT(close()));
+}
+
+void QWpsDrawer::slotWpsStateChanged(wpsstate ws_) {
+    if (api.set_wpsstate)
+        api.set_wpsstate(ws_);
+    update();
+}
+
+void QWpsDrawer::slotTrackStateChanged(trackstate ms_) {
+    if (api.set_wpsstate)
+        api.set_trackstate(ms_);
+    update();
+}
+
+void QWpsDrawer::slotShowGrid(bool show) {
+    showGrid = show;
+    update();
+}
+
+void QWpsDrawer::drawBackdrop() {
+    QPainter b(pix);
+    QImage pink = backdrop.createMaskFromColor(qRgb(255,0,255),Qt::MaskOutColor);
+    backdrop.setAlphaChannel(pink);
+    b.drawImage(0,0,backdrop);
+}
+
+void QWpsDrawer::slotSetAudioStatus(int status) {
+    api.set_audio_status(status);
+    update();
+}
+
+void QWpsDrawer::cleanTemp(bool fileToo) {
+    if (fileToo)
+        QFile::remove(mTmpWpsString+".wps");
+    QDirIterator it(mTmpWpsString, QDirIterator::Subdirectories);
+    while (it.hasNext()) {
+        QFile::remove(it.next());
+    }
+    QDir(mTmpWpsString).rmdir(mTmpWpsString);
+}
+
+void QWpsDrawer::closeEvent(QCloseEvent *event) {
+    qDebug()<<"QWpsDrawer::closeEvent()";
+    cleanTemp();
+    event->accept();
+}
diff --git a/utils/wpseditor/gui/src/qwpsdrawer.h b/utils/wpseditor/gui/src/qwpsdrawer.h
new file mode 100644
index 0000000..d4dfa6c
--- /dev/null
+++ b/utils/wpseditor/gui/src/qwpsdrawer.h
@@ -0,0 +1,82 @@
+#ifndef WPSDRAWER_H
+#define WPSDRAWER_H
+//
+#include <QWidget>
+#include <QPixmap>
+#include <QPointer>
+#include <QTemporaryFile>
+#include "api.h"
+#include "qtrackstate.h"
+#include "qwpsstate.h"
+//
+
+typedef int (*pfwps_init)(const char* buff,struct proxy_api *api, bool isfile);
+typedef int (*pfwps_display)();
+typedef int (*pfwps_refresh)();
+
+class QWpsDrawer : public QWidget {
+    Q_OBJECT
+
+    pfwps_init    wps_init;
+    pfwps_display wps_display;
+    pfwps_refresh wps_refresh;
+
+    static QPixmap    *pix;
+    static QImage     backdrop;
+
+    QWpsState         *wpsState;
+    QTrackState       *trackState;
+
+    bool              showGrid;
+    bool              mResolved;
+    QString           mWpsString;
+    QString           mTargetLibName;
+    static QString    mTmpWpsString;
+
+
+protected:
+    virtual void paintEvent(QPaintEvent * event);
+    virtual void closeEvent(QCloseEvent *event);
+    virtual void mouseReleaseEvent ( QMouseEvent * event ) ;
+    void drawBackdrop();
+    void newTempWps();
+    void cleanTemp(bool fileToo=true);
+    bool tryResolve();
+public:
+    QWpsDrawer(QWpsState *ws,QTrackState *ms, QWidget *parent=0);
+    ~QWpsDrawer();
+    void WpsInit(QString buffer, bool isFile = true);
+
+    QString wpsString() const {
+        return mWpsString;
+    };
+    QString tempWps() const {
+        return mTmpWpsString;
+    };
+
+
+    static proxy_api api;
+    /***********Drawing api******************/
+    static void putsxy(int x, int y, const unsigned char *str);
+    static void transparent_bitmap_part(const void *src, int src_x, int src_y,
+                                        int stride, int x, int y, int width, int height);
+    static void bitmap_part(const void *src, int src_x, int src_y,
+                            int stride, int x, int y, int width, int height);
+    static void drawpixel(int x, int y);
+    static void fillrect(int x, int y, int width, int height);
+    static void hline(int x1, int x2, int y);
+    static void vline(int x, int y1, int y2);
+    static void clear_viewport(int x,int y,int w,int h, int color);
+    static bool load_wps_backdrop(char* filename);
+    static int  read_bmp_file(const char* filename,int *width, int *height);
+    /****************************************/
+public slots:
+    void slotSetVolume();
+    void slotSetProgress();
+
+    void slotShowGrid(bool);
+    void slotWpsStateChanged(wpsstate);
+    void slotTrackStateChanged(trackstate);
+    void slotSetAudioStatus(int);
+};
+#endif
diff --git a/utils/wpseditor/gui/src/qwpsdrawer_static.cpp b/utils/wpseditor/gui/src/qwpsdrawer_static.cpp
new file mode 100644
index 0000000..bf94d28
--- /dev/null
+++ b/utils/wpseditor/gui/src/qwpsdrawer_static.cpp
@@ -0,0 +1,77 @@
+#include "qwpsdrawer.h"
+#include <QPainter>
+#include <QFile>
+#include <QFileInfo>
+#include "utils.h"
+
+void QWpsDrawer::putsxy(int x, int y, const unsigned char *str) {
+    QPainter p(pix);
+    viewport_api avp;
+    api.get_current_vp(&avp);
+    p.setPen(Qt::gray);
+
+
+    QFont font("times",avp.fontheight,QFont::Bold);
+    p.setFont(font);
+    p.drawText(x+avp.x,y + avp.fontheight + avp.y,(char*)str);
+}
+void QWpsDrawer::transparent_bitmap_part(const void *src, int src_x, int src_y,
+        int stride, int x, int y, int width, int height) {
+    QImage img;
+    img.load((char*)src);
+    DEBUGF2("transparent_bitmap_part(const void *src=%s, int src_x=%d, int src_y=%d,int stride=%d, int x=%d, int y=%d, int width=%d, int height=%d",(char*)src,src_x, src_y,stride, x, y, width, height);
+    QPainter p(pix);
+    QPoint target(x,y);
+    QRectF source(src_x, src_y, width, height);
+
+    QImage pink = img.createMaskFromColor(qRgb(255,0,255),Qt::MaskOutColor);
+    img.setAlphaChannel(pink);
+
+    p.drawImage(target, img, source);
+}
+void QWpsDrawer::bitmap_part(const void *src, int src_x, int src_y,
+                             int stride, int x, int y, int width, int height) {
+    transparent_bitmap_part(src,src_x,src_y,stride,x,y,width,height);
+}
+void QWpsDrawer::drawpixel(int x, int y) {
+    QPainter p(pix);
+    p.setPen(Qt::blue);
+    p.drawPoint(x,y);
+}
+void QWpsDrawer::fillrect(int x, int y, int width, int height) {
+    QPainter p(pix);
+    DEBUGF2("fillrect(int x=%d, int y=%d, int width=%d, int height=%d)\n",x, y, width, height);
+    p.setPen(Qt::green);
+}
+void QWpsDrawer::hline(int x1, int x2, int y) {
+    QPainter p(pix);
+    p.setPen(Qt::black);
+    p.drawLine(x1,y,x2,y);
+}
+void QWpsDrawer::vline(int x, int y1, int y2) {
+    QPainter p(pix);
+    p.setPen(Qt::black);
+    p.drawLine(x,y1,x,y2);
+}
+bool QWpsDrawer::load_wps_backdrop(char* filename) {
+    DEBUGF2("load backdrop: %s", filename);
+    QFile file(filename);
+    QFileInfo info(file);
+    file.copy(mTmpWpsString+"/"+info.fileName());
+    backdrop.load(filename);
+    return true;
+}
+
+int QWpsDrawer::read_bmp_file(const char* filename,int *width, int *height) {
+    QImage img;
+
+    QFile file(filename);
+    QFileInfo info(file);
+    file.copy(mTmpWpsString+"/"+info.fileName());
+
+    img.load(filename);
+    //qDebug()<<"QWpsDrawer::read_bmp_file"<<img.width()<<img.height();
+    *width = img.width();
+    *height = img.height();
+    return 1;
+}
diff --git a/utils/wpseditor/gui/src/qwpseditorwindow.cpp b/utils/wpseditor/gui/src/qwpseditorwindow.cpp
new file mode 100644
index 0000000..c3090bd
--- /dev/null
+++ b/utils/wpseditor/gui/src/qwpseditorwindow.cpp
@@ -0,0 +1,120 @@
+#include "qwpseditorwindow.h"
+#include "qwpsdrawer.h"
+#include "utils.h"
+#include <QFileDialog>
+#include <QDebug>
+#include <QInputDialog>
+
+enum api_playmode playmodes[PLAYMODES_NUM] = {
+            API_STATUS_PLAY,
+            API_STATUS_STOP,
+            API_STATUS_PAUSE,
+            API_STATUS_FASTFORWARD,
+            API_STATUS_FASTBACKWARD
+        };
+
+const char *playmodeNames[] = {
+                                  "Play",
+                                  "Stop",
+                                  "Pause",
+                                  "FastForward",
+                                  "FastBackward"
+                              };
+
+QWpsEditorWindow::QWpsEditorWindow( QWidget * parent, Qt::WFlags f)
+        : QMainWindow(parent, f) {
+    logEdit = 0;
+    setupUi(this);
+    drawer = new QWpsDrawer(&wpsState,&trackState, this);
+    QWpsDrawer::api.verbose = 1;
+    //drawer->WpsInit("iCatcher.wps");
+    setCentralWidget(drawer);
+    connectActions();
+    m_propertyEditor->addObject(&trackState);
+    m_propertyEditor->addObject(&wpsState);
+}
+
+void QWpsEditorWindow::connectActions() {
+    qDebug()<<"connect actions";
+    connect(actOpenWps,     SIGNAL(triggered()),     this,   SLOT(slotOpenWps()));
+    connect(actSetVolume,   SIGNAL(triggered()),     drawer, SLOT(slotSetVolume()));
+    connect(actSetProgress, SIGNAL(triggered()),     drawer, SLOT(slotSetProgress()));
+    connect(actShowGrid,    SIGNAL(triggered(bool)), drawer, SLOT(slotShowGrid(bool)));
+
+    connect(actUpdatePlainWps,             SIGNAL(triggered()),                 SLOT(slotUpdatePlainWps()));
+    connect(plainWpsEdit->document(),     SIGNAL(modificationChanged(bool)),    SLOT(slotPlainDocModChanged(bool)));
+
+    connect(&wpsState, SIGNAL(stateChanged(wpsstate)), drawer,   SLOT(slotWpsStateChanged(wpsstate)));
+    connect(&trackState, SIGNAL(stateChanged(trackstate)), drawer,   SLOT(slotTrackStateChanged(trackstate)));
+    connect(&wpsState, SIGNAL(stateChanged(wpsstate)), this,     SLOT(slotWpsStateChanged(wpsstate)));
+    connect(&trackState, SIGNAL(stateChanged(trackstate)), this,     SLOT(slotTrackStateChanged(trackstate)));
+
+    connect(actClearLog, SIGNAL(triggered()), logEdit, SLOT(clear()));
+    connect(actVerboseLevel, SIGNAL(triggered()), SLOT(slotVerboseLevel()));
+
+    actGroupAudios = new QActionGroup(this);
+    signalMapper = new QSignalMapper(this);
+    for (int i=0;i<PLAYMODES_NUM;i++) {
+        QAction *act = new QAction(playmodeNames[i],this);
+        act->setCheckable(true);
+        actGroupAudios->addAction(act);
+        connect(act,SIGNAL(triggered()),signalMapper,SLOT(map()));
+        signalMapper->setMapping(act, i);
+        menuPlay->addAction(act);
+        actAudios[playmodes[i]] = act;
+    }
+    connect(signalMapper, SIGNAL(mapped(int)), SIGNAL(signalAudioStatusChanged(int)));
+    connect(this,         SIGNAL(signalAudioStatusChanged(int)), drawer, SLOT(slotSetAudioStatus(int)));
+    actGroupAudios->setEnabled(false);
+}
+
+void QWpsEditorWindow::slotWpsStateChanged(wpsstate) {
+    m_propertyEditor->updateObject(&wpsState);
+    m_propertyEditor->update();
+}
+
+void QWpsEditorWindow::slotTrackStateChanged(trackstate) {
+    m_propertyEditor->updateObject(&trackState);
+    m_propertyEditor->update();
+}
+
+void QWpsEditorWindow::slotOpenWps() {
+    QString wpsfile = QFileDialog::getOpenFileName(this,
+                      tr("Open WPS"), "", tr("WPS Files (*.wps);; All Files (*.*)"));
+    if (wpsfile == "") {
+        DEBUGF1(tr("File wasn't chosen"));
+        return;
+    }
+    m_propertyEditor->setEnabled(true);
+    drawer->WpsInit(wpsfile);
+    plainWpsEdit->clear();
+    plainWpsEdit->append(drawer->wpsString());
+    trackState.setAlbum(trackState.album());
+    actGroupAudios->setEnabled(true);
+}
+
+void QWpsEditorWindow::logMsg(QString s) {
+    logEdit->append(s);
+}
+
+void QWpsEditorWindow::slotVerboseLevel() {
+    bool ok;
+    int i = QInputDialog::getInteger(this, tr("Set Verbose Level"),tr("Level:"), QWpsDrawer::api.verbose, 0, 3, 1, &ok);
+    if (ok)
+        QWpsDrawer::api.verbose = i;
+}
+
+void QWpsEditorWindow::slotUpdatePlainWps() {
+    DEBUGF1(tr("Updating WPS"));
+    plainWpsEdit->document()->setModified(false);
+    drawer->WpsInit(plainWpsEdit->toPlainText(),false);
+
+}
+
+void QWpsEditorWindow::slotPlainDocModChanged(bool changed) {
+    if (changed)
+        dockPlainWps->setWindowTitle(tr("PlainWps*"));
+    else
+        dockPlainWps->setWindowTitle(tr("PlainWps"));
+}
+
diff --git a/utils/wpseditor/gui/src/qwpseditorwindow.h b/utils/wpseditor/gui/src/qwpseditorwindow.h
new file mode 100644
index 0000000..019eb63
--- /dev/null
+++ b/utils/wpseditor/gui/src/qwpseditorwindow.h
@@ -0,0 +1,45 @@
+#ifndef MAINWINDOWIMPL_H
+#define MAINWINDOWIMPL_H
+//
+#include <QMainWindow>
+#include <QActionGroup>
+#include <QSignalMapper>
+#include "ui_mainwindow.h"
+#include "wpsstate.h"
+#include "qwpsdrawer.h"
+#include "qwpsstate.h"
+#include "qtrackstate.h"
+//
+class QWpsEditorWindow : public QMainWindow, public Ui::MainWindow {
+    Q_OBJECT
+    QWpsState wpsState;
+    QTrackState trackState;
+    QPointer<QWpsDrawer> drawer;
+
+    QHash<int, QAction*> actAudios;
+    QActionGroup     *actGroupAudios;
+    QSignalMapper     *signalMapper;
+
+protected:
+    void connectActions();
+public:
+    QWpsEditorWindow( QWidget * parent = 0, Qt::WFlags f = 0 );
+    void logMsg(QString s);
+private slots:
+    void slotOpenWps();
+    void slotVerboseLevel();
+    void slotWpsStateChanged(wpsstate);
+    void slotTrackStateChanged(trackstate);
+
+    void slotUpdatePlainWps();
+    void slotPlainDocModChanged(bool m);
+
+signals:
+    void signalAudioStatusChanged(int);
+
+};
+#endif
+
+
+
+
diff --git a/utils/wpseditor/gui/src/qwpsstate.cpp b/utils/wpseditor/gui/src/qwpsstate.cpp
new file mode 100644
index 0000000..4244bf6
--- /dev/null
+++ b/utils/wpseditor/gui/src/qwpsstate.cpp
@@ -0,0 +1,29 @@
+#include "qwpsstate.h"
+
+QWpsState::QWpsState(): QObject() {
+    state.fontheight = 8;
+    state.fontwidth = 5;
+    state.volume = -30;
+    state.battery_level = 50;
+
+}
+
+void QWpsState::setFontHeight(int val) {
+    state.fontheight = val;
+    emit stateChanged(state);
+}
+
+void QWpsState::setFontWidth(int val) {
+    state.fontwidth = val;
+    emit stateChanged(state);
+}
+
+void QWpsState::setVolume(int val) {
+    state.volume = val;
+    emit stateChanged(state);
+}
+
+void QWpsState::setBattery(int val) {
+    state.battery_level = val;
+    emit stateChanged(state);
+}
diff --git a/utils/wpseditor/gui/src/qwpsstate.h b/utils/wpseditor/gui/src/qwpsstate.h
new file mode 100644
index 0000000..eb43531
--- /dev/null
+++ b/utils/wpseditor/gui/src/qwpsstate.h
@@ -0,0 +1,54 @@
+#ifndef __WPSSTATE_H__
+#define __WPSSTATE_H__
+
+#include <QObject>
+#include "wpsstate.h"
+
+class QWpsState : public QObject {
+    Q_OBJECT
+
+
+    Q_CLASSINFO("QWpsState", "WPS State");
+    Q_PROPERTY(int FontHeight READ fontHeight WRITE setFontHeight DESIGNABLE true USER true)
+    Q_CLASSINFO("FontHeight", "minimum=6;maximum=20;value=10");
+    Q_PROPERTY(int FontWidth READ fontWidth WRITE setFontWidth DESIGNABLE true USER true)
+    Q_CLASSINFO("FontWidth", "minimum=4;maximum=20;value=8");
+    Q_PROPERTY(int Volume READ volume WRITE setVolume DESIGNABLE true USER true)
+    Q_CLASSINFO("Volume", "minimum=-74;maximum=24;value=-15");
+    Q_PROPERTY(int Battery READ battery WRITE setBattery DESIGNABLE true USER true)
+    Q_CLASSINFO("Battery", "minimum=0;maximum=100;value=50");
+
+    wpsstate state;
+
+public:
+    QWpsState();
+
+    int fontHeight() const {
+        return state.fontheight;
+    }
+    void setFontHeight(int val);
+
+    int fontWidth() const {
+        return state.fontwidth;
+    }
+    void setFontWidth(int val);
+
+    int battery() const {
+        return state.battery_level;
+    }
+    void setBattery(int val);
+
+    int volume() const {
+        return state.volume;
+    }
+public slots:
+    void setVolume(int val);
+
+
+
+
+
+signals:
+    void stateChanged ( wpsstate state );
+};
+#endif // __WPSSTATE_H__
diff --git a/utils/wpseditor/gui/src/slider.cpp b/utils/wpseditor/gui/src/slider.cpp
new file mode 100644
index 0000000..7e3c9a9
--- /dev/null
+++ b/utils/wpseditor/gui/src/slider.cpp
@@ -0,0 +1,20 @@
+#include "slider.h"
+#include <QDebug>
+//
+Slider::Slider(QWidget *parent, QString caption, int min, int max ):QDialog(parent) {
+    setupUi ( this );
+    connect(horslider, SIGNAL(valueChanged(int)), this, SIGNAL(valueChanged(int)));
+    connect(this, SIGNAL(valueChanged(int)), this, SLOT(slotValueChanged(int)));
+    setWindowTitle(caption);
+    horslider->setMinimum(min);
+    horslider->setMaximum(max);
+}
+//
+int Slider::value() {
+    return horslider->value();
+}
+void Slider::slotValueChanged(int step) {
+    setWindowTitle(tr("Value =%1 ").arg(step));
+}
+
+
diff --git a/utils/wpseditor/gui/src/slider.h b/utils/wpseditor/gui/src/slider.h
new file mode 100644
index 0000000..2620731
--- /dev/null
+++ b/utils/wpseditor/gui/src/slider.h
@@ -0,0 +1,21 @@
+#ifndef SLIDERIMPL_H
+#define SLIDERIMPL_H
+//
+#include <QWidget>
+#include <QDialog>
+#include "ui_slider.h"
+//
+class Slider : public QDialog , Ui::slider {
+    Q_OBJECT
+public slots:
+    void slotValueChanged(int step);
+signals:
+    void valueChanged(int);
+public:
+    Slider(QWidget *parent, QString caption, int min, int max );
+    int value();
+
+
+
+};
+#endif
diff --git a/utils/wpseditor/gui/src/utils.cpp b/utils/wpseditor/gui/src/utils.cpp
new file mode 100644
index 0000000..f184425
--- /dev/null
+++ b/utils/wpseditor/gui/src/utils.cpp
@@ -0,0 +1,28 @@
+#include "utils.h"
+#include <QPointer>
+#include <QtGlobal>
+#include "qwpseditorwindow.h"
+
+extern QPointer<QWpsEditorWindow> win;
+
+int qlogger(const char* fmt,...) {
+    va_list ap;
+    va_start(ap, fmt);
+    QString s;
+    s.vsprintf(fmt,ap);
+    va_end(ap);
+    s.replace("\n","");
+    //qDebug()<<s;
+    if (win==0)
+        qDebug()<<s;
+    if (s.indexOf("ERR")>=0)
+        s = "<font color=red>"+s+"</font>";
+    if (win!=0)
+        win->logMsg(s);
+    va_end(ap);
+    return s.length();
+}
+
+int qlogger(const QString& s) {
+    return qlogger(s.toAscii().data());
+}
diff --git a/utils/wpseditor/gui/src/utils.h b/utils/wpseditor/gui/src/utils.h
new file mode 100644
index 0000000..ae88d78
--- /dev/null
+++ b/utils/wpseditor/gui/src/utils.h
@@ -0,0 +1,12 @@
+#ifndef __UTILS_H__
+#define __UTILS_H__
+
+#include <QDebug>
+
+#define DEBUGF1 qlogger
+#define DEBUGF2(...)
+
+extern int qlogger(const char* fmt,...);
+extern int qlogger(const QString& s);
+
+#endif // __UTILS_H__
diff --git a/utils/wpseditor/gui/ui/mainwindow.ui b/utils/wpseditor/gui/ui/mainwindow.ui
new file mode 100644
index 0000000..cd3f52b
--- /dev/null
+++ b/utils/wpseditor/gui/ui/mainwindow.ui
@@ -0,0 +1,290 @@
+<ui version="4.0" >
+ <class>MainWindow</class>
+ <widget class="QMainWindow" name="MainWindow" >
+  <property name="geometry" >
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>882</width>
+    <height>669</height>
+   </rect>
+  </property>
+  <property name="windowTitle" >
+   <string>WPS Editor</string>
+  </property>
+  <widget class="QWidget" name="centralwidget" >
+   <property name="geometry" >
+    <rect>
+     <x>260</x>
+     <y>21</y>
+     <width>344</width>
+     <height>345</height>
+    </rect>
+   </property>
+  </widget>
+  <widget class="QMenuBar" name="menubar" >
+   <property name="geometry" >
+    <rect>
+     <x>0</x>
+     <y>0</y>
+     <width>882</width>
+     <height>21</height>
+    </rect>
+   </property>
+   <widget class="QMenu" name="menuFile" >
+    <property name="title" >
+     <string>File</string>
+    </property>
+    <addaction name="actOpenWps" />
+    <addaction name="actSetVolume" />
+    <addaction name="actSetProgress" />
+    <addaction name="actShowGrid" />
+    <addaction name="actClearLog" />
+    <addaction name="actVerboseLevel" />
+    <addaction name="actQuit" />
+   </widget>
+   <widget class="QMenu" name="menuPlay" >
+    <property name="title" >
+     <string>Play</string>
+    </property>
+   </widget>
+   <addaction name="menuFile" />
+   <addaction name="menuPlay" />
+  </widget>
+  <widget class="QStatusBar" name="statusbar" >
+   <property name="geometry" >
+    <rect>
+     <x>0</x>
+     <y>650</y>
+     <width>882</width>
+     <height>19</height>
+    </rect>
+   </property>
+  </widget>
+  <widget class="QDockWidget" name="dockPlainWps" >
+   <property name="geometry" >
+    <rect>
+     <x>0</x>
+     <y>370</y>
+     <width>882</width>
+     <height>280</height>
+    </rect>
+   </property>
+   <property name="minimumSize" >
+    <size>
+     <width>0</width>
+     <height>30</height>
+    </size>
+   </property>
+   <property name="windowTitle" >
+    <string>PlainWps</string>
+   </property>
+   <attribute name="dockWidgetArea" >
+    <number>8</number>
+   </attribute>
+   <widget class="QWidget" name="dockWidgetContents_3" >
+    <property name="geometry" >
+     <rect>
+      <x>0</x>
+      <y>22</y>
+      <width>882</width>
+      <height>258</height>
+     </rect>
+    </property>
+    <layout class="QGridLayout" name="gridLayout_2" >
+     <item rowspan="2" row="0" column="0" >
+      <widget class="QTextEdit" name="plainWpsEdit" >
+       <property name="autoFillBackground" >
+        <bool>false</bool>
+       </property>
+       <property name="readOnly" >
+        <bool>false</bool>
+       </property>
+      </widget>
+     </item>
+     <item row="0" column="1" >
+      <widget class="QPushButton" name="btnUpdatePlainWps" >
+       <property name="text" >
+        <string>Update WPS</string>
+       </property>
+      </widget>
+     </item>
+     <item row="1" column="1" >
+      <spacer name="verticalSpacer" >
+       <property name="orientation" >
+        <enum>Qt::Vertical</enum>
+       </property>
+       <property name="sizeHint" stdset="0" >
+        <size>
+         <width>20</width>
+         <height>211</height>
+        </size>
+       </property>
+      </spacer>
+     </item>
+    </layout>
+   </widget>
+  </widget>
+  <widget class="QDockWidget" name="m_dockWidget" >
+   <property name="geometry" >
+    <rect>
+     <x>0</x>
+     <y>21</y>
+     <width>256</width>
+     <height>345</height>
+    </rect>
+   </property>
+   <property name="windowTitle" >
+    <string>Property Editor</string>
+   </property>
+   <attribute name="dockWidgetArea" >
+    <number>1</number>
+   </attribute>
+   <widget class="QPropertyEditorWidget" name="m_propertyEditor" >
+    <property name="enabled" >
+     <bool>false</bool>
+    </property>
+    <property name="geometry" >
+     <rect>
+      <x>0</x>
+      <y>22</y>
+      <width>256</width>
+      <height>323</height>
+     </rect>
+    </property>
+   </widget>
+  </widget>
+  <widget class="QDockWidget" name="dockWidget" >
+   <property name="geometry" >
+    <rect>
+     <x>608</x>
+     <y>21</y>
+     <width>274</width>
+     <height>345</height>
+    </rect>
+   </property>
+   <property name="minimumSize" >
+    <size>
+     <width>0</width>
+     <height>30</height>
+    </size>
+   </property>
+   <property name="windowTitle" >
+    <string>Log</string>
+   </property>
+   <attribute name="dockWidgetArea" >
+    <number>2</number>
+   </attribute>
+   <widget class="QWidget" name="dockWidgetContents" >
+    <property name="geometry" >
+     <rect>
+      <x>0</x>
+      <y>22</y>
+      <width>274</width>
+      <height>323</height>
+     </rect>
+    </property>
+    <layout class="QGridLayout" name="gridLayout" >
+     <item row="0" column="0" >
+      <widget class="QTextEdit" name="logEdit" >
+       <property name="autoFillBackground" >
+        <bool>false</bool>
+       </property>
+       <property name="readOnly" >
+        <bool>true</bool>
+       </property>
+      </widget>
+     </item>
+    </layout>
+   </widget>
+  </widget>
+  <action name="actQuit" >
+   <property name="text" >
+    <string>Quit</string>
+   </property>
+  </action>
+  <action name="actOpenWps" >
+   <property name="text" >
+    <string>Open WPS</string>
+   </property>
+  </action>
+  <action name="actSetVolume" >
+   <property name="text" >
+    <string>Set Volume</string>
+   </property>
+  </action>
+  <action name="actSetProgress" >
+   <property name="text" >
+    <string>Set Progress</string>
+   </property>
+  </action>
+  <action name="actShowGrid" >
+   <property name="checkable" >
+    <bool>true</bool>
+   </property>
+   <property name="checked" >
+    <bool>false</bool>
+   </property>
+   <property name="text" >
+    <string>Show Grid</string>
+   </property>
+  </action>
+  <action name="actClearLog" >
+   <property name="text" >
+    <string>Clear Log</string>
+   </property>
+  </action>
+  <action name="actVerboseLevel" >
+   <property name="text" >
+    <string>Verbose Level</string>
+   </property>
+  </action>
+  <action name="actUpdatePlainWps" >
+   <property name="text" >
+    <string>Update WPS</string>
+   </property>
+  </action>
+ </widget>
+ <customwidgets>
+  <customwidget>
+   <class>QPropertyEditorWidget</class>
+   <extends>QTreeView</extends>
+   <header>QPropertyEditorWidget.h</header>
+  </customwidget>
+ </customwidgets>
+ <resources/>
+ <connections>
+  <connection>
+   <sender>btnUpdatePlainWps</sender>
+   <signal>clicked()</signal>
+   <receiver>actUpdatePlainWps</receiver>
+   <slot>trigger()</slot>
+   <hints>
+    <hint type="sourcelabel" >
+     <x>835</x>
+     <y>411</y>
+    </hint>
+    <hint type="destinationlabel" >
+     <x>-1</x>
+     <y>-1</y>
+    </hint>
+   </hints>
+  </connection>
+  <connection>
+   <sender>actQuit</sender>
+   <signal>triggered()</signal>
+   <receiver>MainWindow</receiver>
+   <slot>close()</slot>
+   <hints>
+    <hint type="sourcelabel" >
+     <x>-1</x>
+     <y>-1</y>
+    </hint>
+    <hint type="destinationlabel" >
+     <x>440</x>
+     <y>334</y>
+    </hint>
+   </hints>
+  </connection>
+ </connections>
+</ui>
diff --git a/utils/wpseditor/gui/ui/slider.ui b/utils/wpseditor/gui/ui/slider.ui
new file mode 100644
index 0000000..24fff0b
--- /dev/null
+++ b/utils/wpseditor/gui/ui/slider.ui
@@ -0,0 +1,43 @@
+<ui version="4.0" >
+ <class>slider</class>
+ <widget class="QWidget" name="slider" >
+  <property name="geometry" >
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>295</width>
+    <height>37</height>
+   </rect>
+  </property>
+  <property name="windowTitle" >
+   <string>Value</string>
+  </property>
+  <widget class="QSlider" name="horslider" >
+   <property name="geometry" >
+    <rect>
+     <x>0</x>
+     <y>10</y>
+     <width>291</width>
+     <height>21</height>
+    </rect>
+   </property>
+   <property name="minimum" >
+    <number>-78</number>
+   </property>
+   <property name="maximum" >
+    <number>24</number>
+   </property>
+   <property name="singleStep" >
+    <number>1</number>
+   </property>
+   <property name="value" >
+    <number>-78</number>
+   </property>
+   <property name="orientation" >
+    <enum>Qt::Horizontal</enum>
+   </property>
+  </widget>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/utils/wpseditor/libwps/Makefile b/utils/wpseditor/libwps/Makefile
new file mode 100644
index 0000000..3779a9e
--- /dev/null
+++ b/utils/wpseditor/libwps/Makefile
@@ -0,0 +1,100 @@
+#             __________               __   ___.
+#   Open      \______   \ ____   ____ |  | _\_ |__   _______  ___
+#   Source     |       _//  _ \_/ ___\|  |/ /| __ \ /  _ \  \/  /
+#   Jukebox    |    |   (  <_> )  \___|    < | \_\ (  <_> > <  <
+#   Firmware   |____|_  /\____/ \___  >__|_ \|___  /\____/__/\_ \
+#                     \/            \/     \/    \/            \/
+# $Id$
+#
+ROOT=../../..
+
+OS = w32
+CC = gcc
+MKDIR = mkdir -p
+
+ifeq ($(findstring MINGW,$(shell uname)),MINGW)
+OS = w32
+CC = mingw32-gcc
+COPY = copy
+RM = rm
+endif
+
+ifeq ($(findstring Linux,$(shell uname)),Linux)
+OS = linux
+CC = gcc
+COPY = cp
+RM = rm -f
+endif
+
+
+
+COMMON= \
+	   src/dummies.c \
+	   src/api.c \
+	   src/lcd.c \
+	   $(ROOT)/apps/gui/wps_parser.c \
+	   $(ROOT)/apps/gui/wps_debug.c \
+	   $(ROOT)/firmware/font.c \
+	   $(ROOT)/apps/misc.c \
+	   $(ROOT)/apps/gui/gwps-common.c \
+	   $(ROOT)/apps/status.c \
+	   $(ROOT)/apps/recorder/peakmeter.c \
+	   $(ROOT)/apps/recorder/icons.c \
+	   $(ROOT)/apps/gui/scrollbar.c \
+	   $(ROOT)/firmware/common/timefuncs.c \
+	   $(ROOT)/firmware/common/unicode.c \
+	   $(ROOT)/firmware/common/ctype.c \
+	   $(ROOT)/firmware/id3.c \
+	   $(ROOT)/firmware/font_cache.c \
+	   $(ROOT)/firmware/lru.c \
+	   $(ROOT)/firmware/mp3data.c \
+	   $(ROOT)/firmware/replaygain.c 
+
+#	   $(ROOT)/apps/recorder/bmp.c
+#	   $(ROOT)/apps/abrepeat.c \
+#	   $(ROOT)/apps/action.c \
+#   	   $(ROOT)/apps/cuesheet.c \
+#	   $(ROOT)/apps/gui/statusbar.c \
+#	   $(ROOT)/apps/gui/gwps.c \
+
+INCLUDE=-I src/include \
+        -I $(ROOT)/apps/gui \
+        -I $(ROOT)/firmware/export \
+        -I $(ROOT)/firmware/include \
+        -I $(ROOT)/apps/recorder \
+        -I $(ROOT)/apps \
+        -I src
+
+CFLAGS = -g -Wall -D__PCTOOL__ -DWPSEDITOR -DDEBUG -DROCKBOX_DIR_LEN=1 -DBUTTON_REMOTE
+
+all:
+	@echo To build, run the buildall.sh script
+
+build: build-$(OS)
+
+build-w32: src/proxy.c  $(COMMON)
+	@echo CC [$(TARGET)]
+	@$(CC) $(INCLUDE) $(CFLAGS) -D$(TARGET) -DTARGET_MODEL=\"$(MODEL)\" -DBUILD_DLL $(COMMON) -shared src/proxy.c -o libwps_$(MODEL).dll
+
+build-linux: src/proxy.c  $(COMMON)
+	@echo CC [$(TARGET)]
+	@$(CC) $(INCLUDE) $(CFLAGS) -D$(TARGET) -DTARGET_MODEL=\"$(MODEL)\" -shared -Wl,-soname,libwps_$(MODEL).so,-olibwps_$(MODEL).so -fPIC $(COMMON) src/proxy.c
+
+clean: clean-$(OS)
+
+clean-w32:
+	$(RM) "libwps_$(MODEL).dll"
+
+clean-linux:
+	$(RM) "libwps_$(MODEL).so.1"
+
+shared: shared-$(OS)
+
+shared-w32: src/proxy.c  $(COMMON)
+	@echo CC [IRIVER_H10_5GB]
+	@$(CC) $(INCLUDE) $(CFLAGS) -DIRIVER_H10_5GB -DTARGET_MODEL=\"h10_5gb\" -DBUILD_DLL $(COMMON) -shared src/proxy.c -o ../gui/bin/libwps.dll
+
+shared-linux: src/proxy.c $(COMMON)
+	@echo CC [IRIVER_H10_5GB]
+	@$(CC) $(INCLUDE) $(CFLAGS) -DIRIVER_H10_5GB -DTARGET_MODEL=\"h10_5gb\" -shared -Wl,-soname,libwps.so,-olibwps.so -fPIC $(COMMON) src/proxy.c
+	@$(COPY) libwps.so ../gui/bin/libwps.so
diff --git a/utils/wpseditor/libwps/buildall.sh b/utils/wpseditor/libwps/buildall.sh
new file mode 100644
index 0000000..60677d2
--- /dev/null
+++ b/utils/wpseditor/libwps/buildall.sh
@@ -0,0 +1,7 @@
+#!/bin/sh
+cat targets.txt | (
+    while read target model
+    do
+        make MODEL=$model TARGET=$target build
+    done
+)
diff --git a/utils/wpseditor/libwps/cleanall.sh b/utils/wpseditor/libwps/cleanall.sh
new file mode 100644
index 0000000..15b733a
--- /dev/null
+++ b/utils/wpseditor/libwps/cleanall.sh
@@ -0,0 +1,7 @@
+#!/bin/sh
+cat targets.txt | (
+    while read target model
+    do
+        make MODEL=$model TARGET=$target clean
+    done
+)
diff --git a/utils/wpseditor/libwps/src/api.c b/utils/wpseditor/libwps/src/api.c
new file mode 100644
index 0000000..485efa8
--- /dev/null
+++ b/utils/wpseditor/libwps/src/api.c
@@ -0,0 +1,268 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include "sound.h"
+#include "api.h"
+#include "proxy.h"
+#include "dummies.h"
+#include "scroll_engine.h"
+#include "wpsstate.h"
+#include <string.h>
+
+struct proxy_api *xapi;
+
+void get_current_vp(struct viewport_api *avp);
+/*************************************************************
+
+*************************************************************/
+#ifdef HAVE_LCD_BITMAP
+void screen_clear_area(struct screen * display, int xstart, int ystart,
+                       int width, int height) {
+    display->set_drawmode(DRMODE_SOLID|DRMODE_INVERSEVID);
+    display->fillrect(xstart, ystart, width, height);
+    display->set_drawmode(DRMODE_SOLID);
+}
+#endif
+
+bool load_wps_backdrop(char* filename) {
+    return xapi->load_wps_backdrop(filename);
+}
+
+bool load_remote_wps_backdrop(char* filename) {
+    return xapi->load_remote_wps_backdrop(filename);
+}
+
+int read_bmp_file(const char* filename,struct bitmap *bm, int maxsize,int format) {
+    if (!xapi->read_bmp_file)
+    {
+        DEBUGF1("can't read bmp file! NULL api!\n");
+        return -1;
+    }
+    bm->format = 3;//FORMAT_ANY?
+    bm->data = (unsigned char*)malloc(255);
+    memset(bm->data,0,255);
+    strcpy((char*)bm->data,filename);
+    //bm->data[strlen(filename)] = '\0';
+    xapi->read_bmp_file(filename,&bm->width, &bm->height);
+    return 1;
+}
+
+bool load_wps_backdrop2(char* filename) {
+    DEBUGF1("load_wps_backdrop(char* filename='%s')",filename);
+    return true;
+}
+
+bool load_remote_wps_backdrop2(char* filename) {
+    DEBUGF1("load_remote_wps_backdrop2(char* filename='%s')",filename);
+    return true;
+}
+
+void stop_scroll() {
+    DEBUGF3("stop_scroll\n");
+    return;
+}
+
+void puts_scroll(int x, int y, const unsigned char *string) {
+    DEBUGF2("puts_scroll(int x=%d, int y=%d, const unsigned char *string='%s'\n",x,y,string);
+}
+
+void putsxy(int x, int y, const unsigned char *str) {
+    DEBUGF2("putsxy(int =%d, int y=%d, const unsigned char *str='%s')\n",x,y,str);
+}
+
+void lcd_update() {
+    DEBUGF3("update\n");
+}
+
+void clear_viewport(int x, int y, int w, int h, int color) {
+    DEBUGF3("clear_viewport(int x=%d, int y=%d, int w=%d, int h=%d, int color=%d)\n", x, y, w, h, color);
+};
+
+int getstringsize(const unsigned char *str, int *w, int *h) {
+    //DEBUGF1("getstringsize(const unsigned char *str=\"%s\", int *w=%d, int *h=%d \n",str,*w,*h);
+    *w=strlen((char*)str)*sysfont.maxwidth;
+    *h=sysfont.height;
+    return 1;
+}
+
+void set_wpsstate(struct wpsstate state){
+    sysfont.height = state.fontheight;
+    sysfont.maxwidth = state.fontwidth;
+    global_settings.volume = state.volume;
+    battery_percent = state.battery_level;
+    _audio_status = state.audio_status;
+}
+
+void set_trackstate(struct trackstate state){
+    gui_wps[0].state->id3->title = state.title;
+    gui_wps[0].state->id3->artist = state.artist;
+    gui_wps[0].state->id3->album = state.album;
+    gui_wps[0].state->id3->elapsed = state.elapsed;
+    gui_wps[0].state->id3->length = state.length;
+}
+
+void set_next_trackstate(struct trackstate state)
+{
+    gui_wps[0].state->nid3->title = state.title;
+    gui_wps[0].state->nid3->artist = state.artist;
+    gui_wps[0].state->nid3->album = state.album;
+    gui_wps[0].state->nid3->elapsed = state.elapsed;
+    gui_wps[0].state->nid3->length = state.length;
+}
+
+enum api_playmode playmodes[PLAYMODES_NUM] = {
+    API_STATUS_PLAY,
+    API_STATUS_STOP,
+    API_STATUS_PAUSE,
+    API_STATUS_FASTFORWARD,
+    API_STATUS_FASTBACKWARD
+};
+
+const char *playmodeNames[] = {
+    "Play", "Stop", "Pause", "FastForward", "FastBackward"
+};
+
+
+void set_audio_status(int status){
+    DEBUGF1("%s",playmodeNames[status]);
+    switch(status){
+        case API_STATUS_PLAY:
+            _audio_status = AUDIO_STATUS_PLAY;
+            status_set_ffmode(STATUS_PLAY);
+            break;
+        case API_STATUS_STOP:
+            _audio_status = 0;
+            status_set_ffmode(STATUS_STOP);
+            break;
+        case API_STATUS_PAUSE:
+            _audio_status = AUDIO_STATUS_PAUSE;
+            status_set_ffmode(STATUS_PLAY);
+            break;
+        case API_STATUS_FASTFORWARD:
+            status_set_ffmode(STATUS_FASTFORWARD);
+            break;
+        case API_STATUS_FASTBACKWARD:
+            status_set_ffmode(STATUS_FASTBACKWARD);
+            break;
+        default:
+            DEBUGF1("ERR: Unknown status");
+    }
+}
+
+void test_api(struct proxy_api *api) {
+    if (!api->stop_scroll)
+        api->stop_scroll=stop_scroll;
+    if (!api->set_viewport)
+        api->set_viewport=lcd_set_viewport;
+    if (!api->clear_viewport)
+        api->clear_viewport=clear_viewport;
+    if (!api->getstringsize)
+        api->getstringsize=getstringsize;
+    if (!api->getwidth)
+        api->getwidth=lcd_getwidth;
+    if (!api->getheight)
+        api->getheight=lcd_getheight;
+    if (!api->set_drawmode)
+        api->set_drawmode=lcd_set_drawmode;
+    if (!api->puts_scroll)
+        api->puts_scroll=puts_scroll;
+    if (!api->update)
+        api->update=lcd_update;
+    if (!api->clear_display)
+        api->clear_display=lcd_clear_display;
+    if (!api->getfont)
+        api->getfont=lcd_getfont;
+    if (!api->putsxy)
+        api->putsxy=putsxy;
+
+#if LCD_DEPTH > 1
+    if (!api->get_foreground)
+        api->get_foreground=lcd_get_foreground;
+    if (!api->get_background)
+        api->get_background=lcd_get_background;
+#endif
+    if (!api->load_remote_wps_backdrop)
+        api->load_remote_wps_backdrop = load_remote_wps_backdrop2;
+    if (!api->load_wps_backdrop)
+        api->load_wps_backdrop = load_wps_backdrop2;
+    //dbgf = printf;
+}
+
+/**************************************************************
+
+**************************************************************/
+
+int set_api(struct proxy_api* api) {
+    if (api->debugf)
+        dbgf = api->debugf;
+    screens[0].screen_type=SCREEN_MAIN;
+    screens[0].lcdwidth=LCD_WIDTH;
+    screens[0].lcdheight=LCD_HEIGHT;
+    screens[0].depth=LCD_DEPTH;
+#ifdef HAVE_LCD_COLOR
+    screens[0].is_color=true;
+#else
+    screens[0].is_color=false;
+#endif
+    if (api->getwidth)
+        screens[0].getwidth = api->getwidth;
+    if (api->stop_scroll)
+        screens[0].stop_scroll=api->stop_scroll;
+    screens[0].scroll_stop = lcd_scroll_stop;
+    if (api->set_viewport)
+        screens[0].set_viewport=api->set_viewport;
+    if (api->clear_viewport)
+        screens[0].clear_viewport=lcd_clear_viewport;
+    if (api->getstringsize)
+        screens[0].getstringsize=api->getstringsize;
+    if (api->getwidth)
+        screens[0].getwidth=api->getwidth;
+    if (api->getheight)
+        screens[0].getheight=api->getheight;
+    if (api->set_drawmode)
+        screens[0].set_drawmode=api->set_drawmode;
+    if (api->fillrect)
+        screens[0].fillrect=api->fillrect;
+    if (api->puts_scroll)
+        screens[0].puts_scroll=api->puts_scroll;
+    if (api->transparent_bitmap_part)
+        screens[0].transparent_bitmap_part=api->transparent_bitmap_part;
+    if (api->update)
+        screens[0].update=api->update;
+    if (api->clear_display)
+        screens[0].clear_display=api->clear_display;
+    if (api->getfont)
+        screens[0].getfont=api->getfont;
+    if (api->hline)
+        screens[0].hline=api->hline;
+    if (api->vline)
+        screens[0].vline=api->vline;
+    if (api->drawpixel)
+        screens[0].drawpixel=api->drawpixel;
+    if (api->putsxy)
+        screens[0].putsxy=api->putsxy;
+#if LCD_DEPTH > 1
+    if (api->get_foreground)
+        screens[0].get_foreground=api->get_foreground;
+    if (api->get_background)
+        screens[0].get_background=api->get_background;
+#endif
+
+    screens[0].bitmap_part = api->bitmap_part;
+    /**************************
+    *          OUT            *
+    **************************/
+    api->get_model_name = get_model_name;
+    api->get_current_vp = get_current_vp;
+    api->set_wpsstate = set_wpsstate;
+    api->set_trackstate = set_trackstate;
+    api->set_next_trackstate= set_next_trackstate;
+    api->set_audio_status= set_audio_status;
+    xapi = api;
+    return 0;
+}
+
+
+
+
+
+
diff --git a/utils/wpseditor/libwps/src/api.h b/utils/wpseditor/libwps/src/api.h
new file mode 100644
index 0000000..86bb1a6
--- /dev/null
+++ b/utils/wpseditor/libwps/src/api.h
@@ -0,0 +1,85 @@
+#ifndef API_H_INCLUDED
+#define API_H_INCLUDED
+#include <stdbool.h>
+#include <stddef.h>
+#include "defs.h"
+#include "wpsstate.h"
+#ifdef __PCTOOL__
+#include "dummies.h"
+#endif
+
+struct viewport_api {
+    int x;
+    int y;
+    int width;
+    int height;
+    int font;
+    int drawmode;
+    unsigned fg_pattern;
+    unsigned bg_pattern;
+    unsigned lss_pattern;
+    unsigned lse_pattern;
+    unsigned lst_pattern;
+    
+    //TODO: ??
+    int fontheight;
+    int fontwidth;
+};
+
+struct proxy_api
+{
+    bool        (*load_remote_wps_backdrop)(char* file_name);
+    bool        (*load_wps_backdrop)(char* file_name);
+
+    unsigned    (*get_foreground)(void);
+    unsigned    (*get_background)(void);
+    int         (*getwidth)(void);
+    int         (*getheight)(void);
+
+    void        (*puts_scroll)(int x, int y, const unsigned char *string);
+    void        (*putsxy)(int x, int y, const unsigned char *str);
+    int         (*getfont)();
+    int         (*getstringsize)(const unsigned char *str, int *w, int *h);
+    void        (*stop_scroll)();
+
+    void        (*transparent_bitmap_part)(const void *src, int src_x, int src_y,
+                                        int stride, int x, int y, int width, int height);
+    void        (*bitmap_part)(const void *src, int src_x, int src_y,
+                          int stride, int x, int y, int width, int height);
+    void        (*hline)(int x1, int x2, int y);
+    void        (*vline)(int x, int y1, int y2);
+    void        (*drawpixel)(int x, int y);
+    void        (*set_drawmode)(int mode);
+    void        (*fillrect)(int x, int y, int width, int height);
+
+
+    void        (*update)();
+    void        (*set_viewport)(struct viewport* vp);
+    void        (*clear_display)(void);
+    void        (*clear_viewport)(int x,int y,int w,int h, int color);
+
+    void*       (*plugin_get_buffer)(size_t *buffer_size);
+    int         (*read_bmp_file)(const char* filename,int *width, int *height);
+    void        (*set_wpsstate)(struct wpsstate state);
+    void        (*set_trackstate)(struct trackstate state);
+    void        (*set_next_trackstate)(struct trackstate state);
+    void        (*set_audio_status)(int status);
+    
+    pfdebugf    debugf;
+    int            verbose;
+
+
+/**************************
+*          OUT            *
+**************************/
+    const char* (*get_model_name)();
+    void        (*get_current_vp)(struct viewport_api *avp);
+
+
+};
+
+extern struct proxy_api *xapi;
+
+EXPORT int set_api(struct proxy_api* api);
+
+#endif // API_H_INCLUDED
diff --git a/utils/wpseditor/libwps/src/defs.h b/utils/wpseditor/libwps/src/defs.h
new file mode 100644
index 0000000..810c8da
--- /dev/null
+++ b/utils/wpseditor/libwps/src/defs.h
@@ -0,0 +1,41 @@
+#ifndef DEFS_H_INCLUDED
+#define DEFS_H_INCLUDED
+
+typedef int (*pfdebugf)(const char* fmt,...);
+extern pfdebugf dbgf;
+
+#ifdef BUILD_DLL
+#   define EXPORT __declspec(dllexport)
+#else
+#   define EXPORT
+#endif
+
+#ifndef MIN
+# define MIN(a, b) (((a)<(b))?(a):(b))
+#endif
+
+#ifndef MAX
+# define MAX(a, b) (((a)>(b))?(a):(b))
+#endif
+
+#define SWAP_16(x) ((typeof(x))(unsigned short)(((unsigned short)(x) >> 8) | \
+                                                ((unsigned short)(x) << 8)))
+
+#define SWAP_32(x) ((typeof(x))(unsigned long)( ((unsigned long)(x) >> 24) | \
+                                               (((unsigned long)(x) & 0xff0000ul) >> 8) | \
+                                               (((unsigned long)(x) & 0xff00ul) << 8) | \
+                                                ((unsigned long)(x) << 24)))
+
+#define PLAYMODES_NUM 5
+enum api_playmode {
+    API_STATUS_PLAY,
+    API_STATUS_STOP,
+    API_STATUS_PAUSE,
+    API_STATUS_FASTFORWARD,
+    API_STATUS_FASTBACKWARD
+};
+
+extern enum api_playmode playmodes[PLAYMODES_NUM];
+extern const char *playmodeNames[];
+
+#endif // DEFS_H_INCLUDED
diff --git a/utils/wpseditor/libwps/src/dummies.c b/utils/wpseditor/libwps/src/dummies.c
new file mode 100644
index 0000000..8592610
--- /dev/null
+++ b/utils/wpseditor/libwps/src/dummies.c
@@ -0,0 +1,363 @@
+#include <string.h>
+#include <stdio.h>
+#include "dummies.h"
+#include "proxy.h"
+
+struct user_settings global_settings;
+
+struct wps_state wps_state;
+struct gui_wps gui_wps[NB_SCREENS];
+struct wps_data wps_datas[NB_SCREENS];
+struct cuesheet *curr_cue;
+struct cuesheet *temp_cue;
+struct system_status global_status;
+struct gui_syncstatusbar statusbars;
+struct playlist_info current_playlist;
+struct font sysfont;
+int battery_percent = 100;
+struct mp3entry current_song, next_song;
+int _audio_status;
+
+charger_input_state_type charger_input_state;
+#if CONFIG_CHARGING >= CHARGING_MONITOR
+charge_state_type charge_state;
+#endif
+
+#if defined(CPU_PP) && defined(BOOTLOADER)
+/* We don't enable interrupts in the iPod bootloader, so we need to fake
+the current_tick variable */
+#define current_tick (signed)(USEC_TIMER/10000)
+#else
+volatile long current_tick;
+#endif
+
+
+void dummies_init(){
+    sysfont.height = 9;
+    sysfont.maxwidth = 6;
+    global_settings.statusbar=true;
+}
+
+int playlist_amount_ex(const struct playlist_info* playlist);
+void sound_set_volume(int value)
+{
+    DEBUGF3("sound_set_volume(int value=%d)",value);
+    global_settings.volume = value;
+}
+int sound_get_pitch(void)
+{
+    return 0;
+}
+int sound_min(int setting)
+{
+    DEBUGF3("sound_min(int setting=%d)",setting);
+    return -78; //audiohw_settings[setting].minval;
+}
+
+void sleep(int hz)
+{
+}
+
+void audio_init(void){}
+void audio_wait_for_init(void){}
+void audio_play(long offset){}
+void audio_stop(void){}
+void audio_pause(void){}
+void audio_resume(void){}
+void audio_next(void){}
+void audio_prev(void){}
+int audio_status(void)
+{
+    return _audio_status;
+}
+
+#if CONFIG_CODEC == SWCODEC
+int audio_track_count(void){return 0;} /* SWCODEC only */
+long audio_filebufused(void){return 0;} /* SWCODEC only */
+void audio_pre_ff_rewind(void){} /* SWCODEC only */
+#endif /* CONFIG_CODEC == SWCODEC */
+void audio_ff_rewind(long newtime){}
+void audio_flush_and_reload_tracks(void){}
+#ifdef HAVE_ALBUMART
+int audio_current_aa_hid(void){return -1;}
+#endif
+struct mp3entry* audio_current_track(void){return 0;}
+struct mp3entry* audio_next_track(void){return 0;}
+bool audio_has_changed_track(void)
+{
+    return false;
+}
+
+int get_sleep_timer(void){return 0;}
+
+
+int battery_level(void){return battery_percent;} /* percent */
+int battery_time(void){return 0;} /* minutes */
+unsigned int battery_adc_voltage(void){return 0;} /* voltage from ADC in millivolts */
+unsigned int battery_voltage(void){return 0;} /* filtered batt. voltage in millivolts */
+int  get_radio_status(void){return 0;}
+
+
+/* returns full path of playlist (minus extension) */
+char *playlist_name(const struct playlist_info* playlist, char *buf,
+int buf_size)
+{
+    char *sep;
+
+    if (!playlist)
+    return "no";
+
+    snprintf(buf, buf_size, "%s", playlist->filename+playlist->dirlen);
+
+    if (!buf[0])
+    return NULL;
+
+    /* Remove extension */
+    sep = strrchr(buf, '.');
+    if(sep)
+        *sep = 0;
+
+    return buf;
+}
+int playlist_get_display_index(void)
+{
+    return 1;
+}
+
+void gui_syncsplash(int ticks, const unsigned char *fmt, ...)
+{
+
+}
+
+void splash(int ticks, const unsigned char *fmt, ...)
+{
+
+}
+
+void gui_statusbar_draw(struct gui_statusbar * bar, bool force_redraw){
+    DEBUGF3("gui_statusbar_draw");
+}
+
+void yield(void){}
+
+
+/* returns true if cuesheet support is initialised */
+bool cuesheet_is_enabled(void){return false;}
+
+/* allocates the cuesheet buffer */
+void cuesheet_init(void){}
+
+/* looks if there is a cuesheet file that has a name matching "trackpath" */
+bool look_for_cuesheet_file(const char *trackpath, char *found_cue_path){return false;}
+
+/* parse cuesheet "file" and store the information in "cue" */
+bool parse_cuesheet(char *file, struct cuesheet *cue){return false;}
+
+/* reads a cuesheet to find the audio track associated to it */
+bool get_trackname_from_cuesheet(char *filename, char *buf){return false;}
+
+/* display a cuesheet struct */
+void browse_cuesheet(struct cuesheet *cue){}
+
+/* display a cuesheet file after parsing and loading it to the plugin buffer */
+bool display_cuesheet_content(char* filename){return false;}
+
+/* finds the index of the current track played within a cuesheet */
+int cue_find_current_track(struct cuesheet *cue, unsigned long curpos){return 0;}
+
+/* update the id3 info to that of the currently playing track in the cuesheet */
+void cue_spoof_id3(struct cuesheet *cue, struct mp3entry *id3){}
+
+/* skip to next track in the cuesheet towards "direction" (which is 1 or -1) */
+bool curr_cuesheet_skip(int direction, unsigned long curr_pos){return false;}
+
+#ifdef HAVE_LCD_BITMAP
+/* draw track markers on the progressbar */
+void cue_draw_markers(struct screen *screen, unsigned long tracklen,
+int x1, int x2, int y, int h){}
+#endif
+
+
+void draw_album_art(struct gui_wps *gwps, int handle_id, bool clear)
+{
+    if (!gwps || !gwps->data || !gwps->display || handle_id < 0)
+    return;
+
+    struct wps_data *data = gwps->data;
+
+#ifdef HAVE_REMOTE_LCD
+    /* No album art on RWPS */
+    if (data->remote_wps)
+    return;
+#endif
+
+    struct bitmap *bmp;
+    /* if (bufgetdata(handle_id, 0, (void *)&bmp) <= 0)
+        return;*/
+
+    short x = data->albumart_x;
+    short y = data->albumart_y;
+    short width = bmp->width;
+    short height = bmp->height;
+
+    if (data->albumart_max_width > 0)
+    {
+        /* Crop if the bitmap is too wide */
+        width = MIN(bmp->width, data->albumart_max_width);
+
+        /* Align */
+        if (data->albumart_xalign & WPS_ALBUMART_ALIGN_RIGHT)
+        x += data->albumart_max_width - width;
+        else if (data->albumart_xalign & WPS_ALBUMART_ALIGN_CENTER)
+        x += (data->albumart_max_width - width) / 2;
+    }
+
+    if (data->albumart_max_height > 0)
+    {
+        /* Crop if the bitmap is too high */
+        height = MIN(bmp->height, data->albumart_max_height);
+
+        /* Align */
+        if (data->albumart_yalign & WPS_ALBUMART_ALIGN_BOTTOM)
+        y += data->albumart_max_height - height;
+        else if (data->albumart_yalign & WPS_ALBUMART_ALIGN_CENTER)
+        y += (data->albumart_max_height - height) / 2;
+    }
+
+    if (!clear)
+    {
+        /* Draw the bitmap */
+        gwps->display->set_drawmode(DRMODE_FG);
+        gwps->display->bitmap_part((fb_data*)bmp->data, 0, 0, bmp->width,
+        x, y, width, height);
+        gwps->display->set_drawmode(DRMODE_SOLID);
+    }
+    else
+    {
+        /* Clear the bitmap */
+        gwps->display->set_drawmode(DRMODE_SOLID|DRMODE_INVERSEVID);
+        gwps->display->fillrect(x, y, width, height);
+        gwps->display->set_drawmode(DRMODE_SOLID);
+    }
+}
+
+/* Update the "data" pointer to make the handle's data available to the caller.
+Return the length of the available linear data or < 0 for failure (handle
+not found).
+The caller is blocked until the requested amount of data is available.
+size is the amount of linear data requested. it can be 0 to get as
+much as possible.
+The guard buffer may be used to provide the requested size. This means it's
+unsafe to request more than the size of the guard buffer.
+*/
+size_t bufgetdata(int handle_id, size_t size, void **data)
+{
+
+
+    return size;
+}
+
+
+void gui_syncstatusbar_draw(struct gui_syncstatusbar * bars,
+bool force_redraw)
+{
+#ifdef HAVE_LCD_BITMAP
+    if(!global_settings.statusbar)
+    return;
+#endif /* HAVE_LCD_BITMAP */
+    int i;
+    FOR_NB_SCREENS(i) {
+        gui_statusbar_draw( &(bars->statusbars[i]), force_redraw );
+    }
+}
+void unload_wps_backdrop(void)
+{
+
+}
+
+#if CONFIG_CODEC == SWCODEC
+int get_replaygain_mode(bool have_track_gain, bool have_album_gain)
+{
+    int type;
+
+    bool track = ((global_settings.replaygain_type == REPLAYGAIN_TRACK)
+    || ((global_settings.replaygain_type == REPLAYGAIN_SHUFFLE)
+    && global_settings.playlist_shuffle));
+
+    type = (!track && have_album_gain) ? REPLAYGAIN_ALBUM
+    : have_track_gain ? REPLAYGAIN_TRACK : -1;
+
+    return type;
+}
+#endif
+
+/* Common functions for all targets */
+void rtc_init(void){}
+int rtc_read_datetime(unsigned char* buf){return 0;}
+int rtc_write_datetime(unsigned char* buf){return 0;}
+
+void backlight_on(void){}
+void backlight_off(void){}
+
+
+void debugf(const char *fmt, ...)
+{}
+void panicf( const char *fmt, ...)
+{
+}
+
+off_t filesize(int fd){return 0;}
+
+int playlist_amount(void)
+{
+    return playlist_amount_ex(NULL);
+}
+int playlist_amount_ex(const struct playlist_info* playlist)
+{
+    if (!playlist)
+        playlist = &current_playlist;
+
+    return playlist->amount;
+}
+
+int get_action(int context, int timeout)
+{
+    return 0;
+}
+
+void lcd_mono_bitmap(const unsigned char *src, int x, int y, int width,
+                            int height){}
+
+void pcm_calculate_rec_peaks(int *left, int *right)
+{
+}
+void pcm_calculate_peaks(int *left, int *right)
+{
+}
+bool led_read(int delayticks) /* read by status bar update */
+{
+    return false;
+}
+
+#ifndef HAS_BUTTON_HOLD
+bool is_keys_locked(void)
+{
+    return false;
+}
+#endif
+
+long default_event_handler_ex(long event, void (*callback)(void *), void *parameter)
+{
+     return 0;
+}
+
+long default_event_handler(long event)
+{
+    return default_event_handler_ex(event, NULL, NULL);
+}
+
+void ab_draw_markers(struct screen * screen, int capacity,
+                     int x0, int x1, int y, int h)
+                     {
+                     }
+void pcmbuf_beep(unsigned int frequency, size_t duration, int amplitude){}
diff --git a/utils/wpseditor/libwps/src/dummies.h b/utils/wpseditor/libwps/src/dummies.h
new file mode 100644
index 0000000..2bfce1d
--- /dev/null
+++ b/utils/wpseditor/libwps/src/dummies.h
@@ -0,0 +1,44 @@
+#ifndef DUMMIES_H_INCLUDED
+#define DUMMIES_H_INCLUDED
+
+#include <stdio.h>
+
+#include "settings.h"
+#include "gwps.h"
+#include "lang.h"
+#include "powermgmt.h"
+#include "font.h"
+#include "playlist.h"
+
+#include "defs.h"
+
+extern struct font sysfont;
+extern struct user_settings global_settings;
+extern struct wps_state wps_state;
+extern struct gui_wps gui_wps[NB_SCREENS];
+extern struct wps_data wps_datas[NB_SCREENS];
+extern struct cuesheet *curr_cue;
+extern struct cuesheet *temp_cue;
+extern struct system_status global_status;
+extern struct gui_syncstatusbar statusbars;
+extern struct playlist_info current_playlist;
+extern int battery_percent;
+extern struct mp3entry current_song, next_song;
+extern int _audio_status;
+
+charger_input_state_type charger_input_state;
+#if CONFIG_CHARGING >= CHARGING_MONITOR
+extern charge_state_type charge_state;
+#endif
+
+#if defined(CPU_PP) && defined(BOOTLOADER)
+/* We don't enable interrupts in the iPod bootloader, so we need to fake
+the current_tick variable */
+#define current_tick (signed)(USEC_TIMER/10000)
+#else
+extern volatile long current_tick;
+#endif
+
+void dummies_init();
+
+#endif /*DUMMIES_H_INCLUDED*/
diff --git a/utils/wpseditor/libwps/src/include/lang.h b/utils/wpseditor/libwps/src/include/lang.h
new file mode 100644
index 0000000..3274bde
--- /dev/null
+++ b/utils/wpseditor/libwps/src/include/lang.h
@@ -0,0 +1,10 @@
+#define LANG_END_PLAYLIST   (signed char)1
+#define LANG_KEYLOCK_ON     (signed char)2
+#define LANG_KEYLOCK_OFF    (signed char)3
+#define LANG_WEEKDAY_SUNDAY (signed char)4
+#define LANG_MONTH_JANUARY  (signed char)5
+#define VOICE_PAUSE         (signed char)6
+#define LANG_BATTERY_TIME   (signed char)7
+#define UNIT_PERCENT        (signed char)8
+
+#define str(...) "empty"
diff --git a/utils/wpseditor/libwps/src/include/rockboxlogo.h b/utils/wpseditor/libwps/src/include/rockboxlogo.h
new file mode 100644
index 0000000..8d1c8b6
--- /dev/null
+++ b/utils/wpseditor/libwps/src/include/rockboxlogo.h
@@ -0,0 +1 @@
+ 
diff --git a/utils/wpseditor/libwps/src/include/sysfont.h b/utils/wpseditor/libwps/src/include/sysfont.h
new file mode 100644
index 0000000..4ba7703
--- /dev/null
+++ b/utils/wpseditor/libwps/src/include/sysfont.h
@@ -0,0 +1 @@
+#define SYSFONT_HEIGHT 9
diff --git a/utils/wpseditor/libwps/src/include/system-target.h b/utils/wpseditor/libwps/src/include/system-target.h
new file mode 100644
index 0000000..8d1c8b6
--- /dev/null
+++ b/utils/wpseditor/libwps/src/include/system-target.h
@@ -0,0 +1 @@
+ 
diff --git a/utils/wpseditor/libwps/src/lcd.c b/utils/wpseditor/libwps/src/lcd.c
new file mode 100644
index 0000000..1f12332
--- /dev/null
+++ b/utils/wpseditor/libwps/src/lcd.c
@@ -0,0 +1,150 @@
+#include "font.h"
+#include "screen_access.h"
+//#include <windef.h>
+#include "api.h"
+#include "defs.h"
+#include "proxy.h"
+#include "dummies.h"
+
+static struct viewport default_vp =
+{
+    .x        = 0,
+    .y        = 0,
+    .width    = LCD_WIDTH,
+    .height   = LCD_HEIGHT,
+    .font     = FONT_SYSFIXED,
+    .drawmode = DRMODE_SOLID,
+    .fg_pattern = LCD_DEFAULT_FG,
+    .bg_pattern = LCD_DEFAULT_BG,
+    .lss_pattern = LCD_DEFAULT_BG,
+    .lse_pattern = LCD_DEFAULT_BG,
+    .lst_pattern = LCD_DEFAULT_BG,
+};
+
+struct viewport* current_vp = &default_vp;
+
+void   get_current_vp(struct viewport_api *avp){
+    avp->x = current_vp->x;
+    avp->y = current_vp->y;
+    avp->width = current_vp->width;
+    avp->height = current_vp->height;
+
+    //TODO: font_get(current_vp->font)->height;
+    avp->fontheight = sysfont.height;
+}
+
+void lcd_set_viewport(struct viewport* vp)
+{
+    if (vp == NULL){
+        current_vp = &default_vp;
+        DEBUGF3("lcd_set_viewport(struct viewport* vp= DEFAULT)\n");
+    }
+    else{
+        current_vp = vp;
+        DEBUGF3("lcd_set_viewport(struct viewport* vp=%x,vpx=%d,vpy=%d,vpw=%d,vph=%d)\n",vp,vp->x,vp->y,vp->width,vp->height);
+    }
+}
+
+void lcd_update_viewport(void)
+{
+    //lcd_update_rect(current_vp->x, current_vp->y,current_vp->width, current_vp->height);
+}
+
+void lcd_update_viewport_rect(int x, int y, int width, int height)
+{
+    //lcd_update_rect(current_vp->x + x, current_vp->y + y, width, height);
+}
+/*** parameter handling ***/
+
+void lcd_set_drawmode(int mode)
+{
+    current_vp->drawmode = mode & (DRMODE_SOLID|DRMODE_INVERSEVID);
+}
+
+int lcd_get_drawmode(void)
+{
+    return current_vp->drawmode;
+}
+
+void lcd_set_foreground(unsigned color)
+{
+    current_vp->fg_pattern = color;
+}
+
+unsigned lcd_get_foreground(void)
+{
+    return current_vp->fg_pattern;
+}
+
+void lcd_set_background(unsigned color)
+{
+    current_vp->bg_pattern = color;
+}
+
+unsigned lcd_get_background(void)
+{
+    return current_vp->bg_pattern;
+}
+
+void lcd_set_selector_start(unsigned color)
+{
+    current_vp->lss_pattern = color;
+}
+
+void lcd_set_selector_end(unsigned color)
+{
+    current_vp->lse_pattern = color;
+}
+
+void lcd_set_selector_text(unsigned color)
+{
+    current_vp->lst_pattern = color;
+}
+
+void lcd_set_drawinfo(int mode, unsigned fg_color, unsigned bg_color)
+{
+    //lcd_set_drawmode(mode);
+    current_vp->fg_pattern = fg_color;
+    current_vp->bg_pattern = bg_color;
+}
+
+int lcd_getwidth(void)
+{
+    return current_vp->width;
+}
+
+int lcd_getheight(void)
+{
+    return current_vp->height;
+}
+
+void lcd_setfont(int newfont)
+{
+    current_vp->font = newfont;
+}
+
+int lcd_getfont(void)
+{
+    return current_vp->font;
+}
+
+/* Clear the whole display */
+void lcd_clear_display(void)
+{
+    struct viewport* old_vp = current_vp;
+
+    current_vp = &default_vp;
+
+    lcd_clear_viewport();
+
+    current_vp = old_vp;
+}
+
+void lcd_clear_viewport(){
+    DEBUGF2("lcd_clear_viewport()\n");
+    xapi->clear_viewport(current_vp->x,current_vp->y,current_vp->width,current_vp->height,current_vp->bg_pattern);
+
+}
+void lcd_scroll_stop(struct viewport* vp){
+    DEBUGF3("lcd_scroll_stop(struct viewport* vp=%x)\n",vp);
+}
diff --git a/utils/wpseditor/libwps/src/proxy.c b/utils/wpseditor/libwps/src/proxy.c
new file mode 100644
index 0000000..3a3b8ce
--- /dev/null
+++ b/utils/wpseditor/libwps/src/proxy.c
@@ -0,0 +1,132 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include "dummies.h"
+#include "proxy.h"
+#include "api.h"
+#include "gwps.h"
+#include "gwps-common.h"
+#include <string.h>
+
+struct screen screens[NB_SCREENS];
+struct wps_data wpsdata;
+struct gui_wps gwps;
+struct mp3entry id3;
+struct mp3entry nid3;
+
+extern void test_api(struct proxy_api *api);
+
+bool debug_wps = true;
+int wps_verbose_level = 0;
+int errno_;
+pfdebugf dbgf = 0;
+
+static char pluginbuf[PLUGIN_BUFFER_SIZE];
+
+const char* get_model_name(){
+#ifdef TARGET_MODEL
+    return TARGET_MODEL;
+#else
+    return "unknown";
+#endif
+}
+
+int read_line(int fd, char* buffer, int buffer_size)
+{
+    int count = 0;
+    int num_read = 0;
+
+    errno_ = 0;
+
+    while (count < buffer_size)
+    {
+        unsigned char c;
+
+        if (1 != read(fd, &c, 1))
+            break;
+
+        num_read++;
+
+        if ( c == '\n' )
+            break;
+
+        if ( c == '\r' )
+            continue;
+
+        buffer[count++] = c;
+    }
+
+    buffer[MIN(count, buffer_size - 1)] = 0;
+
+    return errno_ ? -1 : num_read;
+}
+
+void* plugin_get_buffer(size_t *buffer_size)
+{
+    *buffer_size = PLUGIN_BUFFER_SIZE;
+    return pluginbuf;
+}
+
+int checkwps(const char *filename, int verbose){
+    int res;
+    int fd;
+    
+    struct wps_data wps;
+    wps_verbose_level = verbose;
+
+    fd = open(filename, O_RDONLY);
+    if (fd < 0) {
+      DEBUGF1("Failed to open %s\n",filename);
+      return 2;
+    }
+    close(fd);
+
+    res = wps_data_load(&wps, &screens[0], filename, true);
+
+    if (!res) {
+      DEBUGF1("WPS parsing failure\n");
+      return 3;
+    }
+
+    DEBUGF1("WPS parsed OK\n");
+    return 0;
+}
+
+int wps_init(const char* filename,struct proxy_api *api, bool isfile){
+    int res;
+    if (!api)
+        return 4;
+    dummies_init();
+    test_api(api);
+    set_api(api);
+    wps_data_init(&wpsdata);
+    wps_verbose_level = api->verbose;
+    res = wps_data_load(&wpsdata, &screens[0], filename, isfile);
+    if (!res)
+    {
+      DEBUGF1("ERR: WPS parsing failure\n");
+      return 3;
+    }
+    DEBUGF1("WPS parsed OK\n");
+    DEBUGF1("\n-------------------------------------------------\n");
+    wps_state.paused = true;
+    gwps.data = &wpsdata;
+    gwps.display = &screens[0];
+    gwps.state = &wps_state;
+    gwps.state->id3 = &id3;
+    gwps.state->nid3 = &nid3;
+    gui_wps[0] = gwps;
+    return res;
+}
+
+int wps_display(){
+    DEBUGF3("wps_display(): begin\n");
+    int res = gui_wps_display();
+    DEBUGF3("\nWPS %sdisplayed\n", (res ? "" : "not "));
+    return res;
+}
+int wps_refresh(){
+    DEBUGF3("-----------------<wps_refresh(): begin>-----------------\n");
+    int res = gui_wps_refresh(&gwps, 0, WPS_REFRESH_ALL);
+    DEBUGF3("\nWPS %srefreshed\n", (res ? "" : "not "));
+    return res;
+}
diff --git a/utils/wpseditor/libwps/src/proxy.h b/utils/wpseditor/libwps/src/proxy.h
new file mode 100644
index 0000000..3836ecc
--- /dev/null
+++ b/utils/wpseditor/libwps/src/proxy.h
@@ -0,0 +1,25 @@
+#ifndef PROXY_H
+#define PROXY_h
+
+#include "screen_access.h"
+#include "api.h"
+#include "defs.h"
+
+#define DEBUGF  dbgf
+#define DEBUGF1 dbgf
+#define DEBUGF2(...)
+#define DEBUGF3(...)
+
+EXPORT int checkwps(const char *filename, int verbose);
+EXPORT int wps_init(const char* filename,struct proxy_api *api,bool isfile);
+EXPORT int wps_display();
+EXPORT int wps_refresh();
+
+const char* get_model_name();
+
+extern struct screen screens[NB_SCREENS];
+extern bool   debug_wps;
+extern int    wps_verbose_level;
+
+
+#endif
diff --git a/utils/wpseditor/libwps/src/wpsstate.h b/utils/wpseditor/libwps/src/wpsstate.h
new file mode 100644
index 0000000..148936a
--- /dev/null
+++ b/utils/wpseditor/libwps/src/wpsstate.h
@@ -0,0 +1,34 @@
+#ifndef STATES_H
+#define STATES_H
+//
+struct trackstate
+{
+    char* title;
+    char* artist;
+    char* album;
+    char* genre_string;
+    char* disc_string;
+    char* track_string;
+    char* year_string;
+    char* composer;
+    char* comment;
+    char* albumartist;
+    char* grouping;
+    int discnum;
+    int tracknum;
+    int version;
+    int layer;
+    int year;
+
+    int length;
+    int elapsed;
+};
+
+struct wpsstate{
+    int volume;
+    int fontheight;
+    int fontwidth;
+    int battery_level;
+    int audio_status;
+};
+#endif
diff --git a/utils/wpseditor/libwps/targets.txt b/utils/wpseditor/libwps/targets.txt
new file mode 100644
index 0000000..d2c5437
--- /dev/null
+++ b/utils/wpseditor/libwps/targets.txt
@@ -0,0 +1,33 @@
+ARCHOS_RECORDER recorder
+ARCHOS_FMRECORDER fmrecorder
+ARCHOS_RECORDERV2 recorderv2
+ARCHOS_ONDIOSP ondiosp
+ARCHOS_ONDIOFM ondiofm
+IRIVER_H120 h120
+IRIVER_H300 h300
+IRIVER_H100 h100
+IRIVER_IFP7XX ifp7xx
+IRIVER_H10 h10
+IRIVER_H10_5GB h10_5gb
+IPOD_COLOR ipodcolor
+IPOD_NANO ipodnano
+IPOD_VIDEO ipodvideo
+IPOD_3G ipod3g
+IPOD_4G ipod4g
+IPOD_MINI ipodmini
+IPOD_MINI2G ipodmini2g
+IPOD_1G2G ipod1g2g
+IAUDIO_X5 x5
+IAUDIO_M5 m5
+COWON_D2 cowond2
+IAUDIO_M3 m3
+GIGABEAT_F gigabeatf
+GIGABEAT_S gigabeats
+MROBE_500 mrobe500
+MROBE_100 mrobe100
+LOGIK_DAX logikdax
+CREATIVE_ZVM creativezvm
+SANSA_E200 e200
+SANSA_E200 e200r
+SANSA_C200 c200
+ELIO_TPJ1022 tpj1022
diff --git a/utils/wpseditor/wpseditor.pro b/utils/wpseditor/wpseditor.pro
new file mode 100644
index 0000000..0e9ecbb
--- /dev/null
+++ b/utils/wpseditor/wpseditor.pro
@@ -0,0 +1,2 @@
+SUBDIRS =gui/src/QPropertyEditor gui 
+TEMPLATE = subdirs