summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndreas Brugger <brougs78@gmx.net>2006-11-19 16:58:14 +0100
committerThomas Günther <tom@toms-cafe.de>2009-06-03 03:35:58 +0200
commit74a5cc8e14900d48386e33cb576f154a6dd7e557 (patch)
treec7a90ba2fc5952558f6d4f528f94f8057f0d3ecd
parent8d32cf88bbe5b69a2710029cdaa896470a0fe20c (diff)
downloadvdr-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--HISTORY22
-rw-r--r--Makefile9
-rw-r--r--common.c178
-rw-r--r--common.h45
-rw-r--r--display.c92
-rw-r--r--display.h2
-rw-r--r--graphtft/font.c13
-rw-r--r--i18n.c154
-rw-r--r--menu.c23
-rw-r--r--menu.h1
-rw-r--r--render.c24
-rw-r--r--setup.c12
-rw-r--r--setup.h6
-rw-r--r--status.c64
-rw-r--r--status.h2
-rw-r--r--text2skin.c32
-rw-r--r--text2skin.h5
-rw-r--r--xml/object.c6
-rw-r--r--xml/object.h1
-rw-r--r--xml/string.c7
-rw-r--r--xml/string.h10
-rw-r--r--xml/xml.c2
22 files changed, 635 insertions, 75 deletions
diff --git a/HISTORY b/HISTORY
index bc2c26f..b8b96de 100644
--- a/HISTORY
+++ b/HISTORY
@@ -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
diff --git a/Makefile b/Makefile
index a06aa12..e143762 100644
--- a/Makefile
+++ b/Makefile
@@ -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
diff --git a/common.c b/common.c
index b9e1daf..d5bb0b4 100644
--- a/common.c
+++ b/common.c
@@ -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);
+}
diff --git a/common.h b/common.h
index 4c9e74d..f4ec281 100644
--- a/common.h
+++ b/common.h
@@ -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
diff --git a/display.c b/display.c
index 7dc8f5c..fa71016 100644
--- a/display.c
+++ b/display.c
@@ -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();
}
diff --git a/display.h b/display.h
index 3865431..8bb62da 100644
--- a/display.h
+++ b/display.h
@@ -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++) {
diff --git a/i18n.c b/i18n.c
index 295c677..28cd46e 100644
--- a/i18n.c
+++ b/i18n.c
@@ -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",
"",
diff --git a/menu.c b/menu.c
index e8f2306..3117022 100644
--- a/menu.c
+++ b/menu.c
@@ -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;
}
diff --git a/menu.h b/menu.h
index 5cd1563..f9aace7 100644
--- a/menu.h
+++ b/menu.h
@@ -17,6 +17,7 @@ public:
cText2SkinSetupPage(void);
virtual ~cText2SkinSetupPage();
+ void cText2SkinSetupPage::Setup(void);
virtual void Store(void);
eOSState ProcessKey(eKeys Key);
};
diff --git a/render.c b/render.c
index 06096b1..d536c22 100644
--- a/render.c
+++ b/render.c
@@ -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 "";
}
diff --git a/setup.c b/setup.c
index a2ea090..6a27f6d 100644
--- a/setup.c
+++ b/setup.c
@@ -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;
diff --git a/setup.h b/setup.h
index cee476a..d76291c 100644
--- a/setup.h
+++ b/setup.h
@@ -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;
};
diff --git a/status.c b/status.c
index 95e4bec..35be7a5 100644
--- a/status.c
+++ b/status.c
@@ -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();
}
diff --git a/status.h b/status.h
index 8bd0f96..2481a1a 100644
--- a/status.h
+++ b/status.h
@@ -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,
diff --git a/xml/xml.c b/xml/xml.c
index a91f5d6..a6b33c3 100644
--- a/xml/xml.c
+++ b/xml/xml.c
@@ -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;