From 5382d18d05d358bb1c313c642395e835aa44a6a0 Mon Sep 17 00:00:00 2001 From: lordjaxom Date: Wed, 8 Dec 2004 18:48:39 +0000 Subject: 1.0-pre1 --- 00-DEVELOPMENT | 0 HISTORY | 4 - Makefile | 53 ++- bitmap.c | 32 +- bitmap.h | 18 +- cache.c | 4 +- cache.h | 10 +- common.c | 187 +++----- common.h | 177 +------- contrib/list_items.pl | 2 +- contrib/skin_to_10.pl | 254 +++++++++++ data.c | 159 ------- data.h | 103 ----- display.c | 826 +++++++++++++++++++++++++++--------- display.h | 116 ++++- file.c | 4 +- file.h | 8 +- font.c | 142 ++----- font.h | 44 +- graphtft/font.c | 173 ++++++++ graphtft/font.h | 48 +++ i18n.c | 8 +- i18n.h | 8 +- loader.c | 45 +- loader.h | 27 +- menu.c | 34 ++ menu.h | 24 ++ render.c | 1129 ++++++++++++------------------------------------- render.h | 185 ++++---- screen.c | 80 +++- screen.h | 11 +- scroller.c | 4 +- scroller.h | 2 +- setup.c | 30 +- setup.h | 15 +- status.c | 13 +- status.h | 28 +- text2skin.c | 9 +- text2skin.h | 6 +- theme.c | 4 +- theme.h | 11 +- xml/display.c | 42 ++ xml/display.h | 58 +++ xml/function.c | 212 ++++++++++ xml/function.h | 66 +++ xml/object.c | 169 ++++++++ xml/object.h | 148 +++++++ xml/parser.c | 310 ++++++++++++++ xml/parser.h | 14 + xml/skin.c | 44 ++ xml/skin.h | 64 +++ xml/string.c | 161 +++++++ xml/string.h | 128 ++++++ xml/type.c | 20 + xml/type.h | 42 ++ xml/xml.c | 295 +++++++++++++ xml/xml.h | 63 +++ 57 files changed, 3793 insertions(+), 2080 deletions(-) create mode 100644 00-DEVELOPMENT create mode 100755 contrib/skin_to_10.pl delete mode 100644 data.c delete mode 100644 data.h create mode 100644 graphtft/font.c create mode 100644 graphtft/font.h create mode 100644 menu.c create mode 100644 menu.h create mode 100644 xml/display.c create mode 100644 xml/display.h create mode 100644 xml/function.c create mode 100644 xml/function.h create mode 100644 xml/object.c create mode 100644 xml/object.h create mode 100644 xml/parser.c create mode 100644 xml/parser.h create mode 100644 xml/skin.c create mode 100644 xml/skin.h create mode 100644 xml/string.c create mode 100644 xml/string.h create mode 100644 xml/type.c create mode 100644 xml/type.h create mode 100644 xml/xml.c create mode 100644 xml/xml.h diff --git a/00-DEVELOPMENT b/00-DEVELOPMENT new file mode 100644 index 0000000..e69de29 diff --git a/HISTORY b/HISTORY index 0f1e925..ca50bc6 100644 --- a/HISTORY +++ b/HISTORY @@ -1,10 +1,6 @@ VDR Plugin 'text2skin' Revision History --------------------------------------- -2004-07-27: Version 0.0.8.1 - -- fixed ugly race conditions that appears to occur more often with VDR >= 1.3.14 - 2004-07-14: Version 0.0.8 - fixed display of scrollbar if there is no text present diff --git a/Makefile b/Makefile index 097cd02..2439122 100644 --- a/Makefile +++ b/Makefile @@ -5,11 +5,15 @@ HAVE_IMAGEMAGICK=1 #HAVE_IMLIB2=1 +# comment this out if you don't want to use FreeType font rendering + +HAVE_FREETYPE=1 + # DO NOT EDIT BELOW THIS LINE UNLESS YOU KNOW WHAT YOU'RE DOING # ------------------------------------------------------------- # -# $Id: Makefile,v 1.15 2004/07/02 19:00:22 lordjaxom Exp $ +# $Id: Makefile,v 1.7 2004/12/08 18:47:37 lordjaxom Exp $ # # The official name of this plugin. @@ -25,7 +29,7 @@ VERSION = $(shell grep 'const char \*cText2SkinPlugin::VERSION *=' $(PLUGIN).c | ### The C++ compiler and options: CXX ?= g++ -CXXFLAGS ?= -O2 -Wall -Woverloaded-virtual +CXXFLAGS ?= -Wall -Woverloaded-virtual ### The directory environment: @@ -43,10 +47,21 @@ VDRVERSION = $(shell grep 'define VDRVERSION ' $(VDRDIR)/config.h | awk '{ print ARCHIVE = $(PLUGIN)-$(VERSION) PACKAGE = vdr-$(ARCHIVE) -### Includes and Defines (add further entries here): +### Allow user defined options to overwrite defaults: -include $(VDRDIR)/Make.config +### The object files (add further files here): + +OBJS = $(PLUGIN).o loader.o display.o render.o common.o bitmap.o \ + file.o i18n.o theme.o cache.o setup.o status.o scroller.o screen.o \ + menu.o font.o \ + \ + xml/skin.o xml/parser.o xml/string.o xml/object.o xml/function.o \ + xml/type.o xml/display.o xml/xml.o + +### Includes and Defines (add further entries here): + ifdef HAVE_IMLIB2 DEFINES += -DHAVE_IMLIB2 LIBS += -lImlib2 @@ -54,31 +69,32 @@ endif ifdef HAVE_IMAGEMAGICK DEFINES += -DHAVE_IMAGEMAGICK -# LIBS += -lMagick -lMagick++ - LIBS += $(shell Magick++-config --ldflags --libs) + LIBS += -lMagick -lMagick++ +# LIBS += $(shell Magick++-config --ldflags --libs) +endif + +ifdef HAVE_FREETYPE + INCLUDES += $(shell freetype-config --cflags) + LIBS += $(shell freetype-config --libs) + DEFINES += -DHAVE_FREETYPE + OBJS += graphtft/font.o endif ifdef DEBUG + CXXFLAGS += -O2 -g DEFINES += -DDEBUG +else + CXXFLAGS += -O2 endif -INCLUDES += -I$(VDRDIR)/include -I$(DVBDIR)/include +INCLUDES += -I$(VDRDIR)/include -I$(DVBDIR)/include -I. DEFINES += -D_GNU_SOURCE -DPLUGIN_NAME_I18N='"$(PLUGIN)"' -### Allow user defined options to overwrite defaults: - --include $(VDRDIR)/Make.config - -### The object files (add further files here): - -OBJS = $(PLUGIN).o loader.o data.o display.o render.o common.o bitmap.o \ - file.o i18n.o theme.o cache.o setup.o status.o scroller.o screen.o - ### Implicit rules: %.o: %.c - $(CXX) $(CXXFLAGS) -c $(DEFINES) $(INCLUDES) $< + $(CXX) $(CXXFLAGS) -c $(DEFINES) $(INCLUDES) -o $@ $< # Dependencies: @@ -107,8 +123,9 @@ dist: clean @-rm -rf $(TMPDIR)/$(ARCHIVE) @mkdir $(TMPDIR)/$(ARCHIVE) @cp -a * $(TMPDIR)/$(ARCHIVE) - @tar czf $(PACKAGE).tgz -C $(TMPDIR) $(ARCHIVE) - @-rm -rf $(TMPDIR)/$(ARCHIVE) + @ln -s $(ARCHIVE) $(TMPDIR)/$(PLUGIN) + @tar czf $(PACKAGE).tgz -C $(TMPDIR) $(ARCHIVE) $(PLUGIN) + @-rm -rf $(TMPDIR)/$(ARCHIVE) $(TMPDIR)/$(PLUGIN) @echo Distribution package created as $(PACKAGE).tgz clean: diff --git a/bitmap.c b/bitmap.c index 4a2ab27..fa76c29 100644 --- a/bitmap.c +++ b/bitmap.c @@ -1,5 +1,5 @@ /* - * $Id: bitmap.c,v 1.18 2004/07/13 13:52:51 lordjaxom Exp $ + * $Id: bitmap.c,v 1.3 2004/12/08 18:47:37 lordjaxom Exp $ */ #include "bitmap.h" @@ -16,29 +16,29 @@ using namespace Magick; cText2SkinCache cText2SkinBitmap::mCache(Text2SkinSetup.MaxCacheFill); -cText2SkinBitmap *cText2SkinBitmap::Load(const char *Filename, int Alpha) { +cText2SkinBitmap *cText2SkinBitmap::Load(const std::string &Filename, int Alpha) { if (mCache.Contains(Filename)) return mCache[Filename]; else { cText2SkinBitmap *bmp = new cText2SkinBitmap; - int len = strlen(Filename); + int len = Filename.length(); bool result = false; if (len > 4) { - if (strcmp(Filename + len - 4, ".xpm") == 0) - result = bmp->LoadXpm(Filename, Alpha); + if (Filename.substr(len - 4, 4) == ".xpm") + result = bmp->LoadXpm(Filename.c_str()); else { #ifdef HAVE_IMLIB2 - result = bmp->LoadImlib(Filename, Alpha); + result = bmp->LoadImlib(Filename.c_str()); #else # ifdef HAVE_IMAGEMAGICK - result = bmp->LoadMagick(Filename, Alpha); + result = bmp->LoadMagick(Filename.c_str()); +# else + esyslog("ERROR: text2skin: unknown file format for %s", Filename); # endif #endif } - //else - //esyslog("ERROR: text2skin: unknown file format for %s", Filename); } else - esyslog("ERROR: text2skin: filename %s too short to identify format", Filename); + esyslog("ERROR: text2skin: filename %s too short to identify format", Filename.c_str()); if (result) { bmp->SetAlpha(Alpha); @@ -85,7 +85,7 @@ cBitmap &cText2SkinBitmap::Get(int &UpdateIn) { void cText2SkinBitmap::SetAlpha(int Alpha) { if (Alpha > 0) { - vector::iterator it = mBitmaps.begin(); + std::vector::iterator it = mBitmaps.begin(); for (; it != mBitmaps.end(); ++it) { int count; if ((*it)->Colors(count)) { @@ -98,7 +98,7 @@ void cText2SkinBitmap::SetAlpha(int Alpha) { } } -bool cText2SkinBitmap::LoadXpm(const char *Filename, int Alpha) { +bool cText2SkinBitmap::LoadXpm(const char *Filename) { cBitmap *bmp = new cBitmap(1,1,1); if (bmp->LoadXpm(Filename)) { mBitmaps.push_back(bmp); @@ -109,7 +109,7 @@ bool cText2SkinBitmap::LoadXpm(const char *Filename, int Alpha) { } #ifdef HAVE_IMLIB2 -bool cText2SkinBitmap::LoadImlib(const char *Filename, int Alpha) { +bool cText2SkinBitmap::LoadImlib(const char *Filename) { Imlib_Image image; cBitmap *bmp = NULL; image = imlib_load_image(Filename); @@ -136,12 +136,12 @@ bool cText2SkinBitmap::LoadImlib(const char *Filename, int Alpha) { #endif #ifdef HAVE_IMAGEMAGICK -bool cText2SkinBitmap::LoadMagick(const char *Filename, int Alpha) { - vector images; +bool cText2SkinBitmap::LoadMagick(const char *Filename) { + std::vector images; cBitmap *bmp = NULL; try { int w, h; - vector::iterator it; + std::vector::iterator it; readImages(&images, Filename); if (images.size() == 0) { esyslog("ERROR: text2skin: Couldn't load %s", Filename); diff --git a/bitmap.h b/bitmap.h index 79c44e7..af0fd42 100644 --- a/bitmap.h +++ b/bitmap.h @@ -1,5 +1,5 @@ /* - * $Id: bitmap.h,v 1.12 2004/06/18 16:08:11 lordjaxom Exp $ + * $Id: bitmap.h,v 1.2 2004/12/08 18:47:37 lordjaxom Exp $ */ #ifndef VDR_TEXT2SKIN_BITMAP_H @@ -13,16 +13,16 @@ class cText2SkinBitmap { private: static cText2SkinCache mCache; - vector mBitmaps; - int mCurrent; - time_t mDelay; - time_t mLastGet; + std::vector mBitmaps; + int mCurrent; + time_t mDelay; + time_t mLastGet; // disallow direct construction cText2SkinBitmap(void); public: - static cText2SkinBitmap *Load(const char *Filename, int Alpha = 0); + static cText2SkinBitmap *Load(const std::string &Filename, int Alpha = 0); static void ResetCache(void) { mCache.Reset(); } static void FlushCache(void) { mCache.Flush(); } @@ -33,12 +33,12 @@ public: void SetColor(int Index, tColor Color); void SetAlpha(int Alpha); - bool LoadXpm(const char *Filename, int Alpha); + bool LoadXpm(const char *Filename); #ifdef HAVE_IMLIB2 - bool LoadImlib(const char *Filename, int Alpha); + bool LoadImlib(const char *Filename); #endif #ifdef HAVE_IMAGEMAGICK - bool LoadMagick(const char *Filename, int Alpha); + bool LoadMagick(const char *Filename); #endif }; diff --git a/cache.c b/cache.c index 6c3f99a..b5026b7 100644 --- a/cache.c +++ b/cache.c @@ -1,5 +1,5 @@ /* - * $Id: cache.c,v 1.2 2004/06/18 16:08:11 lordjaxom Exp $ + * $Id: cache.c,v 1.2 2004/12/08 18:47:37 lordjaxom Exp $ */ #include "cache.h" @@ -13,7 +13,7 @@ cText2SkinCache::~cText2SkinCache() { Flush(); } -void cText2SkinCache::Delete(const key_type &Key, data_type &Data) { +void cText2SkinCache::Delete(const key_type &/*Key*/, data_type &Data) { delete Data; } diff --git a/cache.h b/cache.h index 3f48de8..3734293 100644 --- a/cache.h +++ b/cache.h @@ -1,23 +1,25 @@ /* - * $Id: cache.h,v 1.5 2004/06/18 16:08:11 lordjaxom Exp $ + * $Id: cache.h,v 1.1.1.1 2004/11/19 16:45:31 lordjaxom Exp $ */ #ifndef VDR_TEXT2SKIN_CACHE_HPP #define VDR_TEXT2SKIN_CACHE_HPP #include "common.h" +#include +#include #include class cText2SkinBitmap; class cText2SkinCache { private: - typedef string key_type; + typedef std::string key_type; typedef cText2SkinBitmap* data_type; - typedef map item_map; + typedef std::map item_map; typedef item_map::iterator item_iterator; - typedef vector usage_list; + typedef std::vector usage_list; typedef usage_list::iterator usage_iterator; item_map mItems; diff --git a/common.c b/common.c index de6f476..42e4e4f 100644 --- a/common.c +++ b/common.c @@ -1,43 +1,11 @@ /* - * $Id: common.c,v 1.12 2004/06/25 17:51:34 lordjaxom Exp $ + * $Id: common.c,v 1.2 2004/12/06 22:35:54 lordjaxom Exp $ */ -#include "data.h" #include "common.h" #include -const string SectionNames[__SECTION_COUNT__] = - { "Skin", "ChannelSmall", "Channel", "Volume", "ReplayMode", "Replay", - "Message", "Menu" }; - -const string ItemNames[__ITEM_COUNT__] = - { "Unknown", "Skin", "Background", "Text", "Scrolltext", "Image", "Rectangle", - "Ellipse", "Slope", "Progress", "Logo", "Symbol", "MenuArea", "MenuItem", - "Scrollbar" }; - -const string DisplayNames[__DISPLAY_COUNT__] = - { "Always", "DateTimeF", "DateTime", "Date", "Time", "ChannelNumberName", - "ChannelNumber", "ChannelName", "Language", "PresentDateTimeF", - "PresentStartTime", "PresentDate", "PresentVPSTime", "PresentEndTime", - "PresentDuration", "PresentVPS", "PresentRunning", "PresentTimer", - "PresentTitle", "PresentShortText", "PresentDescription", - "FollowingStartTime", "FollowingEndTime", "FollowingDuration", - "FollowingTitle", "FollowingShortText", "Teletext", "Audio", "Dolby", - "Encrypted", "Recording", "Radio", "VolumeCurrent", "VolumeTotal", "Mute", - "ReplayTime", "ReplayDuration", "ReplayTitle", "ReplayPrompt", "Play", - "Pause", "FastFwd", "FastRew", "SlowFwd", "SlowRew", "Message", - "MessageStatus", "MessageInfo", "MessageWarning", "MessageError", - "MenuTitle", "MenuRed", "MenuGreen", "MenuYellow", "MenuBlue", "MenuText", - "MenuRecording", "MenuScrollUp", "MenuScrollDown", "MenuItems", - "MenuCurrent", "MenuGroups", "ReplayMode", "PresentTextDescription" }; - -const string ReplayNames[__REPLAY_COUNT__] = - { "", "normal", "mp3", "mplayer", "dvd", "vcd" }; - -const string BaseNames[__BASE_COUNT__] = - { "rel", "abs" }; - -const char *SkinPath(void) { +std::string SkinPath(void) { return cPlugin::ConfigDirectory(PLUGIN_NAME_I18N); } @@ -56,67 +24,69 @@ const char *ChannelNumber(const cChannel *Channel, int Number) { const char *ChannelName(const cChannel *Channel, int Number) { static char buffer[256]; buffer[0] = '\0'; - if (Channel) - snprintf(buffer, sizeof(buffer), "%s", Channel->Name()); - else if (!Number) - snprintf(buffer, sizeof(buffer), "%s", tr("*** Invalid Channel ***")); - return buffer; -} - -string ItemText(cText2SkinItem *Item, const string &Content) { - string s; - if (Item->Text() != "") { - s = Item->Text(); - int pos; - while ((pos = s.find('$')) != -1) - s.replace(pos, 1, Content); - } else - s = Content; - return s; + if (Channel) + snprintf(buffer, sizeof(buffer), "%s", Channel->Name()); + else if (!Number) + snprintf(buffer, sizeof(buffer), "%s", tr("*** Invalid Channel ***")); + + char *ptr; + if ((ptr = strchr(buffer, ',')) != NULL + || (ptr = strchr(buffer, ';')) != NULL) + *ptr = '\0'; + return buffer; } -bool ParseVar(const char *Text, const char *Name, eSkinItem *Value) { - string value; - if (ParseVar(Text, Name, value)) { - int i; - for (i = 0; i < __ITEM_COUNT__; ++i) { - if (ItemNames[i] == value) { - *Value = (eSkinItem)i; - return true; - } - if (i == __ITEM_COUNT__) - esyslog("ERROR: text2skin: unknown item %s", value.c_str()); - } - } - return false; +const char *ChannelShortName(const cChannel *Channel, int Number) { + static char buffer[256]; + buffer[0] = '\0'; + if (Channel) + snprintf(buffer, sizeof(buffer), "%s", Channel->Name()); + else if (!Number) + snprintf(buffer, sizeof(buffer), "%s", tr("*** Invalid Channel ***")); + + char *ptr; + if ((ptr = strchr(buffer, ',')) != NULL) { + char *start = ptr + 1; + if ((ptr = strchr(start, ';')) != NULL) + *ptr = '\0'; + return start; + } else if ((ptr = strchr(buffer, ';')) != NULL) + *ptr = '\0'; + + return buffer; } -bool ParseVar(const char *Text, const char *Name, eSkinDisplay *Value) { - string value; - if (ParseVar(Text, Name, value)) { - int i; - for (i = 0; i < __DISPLAY_COUNT__; ++i) { - if (DisplayNames[i] == value) { - *Value = (eSkinDisplay)i; - return true; - } - if (i == __DISPLAY_COUNT__) - esyslog("ERROR: text2skin: unknown display parameter %s", value.c_str()); - } - } - return false; +const char *ChannelBouquet(const cChannel *Channel, int Number) { + static char buffer[256]; + buffer[0] = '\0'; + if (Channel) + snprintf(buffer, sizeof(buffer), "%s", Channel->Name()); + else if (!Number) + snprintf(buffer, sizeof(buffer), "%s", tr("*** Invalid Channel ***")); + + char *ptr; + if ((ptr = strchr(buffer, ';')) != NULL) + return ptr + 1; + else + return ""; } -bool ParseVar(const char *Text, const char *Name, int *Value) { - string value; - if (ParseVar(Text, Name, value)) { - *Value = atoi(value.c_str()); - return true; +cxType TimeType(time_t Time, const std::string &Format) { + static char result[1000]; + struct tm tm_r, *tm; + tm = localtime_r(&Time, &tm_r); + + if (Time > 0) { + if (Format.length() > 0) { + strftime(result, sizeof(result), Format.c_str(), tm); + return result; + } else + return Time; } - return false; + return ""; } -bool ParseVar(const char *Text, const char *Name, string &Value){ +bool ParseVar(const char *Text, const char *Name, std::string &Value) { const char *ptr1, *ptr2; char *str; bool res = false; @@ -141,7 +111,7 @@ bool ParseVar(const char *Text, const char *Name, string &Value){ } bool ParseVar(const char *Text, const char *Name, tColor *Value) { - string value; + std::string value; if (ParseVar(Text, Name, value) && value[0] == '#') { *Value = (tColor)strtoul(value.c_str() + 1, NULL, 16); return true; @@ -149,48 +119,7 @@ bool ParseVar(const char *Text, const char *Name, tColor *Value) { return false; } -bool ParseVar(const char *Text, const char *Name, eTextAlignment *Value) { - string value; - if (ParseVar(Text, Name, value)) { - int v = atoi(value.c_str()); - if (v == 0) - *Value = (eTextAlignment)(taTop|taLeft); - else if (v == 1) - *Value = (eTextAlignment)(taTop|taCenter); - else if (v == 2) - *Value = (eTextAlignment)(taTop|taRight); - return true; - } - return false; -} - -bool ParseVar(const char *Text, const char *Name, const cFont **Value) { - string value; - if (ParseVar(Text, Name, value)) { - if (value == "Sml") *Value = cFont::GetFont(fontSml); - else if (value == "Fix") *Value = cFont::GetFont(fontFix); - return true; - } - return false; -} - -bool ParseVar(const char *Text, const char *Name, eBaseCoordinate *Value) { - string value; - if (ParseVar(Text, Name, value)) { - int i; - for (i = 0; i < __BASE_COUNT__; ++i) { - if (BaseNames[i] == value) { - *Value = (eBaseCoordinate)i; - return true; - } - if (i == __BASE_COUNT__) - esyslog("ERROR: text2skin: unknown coordinate base %s", value.c_str()); - } - } - return false; -} - -void SkipQuotes(string &Value) { +void SkipQuotes(std::string &Value) { char quote = Value[0]; int i; Value.erase(0, 1); diff --git a/common.h b/common.h index 34b499b..12987d8 100644 --- a/common.h +++ b/common.h @@ -1,19 +1,14 @@ /* - * $Id: common.h,v 1.13 2004/07/02 19:00:22 lordjaxom Exp $ + * $Id: common.h,v 1.3 2004/12/08 17:13:25 lordjaxom Exp $ */ #ifndef VDR_TEXT2SKIN_COMMON_H #define VDR_TEXT2SKIN_COMMON_H +#include "xml/string.h" #include -#include -#include #include -using std::string; -using std::vector; -using std::map; - #ifdef DEBUG # define Dprintf(x...) fprintf(stderr, x); # define Dbench(x) time_t bench_##x = time_ms(); @@ -24,173 +19,27 @@ using std::map; # define Ddiff(x) #endif -// sections and items known by skin files - -enum eSkinSection { - sectionSkin, - sectionChannelSmall, - sectionChannel, - sectionVolume, - sectionReplayMode, - sectionReplay, - sectionMessage, - sectionMenu, - __SECTION_COUNT__ -}; - -enum eSkinItem { - itemUnknown, - itemSkin, // item identifying the Skin itself - itemBackground, - itemText, - itemScrolltext, - itemImage, - itemRectangle, - itemEllipse, - itemSlope, - itemProgress, - itemLogo, - itemSymbol, - itemMenuArea, - itemMenuItem, - itemScrollbar, - __ITEM_COUNT__ -}; - -enum eSkinDisplay { - displayAlways, - displayDateTimeF, // exc: text - displayDateTime, // exc: text - displayDate, // exc: text - displayTime, // exc: text - displayChannelNumberName, // exc: text - displayChannelNumber, // exc: text - displayChannelName, // exc: text, logo - displayLanguage, // exc: text, logo - displayPresentDateTimeF, // exc: text - displayPresentStartTime, // exc: text - displayPresentDate, // exc: text - displayPresentVPSTime, // exc: text - displayPresentEndTime, // exc: text - displayPresentDuration, // exc: text, progress - displayPresentVPS, // exc: symbol - displayPresentRunning, // exc: symbol - displayPresentTimer, // exc: symbol - displayPresentTitle, // exc: text - displayPresentShortText, // exc: text - displayPresentDescription, // exc: text - displayFollowingStartTime, // exc: text - displayFollowingEndTime, // exc: text - displayFollowingDuration, // exc: text - displayFollowingTitle, // exc: text - displayFollowingShortText, // exc: text - displayTeletext, // exc: symbol - displayAudio, // exc: symbol - displayDolby, // exc: symbol - displayEncrypted, // exc: symbol - displayRecording, // exc: symbol - displayRadio, // exc: symbol - displayVolumeCurrent, // exc: text, progress - displayVolumeTotal, // exc: text, progress - displayMute, // exc: symbol - displayReplayTime, // exc: text, progress - displayReplayDuration, // exc: text - displayReplayTitle, // exc: text - displayReplayPrompt, // exc: text - displayPlay, // exc: symbol - displayPause, // exc: symbol - displayFastFwd, // exc: symbol - displayFastRew, // exc: symbol - displaySlowFwd, // exc: symbol - displaySlowRew, // exc: symbol - displayMessage, // exc: text - displayMessageStatus, // exc: text - displayMessageInfo, // exc: text - displayMessageWarning, // exc: text - displayMessageError, // exc: text - displayMenuTitle, // exc: text (TODO: logo?) - displayMenuRed, // exc: text - displayMenuGreen, // exc: text - displayMenuYellow, // exc: text - displayMenuBlue, // exc: text - displayMenuText, // exc: text - displayMenuRecording, // exc: text - displayMenuScrollUp, // exc: symbol - displayMenuScrollDown, // exc: symbol - displayMenuItems, // exc: text (TODO: logo?) - displayMenuCurrent, // exc: text (TODO: logo?) - displayMenuGroups, // exc: text (TODO: logo?) - displayReplayMode, // exc: text, logo - displayPresentTextDescription, // exc: text - __DISPLAY_COUNT__ -}; - -enum eReplayMode { - replayNone, - replayNormal, - replayMP3, - replayMPlayer, - replayDVD, - replayVCD, - __REPLAY_COUNT__ -}; - -enum eBaseCoordinate { - baseRelative, - baseAbsolute, - __BASE_COUNT__ -}; - -extern const string SectionNames[__SECTION_COUNT__]; -extern const string ItemNames[__ITEM_COUNT__]; -extern const string DisplayNames[__DISPLAY_COUNT__]; -extern const string ReplayNames[__REPLAY_COUNT__]; -extern const string BaseNames[__BASE_COUNT__]; +/* Check if a channel is a radio station. */ +#define ISRADIO(x) ((x)->Vpid()==0||(x)->Vpid()==1||(x)->Vpid()==0x1fff) // class forwards class cMarks; class cChannel; -class cText2SkinItem; - -// geometrical and helper structures - -struct POINT { - int x, y; - POINT(int _x = 0, int _y = 0) { x = _x; y = _y; } - POINT &operator+=(const POINT &pt) { x += pt.x; y += pt.y; return *this; } -}; - -struct SIZE { - int w, h; - SIZE(int _w = 0, int _h = 0) { w = _w; h = _h; } -}; - -struct tItemData { - string text; - string path; - int current; - int shown; - int total; - const cMarks *marks; - tItemData(void) { marks = NULL; } -}; // helper functions -const char *SkinPath(void); +std::string SkinPath(void); const char *ChannelNumber(const cChannel *Channel, int Number); const char *ChannelName(const cChannel *Channel, int Number); - -bool ParseVar(const char *Text, const char *Name, eSkinItem *Value); -bool ParseVar(const char *Text, const char *Name, eSkinDisplay *Value); -bool ParseVar(const char *Text, const char *Name, int *Value); -bool ParseVar(const char *Text, const char *Name, const cFont **Value); -bool ParseVar(const char *Text, const char *Name, string &Value); -bool ParseVar(const char *Text, const char *Name, tColor *Value); -bool ParseVar(const char *Text, const char *Name, eTextAlignment *Value); -bool ParseVar(const char *Text, const char *Name, eBaseCoordinate *Value); +const char *ChannelShortName(const cChannel *Channel, int Number); +const char *ChannelBouquet(const cChannel *Channel, int Number); + +cxType TimeType(time_t Time, const std::string &Format); -void SkipQuotes(string &Value); +bool ParseVar(const char *Text, const char *Name, std::string &Value); +bool ParseVar(const char *Text, const char *Name, tColor *Value); + +void SkipQuotes(std::string &Value); #endif // VDR_TEXT2SKIN_COMMON_H diff --git a/contrib/list_items.pl b/contrib/list_items.pl index a47803f..7b53231 100755 --- a/contrib/list_items.pl +++ b/contrib/list_items.pl @@ -1,7 +1,7 @@ #!/usr/bin/perl $ITEMFILE="common.h"; -$PARMFILE="data.h"; +$PARMFILE="xml/object.h"; sub printo { my $text = shift; diff --git a/contrib/skin_to_10.pl b/contrib/skin_to_10.pl new file mode 100755 index 0000000..014259b --- /dev/null +++ b/contrib/skin_to_10.pl @@ -0,0 +1,254 @@ +#!/usr/bin/perl + +use strict; +use warnings; + +my $DISPLAYS = { + Channel => 'channelInfo', + Volume => 'volume', + Message => 'message', + Replay => 'replayInfo', + ReplayMode => 'replaySmall', + Menu => 'menu', +}; + +my $TOKENS = { + DateTimeF => '{DateTime:%s}', + DateTime => '{DateTime:%a %e.%m. %H\:%M}', + Date => '{DateTime:%e.%m.}', + Time => '{DateTime:%H\:%M}', + ChannelNumberName => '{ChannelNumber} {ChannelName}', + PresentDateTimeF => '{PresentStartDateTime:%s}', + PresentStartTime => '{PresentStartDateTime:%H\:%M}', + PresentDate => '{PresentStartDateTime:%e.%m.}', + PresentVPSTime => '{PresentVPSDateTime:%H\:%M}', + PresentEndTime => '{PresentEndDateTime:%H\:%M}', + PresentDuration => '{PresentDuration:%H\:%M}', + PresentTextDescription => '{PresentText}\n\n{PresentDescription}', + FollowingStartTime => '{FollowingStartDateTime:%H\:%M}', + FollowingEndTime => '{FollowingEndDateTime:%H\:%M}', + FollowingDuration => '{FollowingDuration:%H\:%M}', + FollowingTextDescription => '{FollowingText}\n\n{FollowingDescription}', + FastFwd => '{IsFastForward}', + ReplayTime => '{ReplayPosition}', + ReplayDuration => '{ReplayDuration}', + MenuRed => '{ButtonRed}', + MenuGreen => '{ButtonGreen}', + MenuYellow => '{ButtonYellow}', + MenuBlue => '{ButtonBlue}', +}; + +my $ALIGNS = { + 0 => 'left', + 1 => 'center', + 2 => 'right' +}; + +my $SYMBOLS = { + Teletext => '{HasTeletext}', + Audio => '{HasMultilang}', + Dolby => '{HasDolby}', + Radio => '{IsRadio}', + Encrypted => '{IsEncrypted}', + Recording => '{IsRecording}', + + Play => '{IsPlaying}', + Pause => '{IsPausing}', + FastFwd => '{IsFastForward}', + FastRew => '{IsFastRewind}', + SlowFwd => '{IsSlowForward}', + SlowRew => '{IsSlowRewind}', +}; + +my $data = { Skin => [] }; +my $section = "Skin"; + +while (defined($_ = <>)) { + chomp $_; + $_ =~ s/;$//; + next if /^\s*$/; + next if /^\s*#/; + + if ($_ =~ /\[([^\]]+)\]/) { + $section = $1; + $data->{$section} = []; + } else { + my @params = split(/,/, $_); + my $item = {}; + foreach my $param (@params) { + my @param = split(/=/, $param); + $item->{$param[0]} = $param[1]; + } + push @{$data->{$section}}, $item; + } +} + +print "\n"; + +# skin tag +print "{Skin}[0]{name} . "\""; +if (defined($data->{Skin}[0]{base}) && $data->{Skin}[0]{base} eq 'abs') { + print " screenBase=\"absolute\""; +} else { + print " screenBase=\"relative\""; +} +print ">\n"; + +foreach my $display (keys %$data) { + next if (!defined($DISPLAYS->{$display})); + + # display tag + print " {$display} . "\">\n"; + + foreach my $window (@{$data->{$display}}) { + next if ($window->{Item} ne 'Background'); + + print " {x1} . "\" x2=\"" . $window->{x2} + . "\" y1=\"" . $window->{y1} . "\" y2=\"" . $window->{y2} + . "\" bpp=\"" . ($window->{bpp} || 4) . "\"/>\n"; + } + + foreach my $item (@{$data->{$display}}) { + local $_ = $item->{Item}; + /^Background$/ and do { + if (defined($item->{bg})) { + print " {x1} . "\" x2=\"" + . $item->{x2} . "\" y1=\"" . $item->{y1} . "\" y2=\"" + . $item->{y2} . "\" color=\"" . $item->{bg} . "\"/>\n"; + } + if (defined($item->{path})) { + print " {x1} . "\" y=\"" . $item->{y1} + . "\" path=\"" . $item->{path} . "\""; + + if (defined($item->{alpha})) { + print " alpha=\"" . $item->{alpha} . "\""; + } + print "/>\n"; + } + next; + }; + /^Image$/ and do { + print " {x1} . "\" y=\"" . $item->{y1} + . "\" path=\"" . $item->{path} . "\""; + if (defined($item->{alpha})) { + print " alpha=\"" . $item->{alpha} . "\""; + } + print "/>\n"; + next; + }; + /^Rectangle$/ and do { + $item->{x1} ||= 0; + $item->{y1} ||= 0; + $item->{x2} ||= -1; + $item->{y2} ||= -1; + + print " {x1} . "\" x2=\"" + . $item->{x2} . "\" y1=\"" . $item->{y1} . "\" y2=\"" + . $item->{y2} . "\" color=\"" . $item->{fg} . "\""; + if (defined($item->{display})) { + if (defined($TOKENS->{$item->{display}})) { + print " condition=\"" . $TOKENS->{$item->{display}} . "\""; + } else { + print " condition=\"{" . $item->{display} . "}\""; + } + } + print "/>\n"; + next; + }; + /^Logo$/ and do { + print " {x1} . "\" y=\"" . $item->{y1} + . "\""; + if (defined($item->{alpha})) { + print " alpha=\"" . $item->{alpha} . "\""; + } + if ($item->{display} eq 'ChannelName') { + my $p = $item->{path} . "/{" . $item->{display} . "}." + . $item->{type}; + print " condition=\"file('$p')\"" . " path=\"$p\""; + } elsif ($item->{display} eq 'ReplayMode') { + my $p = $item->{path} . "/{" . $item->{display} . "}." + . $item->{type}; + print " condition=\"file('$p')\" path=\"$p\""; + } + print "/>\n"; + next; + }; + /^Text$/ and do { + $item->{x1} ||= 0; + $item->{y1} ||= 0; + $item->{x2} ||= -1; + $item->{y2} ||= -1; + + print " {x1} . "\" x2=\"" + . $item->{x2} . "\" y1=\"" . $item->{y1} . "\" y2=\"" + . $item->{y2} . "\" color=\"" . $item->{fg} . "\""; + if (defined($item->{align})) { + print " align=\"" . $ALIGNS->{$item->{align}} . "\""; + } + if (defined($item->{font})) { + print " font=\"" . $item->{font} . "\""; + } + print ">"; + if ($item->{display} eq 'DateTimeF' + || $item->{display} eq 'PresentDateTimeF') { + my $f = $item->{format}; + $f =~ s/^"|"$//; + $f =~ s/([:\{\}])/\\$1/g; + print sprintf($TOKENS->{$item->{display}}, $f); + } elsif (defined($TOKENS->{$item->{display}})) { + print $TOKENS->{$item->{display}}; + } else { + print "{" . $item->{display} . "}"; + } + print "\n"; + next; + }; + /^Symbol$/ and do { + print " {x1} . "\" y=\"" . $item->{y1} + . "\""; + if (defined($item->{alpha})) { + print " alpha=\"" . $item->{alpha} . "\""; + } + print " condition=\"" . $SYMBOLS->{$item->{display}} . "\" path=\"" + . $item->{path} . "\"/>\n"; + if (defined($item->{altpath})) { + print " {x1} . "\" y=\"" + . $item->{y1} . "\""; + if (defined($item->{alpha})) { + print " alpha=\"" . $item->{alpha} . "\""; + } + print " condition=\"not(" . $SYMBOLS->{$item->{display}} . ")\"" + ." path=\"" . $item->{path} . "\"/>\n"; + } + next; + }; + /^Progress$/ and do { + print " {x1} . "\" x2=\"" + . $item->{x2} . "\" y1=\"" . $item->{y1} . "\" y2=\"" + . $item->{y2} . "\" color=\"" . $item->{fg} . "\""; + if (defined($item->{bg})) { + print " bgcolor=\"" . $item->{bg} . "\""; + } + if ($item->{display} eq 'VolumeCurrent') { + print " current=\"{VolumeCurrent}\" total=\"{VolumeTotal}\""; + } + if ($item->{display} eq 'PresentDuration') { + print " current=\"{PresentProgress}\" " + . " total=\"{PresentDuration}\""; + } + if ($item->{display} eq 'ReplayTime') { + print " current=\"{ReplayPositionIndex}\" " + . " total=\"{ReplayDurationIndex}\""; + } + print "/>\n"; + next; + }; + } + + # display end tag + print " \n"; +} + +# skin end tag +print "\n"; diff --git a/data.c b/data.c deleted file mode 100644 index c7053b1..0000000 --- a/data.c +++ /dev/null @@ -1,159 +0,0 @@ -/* - * $Id: data.c,v 1.21 2004/07/13 13:52:51 lordjaxom Exp $ - */ - -#include "data.h" -#include "common.h" -#include "render.h" - -cText2SkinItem::cText2SkinItem(void) { - mItem = itemUnknown; - mDisplay = displayAlways; - mBpp = 4; - mArc = 0; - mAlpha = 0; - mSelected= "#FFFC1414"; - mMark = "#FF000000"; - mCurrent = "#FFFC1414"; - mFont = cFont::GetFont(fontOsd); - mAlign = taDefault; - mBase = baseRelative; -} - -cText2SkinItem::~cText2SkinItem() { -} - -bool cText2SkinItem::Parse(const char *Text) { - const char *text = Text; - const char *ptr = text; - bool res = false; - - // check if this is an item - if (ParseVar(ptr, "Item", &mItem) && mItem != itemUnknown) { - ParseItem(ptr); - - if (mItem == itemSkin && (mName == "" || mVersion == "")) - esyslog("ERROR: text2skin: Item=Skin is missing the name and/or version parameter(s)"); - else - res = true; - } else - esyslog("ERROR: text2skin: unknown item in skin"); - return res; -} - -bool cText2SkinItem::ParseItem(const char *Text) { - ParseVar(Text, "name", mName); - ParseVar(Text, "version", mVersion); - ParseVar(Text, "base", &mBase); - ParseVar(Text, "display", &mDisplay); - ParseVar(Text, "x1", &mPos1.x); - ParseVar(Text, "y1", &mPos1.y); - ParseVar(Text, "x2", &mPos2.x); - ParseVar(Text, "y2", &mPos2.y); - ParseVar(Text, "bpp", &mBpp); - ParseVar(Text, "arc", &mArc); - ParseVar(Text, "alpha", &mAlpha); - ParseVar(Text, "fg", mFg); - ParseVar(Text, "bg", mBg); - ParseVar(Text, "selected", mSelected); - ParseVar(Text, "mark", mMark); - ParseVar(Text, "current", mCurrent); - ParseVar(Text, "font", &mFont); - ParseVar(Text, "path", mPath); - ParseVar(Text, "altpath", mAltPath); - ParseVar(Text, "text", mText); - ParseVar(Text, "type", mType); - ParseVar(Text, "format", mFormat); - ParseVar(Text, "align", &mAlign); - return true; -} - -const POINT cText2SkinItem::Pos(void) const { - return cText2SkinRender::Transform(mPos1); -} - -const SIZE cText2SkinItem::Size(void) const { - POINT p1 = cText2SkinRender::Transform(mPos1); - POINT p2 = cText2SkinRender::Transform(mPos2); - return SIZE(p2.x - p1.x + 1, p2.y - p1.y + 1); -} - -const tColor *cText2SkinItem::Fg(void) const { - static tColor Fg; - return cText2SkinRender::ItemColor(mFg, Fg) ? &Fg : NULL; -} - -const tColor *cText2SkinItem::Bg(void) const { - static tColor Bg; - return cText2SkinRender::ItemColor(mBg, Bg) ? &Bg : NULL; -} - -const tColor *cText2SkinItem::Selected(void) const { - static tColor Selected; - return cText2SkinRender::ItemColor(mSelected, Selected) ? &Selected : NULL; -} - -const tColor *cText2SkinItem::Mark(void) const { - static tColor Mark; - return cText2SkinRender::ItemColor(mMark, Mark) ? &Mark : NULL; -} - -const tColor *cText2SkinItem::Current(void) const { - static tColor Current; - return cText2SkinRender::ItemColor(mCurrent, Current) ? &Current : NULL; -} - -// --- cText2SkinData --------------------------------------------------------- - -cText2SkinData::cText2SkinData(const char *Skin): cText2SkinFile(Skin) { - mCurrentSection = sectionSkin; -} - -cText2SkinData::~cText2SkinData() { - for (int i = 0; i < __SECTION_COUNT__; ++i) { - for (int j = 0; j < (int)mSections[i].size(); ++j) - delete mSections[i][j]; - mSections[i].clear(); - } -} - -bool cText2SkinData::Parse(const char *Text) { - int l = strlen(Text); - bool result = false; - if (l) { - if (Text[0] == '#') // comment - result = true; - else if (Text[0] == '[' && Text[l - 1] == ']') { // section - char *s; - int i; - asprintf(&s, "%.*s", l - 2, Text + 1); - for (i = 0; i < __SECTION_COUNT__; ++i) { - if (SectionNames[i] == s) { - mCurrentSection = (eSkinSection)i; - result = true; - break; - } - } - if (i == __SECTION_COUNT__) - esyslog("ERROR: text2skin: Unknown section %s", s); - free(s); - } else { - cText2SkinItem *item = new cText2SkinItem; - if (item->Parse(Text)) { - mSections[mCurrentSection].push_back(item); - result = true; - } else - delete item; - } - } - return result; -} - -cText2SkinItem *cText2SkinData::Get(eSkinSection Section, eSkinItem Item) { - vector::iterator it = mSections[Section].begin(); - for (; it != mSections[Section].end(); ++it) { - if ((*it)->Item() == Item) - return (*it); - } - return NULL; -} diff --git a/data.h b/data.h deleted file mode 100644 index b71f63b..0000000 --- a/data.h +++ /dev/null @@ -1,103 +0,0 @@ -/* - * $Id: data.h,v 1.18 2004/07/13 13:52:51 lordjaxom Exp $ - */ - -#ifndef VDR_TEXT2SKIN_DATA_H -#define VDR_TEXT2SKIN_DATA_H - -#include "common.h" -#include "file.h" -#include -#include -#include - -class cText2SkinItem { -private: - eSkinItem mItem; - eSkinDisplay mDisplay; - POINT mPos1; - POINT mPos2; - int mBpp; - int mArc; - int mAlpha; - string mFg; - string mBg; - string mSelected; - string mMark; - string mCurrent; - const cFont *mFont; - string mName; - string mVersion; - string mPath; - string mAltPath; - string mText; - string mType; - string mFormat; - eTextAlignment mAlign; - eBaseCoordinate mBase; - -protected: - bool ParseItem(const char *Text); - -public: - cText2SkinItem(void); - ~cText2SkinItem(); - - bool Parse(const char *Text); - - // writeables - POINT &Pos1(void) { return mPos1; } - POINT &Pos2(void) { return mPos2; } - - // readables - eSkinItem Item(void) const { return mItem; } - eSkinDisplay Display(void) const { return mDisplay; } - eBaseCoordinate Base(void) const { return mBase; } - const POINT &Pos1(void) const { return mPos1; } - const POINT &Pos2(void) const { return mPos2; } - int Bpp(void) const { return mBpp; } - int Arc(void) const { return mArc; } - int Alpha(void) const { return mAlpha; } - const cFont *Font(void) const { return mFont; } - const string &Name(void) const { return mName; } - const string &Version(void) const { return mVersion; } - const string &Path(void) const { return mPath; } - const string &AltPath(void) const { return mAltPath; } - const string &Text(void) const { return mText; } - const string &Type(void) const { return mType; } - const string &Format(void) const { return mFormat; } - eTextAlignment Align(void) const { return mAlign; } - - // auto-conversion - const POINT Pos(void) const; - const SIZE Size(void) const; - const tColor *Fg(void) const; - const tColor *Bg(void) const; - const tColor *Selected(void)const; - const tColor *Mark(void) const; - const tColor *Current(void) const; -}; - -class cText2SkinData: public cText2SkinFile { -public: - typedef vector tSection; - typedef tSection::iterator tIterator; - -private: - eSkinSection mCurrentSection; - tSection mSections[__SECTION_COUNT__]; - -protected: - virtual bool Parse(const char *Text); - -public: - cText2SkinData(const char *Skin); - virtual ~cText2SkinData(); - - tIterator First(eSkinSection Section) { return mSections[Section].begin(); } - tIterator Last(eSkinSection Section) { return mSections[Section].end(); } - - cText2SkinItem *Get(eSkinSection Section, eSkinItem Item); -}; - -#endif // VDR_TEXT2SKIN_DATA_H diff --git a/display.c b/display.c index e2cdbc8..c8e2642 100644 --- a/display.c +++ b/display.c @@ -1,271 +1,554 @@ /* - * $Id: display.c,v 1.19 2004/07/02 19:00:22 lordjaxom Exp $ + * $Id: display.c,v 1.5 2004/12/08 18:47:37 lordjaxom Exp $ */ #include "render.h" -#include "data.h" #include "loader.h" #include "display.h" #include "scroller.h" +#include "status.h" +#include "xml/string.h" +#include // --- cText2SkinDisplayChannel ----------------------------------------------- -cText2SkinDisplayChannel::cText2SkinDisplayChannel(cText2SkinLoader *Loader, bool WithInfo) { - mWithInfo = WithInfo; - mRender = new cText2SkinRender(Loader, WithInfo ? sectionChannel : sectionChannelSmall); - mDirty = false; +cText2SkinDisplayChannel::cText2SkinDisplayChannel(cText2SkinLoader *Loader, bool WithInfo): + cText2SkinRender(Loader, WithInfo ? cxDisplay::channelInfo : cxDisplay::channelSmall), + mChannel(NULL), + mNumber(0), + mPresent(NULL), + mFollowing(NULL), + mType(mtStatus), + mText("") { } cText2SkinDisplayChannel::~cText2SkinDisplayChannel() { - delete mRender; } void cText2SkinDisplayChannel::SetChannel(const cChannel *Channel, int Number) { - mRender->Lock(); - if (mRender->mChannel != Channel || mRender->mChannelNumber != Number) { - mRender->mChannel = Channel; - mRender->mChannelNumber = Number; - mDirty = true; + if (mChannel != Channel || mNumber != Number) { + mChannel = Channel; + mNumber = Number; + SetDirty(); } - mRender->Unlock(); } -void cText2SkinDisplayChannel::SetEvents(const cEvent *Present, const cEvent *Following) { - mRender->Lock(); - if (mRender->mChannelPresent != Present || mRender->mChannelFollowing != Following) { - mRender->mChannelPresent = Present; - mRender->mChannelFollowing = Following; - mDirty = true; +void cText2SkinDisplayChannel::SetEvents(const cEvent *Present, + const cEvent *Following) { + if (mPresent != Present || mFollowing != Following) { + mPresent = Present; + mFollowing = Following; + SetDirty(); } - mRender->Unlock(); } void cText2SkinDisplayChannel::SetMessage(eMessageType Type, const char *Text) { if (Text == NULL) Text = ""; - mRender->Lock(); - if (mRender->mMessageType != Type || mRender->mMessageText != Text) { - mRender->mMessageType = Type; - mRender->mMessageText = Text; - mDirty = true; + if (mType != Type || mText != Text) { + mType = Type; + mText = Text; + SetDirty(); } - mRender->Unlock(); } void cText2SkinDisplayChannel::Flush(void) { - if (mDirty) { - Dprintf("Flushing\n"); - mRender->Flush(); - Dprintf("Flushing done\n"); - mDirty = false; + cText2SkinRender::Flush(); +} + +cxType cText2SkinDisplayChannel::GetTokenData(const txToken &Token) { + switch (Token.Type) { + case tChannelNumber: + return mChannel != NULL + ? (cxType)ChannelNumber(mChannel, mNumber) + : (cxType)false; + + case tChannelName: + return mChannel != NULL + ? (cxType)ChannelName(mChannel, mNumber) + : (cxType)false; + + case tChannelShortName: + return mChannel != NULL + ? (cxType)ChannelShortName(mChannel, mNumber) + : (cxType)false; + + case tChannelBouquet: + return mChannel != NULL + ? (cxType)ChannelBouquet(mChannel, mNumber) + : (cxType)false; + + case tPresentStartDateTime: + return mPresent != NULL + ? (cxType)TimeType(mPresent->StartTime(), Token.Attrib) + : (cxType)false; + + case tPresentVPSDateTime: + return mPresent != NULL + ? (cxType)TimeType(mPresent->Vps(), Token.Attrib) + : (cxType)false; + + case tPresentEndDateTime: + return mPresent != NULL + ? (cxType)TimeType(mPresent->EndTime(), Token.Attrib) + : (cxType)false; + + case tPresentProgress: + return mPresent != NULL + ? (cxType)TimeType(time(NULL) - mPresent->StartTime(), Token.Attrib) + : (cxType)false; + + case tPresentDuration: + return mPresent != NULL + ? (cxType)TimeType(mPresent->Duration(), Token.Attrib) + : (cxType)false; + + case tPresentTitle: + return mPresent != NULL + ? (cxType)mPresent->Title() + : (cxType)false; + + case tPresentShortText: + return mPresent != NULL + ? (cxType)mPresent->ShortText() + : (cxType)false; + + case tPresentDescription: + return mPresent != NULL + ? (cxType)mPresent->Description() + : (cxType)false; + + case tFollowingStartDateTime: + return mFollowing != NULL + ? (cxType)TimeType(mFollowing->StartTime(), Token.Attrib) + : (cxType)false; + + case tFollowingVPSDateTime: + return mFollowing != NULL + ? (cxType)TimeType(mFollowing->Vps(), Token.Attrib) + : (cxType)false; + + case tFollowingEndDateTime: + return mFollowing != NULL + ? (cxType)TimeType(mFollowing->EndTime(), Token.Attrib) + : (cxType)false; + + case tFollowingDuration: + return mFollowing != NULL + ? (cxType)TimeType(mFollowing->Duration(), Token.Attrib) + : (cxType)false; + + case tFollowingTitle: + return mFollowing != NULL + ? (cxType)mFollowing->Title() + : (cxType)false; + + case tFollowingShortText: + return mFollowing != NULL + ? (cxType)mFollowing->ShortText() + : (cxType)false; + + case tFollowingDescription: + return mFollowing != NULL + ? (cxType)mFollowing->Description() + : (cxType)false; + + case tLanguage: { + int cur; + const char **tracks = cDevice::PrimaryDevice()->GetAudioTracks(&cur); + if (tracks) { + int i = 0; + while (tracks[i] != NULL) + ++i; + if (cur < i) + return tracks[cur]; + } + } + return false; + + case tHasTeletext: + return mChannel != NULL && mChannel->Tpid() != 0; + + case tHasMultilang: + return mChannel != NULL && mChannel->Apid2() != 0; + + case tHasDolby: + return mChannel != NULL && mChannel->Dpid1() != 0; + + case tIsEncrypted: + return mChannel != NULL && mChannel->Ca() != 0; + + case tIsRadio: + return mChannel != NULL && ISRADIO(mChannel); + + case tIsRecording: + return cRecordControls::Active(); + + case tHasVPS: + return mPresent != NULL && mPresent->Vps() != 0; + + case tHasTimer: + return mPresent != NULL && mPresent->HasTimer(); + + case tIsRunning: + return mPresent != NULL && mPresent->IsRunning(); + + case tMessage: + return mText; + + case tMessageInfo: + return mType == mtInfo + ? (cxType)mText + : (cxType)false; + + case tMessageWarning: + return mType == mtWarning + ? (cxType)mText + : (cxType)false; + + case tMessageStatus: + return mType == mtStatus + ? (cxType)mText + : (cxType)false; + + case tMessageError: + return mType == mtError + ? (cxType)mText + : (cxType)false; + + default: break; } + + return cText2SkinRender::GetTokenData(Token); } // --- cText2SkinDisplayVolume ------------------------------------------------ -cText2SkinDisplayVolume::cText2SkinDisplayVolume(cText2SkinLoader *Loader) { - mRender = new cText2SkinRender(Loader, sectionVolume); - mDirty = false; +cText2SkinDisplayVolume::cText2SkinDisplayVolume(cText2SkinLoader *Loader): + cText2SkinRender(Loader, cxDisplay::volume), + mCurrent(0), + mTotal(0), + mMute(false) { } cText2SkinDisplayVolume::~cText2SkinDisplayVolume() { - delete mRender; } void cText2SkinDisplayVolume::SetVolume(int Current, int Total, bool Mute) { - mRender->Lock(); - if (mRender->mVolumeCurrent != Current || mRender->mVolumeTotal != Total || mRender->mVolumeMute != Mute) { - mRender->mVolumeCurrent = Current; - mRender->mVolumeTotal = Total; - mRender->mVolumeMute = Mute; - mDirty = true; + if (mCurrent != Current || mTotal != Total || mMute != Mute) { + mCurrent = Current; + mTotal = Total; + mMute = Mute; + SetDirty(); } - mRender->Unlock(); } void cText2SkinDisplayVolume::Flush(void) { - if (mDirty) { - mRender->Flush(); - mDirty = false; + cText2SkinRender::Flush(); +} + +cxType cText2SkinDisplayVolume::GetTokenData(const txToken &Token) { + switch (Token.Type) { + case tVolumeCurrent: + return mCurrent; + + case tVolumeTotal: + return mTotal; + + case tIsMute: + return mMute; + + default: break; } + + return cText2SkinRender::GetTokenData(Token); } // --- cText2SkinDisplayReplay ------------------------------------------------ -cText2SkinDisplayReplay::cText2SkinDisplayReplay(cText2SkinLoader *Loader, bool ModeOnly) { - Dprintf("ModeOnly: %d\n", ModeOnly); - mRender = new cText2SkinRender(Loader, ModeOnly ? sectionReplayMode : sectionReplay); - mDirty = false; +cText2SkinDisplayReplay::cText2SkinDisplayReplay(cText2SkinLoader *Loader, bool ModeOnly): + cText2SkinRender(Loader, ModeOnly ? cxDisplay::replaySmall : cxDisplay::replayInfo), + mTitle(""), + mStateInfo(false), + mPlay(false), + mForward(false), + mSpeed(0), + mCurrent(0), + mTotal(0), + mMarks(NULL), + mPrompt(""), + mType(mtStatus), + mText("") { } cText2SkinDisplayReplay::~cText2SkinDisplayReplay() { - delete mRender; } void cText2SkinDisplayReplay::SetTitle(const char *Title) { if (Title == NULL) Title = ""; - mRender->Lock(); - if (mRender->mReplayTitle != Title) { - mRender->mReplayTitle = Title; - mDirty = true; + if (mTitle != Title) { + mTitle = Title; + SetDirty(); } - mRender->Unlock(); } void cText2SkinDisplayReplay::SetMode(bool Play, bool Forward, int Speed) { - Dprintf("speed: Play = %s, Forward = %s, Speed = %d\n", Play ? "true" : "false", Forward ? "true" : "false", Speed); - mRender->Lock(); - if (mRender->mReplayInfo == false || mRender->mReplayPlay != Play || mRender->mReplayForward != Forward || mRender->mReplaySpeed != Speed) { - mRender->mReplayInfo = true; - mRender->mReplayPlay = Play; - mRender->mReplayForward = Forward; - mRender->mReplaySpeed = Speed; - mDirty = true; + if (!mStateInfo || mPlay != Play || mForward != Forward || mSpeed != Speed) { + mStateInfo = true; + mPlay = Play; + mForward = Forward; + mSpeed = Speed; + SetDirty(); } - mRender->Unlock(); } void cText2SkinDisplayReplay::SetProgress(int Current, int Total) { - mRender->Lock(); - if (mRender->mReplayCurrent != Current || mRender->mReplayTotal != Total) { - mRender->mReplayCurrent = Current; - mRender->mReplayTotal = Total; - mDirty = true; + Dprintf("SetProgress: %d %d\n", Current, Total); + if (mCurrent != Current || mTotal != Total) { + mCurrent = Current; + mTotal = Total; + // SetDirty(); TODO: let this cause a display update every frame? } - mRender->Unlock(); } void cText2SkinDisplayReplay::SetMarks(const cMarks *Marks) { - mRender->Lock(); - if (mRender->mReplayMarks != Marks) { - mRender->mReplayMarks = Marks; - mDirty = true; + if (mMarks != Marks) { + mMarks = Marks; + SetDirty(); } - mRender->Unlock(); } void cText2SkinDisplayReplay::SetCurrent(const char *Current) { if (Current == NULL) Current = ""; - mRender->Lock(); - if (mRender->mReplayCurrentText != Current) { - mRender->mReplayCurrentText = Current; - mDirty = true; - } - mRender->Unlock(); + if (mPosition != Current) { + mPosition = Current; + SetDirty(); + } } void cText2SkinDisplayReplay::SetTotal(const char *Total) { if (Total == NULL) Total = ""; - mRender->Lock(); - if (mRender->mReplayTotalText != Total) { - mRender->mReplayTotalText = Total; - mDirty = true; - } - mRender->Unlock(); + if (mDuration != Total) { + mDuration = Total; + SetDirty(); + } } void cText2SkinDisplayReplay::SetJump(const char *Jump) { if (Jump == NULL) Jump = ""; - mRender->Lock(); - if (mRender->mReplayJump != Jump) { - mRender->mReplayJump = Jump; - mDirty = true; + if (mPrompt != Jump) { + mPrompt = Jump; + SetDirty(); } - mRender->Unlock(); } void cText2SkinDisplayReplay::SetMessage(eMessageType Type, const char *Text) { if (Text == NULL) Text = ""; - mRender->Lock(); - if (mRender->mMessageType != Type || mRender->mMessageText != Text) { - mRender->mMessageType = Type; - mRender->mMessageText = Text; - mDirty = true; + if (mType != Type || mText != Text) { + mType = Type; + mText = Text; + SetDirty(); } - mRender->Unlock(); } void cText2SkinDisplayReplay::Flush(void) { - if (mDirty) { - mRender->Flush(); - mDirty = false; + cText2SkinRender::Flush(); +} + +cxType cText2SkinDisplayReplay::GetTokenData(const txToken &Token) { + switch (Token.Type) { + case tReplayTitle: + return mTitle; + + case tReplayPositionIndex: + return TimeType(mCurrent, Token.Attrib); + + case tReplayDurationIndex: + return TimeType(mTotal, Token.Attrib); + + case tReplayPosition: + return mPosition; + + case tReplayDuration: + return mDuration; + + case tReplayPrompt: + return mPrompt; + + case tIsPlaying: + return mStateInfo && (mSpeed == -1 && mPlay); + + case tIsPausing: + return mStateInfo && (mSpeed == -1 && !mPlay); + + case tIsFastForward: + if (mStateInfo && (mSpeed != -1 && mPlay && mForward)) { + return Token.Attrib.length() > 0 + ? (cxType)(mSpeed == atoi(Token.Attrib.c_str())) + : (cxType)true; + } + return false; + + case tIsFastRewind: + if (mStateInfo && (mSpeed != -1 && mPlay && !mForward)) { + return Token.Attrib.length() > 0 + ? (cxType)(mSpeed == atoi(Token.Attrib.c_str())) + : (cxType)true; + } + return false; + + case tIsSlowForward: + if (mStateInfo && (mSpeed != -1 && !mPlay && mForward)) { + return Token.Attrib.length() > 0 + ? (cxType)(mSpeed == atoi(Token.Attrib.c_str())) + : (cxType)true; + } + return false; + + case tIsSlowRewind: + if (mStateInfo && (mSpeed != -1 && !mPlay && !mForward)) { + return Token.Attrib.length() > 0 + ? (cxType)(mSpeed == atoi(Token.Attrib.c_str())) + : (cxType)true; + } + return false; + + case tMessage: + return mText; + + case tMessageInfo: + return mType == mtInfo + ? (cxType)mText + : (cxType)false; + + case tMessageWarning: + return mType == mtWarning + ? (cxType)mText + : (cxType)false; + + case tMessageStatus: + return mType == mtStatus + ? (cxType)mText + : (cxType)false; + + case tMessageError: + return mType == mtError + ? (cxType)mText + : (cxType)false; + + case tReplayMode: + return cText2SkinStatus::ReplayMode(); + + default: break; } + + return cText2SkinRender::GetTokenData(Token); } // --- cText2SkinDisplayMessage ----------------------------------------------- -cText2SkinDisplayMessage::cText2SkinDisplayMessage(cText2SkinLoader *Loader) { - mRender = new cText2SkinRender(Loader, sectionMessage); - mDirty = false; +cText2SkinDisplayMessage::cText2SkinDisplayMessage(cText2SkinLoader *Loader): + cText2SkinRender(Loader, cxDisplay::message), + mText("") { } cText2SkinDisplayMessage::~cText2SkinDisplayMessage() { - delete mRender; } void cText2SkinDisplayMessage::SetMessage(eMessageType Type, const char *Text) { if (Text == NULL) Text = ""; - mRender->Lock(); - if (mRender->mMessageType != Type || mRender->mMessageText != Text) { - mRender->mMessageType = Type; - mRender->mMessageText = Text; - mDirty = true; + if (mType != Type || mText != Text) { + mType = Type; + mText = Text; + SetDirty(); } - mRender->Unlock(); } void cText2SkinDisplayMessage::Flush(void) { - if (mDirty) { - mRender->Flush(); - mDirty = false; + cText2SkinRender::Flush(); +} + +cxType cText2SkinDisplayMessage::GetTokenData(const txToken &Token) { + switch (Token.Type) { + case tMessage: + return mText; + + case tMessageInfo: + return mType == mtInfo + ? (cxType)mText + : (cxType)false; + + case tMessageWarning: + return mType == mtWarning + ? (cxType)mText + : (cxType)false; + + case tMessageStatus: + return mType == mtStatus + ? (cxType)mText + : (cxType)false; + + case tMessageError: + return mType == mtError + ? (cxType)mText + : (cxType)false; + + default: break; } + + return cText2SkinRender::GetTokenData(Token); } // --- cText2SkinDisplayMenu -------------------------------------------------- -cText2SkinDisplayMenu::cText2SkinDisplayMenu(cText2SkinLoader *Loader) { - mRender = new cText2SkinRender(Loader, sectionMenu); - mDirty = false; - mMaxItems = 0; +cText2SkinDisplayMenu::cText2SkinDisplayMenu(cText2SkinLoader *Loader): + cText2SkinRender(Loader, cxDisplay::menu), + mMaxItems(0), + mTitle(""), + mButtonRed(""), + mButtonGreen(""), + mButtonYellow(""), + mButtonBlue(""), + mMessageType(mtStatus), + mMessageText(""), + mEvent(NULL), + mItems(), + mCurrentItem((uint)-1) +{ + cxDisplay *disp = Loader->Data()->Get(cxDisplay::menu); + const cxObject *area = NULL; + for (uint i = 0; i < disp->Objects(); ++i) { + const cxObject *o = disp->GetObject(i); + if (disp->GetObject(i)->Type() == cxObject::list) { + area = o; + break; + } + } - cText2SkinItem *area = Loader->Data()->Get(sectionMenu, itemMenuArea); - cText2SkinItem *item = Loader->Data()->Get(sectionMenu, itemMenuItem); - if (area && item) - mMaxItems = area->Size().h / item->Size().h; - else - esyslog("ERROR: text2skin: Skin is missing the items MenuArea and/or MenuItem"); + if (area != NULL) { + const cxObject *item = area->GetObject(0); + if (item != NULL && item->Type() == cxObject::item) + mMaxItems = area->Size().h / item->Size().h; + } } cText2SkinDisplayMenu::~cText2SkinDisplayMenu() { - delete mRender; } void cText2SkinDisplayMenu::Clear(void) { - mRender->Lock(); - mRender->mMenuItems.clear(); - mRender->mMenuTitle = ""; - mRender->mMenuCurrent = -1; - mRender->mMenuRed = ""; - mRender->mMenuGreen = ""; - mRender->mMenuYellow = ""; - mRender->mMenuBlue = ""; - mRender->mMenuEvent = NULL; - mRender->mMenuRecording = NULL; - mRender->mMenuText = ""; Dprintf("Clear\n"); - //mRender->mMessageText = ""; - DELETENULL(mRender->mScroller); - mRender->Unlock(); - mDirty = true; + mItems.clear(); + mEvent = NULL; + mRecording = NULL; + mText = ""; + SetDirty(); } void cText2SkinDisplayMenu::SetTitle(const char *Title) { if (Title == NULL) Title = ""; - mRender->Lock(); - if (mRender->mMenuTitle != Title) { - mRender->mMenuTitle = Title; - mDirty = true; + if (mTitle != Title) { + mTitle = Title; + SetDirty(); } - mRender->Unlock(); } void cText2SkinDisplayMenu::SetButtons(const char *Red, const char *Green, const char *Yellow, const char *Blue) { @@ -273,33 +556,32 @@ void cText2SkinDisplayMenu::SetButtons(const char *Red, const char *Green, const if (Green == NULL) Green = ""; if (Yellow == NULL) Yellow = ""; if (Blue == NULL) Blue = ""; - mRender->Lock(); - if (mRender->mMenuRed != Red || mRender->mMenuGreen != Green || mRender->mMenuYellow != Yellow || mRender->mMenuBlue != Blue) { - mRender->mMenuRed = Red; - mRender->mMenuGreen = Green; - mRender->mMenuYellow = Yellow; - mRender->mMenuBlue = Blue; - mDirty = true; + if (mButtonRed != Red || mButtonGreen != Green || mButtonYellow != Yellow || mButtonBlue != Blue) { + mButtonRed = Red; + mButtonGreen = Green; + mButtonYellow = Yellow; + mButtonBlue = Blue; + SetDirty(); } - mRender->Unlock(); } void cText2SkinDisplayMenu::SetMessage(eMessageType Type, const char *Text) { - Dprintf("SetMessage %s\n", Text); if (Text == NULL) Text = ""; - mRender->Lock(); - if (mRender->mMessageType != Type || mRender->mMessageText != Text) { - mRender->mMessageType = Type; - mRender->mMessageText = Text; - mDirty = true; + if (mMessageType != Type || mMessageText != Text) { + mMessageType = Type; + mMessageText = Text; + SetDirty(); } - mRender->Unlock(); } void cText2SkinDisplayMenu::SetItem(const char *Text, int Index, bool Current, bool Selectable) { - cText2SkinRender::MenuItem item; + if (Text == NULL) + return; + + tListItem item; item.text = Text; item.sel = Selectable; + for (int i = 0; i < MaxTabs; ++i) { const char *tab = GetTabbedText(Text, i); if (tab) @@ -307,78 +589,202 @@ void cText2SkinDisplayMenu::SetItem(const char *Text, int Index, bool Current, b if (!Tab(i + 1)) break; } - mRender->Lock(); - SetEditableWidth(mRender->GetEditableWidth(item, Current)); - if ((int)mRender->mMenuItems.size() <= Index) { - mRender->mMenuItems.push_back(item); - mDirty = true; - } else if (mRender->mMenuItems[Index] != item) { - mRender->mMenuItems[Index] = item; - mDirty = true; + + if (mItems.size() <= (uint)Index) { + mItems.push_back(item); + SetDirty(); } - if (Current && mRender->mMenuCurrent != Index) { - mRender->mMenuCurrent = Index; - mDirty = true; + else if (mItems[Index] != item) { + mItems[Index] = item; + SetDirty(); + } + + if (Current && mCurrentItem != Index) { + mCurrentItem = Index; + SetDirty(); } - mRender->Unlock(); } void cText2SkinDisplayMenu::SetEvent(const cEvent *Event) { - mRender->Lock(); - if (mRender->mMenuEvent != Event) { - mRender->mMenuEvent = Event; - mDirty = true; + if (mEvent != Event) { + mEvent = Event; + if (mEvent != NULL) + SetDirty(); } - mRender->Unlock(); } void cText2SkinDisplayMenu::SetRecording(const cRecording *Recording) { - mRender->Lock(); - if (mRender->mMenuRecording != Recording) { - mRender->mMenuRecording = Recording; - mDirty = true; + // yet unused + if (mRecording != Recording) { + mRecording = Recording; + if (mRecording != NULL) + SetDirty(); } - mRender->Unlock(); } -void cText2SkinDisplayMenu::SetText(const char *Text, bool FixedFont) { +void cText2SkinDisplayMenu::SetText(const char *Text, bool /*FixedFont*/) { if (Text == NULL) Text = ""; - mRender->Lock(); - if (mRender->mMenuText != Text || mRender->mMenuTextFixedFont != FixedFont) { - mRender->mMenuText = Text; - mRender->mMenuTextFixedFont = FixedFont; - mDirty = true; + if (mText != Text) { + mText = Text; + SetDirty(); } - mRender->Unlock(); } void cText2SkinDisplayMenu::SetTabs(int Tab1, int Tab2, int Tab3, int Tab4, int Tab5) { cSkinDisplayMenu::SetTabs(Tab1, Tab2, Tab3, Tab4, Tab5); - mRender->Lock(); - mRender->mMenuTabs[0] = Tab(0); - mRender->mMenuTabs[1] = Tab(1); - mRender->mMenuTabs[2] = Tab(2); - mRender->mMenuTabs[3] = Tab(3); - mRender->mMenuTabs[4] = Tab(4); - mRender->mMenuTabs[5] = Tab(5); - mRender->Unlock(); } void cText2SkinDisplayMenu::Scroll(bool Up, bool Page) { - mRender->Lock(); - if (mRender->mScroller && (Up ? mRender->mScroller->CanScrollUp() : mRender->mScroller->CanScrollDown())) { - mRender->mMenuScroll = true; - mRender->mMenuScrollUp = Up; - mRender->mMenuScrollPage = Page; - mDirty = true; - } - mRender->Unlock(); + cText2SkinRender::Scroll(Up, Page); + SetDirty(); } void cText2SkinDisplayMenu::Flush(void) { - if (mDirty) { - mRender->Flush(); - mDirty = false; + cText2SkinRender::Flush(); +} + +cxType cText2SkinDisplayMenu::GetTokenData(const txToken &Token) { + switch (Token.Type) { + case tMenuItem: + case tMenuGroup: + case tIsMenuItem: + case tIsMenuGroup: + case tIsMenuCurrent: + if (Token.Index < 0) return false; + case tMenuCurrent: + Dprintf("MenuCurrent: index %d\n", Token.Index); + if (Token.Index >= 0 && Token.Tab == -1) return false; + break; + + default: + if (Token.Tab >= 0) return false; + break; } -} + switch (Token.Type) { + case tMenuTitle: + return mTitle; + + case tMenuItem: + return mItems.size() > (uint)Token.Index && mItems[Token.Index].sel + && mCurrentItem != Token.Index + ? (cxType)mItems[Token.Index].tabs[Token.Tab] + : (cxType)false; + + case tIsMenuItem: + return mItems.size() > (uint)Token.Index && mItems[Token.Index].sel + && mCurrentItem != Token.Index; + + case tMenuCurrent: + if (Token.Index < 0) + return mItems[mCurrentItem].text; + + return mItems.size() > (uint)Token.Index && mItems[Token.Index].sel + && mCurrentItem == Token.Index + ? (cxType)mItems[Token.Index].tabs[Token.Tab] + : (cxType)false; + + case tIsMenuCurrent: + return mItems.size() > (uint)Token.Index && mItems[Token.Index].sel + && mCurrentItem == Token.Index; + + case tMenuGroup: + return mItems.size() > (uint)Token.Index && !mItems[Token.Index].sel + ? (cxType)mItems[Token.Index].tabs[Token.Tab] + : (cxType)false; + + case tIsMenuGroup: + return mItems.size() > (uint)Token.Index && !mItems[Token.Index].sel; + + case tButtonRed: + return mButtonRed; + + case tButtonGreen: + return mButtonGreen; + + case tButtonYellow: + return mButtonYellow; + + case tButtonBlue: + return mButtonBlue; + + case tMessage: + return mMessageText; + + case tMessageInfo: + return mMessageType == mtInfo + ? (cxType)mMessageText + : (cxType)false; + + case tMessageWarning: + return mMessageType == mtWarning + ? (cxType)mMessageText + : (cxType)false; + + case tMessageStatus: + return mMessageType == mtStatus + ? (cxType)mMessageText + : (cxType)false; + + case tMessageError: + return mMessageType == mtError + ? (cxType)mMessageText + : (cxType)false; + + case tPresentStartDateTime: + return mEvent != NULL + ? (cxType)TimeType(mEvent->StartTime(), Token.Attrib) + : (cxType)false; + + case tPresentVPSDateTime: + return mEvent != NULL + ? (cxType)TimeType(mEvent->Vps(), Token.Attrib) + : (cxType)false; + + case tPresentEndDateTime: + return mEvent != NULL + ? (cxType)TimeType(mEvent->EndTime(), Token.Attrib) + : (cxType)false; + + case tPresentProgress: + return mEvent != NULL + ? (cxType)TimeType(time(NULL) - mEvent->StartTime(), Token.Attrib) + : (cxType)false; + + case tPresentDuration: + return mEvent != NULL + ? (cxType)TimeType(mEvent->Duration(), Token.Attrib) + : (cxType)false; + + case tPresentTitle: + return mEvent != NULL + ? (cxType)mEvent->Title() + : (cxType)false; + + case tPresentShortText: + return mEvent != NULL + ? (cxType)mEvent->ShortText() + : (cxType)false; + + case tPresentDescription: + return mEvent != NULL + ? (cxType)mEvent->Description() + : (cxType)false; + + case tHasVPS: + return mEvent != NULL && mEvent->Vps() != 0; + + case tHasTimer: + return mEvent != NULL && mEvent->HasTimer(); + + case tIsRunning: + return mEvent != NULL && mEvent->IsRunning(); + + case tMenuText: + return mText; + + default: break; + } + + return cText2SkinRender::GetTokenData(Token); +} diff --git a/display.h b/display.h index aa3e23a..5e3df0b 100644 --- a/display.h +++ b/display.h @@ -1,23 +1,31 @@ /* - * $Id: display.h,v 1.6 2004/06/07 18:23:11 lordjaxom Exp $ + * $Id: display.h,v 1.4 2004/12/08 18:47:37 lordjaxom Exp $ */ #ifndef VDR_TEXT2SKIN_SKIN_H #define VDR_TEXT2SKIN_SKIN_H #include "common.h" +#include "render.h" +#include "xml/string.h" #include +#include class cText2SkinData; class cText2SkinI18n; -class cText2SkinRender; class cText2SkinLoader; -class cText2SkinDisplayChannel: public cSkinDisplayChannel { +class cText2SkinDisplayChannel: public cSkinDisplayChannel, public cText2SkinRender { private: - bool mWithInfo; - cText2SkinRender *mRender; - bool mDirty; + const cChannel *mChannel; + int mNumber; + const cEvent *mPresent; + const cEvent *mFollowing; + eMessageType mType; + std::string mText; + +protected: + virtual cxType GetTokenData(const txToken &Token); public: cText2SkinDisplayChannel(cText2SkinLoader *Loader, bool WithInfo); @@ -25,14 +33,18 @@ public: virtual void SetChannel(const cChannel *Channel, int Number); virtual void SetEvents(const cEvent *Present, const cEvent *Following); - virtual void SetMessage(eMessageType Type, const char *Text); + virtual void SetMessage(eMessageType Type, const char *Text); virtual void Flush(void); }; -class cText2SkinDisplayVolume: public cSkinDisplayVolume { +class cText2SkinDisplayVolume: public cSkinDisplayVolume, public cText2SkinRender { private: - cText2SkinRender *mRender; - bool mDirty; + int mCurrent; + int mTotal; + int mMute; + +protected: + virtual cxType GetTokenData(const txToken &Token); public: cText2SkinDisplayVolume(cText2SkinLoader *Loader); @@ -41,10 +53,26 @@ public: virtual void Flush(void); }; -class cText2SkinDisplayReplay: public cSkinDisplayReplay { +class cText2SkinDisplayReplay: public cSkinDisplayReplay, public cText2SkinRender { private: - cText2SkinRender *mRender; - bool mDirty; + std::string mTitle; + bool mStateInfo; + bool mPlay; + bool mForward; + int mSpeed; + int mCurrent; + int mTotal; + std::string mPosition; + std::string mDuration; + const cMarks *mMarks; + std::string mPrompt; + eMessageType mType; + std::string mText; + +protected: + virtual cxType GetTokenData(const txToken &Token); + virtual const cMarks *GetMarks(void) const { return mMarks; } + public: cText2SkinDisplayReplay(cText2SkinLoader *Loader, bool ModeOnly); virtual ~cText2SkinDisplayReplay(); @@ -55,14 +83,17 @@ public: virtual void SetCurrent(const char *Current); virtual void SetTotal(const char *Total); virtual void SetJump(const char *Jump); - virtual void SetMessage(eMessageType Type, const char *Text); + virtual void SetMessage(eMessageType Type, const char *Text); virtual void Flush(void); }; -class cText2SkinDisplayMessage: public cSkinDisplayMessage { +class cText2SkinDisplayMessage: public cSkinDisplayMessage, public cText2SkinRender { private: - cText2SkinRender *mRender; - bool mDirty; + eMessageType mType; + std::string mText; + +protected: + virtual cxType GetTokenData(const txToken &Token); public: cText2SkinDisplayMessage(cText2SkinLoader *Loader); @@ -71,18 +102,50 @@ public: virtual void Flush(void); }; -class cText2SkinDisplayMenu: public cSkinDisplayMenu { +class cText2SkinDisplayMenu: public cSkinDisplayMenu, public cText2SkinRender { private: - cText2SkinRender *mRender; - bool mDirty; int mMaxItems; + // common for all menus + std::string mTitle; + std::string mButtonRed; + std::string mButtonGreen; + std::string mButtonYellow; + std::string mButtonBlue; + eMessageType mMessageType; + std::string mMessageText; + + // detailed event view + const cEvent *mEvent; + // detailed recording + const cRecording *mRecording; + // long text + std::string mText; + + // list view + struct tListItem { + std::string text; + std::string tabs[MaxTabs]; + bool sel; + + bool operator!=(const tListItem &b) { return b.text != text || b.sel != sel; } + }; + + std::vector mItems; + int mCurrentItem; + +protected: + virtual cxType GetTokenData(const txToken &Token); + virtual int GetTab(int n) { return cSkinDisplayMenu::Tab(n); } + virtual bool HasTabText(int Index, int n); + virtual void SetEditableWidth(int Width) { printf("seteditablewidth: %d\n", Width); cSkinDisplayMenu::SetEditableWidth(Width); } + public: cText2SkinDisplayMenu(cText2SkinLoader *Loader); virtual ~cText2SkinDisplayMenu(); - virtual int MaxItems(void) { return mMaxItems; } - virtual void Clear(void); + virtual int MaxItems(void) { return mMaxItems; } + virtual void Clear(void); virtual void SetTitle(const char *Title); virtual void SetButtons(const char *Red, const char *Green, const char *Yellow, const char *Blue); virtual void SetMessage(eMessageType Type, const char *Text); @@ -95,4 +158,13 @@ public: virtual void Flush(void); }; +inline bool cText2SkinDisplayMenu::HasTabText(int Index, int n) +{ + if (Index < 0 || mItems.size () > (uint)Index) + return n == -1 + ? mItems[Index].text.length() > 0 + : mItems[Index].tabs[n].length() > 0; + return false; +} + #endif // VDR_TEXT2SKIN_SKIN_H diff --git a/file.c b/file.c index 083384d..4da0668 100644 --- a/file.c +++ b/file.c @@ -1,5 +1,5 @@ /* - * $Id: file.c,v 1.1 2004/06/02 20:43:05 lordjaxom Exp $ + * $Id: file.c,v 1.1.1.1 2004/11/19 16:45:31 lordjaxom Exp $ */ #include "file.h" @@ -12,7 +12,7 @@ cText2SkinFile::cText2SkinFile(const char *Skin) { cText2SkinFile::~cText2SkinFile() { } -bool cText2SkinFile::Load(const string &Filename) { +bool cText2SkinFile::Load(const std::string &Filename) { bool result = true; if (access(Filename.c_str(), F_OK) == 0) { isyslog("text2skin: loading %s", Filename.c_str()); diff --git a/file.h b/file.h index a941591..7f9a692 100644 --- a/file.h +++ b/file.h @@ -1,5 +1,5 @@ /* - * $Id: file.h,v 1.1 2004/06/02 20:43:05 lordjaxom Exp $ + * $Id: file.h,v 1.1.1.1 2004/11/19 16:45:31 lordjaxom Exp $ */ #ifndef VDR_TEXT2SKIN_FILE_H @@ -10,7 +10,7 @@ class cText2SkinFile { private: - string mSkin; + std::string mSkin; protected: virtual bool Parse(const char *Text) = 0; @@ -19,9 +19,9 @@ public: cText2SkinFile(const char *Skin); virtual ~cText2SkinFile(); - virtual bool Load(const string &Filename); + virtual bool Load(const std::string &Filename); - const string &Skin(void) const { return mSkin; } + const std::string &Skin(void) const { return mSkin; } }; #endif // VDR_TEXT2SKIN_FILE_H diff --git a/font.c b/font.c index d15bd8b..7320f8a 100644 --- a/font.c +++ b/font.c @@ -1,127 +1,43 @@ /* - * $Id: font.c,v 1.5 2004/05/30 21:48:21 austriancoder Exp $ + * $Id: font.c,v 1.5 2004/12/08 17:23:17 lordjaxom Exp $ */ #include "font.h" +#include "render.h" +#include -// ================================== -// constr. -cText2SkinFont::cText2SkinFont() -{ - m_library = 0; - m_face = 0; - - // init freetype2 lib - int error = FT_Init_FreeType(&m_library); - if (error) - { - esyslog("ERROR: Could not init freetype library\n"); - } -} +#ifdef HAVE_FREETYPE +cGraphtftFont cText2SkinFont::mFontCache; +#endif -// ================================== -// deconstr. -cText2SkinFont::~cText2SkinFont() +cText2SkinFont::cText2SkinFont(void) { - if (m_face) - { - FT_Done_Face(m_face); - } - - if (m_library) - { - FT_Done_FreeType(m_library); - } } -// ================================== -// try to load a font -bool cText2SkinFont::LoadFontFile(string Filename) -{ - int error = FT_New_Face(m_library, Filename.c_str(), 0, &m_face); - - // every thing ok? - if (error == FT_Err_Unknown_File_Format) - { - esyslog("ERROR: Font file (%s) could be opened and read, but it appears that its font format is unsupported\n", Filename.c_str()); - return false; - } - else if (error) - { - esyslog("ERROR: Font file (%s) could be opened or read, or simply it is broken\n", Filename.c_str()); - return false; - } - - // set slot - m_slot = m_face->glyph; - - return true; -} - -// ================================== -// sets size of font -void cText2SkinFont::SetFontSize(int size) +cText2SkinFont::~cText2SkinFont() { - FT_Set_Char_Size - ( - m_face, // handle to face object - 0, // char_width in 1/64th of points - size*64, // char_height in 1/64th of points - 300, // horizontal device resolution (dpi) - 300 // vertical device resolution (dpi) - ); } -// ================================== -// write some text :) -void cText2SkinFont::DrawTextTransparent(cOsd *Osd, int x, int y, const char *s, tColor ColorFg, int Width, int Height, int Alignment) +const cFont *cText2SkinFont::Load(const std::string &Path, const std::string &Filename, int Size) { - // where to get this infos? -// int w = Font->Width(s); -// int h = Font->Height(); - - int limit = 0; - if (Width || Height) - { - int cw = Width ? Width : w; - limit = x + cw; - if (Width) - { - if ((Alignment & taLeft) != 0) - ; - else if ((Alignment & taRight) != 0) - { - if (w < Width) - x += Width - w; - } - else - { - // taCentered - if (w < Width) - x += (Width - w) / 2; - } - } - - if (Height) - { - if ((Alignment & taTop) != 0) - ; - else if ((Alignment & taBottom) != 0) - { - if (h < Height) - y += Height - h; - } - else - { - // taCentered - if (h < Height) - y += (Height - h) / 2; - } - } - } - - // write text - while (s && *s) - { - } + if (Filename == "Osd") + return cFont::GetFont(fontOsd); + else if (Filename == "Fix") + return cFont::GetFont(fontFix); + else if (Filename == "Sml") + return cFont::GetFont(fontSml); + + const cFont *res = NULL; +#ifdef HAVE_FREETYPE + char *cachename; + asprintf(&cachename, "%s_%d", Filename.c_str(), Size); + if (mFontCache.Load(Path + "/" + Filename, cachename, Size)) + res = mFontCache.GetFont(cachename); + else + esyslog("ERROR: Text2Skin: Couldn't load font %s:%d", Filename.c_str(), Size); + free(cachename); +#else + esyslog("ERROR: Text2Skin: Font engine not enabled at compile time!"); +#endif + return res; } diff --git a/font.h b/font.h index dfc007f..160076c 100644 --- a/font.h +++ b/font.h @@ -1,39 +1,27 @@ /* - * $Id: font.h,v 1.4 2004/06/02 20:43:05 lordjaxom Exp $ + * $Id: font.h,v 1.5 2004/12/08 17:23:41 lordjaxom Exp $ */ -#ifndef VDR_TEXT2SKIN_FREETYPE_H -#define VDR_TEXT2SKIN_FREETYPE_H +#ifndef VDR_TEXT2SKIN_FONT_H +#define VDR_TEXT2SKIN_FONT_H #include "common.h" -#include "data.h" -#include -#include FT_FREETYPE_H +#ifdef HAVE_FREETYPE +# include "graphtft/font.h" +#endif +class cText2SkinFont { +private: +#ifdef HAVE_FREETYPE + static cGraphtftFont mFontCache; +#endif -// kannst noch einbauen, dass er die fonts "fontOsd" "fontSml" und "fontFix" aus VDR statt aus freetype nimmt + // disallow direct construction + cText2SkinFont(void); + virtual ~cText2SkinFont(); -// ================================== -/* cText2SkinFont - - Adds interface to FreeTpye font lib. -*/ -class cText2SkinFont -{ public: - cText2SkinFont(); - ~cText2SkinFont(); - - // font handling - bool LoadFontFile(string Filename); - void SetFontSize(int size); - void DrawTextTransparent(cOsd *Osd, int x, int y, const char *s, tColor ColorFg, int Width, int Height, int Alignment); - -private: - FT_Library m_library; - FT_Face m_face; - FT_GlyphSlot m_slot; - + static const cFont *Load(const std::string &Path, const std::string &Filename, int Size); }; -#endif /*VDR_TEXT2SKIN_FREETYPE_H*/ +#endif // VDR_TEXT2SKIN_FONT_H diff --git a/graphtft/font.c b/graphtft/font.c new file mode 100644 index 0000000..f4657c3 --- /dev/null +++ b/graphtft/font.c @@ -0,0 +1,173 @@ +/* + * $Id: font.c,v 1.2 2004/12/06 21:19:07 lordjaxom Exp $ + * + * Taken from GraphTFT + */ + +#include "font.h" + +cGraphtftFont::cGraphtftFont() +{ + _library = 0; + _face = 0; + + // init freetype2 lib + int error = FT_Init_FreeType(&_library); + if (error) + { + fprintf(stderr, "ERROR: Could not init freetyie library\n"); + } +} + +cGraphtftFont::~cGraphtftFont() +{ + Clear(); + + if (_face) + { + FT_Done_Face(_face); + } + + if (_library) + { + FT_Done_FreeType(_library); + } +} + +bool cGraphtftFont::Load(string Filename, string CacheName, int Size, int Width) +{ + if ( _cache.find(CacheName) != _cache.end() ) + return true; + + int error = FT_New_Face(_library, Filename.c_str(), 0, &_face); + + // every thing ok? + if (error == FT_Err_Unknown_File_Format) + { + fprintf(stderr, "ERROR: Font file (%s) could be opened and read, but it appears that its font format is unsupported\n", Filename.c_str()); + return false; + } + else if (error) + { + fprintf(stderr, "ERROR: Font file (%s) could be opened or read, or simply it is broken\n", Filename.c_str()); + return false; + } + + // set slot + _slot = _face->glyph; + + // set Size + FT_Set_Char_Size + ( + _face, // handle to face object + Width*64, // char_width in 1/64th of points + Size*64, // char_height in 1/64th of points + 0, // horizontal device resolution (dpi) + 0 // vertical device resolution (dpi) + ); + + /* load glyph image into the slot (erase previous one) */ + error = FT_Load_Char( _face, '_', FT_LOAD_RENDER ); + if ( error ) + return false; + + cFont::tPixelData value; + int num_rows_global = (_face->size->metrics.height / 64 )+1; + int num_rows = num_rows_global + 2; + + cFont::tPixelData * font_data = new cFont::tPixelData[225 * num_rows]; + + for (int i = 0; i < 225; i++) + for (int j = 0; j < num_rows; j++) + font_data[(i*num_rows)+j]=0x00; + + font_data[0+0]=_slot->bitmap.width+2; + font_data[0+1]=num_rows_global; + + // Time to put char 33..255 in font_data + FT_UInt glyph_index; + for ( int num_char = 33, num_char_array = 1; num_char < 256; num_char++, num_char_array++ ) + { + + //Get FT char index + glyph_index = FT_Get_Char_Index( _face, num_char ); + + //Load the char + error = FT_Load_Glyph( _face, glyph_index, FT_LOAD_DEFAULT ); + if ( error ) continue; /* ignore errors */ + + // convert to an mono bitmap + error = FT_Render_Glyph( _face->glyph, ft_render_mode_mono ); + if ( error ) continue; + + // now, convert to vdr font data + int width = ((_slot->bitmap.width+2) > (int)sizeof(cFont::tPixelData) * 8) ? (((int)sizeof(cFont::tPixelData) * 8) - 2) : _slot->bitmap.width; + int top = _slot->bitmap_top; + int y_off = Size - top; + + font_data[(num_char_array*num_rows)+0]=width+2; + font_data[(num_char_array*num_rows)+1]=num_rows_global; + + unsigned char *bmp = _slot->bitmap.buffer; + + for (int y = 0; y < _slot->bitmap.rows; ++y , y_off++) { + int pos = 0; + int bit = 0x80; + value = 0x00; + + for (int x = 0; x < _slot->bitmap.width; ++x) { + if (bmp[pos] & bit && x < width) + value = value | (cFont::tPixelData)1 << _slot->bitmap.width-x+1; + + bit >>= 1; + if (bit == 0) { + bit = 0x80; + ++pos; + } + } + bmp += _slot->bitmap.pitch; + font_data[(num_char_array*num_rows)+y_off+2] = value; + } + + } + // If all was ok, put the vdr font into the cache and return true + cFont* newFont = NULL; + newFont = new cFont(font_data); + if (newFont) { + _cache[CacheName] = newFont; + _del[CacheName] = font_data; + return true; + } + delete(font_data); + // Something went wrong! + return false; +} + +const cFont* cGraphtftFont::GetFont(string CacheName){ + if (CacheName == "Sml") return cFont::GetFont(fontSml); + else if (CacheName == "Fix") return cFont::GetFont(fontFix); + else if ( _cache.find(CacheName) != _cache.end() ){ + return _cache[CacheName]; + } + return cFont::GetFont(fontOsd); +} + +void cGraphtftFont::Clear(string CacheName) +{ + Clear(); +} + +void cGraphtftFont::Clear() +{ + cache_map::iterator it = _cache.begin(); + for (; it != _cache.end(); ++it) + delete((*it).second); + _cache.clear(); + + del_map::iterator del_it = _del.begin(); + for (; del_it != _del.end(); ++del_it) + delete((*del_it).second); + _del.clear(); +} + +cGraphtftFont GraphtftFont; diff --git a/graphtft/font.h b/graphtft/font.h new file mode 100644 index 0000000..5e23498 --- /dev/null +++ b/graphtft/font.h @@ -0,0 +1,48 @@ +/* + * $Id: font.h,v 1.2 2004/12/06 21:19:07 lordjaxom Exp $ + * + * Taken from GraphTFT + */ + +#ifndef VDR__GRAPHTFTFONT_H +#define VDR__GRAPHTFTFONT_H + +#include +#include +#include +#include +#include FT_FREETYPE_H +#include + +using std::map; +using std::string; +using std::vector; + + +class cGraphtftFont +{ +private: + typedef map cache_map; + typedef map del_map; + +public: + cGraphtftFont(); + ~cGraphtftFont(); + + bool Load(string Filename, string CacheName, int Size, int Width = 0); + const cFont* GetFont(string CacheName); + void Clear(string CacheName); + void Clear(); + +private: + FT_Library _library; + FT_Face _face; + FT_GlyphSlot _slot; + cache_map _cache; + del_map _del; + +}; + +extern cGraphtftFont GraphtftFont; + +#endif diff --git a/i18n.c b/i18n.c index efe6d1e..b5612ed 100644 --- a/i18n.c +++ b/i18n.c @@ -1,5 +1,5 @@ /* - * $Id: i18n.c,v 1.9 2004/06/22 16:48:03 lordjaxom Exp $ + * $Id: i18n.c,v 1.1.1.1 2004/11/19 16:45:31 lordjaxom Exp $ */ #include "i18n.h" @@ -85,7 +85,7 @@ const tI18nPhrase Phrases[] = { }; cText2SkinI18n::cText2SkinI18n(const char *Skin): cText2SkinFile(Skin) { - mIdentity = (string)"text2skin_" + Skin; + mIdentity = (std::string)"text2skin_" + Skin; mNumPhrases = 0; mPhrases = (tI18nPhrase*)malloc(sizeof(tI18nPhrase)); memset(mPhrases[mNumPhrases], 0, sizeof(tI18nPhrase)); @@ -112,7 +112,7 @@ bool cText2SkinI18n::Parse(const char *Text) { for (i = 0; i < I18nNumLanguages; ++i) { char *langs = strdup(I18nLanguageCode(i)); char *ptr = langs, *ep; - string text; + std::string text; p[i] = strdup(""); do { if ((ep = strchr(ptr, ',')) != NULL) @@ -139,7 +139,7 @@ bool cText2SkinI18n::Parse(const char *Text) { return result; } -bool cText2SkinI18n::Load(const string &Filename) { +bool cText2SkinI18n::Load(const std::string &Filename) { if (cText2SkinFile::Load(Filename)) { I18nRegister(mPhrases, mIdentity.c_str()); return true; diff --git a/i18n.h b/i18n.h index 11abc13..4156007 100644 --- a/i18n.h +++ b/i18n.h @@ -1,5 +1,5 @@ /* - * $Id: i18n.h,v 1.3 2004/06/22 16:48:03 lordjaxom Exp $ + * $Id: i18n.h,v 1.1.1.1 2004/11/19 16:45:31 lordjaxom Exp $ */ #ifndef VDR_TEXT2SKIN_I18N_H @@ -13,7 +13,7 @@ extern const tI18nPhrase Phrases[]; class cText2SkinI18n: public cText2SkinFile { private: - string mIdentity; + std::string mIdentity; tI18nPhrase *mPhrases; int mNumPhrases; @@ -24,8 +24,8 @@ public: cText2SkinI18n(const char *Skin); virtual ~cText2SkinI18n(); - virtual bool Load(const string &Filename); - string Translate(const string &Text) { return I18nTranslate(Text.c_str(), mIdentity.c_str()); } + virtual bool Load(const std::string &Filename); + std::string Translate(const std::string &Text) { return I18nTranslate(Text.c_str(), mIdentity.c_str()); } }; #endif // VDR_TEXT2SKIN_I18N_H diff --git a/loader.c b/loader.c index f74a6cc..c08c8f1 100644 --- a/loader.c +++ b/loader.c @@ -1,19 +1,20 @@ /* - * $Id: loader.c,v 1.12 2004/06/22 16:48:03 lordjaxom Exp $ + * $Id: loader.c,v 1.4 2004/12/08 17:13:25 lordjaxom Exp $ */ #include "loader.h" -#include "data.h" #include "i18n.h" #include "theme.h" #include "display.h" #include "text2skin.h" +#include "xml/parser.h" +#include "xml/skin.h" #include #include #include void cText2SkinLoader::Start(void) { - DIR *d = opendir(SkinPath()); + DIR *d = opendir(SkinPath().c_str()); if (d) { struct dirent *ent; while ((ent = readdir(d)) != NULL) { @@ -21,7 +22,7 @@ void cText2SkinLoader::Start(void) { struct stat buf; if (strcmp(ent->d_name, ".") == 0 || strcmp(ent->d_name, "..") == 0) continue; - asprintf(&path, "%s/%s", SkinPath(), ent->d_name); + asprintf(&path, "%s/%s", SkinPath().c_str(), ent->d_name); if (stat(path, &buf) == 0 && S_ISDIR(buf.st_mode)) Load(ent->d_name); free(path); @@ -32,7 +33,7 @@ void cText2SkinLoader::Start(void) { void cText2SkinLoader::Load(const char *Skin) { cText2SkinI18n *translations = NULL; - string transfile = (string)SkinPath() + "/" + Skin + "/" + Skin + ".trans"; + std::string transfile = (std::string)SkinPath() + "/" + Skin + "/" + Skin + ".trans"; if (access(transfile.c_str(), F_OK) == 0) { translations = new cText2SkinI18n(Skin); if (!translations->Load(transfile)) @@ -40,34 +41,33 @@ void cText2SkinLoader::Load(const char *Skin) { } cText2SkinTheme *theme = new cText2SkinTheme(Skin); - string themefile = (string)SkinPath() + "/" + Skin + "/" + Skin + ".colors"; + std::string themefile = SkinPath() + "/" + Skin + "/" + Skin + ".colors"; theme->Load(themefile); - string skinfile = (string)SkinPath() + "/" + Skin + "/" + Skin + ".skin"; + std::string skinfile = SkinPath() + "/" + Skin + "/" + Skin + ".skin"; if (access(skinfile.c_str(), F_OK) == 0) { - cText2SkinData *data = new cText2SkinData(Skin); - if (data->Load(skinfile)) { - cText2SkinItem *skin = data->Get(sectionSkin, itemSkin); - if (skin) { - if (skin->Version() == cText2SkinPlugin::ThemeVersion()) { - new cText2SkinLoader(data, translations, theme, Skin, skin->Name()); - return; - } else - esyslog("ERROR: text2skin: Skin is version %s, expecting %s", skin->Version().c_str(), cText2SkinPlugin::ThemeVersion()); + isyslog("parsing %s", skinfile.c_str()); + + cxSkin *skin = xmlParse(Skin, skinfile); + if (skin) { + if (skin->Version() == cText2SkinPlugin::SkinVersion()) { + new cText2SkinLoader(skin, translations, theme, Skin, skin->Title()); return; } else - esyslog("ERROR: text2skin: Item=Skin is missing in Skin"); - } - delete data; - } else - esyslog("ERROR: text2skin: %s/%s is not a valid skin directory", SkinPath(), Skin); + esyslog("ERROR: text2skin: Skin is version %s, expecting %s", skin->Version().c_str(), + cText2SkinPlugin::SkinVersion()); + } else + esyslog("ERROR: error in skin file"); + delete skin; + } } -cText2SkinLoader::cText2SkinLoader(cText2SkinData *Data, cText2SkinI18n *I18n, cText2SkinTheme *Theme, const string &Skin, const string &Description): cSkin(Skin.c_str(), Theme->Theme()) { +cText2SkinLoader::cText2SkinLoader(cxSkin *Data, cText2SkinI18n *I18n, cText2SkinTheme *Theme, const std::string &Skin, const std::string &Description): cSkin(Skin.c_str(), Theme->Theme()) { mData = Data; mI18n = I18n; mTheme = Theme; mDescription = Description; + } cText2SkinLoader::~cText2SkinLoader() { @@ -77,7 +77,6 @@ cText2SkinLoader::~cText2SkinLoader() { } cSkinDisplayChannel *cText2SkinLoader::DisplayChannel(bool WithInfo) { - Dprintf("WithInfo: %d\n", WithInfo); return new cText2SkinDisplayChannel(this, WithInfo); } diff --git a/loader.h b/loader.h index 5f22d7a..159f7fe 100644 --- a/loader.h +++ b/loader.h @@ -1,5 +1,5 @@ /* - * $Id: loader.h,v 1.5 2004/06/07 18:23:11 lordjaxom Exp $ + * $Id: loader.h,v 1.1.1.1 2004/11/19 16:45:31 lordjaxom Exp $ */ #ifndef VDR_TEXT2SKIN_LOADER_H @@ -8,33 +8,34 @@ #include "common.h" #include -class cText2SkinData; +class cxSkin; class cText2SkinI18n; class cText2SkinTheme; class cText2SkinLoader: public cSkin { private: - cText2SkinData *mData; + cxSkin *mData; cText2SkinI18n *mI18n; cText2SkinTheme *mTheme; - string mDescription; + std::string mDescription; public: static void Start(void); static void Load(const char *Skin); - cText2SkinLoader(cText2SkinData *Data, cText2SkinI18n *I18n, cText2SkinTheme *Theme, const string &Skin, const string &Description); + cText2SkinLoader(cxSkin *Data, cText2SkinI18n *I18n, cText2SkinTheme *Theme, + const std::string &Skin, const std::string &Description); ~cText2SkinLoader(); virtual const char *Description(void) { return mDescription.c_str(); } - virtual cSkinDisplayChannel *DisplayChannel(bool WithInfo); - virtual cSkinDisplayMenu *DisplayMenu(void); - virtual cSkinDisplayReplay *DisplayReplay(bool ModeOnly); - virtual cSkinDisplayVolume *DisplayVolume(void); - virtual cSkinDisplayMessage *DisplayMessage(void); - - cText2SkinData *Data(void) const { return mData; } - cText2SkinI18n *I18n(void) const { return mI18n; } + virtual cSkinDisplayChannel *DisplayChannel(bool WithInfo); + virtual cSkinDisplayMenu *DisplayMenu(void); + virtual cSkinDisplayReplay *DisplayReplay(bool ModeOnly); + virtual cSkinDisplayVolume *DisplayVolume(void); + virtual cSkinDisplayMessage *DisplayMessage(void); + + cxSkin *Data(void) const { return mData; } + cText2SkinI18n *I18n(void) const { return mI18n; } cText2SkinTheme *Theme(void) const { return mTheme; } }; diff --git a/menu.c b/menu.c new file mode 100644 index 0000000..167b9b9 --- /dev/null +++ b/menu.c @@ -0,0 +1,34 @@ +/* + * $Id: menu.c,v 1.1.1.1 2004/11/19 16:45:31 lordjaxom Exp $ + */ + +#include "menu.h" +#include "bitmap.h" + +// --- cText2SkinSetupPage ---------------------------------------------------- + +cText2SkinSetupPage::cText2SkinSetupPage(void) { + mData = Text2SkinSetup; + Add(new cOsdItem(tr("Flush image cache"), osUser1)); + Add(new cMenuEditIntItem(tr("Max. image cache size"), &mData.MaxCacheFill)); +} + +cText2SkinSetupPage::~cText2SkinSetupPage() { +} + +void cText2SkinSetupPage::Store(void) { + SetupStore("MaxCacheFill", mData.MaxCacheFill); + Text2SkinSetup = mData; +} + +eOSState cText2SkinSetupPage::ProcessKey(eKeys Key) { + eOSState state = cMenuSetupPage::ProcessKey(Key); + if (state == osUser1) { + Skins.Message(mtInfo, tr("Flushing image cache...")); + cText2SkinBitmap::FlushCache(); + Skins.Message(mtInfo, NULL); + return osContinue; + } + return state; +} + diff --git a/menu.h b/menu.h new file mode 100644 index 0000000..5b4ffa1 --- /dev/null +++ b/menu.h @@ -0,0 +1,24 @@ +/* + * $Id: menu.h,v 1.1.1.1 2004/11/19 16:45:31 lordjaxom Exp $ + */ + +#ifndef VDR_TEXT2SKIN_MENU_H +#define VDR_TEXT2SKIN_MENU_H + +#include "common.h" +#include "setup.h" +#include + +class cText2SkinSetupPage: public cMenuSetupPage { +private: + cText2SkinSetup mData; + +public: + cText2SkinSetupPage(void); + virtual ~cText2SkinSetupPage(); + + virtual void Store(void); + eOSState ProcessKey(eKeys Key); +}; + +#endif // VDR_TEXT2SKIN_MENU_H diff --git a/render.c b/render.c index 02b97a0..2e0fda5 100644 --- a/render.c +++ b/render.c @@ -1,5 +1,5 @@ /* - * $Id: render.c,v 1.39 2004/07/14 16:29:48 lordjaxom Exp $ + * $Id: render.c,v 1.6 2004/12/08 18:47:37 lordjaxom Exp $ */ #include "render.h" @@ -10,87 +10,57 @@ #include "status.h" #include "screen.h" #include "scroller.h" +#include "xml/display.h" #include #include #include cText2SkinRender *cText2SkinRender::mRender = NULL; -cText2SkinRender::cText2SkinRender(cText2SkinLoader *Loader, eSkinSection Section) { - tArea areas[MAXOSDAREAS]; - int numAreas = 0; - - SetDescription("Text2Skin: %s display update", SectionNames[Section].c_str()); - - mData = Loader->Data(); - mI18n = Loader->I18n(); - mTheme = Loader->Theme(); - mSection = Section; - mScreen = NULL; - mScroller = NULL; - mChannel = NULL; - mChannelNumber = 0; - mVolumeCurrent = -1; - mVolumeTotal = -1; - mVolumeMute = false; - mReplayInfo = false; - mReplayPlay = false; - mReplayForward = false; - mReplaySpeed = 0; - mReplayCurrent = 0; - mReplayTotal = 0; - mReplayMarks = NULL; - mMessageType = (eMessageType)-1; - mChannelPresent = NULL; - mChannelFollowing = NULL; - mMenuCurrent = 0; - mMenuEvent = NULL; - mMenuRecording = NULL; - mMenuTextFixedFont = false; - mMenuScroll = false; - mMenuScrollUp = false; - mMenuScrollPage = false; - mActive = false; - mUpdateIn = 0; - mBase = baseRelative; - - mRender = this; - - cText2SkinItem *item = mData->Get(sectionSkin, itemSkin); - switch (mBase = item->Base()) { - case baseRelative: - mScreen = new cText2SkinScreen(Setup.OSDLeft, Setup.OSDTop); - mBaseSize = SIZE(Setup.OSDWidth, Setup.OSDHeight); - break; - case baseAbsolute: - mScreen = new cText2SkinScreen(0, 0); - mBaseSize = SIZE(720, 576); //XXX - break; - default: - break; - } - - Dprintf("base: %d\n", item->Base()); +cText2SkinRender::cText2SkinRender(cText2SkinLoader *Loader, cxDisplay::eType Display, const std::string &BasePath, bool OffScreen): + mSkin(Loader->Data()), + mDisplay(mSkin->Get(Display)), + mI18n(Loader->I18n()), + mTheme(Loader->Theme()), + mScreen(NULL), + mScroller(NULL), + mBasePath(BasePath), + mDirty(true), + mActive(false), + mDoUpdate(), + mMutex(), + mStarted(), + mUpdateIn(0), + mBaseSize() +{ + mRender = this; + + SetDescription("Text2Skin: %s display update", mDisplay->GetType().c_str()); + + if (mBasePath.length() == 0) + mBasePath = SkinPath() + "/" + mSkin->Name(); + + if (mDisplay == NULL) + return; + + mScreen = new cText2SkinScreen(OffScreen); + mBaseSize = mSkin->BaseSize(); eOsdError res; - cText2SkinData::tIterator it = mData->First(mSection); - for (; it != mData->Last(mSection); ++it) { - if ((*it)->Item() == itemBackground) { - if (numAreas < MAXOSDAREAS) { - POINT p = (*it)->Pos(); - SIZE s = (*it)->Size(); - areas[numAreas].x1 = p.x; - areas[numAreas].y1 = p.y; - areas[numAreas].x2 = p.x + s.w - 1; - areas[numAreas].y2 = p.y + s.h - 1; - areas[numAreas].bpp = (*it)->Bpp(); - ++numAreas; - } else - esyslog("ERROR: text2skin: too many background areas\n"); - } - } - res = mScreen->SetAreas(areas, numAreas); - Dprintf("areas set, res = %d\n", res); + tArea areas[mDisplay->NumWindows()]; + for (int i = 0; i < mDisplay->NumWindows(); ++i) { + txPoint pos1 = Transform(mDisplay->Windows()[i].pos1); + txPoint pos2 = Transform(mDisplay->Windows()[i].pos2); + areas[i].x1 = mSkin->BaseOffset().x + pos1.x; + areas[i].y1 = mSkin->BaseOffset().y + pos1.y; + areas[i].x2 = mSkin->BaseOffset().x + pos2.x; + areas[i].y2 = mSkin->BaseOffset().y + pos2.y; + areas[i].bpp = mDisplay->Windows()[i].bpp; + Dprintf("setting area: %d, %d, %d, %d, %d\n", + areas[i].x1, areas[i].y1, areas[i].x2, areas[i].y2, + areas[i].bpp); + } + res = mScreen->SetAreas(areas, mDisplay->NumWindows()); if (res != oeOk) { const char *emsg = NULL; @@ -113,23 +83,25 @@ cText2SkinRender::cText2SkinRender(cText2SkinLoader *Loader, eSkinSection Sectio break; } esyslog("ERROR: text2skin: OSD provider can't handle skin: %s\n", emsg); + return; } - Lock(); - Start(); - mStarted.Wait(mMutex); - Unlock(); - // Make sure this constructor returns when the thread is running + if (!OffScreen) { + Lock(); + Start(); + mStarted.Wait(mMutex); + Unlock(); + } } cText2SkinRender::~cText2SkinRender() { if (mActive) { mActive = false; - Flush(); + Flush(true); Cancel(3); } delete mScroller; - delete mScreen; + delete mScreen; cText2SkinBitmap::ResetCache(); mRender = NULL; } @@ -137,13 +109,10 @@ cText2SkinRender::~cText2SkinRender() { void cText2SkinRender::Action(void) { mActive = true; Lock(); - mStarted.Broadcast(); // signal the constructor + mStarted.Broadcast(); while (mActive) { - Dprintf("mutex locked? %d\n", mMutex.locked); - int b = time_ms(); if (mUpdateIn) mDoUpdate.TimedWait(mMutex, mUpdateIn); else mDoUpdate.Wait(mMutex); - Dprintf("waited %d\n", time_ms() - b); if (!mActive) break; // fall out if thread to be stopped @@ -154,181 +123,163 @@ void cText2SkinRender::Action(void) { } void cText2SkinRender::Update(void) { - // Dbench(update); + Dbench(update); - cText2SkinData::tIterator it = mData->First(mSection); - for (; it != mData->Last(mSection); ++it) { - switch ((*it)->Display()) { - case displayAlways: - DisplayItem(*it); - break; - case displayDateTimeF: - case displayDateTime: - case displayDate: - case displayTime: - DisplayDateTime(*it); - break; - case displayChannelNumberName: - case displayChannelNumber: - case displayChannelName: - DisplayChannelNumberName(*it); - break; - case displayPresentDateTimeF: - case displayPresentStartTime: - case displayPresentDate: - case displayPresentVPSTime: - case displayPresentEndTime: - case displayPresentDuration: - DisplayPresentTime(*it); - break; - case displayPresentVPS: - case displayPresentRunning: - case displayPresentTimer: - DisplayPresentIcon(*it); - break; - case displayPresentTitle: - case displayPresentShortText: - case displayPresentDescription: - case displayPresentTextDescription: - DisplayPresentText(*it); - break; - case displayFollowingStartTime: - case displayFollowingEndTime: - case displayFollowingDuration: - DisplayFollowingTime(*it); - break; - case displayFollowingTitle: - DisplayFollowingTitle(*it); - break; - case displayFollowingShortText: - DisplayFollowingShortText(*it); - break; - case displayLanguage: - DisplayLanguage(*it); - break; - case displayTeletext: - case displayAudio: - case displayDolby: - case displayEncrypted: - case displayRecording: - case displayRadio: - DisplayChannelIcon(*it); - break; - case displayVolumeCurrent: - case displayVolumeTotal: - DisplayVolume(*it); - break; - case displayMute: - DisplayMuteIcon(*it); - break; - case displayReplayTime: - case displayReplayDuration: - DisplayReplayTime(*it); - break; - case displayReplayTitle: - DisplayReplayTitle(*it); - break; - case displayReplayPrompt: - DisplayReplayPrompt(*it); - break; - case displayPlay: - case displayPause: - case displayFastFwd: - case displayFastRew: - case displaySlowFwd: - case displaySlowRew: - DisplayReplaySymbol(*it); - break; - case displayReplayMode: - DisplayReplayMode(*it); - break; - case displayMessage: - case displayMessageStatus: - case displayMessageInfo: - case displayMessageWarning: - case displayMessageError: - DisplayMessage(*it); - break; - case displayMenuTitle: - DisplayMenuTitle(*it); - break; - case displayMenuRed: - case displayMenuGreen: - case displayMenuYellow: - case displayMenuBlue: - DisplayMenuButton(*it); - break; - case displayMenuText: - case displayMenuRecording: - DisplayMenuText(*it); - break; - case displayMenuScrollUp: - case displayMenuScrollDown: - DisplayMenuScrollIcon(*it); - break; - case displayMenuItems: - case displayMenuCurrent: - case displayMenuGroups: - DisplayMenuItems(*it); - break; - default: - break; - } - } - // Dbench(flush); + for (uint i = 0; i < mDisplay->Objects(); ++i) + DrawObject(mDisplay->GetObject(i)); + + Dbench(flush); mScreen->Flush(); - // Dprintf("flush only took %d ms\n", Ddiff(flush)); - // Dprintf("complete flush took %d ms\n", Ddiff(update)); + Dprintf("flush only took %ld ms\n", Ddiff(flush)); + Dprintf("complete flush took %ld ms\n", Ddiff(update)); } -void cText2SkinRender::DrawBackground(const POINT &Pos, const SIZE &Size, const tColor *Bg, const tColor *Fg, int Alpha, const string &Path) { - cText2SkinBitmap *bmp = NULL; - if (Path != "") { - char *p; - asprintf(&p, "%s/%s/%s", SkinPath(), mData->Skin().c_str(), Path.c_str()); - if ((bmp = cText2SkinBitmap::Load(p, Alpha)) != NULL) { - if (Bg) bmp->SetColor(0, *Bg); - if (Fg) bmp->SetColor(1, *Fg); +void cText2SkinRender::DrawObject(const cxObject *Object) +{ + if (Object->Condition() != NULL && !Object->Condition()->EvaluateToBool()) + return; + + switch (Object->Type()) { + case cxObject::image: + DrawImage(Object->Pos(), Object->Bg(), Object->Fg(), Object->Alpha(), Object->Path()); + break; + + case cxObject::text: + DrawText(Object->Pos(), Object->Size(), Object->Fg(), Object->Text(), Object->Font(), Object->Align()); + break; + + case cxObject::rectangle: + DrawRectangle(Object->Pos(), Object->Size(), Object->Fg()); + break; + + case cxObject::ellipse: + DrawEllipse(Object->Pos(), Object->Size(), Object->Fg(), Object->Arc()); + break; + + case cxObject::slope: + DrawSlope(Object->Pos(), Object->Size(), Object->Fg(), Object->Arc()); + break; + + case cxObject::progress: + DrawProgressbar(Object->Pos(), Object->Size(), Object->Current(), Object->Total(), Object->Bg(), Object->Fg(), Object->Active(), Object->Mark(), Object->Keep(), GetMarks()); + break; + + case cxObject::scrolltext: + DrawScrolltext(Object->Pos(), Object->Size(), Object->Fg(), Object->Text(), Object->Font(), Object->Align()); + break; + + case cxObject::scrollbar: + DrawScrollbar(Object->Pos(), Object->Size(), Object->Bg(), Object->Fg()); + + case cxObject::block: + for (uint i = 0; i < Object->Objects(); ++i) + DrawObject(Object->GetObject(i)); + break; + + case cxObject::list: { + const cxObject *item = Object->GetObject(0); + if (item && item->Type() == cxObject::item) { + txSize areasize = Object->Size(); + uint itemheight = item->Size().h; + uint maxitems = areasize.h / itemheight; + uint yoffset = 0; + + for (uint i = 0; i < maxitems; ++i, yoffset += itemheight) { + for (uint j = 0; j < Object->Objects(); ++j) { + const cxObject *o = Object->GetObject(j); + if (o->Type() == cxObject::item) + continue; + + for (int t = -1; t < cSkinDisplayMenu::MaxTabs; ++t) { + if (!HasTabText(i, t)) + continue; + + int thistab = GetTab(t); + int nexttab = GetTab(t + 1); + + cxObject obj(*o); + obj.SetIndex(i, t); + if (obj.Condition() != NULL && !obj.Condition()->EvaluateToBool()) + continue; + + obj.mPos1.x += Object->mPos1.x + (t >= 0 ? thistab : 0); + obj.mPos1.y += Object->mPos1.y + yoffset; + + // get end position + if (t >= 0 && nexttab > 0) { + // there is a "next tab".. see if it contains text + int n = t + 1; + while (n < cSkinDisplayMenu::MaxTabs && !HasTabText(i, n)) + ++n; + nexttab = GetTab(n); + } + + if (t >= 0 && nexttab > 0 && nexttab < obj.mPos2.x) + // there is a "next tab" with text + obj.mPos2.x = Object->mPos1.x + o->mPos1.x + nexttab; + else { + // there is no "next tab", use the rightmost edge + obj.mPos2.x += Object->mPos1.x; + SetEditableWidth(obj.Size().w); + } + + obj.mPos2.y += Object->mPos1.y + yoffset; + DrawObject(&obj); + } + } + } + } } - free(p); - } + break; - if (bmp) - mScreen->DrawBitmap(Pos.x, Pos.y, bmp->Get(mUpdateIn)); - else if (Bg) - mScreen->DrawRectangle(Pos.x, Pos.y, Pos.x + Size.w - 1, Pos.y + Size.h - 1, *Bg); + case cxObject::item: + // ignore + break; + + } } -void cText2SkinRender::DrawImage(const POINT &Pos, const SIZE &Size, const tColor *Bg, const tColor *Fg, int Alpha, const string &Path) { +void cText2SkinRender::DrawImage(const txPoint &Pos, const tColor *Bg, const tColor *Fg, int Alpha, + const std::string &Path) +{ cText2SkinBitmap *bmp; - char *p; - asprintf(&p, "%s/%s/%s", SkinPath(), mData->Skin().c_str(), Path.c_str()); - // Dprintf("Trying to load image: %s\n", p); - if ((bmp = cText2SkinBitmap::Load(p, Alpha)) != NULL) { + Dprintf("trying to draw image %s to %dx%d\n", ImagePath(Path).c_str(), Pos.x, Pos.y); + if ((bmp = cText2SkinBitmap::Load(ImagePath(Path), Alpha)) != NULL) { + Dprintf("success loading image\n"); if (Bg) bmp->SetColor(0, *Bg); if (Fg) bmp->SetColor(1, *Fg); mScreen->DrawBitmap(Pos.x, Pos.y, bmp->Get(mUpdateIn)); } - free(p); } -void cText2SkinRender::DrawText(const POINT &Pos, const SIZE &Size, const tColor *Fg, const string &Text, const cFont *Font, int Align) { +void cText2SkinRender::DrawText(const txPoint &Pos, const txSize &Size, const tColor *Fg, + const std::string &Text, const cFont *Font, int Align) +{ + Dprintf("trying to draw text %s to %d,%d size %d,%d, color %x\n", Text.c_str(), Pos.x, Pos.y, Size.w, Size.h, Fg ? *Fg : 0); mScreen->DrawText(Pos.x, Pos.y, Text.c_str(), Fg ? *Fg : 0, 0, Font, Size.w, Size.h, Align); } -void cText2SkinRender::DrawRectangle(const POINT &Pos, const SIZE &Size, const tColor *Fg) { +void cText2SkinRender::DrawRectangle(const txPoint &Pos, const txSize &Size, const tColor *Fg) +{ mScreen->DrawRectangle(Pos.x, Pos.y, Pos.x + Size.w - 1, Pos.y + Size.h - 1, Fg ? *Fg : 0); } -void cText2SkinRender::DrawEllipse(const POINT &Pos, const SIZE &Size, const tColor *Fg, int Arc) { +void cText2SkinRender::DrawEllipse(const txPoint &Pos, const txSize &Size, const tColor *Fg, + int Arc) +{ mScreen->DrawEllipse(Pos.x, Pos.y, Pos.x + Size.w - 1, Pos.y + Size.h - 1, Fg ? *Fg : 0, Arc); } -void cText2SkinRender::DrawSlope(const POINT &Pos, const SIZE &Size, const tColor *Fg, int Arc) { +void cText2SkinRender::DrawSlope(const txPoint &Pos, const txSize &Size, const tColor *Fg, int Arc) { mScreen->DrawSlope(Pos.x, Pos.y, Pos.x + Size.w - 1, Pos.y + Size.h - 1, Fg ? *Fg : 0, Arc); } -void cText2SkinRender::DrawProgressbar(const POINT &Pos, const SIZE &Size, int Current, int Total, const tColor *Bg, const tColor *Fg, const tColor *Selected, const tColor *Mark, const tColor *Cur, const cMarks *Marks) { +void cText2SkinRender::DrawProgressbar(const txPoint &Pos, const txSize &Size, int Current, + int Total, const tColor *Bg, const tColor *Fg, + const tColor *Selected, const tColor *Mark, + const tColor *Cur, const cMarks *Marks) +{ + Dprintf("trying to draw Progressbar, Current = %d, Total = %d\n", Current, Total); if (Bg) DrawRectangle(Pos, Size, Bg); if (Total == 0) @@ -336,30 +287,30 @@ void cText2SkinRender::DrawProgressbar(const POINT &Pos, const SIZE &Size, int C if (Current > Total) Current = Total; if (Size.w > Size.h) { - DrawRectangle(Pos, SIZE(Size.w * Current / Total, Size.h), Fg); + DrawRectangle(Pos, txSize(Size.w * Current / Total, Size.h), Fg); if (Marks) { bool start = true; for (const cMark *m = Marks->First(); m; m = Marks->Next(m)) { - POINT pt(Pos.x + m->position * Size.w / Total, Pos.y); + txPoint pt(Pos.x + m->position * Size.w / Total, Pos.y); if (Selected && start) { const cMark *m2 = Marks->Next(m); - DrawRectangle(POINT(pt.x, Pos.y + Size.h / 3), SIZE(((m2 ? m2->position : Total) - m->position) * Size.w / Total, Size.h / 3), Selected); + DrawRectangle(txPoint(pt.x, Pos.y + Size.h / 3), txSize(((m2 ? m2->position : Total) - m->position) * Size.w / Total, Size.h / 3), Selected); } DrawMark(pt, Size, start, m->position == Current, false, Mark, Cur); start = !start; } } } else { - DrawRectangle(Pos, SIZE(Size.w, Size.h * Current / Total), Fg); + DrawRectangle(Pos, txSize(Size.w, Size.h * Current / Total), Fg); if (Marks) { bool start = true; for (const cMark *m = Marks->First(); m; m = Marks->Next(m)) { - POINT pt(Pos.x, Pos.y + m->position * Size.h / Total); + txPoint pt(Pos.x, Pos.y + m->position * Size.h / Total); if (Selected && start) { const cMark *m2 = Marks->Next(m); - DrawRectangle(POINT(Pos.x + Size.w / 3, pt.y), SIZE(Size.w / 3, ((m2 ? m2->position : Total) - m->position) * Size.h / Total), Selected); + DrawRectangle(txPoint(Pos.x + Size.w / 3, pt.y), txSize(Size.w / 3, ((m2 ? m2->position : Total) - m->position) * Size.h / Total), Selected); } DrawMark(pt, Size, start, m->position == Current, true, Mark, Cur); start = !start; @@ -368,660 +319,138 @@ void cText2SkinRender::DrawProgressbar(const POINT &Pos, const SIZE &Size, int C } } -void cText2SkinRender::DrawMark(const POINT &Pos, const SIZE &Size, bool Start, bool Current, bool Horizontal, const tColor *Mark, const tColor *Cur) { - POINT p1 = Pos; +void cText2SkinRender::DrawMark(const txPoint &Pos, const txSize &Size, bool Start, bool Current, + bool Horizontal, const tColor *Mark, const tColor *Cur) +{ + txPoint p1 = Pos; if (Horizontal) { if (Mark) - DrawRectangle(p1, SIZE(Size.w, 1), Mark); + DrawRectangle(p1, txSize(Size.w, 1), Mark); const int d = Size.w / (Current ? 3 : 9); for (int i = 0; i < d; i++) { const tColor *col = Current ? Cur : Mark; int h = Start ? i : Size.w - 1 - i; if (col) - DrawRectangle(POINT(Pos.x + h, Pos.y - d + i), SIZE(1, (d - i) * 2), col); + DrawRectangle(txPoint(Pos.x + h, Pos.y - d + i), txSize(1, (d - i) * 2), col); } } else { if (Mark) - DrawRectangle(p1, SIZE(1, Size.h), Mark); + DrawRectangle(p1, txSize(1, Size.h), Mark); const int d = Size.h / (Current ? 3 : 9); for (int i = 0; i < d; i++) { const tColor *col = Current ? Cur : Mark; int h = Start ? i : Size.h - 1 - i; - if (col) - DrawRectangle(POINT(Pos.x - d + i, Pos.y + h), SIZE((d - i) * 2, 1), col); + if (col) + DrawRectangle(txPoint(Pos.x - d + i, Pos.y + h), txSize((d - i) * 2, 1), col); } } } -void cText2SkinRender::DrawScrolltext(const POINT &Pos, const SIZE &Size, const tColor *Fg, const string &Text, const cFont *Font, int Align) { +void cText2SkinRender::DrawScrolltext(const txPoint &Pos, const txSize &Size, const tColor *Fg, + const std::string &Text, const cFont *Font, int /*Align*/) +{ + Dprintf("trying to draw scrolltext %s\n", Text.c_str()); if (mScroller == NULL) mScroller = new cText2SkinScroller(mScreen, Pos.x, Pos.y, Size.w, Size.h, Text.c_str(), Font, Fg ? *Fg : 0, clrTransparent); - else if (mMenuScroll) { - mScroller->Scroll(mMenuScrollUp, mMenuScrollPage); - mMenuScroll = false; - } else + else mScroller->DrawText(); } -void cText2SkinRender::DrawScrollbar(const POINT &Pos, const SIZE &Size, int Offset, int Shown, int Total, const tColor *Bg, const tColor *Fg) { - DrawRectangle(Pos, Size, Bg); - if (Total == 0) - Total = 1; - if (Size.h > Size.w) { - POINT sp = Pos; - SIZE ss = Size; - sp.y += Size.h * Offset / Total; - ss.h = Size.h * Shown / Total + 1; - DrawRectangle(sp, ss, Fg); - } else { - POINT sp = Pos; - SIZE ss = Size; - sp.x += Size.w * Offset / Total; - ss.w = Size.w * Shown / Total + 1; - DrawRectangle(sp, ss, Fg); - } -} - -void cText2SkinRender::DisplayItem(cText2SkinItem *Item, const tItemData *Data) { - static tItemData dummyData; - if (Data == NULL) Data = &dummyData; - switch (Item->Item()) { - case itemBackground: - DrawBackground(Item->Pos(), Item->Size(), Item->Bg(), Item->Fg(), Item->Alpha(), Item->Path()); - break; - case itemText: - DrawText(Item->Pos(), Item->Size(), Item->Fg(), ItemText(Item, Data->text), Item->Font(), Item->Align()); - break; - case itemScrolltext: - DrawScrolltext(Item->Pos(), Item->Size(), Item->Fg(), Data->text, Item->Font(), Item->Align()); - break; - case itemImage: - DrawImage(Item->Pos(), Item->Size(), Item->Bg(), Item->Fg(), Item->Alpha(), Item->Path()); - break; - case itemLogo: - case itemSymbol: - if (Data->path != "") - DrawImage(Item->Pos(), Item->Size(), Item->Bg(), Item->Fg(), Item->Alpha(), Data->path); - break; - case itemRectangle: - DrawRectangle(Item->Pos(), Item->Size(), Item->Fg()); - break; - case itemEllipse: - DrawEllipse(Item->Pos(), Item->Size(), Item->Fg(), Item->Arc()); - break; - case itemSlope: - DrawSlope(Item->Pos(), Item->Size(), Item->Fg(), Item->Arc()); - break; - case itemProgress: - DrawProgressbar(Item->Pos(), Item->Size(), Data->current, Data->total, Item->Bg(), Item->Fg(), Item->Selected(), Item->Mark(), Item->Current(), Data->marks); - break; - case itemScrollbar: - DrawScrollbar(Item->Pos(), Item->Size(), Data->current, Data->shown, Data->total, Item->Bg(), Item->Fg()); - default: - break; - } -} - -void cText2SkinRender::DisplayDateTime(cText2SkinItem *Item) { - tItemData data; - char text[1000]; - time_t t = time(NULL); - struct tm tm_r, *tm; - *text = '\0'; - tm = localtime_r(&t, &tm_r); - - switch (Item->Display()) { - case displayDateTimeF: - strftime(text, 1000, Item->Format().c_str(), tm); - break; - case displayDateTime: - strftime(text, 1000, "%a %e.%m. %H:%M", tm); - break; - case displayDate: - strftime(text, 1000, "%e.%m.", tm); - break; - case displayTime: - strftime(text, 1000, "%H:%M", tm); - break; - default: - break; - } - - data.text = text; - DisplayItem(Item, &data); -} - -void cText2SkinRender::DisplayChannelNumberName(cText2SkinItem *Item) { - if (mChannel || mChannelNumber) { - tItemData data; - data.path = Item->Path() + "/" + ChannelName(mChannel, mChannelNumber) + "." + Item->Type(); - switch (Item->Display()) { - case displayChannelNumberName: - data.text = ChannelString(mChannel, mChannelNumber); - break; - case displayChannelNumber: - data.text = ChannelNumber(mChannel, mChannelNumber); - break; - case displayChannelName: - data.text = ChannelName(mChannel, mChannelNumber); - break; - default: - break; - } - DisplayItem(Item, &data); - } -} - -void cText2SkinRender::DisplayPresentTime(cText2SkinItem *Item) { - const cEvent *event = NULL; - switch (mSection) { - case sectionChannel: - case sectionChannelSmall: - event = mChannelPresent; - break; - case sectionMenu: - event = mMenuEvent; - break; - default: - break; - } - - if (event && event->StartTime()) { - tItemData data; - char text[1000]; - const char *f = "%H:%M"; - time_t t = 0, n = time(NULL); - struct tm tm_r, *tm; - *text = '\0'; - data.path = Item->Path(); - - switch (Item->Display()) { - case displayPresentDateTimeF: - f = Item->Format().c_str(); - t = event->StartTime(); - break; - case displayPresentStartTime: - t = event->StartTime(); - break; - case displayPresentDate: - f = "%e.%m."; - t = event->StartTime(); - break; - case displayPresentVPSTime: - t = event->StartTime() != event->Vps() ? event->Vps() : 0; - break; - case displayPresentEndTime: - t = event->EndTime(); - break; - case displayPresentDuration: - t = event->Duration(); - break; - default: - break; - } - - if (t) { - tm = localtime_r(&t, &tm_r); - strftime(text, 1000, f, tm); - data.text = text; - data.total = event->Duration(); - data.current = n - event->StartTime(); - DisplayItem(Item, &data); - } - } -} - -void cText2SkinRender::DisplayPresentIcon(cText2SkinItem *Item) { - const cEvent *event = NULL; - switch (mSection) { - case sectionChannel: - case sectionChannelSmall: - event = mChannelPresent; - break; - case sectionMenu: - event = mMenuEvent; - break; - default: - break; - } - - if (event) { - tItemData data; - switch (Item->Display()) { - case displayPresentVPS: - data.path = event->Vps() && event->Vps() != event->StartTime() ? Item->Path() : Item->AltPath(); - break; - case displayPresentRunning: - data.path = event->IsRunning() ? Item->Path() : Item->AltPath(); - break; - case displayPresentTimer: - data.path = event->HasTimer() ? Item->Path() : Item->AltPath(); - break; - default: - break; - } - if (data.path != "") - DisplayItem(Item, &data); - } -} - -void cText2SkinRender::DisplayPresentText(cText2SkinItem *Item) { - const cEvent *event = NULL; - switch (mSection) { - case sectionChannel: - case sectionChannelSmall: - event = mChannelPresent; - break; - case sectionMenu: - event = mMenuEvent; - break; - default: - break; - } - - if (event) { - string text; - switch (Item->Display()) { - case displayPresentTitle: - text = event->Title() ? event->Title() : ""; - break; - case displayPresentShortText: - text = event->ShortText() ? event->ShortText() : ""; - break; - case displayPresentDescription: - text = event->Description() ? event->Description() : ""; - break; - case displayPresentTextDescription: - if (event->ShortText()) - text += (string)event->ShortText() + "\n\n"; - if (event->Description()) - text += event->Description(); - default: - break; - } - - if (text != "") { - tItemData data; - data.text = text; - DisplayItem(Item, &data); - } - } -} - -void cText2SkinRender::DisplayFollowingTime(cText2SkinItem *Item) { - if (mChannelFollowing && mChannelFollowing->StartTime()) { - tItemData data; - char text[1000]; - time_t t = 0, n = time(NULL); - struct tm tm_r, *tm; - *text = '\0'; - - switch (Item->Display()) { - case displayFollowingStartTime: - t = mChannelFollowing->StartTime(); - break; - case displayFollowingEndTime: - t = mChannelFollowing->EndTime(); - break; - case displayFollowingDuration: - t = mChannelFollowing->Duration(); - break; - default: - break; +void cText2SkinRender::DrawScrollbar(const txPoint &Pos, const txSize &Size, const tColor *Bg, + const tColor *Fg) +{ + if (mScroller != NULL) { + int total = mScroller->Total(); + DrawRectangle(Pos, Size, Bg); + if (total == 0) + total = 1; + if (Size.h > Size.w) { + txPoint sp = Pos; + txSize ss = Size; + sp.y += Size.h * mScroller->Offset() / total; + ss.h = Size.h * mScroller->Shown() / total + 1; + DrawRectangle(sp, ss, Fg); + } else { + txPoint sp = Pos; + txSize ss = Size; + sp.x += Size.w * mScroller->Offset() / total; + ss.w = Size.w * mScroller->Shown() / total + 1; + DrawRectangle(sp, ss, Fg); } - - tm = localtime_r(&t, &tm_r); - strftime(text, 1000, "%H:%M", tm); - data.text = text; - data.total = mChannelFollowing->Duration(); - data.current = n - mChannelFollowing->StartTime(); - DisplayItem(Item, &data); } } -void cText2SkinRender::DisplayFollowingTitle(cText2SkinItem *Item) { - if (mChannelFollowing && mChannelFollowing->Title()) { - tItemData data; - data.text = mChannelFollowing->Title(); - DisplayItem(Item, &data); - } -} - -void cText2SkinRender::DisplayFollowingShortText(cText2SkinItem *Item) { - if (mChannelFollowing && mChannelFollowing->ShortText()) { - tItemData data; - data.text = mChannelFollowing->ShortText(); - DisplayItem(Item, &data); - } +txPoint cText2SkinRender::Transform(const txPoint &Pos) +{ + txSize base = mRender->mBaseSize; + return txPoint(Pos.x < 0 ? base.w + Pos.x : Pos.x, Pos.y < 0 ? base.h + Pos.y : Pos.y); } -void cText2SkinRender::DisplayLanguage(cText2SkinItem *Item) { - int current; - const char **tracks = cDevice::PrimaryDevice()->GetAudioTracks(¤t); - if (tracks) { - Dprintf("Languages: "); - int i; - for (i = 0; tracks[i] != NULL; ++i) - Dprintf("%s%s, ", tracks[i], i == current ? " (current)" : ""); - Dprintf("\n"); - - if (current < i) { - tItemData data; - data.text = tracks[current]; - data.path = Item->Path() + "/" + tracks[current] + "." + Item->Type(); - DisplayItem(Item, &data); - } - } +bool cText2SkinRender::ItemColor(const std::string &Color, tColor &Result) +{ + if (Color != "" && Color != "None") { + if (Color[0] == '#') + Result = strtoul(Color.c_str() + 1, NULL, 16); + else + Result = mRender->mTheme->Color(Color); + } else + return false; + return true; } -void cText2SkinRender::DisplayChannelIcon(cText2SkinItem *Item) { - if (mChannel && !mChannel->GroupSep()) { - tItemData data; - switch (Item->Display()) { - case displayTeletext: - data.path = mChannel->Tpid() ? Item->Path() : Item->AltPath(); - break; - case displayAudio: - data.path = mChannel->Apid2() ? Item->Path() : Item->AltPath(); - break; - case displayDolby: - data.path = mChannel->Dpid1() ? Item->Path() : Item->AltPath(); - break; - case displayEncrypted: - data.path = mChannel->Ca() ? Item->Path() : Item->AltPath(); - break; - case displayRadio: - data.path = mChannel->Vpid() == 0 || mChannel->Vpid() == 1 || mChannel->Vpid() == 0x1FFF ? Item->Path() : Item->AltPath(); - break; - case displayRecording: - data.path = cRecordControls::Active() ? Item->Path() : Item->AltPath(); - break; - default: - break; - } - if (data.path != "") - DisplayItem(Item, &data); - } +std::string cText2SkinRender::ImagePath(const std::string &Filename) +{ + if (mRender) + return mRender->mBasePath + "/" + Filename; + return ""; } -void cText2SkinRender::DisplayVolume(cText2SkinItem *Item) { - if (mVolumeTotal && mVolumeCurrent <= mVolumeTotal && !mVolumeMute) { - tItemData data; - char *text = NULL; - data.total = mVolumeTotal; - data.current = mVolumeCurrent; - switch (Item->Display()) { - case displayVolumeCurrent: - asprintf(&text, "%d", mVolumeCurrent); - break; - case displayVolumeTotal: - asprintf(&text, "%d", mVolumeTotal); - break; - default: - break; - } - if (text) { - data.text = text; - free(text); - } - DisplayItem(Item, &data); +/* TODO: translation when parsing +string cText2SkinRender::Translate(const string &Text) { + if (mRender != NULL) { + string result; + if (mRender->mI18n != NULL) + result = mRender->mI18n->Translate(Text); + else + result = Text; + return result; } + return Text; } +*/ -void cText2SkinRender::DisplayMuteIcon(cText2SkinItem *Item) { - tItemData data; - data.path = mVolumeMute ? Item->Path() : Item->AltPath(); - if (data.path != "") - DisplayItem(Item, &data); -} - -void cText2SkinRender::DisplayReplayTime(cText2SkinItem *Item) { - if (mReplayTotal && mReplayCurrent <= mReplayTotal) { - tItemData data; - data.total = mReplayTotal; - data.current = mReplayCurrent; - data.marks = mReplayMarks; - switch (Item->Display()) { - case displayReplayTime: - data.text = mReplayCurrentText; - break; - case displayReplayDuration: - data.text = mReplayTotalText; - break; - default: - break; - } - DisplayItem(Item, &data); - } -} +cxType cText2SkinRender::GetToken(const txToken &Token) +{ + if (mRender != NULL) { + cxType res = mRender->GetTokenData(Token); + if (Token.Attrib.length() > 0) { + if (Token.Attrib == "clean") { + std::string str = res.String(); + int pos = -1; -void cText2SkinRender::DisplayReplayTitle(cText2SkinItem *Item) { - if (mReplayTitle != "") { - tItemData data; - data.text = mReplayTitle; - DisplayItem(Item, &data); - } -} - -void cText2SkinRender::DisplayReplayPrompt(cText2SkinItem *Item) { - if (mReplayJump != "") { - tItemData data; - data.text = mReplayJump; - DisplayItem(Item, &data); - } -} - -void cText2SkinRender::DisplayReplaySymbol(cText2SkinItem *Item) { - if (mReplayInfo) { - tItemData data; - switch (Item->Display()) { - case displayPlay: - data.path = (mReplaySpeed == -1 && mReplayPlay) ? Item->Path() : Item->AltPath(); - break; - case displayPause: - data.path = (mReplaySpeed == -1 && !mReplayPlay) ? Item->Path() : Item->AltPath(); - break; - case displayFastFwd: - data.path = (mReplaySpeed != -1 && mReplayPlay && mReplayForward) ? Item->Path() : Item->AltPath(); - break; - case displayFastRew: - data.path = (mReplaySpeed != -1 && mReplayPlay && !mReplayForward) ? Item->Path() : Item->AltPath(); - break; - case displaySlowFwd: - data.path = (mReplaySpeed != -1 && !mReplayPlay && mReplayForward) ? Item->Path() : Item->AltPath(); - break; - case displaySlowRew: - data.path = (mReplaySpeed != -1 && !mReplayPlay && !mReplayForward) ? Item->Path() : Item->AltPath(); - break; - default: - break; - } - DisplayItem(Item, &data); - } -} - -void cText2SkinRender::DisplayReplayMode(cText2SkinItem *Item) { - if (cText2SkinStatus::ReplayMode() != replayNone) { - tItemData data; - Dprintf("Replay Type is %s\n", ReplayNames[cText2SkinStatus::ReplayMode()].c_str()); - data.path = Item->Path() + "/" + ReplayNames[cText2SkinStatus::ReplayMode()] + "." + Item->Type(); - DisplayItem(Item, &data); - } -} - -void cText2SkinRender::DisplayMessage(cText2SkinItem *Item) { - if (mMessageText != "" && (Item->Display() == displayMessage || (Item->Display() - displayMessageStatus) == mMessageType)) { - tItemData data; - data.text = mMessageText; - DisplayItem(Item, &data); - } -} - -void cText2SkinRender::DisplayMenuTitle(cText2SkinItem *Item) { - if (mMenuTitle != "") { - tItemData data; - data.text = mMenuTitle; - DisplayItem(Item, &data); - } -} - -void cText2SkinRender::DisplayMenuButton(cText2SkinItem *Item) { - tItemData data; - switch (Item->Display()) { - case displayMenuRed: - data.text = mMenuRed; - break; - case displayMenuGreen: - data.text = mMenuGreen; - break; - case displayMenuYellow: - data.text = mMenuYellow; - break; - case displayMenuBlue: - data.text = mMenuBlue; - break; - default: - break; - } - if (data.text != "") - DisplayItem(Item, &data); -} - -void cText2SkinRender::DisplayMenuText(cText2SkinItem *Item) { - tItemData data; - - switch (Item->Display()) { - case displayMenuText: - data.text = mMenuText; - break; - case displayMenuRecording: - if (mMenuRecording && mMenuRecording->Summary()) - data.text = mMenuRecording->Summary(); - break; - default: - break; - } - if (data.text != "") { - // HACK: make sure the scroller exists! - if (mScroller) { - data.current = mScroller->Offset(); - data.shown = mScroller->Shown(); - data.total = mScroller->Total(); - } - DisplayItem(Item, &data); - } -} - -void cText2SkinRender::DisplayMenuScrollIcon(cText2SkinItem *Item) { - if (mScroller) { - tItemData data; - switch (Item->Display()) { - case displayMenuScrollUp: - data.path = mScroller->CanScrollUp() ? Item->Path() : Item->AltPath(); - break; - case displayMenuScrollDown: - data.path = mScroller->CanScrollDown() ? Item->Path() : Item->AltPath(); - break; - default: - break; - } - if (data.path != "") - DisplayItem(Item, &data); - } -} - -void cText2SkinRender::DisplayMenuItems(cText2SkinItem *Item) { - cText2SkinItem *area = mData->Get(sectionMenu, itemMenuArea); - cText2SkinItem *item = mData->Get(sectionMenu, itemMenuItem); - - if (item && area) { - POINT pos = area->Pos1(); - - int max = area->Size().h / item->Size().h; - for (int i = 0; i < min((int)mMenuItems.size(), max); ++i) { - switch (Item->Display()) { - case displayMenuItems: - if (i == mMenuCurrent || !mMenuItems[i].sel) - continue; - break; - case displayMenuCurrent: - if (i != mMenuCurrent) - continue; - break; - case displayMenuGroups: - if (mMenuItems[i].sel) - continue; - break; - default: - break; - } - - POINT itempos = pos; - itempos.y += i * item->Size().h; - if (Item->Item() == itemText) { // draw tabs - for (int t = 0; t < cSkinDisplayMenu::MaxTabs; ++t) { - if (mMenuItems[i].tabs[t] != "") { - tItemData data; - cText2SkinItem cur = *Item; - cur.Pos1() = itempos; - cur.Pos1() += Item->Pos1(); - cur.Pos1().x += mMenuTabs[t]; - cur.Pos2() += itempos; - if (t + 1 < cSkinDisplayMenu::MaxTabs && mMenuItems[i].tabs[t + 1] != "") - cur.Pos2().x = itempos.x + mMenuTabs[t + 1]; - data.text = mMenuItems[i].tabs[t]; - // Dprintf("Menuitem: x = %d, w = %d, f = %08x\n", cur.Pos().x, cur.Pos2().x - cur.Pos1().x + 1, *ItemFg(&cur)); - DisplayItem(&cur, &data); - } - if (!mMenuTabs[t + 1]) - break; - } - } else { - tItemData data; - cText2SkinItem cur = *Item; - cur.Pos1() = itempos; - cur.Pos1() += Item->Pos1(); - cur.Pos2() += itempos; - DisplayItem(&cur, &data); + if (Token.Type == tMenuCurrent && (pos = str.rfind(' ')) != -1) + return str.substr(pos + 1); + else if (Token.Type == tMenuTitle && (pos = str.find(' ')) != -1) + return str.substr(0, pos); } } + return res; } + return false; } -string cText2SkinRender::ItemText(cText2SkinItem *Item) { - return mI18n ? mI18n->Translate(Item->Text()) : Item->Text(); -} +cxType cText2SkinRender::GetTokenData(const txToken &Token) +{ + switch (Token.Type) { + case tDateTime: return TimeType(time(NULL), Token.Attrib); + + case tCanScrollUp: return mScroller != NULL && mScroller->CanScrollUp(); -string cText2SkinRender::ItemText(cText2SkinItem *Item, const string &Content) { - if (Item->Text() != "") { - string s = mI18n ? mI18n->Translate(Item->Text()) : Item->Text(); - int pos; - while ((pos = s.find("{*}")) != -1) - s.replace(pos, 3, Content); - return s; + case tCanScrollDown: return mScroller != NULL && mScroller->CanScrollDown(); + + //default: return txToken::Token(Token); // return literal token + default: break; } - return Content; -} -int cText2SkinRender::GetEditableWidth(MenuItem Item, bool Current) { - cText2SkinItem *item; - item = mData->Get(sectionMenu, itemMenuItem); - return item->Size().w - mMenuTabs[1]; + return false; } - -POINT cText2SkinRender::Transform(const POINT &Pos) { - SIZE base = mRender->mBaseSize; - return POINT(Pos.x < 0 ? base.w + Pos.x : Pos.x, Pos.y < 0 ? base.h + Pos.y : Pos.y); -} - -bool cText2SkinRender::ItemColor(const string &Color, tColor &Result) { - if (Color != "" && Color != "None") { - if (Color[0] == '#') - Result = strtoul(Color.c_str() + 1, NULL, 16); - else - Result = mRender->mTheme->Color(Color); - } else - return false; - return true; -} - diff --git a/render.h b/render.h index 7057315..2cb7562 100644 --- a/render.h +++ b/render.h @@ -1,12 +1,14 @@ /* - * $Id: render.h,v 1.26 2004/07/13 13:52:51 lordjaxom Exp $ + * $Id: render.h,v 1.5 2004/12/08 18:47:37 lordjaxom Exp $ */ #ifndef VDR_TEXT2SKIN_RENDER_H #define VDR_TEXT2SKIN_RENDER_H #include "common.h" -#include "data.h" +#include "scroller.h" +#include "xml/skin.h" +#include "xml/type.h" #include #include #include @@ -14,10 +16,8 @@ class cChannel; class cEvent; class cText2SkinLoader; -class cText2SkinData; class cText2SkinI18n; class cText2SkinTheme; -class cText2SkinScroller; class cText2SkinScreen; class cText2SkinRender: public cThread { @@ -27,77 +27,31 @@ class cText2SkinRender: public cThread { friend class cText2SkinDisplayMessage; friend class cText2SkinDisplayMenu; + /* Skin Editor */ + friend class VSkinnerScreen; + private: static cText2SkinRender *mRender; - cText2SkinData *mData; + cxSkin *mSkin; + cxDisplay *mDisplay; cText2SkinI18n *mI18n; cText2SkinTheme *mTheme; - eSkinSection mSection; cText2SkinScreen *mScreen; cText2SkinScroller *mScroller; - // channel display - const cChannel *mChannel; - int mChannelNumber; - const cEvent *mChannelPresent; - const cEvent *mChannelFollowing; - - // volume display - int mVolumeCurrent; - int mVolumeTotal; - bool mVolumeMute; - - // replay display - string mReplayTitle; - bool mReplayInfo; - bool mReplayPlay; - bool mReplayForward; - int mReplaySpeed; - int mReplayCurrent; - int mReplayTotal; - const cMarks *mReplayMarks; - string mReplayCurrentText; - string mReplayTotalText; - string mReplayJump; - - // message display - eMessageType mMessageType; - string mMessageText; - - // menu - struct MenuItem { - string text; - string tabs[cSkinDisplayMenu::MaxTabs]; - bool sel; - bool operator!=(const MenuItem &b) { return b.text != text || b.sel != sel; } - }; - string mMenuTitle; - vector mMenuItems; - int mMenuCurrent; - string mMenuRed; - string mMenuGreen; - string mMenuYellow; - string mMenuBlue; - const cEvent *mMenuEvent; - const cRecording *mMenuRecording; - string mMenuText; - bool mMenuTextFixedFont; - bool mMenuScroll; - bool mMenuScrollUp; - bool mMenuScrollPage; - int mMenuTabs[cSkinDisplayMenu::MaxTabs]; + std::string mBasePath; + bool mDirty; // update thread - bool mActive; - cCondVar mDoUpdate; - cCondVar mStarted; - cMutex mMutex; - int mUpdateIn; + bool mActive; + cCondVar mDoUpdate; + cMutex mMutex; + cCondVar mStarted; + int mUpdateIn; // coordinate transformation - eBaseCoordinate mBase; - SIZE mBaseSize; + txSize mBaseSize; protected: // Update thread @@ -105,60 +59,67 @@ protected: void Unlock(void) { mMutex.Unlock(); } virtual void Action(void); - // Basic operations - void DrawBackground(const POINT &Pos, const SIZE &Size, const tColor *Bg, const tColor *Fg, int Alpha, const string &Path); - void DrawImage(const POINT &Pos, const SIZE &Size, const tColor *Bg, const tColor *Fg, int Alpha, const string &Path); - void DrawText(const POINT &Pos, const SIZE &Size, const tColor *Fg, const string &Text, const cFont *Font, int Align); - void DrawRectangle(const POINT &Pos, const SIZE &Size, const tColor *Fg); - void DrawEllipse(const POINT &Pos, const SIZE &Size, const tColor *Fg, int Arc); - void DrawSlope(const POINT &Pos, const SIZE &Size, const tColor *Fg, int Arc); - void DrawProgressbar(const POINT &Pos, const SIZE &Size, int Current, int Total, const tColor *Fg, const tColor *Bg, const tColor *Selected, const tColor *Mark, const tColor *Cur, const cMarks *Marks = NULL); - void DrawMark(const POINT &Pos, const SIZE &Size, bool Start, bool Current, bool Horizontal, const tColor *Mark, const tColor *Cur); - void DrawScrolltext(const POINT &Pos, const SIZE &Size, const tColor *Fg, const string &Text, const cFont *Font, int Align); - void DrawScrollbar(const POINT &Pos, const SIZE &Size, int Offset, int Shown, int Total, const tColor *Bg, const tColor *Fg); - - // displays a full item - void DisplayItem(cText2SkinItem *Item, const tItemData *Data = NULL); - - // High-level operations - void DisplayDateTime(cText2SkinItem *Item); - void DisplayChannelNumberName(cText2SkinItem *Item); - void DisplayPresentTime(cText2SkinItem *Item); - void DisplayPresentIcon(cText2SkinItem *Item); - void DisplayPresentText(cText2SkinItem *Item); - void DisplayFollowingTime(cText2SkinItem *Item); - void DisplayFollowingTitle(cText2SkinItem *Item); - void DisplayFollowingShortText(cText2SkinItem *Item); - void DisplayLanguage(cText2SkinItem *Item); - void DisplayChannelIcon(cText2SkinItem *Item); - void DisplayVolume(cText2SkinItem *Item); - void DisplayMuteIcon(cText2SkinItem *Item); - void DisplayReplayTime(cText2SkinItem *Item); - void DisplayReplayTitle(cText2SkinItem *Item); - void DisplayReplayPrompt(cText2SkinItem *Item); - void DisplayReplaySymbol(cText2SkinItem *Item); - void DisplayReplayMode(cText2SkinItem *Item); - void DisplayMessage(cText2SkinItem *Item); - void DisplayMenuTitle(cText2SkinItem *Item); - void DisplayMenuButton(cText2SkinItem *Item); - void DisplayMenuText(cText2SkinItem *Item); - void DisplayMenuScrollIcon(cText2SkinItem *Item); - void DisplayMenuItems(cText2SkinItem *Item); - - // Helpers - string ItemText(cText2SkinItem *Item); - string ItemText(cText2SkinItem *Item, const string &Content); - int GetEditableWidth(MenuItem Item, bool Current); + // Drawing operations + void DrawObject(const cxObject *Object); + void DrawBackground(const txPoint &Pos, const txSize &Size, const tColor *Bg, const tColor *Fg, + int Alpha, const std::string &Path); + void DrawImage(const txPoint &Pos, const tColor *Bg, const tColor *Fg, int Alpha, + const std::string &Path); + void DrawText(const txPoint &Pos, const txSize &Size, const tColor *Fg, + const std::string &Text, const cFont *Font, int Align); + void DrawRectangle(const txPoint &Pos, const txSize &Size, + const tColor *Fg); + void DrawEllipse(const txPoint &Pos, const txSize &Size, const tColor *Fg, + int Arc); + void DrawSlope(const txPoint &Pos, const txSize &Size, const tColor *Fg, + int Arc); + void DrawProgressbar(const txPoint &Pos, const txSize &Size, int Current, + int Total, const tColor *Fg, const tColor *Bg, + const tColor *Selected, const tColor *Mark, const tColor *Cur, + const cMarks *Marks = NULL); + void DrawMark(const txPoint &Pos, const txSize &Size, bool Start, + bool Current, bool Horizontal, const tColor *Mark, + const tColor *Cur); + void DrawScrolltext(const txPoint &Pos, const txSize &Size, + const tColor *Fg, const std::string &Text, const cFont *Font, int Align); + void DrawScrollbar(const txPoint &Pos, const txSize &Size, const tColor *Bg, const tColor *Fg); + + //int GetEditableWidth(MenuItem Item, bool Current); void Update(void); + // all renderers shall return appropriate data for the tokens + virtual cxType GetTokenData(const txToken &Token); + // the replay renderer shall return its marks here + virtual const cMarks *GetMarks(void) const { return NULL; } + // the menu renderer shall return its tab information here + virtual int GetTab(int n) { return 0; } + virtual bool HasTabText(int Index, int n) { return false; } + virtual void SetEditableWidth(int Width) {} + + // functions for display renderer to control behaviour + void Flush(bool Force = false); + void SetDirty(void) { mDirty = true; } + void Scroll(bool Up, bool Page) { if (mScroller) mScroller->Scroll(Up, Page); } + public: - cText2SkinRender(cText2SkinLoader *Loader, eSkinSection Section); + cText2SkinRender(cText2SkinLoader *Loader, cxDisplay::eType Section, const std::string &BasePath = "", + bool OffScreen = false); virtual ~cText2SkinRender(); - static POINT Transform(const POINT &Pos); - static bool ItemColor(const string &Color, tColor &Result); - - void Flush(void) { Lock(); mDoUpdate.Broadcast(); Unlock(); } + // functions for object classes to obtain dynamic item information + static txPoint Transform(const txPoint &Pos); + static bool ItemColor(const std::string &Color, tColor &Result); + static std::string ImagePath(const std::string &Filename); + static cxType GetToken(const txToken &Token); }; +inline void cText2SkinRender::Flush(bool Force) { + if (mDirty || Force) { + Lock(); + mDoUpdate.Broadcast(); + Unlock(); + mDirty = false; + } +} + #endif // VDR_TEXT2SKIN_RENDER_H diff --git a/screen.c b/screen.c index 3b85515..a45cb4a 100644 --- a/screen.c +++ b/screen.c @@ -1,66 +1,116 @@ /* - * $Id: screen.c,v 1.2 2004/07/13 13:52:51 lordjaxom Exp $ + * $Id: screen.c,v 1.2 2004/12/06 15:01:02 lordjaxom Exp $ */ #include "screen.h" -cText2SkinScreen::cText2SkinScreen(int x, int y) { - mOsd = cOsdProvider::NewOsd(x, y); - Dprintf("got osd -> %p\n", mOsd); +cText2SkinScreen::cText2SkinScreen(bool OffScreen) { + mOsd = NULL; + mScreen = NULL; + mOffScreen = OffScreen; + + if (mOffScreen) + mScreen = new cBitmap(720, 576, 8); + else + mOsd = cOsdProvider::NewOsd(0, 0); } cText2SkinScreen::~cText2SkinScreen() { + delete mScreen; delete mOsd; } eOsdError cText2SkinScreen::SetAreas(const tArea *Areas, int NumAreas) { - eOsdError result = mOsd->CanHandleAreas(Areas, NumAreas); - if (result == oeOk) { - mOsd->SetAreas(Areas, NumAreas); - mNumRegions = NumAreas; - for (int i = 0; i < mNumRegions; ++i) - mRegions[i] = new cBitmap(Areas[i].Width(), Areas[i].Height(), Areas[i].bpp, Areas[i].x1, Areas[i].y1); - Clear(); + if (!mOffScreen) { + eOsdError result = mOsd->CanHandleAreas(Areas, NumAreas); + if (result == oeOk) + mOsd->SetAreas(Areas, NumAreas); + else + return result; } - return result; + + mNumRegions = NumAreas; +#ifndef DIRECTBLIT + for (int i = 0; i < mNumRegions; ++i) + mRegions[i] = new cBitmap(Areas[i].Width(), Areas[i].Height(), Areas[i].bpp, Areas[i].x1, Areas[i].y1); +#endif + Clear(); + + return oeOk; } void cText2SkinScreen::Clear(void) { for (int i = 0; i < mNumRegions; ++i) { +#ifndef DIRECTBLIT mRegions[i]->Reset(); mRegions[i]->Clean(); mRegions[i]->DrawRectangle(mRegions[i]->X0(), mRegions[i]->Y0(), mRegions[i]->X0() + mRegions[i]->Width() - 1, mRegions[i]->Y0() + mRegions[i]->Height() - 1, clrTransparent); +#else + cBitmap *b = mOsd->GetBitmap(i); + if (b) { + b->Reset(); + b->Clean(); + b->DrawRectangle(b->X0(), b->Y0(), b->X0() + b->Width() - 1, b->Y0() + b->Height() - 1, clrTransparent); + } +#endif } } void cText2SkinScreen::DrawBitmap(int x, int y, const cBitmap &Bitmap, tColor ColorFg, tColor ColorBg) { +#ifndef DIRECTBLIT for (int i = 0; i < mNumRegions; ++i) mRegions[i]->DrawBitmap(x, y, Bitmap, ColorFg, ColorBg); +#else + mOsd->DrawBitmap(x, y, Bitmap, ColorFg, ColorBg); +#endif } void cText2SkinScreen::DrawRectangle(int x1, int y1, int x2, int y2, tColor Color) { +#ifndef DIRECTBLIT for (int i = 0; i < mNumRegions; ++i) mRegions[i]->DrawRectangle(x1, y1, x2, y2, Color); +#else + mOsd->DrawRectangle(x1, y1, x2, y2, Color); +#endif } void cText2SkinScreen::DrawText(int x, int y, const char *s, tColor ColorFg, tColor ColorBg, const cFont *Font, int Width, int Height, int Alignment) { +#ifndef DIRECTBLIT for (int i = 0; i < mNumRegions; ++i) mRegions[i]->DrawText(x, y, s, ColorFg, ColorBg, Font, Width, Height, Alignment); +#else + mOsd->DrawText(x, y, s, ColorFg, ColorBg, Font, Width, Height, Alignment); +#endif } void cText2SkinScreen::DrawEllipse(int x1, int y1, int x2, int y2, tColor Color, int Quadrants) { +#ifndef DIRECTBLIT for (int i = 0; i < mNumRegions; ++i) mRegions[i]->DrawEllipse(x1, y1, x2, y2, Color, Quadrants); +#else + mOsd->DrawEllipse(x1, y1, x2, y2, Color, Quadrants); +#endif } void cText2SkinScreen::DrawSlope(int x1, int y1, int x2, int y2, tColor Color, int Type) { +#ifndef DIRECTBLIT for (int i = 0; i < mNumRegions; ++i) mRegions[i]->DrawSlope(x1, y1, x2, y2, Color, Type); +#else + mOsd->DrawSlope(x1, y1, x2, y2, Color, Type); +#endif } void cText2SkinScreen::Flush(void) { - for (int i = 0; i < mNumRegions; ++i) - mOsd->DrawBitmap(mRegions[i]->X0(), mRegions[i]->Y0(), *mRegions[i]); - mOsd->Flush(); + for (int i = 0; i < mNumRegions; ++i) { + if (mOffScreen) + mScreen->DrawBitmap(mRegions[i]->X0(), mRegions[i]->Y0(), *mRegions[i]); +#ifndef DIRECTBLIT + else + mOsd->DrawBitmap(mRegions[i]->X0(), mRegions[i]->Y0(), *mRegions[i]); +#endif + } + if (!mOffScreen) + mOsd->Flush(); } diff --git a/screen.h b/screen.h index 71572a0..b397785 100644 --- a/screen.h +++ b/screen.h @@ -1,5 +1,5 @@ /* - * $Id: screen.h,v 1.2 2004/07/13 13:52:51 lordjaxom Exp $ + * $Id: screen.h,v 1.2 2004/12/06 15:01:02 lordjaxom Exp $ */ #ifndef VDR_TEXT2SKIN_SCREEN_H @@ -8,14 +8,21 @@ #include "common.h" #include +#undef DIRECTBLIT + class cText2SkinScreen { + /* Skin Editor */ + friend class VSkinnerScreen; + private: cOsd *mOsd; + cBitmap *mScreen; cBitmap *mRegions[MAXOSDAREAS]; + bool mOffScreen; int mNumRegions; public: - cText2SkinScreen(int x, int y); + cText2SkinScreen(bool OffScreen = false); ~cText2SkinScreen(); eOsdError SetAreas(const tArea *Areas, int NumAreas); diff --git a/scroller.c b/scroller.c index 465dcde..9a057cc 100644 --- a/scroller.c +++ b/scroller.c @@ -1,5 +1,5 @@ /* - * $Id: scroller.c,v 1.1 2004/07/05 17:55:34 lordjaxom Exp $ + * $Id: scroller.c,v 1.3 2004/12/08 17:13:26 lordjaxom Exp $ */ #include "scroller.h" @@ -56,14 +56,12 @@ void cText2SkinScroller::Scroll(bool Up, bool Page) mOffset -= Page ? mShown : 1; if (mOffset < 0) mOffset = 0; - DrawText(); } } else { if (CanScrollDown()) { mOffset += Page ? mShown : 1; if (mOffset + mShown > Total()) mOffset = Total() - mShown; - DrawText(); } } } diff --git a/scroller.h b/scroller.h index 9b338d9..dae6cf2 100644 --- a/scroller.h +++ b/scroller.h @@ -1,5 +1,5 @@ /* - * $Id: scroller.h,v 1.1 2004/07/05 17:55:34 lordjaxom Exp $ + * $Id: scroller.h,v 1.1.1.1 2004/11/19 16:45:31 lordjaxom Exp $ */ #ifndef VDR_TEXT2SKIN_SCROLLER_H diff --git a/setup.c b/setup.c index 3a96131..7a8a9e8 100644 --- a/setup.c +++ b/setup.c @@ -1,9 +1,8 @@ /* - * $Id: setup.c,v 1.4 2004/06/18 16:08:11 lordjaxom Exp $ + * $Id: setup.c,v 1.1.1.1 2004/11/19 16:45:31 lordjaxom Exp $ */ #include "setup.h" -#include "bitmap.h" cText2SkinSetup Text2SkinSetup; @@ -19,30 +18,3 @@ bool cText2SkinSetup::SetupParse(const char *Name, const char *Value) { return true; } -// --- cText2SkinSetupPage ---------------------------------------------------- - -cText2SkinSetupPage::cText2SkinSetupPage(void) { - mData = Text2SkinSetup; - Add(new cOsdItem(tr("Flush image cache"), osUser1)); - Add(new cMenuEditIntItem(tr("Max. image cache size"), &mData.MaxCacheFill)); -} - -cText2SkinSetupPage::~cText2SkinSetupPage() { -} - -void cText2SkinSetupPage::Store(void) { - SetupStore("MaxCacheFill", mData.MaxCacheFill); - Text2SkinSetup = mData; -} - -eOSState cText2SkinSetupPage::ProcessKey(eKeys Key) { - eOSState state = cMenuSetupPage::ProcessKey(Key); - if (state == osUser1) { - Skins.Message(mtInfo, tr("Flushing image cache...")); - cText2SkinBitmap::FlushCache(); - Skins.Message(mtInfo, NULL); - return osContinue; - } - return state; -} - diff --git a/setup.h b/setup.h index c726190..935873a 100644 --- a/setup.h +++ b/setup.h @@ -1,12 +1,11 @@ /* - * $Id: setup.h,v 1.3 2004/06/18 16:08:11 lordjaxom Exp $ + * $Id: setup.h,v 1.1.1.1 2004/11/19 16:45:31 lordjaxom Exp $ */ #ifndef VDR_TEXT2SKIN_SETUP_H #define VDR_TEXT2SKIN_SETUP_H #include "common.h" -#include class cText2SkinSetup { public: @@ -17,18 +16,6 @@ public: int MaxCacheFill; }; -class cText2SkinSetupPage: public cMenuSetupPage { -private: - cText2SkinSetup mData; - -public: - cText2SkinSetupPage(void); - virtual ~cText2SkinSetupPage(); - - virtual void Store(void); - eOSState ProcessKey(eKeys Key); -}; - extern cText2SkinSetup Text2SkinSetup; #endif // VDR_TEXT2SKIN_SETUP_H diff --git a/status.c b/status.c index fb2002d..7bbb749 100644 --- a/status.c +++ b/status.c @@ -1,16 +1,21 @@ /* - * $Id: status.c,v 1.2 2004/06/12 19:17:06 lordjaxom Exp $ + * $Id: status.c,v 1.3 2004/12/08 18:47:37 lordjaxom Exp $ */ #include "status.h" -cText2SkinStatus cText2SkinStatus::mStatus; +cText2SkinStatus *cText2SkinStatus::mStatus = NULL; +const std::string cText2SkinStatus::ReplayNames[__REPLAY_COUNT__] = + { "", "normal", "mp3", "mplayer", "dvd", "vcd", "image" }; + +cText2SkinStatus Text2SkinStatus; cText2SkinStatus::cText2SkinStatus(void) { + mStatus = this; mReplayMode = replayNone; } -void cText2SkinStatus::Replaying(const cControl *Control, const char *Name) { +void cText2SkinStatus::Replaying(const cControl* /*Control*/, const char *Name) { if (Name != NULL) { mReplayMode = replayNormal; if (strlen(Name) > 6 && Name[0]=='[' && Name[3]==']' && Name[5]=='(') { @@ -27,6 +32,8 @@ void cText2SkinStatus::Replaying(const cControl *Control, const char *Name) { mReplayMode = replayVCD; else if (access(Name, F_OK) == 0) mReplayMode = replayMPlayer; + else if (strncmp(Name, "[image]", 7) == 0) + mReplayMode = replayImage; else if (strlen(Name) > 7) { int i, n; for (i = 0, n = 0; Name[i]; ++i) { diff --git a/status.h b/status.h index a67e3e3..ccdbf85 100644 --- a/status.h +++ b/status.h @@ -1,5 +1,5 @@ /* - * $Id: status.h,v 1.2 2004/06/12 19:17:06 lordjaxom Exp $ + * $Id: status.h,v 1.2 2004/12/08 17:13:26 lordjaxom Exp $ */ #ifndef VDR_TEXT2SKIN_STATUS_H @@ -9,18 +9,36 @@ #include class cText2SkinStatus: public cStatus { +public: + enum eReplayMode { + replayNone, + replayNormal, + replayMP3, + replayMPlayer, + replayDVD, + replayVCD, + replayImage, + +#define __REPLAY_COUNT__ (replayImage+1) + }; + private: - static cText2SkinStatus mStatus; + static cText2SkinStatus *mStatus; + static const std::string ReplayNames[__REPLAY_COUNT__]; eReplayMode mReplayMode; protected: - cText2SkinStatus(void); - virtual void Replaying(const cControl *Control, const char *Name); public: - static eReplayMode ReplayMode(void) { return mStatus.mReplayMode; } + cText2SkinStatus(void); + + static const std::string &ReplayMode(void); }; +inline const std::string &cText2SkinStatus::ReplayMode(void) { + return ReplayNames[mStatus->mReplayMode]; +} + #endif // VDR_TEXT2SKIN_STATUS_H diff --git a/text2skin.c b/text2skin.c index f014c9e..f90c698 100644 --- a/text2skin.c +++ b/text2skin.c @@ -3,16 +3,17 @@ * * See the README file for copyright information and how to reach the author. * - * $Id: text2skin.c,v 1.25 2004/07/14 16:01:38 lordjaxom Exp $ + * $Id: text2skin.c,v 1.2 2004/12/08 17:13:26 lordjaxom Exp $ */ #include "text2skin.h" #include "setup.h" +#include "menu.h" #include "i18n.h" #include "loader.h" -const char *cText2SkinPlugin::VERSION = "0.0.8.1"; -const char *cText2SkinPlugin::THEMEVERSION = "0.0.3"; +const char *cText2SkinPlugin::VERSION = "1.0-pre1"; +const char *cText2SkinPlugin::SKINVERSION = "1.0"; const char *cText2SkinPlugin::DESCRIPTION = "Loader for text-based skins"; cText2SkinPlugin::cText2SkinPlugin(void) { @@ -24,7 +25,7 @@ cText2SkinPlugin::~cText2SkinPlugin() { bool cText2SkinPlugin::Start(void) { RegisterI18n(Phrases); cText2SkinLoader::Start(); - return true; + return true; } cMenuSetupPage *cText2SkinPlugin::SetupMenu(void) { diff --git a/text2skin.h b/text2skin.h index 8699c65..9391e5b 100644 --- a/text2skin.h +++ b/text2skin.h @@ -1,5 +1,5 @@ /* - * $Id: text2skin.h,v 1.4 2004/06/11 15:01:58 lordjaxom Exp $ + * $Id: text2skin.h,v 1.2 2004/12/08 17:13:26 lordjaxom Exp $ */ #ifndef VDR_TEXT2SKIN_H @@ -11,11 +11,11 @@ class cText2SkinPlugin : public cPlugin { private: static const char *VERSION; - static const char *THEMEVERSION; + static const char *SKINVERSION; static const char *DESCRIPTION; public: - static const char *ThemeVersion(void) { return THEMEVERSION; } + static const char *SkinVersion(void) { return SKINVERSION; } cText2SkinPlugin(void); virtual ~cText2SkinPlugin(); diff --git a/theme.c b/theme.c index 706a15d..376d468 100644 --- a/theme.c +++ b/theme.c @@ -1,5 +1,5 @@ /* - * $Id: theme.c,v 1.2 2004/06/16 18:46:50 lordjaxom Exp $ + * $Id: theme.c,v 1.1.1.1 2004/11/19 16:45:31 lordjaxom Exp $ */ #include "theme.h" #include @@ -16,7 +16,7 @@ bool cText2SkinTheme::Parse(const char *Text) { if (l) { if (strncmp(Text, "Item=Color,", 11) == 0) { Text += 11; - string name; + std::string name; tColor value; if (ParseVar(Text, "name", name) && ParseVar(Text, "default", &value)) { mMap[name] = mTheme.AddColor(name.c_str(), value); diff --git a/theme.h b/theme.h index 36ba3d1..0d6b167 100644 --- a/theme.h +++ b/theme.h @@ -1,5 +1,5 @@ /* - * $Id: theme.h,v 1.1 2004/06/02 20:43:05 lordjaxom Exp $ + * $Id: theme.h,v 1.1.1.1 2004/11/19 16:45:31 lordjaxom Exp $ */ #ifndef VDR_TEXT2SKIN_THEME_H @@ -7,12 +7,13 @@ #include "common.h" #include "file.h" +#include #include class cText2SkinTheme: public cText2SkinFile { private: - cTheme mTheme; - map mMap; + cTheme mTheme; + std::map mMap; protected: bool Parse(const char *Text); @@ -22,10 +23,10 @@ public: virtual ~cText2SkinTheme(); cTheme *Theme(void) { return &mTheme; } - tColor Color(const string &Name); + tColor Color(const std::string &Name); }; -inline tColor cText2SkinTheme::Color(const string &Name) { +inline tColor cText2SkinTheme::Color(const std::string &Name) { if (mMap.find(Name) != mMap.end()) return mTheme.Color(mMap[Name]); else diff --git a/xml/display.c b/xml/display.c new file mode 100644 index 0000000..4790b2d --- /dev/null +++ b/xml/display.c @@ -0,0 +1,42 @@ +/* + * $Id: display.c,v 1.3 2004/12/08 17:13:26 lordjaxom Exp $ + */ + +#include "xml/display.h" + +static const std::string DisplayNames[] = + { "channelInfo", "channelSmall", "volume", "message", "replayInfo", "replaySmall", "menu" }; + +cxDisplay::cxDisplay(cxSkin *parent): + mType((eType)__COUNT_DISPLAY__), + mNumWindows(0), + mSkin(parent) +{ +} + +bool cxDisplay::ParseType(const std::string &Text) +{ + for (int i = 0; i < (int)__COUNT_DISPLAY__; ++i) { + if (DisplayNames[i].length() > 0 && DisplayNames[i] == Text) { + mType = (eType)i; + return true; + } + } + return false; +} + +const std::string &cxDisplay::GetType(void) const +{ + return DisplayNames[mType]; +} + +cxDisplays::cxDisplays(void) +{ +} + +cxDisplays::~cxDisplays() +{ + iterator it = begin(); + while (it != end()) + (delete (*it).second, ++it); +} diff --git a/xml/display.h b/xml/display.h new file mode 100644 index 0000000..6c233b2 --- /dev/null +++ b/xml/display.h @@ -0,0 +1,58 @@ +/* + * $Id: display.h,v 1.3 2004/12/08 17:13:26 lordjaxom Exp $ + */ + +#ifndef VDR_TEXT2SKIN_DISPLAY_H +#define VDR_TEXT2SKIN_DISPLAY_H + +#include "xml/object.h" +#include +#include + +class cxSkin; + +class cxDisplay { + friend bool xStartElem(const std::string &name, std::map &attrs); + friend bool xEndElem(const std::string &name); + +public: + enum eType { + channelInfo, + channelSmall, + volume, + message, + replayInfo, + replaySmall, + menu, +#define __COUNT_DISPLAY__ (menu + 1) + }; + +private: + eType mType; + txWindow mWindows[MAXOSDAREAS]; + int mNumWindows; + cxObjects mObjects; + cxSkin *mSkin; + +public: + cxDisplay(cxSkin *parent); + + bool ParseType(const std::string &Text); + const std::string &GetType(void) const; + + eType Type(void) const { return mType; } + const txWindow *Windows(void) const { return mWindows; } + int NumWindows(void) const { return mNumWindows; } + cxSkin *Skin(void) const { return mSkin; } + + uint Objects(void) const { return mObjects.size(); } + const cxObject *GetObject(int n) const { return mObjects[n]; } +}; + +class cxDisplays: public std::map { +public: + cxDisplays(void); + ~cxDisplays(); +}; + +#endif // VDR_TEXT2SKIN_DISPLAY_H diff --git a/xml/function.c b/xml/function.c new file mode 100644 index 0000000..e6e321c --- /dev/null +++ b/xml/function.c @@ -0,0 +1,212 @@ +/* + * $Id: function.c,v 1.4 2004/12/08 18:47:37 lordjaxom Exp $ + */ + +#include "xml/function.h" +#include "render.h" +#include "common.h" +#include + +static const char *Internals[] = { + "not", "and", "or", "equal", "file", "trans", NULL +}; + +const std::string cxFunction::False = ""; +const std::string cxFunction::True = "1"; + +cxFunction::cxFunction(void): + mType(string), + mString(), + mNumber(0), + mNumParams(0) +{ +} + +cxFunction::cxFunction(const cxString &String): + mType(string), + mString(String), + mNumber(0), + mNumParams(0) +{ +} + +cxFunction::cxFunction(const cxFunction &Src): + mType(Src.mType), + mString(Src.mString), + mNumber(Src.mNumber), + mNumParams(Src.mNumParams) +{ + for (uint i = 0; i < mNumParams; ++i) + mParams[i] = new cxFunction(*Src.mParams[i]); +} + +cxFunction::~cxFunction() +{ + for (uint i = 0; i < mNumParams; ++i) + delete mParams[i]; +} + +bool cxFunction::Parse(const std::string &Text) +{ + const char *text = Text.c_str(); + const char *ptr = text, *last = text; + eType type = undefined_function; + int inExpr = 0; + cxFunction *expr; + + if (*ptr == '\'' || *ptr == '{') { + // must be string + if (strlen(ptr) < 2 + || (*ptr == '\'' && *(ptr + strlen(ptr) - 1) != '\'') + || (*ptr == '{' && *(ptr + strlen(ptr) - 1) != '}')) { + esyslog("ERROR: Unmatched string end\n"); + return false; + } + + std::string temp; + if (*ptr == '\'') + temp.assign(ptr + 1, strlen(ptr) - 2); + else + temp.assign(ptr); + + int pos = -1; + while ((pos = temp.find("\\'", pos + 1)) != -1) + temp.replace(pos, 1, "\'"); + + if (!mString.Parse(temp)) + return false; + + mType = string; + } + else { + // expression + for (; *ptr; ++ptr) { + if (*ptr == '(') { + if (inExpr++ == 0) { + int i; + for (i = 0; Internals[i] != NULL; ++i) { + if ((size_t)(ptr - last) == strlen(Internals[i]) + && memcmp(last, Internals[i], ptr - last) == 0){ + type = (eType)(INTERNAL + 1 + i); + break; + } + } + + if (Internals[i] == NULL) { + esyslog("ERROR: Unknown function %.*s", (int)(ptr - last), last); + return false; + } + last = ptr + 1; + } + } + else if (*ptr == ',' || *ptr == ')') { + if (inExpr == 0) { + esyslog("ERROR: Unmatched '%c' in expression", *ptr); + return false; + } + + if (inExpr == 1) { + expr = new cxFunction; + if (!expr->Parse(std::string(last, ptr - last))) { + delete expr; + return false; + } + + mType = type; + mParams[mNumParams++] = expr; + last = ptr + 1; + } + + if (*ptr == ')') { + if (inExpr == 1) { + int params = 0; + + switch (mType) { + case fun_and: + case fun_or: params = -1; break; + + case fun_eq: ++params; + case fun_not: + case fun_trans: + case fun_file: ++params; + default: break; + } + + if (params != -1 && mNumParams != (uint)params) { + esyslog("ERROR: Text2Skin: Wrong number of parameters to %s, " + "expecting %d", Internals[mType - 1 - INTERNAL], params); + return false; + } + } + + --inExpr; + } + } + } + + if (inExpr > 0) { + esyslog("ERROR: Expecting ')' in expression"); + return false; + } + } + + return true; +} + +const std::string &cxFunction::FunFile(const std::string &Param) const +{ + std::string path = cText2SkinRender::ImagePath(Param); + Dprintf("checking file(%s)\n", path.c_str()); + if (access(path.c_str(), F_OK) == 0) + return Param; + return False; +} + +std::string cxFunction::Evaluate(void) const +{ + switch (mType) { + case string: + return mString.Evaluate(); + + case fun_not: + return mParams[0]->EvaluateToBool() ? False : True; + + case fun_and: + for (uint i = 0; i < mNumParams; ++i) { + if (!mParams[i]->EvaluateToBool()) + return False; + } + return True; + + case fun_or: + for (uint i = 0; i < mNumParams; ++i) { + if (mParams[i]->EvaluateToBool()) + return True; + } + return False; + + case fun_eq: + return mParams[0]->Evaluate() == mParams[1]->Evaluate() ? True : False; + + case fun_file: + return FunFile(mParams[0]->Evaluate()); + + case fun_trans: + return tr(mParams[0]->Evaluate().c_str()); + + default: + Dprintf("unknown function code\n"); + esyslog("ERROR: Unknown function code called (this shouldn't happen)"); + break; + } + return False; +} + +bool cxFunction::EvaluateToBool(void) +{ + std::string result = Evaluate(); + if (result == False/* || result == "0"*/) + return false; + return true; +} + diff --git a/xml/function.h b/xml/function.h new file mode 100644 index 0000000..a7d8838 --- /dev/null +++ b/xml/function.h @@ -0,0 +1,66 @@ +/* + * $Id: function.h,v 1.4 2004/12/08 18:47:37 lordjaxom Exp $ + */ + +#ifndef VDR_TEXT2SKIN_XML_FUNCTION_H +#define VDR_TEXT2SKIN_XML_FUNCTION_H + +#include "xml/string.h" +#include + +#define STRING 0x01000000 +#define NUMBER 0x02000000 +#define INTERNAL 0x04000000 + +#define MAXPARAMETERS 16 + +class cxFunction { +public: + enum eType { + undefined_function, + + string = STRING, + number = NUMBER, + + fun_not = INTERNAL + 1, + fun_and = INTERNAL + 2, + fun_or = INTERNAL + 3, + fun_eq = INTERNAL + 4, + fun_file = INTERNAL + 5, + fun_trans = INTERNAL + 6 + }; + + static const std::string False; + static const std::string True; + +private: + eType mType; + cxString mString; + int mNumber; + cxFunction *mParams[MAXPARAMETERS]; + uint mNumParams; + +protected: + const std::string &FunFile(const std::string &Param) const; + +public: + cxFunction(void); + cxFunction(const cxString &String); + cxFunction(const cxFunction &Src); + ~cxFunction(); + + bool Parse(const std::string &Text); + std::string Evaluate(void) const; + bool EvaluateToBool(void); + + void SetIndex(uint Index, int Tab); +}; + +inline void cxFunction::SetIndex(uint Index, int Tab) +{ + mString.SetIndex(Index, Tab); + for (uint i = 0; i < mNumParams; ++i) + mParams[i]->SetIndex(Index, Tab); +} + +#endif // VDR_TEXT2SKIN_XML_FUNCTION_H diff --git a/xml/object.c b/xml/object.c new file mode 100644 index 0000000..6932106 --- /dev/null +++ b/xml/object.c @@ -0,0 +1,169 @@ +/* + * $Id: object.c,v 1.4 2004/12/08 17:13:26 lordjaxom Exp $ + */ + +#include "xml/object.h" +#include "render.h" +#include "font.h" + +static const std::string ObjectNames[] = + { "image", "text", "rectangle", "ellipse", "slope", "progress", "scrolltext", "scrollbar", + "block", "list", "item" }; + +cxObject::cxObject(cxDisplay *parent): + mType((eType)__COUNT_OBJECT__), + mPos1(0, 0), + mPos2(-1, -1), + mAlpha(255), + mArc(0), + mAlign(taDefault), + mCondition(NULL), + mFont(cFont::GetFont(fontOsd)), + mObjects(NULL), + mDisplay(parent), + mSkin(parent->Skin()) +{ +} + +cxObject::cxObject(const cxObject &Src): + mType(Src.mType), + mPos1(Src.mPos1), + mPos2(Src.mPos2), + mAlpha(Src.mAlpha), + mArc(Src.mArc), + mFg(Src.mFg), + mBg(Src.mBg), + mMark(Src.mMark), + mActive(Src.mActive), + mKeep(Src.mKeep), + mPath(Src.mPath), + mText(Src.mText), + mAlign(Src.mAlign), + mCondition(NULL), + mCurrent(Src.mCurrent), + mTotal(Src.mTotal), + mFont(Src.mFont), + mObjects(NULL), + mDisplay(Src.mDisplay), + mSkin(Src.mSkin) +{ + if (Src.mCondition) + mCondition = new cxFunction(*Src.mCondition); + if (Src.mObjects) + mObjects = new cxObjects(*Src.mObjects); +} + +cxObject::~cxObject() +{ + delete mCondition; + delete mObjects; +} + +bool cxObject::ParseType(const std::string &Text) { + for (int i = 0; i < (int)__COUNT_OBJECT__; ++i) { + if (ObjectNames[i] == Text) { + mType = (eType)i; + return true; + } + } + return false; +} + +bool cxObject::ParseCondition(const std::string &Text) { + cxFunction *result = new cxFunction; + if (result->Parse(Text)) { + delete mCondition; + mCondition = result; + return true; + } + return false; +} + +bool cxObject::ParseAlignment(const std::string &Text) { + if (Text == "center") mAlign = (eTextAlignment)(taTop | taCenter); + else if (Text == "right") mAlign = (eTextAlignment)(taTop | taRight); + else if (Text == "left") mAlign = (eTextAlignment)(taTop | taLeft); + else + return false; + return true; +} + +bool cxObject::ParseFontFace(const std::string &Text) { + /*for (int i = 0; i < eDvbFontSize; ++i) { + if (FontNames[i] == Text) { + mFont = cFont::GetFont((eDvbFont)i); + return true; + } + }*/ + + int size = 0, pos; + std::string face = Text; + if ((pos = face.find(':')) != -1) { + size = atoi(face.substr(pos + 1).c_str()); + face.erase(pos); + } + Dprintf("trying: %s %d\n", ((std::string)SkinPath() + "/fonts/" + face).c_str(), size); + if ((mFont = cText2SkinFont::Load(SkinPath() + "/fonts", face, size)) != NULL) + return true; + else if ((mFont = cText2SkinFont::Load(SkinPath() + "/" + mSkin->Name(), face, size)) != NULL) + return true; + return false; +} + +const std::string &cxObject::TypeName(void) const { + return ObjectNames[mType]; +} + +txPoint cxObject::Pos(void) const { + return txPoint(mSkin->BaseOffset().x + (mPos1.x < 0 ? Skin()->BaseSize().w + mPos1.x : mPos1.x), + mSkin->BaseOffset().y + (mPos1.y < 0 ? Skin()->BaseSize().h + mPos1.y : mPos1.y)); +} + +txSize cxObject::Size(void) const { + txPoint p1(mSkin->BaseOffset().x + (mPos1.x < 0 ? Skin()->BaseSize().w + mPos1.x : mPos1.x), + mSkin->BaseOffset().y + (mPos1.y < 0 ? Skin()->BaseSize().h + mPos1.y : mPos1.y)); + txPoint p2(mSkin->BaseOffset().x + (mPos2.x < 0 ? Skin()->BaseSize().w + mPos2.x : mPos2.x), + mSkin->BaseOffset().y + (mPos2.y < 0 ? Skin()->BaseSize().h + mPos2.y : mPos2.y)); + return txSize(p2.x - p1.x + 1, p2.y - p1.y + 1); +} + +const tColor *cxObject::Fg(void) const +{ + static tColor Fg; + return cText2SkinRender::ItemColor(mFg, Fg) ? &Fg : NULL; +} + +const tColor *cxObject::Bg(void) const +{ + static tColor Bg; + return cText2SkinRender::ItemColor(mBg, Bg) ? &Bg : NULL; +} + +const tColor *cxObject::Mark(void) const +{ + static tColor Mark; + return cText2SkinRender::ItemColor(mMark, Mark) ? &Mark : NULL; +} + +const tColor *cxObject::Active(void) const +{ + static tColor Active; + return cText2SkinRender::ItemColor(mActive, Active) ? &Active : NULL; +} + +const tColor *cxObject::Keep(void) const +{ + static tColor Keep; + return cText2SkinRender::ItemColor(mKeep, Keep) ? &Keep : NULL; +} + +cxObjects::cxObjects(void) +{ +} + +cxObjects::~cxObjects() +{ + for (uint i = 0; i < size(); ++i) + delete operator[](i); +} + diff --git a/xml/object.h b/xml/object.h new file mode 100644 index 0000000..8b134a9 --- /dev/null +++ b/xml/object.h @@ -0,0 +1,148 @@ +/* + * $Id: object.h,v 1.4 2004/12/08 17:13:26 lordjaxom Exp $ + */ + +#ifndef VDR_TEXT2SKIN_XML_OBJECT_H +#define VDR_TEXT2SKIN_XML_OBJECT_H + +#include "xml/string.h" +#include "xml/function.h" +#include +#include +#include +#include + +class cxDisplay; +class cxSkin; + +struct txPoint { + int x, y; + txPoint(int _x = 0, int _y = 0) { x = _x; y = _y; } +}; + +struct txSize { + int w, h; + txSize(int _w = 0, int _h = 0) { w = _w; h = _h; } +}; + +struct txWindow { + txPoint pos1; + txPoint pos2; + int bpp; + txWindow(int _x1 = 0, int _y1 = 0, int _x2 = -1, int _y2 = -1, int _bpp=4): + pos1(_x1, _y2), pos2(_x2, _y2), bpp(_bpp) {} +}; + +class cxObjects; + +class cxObject { + friend class cText2SkinRender; + friend bool xStartElem(const std::string &name, std::map &attrs); + friend bool xCharData(const std::string &text); + friend bool xEndElem(const std::string &name); + + /* Skin Editor */ + friend class VSkinnerItem; + +public: + enum eType { + image, + text, + rectangle, + ellipse, + slope, + progress, + scrolltext, + scrollbar, + block, + list, + item, +#define __COUNT_OBJECT__ (item + 1) + }; + +private: + eType mType; + txPoint mPos1; + txPoint mPos2; + int mAlpha; + int mArc; + std::string mFg; + std::string mBg; + std::string mMark; + std::string mActive; + std::string mKeep; + cxString mPath; + cxString mText; + eTextAlignment mAlign; + cxFunction *mCondition; + cxString mCurrent; + cxString mTotal; + const cFont *mFont; + cxObjects *mObjects; // used for block objects such as + cxDisplay *mDisplay; + cxSkin *mSkin; + +public: + cxObject(cxDisplay *parent); + cxObject(const cxObject &Src); + ~cxObject(); + + bool ParseType (const std::string &Text); + bool ParseCondition(const std::string &Text); + bool ParseAlignment(const std::string &Text); + bool ParseFontFace (const std::string &Text); + + void SetIndex(uint Index, int Tab); + + eType Type(void) const { return mType; } + cxFunction *Condition(void) const { return mCondition; } + int Alpha(void) const { return mAlpha; } + eTextAlignment Align(void) const { return mAlign; } + int Arc(void) const { return mArc; } + std::string Path(void) const { return mPath.Evaluate(); } + std::string Text(void) const { return mText.Evaluate(); } + int Current(void) const { return mCurrent.Evaluate(); } + int Total(void) const { return mTotal.Evaluate(); } + const cFont *Font(void) const { return mFont; } + cxDisplay *Display(void) const { return mDisplay; } + cxSkin *Skin(void) const { return mSkin; } + + const std::string &TypeName(void) const; + txPoint Pos(void) const; + txSize Size(void) const; + const tColor *Fg(void) const; + const tColor *Bg(void) const; + const tColor *Mark(void) const; + const tColor *Active(void) const; + const tColor *Keep(void) const; + + uint Objects(void) const; + const cxObject *GetObject(uint Index) const; +}; + +inline void cxObject::SetIndex(uint Index, int Tab) +{ + mText.SetIndex(Index, Tab); + mPath.SetIndex(Index, Tab); + if (mCondition != NULL) + mCondition->SetIndex(Index, Tab); +} + +class cxObjects: public std::vector { +public: + cxObjects(void); + ~cxObjects(); +}; + +// recursive dependancy +inline uint cxObject::Objects(void) const +{ + return mObjects ? mObjects->size() : 0; +} + +inline const cxObject *cxObject::GetObject(uint Index) const +{ + return mObjects ? (*mObjects)[Index] : NULL; +} + +#endif // VDR_TEXT2SKIN_XML_OBJECT_H diff --git a/xml/parser.c b/xml/parser.c new file mode 100644 index 0000000..1349769 --- /dev/null +++ b/xml/parser.c @@ -0,0 +1,310 @@ +/* + * $Id: parser.c,v 1.4 2004/12/08 17:13:26 lordjaxom Exp $ + */ + +#include "xml/parser.h" +#include "xml/xml.h" +#include "xml/skin.h" +#include "common.h" +#include +#include +#include +#include + +#define STR_SKIN "skin" +#define STR_DISPLAY "display" +#define STR_ID "id" +#define STR_WINDOW "window" +#define STR_X1 "x1" +#define STR_Y1 "y1" +#define STR_X "x" +#define STR_Y "y" +#define STR_X2 "x2" +#define STR_Y2 "y2" +#define STR_BPP "bpp" +#define STR_IMAGE "image" +#define STR_PATH "path" +#define STR_ALPHA "alpha" +#define STR_TEXT "text" +#define STR_CONDITION "condition" +#define STR_NOT "not" +#define STR_FILE "file" +#define STR_COLOR "color" +#define STR_ALIGN "align" +#define STR_RECTANGLE "rectangle" +#define STR_ELLIPSE "ellipse" +#define STR_SLOPE "slope" +#define STR_PROGRESS "progress" +#define STR_BGCOLOR "bgcolor" +#define STR_CURRENT "current" +#define STR_TOTAL "total" +#define STR_VERSION "version" +#define STR_NAME "name" +#define STR_SCREENBASE "screenBase" +#define STR_FONT "font" +#define STR_ARC "arc" + +#define MSG_BADTAG "ERROR: The tag %s was not expected in this context" +#define MSG_BADENDTAG "ERROR: The tag %s was not expected in this context" +#define MSG_BADATTR "ERROR: The attribute %s was not expected in tag %s" +#define MSG_MISSATTR "ERROR: The tag %s lacks the attribute %s" +#define MSG_BADVALUE "ERROR: %s is not allowed for attribute %s" +#define MSG_PARSERR "ERROR: Parser error in %s:%d: %s" +#define MSG_BADCDATA "ERROR: Bad character data" +#define MSG_NOFILE "ERROR: Couldn't read %s: %m" +#define MSG_MANYWINS "ERROR: Too many windows" + +#define TAG_ERR_REMAIN(_context) do { \ + esyslog("ERROR: Text2Skin: Unexpected tag %s within %s", \ + name.c_str(), _context); \ + return false; \ + } while (0) + +#define TAG_ERR_CHILD(_context) do { \ + esyslog("ERROR: Text2Skin: No child tag %s expected within %s", \ + name.c_str(), _context); \ + return false; \ + } while (0) + +#define TAG_ERR_END(_context) do { \ + esyslog("ERROR: Text2Skin: Unexpected closing tag for %s within %s", \ + name.c_str(), _context); \ + return false; \ + } while (0) + +#define ATTRIB_OPT_STRING(_attr,_target) \ + if (attrs.find(_attr) != attrs.end()) { \ + _target = attrs[_attr]; \ + attrs.erase(_attr); \ + } + +#define ATTRIB_MAN_STRING(_attr,_target) \ + ATTRIB_OPT_STRING(_attr,_target) \ + else { \ + esyslog("ERROR: Text2Skin: Mandatory attribute %s missing in tag %s", \ + _attr, name.c_str()); \ + return false; \ + } + +#define ATTRIB_OPT_NUMBER(_attr,_target) \ + if (attrs.find(_attr) != attrs.end()) { \ + char *_e; const char *_t = attrs[_attr].c_str(); \ + long _l = strtol(_t, &_e, 10); \ + if (_e ==_t || *_e != '\0') { \ + esyslog("ERROR: Text2Skin: Invalid numeric value \"%s\" in attribute %s", \ + _t, _attr); \ + return false; \ + } else \ + _target = _l; \ + attrs.erase(_attr); \ + } + +#define ATTRIB_MAN_NUMBER(_attr,_target) \ + ATTRIB_OPT_NUMBER(_attr,_target) \ + else { \ + esyslog("ERROR: Text2Skin: Mandatory attribute %s missing in tag %s", \ + _attr, name.c_str()); \ + return false; \ + } + +#define ATTRIB_OPT_FUNC(_attr,_func) \ + if (attrs.find(_attr) != attrs.end()) { \ + if (!_func(attrs[_attr])) { \ + esyslog("ERROR: Text2Skin: Unexpected value %s for attribute %s", \ + attrs[_attr].c_str(), _attr); \ + return false; \ + } \ + attrs.erase(_attr); \ + } + +#define ATTRIB_MAN_FUNC(_attr,_func) \ + ATTRIB_OPT_FUNC(_attr,_func) \ + else { \ + esyslog("ERROR: Text2Skin: Mandatory attribute %s missing in tag %s", \ + _attr, name.c_str()); \ + return false; \ + } + +static std::vector context; +static cxSkin *skin = NULL; +static cxDisplay *display = NULL; +static cxObject *parent = NULL; +static cxObject *object = NULL; + +bool xStartElem(const std::string &name, std::map &attrs) { + Dprintf("start element: %s\n", name.c_str()); + + if (context.size() == 0) { + if (name == "skin") { + ATTRIB_MAN_STRING("version", skin->mVersion); + ATTRIB_MAN_STRING("name", skin->mTitle); + ATTRIB_MAN_FUNC ("screenBase", skin->ParseBase); + } + else + TAG_ERR_REMAIN("document"); + } + else if (context[context.size() - 1] == "skin") { + if (name == "display") { + display = new cxDisplay(skin); + ATTRIB_MAN_FUNC ("id", display->ParseType); + } + else + TAG_ERR_REMAIN("skin"); + } + else if (context[context.size() - 1] == "display" + || context[context.size() - 1] == "list" + || context[context.size() - 1] == "block") { + if (object != NULL) { + parent = object; + object = NULL; + } + + if (name == "window") { + if (display->mNumWindows < MAXOSDAREAS) { + txWindow window; + ATTRIB_OPT_NUMBER("x1", window.pos1.x); + ATTRIB_OPT_NUMBER("y1", window.pos1.y); + ATTRIB_OPT_NUMBER("x2", window.pos2.x); + ATTRIB_OPT_NUMBER("y2", window.pos2.y); + ATTRIB_OPT_NUMBER("bpp", window.bpp); + display->mWindows[display->mNumWindows++] = window; + } else + esyslog("ERROR: Text2Skin: Too many windows in display"); + } + else { + object = new cxObject(display); + if (object->ParseType(name)) { + ATTRIB_OPT_NUMBER("x1", object->mPos1.x); + ATTRIB_OPT_NUMBER("y1", object->mPos1.y); + ATTRIB_OPT_NUMBER("x2", object->mPos2.x); + ATTRIB_OPT_NUMBER("y2", object->mPos2.y); + ATTRIB_OPT_FUNC ("condition", object->ParseCondition); + + if (name == "image") { + ATTRIB_OPT_NUMBER("x", object->mPos1.x); + ATTRIB_OPT_NUMBER("y", object->mPos1.y); + ATTRIB_OPT_NUMBER("alpha", object->mAlpha); + ATTRIB_OPT_STRING("color", object->mFg); + ATTRIB_OPT_STRING("bgColor", object->mBg); + ATTRIB_MAN_FUNC ("path", object->mPath.Parse); + } + else if (name == "text" + || name == "scrolltext") { + ATTRIB_OPT_STRING("color", object->mFg); + ATTRIB_OPT_FUNC ("align", object->ParseAlignment); + ATTRIB_OPT_FUNC ("font", object->ParseFontFace); + } + else if (name == "rectangle") { + ATTRIB_OPT_STRING("color", object->mFg); + } + else if (name == "ellipse" || name == "slope") { + ATTRIB_OPT_STRING("color", object->mFg); + ATTRIB_OPT_NUMBER("arc", object->mArc); + } + else if (name == "progress" + || name == "scrollbar") { + ATTRIB_OPT_STRING("color", object->mFg); + ATTRIB_OPT_STRING("bgColor", object->mBg); + ATTRIB_OPT_FUNC ("current", object->mCurrent.Parse); + ATTRIB_OPT_FUNC ("total", object->mTotal.Parse); + } + else if (name == "item") { + ATTRIB_MAN_NUMBER("height", object->mPos2.y); + --object->mPos2.y; + } + } else + TAG_ERR_REMAIN(context[context.size() - 1].c_str()); + } + } else + TAG_ERR_CHILD(context[context.size() - 1].c_str()); + context.push_back(name); + return true; +} + +bool xCharData(const std::string &text) { + int start = 0, end = text.length() - 1; + + Dprintf("char data before: %s\n", text.c_str()); + + while (text[start] == '\012' || text[start] == '\015' || text[start] == ' ' || text[start] == '\t') + ++start; + + while (text[end] == '\012' || text[end] == '\015' || text[end] == ' ' || text[end] == '\t') + --end; + + Dprintf("char data after: %s\n", text.substr(start, end - start + 1).c_str()); + + if (end - start + 1 > 0) { + Dprintf("context: %s\n", context[context.size() - 1].c_str()); + if (context[context.size() - 1] == "text" + || context[context.size() - 1] == "scrolltext") { + if (!object->mText.Parse(text.substr(start, end - start + 1))) + return false; + } else + esyslog(MSG_BADCDATA); + } + return true; +} + +bool xEndElem(const std::string &name) { + Dprintf("end element: %s\n", name.c_str()); + if (context[context.size() - 1] == name) { + if (name == "display") { + skin->mDisplays[display->Type()] = display; + display = NULL; + } + else if (object != NULL || parent != NULL) { + if (object == NULL) { + Dprintf("rotating parent to object\n"); + object = parent; + parent = NULL; + } + + if (object->mCondition == NULL) { + switch (object->mType) { + case cxObject::text: + object->mCondition = new cxFunction(object->mText); + break; + + default: + break; + } + } + + if (parent != NULL) { + Dprintf("pushing to parent\n"); + if (parent->mObjects == NULL) + parent->mObjects = new cxObjects(); + parent->mObjects->push_back(object); + } + else + display->mObjects.push_back(object); + object = NULL; + } + context.pop_back(); + } else + TAG_ERR_END(context[context.size() - 1].c_str()); + return true; +} + +cxSkin *xmlParse(const std::string &name, const std::string &fileName) { + skin = new cxSkin(name); + context.clear(); + + XML xml(fileName); + xml.nodeStartCB(xStartElem); + xml.nodeEndCB(xEndElem); + xml.cdataCB(xCharData); + if (xml.parse() != 0) { + esyslog("ERROR: Text2Skin: Parse error in %s, line %d", fileName.c_str(), xml.lineNr()); + DELETENULL(skin); + DELETENULL(display); + DELETENULL(object); + return NULL; + } + + cxSkin *result = skin; + skin = NULL; + return result; +} + diff --git a/xml/parser.h b/xml/parser.h new file mode 100644 index 0000000..60fe30c --- /dev/null +++ b/xml/parser.h @@ -0,0 +1,14 @@ +/* + * $Id: parser.h,v 1.1.1.1 2004/11/19 16:45:31 lordjaxom Exp $ + */ + +#ifndef VDR_TEXT2SKIN_PARSER_H +#define VDR_TEXT2SKIN_PARSER_H + +#include + +class cxSkin; + +cxSkin *xmlParse(const std::string &name, const std::string &fileName); + +#endif // VDR_TEXT2SKIN_PARSER_H diff --git a/xml/skin.c b/xml/skin.c new file mode 100644 index 0000000..0cc753b --- /dev/null +++ b/xml/skin.c @@ -0,0 +1,44 @@ +/* + * $Id: skin.c,v 1.2 2004/12/08 17:13:26 lordjaxom Exp $ + */ + +#include "xml/skin.h" +#include +#include + +const std::string ScreenBases[] = { "relative", "absolute" }; + +cxSkin::cxSkin(const std::string &Name): + mName(Name) { +} + +void cxSkin::SetBase(eScreenBase Base) { + mBase = Base; + switch (mBase) { + case relative: + mBaseOffset = txPoint(Setup.OSDLeft, Setup.OSDTop); + mBaseSize = txSize(Setup.OSDWidth, Setup.OSDHeight); + break; + + case absolute: + mBaseOffset = txPoint(0, 0); + mBaseSize = txSize(720, 576); //XXX + break; + + default: + break; + } +} + +bool cxSkin::ParseBase(const std::string &Text) { + int i; + for (i = 0; i < (int)__COUNT_BASE__; ++i) { + if (ScreenBases[i] == Text) + break; + } + if (i < (int)__COUNT_BASE__) { + SetBase((eScreenBase)i); + return true; + } + return false; +} diff --git a/xml/skin.h b/xml/skin.h new file mode 100644 index 0000000..40e25e7 --- /dev/null +++ b/xml/skin.h @@ -0,0 +1,64 @@ +/* + * $Id: skin.h,v 1.3 2004/12/08 17:13:26 lordjaxom Exp $ + */ + +#ifndef VDR_TEXT2SKIN_XML_SKIN_H +#define VDR_TEXT2SKIN_XML_SKIN_H + +#include "xml/display.h" +#include +#include +#include +#include + +// --- cxSkin ----------------------------------------------------------------- + +class cxSkin { + friend bool xStartElem(const std::string &name, std::map &attrs); + friend bool xEndElem(const std::string &name); + + /* Skin Editor */ + friend class VSkinnerView; + +public: + enum eScreenBase { + relative, + absolute, +#define __COUNT_BASE__ (absolute + 1) + }; + +private: + eScreenBase mBase; + txPoint mBaseOffset; + txSize mBaseSize; + std::string mName; + std::string mTitle; + std::string mVersion; + + cxDisplays mDisplays; + +protected: + void SetBase(eScreenBase Base); + +public: + cxSkin(const std::string &Name); + + cxDisplay *Get(cxDisplay::eType Type); + + bool ParseBase(const std::string &Text); + + eScreenBase Base(void) const { return mBase; } + const txPoint &BaseOffset(void) const { return mBaseOffset; } + const txSize &BaseSize(void) const { return mBaseSize; } + const std::string &Name(void) const { return mName; } + const std::string &Title(void) const { return mTitle; } + const std::string &Version(void) const { return mVersion; } +}; + +inline cxDisplay *cxSkin::Get(cxDisplay::eType Type) { + if (mDisplays.find(Type) != mDisplays.end()) + return mDisplays[Type]; + return NULL; +} + +#endif // VDR_TEXT2SKIN_XML_SKIN_H diff --git a/xml/string.c b/xml/string.c new file mode 100644 index 0000000..051a003 --- /dev/null +++ b/xml/string.c @@ -0,0 +1,161 @@ +/* + * $Id: string.c,v 1.5 2004/12/08 17:22:28 lordjaxom Exp $ + */ + +#include "xml/string.h" +#include "render.h" +#include + +static const char *Tokens[__COUNT_TOKEN__] = { + "DateTime", + + // Channel Display + "ChannelNumber", "ChannelName", "ChannelShortName", "ChannelBouquet", "PresentStartDateTime", + "PresentVPSDateTime", "PresentEndDateTime", "PresentDuration", "PresentProgress", + "PresentTitle", "PresentShortText", "PresentDescription", "FollowingStartDateTime", + "FollowingVPSDateTime", "FollowingEndDateTime", "FollowingDuration", + "FollowingTitle", "FollowingShortText", "FollowingDescription", "Language", + "HasTeletext", "HasMultilang", "HasDolby", "IsEncrypted", "IsRadio", "IsRecording", "HasVPS", + "HasTimer", "IsRunning", + + // Volume Display + "VolumeCurrent", "VolumeTotal", "IsMute", + + // Message Display + "Message", "MessageStatus", "MessageInfo", "MessageWarning", + "MessageError", + + // Replay Display + "ReplayTitle", "ReplayPositionIndex", "ReplayDurationIndex", "ReplayPrompt", "IsPlaying", + "IsFastForward", "IsFastRewind", "IsSlowForward", "IsSlowRewind", "IsPausing", + "ReplayPosition", "ReplayDuration", "ReplayMode", + + // Menu Page + "MenuTitle", "MenuGroup", "IsMenuGroup", "MenuItem", "IsMenuItem", "MenuCurrent", "IsMenuCurrent", + "MenuText", "ButtonRed", "ButtonGreen", "ButtonYellow", "ButtonBlue", "CanScrollUp", + "CanScrollDown" +}; + +std::string txToken::Token(const txToken &Token) { + std::string result = (std::string)"{" + Tokens[Token.Type]; + if (Token.Attrib.length() > 0) + result += ":" + Token.Attrib; + result += "}"; + + return result; +} + +cxString::cxString(void) { +} + +bool cxString::Parse(const std::string &Text) { + const char *text = Text.c_str(); + const char *ptr = text, *last = text; + bool inToken = false; + bool inAttrib = false; + int offset = 0; + + Dprintf("parsing: %s\n", Text.c_str()); + + for (; *ptr; ++ptr) { + if (inToken && *ptr == '\\') { + if (*(ptr + 1) == '\0') { + esyslog("ERROR: Stray \\ in token attribute\n"); + return false; + } + + ++ptr; + continue; + } + else if (*ptr == '{') { + if (inToken) { + esyslog("ERROR: Unexpected '{' in token"); + return false; + } + + mText.append(last, ptr - last); + last = ptr + 1; + inToken = true; + } + else if (*ptr == '}' || (inToken && *ptr == ':')) { + if (!inToken) { + esyslog("ERROR: Unexpected '}' outside of token"); + return false; + } + + if (inAttrib) { + if (*ptr == ':') { + esyslog("ERROR: Unexpected ':' inside of token attribute"); + return false; + } + + int pos = -1; + txToken &lastToken = mTokens[mTokens.size() - 1]; + lastToken.Attrib.assign(last, ptr - last); + while ((pos = lastToken.Attrib.find('\\', pos + 1)) != -1) { + switch (lastToken.Attrib[pos + 1]) { + case 'n': + lastToken.Attrib.replace(pos, 2, "\n"); + break; + + default: + lastToken.Attrib.erase(pos, 1); + } + } + + inAttrib = false; + inToken = false; + } else { + int i; + for (i = 0; i < (int)__COUNT_TOKEN__; ++i) { + if ((size_t)(ptr - last) == strlen(Tokens[i]) + && memcmp(last, Tokens[i], ptr - last) == 0) { + txToken token((exToken)i, offset, ""); + mTokens.push_back(token); + break; + } + } + + if (i == (int)__COUNT_TOKEN__) { + esyslog("ERROR: Unexpected token {%.*s}", (int)(ptr - last), last); + return false; + } + + if (*ptr == ':') + inAttrib = true; + else + inToken = false; + } + + last = ptr + 1; + } + else if (!inToken) + ++offset; + } + + if (inToken) { + esyslog("ERROR: Expecting '}' in token"); + return false; + } + + mText.append(last, ptr - last); + return true; +} + +cxType cxString::Evaluate(void) const +{ + std::string result; + int offset = 0; + + if (mText.length() == 0 && mTokens.size() == 1) + return cText2SkinRender::GetToken(mTokens[0]); + + for (uint i = 0; i < mTokens.size(); ++i) { + result.append(mText.c_str() + offset, mTokens[i].Offset - offset); + result.append(cText2SkinRender::GetToken(mTokens[i])); + offset = mTokens[i].Offset; + } + result.append(mText.c_str() + offset); + return result; +} + diff --git a/xml/string.h b/xml/string.h new file mode 100644 index 0000000..5c89d13 --- /dev/null +++ b/xml/string.h @@ -0,0 +1,128 @@ +/* + * $Id: string.h,v 1.5 2004/12/08 18:47:37 lordjaxom Exp $ + */ + +#ifndef VDR_TEXT2SKIN_XML_STRING_H +#define VDR_TEXT2SKIN_XML_STRING_H + +#include "xml/type.h" +#include +#include + +enum exToken { + tDateTime, + + // Channel Display + tChannelNumber, + tChannelName, + tChannelShortName, + tChannelBouquet, + // next 8 also in Menu + tPresentStartDateTime, + tPresentVPSDateTime, + tPresentEndDateTime, + tPresentDuration, + tPresentProgress, + tPresentTitle, + tPresentShortText, + tPresentDescription, + tFollowingStartDateTime, + tFollowingVPSDateTime, + tFollowingEndDateTime, + tFollowingDuration, + tFollowingTitle, + tFollowingShortText, + tFollowingDescription, + tLanguage, + tHasTeletext, + tHasMultilang, + tHasDolby, + tIsEncrypted, + tIsRadio, + tIsRecording, + // next 3 also in Menu + tHasVPS, + tHasTimer, + tIsRunning, + + // VolumeDisplay + tVolumeCurrent, + tVolumeTotal, + tIsMute, + + // Message Display + tMessage, + tMessageStatus, + tMessageInfo, + tMessageWarning, + tMessageError, + + // Replay Display + tReplayTitle, + tReplayPositionIndex, + tReplayDurationIndex, + tReplayPrompt, + tIsPlaying, + tIsFastForward, + tIsFastRewind, + tIsSlowForward, + tIsSlowRewind, + tIsPausing, + tReplayPosition, + tReplayDuration, + tReplayMode, + + // Menu Page + tMenuTitle, + tMenuGroup, + tIsMenuGroup, + tMenuItem, + tIsMenuItem, + tMenuCurrent, + tIsMenuCurrent, + tMenuText, + tButtonRed, + tButtonGreen, + tButtonYellow, + tButtonBlue, + tCanScrollUp, + tCanScrollDown, + +#define __COUNT_TOKEN__ (tCanScrollDown + 1) +}; + +struct txToken { + exToken Type; + uint Offset; + std::string Attrib; + int Index; + int Tab; + + txToken(void): Index(-1), Tab(-1) {} + txToken(exToken t, uint o, const std::string &a): Type(t), Offset(o), Attrib(a), Index(-1), Tab(-1) {} + static std::string Token(const txToken &Token); +}; + +class cxString { +private: + std::string mText; + std::vector mTokens; + +public: + cxString(void); + + bool Parse(const std::string &Text); + cxType Evaluate(void) const; + + void SetIndex(uint Index, int Tab); +}; + +inline void cxString::SetIndex(uint Index, int Tab) +{ + for (uint i = 0; i < mTokens.size(); ++i) { + mTokens[i].Index = Index; + mTokens[i].Tab = Tab; + } +} + +#endif // VDR_TEXT2SKIN_XML_STRING_H diff --git a/xml/type.c b/xml/type.c new file mode 100644 index 0000000..d311b30 --- /dev/null +++ b/xml/type.c @@ -0,0 +1,20 @@ +/* + * $Id: type.c,v 1.2 2004/12/08 17:13:26 lordjaxom Exp $ + */ + +#include "xml/type.h" +#include "xml/function.h" +#include + +const std::string &cxType::String(void) { + static char buffer[50]; + if (mType == number) { + snprintf(buffer, sizeof(buffer), "%d", mNumber); + mString = buffer; + mType = string; + } else if (mType == boolean) { + mString = mNumber ? cxFunction::True : cxFunction::False; + mType = string; + } + return mString; +} diff --git a/xml/type.h b/xml/type.h new file mode 100644 index 0000000..1b1113c --- /dev/null +++ b/xml/type.h @@ -0,0 +1,42 @@ +/* + * $Id: type.h,v 1.3 2004/12/08 17:13:26 lordjaxom Exp $ + */ + +#ifndef VDR_TEXT2SKIN_XML_TYPE_H +#define VDR_TEXT2SKIN_XML_TYPE_H + +#include + +class cxType { +public: + enum eType { + string, + number, + boolean + }; + +private: + eType mType; + std::string mString; + int mNumber; + +public: + cxType(const char *String): mType(string), mString(String ?: "") {} + cxType(std::string String): mType(string), mString(String) {} + cxType(int Number): mType(number), mNumber(Number) {} + cxType(time_t Number): mType(number), mNumber(Number) {} + cxType(bool Value): mType(boolean), mNumber(Value ? 1 : 0) {} + + const std::string &String(void); + int Number(void) const; + + operator std::string () { return String(); } + operator int () { return Number(); } + operator bool () { return Number(); } +}; + +inline int cxType::Number(void) const { + return mType == number ? mNumber : 0; +} + +#endif // VDR_TEXT2SKIN_XML_TYPE_H diff --git a/xml/xml.c b/xml/xml.c new file mode 100644 index 0000000..07dae8c --- /dev/null +++ b/xml/xml.c @@ -0,0 +1,295 @@ +/* + * $Id: xml.c,v 1.2 2004/12/06 15:01:02 lordjaxom Exp $ + * This module was kindly provided by Clemens Kirchgatterer + */ + +#include + +#include +#include + +#include "xml.h" + +using namespace std; + +enum { + LOOK4START, // looking for first element start + LOOK4TAG, // looking for element tag + INTAG, // reading tag + LOOK4ATTRN, // looking for attr name, > or / + INATTRN, // reading attr name + LOOK4ATTRV, // looking for attr value + SAWSLASH, // saw / in element opening + INATTRV, // in attr value + LOOK4CLOSETAG, // looking for closing tag after < + INCLOSETAG, // reading closing tag +}; + +XML::XML(const string &file) { + char *buffer; + long size; + + ifstream f(file.c_str(), ios::in|ios::binary|ios::ate); + size = f.tellg(); + f.seekg(0, ios::beg); + buffer = new char [size]; + f.read(buffer, size); + f.close(); + data = buffer; + delete[] buffer; + nodestartcb = NULL; + nodeendcb = NULL; + cdatacb = NULL; + parseerrorcb = NULL; + progresscb = NULL; +} + +XML::XML(const char *mem, unsigned int len) { + data.assign(mem, len); + nodestartcb = NULL; + nodeendcb = NULL; + cdatacb = NULL; + parseerrorcb = NULL; + progresscb = NULL; +} + +void +XML::nodeStartCB(XML_NODE_START_CB(cb)) { + nodestartcb = cb; +} + +void +XML::nodeEndCB(XML_NODE_END_CB(cb)) { + nodeendcb = cb; +} + +void +XML::cdataCB(XML_CDATA_CB(cb)) { + cdatacb = cb; +} + +void +XML::parseErrorCB(XML_PARSE_ERROR_CB(cb)) { + parseerrorcb = cb; +} + +void +XML::progressCB(XML_PROGRESS_CB(cb)) { + progresscb = cb; +} + +int +XML::parse(void) { + float percent = 0; + unsigned int len; + int last = 0; + + state = LOOK4START; + linenr = 1; + skipping = false; + len = data.length(); + for (unsigned int i=0; ilast) { + progresscb((int)percent); + last = ((int)percent); + } + } + } + return (0); +} + +bool +XML::isTokenChar(bool start, int c) { + return (isalpha(c) || c == '_' || (!start && isdigit(c))); +} + +int +XML::readChar(int c) { + // new line? + if (c == '\n') linenr++; + + switch (state) { + + // looking for element start + case LOOK4START: + if (c == '<') { + if (cdatacb) { + int pos = 0; + while ((pos = cdata.find('&', pos)) != -1) { + if (cdata.substr(pos, 4) == "<") + cdata.replace(pos, 4, "<"); + else if (cdata.substr(pos, 4) == ">") + cdata.replace(pos, 4, ">"); + else if (cdata.substr(pos, 5) == "&") + cdata.replace(pos, 5, "&"); + ++pos; + } + if (!cdatacb(cdata)) + return (-1); + } + cdata = ""; + attr.clear(); + tag = ""; + state = LOOK4TAG; + } else + cdata += c; + // silently ignore until resync + break; + + // looking for element tag + case LOOK4TAG: + // skip comments and declarations. + if (skipping) { + if (c == '>') { + skipping = false; + state = LOOK4START; + } + break; + } else { + if (c == '?' || c == '!') { + skipping = true; + break; + } + } + if (isTokenChar(1, c)) { + tag += c; + state = INTAG; + } else if (c == '/') { + state = LOOK4CLOSETAG; + } else if (!isspace(c)) { + if (parseerrorcb) { + parseerrorcb(linenr, "Bogus tag char", c); + } + return (-1); + } + break; + + // reading tag + case INTAG: + if (isTokenChar(0, c)) { + tag += c; + } else if (c == '>') { + if (nodestartcb) + if (!nodestartcb(tag, attr)) + return (-1); + state = LOOK4START; + } else if (c == '/') { + state = SAWSLASH; + } else { + state = LOOK4ATTRN; + } + break; + + // looking for attr name, > or / + case LOOK4ATTRN: + if (c == '>') { + if (nodestartcb) + if (!nodestartcb(tag, attr)) + return (-1); + state = LOOK4START; + } else if (c == '/') { + state = SAWSLASH; + } else if (isTokenChar(1, c)) { + attrn = ""; + attrn += c; + state = INATTRN; + } else if (!isspace(c)) { + if (parseerrorcb) { + parseerrorcb(linenr, "Bogus 1st attr name char", c); + } + return (-2); + } + break; + + // saw / in element opening + case SAWSLASH: + if (c == '>') { + if (nodestartcb) + if (!nodestartcb(tag, attr)) + return (-1); + if (nodeendcb) + if (!nodeendcb(tag)) + return (-1); + state = LOOK4START; + } else { + if (parseerrorcb) { + parseerrorcb(linenr, "Bogus char before >", c); + } + return (-3); + } + break; + + // reading attr name + case INATTRN: + if (isTokenChar(0, c)) { + attrn += c; + } else if (isspace(c) || c == '=') { + state = LOOK4ATTRV; + } else { + if (parseerrorcb) { + parseerrorcb(linenr, "Bogus attr name char", c); + } + return (-4); + } + break; + + // looking for attr value + case LOOK4ATTRV: + if (c == '\'' || c == '"') { + delim = c; + attrv = ""; + state = INATTRV; + } else if (!(isspace(c) || c == '=')) { + if (parseerrorcb) { + parseerrorcb(linenr, "No attribute value", c); + } + return (-5); + } + break; + + // in attr value + case INATTRV: + if (c == delim) { + attr[attrn] = attrv; + state = LOOK4ATTRN; + } else if (!iscntrl(c)) { + attrv += c; + } + break; + + // looking for closing tag after < + case LOOK4CLOSETAG: + if (isTokenChar(1, c)) { + tag += c; + state = INCLOSETAG; + } else if (!isspace(c)) { + if (parseerrorcb) { + parseerrorcb(linenr, "Bogus preend tag char", c); + } + return (-6); + } + break; + + // reading closing tag + case INCLOSETAG: + if (isTokenChar(0, c)) { + tag += c; + } else if (c == '>') { + if (nodeendcb) + if (!nodeendcb(tag)) + return false; + state = LOOK4START; + } else if (!isspace(c)) { + if (parseerrorcb) { + parseerrorcb(linenr, "Bogus end tag char", c); + } + return (-7); + } + break; + } + + return (0); +} diff --git a/xml/xml.h b/xml/xml.h new file mode 100644 index 0000000..9abc641 --- /dev/null +++ b/xml/xml.h @@ -0,0 +1,63 @@ +/* + * $Id: xml.h,v 1.1.1.1 2004/11/19 16:45:31 lordjaxom Exp $ + * This module was kindly provided by Clemens Kirchgatterer + */ + +#ifndef _XML_H_ +#define _XML_H_ + +#include +#include + +#define XML_NODE_START_CB(CB) \ +bool (*CB)(const std::string &tag, std::map &attr) +#define XML_NODE_END_CB(CB) \ +bool (*CB)(const std::string &tag) +#define XML_CDATA_CB(CB) \ +bool (*CB)(const std::string &text) +#define XML_PARSE_ERROR_CB(CB) \ +void (*CB)(int line, const char *txt, char c) +#define XML_PROGRESS_CB(CB) \ +void (*CB)(int percent) + +class XML { + +public: + + XML(const std::string &file); + XML(const char *mem, unsigned int len); + + void nodeStartCB(XML_NODE_START_CB(cb)); + void nodeEndCB(XML_NODE_END_CB(cb)); + void cdataCB(XML_CDATA_CB(cb)); + void parseErrorCB(XML_PARSE_ERROR_CB(cb)); + void progressCB(XML_PROGRESS_CB(cb)); + + int parse(void); + + int lineNr(void) const { return linenr; } + +protected: + + bool isTokenChar(bool start, int c); + int readChar(int c); + +private: + + bool skipping; + int state; + int linenr; + int delim; + + std::string data, cdata, tag, attrn, attrv; + std::map attr; + + XML_NODE_START_CB(nodestartcb); + XML_NODE_END_CB(nodeendcb); + XML_CDATA_CB(cdatacb); + XML_PARSE_ERROR_CB(parseerrorcb); + XML_PROGRESS_CB(progresscb); + +}; + +#endif // _XML_H_ -- cgit v1.2.3