diff options
author | lordjaxom <lordjaxom> | 2004-06-05 18:06:22 +0000 |
---|---|---|
committer | lordjaxom <lordjaxom> | 2004-06-05 18:06:22 +0000 |
commit | 6094765d94e4caaf0813039dff826b731f277753 (patch) | |
tree | fed79334167f26d5a81a6cae9be3f1341375a36f | |
parent | e0c2ee1d37c0f213f22a04df71710bebe3526f85 (diff) | |
download | vdr-plugin-text2skin-6094765d94e4caaf0813039dff826b731f277753.tar.gz vdr-plugin-text2skin-6094765d94e4caaf0813039dff826b731f277753.tar.bz2 |
- added scrollable texts and "SymbolScrollUp" and "SymbolScrollDown"v0.0.1
- added "MenuText", "MenuEventTitle", "MenuEventShortText",
"MenuEventDescription", "MenuEventTime", "MenuRecording",
"SymbolEventRunning", "SymbolEventTimer" and "SymbolEventVPS"
- implemented image caching
- added english and german README
- removed some workarounds, and added a patch to vdr to the tree (will be
included in 1.3.10)
- fixed two bugs when displaying replay symbols
- implemented tabbed texts in menu
-rw-r--r-- | HISTORY | 13 | ||||
-rw-r--r-- | Makefile | 27 | ||||
-rw-r--r-- | README | 92 | ||||
-rw-r--r-- | README.de | 101 | ||||
-rw-r--r-- | SKINS | 133 | ||||
-rw-r--r-- | bitmap.c | 53 | ||||
-rw-r--r-- | bitmap.h | 17 | ||||
-rw-r--r-- | cache.c | 6 | ||||
-rw-r--r-- | cache.h | 124 | ||||
-rw-r--r-- | common.c | 69 | ||||
-rw-r--r-- | common.h | 10 | ||||
-rw-r--r-- | data.c | 113 | ||||
-rw-r--r-- | data.h | 16 | ||||
-rw-r--r-- | display.c | 46 | ||||
-rw-r--r-- | display.h | 4 | ||||
-rw-r--r-- | i18n.c | 18 | ||||
-rw-r--r-- | loader.c | 7 | ||||
-rw-r--r-- | patches/vdr-1.3.9-osd.diff | 106 | ||||
-rw-r--r-- | render.c | 192 | ||||
-rw-r--r-- | render.h | 23 | ||||
-rw-r--r-- | text2skin.c | 23 | ||||
-rw-r--r-- | text2skin.h | 27 |
22 files changed, 940 insertions, 280 deletions
@@ -1,6 +1,19 @@ VDR Plugin 'text2skin' Revision History --------------------------------------- +2004-06-05: Version 0.0.1 + +- added scrollable texts and "SymbolScrollUp" and "SymbolScrollDown" +- added "MenuText", "MenuEventTitle", "MenuEventShortText", + "MenuEventDescription", "MenuEventTime", "MenuRecording", + "SymbolEventRunning", "SymbolEventTimer" and "SymbolEventVPS" +- implemented image caching +- added english and german README +- removed some workarounds, and added a patch to vdr to the tree (will be + included in 1.3.10) +- fixed two bugs when displaying replay symbols +- implemented tabbed texts in menu + 2004-06-02: Version 0.0.1-rc4 - implemented image loading through ImageMagick (fixes crashes when running @@ -1,15 +1,16 @@ -# -# Makefile for a Video Disk Recorder plugin -# -# $Id: Makefile,v 1.5 2004/06/02 20:43:05 lordjaxom Exp $ +# exchange the comments on the following to lines if you would like to use +# Imlib2 for loading images. BEWARE that you can not use GraphTFT together with +# Text2Skin if you use Imlib2! (That's why I actually implemented ImageMagick) -# disable in case you don't want to install imlib -# in that case, you will not be able to load other files than simple xpms +HAVE_IMAGEMAGICK=1 # HAVE_IMLIB2=1 -# disable in case you don't want to install ImageMagick -# in that case, you will not be able to load other files than simple xpms -HAVE_IMAGEMAGICK=1 + +# DO NOT EDIT BELOW THIS LINE UNLESS YOU KNOW WHAT YOU'RE DOING +# ------------------------------------------------------------- +# +# $Id: Makefile,v 1.7 2004/06/05 16:52:44 lordjaxom Exp $ +# # The official name of this plugin. # This name will be used in the '-P...' option of VDR to load the plugin. @@ -19,7 +20,7 @@ PLUGIN = text2skin ### The version number of this plugin (taken from the main source file): -VERSION = $(shell grep 'static const char \*VERSION *=' $(PLUGIN).c | awk '{ print $$6 }' | sed -e 's/[";]//g') +VERSION = $(shell grep 'const char \*cText2SkinPlugin::VERSION *=' $(PLUGIN).c | awk '{ print $$5 }' | sed -e 's/[";]//g') ### The C++ compiler and options: @@ -58,6 +59,10 @@ ifdef HAVE_IMAGEMAGICK LIBS += -lMagick++ endif +ifdef DEBUG + DEFINES += -DDEBUG +endif + INCLUDES += -I$(VDRDIR)/include -I$(DVBDIR)/include DEFINES += -D_GNU_SOURCE -DPLUGIN_NAME_I18N='"$(PLUGIN)"' @@ -65,7 +70,7 @@ DEFINES += -D_GNU_SOURCE -DPLUGIN_NAME_I18N='"$(PLUGIN)"' ### 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 + file.o i18n.o theme.o cache.o ### Implicit rules: @@ -1,11 +1,97 @@ This is a "plugin" for the Video Disk Recorder (VDR). -Written by: Your Name <email@host.dom> +Written by: Sascha Volkenandt <sascha@akv-soft.de> -Project's homepage: URL +Project's homepage: http://www.magoa.net/linux/contrib/ -Latest version available at: URL +Latest version available at: http://www.magoa.net/linux/contrib/ See the file COPYING for license information. + Description: +------------ + +This plugin is designed to load and interpret a set of files describing the +layout of the On Screen Display and to make this "Skin" available to VDR via +Setup -> OSD in the main menu. Of course it is possible to load more than one +text-based skin this way and to choose between them while running VDR. All +skins may be themeable (you can create your own color-theme) and translateable +as the author of the skin wishes. + + +Prerequisites: +-------------- + +For loading images in format other than simple XPM, you will need an image +library. You can choose between two supported libraries, ImageMagick or Imlib2, +from which the first one is the default. You can specify which library to use +(if any) in the first few lines of the Makefile. Here is an overview of the +advantages and drawbacks of each solution: + +No library + - you can only load XPM files + - XPMs don't support partial transparency / alpha channels + +ImageMagick + + you can load many different image types + - is a but slower than Imlib2 + +Imlib2 + + you can load many different image types + - CRASHES WHEN USED TOGETHER WITH THE GRAPHTFT-PLUGIN! + +Using both libraries at the same time doesn't make sense anyway. + +HINT: Although the manual of ImageMagick claims that the used library Magick++ +is part of the source distribution, some binary distributions may have to +install Magick++ separately. + + +Installation: +------------- + +Install text2skin like any other plugin. In this example I assume that you have +changed to the folder where the VDR sourcecode is located, and that it is +version 0.0.1 of the plugin you wish to install. + +root@linux # cd PLUGINS/src +root@linux # wget http://www.magoa.net/linux/contrib/vdr-text2skin-0.0.1.tgz +root@linux # tar -xfz vdr-text2skin-0.0.1.tgz +root@linux # ln -s text2skin-0.0.1 text2skin +root@linux # cd ../.. +root@linux # make plugins +root@linux # ./vdr -P text2skin + +If you are using VDR 1.3.9, you also have to apply a patch to the sources. This +patch will be included in VDR 1.3.10. + +root@linux # patch -p1 < PLUGINS/src/text2skin/patches/vdr-1.3.9-osd.diff +root@linux # make vdr +root@linux # ./vdr -P text2skin + + +Where to put the skins: +----------------------- + +As you might know, VDR has a subfolder "plugins" inside it's configuration +folder, where all plugin-related files should reside. If you don't know, where +this could be, look into the folder you gave to VDR with the -v parameter +(or the -c parameter, if that was given). "plugins" should be inside that +folder. + +Inside that "plugins" folder, create a subfolder called "text2skin". Inside +"text2skin", create one folder for each skin. These skin-folders must have the +same names as the skins residing in them. Each skin must at least have a file +carrying the same name, but ending in ".skin". Example: + +/video0/plugins/text2skin/demo/demo.skin +/video0/plugins/text2skin/skin2/skin2.skin +... + +The other files inside the skin-folder are additional description files (for +Themeing and Translation), images, logos and symbols. + +If you download a skin, you usually just change to plugins/text2skin and unpack +it there. + diff --git a/README.de b/README.de new file mode 100644 index 0000000..49a9945 --- /dev/null +++ b/README.de @@ -0,0 +1,101 @@ +Dies ist ein "plugin" für den Video Disk Recorder (VDR). + +Geschrieben von: Sascha Volkenandt <sascha@akv-soft.de> + +Projekthomepage: http://www.magoa.net/linux/contrib/ + +Letzte Version verfügbar auf: http://www.magoa.net/linux/contrib/ + +Siehe COPYING für Linzensierungsinformationen. + + +Beschreibung: +------------- + +Dieses Plugin wurde designed um eine Reihe von Dateien zu laden und zu +interpretieren, die das Aussehen des On Screen Display beschreiben, und diese +dem VDR via Einstellungen -> OSD zur Verfügung zu stellen. Natürlich ist es +möglich mehrere textbasierte Skins auf diesem Wege zu laden, und unter diesen +bei laufendem VDR auszuwählen. Alle Skins können Themeable (die Farbvarianten +können geändert werden) und Übersetzbar sein, wenn der Autor des Skins dies +möchte. + + +Voraussetzungen: +---------------- + +Um andere Bildformate als einfaches XPM zu laden, brauchen Sie eine +Grafikbibliothek. Es werden zwei Bibliotheken unterstützt, aus der Sie eine +zu benutzende wählen können. Dies sind ImageMagick oder Imlib2, wobei erstere +standardmäßig herangezogen wird. Sie können beeinflussen, welche Bibliothek +(wenn überhaupt eine) genutzt werden soll, indem Sie die ersten paar Zeilen +der Datei Makefile ändern. Hier ist eine Übersicht über Möglichkeiten und +Nachteile jeder möglichen Lösung: + +Keine Bibliothek + - Sie können nur XPM Dateien laden + - XPMs haben weder Teiltransparenzen noch Alphakanäle + +ImageMagick + + Sie können viele verschiedene Bildformate laden + - ist aber etwas langsamer als Imlib2 + +Imlib2 + + Sie können viele verschiedene Bildformate laden + - STÜRZT AB, WENN ES ZUSAMMEN MIT DEM GRAPHTFT-PLUGIN ZUM EINSATZ KOMMT! + +Beide Bibliotheken gleichzeitig zu benutzen macht keinen Sinn. + +HINWEIS: Obwohl das Handbuch von ImageMagick behauptet, dass die hier benutzte +Bibliothek Magick++ integraler Bestandteil der Quellen sind, muss auf manchen +Distributionen das Paket Magick++ zusätzlich installiert werden. + + +Installation: +------------- + +Installieren Sie text2skin wie jedes andere Plugin. In diesem Beispiel nehme +ich an Sie sind in den Ordner gewechselt, in dem VDR's Quelltext liegt, und +Sie wollen Version 0.0.1 des Plugins installieren. + +root@linux # cd PLUGINS/src +root@linux # wget http://www.magoa.net/linux/contrib/vdr-text2skin-0.0.1.tgz +root@linux # tar -xfz vdr-text2skin-0.0.1.tgz +root@linux # ln -s text2skin-0.0.1 text2skin +root@linux # cd ../.. +root@linux # make plugins +root@linux # ./vdr -P text2skin + +Wenn Sie VDR 1.3.9 benutzen, müssen Sie auch noch einen Patch anwenden. Dieser +Patch wird in VDR 1.3.10 aber enthalten sein. + +root@linux # patch -p1 < PLUGINS/src/text2skin/patches/vdr-1.3.9-osd.diff +root@linux # make vdr +root@linux # ./vdr -P text2skin + + +Wo die Skins hingehören: +------------------------ + +Wie Sie vielleicht wissen, hat VDR einen Unterordner "plugins" innerhalb seines +Konfigurationsordners, in dem alle Dateien, die zu Plugins gehören, enthalten +sein sollten. Wenn Sie nicht wissen, wo das sein könnte, schauen Sie in dem +Ordner nach, den Sie VDR beim Starten mit -v (oder -c, falls gegeben) übergeben +haben. "plugins" sollte in diesem Ordner enthalten sein. + +Innerhalb dieses "plugins" Ordners erstellen Sie einen Ordner namens +"text2skin". In "text2skin" erstellen Sie einen weiteren Ordner pro Skin. Diese +Skin-Ordner müssen den gleichen Namen tragen wie die Skins in ihnen. Jedes +Skin muss mindestens eine Datei enthalten, die denselben Namen trägt, aber mit +der Endung ".skin". Beispiel: + +/video0/plugins/text2skin/demo/demo.skin +/video0/plugins/text2skin/skin2/skin2.skin +... + +Die anderen Dateien in dem Skin-Ordner sind weitere Beschreibungsdateien (für +Farben und Übersetzungen) sowie Bilder, Logos und Symbole. + +Wenn Sie ein Skin herunterladen, wechseln Sie normalerweise einfach in den +plugins/text2skin Ordner und entpacken es dort. + @@ -261,6 +261,84 @@ Description: Draws the specified image into the specified location if the image handling, see Item=Background. Parameters: x, y, width, height, path, altpath, fg, bg +Item: Item=SymbolPlay +Description: Draws the specified image into the specified location if the + current replay is playing normally. If that is not the case, the + alternative image (if given) will be displayed. For details on the + image handling, see Item=Background. +Parameters: x, y, width, height, path, altpath, fg, bg + +Item: Item=SymbolPause +Description: Draws the specified image into the specified location if the + current replay is paused. If that is not the case, the + alternative image (if given) will be displayed. For details on the + image handling, see Item=Background. +Parameters: x, y, width, height, path, altpath, fg, bg + +Item: Item=SymbolFastFwd +Description: Draws the specified image into the specified location if the + current replay is fast forwarding. If that is not the case, the + alternative image (if given) will be displayed. For details on the + image handling, see Item=Background. +Parameters: x, y, width, height, path, altpath, fg, bg + +Item: Item=SymbolFastRew +Description: Draws the specified image into the specified location if the + current replay is fast rewinding. If that is not the case, the + alternative image (if given) will be displayed. For details on the + image handling, see Item=Background. +Parameters: x, y, width, height, path, altpath, fg, bg + +Item: Item=SymbolSlowFwd +Description: Draws the specified image into the specified location if the + current replay is slow forwarding. If that is not the case, the + alternative image (if given) will be displayed. For details on the + image handling, see Item=Background. +Parameters: x, y, width, height, path, altpath, fg, bg + +Item: Item=SymbolSlowRew +Description: Draws the specified image into the specified location if the + current replay is slow rewinding. If that is not the case, the + alternative image (if given) will be displayed. For details on the + image handling, see Item=Background. +Parameters: x, y, width, height, path, altpath, fg, bg + +Item: Item=SymbolEventRunning +Description: Draws the specified image into the specified location if the + displayed event (in menu display) is currently running. If that + is not the case, the alternative image (if given) will be + displayed. For details on the image handling, see Item=Background. +Parameters: x, y, width, height, path, altpath, fg, bg + +Item: Item=SymbolEventTimer +Description: Draws the specified image into the specified location if the + displayed event (in menu display) will be recorded. If that is + not the case, the alternative image (if given) will be displayed. + For details on the image handling, see Item=Background. +Parameters: x, y, width, height, path, altpath, fg, bg + +Item: Item=SymbolEventVPS +Description: Draws the specified image into the specified location if the + displayed event (in menu display) is VPS. If that is not the + case, the alternative image (if given) will be displayed. For + details on the image handling, see Item=Background. +Parameters: x, y, width, height, path, altpath, fg, bg + +Item: Item=SymbolScrollUp +Description: Draws the specified image into the specified location if the + current display is scrollable and not at the top of its contents. + If that is not the case, the alternative image (if given) will be + displayed. For details on the image handling, see Item=Background. +Parameters: x, y, width, height, path, altpath, fg, bg + +Item: Item=SymbolScrollDown +Description: Draws the specified image into the specified location if the + current display is scrollable and not at the bottom of its + contents. If that is not the case, the alternative image (if + given) will be displayed. For details on the image handling, see + Item=Background. +Parameters: x, y, width, height, path, altpath, fg, bg + Item: Item=Language Description: Draws a logo for the current language (currently the only languages VDR knows are "Audio 1" and possibly "Audio 2", @@ -317,6 +395,61 @@ Item: Item=MessageError Description: Draws the current error message (if present). Parameters: x, y, width, height, fg, font, align, text +Item: Item=MenuArea +Description: Specifies the area in which the menu items will be shown as a + list. +Parameters: x, y, width, height + +Item: Item=MenuItem +Description: Specifies how one item is drawn in the list of menu items. + list. +Parameters: [x,] [y,] width, height, fg, bg, font, align + +Item: Item=MenuCurrent +Description: Specifies how the currently selected item is drawn in the list of + menu items. + list. +Parameters: [x,] [y,] width, height, fg, bg, font, align + +Item: Item=MenuTitle +Description: Draws the title line of the displayed menu. +Parameters: x, y, width, height, fg, font, align, text + +Item: Item=MenuRed, Item=MenuGreen, Item=MenuYellow, Item=MenuBlue +Description: Draws the red, green, yellow or blue (respectively) button. +Parameters: x, y, width, height, fg, font, align, text + +Item: Item=MenuText +Description: Draws the current menu text in a scrollable text-area. If this + item is present, SymbolScrollUp and SymbolScrollDown apply, too. +Parameters: x, y, width, height, fg, [bg,] font, [align,] text + +Item: Item=MenuEventTitle +Description: Draws the title of the currently selected event when viewing EPG + entries. +Parameters: x, y, width, height, fg, font, align, text + +Item: Item=MenuEventShortText +Description: Draws the short text or episode name of the currently selected + event when viewing EPG entries. +Parameters: x, y, width, height, fg, font, align, text + +Item: Item=MenuEventDescription +Description: Draws the long text of the currently selected event when viewing + EPG entries in a scrollable text-area. If this item is present, + SymbolScrollUp and SymbolScrollDown apply, too. +Parameters: x, y, width, height, fg, [bg,] font, [align,] text + +Item: Item=MenuEventTime +Description: Draws the start time of the currently selected event when viewing + EPG entries. +Parameters: x, y, width, height, fg, font, align, text + +Item: Item=MenuRecording +Description: Draws the summary of the currently selected recording when + browsing recordings in a scrollable text-area. If this item is + present, SymbolScrollUp and SymbolScrollDown apply, too. +Parameters: x, y, width, height, fg, [bg,] font, [align,] text Known Parameters ---------------- @@ -1,5 +1,5 @@ /* - * $Id: bitmap.c,v 1.9 2004/06/02 20:43:05 lordjaxom Exp $ + * $Id: bitmap.c,v 1.11 2004/06/05 16:52:44 lordjaxom Exp $ */ #include "bitmap.h" @@ -12,40 +12,46 @@ #include <Magick++.h> #endif -cText2SkinBitmap::cText2SkinBitmap(void): cBitmap(1, 1, 1) { -#ifdef HAVE_IMLIB2 - imlib_set_cache_size(4096 * 1024); -#endif +template<> +void cImageCache::Delete(string &key, cText2SkinBitmap *&value) { + delete value; } -cText2SkinBitmap::cText2SkinBitmap(const char *Filename): cBitmap(1, 1, 1) { -#ifdef HAVE_IMLIB2 - imlib_set_cache_size(4096 * 1024); -#endif - Load(Filename); +cImageCache cText2SkinBitmap::mCache(10); + +cText2SkinBitmap::cText2SkinBitmap(void): cBitmap(1, 1, 1) { } cText2SkinBitmap::~cText2SkinBitmap() { } -bool cText2SkinBitmap::Load(const char *Filename) { - int len = strlen(Filename); - if (len > 4) { - if (strcmp(Filename + len - 4, ".xpm") == 0) - return LoadXpm(Filename); +cText2SkinBitmap *cText2SkinBitmap::Load(const char *Filename) { + if (mCache.Contains(Filename)) { + return mCache[Filename]; + } else { + cText2SkinBitmap *bmp = new cText2SkinBitmap; + int len = strlen(Filename); + bool result = false; + if (len > 4) { + if (strcmp(Filename + len - 4, ".xpm") == 0) + result = bmp->LoadXpm(Filename); + else { #ifdef HAVE_IMLIB2 - else if (strcmp(Filename + len - 4, ".png") == 0) - return LoadImlib(Filename); + result = bmp->LoadImlib(Filename); #else # ifdef HAVE_IMAGEMAGICK - else if (strcmp(Filename + len - 4, ".png") == 0) - return LoadMagick(Filename); + result = bmp->LoadMagick(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); + } + //else + //esyslog("ERROR: text2skin: unknown file format for %s", Filename); + } else + esyslog("ERROR: text2skin: filename %s too short to identify format", Filename); + + if (result) + return (mCache[Filename] = bmp); + } return false; } @@ -66,7 +72,6 @@ bool cText2SkinBitmap::LoadImlib(const char *Filename) { for (int x = 0; x < Width(); ++x) { tColor col = (data[pos + 3] << 24) | (data[pos + 2] << 16) | (data[pos + 1] << 8) | data[pos + 0]; int res = Index(col); - //printf("color: r=%d,g=%d,b=%d,a=%d\n", data[pos], data[pos+1], data[pos+2], data[pos+3]); if (pal > 0 && res == 0) ;//esyslog("ERROR: text2skin: Too many colors used in palette"); else @@ -1,20 +1,29 @@ /* - * $Id: bitmap.h,v 1.6 2004/06/02 20:43:05 lordjaxom Exp $ + * $Id: bitmap.h,v 1.7 2004/06/05 01:39:36 lordjaxom Exp $ */ #ifndef VDR_TEXT2SKIN_BITMAP_H #define VDR_TEXT2SKIN_BITMAP_H #include "common.h" +#include "cache.h" #include <vdr/osd.h> +class cText2SkinBitmap; +typedef cText2SkinCache<string,cText2SkinBitmap*> cImageCache; + class cText2SkinBitmap: public cBitmap { -public: +private: + static cImageCache mCache; + + // disallow direct construction cText2SkinBitmap(void); - cText2SkinBitmap(const char *Filename); + +public: + static cText2SkinBitmap *Load(const char *Filename); + virtual ~cText2SkinBitmap(); - bool Load(const char *Filename); #ifdef HAVE_IMLIB2 bool LoadImlib(const char *Filename); #endif @@ -0,0 +1,6 @@ +/* + * $Id: cache.c,v 1.1 2004/06/05 01:40:13 lordjaxom Exp $ + */ + +#include "cache.h" + @@ -0,0 +1,124 @@ +/* + * $Id: cache.h,v 1.1 2004/06/05 01:40:13 lordjaxom Exp $ + */ + +#ifndef VDR_TEXT2SKIN_CACHE_HPP +#define VDR_TEXT2SKIN_CACHE_HPP + +#include "common.h" + +// template class generic cache + +template<class K,class D> +class cText2SkinCache { +private: + struct Item { + K _key; + D _data; + time_t _lastUsed; + + Item *_next; + Item *_prev; + + Item() { _next = _prev = NULL; } + }; + + typedef map <K,Item*> DataMap; + + DataMap _items; + int _maxItems; + Item *_first; + Item *_last; + + void Unlink(Item *item); + void Update(Item *item); + void Delete(Item *item); + void Delete(K &key, D &data); + +public: + cText2SkinCache(int maxItems); + ~cText2SkinCache(); + + bool Contains(const K &key); + D &operator[](const K &key); +}; + +template<class K,class D> +inline void cText2SkinCache<K,D>::Unlink(Item *item) { + if (item == _first) { + _first = item->_next; + if (_first) + _first->_prev = NULL; + else + _last = NULL; + } else if (item == _last) { + _last = item->_prev; + _last->_next = NULL; + } else { + item->_prev->_next = item->_next; + item->_next->_prev = item->_prev; + } +} + +template<class K,class D> +inline void cText2SkinCache<K,D>::Delete(Item *item) { + Delete(item->_key, item->_data); + delete item; +} + +template<class K,class D> +inline void cText2SkinCache<K,D>::Delete(K &key, D &Data) { +} + +template<class K,class D> +inline void cText2SkinCache<K,D>::Update(Item *item) { + item->_lastUsed = time_ms(); + if (item->_next != NULL || item->_prev != NULL) + Unlink(item); + + item->_next = NULL; + item->_prev = _last; + if (_last) + _last->_next = item; + _last = item; + if (!_first) + _first = item; + + while ((int)_items.size() > _maxItems) { + Item *aged = _first; + _items.erase(aged->_key); + Unlink(aged); + Delete(aged); + } +} + +template<class K,class D> +inline bool cText2SkinCache<K,D>::Contains(const K &key) { + return (_items.find(key) != _items.end()); +} + +template<class K,class D> +cText2SkinCache<K,D>::cText2SkinCache(int maxItems) { + _maxItems = maxItems; + _first = _last = NULL; +} + +template<class K,class D> +cText2SkinCache<K,D>::~cText2SkinCache() { +} + +template<class K,class D> +D &cText2SkinCache<K,D>::operator[](const K &key) { + Item *item; + if (Contains(key)) { + item = _items[key]; + } else { + item = new Item; + item->_key = key; + _items[key] = item; + } + Update(item); + return item->_data; +} + +#endif // VDR_TEXT2SKIN_CACHE_HPP @@ -1,5 +1,5 @@ /* - * $Id: common.c,v 1.6 2004/06/02 20:43:05 lordjaxom Exp $ + * $Id: common.c,v 1.7 2004/06/05 16:52:44 lordjaxom Exp $ */ #include "data.h" @@ -10,73 +10,6 @@ const char *SkinPath(void) { return cPlugin::ConfigDirectory(PLUGIN_NAME_I18N); } -void DrawTextTransparent(cOsd *Osd, int x, int y, const char *s, tColor ColorFg, tColor ColorBg, const cFont *Font, int Width, int Height, int Alignment) { - 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; - } - } - } - while (s && *s) { - const cFont::tCharData *CharData = Font->CharData(*s++); - if (limit && int(x + CharData->width) > limit) - break; // we don't draw partial characters - if (int(x + CharData->width) > 0) { - for (int row = 0; row < h; row++) { - cFont::tPixelData PixelData = CharData->lines[row]; - for (int col = CharData->width; col-- > 0; ) { - if (PixelData & 1) - Osd->DrawRectangle(x + col, y + row, x + col, y + row, ColorFg); - PixelData >>= 1; - } - } - } - x += CharData->width; - } -} - -void DrawBitmap(cOsd *Osd, int x, int y, cBitmap &Bitmap, tColor ColorFg, tColor ColorBg) { - if (ColorFg || ColorBg) { - Bitmap.SetColor(0, ColorBg); - Bitmap.SetColor(1, ColorFg); - } - tColor fill = Bitmap.Color(*Bitmap.Data(0, 0)); // to be sure to grab a USED color - Osd->DrawRectangle(x, y, x + Bitmap.Width() - 1, y + Bitmap.Height() - 1, fill); // to be sure the palette is reset, if the Bitmap covers an Area - for (int iy = 0; iy < Bitmap.Height(); iy++) { - const tIndex *ptr = Bitmap.Data(0, iy); - for (int ix = 0; ix < Bitmap.Width(); ix++, ptr += sizeof(tIndex)) { - // DrawPixel is b0rked - //Osd->DrawPixel(x + ix, y + iy, Bitmap.Color(*ptr)); - Osd->DrawRectangle(x + ix, y + iy, x + ix, y + iy, Bitmap.Color(*ptr)); - } - } -} - const char *ChannelNumber(const cChannel *Channel, int Number) { static char buffer[256]; buffer[0] = '\0'; @@ -1,5 +1,5 @@ /* - * $Id: common.h,v 1.6 2004/06/02 20:43:05 lordjaxom Exp $ + * $Id: common.h,v 1.7 2004/06/05 16:52:44 lordjaxom Exp $ */ #ifndef VDR_TEXT2SKIN_COMMON_H @@ -14,14 +14,16 @@ using std::string; using std::vector; using std::map; -#define precond(x) if ((x)) { esyslog("ERROR: text2skin: "#x " not given"); return; } +#ifdef DEBUG +# define Dprintf(x...) fprintf(stderr, x); +#else +# define Dprintf(x...) +#endif class cChannel; class cText2SkinItem; const char *SkinPath(void); -void DrawTextTransparent(cOsd *Osd, int x, int y, const char *s, tColor ColorFg, tColor ColorBg, const cFont *Font, int Width, int Height, int Alignment); -void DrawBitmap(cOsd *Osd, int x, int y, cBitmap &Bitmap, tColor ColorFg = 0, tColor ColorBg = 0); const char *ChannelNumber(const cChannel *Channel, int Number); const char *ChannelName(const cChannel *Channel, int Number); @@ -1,13 +1,30 @@ /* - * $Id: data.c,v 1.12 2004/06/02 20:43:05 lordjaxom Exp $ + * $Id: data.c,v 1.13 2004/06/05 01:39:36 lordjaxom Exp $ */ #include "data.h" #include "common.h" static string SectionNames[__SECTION_COUNT__] = - { "Skin", "ChannelSmall", "Channel", "Volume", - "ReplayMode", "Replay", "Message", "Menu" }; + { "Skin", "ChannelSmall", "Channel", "Volume", "ReplayMode", "Replay", + "Message", "Menu" }; + +static string ItemNames[__ITEM_COUNT__] = + { "Unknown", "Skin", "Background", "Text", "Image", "Rectangle", "Ellipse", + "Slope", "DateTime", "Date", "Time", "ChannelLogo", "ChannelNumberName", + "ChannelNumber", "ChannelName", "Language", "Timebar", "PresentTime", + "PresentTitle", "PresentShortText", "FollowingTime", "FollowingTitle", + "FollowingShortText", "SymbolTeletext", "SymbolAudio", "SymbolDolby", + "SymbolEncrypted", "SymbolRecording", "SymbolRadio", "Volumebar", "Mute", + "Replaybar", "ReplayTitle", "ReplayCurrent", "ReplayTotal", "ReplayJump", + "SymbolPlay", "SymbolPause", "SymbolFastFwd", "SymbolFastRew", + "SymbolSlowFwd", "SymbolSlowRew", "MessageStatus", "MessageInfo", + "MessageWarning", "MessageError", "MenuArea", "MenuItem", "MenuCurrent", + "MenuTitle", "MenuRed", "MenuGreen", "MenuYellow", "MenuBlue", "MenuText", + "SymbolScrollUp", "SymbolScrollDown", "MenuEventTitle", + "MenuEventShortText", "MenuEventDescription", "MenuEventTime", + "SymbolEventRunning", "SymbolEventTimer", "SymbolEventVPS", + "MenuRecording" }; cText2SkinItem::cText2SkinItem(void) { mItem = itemUnknown; @@ -17,40 +34,17 @@ cText2SkinItem::cText2SkinItem(void) { mSize.h = 0; mBpp = 4; mArc = 0; - //mFg = NULL; - //mBg = NULL; mFont = cFont::GetFont(fontOsd); mAlign = taDefault; } cText2SkinItem::~cText2SkinItem() { - //delete mBg; - //delete mFg; } bool cText2SkinItem::Parse(const char *Text) { char *text = strdup(Text); char *ptr = text; - /*ptr = text + strlen(text) - 1; - for (; ptr >= text && *ptr == ' '; --ptr) - *ptr = '\0'; - ptr = skipspace(text); - if (*ptr == '\0' || *ptr == '#') // empty line or comment - return true; - else if (*ptr == '[' && ptr[strlen(ptr)-1] == ']') { // section - ++ptr; - ptr[strlen(ptr)-1] = '\0'; - if (strcmp(ptr, "Channel") == 0) mParseSection = sectionChannel; - else if (strcmp(ptr, "ChannelSmall") == 0) mParseSection = sectionChannelSmall; - else if (strcmp(ptr, "Menu") == 0) mParseSection = sectionMenu; - else if (strcmp(ptr, "Volume") == 0) mParseSection = sectionVolume; - else if (strcmp(ptr, "ReplayMode") == 0) mParseSection = sectionReplayMode; - else if (strcmp(ptr, "Replay") == 0) mParseSection = sectionReplay; - else if (strcmp(ptr, "Message") == 0) mParseSection = sectionMessage; - return true; - }*/ - // check if this is an item string item; if (ParseVar(ptr, "Item", item)) { @@ -59,62 +53,19 @@ bool cText2SkinItem::Parse(const char *Text) { mItem = itemSkin; else esyslog("ERROR: text2skin: Skin doesn't contain Item=Skin keyphrase"); + } else { + int i; + // valid items begin at index two + for (i = 2; i < __ITEM_COUNT__; ++i) { + if (ItemNames[i] == item) { + mItem = (eSkinItem)i; + break; + } + } + if (i == __ITEM_COUNT__) + esyslog("ERROR: text2skin: %s is not a valid theme item\n", item.c_str()); } - else if (item == "Background") mItem = itemBackground; - else if (item == "ChannelLogo") mItem = itemChannelLogo; - else if (item == "Language") mItem = itemLanguage; - else if (item == "Text") mItem = itemText; - else if (item == "Image") mItem = itemImage; - else if (item == "DateTime") mItem = itemDateTime; - else if (item == "Date") mItem = itemDate; - else if (item == "Time") mItem = itemTime; - else if (item == "ChannelNumberName") mItem = itemChannelNumberName; - else if (item == "ChannelNumber") mItem = itemChannelNumber; - else if (item == "ChannelName") mItem = itemChannelName; - else if (item == "Rectangle") mItem = itemRectangle; - else if (item == "Ellipse") mItem = itemEllipse; - else if (item == "Slope") mItem = itemSlope; - else if (item == "Timebar") mItem = itemTimebar; - else if (item == "PresentTime") mItem = itemPresentTime; - else if (item == "PresentTitle") mItem = itemPresentTitle; - else if (item == "PresentShortText") mItem = itemPresentShortText; - else if (item == "FollowingTime") mItem = itemFollowingTime; - else if (item == "FollowingTitle") mItem = itemFollowingTitle; - else if (item == "FollowingShortText") mItem = itemFollowingShortText; - else if (item == "SymbolTeletext") mItem = itemSymbolTeletext; - else if (item == "SymbolAudio") mItem = itemSymbolAudio; - else if (item == "SymbolDolby") mItem = itemSymbolDolby; - else if (item == "SymbolEncrypted") mItem = itemSymbolEncrypted; - else if (item == "SymbolRecording") mItem = itemSymbolRecording; - else if (item == "SymbolRadio") mItem = itemSymbolRadio; - else if (item == "Volumebar") mItem = itemVolumebar; - else if (item == "Mute") mItem = itemMute; - else if (item == "Replaybar") mItem = itemReplaybar; - else if (item == "ReplayTitle") mItem = itemReplayTitle; - else if (item == "ReplayCurrent") mItem = itemReplayCurrent; - else if (item == "ReplayTotal") mItem = itemReplayTotal; - else if (item == "ReplayJump") mItem = itemReplayJump; - else if (item == "SymbolPlay") mItem = itemSymbolPlay; - else if (item == "SymbolPause") mItem = itemSymbolPause; - else if (item == "SymbolFastFwd") mItem = itemSymbolFastFwd; - else if (item == "SymbolFastRew") mItem = itemSymbolFastRew; - else if (item == "SymbolSlowFwd") mItem = itemSymbolSlowFwd; - else if (item == "SymbolFastFwd") mItem = itemSymbolFastFwd; - else if (item == "MessageStatus") mItem = itemMessageStatus; - else if (item == "MessageInfo") mItem = itemMessageInfo; - else if (item == "MessageWarning") mItem = itemMessageWarning; - else if (item == "MessageError") mItem = itemMessageError; - else if (item == "MenuArea") mItem = itemMenuArea; - else if (item == "MenuItem") mItem = itemMenuItem; - else if (item == "MenuCurrent") mItem = itemMenuCurrent; - else if (item == "MenuTitle") mItem = itemMenuTitle; - else if (item == "MenuRed") mItem = itemMenuRed; - else if (item == "MenuGreen") mItem = itemMenuGreen; - else if (item == "MenuYellow") mItem = itemMenuYellow; - else if (item == "MenuBlue") mItem = itemMenuBlue; - else - esyslog("ERROR: text2skin: %s is not a valid theme item\n", item.c_str()); - + if (mItem != itemUnknown) { if (mItem != itemSkin) ParseItem(ptr); @@ -1,5 +1,5 @@ /* - * $Id: data.h,v 1.10 2004/06/02 20:43:05 lordjaxom Exp $ + * $Id: data.h,v 1.11 2004/06/05 01:39:36 lordjaxom Exp $ */ #ifndef VDR_TEXT2SKIN_DATA_H @@ -80,6 +80,18 @@ enum eSkinItem { itemMenuGreen, itemMenuYellow, itemMenuBlue, + itemMenuText, + itemSymbolScrollUp, + itemSymbolScrollDown, + itemMenuEventTitle, + itemMenuEventShortText, + itemMenuEventDescription, + itemMenuEventTime, + itemSymbolEventRunning, + itemSymbolEventTimer, + itemSymbolEventVPS, + itemMenuRecording, + __ITEM_COUNT__ }; struct POINT { @@ -124,8 +136,6 @@ public: const SIZE &Size(void) const { return mSize; } int Bpp(void) const { return mBpp; } int Arc(void) const { return mArc; } - //const tColor *Fg(void) const { return mFg; } - //const tColor *Bg(void) const { return mBg; } const string &Fg(void) const { return mFg; } const string &Bg(void) const { return mBg; } const cFont *Font(void) const { return mFont; } @@ -1,5 +1,5 @@ /* - * $Id: display.c,v 1.9 2004/06/02 20:43:05 lordjaxom Exp $ + * $Id: display.c,v 1.12 2004/06/05 18:04:29 lordjaxom Exp $ */ #include "render.h" @@ -81,6 +81,7 @@ void cText2SkinDisplayVolume::Flush(void) { // --- cText2SkinDisplayReplay ------------------------------------------------ cText2SkinDisplayReplay::cText2SkinDisplayReplay(cText2SkinData *Data, cText2SkinI18n *I18n, cText2SkinTheme *Theme, bool ModeOnly) { + Dprintf("ModeOnly: %d\n", ModeOnly); mRender = new cText2SkinRender(Data, I18n, Theme, ModeOnly ? sectionReplayMode : sectionReplay); mDirty = false; } @@ -98,7 +99,7 @@ void cText2SkinDisplayReplay::SetTitle(const char *Title) { } void cText2SkinDisplayReplay::SetMode(bool Play, bool Forward, int Speed) { - if (mRender->mReplayPlay != Play || mRender->mReplayPlay != Forward || mRender->mReplaySpeed != Speed) { + if (mRender->mReplayPlay != Play || mRender->mReplayForward != Forward || mRender->mReplaySpeed != Speed) { mRender->mReplayPlay = Play; mRender->mReplayForward = Forward; mRender->mReplaySpeed = Speed; @@ -209,7 +210,15 @@ cText2SkinDisplayMenu::~cText2SkinDisplayMenu() { void cText2SkinDisplayMenu::Clear(void) { mRender->mMenuItems.clear(); - mRender->mMenuCurrent = -1; + mRender->mMenuTitle = ""; + mRender->mMenuCurrent = -1; + mRender->mMenuRed = ""; + mRender->mMenuGreen = ""; + mRender->mMenuYellow = ""; + mRender->mMenuBlue = ""; + mRender->mMenuEvent = NULL; + mRender->mMenuRecording = NULL; + mRender->mMenuText = ""; mDirty = true; } @@ -245,7 +254,17 @@ void cText2SkinDisplayMenu::SetMessage(eMessageType Type, const char *Text) { } void cText2SkinDisplayMenu::SetItem(const char *Text, int Index, bool Current, bool Selectable) { - cText2SkinRender::MenuItem item = { Text, Selectable }; + cText2SkinRender::MenuItem item; + item.text = Text; + item.sel = Selectable; + for (int i = 0; i < MaxTabs; ++i) { + const char *tab = GetTabbedText(Text, i); + if (tab) + item.tabs[i] = tab; + if (!Tab(i + 1)) + break; + } + SetEditableWidth(mRender->GetEditableWidth(item, Current)); if ((int)mRender->mMenuItems.size() <= Index) { mRender->mMenuItems.push_back(item); mDirty = true; @@ -282,6 +301,25 @@ void cText2SkinDisplayMenu::SetText(const char *Text, bool FixedFont) { } } +void cText2SkinDisplayMenu::SetTabs(int Tab1, int Tab2, int Tab3, int Tab4, int Tab5) { + cSkinDisplayMenu::SetTabs(Tab1, Tab2, Tab3, Tab4, Tab5); + 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); +} + +void cText2SkinDisplayMenu::Scroll(bool Up, bool Page) { + if (mRender->mScroller && (Up ? mRender->mScroller->CanScrollUp() : mRender->mScroller->CanScrollDown())) { + mRender->mMenuScroll = true; + mRender->mMenuScrollUp = Up; + mRender->mMenuScrollPage = Page; + mDirty = true; + } +} + void cText2SkinDisplayMenu::Flush(void) { if (mDirty) { mRender->Flush(); @@ -1,5 +1,5 @@ /* - * $Id: display.h,v 1.3 2004/06/02 20:43:05 lordjaxom Exp $ + * $Id: display.h,v 1.5 2004/06/05 18:04:29 lordjaxom Exp $ */ #ifndef VDR_TEXT2SKIN_SKIN_H @@ -89,6 +89,8 @@ public: virtual void SetEvent(const cEvent *Event); virtual void SetRecording(const cRecording *Recording); virtual void SetText(const char *Text, bool FixedFont); + virtual void SetTabs(int Tab1, int Tab2, int Tab3, int Tab4, int Tab5); + virtual void Scroll(bool Up, bool Page); virtual void Flush(void); }; @@ -1,5 +1,5 @@ /* - * $Id: i18n.c,v 1.1 2004/06/02 20:43:05 lordjaxom Exp $ + * $Id: i18n.c,v 1.2 2004/06/05 16:52:44 lordjaxom Exp $ */ #include "i18n.h" @@ -24,12 +24,20 @@ bool cText2SkinI18n::Parse(const char *Text) { memset(&p, 0, sizeof(tI18nPhrase)); Text += 17; + for (i = 0; i < I18nNumLanguages; ++i) { + char *langs = strdup(I18nLanguageCode(i)); + char *ptr = langs, *ep; string text; - if (ParseVar(Text, I18nLanguageCode(i), text)) - p[i] = strdup(text.c_str()); - else - p[i] = ""; + p[i] = ""; + do { + if ((ep = strchr(ptr, ',')) != NULL) + *ep = '\0'; + if (ParseVar(Text, ptr, text)) + p[i] = strdup(text.c_str()); + ptr = ep + 1; + } while (ep != NULL); + free(langs); } int idx = mNumPhrases++; @@ -1,5 +1,5 @@ /* - * $Id: loader.c,v 1.6 2004/06/02 20:43:05 lordjaxom Exp $ + * $Id: loader.c,v 1.8 2004/06/05 16:52:44 lordjaxom Exp $ */ #include "loader.h" @@ -34,9 +34,8 @@ void cText2SkinLoader::Load(const char *Skin) { string transfile = (string)SkinPath() + "/" + Skin + "/" + Skin + ".trans"; if (access(transfile.c_str(), F_OK) == 0) { translations = new cText2SkinI18n(Skin); - if (!translations->Load(transfile)) { + if (!translations->Load(transfile)) DELETENULL(translations); - } } cText2SkinTheme *theme = new cText2SkinTheme(Skin); @@ -74,7 +73,7 @@ cText2SkinLoader::~cText2SkinLoader() { } cSkinDisplayChannel *cText2SkinLoader::DisplayChannel(bool WithInfo) { - printf("WithInfo: %d\n", WithInfo); + Dprintf("WithInfo: %d\n", WithInfo); return new cText2SkinDisplayChannel(mData, mI18n, mTheme, WithInfo); } diff --git a/patches/vdr-1.3.9-osd.diff b/patches/vdr-1.3.9-osd.diff new file mode 100644 index 0000000..0da295b --- /dev/null +++ b/patches/vdr-1.3.9-osd.diff @@ -0,0 +1,106 @@ +diff -Nru -x PLUGINS o/vdr-1.3.9/osd.c vdr-1.3.9/osd.c +--- o/vdr-1.3.9/osd.c 2004-05-28 17:33:22.000000000 +0200 ++++ vdr-1.3.9/osd.c 2004-06-05 17:25:33.036994648 +0200 +@@ -244,7 +246,7 @@ + return Result; + } + +-bool cBitmap::SetXpm(char *Xpm[]) ++bool cBitmap::SetXpm(char *Xpm[], bool IgnoreNone) + { + char **p = Xpm; + int w, h, n, c; +@@ -257,10 +259,11 @@ + return false; + } + int b = 0; +- while (1 << (1 << b) < n) ++ while (1 << (1 << b) < (IgnoreNone ? n - 1 : n)) + b++; + SetBpp(1 << b); + SetSize(w, h); ++ int NoneColorIndex = MAXNUMCOLORS; + for (int i = 0; i < n; i++) { + const char *s = *++p; + if (int(strlen(s)) < c) { +@@ -273,14 +276,18 @@ + return false; + } + s = skipspace(s + 1); +- if (strcasecmp(s, "none") == 0) +- s = "#00000000"; ++ if (strcasecmp(s, "none") == 0) { ++ s = "#00000000"; ++ NoneColorIndex = i; ++ if (IgnoreNone) ++ continue; ++ } + if (*s != '#') { + esyslog("ERROR: unknown color code in XPM: '%c'", *s); + return false; + } + tColor color = strtoul(++s, NULL, 16) | 0xFF000000; +- SetColor(i, color); ++ SetColor((IgnoreNone && i > NoneColorIndex) ? i - 1 : i, color); + } + for (int y = 0; y < h; y++) { + const char *s = *++p; +@@ -295,13 +302,17 @@ + return false; + } + if (strncmp(Xpm[i + 1], s, c) == 0) { +- SetIndex(x, y, i); ++ if (i == NoneColorIndex) ++ NoneColorIndex = MAXNUMCOLORS; ++ SetIndex(x, y, (IgnoreNone && i > NoneColorIndex) ? i - 1 : i); + break; + } + } + s += c; + } + } ++ if (NoneColorIndex < MAXNUMCOLORS && !IgnoreNone) ++ return SetXpm(Xpm, true); + return true; + } + +@@ -354,7 +365,8 @@ + int ch = Height ? Height : h; + if (!Intersects(x, y, x + cw - 1, y + ch - 1)) + return; +- DrawRectangle(x, y, x + cw - 1, y + ch - 1, ColorBg); ++ if (ColorBg != clrTransparent) ++ DrawRectangle(x, y, x + cw - 1, y + ch - 1, ColorBg); + limit = x + cw - x0; + if (Width) { + if ((Alignment & taLeft) != 0) +@@ -395,7 +408,8 @@ + for (int row = 0; row < h; row++) { + cFont::tPixelData PixelData = CharData->lines[row]; + for (int col = CharData->width; col-- > 0; ) { +- SetIndex(x + col, y + row, (PixelData & 1) ? fg : bg); ++ if (ColorBg != clrTransparent || (PixelData & 1)) ++ SetIndex(x + col, y + row, (PixelData & 1) ? fg : bg); + PixelData >>= 1; + } + } +diff -Nru -x PLUGINS o/vdr-1.3.9/osd.h vdr-1.3.9/osd.h +--- o/vdr-1.3.9/osd.h 2004-05-29 16:02:47.000000000 +0200 ++++ vdr-1.3.9/osd.h 2004-06-05 17:15:17.809523440 +0200 +@@ -136,9 +136,15 @@ + bool LoadXpm(const char *FileName); + ///< Calls SetXpm() with the data from the file FileName. + ///< Returns true if the operation was successful. +- bool SetXpm(char *Xpm[]); ++ bool SetXpm(char *Xpm[], bool IgnoreNone = false); + ///< Sets this bitmap to the given XPM data. Any previous bitmap or + ///< palette data will be overwritten with the new data. ++ ///< If IgnoreNone is true, a "none" color entry will be ignored. ++ ///< Only set IgnoreNone to true if you know that there is a "none" ++ ///< color entry in the XPM data and that this entry is not used! ++ ///< If SetXpm() is called with IgnoreNone set to false and the XPM ++ ///< data contains an unused "none" entry, it will be automatically ++ ///< called again with IgnoreNone set to true. + ///< Returns true if the operation was successful. + void SetIndex(int x, int y, tIndex Index); + ///< Sets the index at the given coordinates to Index. @@ -1,5 +1,5 @@ /* - * $Id: render.c,v 1.16 2004/06/02 20:43:05 lordjaxom Exp $ + * $Id: render.c,v 1.19 2004/06/05 18:04:29 lordjaxom Exp $ */ #include "render.h" @@ -18,6 +18,7 @@ cText2SkinRender::cText2SkinRender(cText2SkinData *Data, cText2SkinI18n *I18n, c mTheme = Theme; mSection = Section; mOsd = cOsdProvider::NewOsd(Setup.OSDLeft, Setup.OSDTop); + mScroller = NULL; mChannel = NULL; mChannelNumber = 0; mVolumeCurrent = 0; @@ -36,6 +37,9 @@ cText2SkinRender::cText2SkinRender(cText2SkinData *Data, cText2SkinI18n *I18n, c mMenuEvent = NULL; mMenuRecording = NULL; mMenuTextFixedFont = false; + mMenuScroll = false; + mMenuScrollUp = false; + mMenuScrollPage = false; cText2SkinData::tIterator it = Data->First(mSection); for (; it != Data->Last(mSection); ++it) { @@ -81,6 +85,7 @@ cText2SkinRender::cText2SkinRender(cText2SkinData *Data, cText2SkinI18n *I18n, c } cText2SkinRender::~cText2SkinRender() { + delete mScroller; delete mOsd; } @@ -143,6 +148,11 @@ void cText2SkinRender::Flush(void) { case itemSymbolFastRew: case itemSymbolSlowFwd: case itemSymbolSlowRew: + case itemSymbolScrollUp: + case itemSymbolScrollDown: + case itemSymbolEventRunning: + case itemSymbolEventTimer: + case itemSymbolEventVPS: DisplaySymbol(item); break; case itemVolumebar: DisplayVolumebar(item); break; @@ -172,6 +182,18 @@ void cText2SkinRender::Flush(void) { case itemMenuYellow: case itemMenuBlue: DisplayMenuColorbutton(item); break; + case itemMenuText: + DisplayMenuText(item); break; + case itemMenuEventTitle: + DisplayMenuEventTitle(item); break; + case itemMenuEventShortText: + DisplayMenuEventShortText(item); break; + case itemMenuEventDescription: + DisplayMenuEventDescription(item); break; + case itemMenuEventTime: + DisplayMenuEventTime(item); break; + case itemMenuRecording: + DisplayMenuRecording(item); break; default: break; } @@ -180,41 +202,39 @@ void cText2SkinRender::Flush(void) { } void cText2SkinRender::DrawBackground(const POINT &Pos, const SIZE &Size, const tColor *Bg, const tColor *Fg, const string &Path) { - bool image = false; - cText2SkinBitmap bm; + cText2SkinBitmap *bmp = NULL; if (Path != "") { char *p; asprintf(&p, "%s/%s/%s", SkinPath(), mData->Skin().c_str(), Path.c_str()); - if (bm.Load(p)) { - if (Bg) bm.SetColor(0, *Bg); - if (Fg) bm.SetColor(1, *Fg); - image = true; + if ((bmp = cText2SkinBitmap::Load(p)) != NULL) { + if (Bg) bmp->SetColor(0, *Bg); + if (Fg) bmp->SetColor(1, *Fg); } free(p); } - if (image) - DrawBitmap(mOsd, Pos.x, Pos.y, bm); + if (bmp) + mOsd->DrawBitmap(Pos.x, Pos.y, *bmp); else mOsd->DrawRectangle(Pos.x, Pos.y, Pos.x + Size.w - 1, Pos.y + Size.h - 1, Bg ? *Bg : 0); } void cText2SkinRender::DrawImage(const POINT &Pos, const SIZE &Size, const tColor *Bg, const tColor *Fg, const string &Path) { - cText2SkinBitmap bm; + cText2SkinBitmap *bmp; char *p; asprintf(&p, "%s/%s/%s", SkinPath(), mData->Skin().c_str(), Path.c_str()); - printf("Trying to load image: %s\n", p); - if (bm.Load(p)) { - if (Bg) bm.SetColor(0, *Bg); - if (Fg) bm.SetColor(1, *Fg); + Dprintf("Trying to load image: %s\n", p); + if ((bmp = cText2SkinBitmap::Load(p)) != NULL) { + if (Bg) bmp->SetColor(0, *Bg); + if (Fg) bmp->SetColor(1, *Fg); //mOsd->DrawRectangle(Pos.x, Pos.y, Pos.x + Size.w - 1, Pos.y + Size.h - 1, bm.Color(0)); - DrawBitmap(mOsd, Pos.x, Pos.y, bm); + mOsd->DrawBitmap(Pos.x, Pos.y, *bmp); } free(p); } void cText2SkinRender::DrawText(const POINT &Pos, const SIZE &Size, const tColor *Fg, const string &Text, const cFont *Font, int Align) { - DrawTextTransparent(mOsd, Pos.x, Pos.y, Text.c_str(), Fg ? *Fg : 0, 0, Font, Size.w, Size.h, Align); + mOsd->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) { @@ -300,6 +320,15 @@ void cText2SkinRender::DrawMark(const POINT &Pos, const SIZE &Size, bool Start, } } +void cText2SkinRender::DrawScrollText(const POINT &Pos, const SIZE &Size, const tColor *Fg, const string &Text, const cFont *Font, int Align) { + if (mScroller == NULL) + mScroller = new cTextScroller(mOsd, 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; + } +} + void cText2SkinRender::DisplayBackground(cText2SkinItem *Item) { DrawBackground(Item->Pos(), Item->Size(), ItemBg(Item), ItemFg(Item), Item->Path()); } @@ -315,13 +344,13 @@ void cText2SkinRender::DisplayLanguage(cText2SkinItem *Item) { int current; const char **tracks = cDevice::PrimaryDevice()->GetAudioTracks(¤t); if (Item->Path() != "" && Item->Type() != "" && tracks) { - printf("Languages: "); + Dprintf("Languages: "); int i = 0; while (tracks[i]) { - printf("%s%s, ", tracks[i], i == current ? " (current)" : ""); + Dprintf("%s%s, ", tracks[i], i == current ? " (current)" : ""); ++i; } - printf("\n"); + Dprintf("\n"); if (current < i) { string path = Item->Path() + "/" + tracks[current] + "." + Item->Type(); DrawImage(Item->Pos(), Item->Size(), ItemBg(Item), ItemFg(Item), path); @@ -444,22 +473,45 @@ void cText2SkinRender::DisplaySymbol(cText2SkinItem *Item) { default: break; } - } else if (mSection == sectionReplay) { + } else if (mSection == sectionReplay || mSection == sectionReplayMode) { switch (Item->Item()) { - case itemSymbolPlay: - image = (mReplaySpeed == -1 && mReplayPlay) ? Item->Path() : Item->AltPath(); break; - case itemSymbolPause: - image = (mReplaySpeed == -1 && !mReplayPlay) ? Item->Path() : Item->AltPath(); break; - case itemSymbolFastFwd: - image = (mReplayPlay && mReplayForward) ? Item->Path() : Item->AltPath(); break; - case itemSymbolFastRew: - image = (mReplayPlay && !mReplayForward) ? Item->Path() : Item->AltPath(); break; - case itemSymbolSlowFwd: - image = (!mReplayPlay && mReplayForward) ? Item->Path() : Item->AltPath(); break; - case itemSymbolSlowRew: - image = (!mReplayPlay && !mReplayForward) ? Item->Path() : Item->AltPath(); break; + case itemSymbolPlay: + image = (mReplaySpeed == -1 && mReplayPlay) ? Item->Path() : Item->AltPath(); break; + case itemSymbolPause: + image = (mReplaySpeed == -1 && !mReplayPlay) ? Item->Path() : Item->AltPath(); break; + case itemSymbolFastFwd: + image = (mReplaySpeed != -1 && mReplayPlay && mReplayForward) ? Item->Path() : Item->AltPath(); break; + case itemSymbolFastRew: + image = (mReplaySpeed != -1 && mReplayPlay && !mReplayForward) ? Item->Path() : Item->AltPath(); break; + case itemSymbolSlowFwd: + image = (mReplaySpeed != -1 && !mReplayPlay && mReplayForward) ? Item->Path() : Item->AltPath(); break; + case itemSymbolSlowRew: + image = (mReplaySpeed != -1 && !mReplayPlay && !mReplayForward) ? Item->Path() : Item->AltPath(); break; + default: + break; + } + } else if (mSection == sectionMenu) { + if (mScroller) { + switch (Item->Item()) { + case itemSymbolScrollUp: + image = mScroller->CanScrollUp() ? Item->Path() : Item->AltPath(); break; + case itemSymbolScrollDown: + image = mScroller->CanScrollDown() ? Item->Path() : Item->AltPath(); break; + default: + break; + } + } + if (mMenuEvent) { + switch (Item->Item()) { + case itemSymbolEventRunning: + image = mMenuEvent->IsRunning() ? Item->Path() : Item->AltPath(); break; + case itemSymbolEventTimer: + image = mMenuEvent->HasTimer() ? Item->Path() : Item->AltPath(); break; + case itemSymbolEventVPS: + image = mMenuEvent->Vps() > 0 ? Item->Path() : Item->AltPath(); break; default: break; + } } } if (image != "") @@ -543,21 +595,26 @@ void cText2SkinRender::DisplayMenuItems(cText2SkinItem *Item) { int index = 0; while (yoffs < area->Pos().y + area->Size().h && index < (int)mMenuItems.size()) { - if (index == mMenuCurrent) { - POINT pt = { xoffs, yoffs }; - if (current->Pos().x != -1) - pt.x += current->Pos().x; - if (current->Pos().y != -1) - pt.y += current->Pos().y; - SIZE size = { current->Size().w, current->Size().h }; - if (ItemBg(current)) - DrawRectangle(pt, size, ItemBg(current)); - DrawText(pt, size, ItemFg(current), mMenuItems[index].name.c_str(), current->Font(), current->Align()); - } else { - POINT pt = { xoffs + Item->Pos().x, yoffs + Item->Pos().y }; - SIZE size = { Item->Size().w, Item->Size().h }; - DrawText(pt, size, ItemFg(Item), mMenuItems[index].name.c_str(), Item->Font(), Item->Align()); + cText2SkinItem *item = (index == mMenuCurrent) ? current : Item; + POINT pt = { xoffs, yoffs }; + SIZE size = item->Size(); + if (item->Pos().x != -1) + pt.x += item->Pos().x; + if (item->Pos().y != -1) + pt.y += item->Pos().y; + if (ItemBg(item)) + DrawRectangle(pt, size, ItemBg(item)); + + for (int i = 0; i < cSkinDisplayMenu::MaxTabs; ++i) { + if (mMenuItems[index].tabs[i] != "") { + POINT pt2 = { pt.x + mMenuTabs[i], pt.y }; + SIZE sz = { size.w - mMenuTabs[i], size.h }; + DrawText(pt2, sz, ItemFg(item), mMenuItems[index].tabs[i], item->Font(), item->Align()); + } + if (!mMenuTabs[i + 1]) + break; } + yoffs += Item->Size().h; ++index; } @@ -585,6 +642,40 @@ void cText2SkinRender::DisplayMenuColorbutton(cText2SkinItem *Item) { DrawText(Item->Pos(), Item->Size(), ItemFg(Item), ItemText(Item, text), Item->Font(), Item->Align()); } +void cText2SkinRender::DisplayMenuText(cText2SkinItem *Item) { + if (mMenuText != "") + DrawScrollText(Item->Pos(), Item->Size(), ItemFg(Item), ItemText(Item, mMenuText), Item->Font(), Item->Align()); + else + DELETENULL(mScroller); +} + +void cText2SkinRender::DisplayMenuEventTitle(cText2SkinItem *Item) { + if (mMenuEvent && mMenuEvent->Title()) + DrawText(Item->Pos(), Item->Size(), ItemFg(Item), ItemText(Item, mMenuEvent->Title()), Item->Font(), Item->Align()); +} + +void cText2SkinRender::DisplayMenuEventShortText(cText2SkinItem *Item) { + if (mMenuEvent && mMenuEvent->ShortText()) + DrawText(Item->Pos(), Item->Size(), ItemFg(Item), ItemText(Item, mMenuEvent->ShortText()), Item->Font(), Item->Align()); +} + +void cText2SkinRender::DisplayMenuEventDescription(cText2SkinItem *Item) { + if (mMenuEvent && mMenuEvent->Description()) + DrawScrollText(Item->Pos(), Item->Size(), ItemFg(Item), ItemText(Item, mMenuEvent->Description()), Item->Font(), Item->Align()); +} + +void cText2SkinRender::DisplayMenuEventTime(cText2SkinItem *Item) { + if (mMenuEvent) { + const char *text = DayDateTime(mMenuEvent->StartTime()); + DrawText(Item->Pos(), Item->Size(), ItemFg(Item), ItemText(Item, text + 10), Item->Font(), Item->Align()); + } +} + +void cText2SkinRender::DisplayMenuRecording(cText2SkinItem *Item) { + if (mMenuRecording) + DrawScrollText(Item->Pos(), Item->Size(), ItemFg(Item), ItemText(Item, mMenuRecording->Summary()), Item->Font(), Item->Align()); +} + string cText2SkinRender::ItemText(cText2SkinItem *Item) { return mI18n ? mI18n->Translate(Item->Text()) : Item->Text(); } @@ -624,3 +715,12 @@ tColor *cText2SkinRender::ItemBg(cText2SkinItem *Item) { return NULL; return &Bg; } + +int cText2SkinRender::GetEditableWidth(MenuItem Item, bool Current) { + cText2SkinItem *current; + if (Current) + current = mData->Get(sectionMenu, itemMenuCurrent); + else + current = mData->Get(sectionMenu, itemMenuItem); + return current->Size().w - mMenuTabs[1]; +} @@ -1,5 +1,5 @@ /* - * $Id: render.h,v 1.12 2004/06/02 20:43:05 lordjaxom Exp $ + * $Id: render.h,v 1.15 2004/06/05 18:04:29 lordjaxom Exp $ */ #ifndef VDR_TEXT2SKIN_RENDER_H @@ -28,6 +28,7 @@ private: cText2SkinTheme *mTheme; eSkinSection mSection; cOsd *mOsd; + cTextScroller *mScroller; // channel display const cChannel *mChannel; @@ -58,9 +59,10 @@ private: // menu struct MenuItem { - string name; + string text; + string tabs[cSkinDisplayMenu::MaxTabs]; bool sel; - bool operator!=(const MenuItem &b) { return b.name != name || b.sel != sel; } + bool operator!=(const MenuItem &b) { return b.text != text || b.sel != sel; } }; string mMenuTitle; vector<MenuItem> mMenuItems; @@ -73,7 +75,11 @@ private: const cRecording *mMenuRecording; string mMenuText; bool mMenuTextFixedFont; - + bool mMenuScroll; + bool mMenuScrollUp; + bool mMenuScrollPage; + int mMenuTabs[cSkinDisplayMenu::MaxTabs]; + protected: // Basic operations void DrawBackground(const POINT &Pos, const SIZE &Size, const tColor *Bg, const tColor *Fg, const string &Path); @@ -84,6 +90,7 @@ protected: 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 cMarks *Marks = NULL); void DrawMark(const POINT &Pos, const SIZE &Size, bool Start, bool Current, bool Horizontal); + void DrawScrollText(const POINT &Pos, const SIZE &Size, const tColor *Fg, const string &Text, const cFont *Font, int Align); // High-level operations void DisplayBackground(cText2SkinItem *Item); @@ -119,13 +126,19 @@ protected: void DisplayMenuItems(cText2SkinItem *Item); void DisplayMenuTitle(cText2SkinItem *Item); void DisplayMenuColorbutton(cText2SkinItem *Item); - void DisplayMenuMessage(cText2SkinItem *Item); + void DisplayMenuText(cText2SkinItem *Item); + void DisplayMenuEventTitle(cText2SkinItem *Item); + void DisplayMenuEventShortText(cText2SkinItem *Item); + void DisplayMenuEventDescription(cText2SkinItem *Item); + void DisplayMenuEventTime(cText2SkinItem *Item); + void DisplayMenuRecording(cText2SkinItem *Item); // Helpers string ItemText(cText2SkinItem *Item); string ItemText(cText2SkinItem *Item, const string &Content); tColor *ItemFg(cText2SkinItem *Item); tColor *ItemBg(cText2SkinItem *Item); + int GetEditableWidth(MenuItem Item, bool Current); public: cText2SkinRender(cText2SkinData *Data, cText2SkinI18n *I18n, cText2SkinTheme *Theme, eSkinSection Section); diff --git a/text2skin.c b/text2skin.c index 68602d2..bd52294 100644 --- a/text2skin.c +++ b/text2skin.c @@ -3,26 +3,15 @@ * * See the README file for copyright information and how to reach the author. * - * $Id: text2skin.c,v 1.9 2004/06/02 19:55:55 lordjaxom Exp $ + * $Id: text2skin.c,v 1.10 2004/06/05 16:52:44 lordjaxom Exp $ */ +#include "text2skin.h" #include "loader.h" -#include <vdr/plugin.h> - -static const char *VERSION = "0.0.1-rc4"; -static const char *DESCRIPTION = "Loader for text-based skins"; - -class cText2SkinPlugin : public cPlugin { -private: -public: - cText2SkinPlugin(void); - virtual ~cText2SkinPlugin(); - virtual const char *Version(void) { return VERSION; } - virtual const char *Description(void) { return DESCRIPTION; } - virtual bool Start(void); - virtual cMenuSetupPage *SetupMenu(void); - virtual bool SetupParse(const char *Name, const char *Value); - }; + +const char *cText2SkinPlugin::VERSION = "0.0.1"; +const char *cText2SkinPlugin::THEMEVERSION = "0.0.1"; +const char *cText2SkinPlugin::DESCRIPTION = "Loader for text-based skins"; cText2SkinPlugin::cText2SkinPlugin(void) { diff --git a/text2skin.h b/text2skin.h new file mode 100644 index 0000000..a42faf1 --- /dev/null +++ b/text2skin.h @@ -0,0 +1,27 @@ +/* + * $Id: text2skin.h,v 1.2 2004/06/05 16:53:14 lordjaxom Exp $ + */ + +#ifndef VDR_TEXT2SKIN_H +#define VDR_TEXT2SKIN_H + +#include "common.h" +#include <vdr/plugin.h> + +class cText2SkinPlugin : public cPlugin { +private: + static const char *VERSION; + static const char *THEMEVERSION; + static const char *DESCRIPTION; +public: + cText2SkinPlugin(void); + virtual ~cText2SkinPlugin(); + virtual const char *Version(void) { return VERSION; } + virtual const char *ThemeVersion(void) { return THEMEVERSION; } + virtual const char *Description(void) { return DESCRIPTION; } + virtual bool Start(void); + virtual cMenuSetupPage *SetupMenu(void); + virtual bool SetupParse(const char *Name, const char *Value); +}; + +#endif // VDR_TEXT2SKIN_H |