diff options
author | Andreas Brugger <brougs78@gmx.net> | 2006-11-19 16:58:14 +0100 |
---|---|---|
committer | Thomas Günther <tom@toms-cafe.de> | 2009-06-03 03:35:58 +0200 |
commit | 74a5cc8e14900d48386e33cb576f154a6dd7e557 (patch) | |
tree | c7a90ba2fc5952558f6d4f528f94f8057f0d3ecd | |
parent | 8d32cf88bbe5b69a2710029cdaa896470a0fe20c (diff) | |
download | vdr-plugin-text2skin-74a5cc8e14900d48386e33cb576f154a6dd7e557.tar.gz vdr-plugin-text2skin-74a5cc8e14900d48386e33cb576f154a6dd7e557.tar.bz2 |
2006-11-19: Version 1.1-cvs_ext-0.9 (vdr-text2skin-1.1-cvs_ext-0.9.diff)
- added a test-feature to search for reruns of a program and add the
information to the extended epg-info (trigger DEVELOPMENT_FEATURES).
This uses a service-interface of the epgsearch-plugin
"Epgsearch-searchresults-v1.0"
- the timer-conflicts are now checked with epgsearch (service-interface
"Epgsearch-lastconflictinfo-v1.0", as it works more reliable and is
supported by the plugin author
- the extended epg-info and the recording-info are extended by AUX-Infos
(configurable)
there is also an option to strip known tags
- the tab-widths are scaled for taking into account that different TT-Fonts
have a different width than the default font from VDR
- added tokens for signal-info:
FrontendSTR, FrontendSNR, FrontendHasLock, FrontendHasSignal
- changed token TimerConflict to TimerConflicts
- added token PresentEventID for EPG-images
- added tokens for recordings:
RecordingFilename, RecordingPriority, RecordingLifetime
- removed Text2skin.diff from the rotor-plugin
-rw-r--r-- | HISTORY | 22 | ||||
-rw-r--r-- | Makefile | 9 | ||||
-rw-r--r-- | common.c | 178 | ||||
-rw-r--r-- | common.h | 45 | ||||
-rw-r--r-- | display.c | 92 | ||||
-rw-r--r-- | display.h | 2 | ||||
-rw-r--r-- | graphtft/font.c | 13 | ||||
-rw-r--r-- | i18n.c | 154 | ||||
-rw-r--r-- | menu.c | 23 | ||||
-rw-r--r-- | menu.h | 1 | ||||
-rw-r--r-- | render.c | 24 | ||||
-rw-r--r-- | setup.c | 12 | ||||
-rw-r--r-- | setup.h | 6 | ||||
-rw-r--r-- | status.c | 64 | ||||
-rw-r--r-- | status.h | 2 | ||||
-rw-r--r-- | text2skin.c | 32 | ||||
-rw-r--r-- | text2skin.h | 5 | ||||
-rw-r--r-- | xml/object.c | 6 | ||||
-rw-r--r-- | xml/object.h | 1 | ||||
-rw-r--r-- | xml/string.c | 7 | ||||
-rw-r--r-- | xml/string.h | 10 | ||||
-rw-r--r-- | xml/xml.c | 2 |
22 files changed, 635 insertions, 75 deletions
@@ -1,6 +1,28 @@ VDR Plugin 'text2skin' Revision History --------------------------------------- +2006-11-19: Version 1.1-cvs_ext-0.9 (vdr-text2skin-1.1-cvs_ext-0.9.diff) + +- added a test-feature to search for reruns of a program and add the + information to the extended epg-info (trigger DEVELOPMENT_FEATURES). + This uses a service-interface of the epgsearch-plugin + "Epgsearch-searchresults-v1.0" +- the timer-conflicts are now checked with epgsearch (service-interface + "Epgsearch-lastconflictinfo-v1.0", as it works more reliable and is + supported by the plugin author +- the extended epg-info and the recording-info are extended by AUX-Infos + (configurable) + there is also an option to strip known tags +- the tab-widths are scaled for taking into account that different TT-Fonts + have a different width than the default font from VDR +- added tokens for signal-info: + FrontendSTR, FrontendSNR, FrontendHasLock, FrontendHasSignal +- changed token TimerConflict to TimerConflicts +- added token PresentEventID for EPG-images +- added tokens for recordings: + RecordingFilename, RecordingPriority, RecordingLifetime +- removed Text2skin.diff from the rotor-plugin + 2006-02-04: Version 1.1-cvs_ext-0.8 (vdr-text2skin-1.1-cvs_ext-0.8.diff) - added a configuration option for showing the scrollbar in the menus and @@ -2,8 +2,11 @@ # 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) +#DEBUG=1 +#BENCH=1 + HAVE_IMAGEMAGICK=1 -#HAVE_IMLIB2=1 +#HAVE_IMLIB2=1 # not recommended # comment this out if you don't want to use FreeType font rendering @@ -62,6 +65,10 @@ OBJS = $(PLUGIN).o loader.o display.o render.o common.o bitmap.o \ ### Includes and Defines (add further entries here): +ifdef DEVELOPMENT_FEATURES + DEFINES += -DDEVELOPMENT_FEATURES +endif + ifdef HAVE_IMLIB2 DEFINES += -DHAVE_IMLIB2 LIBS += -lImlib2 @@ -3,7 +3,13 @@ */ #include "common.h" +#include <sstream> #include <vdr/plugin.h> +#include <vdr/device.h> +#include <sys/ioctl.h> +#include <linux/dvb/frontend.h> + +#define FRONTEND_DEVICE "/dev/dvb/adapter%d/frontend%d" const std::string &SkinPath(void) { @@ -69,6 +75,14 @@ const char *ChannelShortName(const cChannel *Channel, int Number) return buffer; } + +const char *EventType(uint Number) +{ + static char buffer[25]; + buffer[0] = '\0'; + snprintf(buffer, sizeof(buffer), "%d", Number); + return buffer; +} /* const char *ChannelBouquet(const cChannel *Channel, int Number) { static char buffer[256]; @@ -120,6 +134,137 @@ const cRecording *GetRecordingByFileName(const char *FileName) return (FileName) ? Recordings.GetByName(FileName) : NULL; } +int GetFrontendSTR(void) +{ + uint16_t value = 0; + char *dev = NULL; + + asprintf(&dev, FRONTEND_DEVICE, cDevice::ActualDevice()->CardIndex(), 0); + int fe = open(dev, O_RDONLY | O_NONBLOCK); + free(dev); + if (fe >= 0) { + CHECK(ioctl(fe, FE_READ_SIGNAL_STRENGTH, &value)); + close(fe); + } + return value / 655; +} + +int GetFrontendSNR(void) +{ + uint16_t value = 0; + char *dev = NULL; + + asprintf(&dev, FRONTEND_DEVICE, cDevice::ActualDevice()->CardIndex(), 0); + int fe = open(dev, O_RDONLY | O_NONBLOCK); + free(dev); + if (fe >= 0) { + CHECK(ioctl(fe, FE_READ_SNR, &value)); + close(fe); + } + return value / 655; +} + +bool GetFrontendHasLock(void) +{ + uint16_t value = 0; + char *dev = NULL; + + asprintf(&dev, FRONTEND_DEVICE, cDevice::ActualDevice()->CardIndex(), 0); + int fe = open(dev, O_RDONLY | O_NONBLOCK); + free(dev); + if (fe >= 0) { + CHECK(ioctl(fe, FE_READ_STATUS, &value)); + close(fe); + } + return value & FE_HAS_LOCK; +} + +bool GetFrontendHasSignal(void) +{ + uint16_t value = 0; + char *dev = NULL; + + asprintf(&dev, FRONTEND_DEVICE, cDevice::ActualDevice()->CardIndex(), 0); + int fe = open(dev, O_RDONLY | O_NONBLOCK); + free(dev); + if (fe >= 0) { + CHECK(ioctl(fe, FE_READ_STATUS, &value)); + close(fe); + } + return value & FE_HAS_SIGNAL; +} + +std::string AddExtInfoToDescription(const char *Title, const char *ShortText, const char *Description, const char *Aux, bool StripAux) +{ + // max. width so lines don't get wrapped + #define MAX_CHARS 50 + + // prepare the description + std::stringstream desc(""); + + if (!isempty(Description)) { + // it seems that sometimes the description ends with a newline + // and sometimes it does not + std::string buf(Description); + while (!buf.empty() && buf[buf.size() - 1] == '\n') buf.erase(buf.size() - 1); + desc << buf << "\n"; // keep one newline + } + +#ifdef DEVELOPMENT_FEATURES + // try to find a rerun of the show using epgsearch-service + if (!isempty(Title)) { + Epgsearch_searchresults_v1_0 data; + data.query = strdup(Title); + data.mode = 0; + data.channelNr = 0; + data.useTitle = true; + data.useSubTitle = false; + data.useDescription = false; + if (cPluginManager::CallFirstService("Epgsearch-searchresults-v1.0", &data)) { + cList<Epgsearch_searchresults_v1_0::cServiceSearchResult>* list = data.pResultList; + if (list) { + // die aktuelle Sendung wird noch als WH angezeigt !!! + if (!desc.str().empty()) desc << "\n"; + desc << tr("RERUNS OF THIS SHOW") << ":\n"; + int i = 0; + for (Epgsearch_searchresults_v1_0::cServiceSearchResult *r = + list->First(); r && i < 5; r = list->Next(r)) { + i++; + std::stringstream buf; + buf << " - "; + buf << *DayDateTime(r->event->StartTime()); + buf << ": " << r->event->Title(); + if (!isempty(r->event->ShortText())) buf << "~" << r->event->ShortText(); + desc << FitToWidth(buf, MAX_CHARS) << "\n"; + } + delete list; + } + } + } +#endif // DEVELOPMENT_FEATURES + + // Add the AUX-Info of the Recording + if (Aux) { + if (StripAux) { + std::string auxRaw(Aux); + std::string auxEpgsearch = StripXmlTag(auxRaw, "epgsearch"); + if (!auxEpgsearch.empty()) { + if (!desc.str().empty()) desc << "\n"; + desc << tr("AUXILIARY INFOS") << ":\n"; + std::stringstream buf; + buf << " - " << tr("Search timer") << ": " << StripXmlTag(auxRaw, "Search timer"); + desc << FitToWidth(buf, MAX_CHARS) << "\n"; + } + } else { + if (!desc.str().empty()) desc << "\n"; + desc << tr("AUXILIARY INFOS") << ":\n"; + desc << Aux << "\n"; + } + } + + return desc.str(); +} + int GetRecordingSize(const char *FileName) #if VDRVERSNUM >= 10338 // use VDR's routine @@ -404,3 +549,36 @@ void SkipQuotes(std::string &Value) { else esyslog("ERROR: text2skin: missing closing %c", quote); } + +std::string FitToWidth(std::string &Line, uint Width) { + std::string buf(Line); + if (buf.size() > Width) { + buf.erase(Width - 3); + buf.append("..."); + } + return buf; +} + +std::string FitToWidth(std::stringstream &Line, uint Width) { + std::string buf(Line.str()); + if (buf.size() > Width) { + buf.erase(Width - 3); + buf.append("..."); + } + return buf; +} + +std::string StripXmlTag(std::string &Line, const char *Tag) { + // set the search strings + std::stringstream strStart, strStop; + strStart << "<" << Tag << ">"; + strStop << "</" << Tag << ">"; + // find the strings + std::string::size_type locStart = Line.find(strStart.str()); + std::string::size_type locStop = Line.find(strStop.str()); + if (locStart == std::string::npos || locStop == std::string::npos) return ""; + // extract relevant text + int pos = locStart + strStart.str().size(); + int len = locStop - pos; + return len < 0 ? "" : Line.substr(pos, len); +} @@ -9,6 +9,7 @@ #include <string> #include <vdr/osd.h> #include <vdr/config.h> +#include <vdr/epg.h> #if defined(DEBUG) || defined(BENCH) # ifdef DEBUG @@ -24,6 +25,9 @@ # define Ddiff(t,x) #endif +#define DStartBench(x) uint64 bench_##x = time_ms() +#define DShowBench(t,x) fprintf(stderr, "%s took %llu ms\n", t, time_ms() - bench_##x) + #if VDRVERSNUM >= 10318 # define time_ms() cTimeMs::Now() # define Apid1() Apid(0) @@ -47,11 +51,17 @@ const std::string &SkinPath(void); const char *ChannelNumber(const cChannel *Channel, int Number); const char *ChannelName(const cChannel *Channel, int Number); const char *ChannelShortName(const cChannel *Channel, int Number); +const char *EventType(uint Number); //const char *ChannelBouquet(const cChannel *Channel, int Number); bool StoppedTimer(const char *Name); const cRecording *GetRecordingByName(const char *Name); const cRecording *GetRecordingByFileName(const char *FileName); +int GetFrontendSTR(void); // Signal strength [%] +int GetFrontendSNR(void); // Signal to Noise ratio [%] +bool GetFrontendHasLock(void); +bool GetFrontendHasSignal(void); +std::string AddExtInfoToDescription(const char *Title, const char *ShortText, const char *Description, const char *Aux = NULL, bool StripAux = false); int GetRecordingSize(const char *FileName); // [MB] int GetRecordingLength(const char *FileName); // [min] int GetRecordingCuttedLength(const char *FileName); // [min] @@ -63,5 +73,40 @@ 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); +std::string FitToWidth(std::string &Line, uint Width); +std::string FitToWidth(std::stringstream &Line, uint Width); +std::string StripXmlTag(std::string &Line, const char *Tag); + +// Data structure for service "Epgsearch-searchresults-v1.0" +struct Epgsearch_searchresults_v1_0 +{ +// in + char* query; // search term + int mode; // search mode (0=phrase, 1=and, 2=or, 3=regular expression) + int channelNr; // channel number to search in (0=any) + bool useTitle; // search in title + bool useSubTitle; // search in subtitle + bool useDescription; // search in description +// out + + class cServiceSearchResult : public cListObject + { + public: + const cEvent* event; + cServiceSearchResult(const cEvent* Event) : event(Event) {} + }; + + cList<cServiceSearchResult>* pResultList; // pointer to the results +}; + +// Data structure for service "Epgsearch-lastconflictinfo-v1.0" +struct Epgsearch_lastconflictinfo_v1_0 +{ +// in +// out + time_t nextConflict; // next conflict date, 0 if none + int relevantConflicts; // number of relevant conflicts + int totalConflicts; // total number of conflicts +}; #endif // VDR_TEXT2SKIN_COMMON_H @@ -10,6 +10,7 @@ #include "common.h" #include "xml/string.h" #include <vdr/menu.h> +#include <vdr/plugin.h> // --- cText2SkinDisplayChannel ----------------------------------------------- @@ -772,7 +773,9 @@ void cText2SkinDisplayMenu::Clear(void) mItems.clear(); mCurrentItem = (uint)-1; mEvent = NULL; + ExtPresentDescription = ""; mRecording = NULL; + ExtRecordingDescription = ""; mText = ""; cText2SkinRender::Clear(); SetDirty(); @@ -888,6 +891,7 @@ void cText2SkinDisplayMenu::SetEvent(const cEvent *Event) UpdateLock(); if (mEvent != Event) { mEvent = Event; + ExtPresentDescription = ""; if (mEvent != NULL) SetDirty(); } @@ -905,6 +909,7 @@ void cText2SkinDisplayMenu::SetRecording(const cRecording *Recording) // yet unused if (mRecording != Recording) { mRecording = Recording; + ExtRecordingDescription = ""; if (mRecording != NULL) SetDirty(); } @@ -1086,9 +1091,22 @@ cxType cText2SkinDisplayMenu::GetTokenData(const txToken &Token) : (cxType)false; case tPresentDescription: - return mEvent != NULL - ? (cxType)mEvent->Description() - : (cxType)false; + if (mEvent) { + if (ExtPresentDescription == "") { +#if VDRVERSNUM >= 10344 + // find corresponding timer + const char *aux = NULL; + for (cTimer *tim = Timers.First(); tim; tim = Timers.Next(tim)) { + if (tim->Event() == mEvent) aux = tim->Aux(); + } + ExtPresentDescription = AddExtInfoToDescription(mEvent->Title(), mEvent->ShortText(), mEvent->Description(), aux, Text2SkinSetup.StripAux); +#else + ExtPresentDescription = AddExtInfoToDescription(mEvent->Title(), mEvent->ShortText(), mEvent->Description()); +#endif + } + return (cxType)ExtPresentDescription; + } else + return (cxType)false; #if VDRVERSNUM >= 10318 case tPresentLanguageCode: @@ -1108,7 +1126,7 @@ cxType cText2SkinDisplayMenu::GetTokenData(const txToken &Token) { std::string buffer(c->language); if (c->type == 1) buffer.append("MONO"); - if (c->type == 2) buffer.append("DUAL"); + if ((c->type == 2) || (c->type == 4)) buffer.append("DUAL"); if (c->type == 5) buffer.append("DD"); return (cxType)buffer.c_str(); } @@ -1159,10 +1177,45 @@ cxType cText2SkinDisplayMenu::GetTokenData(const txToken &Token) return false; #endif + case tPresentEventID: + return mEvent != NULL + ? (cxType)EventType(mEvent->EventID()) + : (cxType)false; + case tHasVPS: case tChannelHasVPS: return mEvent != NULL && mEvent->Vps() != 0; + case tChannelName: + if (mEvent) { // extended EPG + cChannel *channel = Channels.GetByChannelID(mEvent->ChannelID(), true); + return channel != NULL + ? (cxType)ChannelName(channel, 0) + : (cxType)false; + } else if (mRecording) { // recording Info + cRecordingInfo *recInfo = const_cast<cRecordingInfo*>(mRecording->Info()); + tChannelID chID = recInfo->ChannelID(); + cChannel *channel = Channels.GetByChannelID(recInfo->ChannelID(), true); + return channel != NULL + ? (cxType)ChannelName(channel, 0) + : (cxType)false; + } else return (cxType)false; + + case tChannelShortName: + if (mEvent) { // extended EPG + cChannel *channel = Channels.GetByChannelID(mEvent->ChannelID(), true); + return channel != NULL + ? (cxType)ChannelShortName(channel, 0) + : (cxType)false; + } else if (mRecording) { // recording Info + cRecordingInfo *recInfo = const_cast<cRecordingInfo*>(mRecording->Info()); + tChannelID chID = recInfo->ChannelID(); + cChannel *channel = Channels.GetByChannelID(recInfo->ChannelID(), true); + return channel != NULL + ? (cxType)ChannelShortName(channel, 0) + : (cxType)false; + } else return (cxType)false; + case tPresentHasVPS: return mEvent != NULL && mEvent->Vps() != 0 && mEvent->Vps() != mEvent->StartTime(); @@ -1183,6 +1236,21 @@ cxType cText2SkinDisplayMenu::GetTokenData(const txToken &Token) ? (cxType)mRecording->Name() : (cxType)false; + case tRecordingFilename: + return mRecording != NULL + ? (cxType)mRecording->FileName() + : (cxType)false; + + case tRecordingPriority: + return mRecording != NULL + ? (cxType)mRecording->priority + : (cxType)false; + + case tRecordingLifetime: + return mRecording != NULL + ? (cxType)mRecording->lifetime + : (cxType)false; + case tRecordingDateTime: return mRecording != NULL ? (cxType)TimeType(mRecording->start, Token.Attrib.Text) @@ -1199,9 +1267,17 @@ cxType cText2SkinDisplayMenu::GetTokenData(const txToken &Token) : (cxType)false; case tRecordingDescription: - return mRecording != NULL - ? (cxType)mRecording->Info()->Description() - : (cxType)false; + if (mRecording) { + if (ExtRecordingDescription == "") { +#if VDRVERSNUM >= 10344 + ExtRecordingDescription = AddExtInfoToDescription(mRecording->Info()->Title(), mRecording->Info()->ShortText(), mRecording->Info()->Description(), Text2SkinSetup.ShowAux ? mRecording->Info()->Aux() : NULL, Text2SkinSetup.StripAux); +#else + ExtRecordingDescription = AddExtInfoToDescription(mRecording->Info()->Title(), mRecording->Info()->ShortText(), mRecording->Info()->Description()); +#endif + } + return (cxType)ExtRecordingDescription; + } else + return (cxType)false; case tRecordingLanguageCode: if (mRecording) @@ -1220,7 +1296,7 @@ cxType cText2SkinDisplayMenu::GetTokenData(const txToken &Token) { std::string buffer(c->language); if (c->type == 1) buffer.append("MONO"); - if (c->type == 2) buffer.append("DUAL"); + if ((c->type == 2) || (c->type == 4)) buffer.append("DUAL"); if (c->type == 5) buffer.append("DD"); return (cxType)buffer.c_str(); } @@ -142,8 +142,10 @@ private: // detailed event view const cEvent *mEvent; + std::string ExtPresentDescription; // detailed recording const cRecording *mRecording; + std::string ExtRecordingDescription; // long text std::string mText; diff --git a/graphtft/font.c b/graphtft/font.c index 7941b74..9cfa812 100644 --- a/graphtft/font.c +++ b/graphtft/font.c @@ -138,21 +138,22 @@ bool cGraphtftFont::Load(string Filename, string CacheName, int Size, int Langua //Load the char error = FT_Load_Glyph( _face, glyph_index, FT_LOAD_DEFAULT ); if ( error ) continue; /* ignore errors */ - - // convert to a mono bitmap - error = FT_Render_Glyph( _face->glyph, ft_render_mode_mono ); - if ( error ) continue; // now, convert to vdr font data int width = (_slot->metrics.horiAdvance / 64) + 1; int bearingX = (_slot->metrics.horiBearingX / 64) +1; width = (width > (int)sizeof(cFont::tPixelData) * 8) ? (((int)sizeof(cFont::tPixelData) * 8)-2) :width ; - int top = _slot->bitmap_top; - int y_off = Size - top; font_data[(num_char_array*num_rows)+0]=width; font_data[(num_char_array*num_rows)+1]=num_rows_global; + // convert to a mono bitmap + error = FT_Render_Glyph( _face->glyph, ft_render_mode_mono ); + if ( error ) continue; + + int top = _slot->bitmap_top; + int y_off = Size - top; + unsigned char *bmp = _slot->bitmap.buffer; for (int y = 0; y < _slot->bitmap.rows; ++y , y_off++) { @@ -104,6 +104,56 @@ const tI18nPhrase Phrases[] = { "", #endif }, + { "RERUNS OF THIS SHOW", + "WIEDERHOLUNGEN DIESER SENDUNG", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", +#if VDRVERSNUM >= 10313 + "", +#endif +#if VDRVERSNUM >= 10316 + "", +#endif + }, + { "Scale factor of the tab-widths [%]", + "Skalierungsfaktor für die Tabolatorweiten [%]", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", +#if VDRVERSNUM >= 10313 + "", +#endif +#if VDRVERSNUM >= 10316 + "", +#endif + }, { "Scrolling behaviour", "Scroll-Verhalten", "", @@ -179,8 +229,8 @@ const tI18nPhrase Phrases[] = { "", #endif }, - { "Use 'timeline' to check timer-conflicts", - "Timerkonflikte mit 'timeline' überprüfen", + { "Use 'epgsearch' to check timer-conflicts", + "Timerkonflikte mit 'epgsearch' überprüfen", "", "", "", @@ -254,6 +304,106 @@ const tI18nPhrase Phrases[] = { "", #endif }, + { "AUXILIARY INFOS", + "ZUSATZINFOS", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", +#if VDRVERSNUM >= 10313 + "", +#endif +#if VDRVERSNUM >= 10316 + "", +#endif + }, + { "Show auxiliary infos of recordings", + "Zusatzinfos der Aufnahmen anzeigen", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", +#if VDRVERSNUM >= 10313 + "", +#endif +#if VDRVERSNUM >= 10316 + "", +#endif + }, + { " Extract known tags", + " Bekannte Tags extrahieren", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", +#if VDRVERSNUM >= 10313 + "", +#endif +#if VDRVERSNUM >= 10316 + "", +#endif + }, + { "Search timer", + "Suchtimer", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", +#if VDRVERSNUM >= 10313 + "", +#endif +#if VDRVERSNUM >= 10316 + "", +#endif + }, { "Max. image cache size", "Max. Größe des Bildspeichers", "", @@ -9,14 +9,28 @@ cText2SkinSetupPage::cText2SkinSetupPage(void) { mData = Text2SkinSetup; + Setup(); +} + +void cText2SkinSetupPage::Setup(void) { + int current = Current(); + Clear(); + Add(new cMenuEditBoolItem(tr("Show scrollbar in the menus"), &mData.MenuScrollbar, tr("no"), tr("yes"))); Add(new cMenuEditBoolItem(tr("Scrolling behaviour"), &mData.MarqueeLeftRight, tr("to the left"), tr("left and right"))); Add(new cMenuEditBoolItem(tr("Reset Marquee for new item"), &mData.MarqueeReset, tr("no"), tr("yes"))); +#if VDRVERSNUM >= 10344 + Add(new cMenuEditBoolItem(tr("Show auxiliary infos of recordings"), &mData.ShowAux, tr("no"), tr("yes"))); + if (mData.ShowAux) Add(new cMenuEditBoolItem(tr(" Extract known tags"), &mData.StripAux, tr("no"), tr("yes"))); +#endif #if VDRVERSNUM >= 10330 Add(new cMenuEditBoolItem(tr("Use 'timeline' to check timer-conflicts"), &mData.CheckTimerConflict, tr("no"), tr("yes"))); #endif Add(new cOsdItem(tr("Flush image cache"), osUser1)); Add(new cMenuEditIntItem(tr("Max. image cache size"), &mData.MaxCacheFill)); + + SetCurrent(Get(current)); + Display(); } cText2SkinSetupPage::~cText2SkinSetupPage() { @@ -26,6 +40,10 @@ void cText2SkinSetupPage::Store(void) { SetupStore("MenuScrollbar", mData.MenuScrollbar); SetupStore("MarqueeLeftRight", mData.MarqueeLeftRight); SetupStore("MarqueeReset", mData.MarqueeReset); +#if VDRVERSNUM >= 10344 + SetupStore("ShowAux", mData.ShowAux); + SetupStore("StripAux", mData.StripAux); +#endif #if VDRVERSNUM >= 10330 SetupStore("CheckTimerConflict", mData.CheckTimerConflict); #endif @@ -34,6 +52,8 @@ void cText2SkinSetupPage::Store(void) { } eOSState cText2SkinSetupPage::ProcessKey(eKeys Key) { + int oldShowAux = mData.ShowAux; + eOSState state = cMenuSetupPage::ProcessKey(Key); if (state == osUser1) { Skins.Message(mtInfo, tr("Flushing image cache...")); @@ -41,6 +61,9 @@ eOSState cText2SkinSetupPage::ProcessKey(eKeys Key) { Skins.Message(mtInfo, NULL); return osContinue; } + + if (mData.ShowAux != oldShowAux) Setup(); + return state; } @@ -17,6 +17,7 @@ public: cText2SkinSetupPage(void); virtual ~cText2SkinSetupPage(); + void cText2SkinSetupPage::Setup(void); virtual void Store(void); eOSState ProcessKey(eKeys Key); }; @@ -145,15 +145,22 @@ void cText2SkinRender::Action(void) void cText2SkinRender::Update(void) { + //DStartBench(malen); + //DStartBench(ges); Dbench(update); for (uint i = 0; i < mDisplay->Objects(); ++i) DrawObject(mDisplay->GetObject(i)); + //DShowBench("---\t", malen); + //DStartBench(flushen); Dbench(flush); mScreen->Flush(); Ddiff("flush only", flush); Ddiff("complete flush", update); + //DShowBench("===\t", flushen); + //DShowBench("=== ges\t", ges); + //printf("====\t%d\n", mDisplay->Objects()); } void cText2SkinRender::DrawObject(const cxObject *Object) @@ -262,8 +269,17 @@ void cText2SkinRender::DrawObject(const cxObject *Object) else { // there is no "next tab", use the rightmost edge obj.mPos2.x += Object->mPos1.x; - SetEditableWidth(obj.Size().w); - //printf("EditableWidth von '%s': %d Pixels\n", obj.Text().c_str(), obj.Size().w); + if (obj.Type() == cxObject::text && t == 1) { + // VDR assumes, that the font in the menu is fontOsd, + // so the EditableWidth is not necessarily correct + // for TTF + const cFont *defFont = cFont::GetFont(fontOsd); + const char *dummy = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789 "; + int editableWidth = obj.Size().w; + if (defFont != obj.Font()) + editableWidth = (int)(editableWidth * defFont->Width(dummy) / (1.1 * obj.Font()->Width(dummy))); + SetEditableWidth(editableWidth); + } } obj.mPos2.y += Object->mPos1.y + yoffset; @@ -610,7 +626,9 @@ bool cText2SkinRender::ItemColor(const std::string &Color, tColor &Result) std::string cText2SkinRender::ImagePath(const std::string &Filename) { if (mRender) - return mRender->mBasePath + "/" + Filename; + return (*Filename.data() == '/') + ? Filename + : mRender->mBasePath + "/" + Filename; return ""; } @@ -12,7 +12,13 @@ cText2SkinSetup::cText2SkinSetup(void) { MenuScrollbar = false; MarqueeLeftRight = true; MarqueeReset = false; +#if VDRVERSNUM >= 10344 + ShowAux = true; + StripAux = true; +#endif +#if VDRVERSNUM >= 10330 CheckTimerConflict = false; +#endif MaxCacheFill = 25; } @@ -20,7 +26,13 @@ bool cText2SkinSetup::SetupParse(const char *Name, const char *Value) { if (strcmp(Name, "MenuScrollbar") == 0) MenuScrollbar = atoi(Value); else if (strcmp(Name, "MarqueeLeftRight") == 0) MarqueeLeftRight = atoi(Value); else if (strcmp(Name, "MarqueeReset") == 0) MarqueeReset = atoi(Value); +#if VDRVERSNUM >= 10344 + else if (strcmp(Name, "ShowAux") == 0) ShowAux = atoi(Value); + else if (strcmp(Name, "StripAux") == 0) StripAux = atoi(Value); +#endif +#if VDRVERSNUM >= 10330 else if (strcmp(Name, "CheckTimerConflict") == 0) CheckTimerConflict = atoi(Value); +#endif else if (strcmp(Name, "MaxCacheFill") == 0) MaxCacheFill = atoi(Value); else return false; @@ -16,7 +16,13 @@ public: int MenuScrollbar; int MarqueeLeftRight; int MarqueeReset; +#if VDRVERSNUM >= 10344 + int ShowAux; + int StripAux; +#endif +#if VDRVERSNUM >= 10330 int CheckTimerConflict; +#endif int MaxCacheFill; }; @@ -143,13 +143,13 @@ void cText2SkinStatus::OsdClear(void) void cText2SkinStatus::OsdCurrentItem(const char *Text) { - if (mRender != NULL) + if (mRender && Text) { // update infos cText2SkinRender::tUpdate *u = &mRender->mUpdate; - static std::string lastItem; + //static std::string lastItem; - lastItem = u->currentItem; + //lastItem = u->currentItem; u->currentItem = Text; u->resetMarquee = true; u->foundFirstItem = false; @@ -172,7 +172,7 @@ void cText2SkinStatus::OsdCurrentItem(const char *Text) void cText2SkinStatus::OsdItem(const char *Text, int Index) { - if (mRender && Text2SkinSetup.MenuScrollbar) + if (mRender && Text2SkinSetup.MenuScrollbar && Text) { uint curr = (uint)Index; cText2SkinRender::tMenuScrollbar *sb = &mRender->mMenuScrollbar; @@ -214,11 +214,13 @@ void cText2SkinStatus::UpdateEvents(void) if (!dummy.IsSingleEvent()) // add 4 additional rep. timer { + int j = 0; do { + j++; // just to avoid a endless loop dummy.Skip(); dummy.Matches(); // Refresh start- and end-time - } while (!dummy.DayMatches(dummy.Day())); + } while (!dummy.DayMatches(dummy.StartTime()) && (j < 7)); } i++; @@ -238,7 +240,19 @@ cxType cText2SkinStatus::GetTokenData(const txToken &Token) switch (Token.Type) { case tReplayMode: return ReplayNames[mReplayMode]; - + + case tFrontendSTR: + return GetFrontendSTR(); + + case tFrontendSNR: + return GetFrontendSNR(); + + case tFrontendHasLock: + return GetFrontendHasLock(); + + case tFrontendHasSignal: + return GetFrontendHasSignal(); + case tCurrentEventsTitle3: event++; case tCurrentEventsTitle2: @@ -299,34 +313,26 @@ cxType cText2SkinStatus::GetTokenData(const txToken &Token) ? (cxType)mEvents.Get(event)->isRecording : (cxType)false; - case tTimerConflict: + case tTimerConflicts: #if VDRVERSNUM >= 10330 - if (Text2SkinSetup.CheckTimerConflict) - { - bool conflict; - - if (mRender->mUpdate.timerConflict) - { + if (Text2SkinSetup.CheckTimerConflict) { + if (mRender->mUpdate.timerConflict) { + Epgsearch_lastconflictinfo_v1_0 conflict; mRender->mUpdate.timerConflict = false; - if (cPluginManager::CallFirstService("CheckTimerConflict-v1.0", &conflict) ) - { - mTimerConflict = conflict; - } - else - { - mTimerConflict = false; + if (cPluginManager::CallFirstService("Epgsearch-lastconflictinfo-v1.0", &conflict)) { + mTimerConflicts = conflict.relevantConflicts; + } else { + mTimerConflicts = 0; } } - - return mTimerConflict; - } - else + return mTimerConflicts; + } else +#endif { - return false; + return 0; } -#endif - + #if VDRVERSNUM >= 10325 #if VDRVERSNUM >= 10338 case tReplayName: @@ -338,7 +344,7 @@ cxType cText2SkinStatus::GetTokenData(const txToken &Token) return mReplay != NULL ? (cxType)TimeType(mReplay->start, Token.Attrib.Text) : (cxType)false; - + case tReplayShortText: return mReplay != NULL ? (cxType)mReplay->Info()->ShortText() @@ -378,7 +384,7 @@ cxType cText2SkinStatus::GetTokenData(const txToken &Token) { std::string buffer(c->language); if (c->type == 1) buffer.append("MONO"); - if (c->type == 2) buffer.append("DUAL"); + if ((c->type == 2) || (c->type == 4)) buffer.append("DUAL"); if (c->type == 5) buffer.append("DD"); return (cxType)buffer.c_str(); } @@ -72,7 +72,7 @@ private: uint mCurrentRecording; uint mNextRecording; int mLastLanguage; - bool mTimerConflict; + int mTimerConflicts; protected: #if VDRVERSNUM >= 10338 diff --git a/text2skin.c b/text2skin.c index cf4f618..86869e2 100644 --- a/text2skin.c +++ b/text2skin.c @@ -7,14 +7,14 @@ */ #include "text2skin.h" +#include "bitmap.h" #include "setup.h" #include "menu.h" #include "i18n.h" #include "loader.h" #include "status.h" -#include "xml/object.h" -const char *cText2SkinPlugin::VERSION = "1.1-cvs"; +const char *cText2SkinPlugin::VERSION = "1.1-cvs_ext-0.9"; const char *cText2SkinPlugin::SKINVERSION = "1.0"; const char *cText2SkinPlugin::DESCRIPTION = "Loader for text-based skins"; @@ -24,16 +24,26 @@ cText2SkinPlugin::cText2SkinPlugin(void) { cText2SkinPlugin::~cText2SkinPlugin() { } -#if VDRVERSNUM >= 10330 -bool cText2SkinPlugin::Service(const char *Id, void *Data) +#if VDRVERSNUM >= 10331 +const char **cText2SkinPlugin::SVDRPHelpPages(void) { - if (strcmp(Id,"Text2Skin-TTF") == 0) { - if (Data == NULL) - return true; - cxObject::UseTTF = *(int*)Data; - return true; - } - return false; + static const char *HelpPages[] = { + "FLUS\n" + " Flush the image cache (useful if images have changed and the" + " current version should be loaded).", + NULL + }; + return HelpPages; +} + +cString cText2SkinPlugin::SVDRPCommand(const char *Command, const char *Option, int &ReplyCode) +{ + if (strcasecmp(Command, "FLUS") == 0) { + // we use the default reply code here + cText2SkinBitmap::FlushCache(); + return "image cache flushed."; + } + return NULL; } #endif diff --git a/text2skin.h b/text2skin.h index cdd95ca..19fa341 100644 --- a/text2skin.h +++ b/text2skin.h @@ -21,8 +21,9 @@ public: virtual ~cText2SkinPlugin(); virtual const char *Version(void) { return VERSION; } virtual const char *Description(void) { return tr(DESCRIPTION); } -#if VDRVERSNUM >= 10330 - virtual bool Service(const char *Id, void *Data); +#if VDRVERSNUM >= 10331 + virtual const char **SVDRPHelpPages(void); + virtual cString SVDRPCommand(const char *Command, const char *Option, int &ReplyCode); #endif virtual bool Start(void); virtual cMenuSetupPage *SetupMenu(void); diff --git a/xml/object.c b/xml/object.c index 3979384..c63c2ea 100644 --- a/xml/object.c +++ b/xml/object.c @@ -140,14 +140,10 @@ const std::string &cxObject::TypeName(void) const return ObjectNames[mType]; } -int cxObject::UseTTF = true; - const cFont *cxObject::Font(void) const { const cFont *font; - if (UseTTF) { - if ((font = cText2SkinFont::Load(SkinPath() + "/" + mSkin->Name(), mFontFace, mFontSize, mFontWidth)) != NULL) return font; @@ -156,8 +152,6 @@ const cFont *cxObject::Font(void) const != NULL) return font; - } - return cFont::GetFont(fontOsd); } diff --git a/xml/object.h b/xml/object.h index 96cdd14..bbc37a0 100644 --- a/xml/object.h +++ b/xml/object.h @@ -45,7 +45,6 @@ class cxObject { friend class VSkinnerItem; public: - static int UseTTF; enum eType { image, text, diff --git a/xml/string.c b/xml/string.c index b8fc1f9..7568b37 100644 --- a/xml/string.c +++ b/xml/string.c @@ -13,9 +13,9 @@ static const char *Tokens[__COUNT_TOKEN__] = { "ChannelSource", "ChannelID", "PresentStartDateTime", "PresentVPSDateTime", "CurrentEventsTitle1", "CurrentEventsStartDateTime1", "CurrentEventsStopDateTime1", "CurrentEventsChannelNumber1", "CurrentEventsChannelName1", "CurrentEventsIsRecording1", "CurrentEventsTitle2", "CurrentEventsStartDateTime2", "CurrentEventsStopDateTime2", "CurrentEventsChannelNumber2", "CurrentEventsChannelName2", "CurrentEventsIsRecording2", "CurrentEventsTitle3", "CurrentEventsStartDateTime3", "CurrentEventsStopDateTime3", "CurrentEventsChannelNumber3", "CurrentEventsChannelName3", "CurrentEventsIsRecording3", - "TimerConflict", + "TimerConflicts", "PresentEndDateTime", "PresentDuration", "PresentProgress", "PresentRemaining", - "PresentLanguageCode", "PresentLanguageDescription", "PresentVideoAR", + "PresentLanguageCode", "PresentLanguageDescription", "PresentVideoAR", "PresentEventID", "PresentTitle", "PresentShortText", "PresentDescription", "FollowingStartDateTime", "FollowingVPSDateTime", "FollowingEndDateTime", "FollowingDuration", "FollowingTitle", "FollowingShortText", "FollowingDescription", "Language", @@ -44,8 +44,9 @@ static const char *Tokens[__COUNT_TOKEN__] = { // Menu Page "MenuTitle", "MenuGroup", "IsMenuGroup", "MenuItem", "IsMenuItem", "MenuCurrent", - "IsMenuCurrent", "MenuText", "RecordingName", "RecordingDateTime", "RecordingTitle", + "IsMenuCurrent", "MenuText", "RecordingName", "RecordingFilename", "RecordingDateTime", "RecordingTitle", "RecordingShortText", "RecordingDescription", "RecordingLanguageCode", + "FrontendSTR", "FrontendSNR", "FrontendHasLock", "FrontendHasSignal", "RecordingPriority", "RecordingLifetime", "RecordingVideoAR", "RecordingSize", "RecordingLength", "RecordingCuttedLength", "OsdWidth", "OsdHeight", "RecordingLanguageDescription", "ButtonRed", "ButtonGreen", "ButtonYellow", "ButtonBlue", "CanScrollUp", "CanScrollDown" diff --git a/xml/string.h b/xml/string.h index 68cd8fa..55adbcf 100644 --- a/xml/string.h +++ b/xml/string.h @@ -44,7 +44,7 @@ enum exToken { tCurrentEventsChannelNumber3, tCurrentEventsChannelName3, tCurrentEventsIsRecording3, - tTimerConflict, + tTimerConflicts, tPresentEndDateTime, tPresentDuration, tPresentProgress, @@ -52,6 +52,7 @@ enum exToken { tPresentLanguageCode, tPresentLanguageDescription, tPresentVideoAR, + tPresentEventID, tPresentTitle, tPresentShortText, tPresentDescription, @@ -144,11 +145,18 @@ enum exToken { tMenuText, // Recordings Page tRecordingName, + tRecordingFilename, tRecordingDateTime, tRecordingTitle, tRecordingShortText, tRecordingDescription, tRecordingLanguageCode, + tFrontendSTR, + tFrontendSNR, + tFrontendHasLock, + tFrontendHasSignal, + tRecordingPriority, + tRecordingLifetime, tRecordingVideoAR, tRecordingSize, tRecordingLength, @@ -35,7 +35,7 @@ XML::XML(const string &file) { ifstream f(file.c_str(), ios::in|ios::binary|ios::ate); size = f.tellg(); f.seekg(0, ios::beg); - buffer = new char [size]; + buffer = new char [size+1]; f.read(buffer, size); f.close(); data = buffer; |