diff options
-rw-r--r-- | HISTORY | 55 | ||||
-rw-r--r-- | common.c | 150 | ||||
-rw-r--r-- | common.h | 4 | ||||
-rw-r--r-- | display.c | 201 | ||||
-rw-r--r-- | i18n.c | 131 | ||||
-rw-r--r-- | menu.c | 10 | ||||
-rw-r--r-- | render.c | 28 | ||||
-rw-r--r-- | render.h | 12 | ||||
-rw-r--r-- | setup.c | 9 | ||||
-rw-r--r-- | setup.h | 3 | ||||
-rw-r--r-- | status.c | 287 | ||||
-rw-r--r-- | status.h | 34 | ||||
-rw-r--r-- | text2skin.c | 14 | ||||
-rw-r--r-- | text2skin.h | 3 | ||||
-rw-r--r-- | xml/object.c | 12 | ||||
-rw-r--r-- | xml/object.h | 1 | ||||
-rw-r--r-- | xml/string.c | 7 | ||||
-rw-r--r-- | xml/string.h | 37 |
18 files changed, 967 insertions, 31 deletions
@@ -1,6 +1,61 @@ VDR Plugin 'text2skin' Revision History --------------------------------------- +2006-01-10: Version 1.1-cvs_ext-0.6 (vdr-text2skin-1.1-cvs_ext-0.6.diff) + +- updated to cvs-version of text2skin +- since vdr-1.3.38 it is possible to exactly identify the replayed + recording, so the replay-tokens work now +- switched the search-order for the fonts to priorise the skin-folder + (this avoids error-messages in the log) + +2006-01-07: Version 1.1-cvs_ext-0.5 (vdr-text2skin-1.1-cvs_ext-0.5.diff) + +- modifications to compile with vdr-versions >= 1.3.18 +- added tokens: + OsdWidth, OsdHeight +- activating the token ReplayVideoAR + +2005-12-18: Version 1.1-cvs_ext-0.4 (vdr-text2skin-1.1-cvs_ext-0.4.diff) + +- modified the way, the current replayed recording is determined (status.c: + cText2SkinStatus::Replaying) + There remains a problem that recordings with the same name cannot be + distinguished, so information optained from mReplay are not necessarily + correct (all the ones added in vdr-text2skin-1.1-cvs_ext-0.2.diff) + +2005-12-11: Version 1.1-cvs_ext-0.3 (vdr-text2skin-1.1-cvs_ext-0.3.diff) + +- added recording-tokens: + RecordingLength, RecordingCuttedLength + +2005-11-19: Version 1.1-cvs_ext-0.2 (vdr-text2skin-1.1-cvs_ext-0.2.diff) + +- removed the previously introduced tokens NextTimerName, NextTimerStart, + NextTimerChannel, CurrentRecordingsCount and added tokens for the next + 3 timers: CurrentEventsTitle[123], CurrentEventsStartDateTime[123], + CurrentEventsStopDateTime[123], CurrentEventsChannelNumber[123], + CurrentEventsChannelName[123], CurrentEventsIsRecording[123] +- added audio- and video-tokens: + PresentLanguageCode, PresentLanguageDescription, PresentVideoAR and + implemented the missing code for the Language-token +- added tokens for replay: + ReplayName, ReplayDateTime, ReplayShortText, ReplayDescription, + ReplayLanguageCode, ReplayLanguageDescription, ReplayVideoAR + (not activated yet) +- additional recording-tokens: + RecordingVideoAR, RecordingSize +- added a reset for scrolling text (configurable) +- included Text2skin.diff from the rotor-plugin + +2005-10-22: Version 1.1-cvs_ext-0.1 (vdr-text2skin-1.1-cvs_ext-0.1.diff) + +- added several tokens: + NextTimerName, NextTimerStart, NextTimerChannel, TimerConflict, + CurrentRecordingsCount, using the service "CheckTimerConflict-v1.0" to + check timer conflicts. A patch for the timeline-plugin is included in + Enigma-0.4pre2 (timeline_CheckTimerConflictService-0.1.diff) + 2005-06-xx: Version 1.1 - fixed crash due to uninitialized pointer (thanks to Frank Enderle) @@ -115,6 +115,156 @@ const cRecording *GetRecordingByName(const char *Name) return NULL; } +const cRecording *GetRecordingByFileName(const char *FileName) +{ + return (FileName) ? Recordings.GetByName(FileName) : NULL; +} + +int GetRecordingSize(const char *FileName) +{ + if (FileName != NULL) { + bool bRet=false; + long long size = 0; + int nFiles; + struct stat fileinfo; // Holds file information structure + char *cmd = NULL; +#if VDRVERSNUM >= 10318 + cReadLine reader; +#endif + asprintf(&cmd, "find '%s' -follow -type f -name '*.*'|sort ", FileName); + + FILE *p = popen(cmd, "r"); + int ret=0; + if (p) + { + char *s; + +#if VDRVERSNUM >= 10318 + while ((s = reader.Read(p)) != NULL) +#else + while ((s = readline(p)) != NULL) +#endif + { + if ((ret=stat(s, &fileinfo)) != -1) + { + size += (long long)fileinfo.st_size; + nFiles++; + } + } + + bRet=true; + } + + pclose(p); + delete cmd; + + return (int)(size / 1024 / 1024); // [MB] + } + else + { + return 0; + } +} + +int GetRecordingLength(const char *FileName) +{ + // based on the enAIO-Patch for VDR + #define INDEXFILESUFFIX "/index.vdr" + + struct tIndex { int offset; uchar type; uchar number; short reserved; }; + tIndex *index; + char RecLength[21]; + char *filename = NULL; + int last = -1; + index = NULL; + if (FileName) { + filename = MALLOC(char, strlen(FileName) + strlen(INDEXFILESUFFIX) + 1); + if (filename) { + strcpy(filename, FileName); + char *pFileExt = filename + strlen(filename); + strcpy(pFileExt, INDEXFILESUFFIX); + int delta = 0; + if (access(filename, R_OK) == 0) { + struct stat buf; + if (stat(filename, &buf) == 0) { + delta = buf.st_size % sizeof(tIndex); + if (delta) { + delta = sizeof(tIndex) - delta; + esyslog("ERROR: invalid file size (%ld) in '%s'", buf.st_size, filename); + } + last = (buf.st_size + delta) / sizeof(tIndex) - 1; + char hour[2], min[3]; +#if VDRVERSNUM >= 10318 + snprintf(RecLength, sizeof(RecLength), "%s", *IndexToHMSF(last, true)); +#else + snprintf(RecLength, sizeof(RecLength), "%s", IndexToHMSF(last, true)); +#endif + snprintf(hour, sizeof(hour), "%c", RecLength[0]); + snprintf(min, sizeof(min), "%c%c", RecLength[2], RecLength[3]); + return (atoi(hour) * 60) + atoi(min); + } + } + free(filename); + } + } + + return 0; +} + +int GetRecordingCuttedLength(const char *FileName) +{ + cMarks marks; + double length = 0; + int totalLength = GetRecordingLength(FileName); + const double diffIFrame = FRAMESPERSEC / 2; // approx. 1/2 sec. + /* + // not useful + static std::string lastFileName = ""; + static uint64 nextUpdate = 0; + static int totalLength = 0; + const uint64 bufferTime = 30 * 1000; // [ms] + */ + + + marks.Load(FileName); + + /* + // buffer the result of 'GetRecordingLength' + if (FileName != lastFileName || time_ms() >= nextUpdate) + { + lastFileName = FileName; + nextUpdate = time_ms() + bufferTime; + totalLength = GetRecordingLength(FileName); + } + */ + + if (marks.Count()) + { + int start = 1; // first frame + bool isStart = true; + + for (cMark *m = marks.First(); m; m = marks.GetNext(m->position)) + { + if (isStart) + { + start = m->position; + } + else + { + length += (double)(m->position - start + 1 + diffIFrame) / (FRAMESPERSEC * 60); // [min] + } + + isStart = !isStart; + } + + // if there is no end-mark the last segment goes to the end of the rec. + if (!isStart) length += totalLength - (double)(start - 1 - diffIFrame) / (FRAMESPERSEC * 60); // [min] + } + + // just to avoid, that the cutted length is bigger than the total length + return (int)length > totalLength ? totalLength : (int)length; +} + cxType TimeType(time_t Time, const std::string &Format) { static char result[1000]; @@ -51,6 +51,10 @@ const char *ChannelShortName(const cChannel *Channel, int Number); bool StoppedTimer(const char *Name); const cRecording *GetRecordingByName(const char *Name); +const cRecording *GetRecordingByFileName(const char *FileName); +int GetRecordingSize(const char *FileName); // [MB] +int GetRecordingLength(const char *FileName); // [min] +int GetRecordingCuttedLength(const char *FileName); // [min] cxType TimeType(time_t Time, const std::string &Format); cxType DurationType(uint Index, const std::string &Format); @@ -241,7 +241,16 @@ cxType cText2SkinDisplayChannel::GetTokenData(const txToken &Token) case tLanguage: { #if VDRVERSNUM >= 10318 - // TODO !!! + cDevice *dev = cDevice::PrimaryDevice(); + eTrackType trackType = dev->GetCurrentAudioTrack(); + const tTrackId *track = dev->GetTrack(trackType); + if (track) + { + std::string buffer(track->language); + if (trackType >= ttDolby) buffer.append("DD"); + return (cxType)buffer.c_str(); + } + return (cxType)false; #else int cur; const char **tracks = cDevice::PrimaryDevice()->GetAudioTracks(&cur); @@ -582,6 +591,32 @@ cxType cText2SkinDisplayReplay::GetTokenData(const txToken &Token) } return false; + case tLanguage: { +#if VDRVERSNUM >= 10318 + cDevice *dev = cDevice::PrimaryDevice(); + eTrackType trackType = dev->GetCurrentAudioTrack(); + const tTrackId *track = dev->GetTrack(trackType); + if (track) + { + std::string buffer(track->language); + if (trackType >= ttDolby) buffer.append("DD"); + return (cxType)buffer.c_str(); + } + return (cxType)false; +#else + int cur; + const char **tracks = cDevice::PrimaryDevice()->GetAudioTracks(&cur); + if (tracks) { + int i = 0; + while (tracks[i] != NULL) + ++i; + if (cur < i) + return tracks[cur]; + } +#endif + } + return false; + case tMessage: return mText; @@ -755,6 +790,9 @@ void cText2SkinDisplayMenu::SetTitle(const char *Title) UpdateLock(); if (Title == NULL) Title = ""; if (mTitle != Title) { + mUpdate.timerConflict = true; + mUpdate.events = true; + mUpdate.resetMarquee = true; mTitle = Title; SetDirty(); } @@ -1049,7 +1087,76 @@ cxType cText2SkinDisplayMenu::GetTokenData(const txToken &Token) return mEvent != NULL ? (cxType)mEvent->Description() : (cxType)false; - + +#if VDRVERSNUM >= 10318 + case tPresentLanguageCode: + if (mEvent) + { + const cComponents *components = mEvent->Components(); + if (components) + { + int index = Token.Attrib.Number; + + // don't return language-code for the video-stream + for (int i = 0; i < components->NumComponents(); i++) + { + const tComponent *c = components->Component(i); + if (c->stream != 2) index++; // only audio-streams + if (i == index) + { + std::string buffer(c->language); + if (c->type == 1) buffer.append("MONO"); + if (c->type == 2) buffer.append("DUAL"); + if (c->type == 5) buffer.append("DD"); + return (cxType)buffer.c_str(); + } + } + } + } + return false; + + case tPresentLanguageDescription: + if (mEvent) + { + const cComponents *components = mEvent->Components(); + if (components) + { + int index = Token.Attrib.Number; + + // don't return language-code for the video-stream + for (int i = 0; i < components->NumComponents(); i++) + { + const tComponent *c = components->Component(i); + if (c->stream != 2) index++; // only audio-streams + if (i == index) return (cxType)c->description; + } + } + } + return false; + + case tPresentVideoAR: + if (mEvent) + { + const cComponents *components = mEvent->Components(); + if (components) + { + for (int i = 0; i < components->NumComponents(); i++) + { + const tComponent *c = components->Component(i); + if (c->stream == 1) + { + switch (c->type) + { + case 1: return "4:3"; + case 3: return "16:9"; + } + } + } + } + } + return false; +#endif + case tHasVPS: case tChannelHasVPS: return mEvent != NULL && mEvent->Vps() != 0; @@ -1094,27 +1201,89 @@ cxType cText2SkinDisplayMenu::GetTokenData(const txToken &Token) ? (cxType)mRecording->Info()->Description() : (cxType)false; - case tRecordingLanguageCode: - if (mRecording != NULL) { - const tComponent *c - = mRecording->Info()->Components()->Component(Token.Attrib.Number); - return c != NULL - ? (cxType)c->language - : (cxType)false; + case tRecordingLanguageCode: + if (mRecording) + { + const cComponents *components = mRecording->Info()->Components(); + if (components) + { + int index = Token.Attrib.Number; + + // don't return language-code for the video-stream + for (int i = 0; i < components->NumComponents(); i++) + { + const tComponent *c = components->Component(i); + if (c->stream != 2) index++; // only audio-streams + if (i == index) + { + std::string buffer(c->language); + if (c->type == 1) buffer.append("MONO"); + if (c->type == 2) buffer.append("DUAL"); + if (c->type == 5) buffer.append("DD"); + return (cxType)buffer.c_str(); + } + } + } } return false; - + case tRecordingLanguageDescription: - if (mRecording != NULL) { - const tComponent *c - = mRecording->Info()->Components()->Component(Token.Attrib.Number); - return c != NULL - ? (cxType)c->description - : (cxType)false; + if (mRecording) + { + const cComponents *components = mRecording->Info()->Components(); + if (components) + { + int index = Token.Attrib.Number; + + // don't return language-code for the video-stream + for (int i = 0; i < components->NumComponents(); i++) + { + const tComponent *c = components->Component(i); + if (c->stream != 2) index++; // only audio-streams + if (i == index) return (cxType)c->description; + } + } + } + return false; + + case tRecordingVideoAR: + if (mRecording) + { + const cComponents *components = mRecording->Info()->Components(); + if (components) + { + for (int i = 0; i < components->NumComponents(); i++) + { + const tComponent *c = components->Component(i); + if (c->stream == 1) + { + switch (c->type) + { + case 1: return "4:3"; + case 3: return "16:9"; + } + } + } + } } return false; #endif + case tRecordingSize: + return mRecording != NULL + ? (cxType)GetRecordingSize(mRecording->FileName()) + : (cxType)false; + + case tRecordingLength: + return mRecording != NULL + ? (cxType)GetRecordingLength(mRecording->FileName()) + : (cxType)false; + + case tRecordingCuttedLength: + return mRecording != NULL + ? (cxType)GetRecordingCuttedLength(mRecording->FileName()) + : (cxType)false; + default: return cText2SkinRender::GetTokenData(Token); } @@ -79,15 +79,140 @@ const tI18nPhrase Phrases[] = { "", #endif }, - { "Flushing image cache...", - "Bildspeicher wird geleert...", + { "Flush image cache", + "Bildspeicher leeren", + "", + "", + "", + "", + "", + "", + "Tyhjennä kuvat välimuistista", + "", + "", + "", + "", + "", + "", + "", + "", + "", +#if VDRVERSNUM >= 10313 + "", +#endif +#if VDRVERSNUM >= 10316 + "", +#endif + }, + { "Scrolling behaviour", + "Scroll-Verhalten", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", +#if VDRVERSNUM >= 10313 + "", +#endif +#if VDRVERSNUM >= 10316 + "", +#endif + }, + { "Reset Marquee for new item", + "Marquee für neues Item zurücksetzen", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", +#if VDRVERSNUM >= 10313 + "", +#endif +#if VDRVERSNUM >= 10316 + "", +#endif + }, + { "Use 'timeline' to check timer-conflicts", + "Timerkonflikte mit 'timeline' überprüfen", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", +#if VDRVERSNUM >= 10313 + "", +#endif +#if VDRVERSNUM >= 10316 + "", +#endif + }, + { "to the left", + "nach links", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", +#if VDRVERSNUM >= 10313 + "", +#endif +#if VDRVERSNUM >= 10316 + "", +#endif + }, + { "left and right", + "links und rechts", + "", "", "", "", "", "", "", - "Tyhjennetään välimuistia...", "", "", "", @@ -9,6 +9,11 @@ cText2SkinSetupPage::cText2SkinSetupPage(void) { mData = Text2SkinSetup; + 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 >= 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)); } @@ -17,6 +22,11 @@ cText2SkinSetupPage::~cText2SkinSetupPage() { } void cText2SkinSetupPage::Store(void) { + SetupStore("MarqueeLeftRight", mData.MarqueeLeftRight); + SetupStore("MarqueeReset", mData.MarqueeReset); +#if VDRVERSNUM >= 10330 + SetupStore("CheckTimerConflict", mData.CheckTimerConflict); +#endif SetupStore("MaxCacheFill", mData.MaxCacheFill); Text2SkinSetup = mData; } @@ -11,6 +11,7 @@ #include "screen.h" #include "display.h" #include "scroller.h" +#include "setup.h" #include "xml/display.h" #include <vdr/channels.h> #include <vdr/epg.h> @@ -353,13 +354,30 @@ void cText2SkinRender::DrawMarquee(const txPoint &Pos, const txSize &Size, const uint Delay, uint Index) { bool scrolling = Font->Width(Text.c_str()) > Size.w; - + tState &state = mStates[Index]; if (state.text != Text) { state = tState(); state.text = Text; } + if (Text2SkinSetup.MarqueeReset && mUpdate.resetMarquee && mUpdate.currentItem.find(Text, 0) != std::string::npos) + { + state.offset = 0; + state.direction = 1; + state.nexttime = 0; + state.scrolling = false; + mUpdate.foundFirstItem = true; + } + else + { + if (mUpdate.foundFirstItem) + { + mUpdate.resetMarquee = false; + mUpdate.foundFirstItem = false; + } + } + if (state.nexttime == 0) state.nexttime = mNow + 1500; else if (mNow >= state.nexttime) { @@ -376,7 +394,7 @@ void cText2SkinRender::DrawMarquee(const txPoint &Pos, const txSize &Size, const ++state.direction; nextin = 1500; } else - --state.offset; + Text2SkinSetup.MarqueeLeftRight ? --state.offset : state.offset = 0; } state.nexttime = mNow + nextin; } @@ -661,7 +679,11 @@ cxType cText2SkinRender::GetTokenData(const txToken &Token) case tCanScrollDown: return mScroller != NULL && mScroller->CanScrollDown(); case tIsRecording: return cRecordControls::Active(); - + + case tOsdWidth: return (cxType)mBaseSize.w; + + case tOsdHeight: return (cxType)mBaseSize.h; + #if VDRVERSNUM >=10318 case tAudioTrack: { cDevice *dev = cDevice::PrimaryDevice(); @@ -134,6 +134,18 @@ public: static bool ItemColor(const std::string &Color, tColor &Result); static std::string ImagePath(const std::string &Filename); static cxType GetToken(const txToken &Token); + + // update infos + struct tUpdate + { + bool timerConflict; + bool events; + std::string currentItem; + bool resetMarquee; + bool foundFirstItem; + + tUpdate(void) : timerConflict(true), events(true), currentItem(""), resetMarquee(true), foundFirstItem(false) {} + } mUpdate; }; inline void cText2SkinRender::Flush(bool Force) @@ -9,12 +9,19 @@ cText2SkinSetup Text2SkinSetup; // --- cText2SkinSetup -------------------------------------------------------- cText2SkinSetup::cText2SkinSetup(void) { + MarqueeLeftRight = true; + MarqueeReset = false; + CheckTimerConflict = false; MaxCacheFill = 25; } bool cText2SkinSetup::SetupParse(const char *Name, const char *Value) { - if (strcmp(Name, "MaxCacheFill") == 0) MaxCacheFill = atoi(Value); + if (strcmp(Name, "MarqueeLeftRight") == 0) MarqueeLeftRight = atoi(Value); + else if (strcmp(Name, "MarqueeReset") == 0) MarqueeReset = atoi(Value); + else if (strcmp(Name, "CheckTimerConflict") == 0) CheckTimerConflict = atoi(Value); + else if (strcmp(Name, "MaxCacheFill") == 0) MaxCacheFill = atoi(Value); else return false; + return true; } @@ -13,6 +13,9 @@ public: bool SetupParse(const char *Name, const char *Value); + int MarqueeLeftRight; + int MarqueeReset; + int CheckTimerConflict; int MaxCacheFill; }; @@ -4,6 +4,10 @@ #include "status.h" #include "render.h" +#include "menu.h" +#include <vdr/timers.h> +#include <vdr/plugin.h> +#include <vdr/menu.h> const std::string ReplayNames[__REPLAY_COUNT__] = { "", "normal", "mp3", "mplayer", "dvd", "vcd", "image" }; @@ -29,7 +33,12 @@ void cText2SkinStatus::SetRender(cText2SkinRender *Render) mNextRecording = 0; } -void cText2SkinStatus::Replaying(const cControl* /*Control*/, const char *Name) { +#if VDRVERSNUM >= 10338 +void cText2SkinStatus::Replaying(const cControl* /*Control*/, const char *Name, const char *FileName, bool On) +#else +void cText2SkinStatus::Replaying(const cControl* /*Control*/, const char *Name) +#endif +{ Dprintf("cText2SkinStatus::Replaying(%s)\n", Name); eReplayMode oldMode = mReplayMode; @@ -49,9 +58,20 @@ void cText2SkinStatus::Replaying(const cControl* /*Control*/, const char *Name) mReplayIsLoop = Name[1] == 'L'; mReplayIsShuffle = Name[2] == 'S'; } - } - else if (GetRecordingByName(Name) != NULL) + } +#if VDRVERSNUM >= 10338 + else if (const cRecording *rec = GetRecordingByFileName(FileName)) + { + mReplay = rec; mReplayMode = replayNormal; + } +#else + else if (const cRecording *rec = GetRecordingByName(Name)) + { + mReplay = rec; + mReplayMode = replayNormal; + } +#endif else if (strcmp(Name, "DVD") == 0) mReplayMode = replayDVD; else if (strcmp(Name, "VCD") == 0) @@ -83,7 +103,11 @@ void cText2SkinStatus::Replaying(const cControl* /*Control*/, const char *Name) } } -void cText2SkinStatus::Recording(const cDevice *Device, const char *Name) +#if VDRVERSNUM >= 10338 +void cText2SkinStatus::Recording(const cDevice *Device, const char *Name, const char *FileName, bool On) +#else +void cText2SkinStatus::Recording(const cDevice *Device, const char *Name) +#endif { if (mRender != NULL) mRender->UpdateLock(); @@ -112,12 +136,267 @@ void cText2SkinStatus::OsdClear(void) } } +void cText2SkinStatus::OsdCurrentItem(const char *Text) +{ + if (mRender != NULL) + { + static std::string lastItem; + + lastItem = mRender->mUpdate.currentItem; + mRender->mUpdate.currentItem = Text; + mRender->mUpdate.resetMarquee = true; + mRender->mUpdate.foundFirstItem = false; + } +} + +void cText2SkinStatus::UpdateEvents(void) +{ + if (mRender->mUpdate.events) + { + mRender->mUpdate.events = false; + + mEvents.clear(); + Timers.IncBeingEdited(); + + for (cTimer *tim = Timers.First(); tim != NULL; tim = Timers.Next(tim)) + { + if (tim->HasFlags(tfActive)) + { + int i = 0; + cTimer dummy; + dummy = *tim; // copy the timer + + do + { + tEvent ev; + + ev.title = dummy.File(); + ev.isRecording = dummy.Recording(); + ev.channelName = dummy.Channel()->Name(); + ev.channelNumber = dummy.Channel()->Number(); + ev.startTime = dummy.StartTime(); + ev.stopTime = dummy.StopTime(); + ev.priority = dummy.Priority(); + + mEvents.push_back(ev); + + if (!dummy.IsSingleEvent()) // add 4 additional rep. timer + { + do + { + dummy.Skip(); + dummy.Matches(); // Refresh start- and end-time + } while (!dummy.DayMatches(dummy.Day())); + } + + i++; + } while (!dummy.IsSingleEvent() && i < 5); + } + } + + Timers.DecBeingEdited(); + std::sort(mEvents.rbegin(), mEvents.rend()); + } +} + cxType cText2SkinStatus::GetTokenData(const txToken &Token) { + uint event = 0; + switch (Token.Type) { case tReplayMode: return ReplayNames[mReplayMode]; + case tCurrentEventsTitle3: + event++; + case tCurrentEventsTitle2: + event++; + case tCurrentEventsTitle1: + UpdateEvents(); + return mEvents.size() > event + ? (cxType)mEvents[event].title.c_str() + : (cxType)false; + + case tCurrentEventsStartDateTime3: + event++; + case tCurrentEventsStartDateTime2: + event++; + case tCurrentEventsStartDateTime1: + UpdateEvents(); + return mEvents.size() > event + ? (cxType)TimeType(mEvents[event].startTime, Token.Attrib.Text) + : (cxType)false; + + case tCurrentEventsStopDateTime3: + event++; + case tCurrentEventsStopDateTime2: + event++; + case tCurrentEventsStopDateTime1: + UpdateEvents(); + return mEvents.size() > event + ? (cxType)TimeType(mEvents[event].stopTime, Token.Attrib.Text) + : (cxType)false; + + case tCurrentEventsChannelNumber3: + event++; + case tCurrentEventsChannelNumber2: + event++; + case tCurrentEventsChannelNumber1: + UpdateEvents(); + return mEvents.size() > event + ? (cxType)mEvents[event].channelNumber + : (cxType)false; + + case tCurrentEventsChannelName3: + event++; + case tCurrentEventsChannelName2: + event++; + case tCurrentEventsChannelName1: + UpdateEvents(); + return mEvents.size() > event + ? (cxType)mEvents[event].channelName.c_str() + : (cxType)false; + + case tCurrentEventsIsRecording3: + event++; + case tCurrentEventsIsRecording2: + event++; + case tCurrentEventsIsRecording1: + UpdateEvents(); + return mEvents.size() > event + ? (cxType)mEvents[event].isRecording + : (cxType)false; + + case tTimerConflict: +#if VDRVERSNUM >= 10330 + if (Text2SkinSetup.CheckTimerConflict) + { + bool conflict; + + if (mRender->mUpdate.timerConflict) + { + mRender->mUpdate.timerConflict = false; + + if (cPluginManager::CallFirstService("CheckTimerConflict-v1.0", &conflict) ) + { + mTimerConflict = conflict; + } + else + { + mTimerConflict = false; + } + } + + return mTimerConflict; + } + else + { + return false; + } +#endif + +#if VDRVERSNUM >= 10325 +#if VDRVERSNUM >= 10338 + case tReplayName: + return mReplay != NULL + ? (cxType)mReplay->Name() + : (cxType)false; + + case tReplayDateTime: + return mReplay != NULL + ? (cxType)TimeType(mReplay->start, Token.Attrib.Text) + : (cxType)false; + + case tReplayShortText: + return mReplay != NULL + ? (cxType)mReplay->Info()->ShortText() + : (cxType)false; + + case tReplayDescription: + return mReplay != NULL + ? (cxType)mReplay->Info()->Description() + : (cxType)false; +#else + case tReplayName: + return (cxType)false; + + case tReplayDateTime: + return (cxType)false; + + case tReplayShortText: + return (cxType)false; + + case tReplayDescription: + return (cxType)false; +#endif + + case tReplayLanguageCode: + if (mReplay) + { + const cComponents *components = mReplay->Info()->Components(); + if (components) + { + int index = Token.Attrib.Number; + + // don't return language-code for the video-stream + for (int i = 0; i < components->NumComponents(); i++) + { + const tComponent *c = components->Component(i); + if (c->stream != 2) index++; // only audio-streams + { + std::string buffer(c->language); + if (c->type == 1) buffer.append("MONO"); + if (c->type == 2) buffer.append("DUAL"); + if (c->type == 5) buffer.append("DD"); + return (cxType)buffer.c_str(); + } + } + } + } + return false; + + case tReplayLanguageDescription: + if (mReplay) + { + const cComponents *components = mReplay->Info()->Components(); + if (components) + { + int index = Token.Attrib.Number; + + // don't return language-code for the video-stream + for (int i = 0; i < components->NumComponents(); i++) + { + const tComponent *c = components->Component(i); + if (c->stream != 2) index++; // only audio-streams + if (i == index) return (cxType)c->description; + } + } + } + return false; + + case tReplayVideoAR: + if (mReplay) + { + const cComponents *components = mReplay->Info()->Components(); + if (components) + { + for (int i = 0; i < components->NumComponents(); i++) + { + const tComponent *c = components->Component(i); + if (c->stream == 1) + { + switch (c->type) + { + case 1: return "4:3"; + case 3: return "16:9"; + } + } + } + } + } + return false; +#endif + case tCurrentRecording: Dprintf("token attrib type is: %d, number: %d\n", Token.Attrib.Type, Token.Attrib.Number); if (Token.Attrib.Type == aNumber) { @@ -5,9 +5,12 @@ #ifndef VDR_TEXT2SKIN_STATUS_H #define VDR_TEXT2SKIN_STATUS_H +#include <algorithm> +#include <vector> #include "common.h" #include <vdr/status.h> + class cText2SkinRender; class cText2SkinStatus: public cStatus { @@ -27,21 +30,52 @@ public: typedef std::string tRecordingInfo; typedef std::vector<tRecordingInfo> tRecordings; + struct tEvent + { + std::string title; + bool isRecording; + std::string channelName; + int channelNumber; + time_t startTime; + time_t stopTime; + int priority; + + bool tEvent::operator< (const tEvent &b) const + { + int r = startTime - b.startTime; + r = r == 0 ? b.priority - priority : r; + return r > 0 ? true : false; + }; + }; + + typedef std::vector<tEvent> tEvents; + private: + void UpdateEvents(void); + cText2SkinRender *mRender; eReplayMode mReplayMode; bool mReplayIsLoop; bool mReplayIsShuffle; tRecordings mRecordings; + tEvents mEvents; + const cRecording *mReplay; cMutex mRecordingsLock; uint mCurrentRecording; uint mNextRecording; int mLastLanguage; + bool mTimerConflict; protected: +#if VDRVERSNUM >= 10338 + virtual void Replaying(const cControl *Control, const char *Name, const char *FileName, bool On); + virtual void Recording(const cDevice *Device, const char *Name, const char *FileName, bool On); +#else virtual void Replaying(const cControl *Control, const char *Name); virtual void Recording(const cDevice *Device, const char *Name); +#endif virtual void OsdClear(void); + virtual void OsdCurrentItem(const char *Text); public: cText2SkinStatus(void); diff --git a/text2skin.c b/text2skin.c index be63af4..cf4f618 100644 --- a/text2skin.c +++ b/text2skin.c @@ -12,6 +12,7 @@ #include "i18n.h" #include "loader.h" #include "status.h" +#include "xml/object.h" const char *cText2SkinPlugin::VERSION = "1.1-cvs"; const char *cText2SkinPlugin::SKINVERSION = "1.0"; @@ -23,6 +24,19 @@ cText2SkinPlugin::cText2SkinPlugin(void) { cText2SkinPlugin::~cText2SkinPlugin() { } +#if VDRVERSNUM >= 10330 +bool cText2SkinPlugin::Service(const char *Id, void *Data) +{ + if (strcmp(Id,"Text2Skin-TTF") == 0) { + if (Data == NULL) + return true; + cxObject::UseTTF = *(int*)Data; + return true; + } + return false; +} +#endif + bool cText2SkinPlugin::Start(void) { RegisterI18n(Phrases); Text2SkinStatus.SetLanguage(Setup.OSDLanguage); diff --git a/text2skin.h b/text2skin.h index b40ea54..cdd95ca 100644 --- a/text2skin.h +++ b/text2skin.h @@ -21,6 +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); +#endif virtual bool Start(void); virtual cMenuSetupPage *SetupMenu(void); virtual bool SetupParse(const char *Name, const char *Value); diff --git a/xml/object.c b/xml/object.c index 6ea0ab6..3979384 100644 --- a/xml/object.c +++ b/xml/object.c @@ -140,17 +140,23 @@ 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; + if ((font = cText2SkinFont::Load(SkinPath() + "/fonts", mFontFace, mFontSize, mFontWidth)) != NULL) return font; - if ((font = cText2SkinFont::Load(SkinPath() + "/" + mSkin->Name(), mFontFace, mFontSize, - mFontWidth)) != NULL) - return font; + } return cFont::GetFont(fontOsd); } diff --git a/xml/object.h b/xml/object.h index bbc37a0..96cdd14 100644 --- a/xml/object.h +++ b/xml/object.h @@ -45,6 +45,7 @@ class cxObject { friend class VSkinnerItem; public: + static int UseTTF; enum eType { image, text, diff --git a/xml/string.c b/xml/string.c index afc0c7a..b8fc1f9 100644 --- a/xml/string.c +++ b/xml/string.c @@ -11,7 +11,11 @@ static const char *Tokens[__COUNT_TOKEN__] = { // Channel Display "ChannelNumber", "ChannelName", "ChannelShortName", "ChannelBouquet", "ChannelPortal", "ChannelSource", "ChannelID", "PresentStartDateTime", "PresentVPSDateTime", + "CurrentEventsTitle1", "CurrentEventsStartDateTime1", "CurrentEventsStopDateTime1", "CurrentEventsChannelNumber1", "CurrentEventsChannelName1", "CurrentEventsIsRecording1", "CurrentEventsTitle2", "CurrentEventsStartDateTime2", "CurrentEventsStopDateTime2", "CurrentEventsChannelNumber2", "CurrentEventsChannelName2", "CurrentEventsIsRecording2", + "CurrentEventsTitle3", "CurrentEventsStartDateTime3", "CurrentEventsStopDateTime3", "CurrentEventsChannelNumber3", "CurrentEventsChannelName3", "CurrentEventsIsRecording3", + "TimerConflict", "PresentEndDateTime", "PresentDuration", "PresentProgress", "PresentRemaining", + "PresentLanguageCode", "PresentLanguageDescription", "PresentVideoAR", "PresentTitle", "PresentShortText", "PresentDescription", "FollowingStartDateTime", "FollowingVPSDateTime", "FollowingEndDateTime", "FollowingDuration", "FollowingTitle", "FollowingShortText", "FollowingDescription", "Language", @@ -30,6 +34,8 @@ static const char *Tokens[__COUNT_TOKEN__] = { // Replay Display "ReplayTitle", "ReplayPositionIndex", "ReplayDurationIndex", "ReplayPrompt", + "ReplayName", "ReplayDateTime", "ReplayShortText", "ReplayDescription", + "ReplayLanguageCode", "ReplayLanguageDescription", "ReplayVideoAR", "IsPlaying", "ReplayIsPlaying", "IsFastForward", "ReplayIsFastForward", "IsFastRewind", "ReplayIsFastRewind", "IsSlowForward", "ReplayIsSlowForward", "IsSlowRewind", "ReplayIsSlowRewind", "IsPausing", "ReplayIsPausing", @@ -40,6 +46,7 @@ static const char *Tokens[__COUNT_TOKEN__] = { "MenuTitle", "MenuGroup", "IsMenuGroup", "MenuItem", "IsMenuItem", "MenuCurrent", "IsMenuCurrent", "MenuText", "RecordingName", "RecordingDateTime", "RecordingTitle", "RecordingShortText", "RecordingDescription", "RecordingLanguageCode", + "RecordingVideoAR", "RecordingSize", "RecordingLength", "RecordingCuttedLength", "OsdWidth", "OsdHeight", "RecordingLanguageDescription", "ButtonRed", "ButtonGreen", "ButtonYellow", "ButtonBlue", "CanScrollUp", "CanScrollDown" }; diff --git a/xml/string.h b/xml/string.h index 7c3f30f..68cd8fa 100644 --- a/xml/string.h +++ b/xml/string.h @@ -26,10 +26,32 @@ enum exToken { // next 9 also in Menu tPresentStartDateTime, tPresentVPSDateTime, + tCurrentEventsTitle1, + tCurrentEventsStartDateTime1, + tCurrentEventsStopDateTime1, + tCurrentEventsChannelNumber1, + tCurrentEventsChannelName1, + tCurrentEventsIsRecording1, + tCurrentEventsTitle2, + tCurrentEventsStartDateTime2, + tCurrentEventsStopDateTime2, + tCurrentEventsChannelNumber2, + tCurrentEventsChannelName2, + tCurrentEventsIsRecording2, + tCurrentEventsTitle3, + tCurrentEventsStartDateTime3, + tCurrentEventsStopDateTime3, + tCurrentEventsChannelNumber3, + tCurrentEventsChannelName3, + tCurrentEventsIsRecording3, + tTimerConflict, tPresentEndDateTime, tPresentDuration, tPresentProgress, tPresentRemaining, + tPresentLanguageCode, + tPresentLanguageDescription, + tPresentVideoAR, tPresentTitle, tPresentShortText, tPresentDescription, @@ -85,6 +107,13 @@ enum exToken { tReplayPositionIndex, tReplayDurationIndex, tReplayPrompt, + tReplayName, + tReplayDateTime, + tReplayShortText, + tReplayDescription, + tReplayLanguageCode, + tReplayLanguageDescription, + tReplayVideoAR, tIsPlaying, tReplayIsPlaying, // alias tIsFastForward, @@ -120,6 +149,12 @@ enum exToken { tRecordingShortText, tRecordingDescription, tRecordingLanguageCode, + tRecordingVideoAR, + tRecordingSize, + tRecordingLength, + tRecordingCuttedLength, + tOsdWidth, + tOsdHeight, tRecordingLanguageDescription, // next four also in Channel and Replay display (if supported by vdr/plugin) tButtonRed, @@ -128,7 +163,7 @@ enum exToken { tButtonBlue, tCanScrollUp, tCanScrollDown, - + #define __COUNT_TOKEN__ (tCanScrollDown + 1) }; |