#include #include #include "config.h" #include "services/epgsearch.h" #include "services/remotetimers.h" #include "tools.h" #include "setup.h" #include "tvguideosd.h" cTvGuideOsd::cTvGuideOsd(void) { detailView = NULL; detailViewActive = false; activeGrid = NULL; timeLine = NULL; recMenuView = NULL; channelJumper = NULL; } cTvGuideOsd::~cTvGuideOsd() { delete timeManager; columns.Clear(); if (config.displayStatusHeader) { delete statusHeader; } if (detailView) delete detailView; delete timeLine; delete channelGroups; delete footer; delete recMenuView; if (channelJumper) delete channelJumper; osdManager.DeleteOsd(); } void cTvGuideOsd::Show(void) { int start = cTimeMs::Now(); if (osdManager.CreateOsd()) { bool themeChanged = config.LoadTheme(); config.SetStyle(); config.setDynamicValues(); bool geoChanged = geoManager.SetGeometry(cOsd::OsdWidth(), cOsd::OsdHeight()); if (themeChanged || geoChanged) { fontManager.DeleteFonts(); fontManager.SetFonts(); imgCache.Clear(); imgCache.CreateCache(); } osdManager.SetBackground(); timeManager = new cTimeManager(); timeManager->Now(); SwitchTimers.Load(AddDirectory(cPlugin::ConfigDirectory("epgsearch"), "epgsearchswitchtimers.conf")); recMenuView = new cRecMenuView(); pRemoteTimers = cPluginManager::CallFirstService("RemoteTimers::RefreshTimers-v1.0", NULL); if (pRemoteTimers) { isyslog("tvguide: remotetimers-plugin is available"); } if (config.useRemoteTimers && pRemoteTimers) { cString errorMsg; if (!pRemoteTimers->Service("RemoteTimers::RefreshTimers-v1.0", &errorMsg)) { esyslog("tvguide: %s", *errorMsg); } } drawOsd(); } esyslog("tvguide: Rendering took %d ms", int(cTimeMs::Now()-start)); } void cTvGuideOsd::drawOsd() { cPixmap::Lock(); int numBack = config.numGrids / 2; int offset = 0; const cChannel *newStartChannel; #if VDRVERSNUM >= 20301 { LOCK_CHANNELS_READ; const cChannel *startChannel = Channels->GetByNumber(cDevice::CurrentChannel()); #else cChannel *startChannel = Channels.GetByNumber(cDevice::CurrentChannel()); #endif newStartChannel = startChannel; #if VDRVERSNUM >= 20301 for (; newStartChannel ; newStartChannel = Channels->Prev(newStartChannel)) { #else for (; newStartChannel ; newStartChannel = Channels.Prev(newStartChannel)) { #endif if (newStartChannel && !newStartChannel->GroupSep()) { offset++; } if (offset == numBack) break; } if (!newStartChannel) #if VDRVERSNUM >= 20301 newStartChannel = Channels->First(); } //LOCK_CHANNELS_READ #else newStartChannel = Channels.First(); #endif offset--; if (offset < 0) offset = 0; if (config.displayStatusHeader) { statusHeader = new cStatusHeader(); statusHeader->Draw(); statusHeader->ScaleVideo(); } timeLine = new cTimeLine(timeManager); timeLine->DrawDateViewer(); timeLine->DrawTimeline(); timeLine->DrawClock(); channelGroups = new cChannelGroups(); channelGroups->ReadChannelGroups(); footer = new cFooter(channelGroups); recMenuView->AddFooter(footer); footer->drawRedButton(); if (config.channelJumpMode == eNumJump) { footer->drawGreenButton(); footer->drawYellowButton(); } footer->drawBlueButton(false); osdManager.Flush(); readChannels(newStartChannel); drawGridsChannelJump(offset); osdManager.Flush(); cPixmap::Unlock(); } void cTvGuideOsd::readChannels(const cChannel *channelStart) { int i=0; bool foundEnough = false; columns.Clear(); if (!channelStart) return; #if VDRVERSNUM >= 20301 const cChannels *channels; { LOCK_CHANNELS_READ; channels = Channels; } #else cChannels *channels = &Channels; #endif for (const cChannel *channel = channelStart; channel; channel = channels->Next(channel)) { if (!channel->GroupSep()) { if (channelGroups->IsInLastGroup(channel)) { break; } cChannelEpg *column = new cChannelEpg(i, channel, timeManager); if (column->readGrids()) { columns.Add(column); i++; } else { delete column; } } if (i == config.numGrids) { foundEnough = true; break; } } if (!foundEnough) { int numCurrent = columns.Count(); int numBack = config.numGrids - numCurrent; int newChannelNumber = columns.First()->getChannel()->Number() - numBack; const cChannel *newStart = channels->GetByNumber(newChannelNumber); readChannels(newStart); } } void cTvGuideOsd::drawGridsChannelJump(int offset) { if (columns.Count() == 0) return; activeGrid = columns.Get(offset)->getActive(); if (activeGrid) activeGrid->SetActive(); if (config.displayStatusHeader) { statusHeader->DrawInfoText(activeGrid); } if (activeGrid && (config.channelJumpMode == eGroupJump)) { footer->UpdateGroupButtons(activeGrid->column->getChannel()); } if (config.displayChannelGroups) { channelGroups->DrawChannelGroups(columns.First()->getChannel(), columns.Last()->getChannel()); } for (cChannelEpg *column = columns.First(); column; column = columns.Next(column)) { column->createHeader(); column->drawGrids(); } } void cTvGuideOsd::drawGridsTimeJump(bool last) { if (columns.Count() == 0) return; cChannelEpg *colActive = NULL; if (activeGrid) { colActive = activeGrid->column; } else { colActive = columns.First(); } for (cChannelEpg *column = columns.First(); column; column = columns.Next(column)) { column->clearGrids(); column->readGrids(); column->drawGrids(); } activeGrid = colActive->getActive(last); if (activeGrid) { activeGrid->SetActive(); activeGrid->Draw(); if (config.displayStatusHeader) { statusHeader->DrawInfoText(activeGrid); } } } void cTvGuideOsd::setNextActiveGrid(cGridElement *next) { if (!next || !activeGrid) { return; } activeGrid->SetInActive(); activeGrid->Draw(); activeGrid = next; activeGrid->SetActive(); activeGrid->Draw(); if (config.displayStatusHeader) { statusHeader->DrawInfoText(activeGrid); } } void cTvGuideOsd::channelForward() { cChannelEpg *colRight = columns.Next(activeGrid->column); bool colAdded = false; if (!colRight) { const cChannel *channelRight = activeGrid->column->getChannel(); const cChannels *channels; #if VDRVERSNUM >= 20301 { LOCK_CHANNELS_READ; channels = Channels; } #else channels = &Channels; #endif while (channelRight = channels->Next(channelRight)) { if (!channelRight->GroupSep()) { if (channelGroups->IsInLastGroup(channelRight)) { break; } colRight = new cChannelEpg(config.numGrids - 1, channelRight, timeManager); if (colRight->readGrids()) { break; } else { delete colRight; colRight = NULL; } } } if (colRight) { colAdded = true; if (columns.Count() == config.numGrids) { cChannelEpg *cFirst = columns.First(); columns.Del(cFirst); } for (cChannelEpg *column = columns.First(); column; column = columns.Next(column)) { column->SetNum(column->GetNum() - 1); column->drawHeader(); column->drawGrids(); } columns.Add(colRight); colRight->createHeader(); colRight->drawGrids(); } } if (colRight) { cGridElement *right = colRight->getNeighbor(activeGrid); if (right) { setNextActiveGrid(right); } } if (config.displayChannelGroups && colAdded) { channelGroups->DrawChannelGroups(columns.First()->getChannel(), columns.Last()->getChannel()); } if (activeGrid && (config.channelJumpMode == eGroupJump)) { footer->UpdateGroupButtons(activeGrid->column->getChannel()); } osdManager.Flush(); } void cTvGuideOsd::channelBack() { cChannelEpg *colLeft = columns.Prev(activeGrid->column); bool colAdded = false; if (!colLeft) { const cChannel *channelLeft = activeGrid->column->getChannel(); const cChannels *channels; #if VDRVERSNUM >= 20301 { LOCK_CHANNELS_READ; channels = Channels; } #else channels = &Channels; #endif while (channelLeft = channels->Prev(channelLeft)) { if (!channelLeft->GroupSep()) { colLeft = new cChannelEpg(0, channelLeft, timeManager); if (colLeft->readGrids()) { break; } else { delete colLeft; colLeft = NULL; } } } if (colLeft) { colAdded = true; if (columns.Count() == config.numGrids) { cChannelEpg *cLast = columns.Last(); columns.Del(cLast); } for (cChannelEpg *column = columns.First(); column; column = columns.Next(column)) { column->SetNum(column->GetNum() + 1); column->drawHeader(); column->drawGrids(); } columns.Ins(colLeft, columns.First()); colLeft->createHeader(); colLeft->drawGrids(); } } if (colLeft) { cGridElement *left = colLeft->getNeighbor(activeGrid); if (left) { setNextActiveGrid(left); } } if (config.displayChannelGroups && colAdded) { channelGroups->DrawChannelGroups(columns.First()->getChannel(), columns.Last()->getChannel()); } if (activeGrid && (config.channelJumpMode == eGroupJump)) { footer->UpdateGroupButtons(activeGrid->column->getChannel()); } osdManager.Flush(); } void cTvGuideOsd::timeForward() { bool actionDone = false; if ((timeManager->GetEnd() - activeGrid->EndTime())/60 < 30 ) { ScrollForward(); actionDone = true; } cGridElement *next = activeGrid->column->getNext(activeGrid); if (next) { if ( (next->EndTime() < timeManager->GetEnd()) || ( (timeManager->GetEnd() - next->StartTime())/60 > 30 ) ) { setNextActiveGrid(next); actionDone = true; } } if (!actionDone) { ScrollForward(); } osdManager.Flush(); } void cTvGuideOsd::ScrollForward() { timeManager->AddStep(config.stepMinutes); if (config.useHWAccel) { drawGridsTimeJump(true); timeLine->DrawDateViewer(); timeLine->DrawClock(); timeLine->DrawTimeline(); } else { timeLine->DrawDateViewer(); timeLine->DrawTimeline(); for (cChannelEpg *column = columns.First(); column; column = columns.Next(column)) { column->AddNewGridsAtEnd(); column->ClearOutdatedStart(); column->drawGrids(); } } } void cTvGuideOsd::timeBack() { bool actionDone = false; if ((activeGrid->StartTime() - timeManager->GetStart())/60 < 30 ) { ScrollBack(); actionDone = true; } cGridElement *prev = activeGrid->column->getPrev(activeGrid); if (prev) { if ( (prev->StartTime() > timeManager->GetStart()) || ( (prev->EndTime() - timeManager->GetStart())/60 > 30 ) || ( prev->isFirst()) ) { setNextActiveGrid(prev); actionDone = true; } } if (!actionDone) { ScrollBack(); } osdManager.Flush(); } void cTvGuideOsd::ScrollBack() { timeManager->DelStep(config.stepMinutes); if (config.useHWAccel) { drawGridsTimeJump(); timeLine->DrawDateViewer(); timeLine->DrawClock(); timeLine->DrawTimeline(); } else { timeLine->DrawDateViewer(); timeLine->DrawTimeline(); for (cChannelEpg *column = columns.First(); column; column = columns.Next(column)) { column->AddNewGridsAtStart(); column->ClearOutdatedEnd(); column->drawGrids(); } } } void cTvGuideOsd::processKeyUp() { if (!activeGrid) { return; } if (config.displayMode == eVertical) { timeBack(); } else if (config.displayMode == eHorizontal) { channelBack(); } } void cTvGuideOsd::processKeyDown() { if (!activeGrid) { return; } if (config.displayMode == eVertical) { timeForward(); } else if (config.displayMode == eHorizontal) { channelForward(); } } void cTvGuideOsd::processKeyLeft() { if (activeGrid == NULL) return; if (config.displayMode == eVertical) { channelBack(); } else if (config.displayMode == eHorizontal) { timeBack(); } } void cTvGuideOsd::processKeyRight() { if (activeGrid == NULL) return; if (config.displayMode == eVertical) { channelForward(); } else if (config.displayMode == eHorizontal) { timeForward(); } } void cTvGuideOsd::processKeyRed() { if ((activeGrid == NULL) || activeGrid->IsDummy()) return; recMenuView->Start(activeGrid->GetEvent()); } void cTvGuideOsd::processKeyGreen() { if (activeGrid == NULL) return; const cChannel *currentChannel = activeGrid->column->getChannel(); const cChannel *firstChannel = columns.First()->getChannel(); int currentCol = activeGrid->column->GetNum(); const cChannel *prev = NULL; if (config.channelJumpMode == eGroupJump) { int prevNum = channelGroups->GetPrevGroupChannelNumber(currentChannel); if (prevNum) { #if VDRVERSNUM >= 20301 LOCK_CHANNELS_READ; prev = Channels->GetByNumber(prevNum); #else prev = Channels.GetByNumber(prevNum); #endif } } else if (config.channelJumpMode == eNumJump) { int i = config.jumpChannels + 1; #if VDRVERSNUM >= 20301 LOCK_CHANNELS_READ; for (const cChannel *channel = firstChannel; channel; channel = Channels->Prev(channel)) { #else for (const cChannel *channel = firstChannel; channel; channel = Channels.Prev(channel)) { #endif if (!channel->GroupSep()) { prev = channel; i--; } if (i == 0) break; } } if (prev) { readChannels(prev); if (columns.Count() > 0) { if (config.channelJumpMode == eGroupJump) drawGridsChannelJump(); else drawGridsChannelJump(currentCol); } osdManager.Flush(); } } void cTvGuideOsd::processKeyYellow() { if (activeGrid == NULL) return; const cChannel *currentChannel = activeGrid->column->getChannel(); int currentCol = activeGrid->column->GetNum(); const cChannel *firstChannel = columns.First()->getChannel(); const cChannel *next = NULL; if (config.channelJumpMode == eGroupJump) { int nextNum = channelGroups->GetNextGroupChannelNumber(currentChannel); if (nextNum) { #if VDRVERSNUM >= 20301 LOCK_CHANNELS_READ; next = Channels->GetByNumber(nextNum); #else next = Channels.GetByNumber(nextNum); #endif } } else if (config.channelJumpMode == eNumJump) { int i=0; #if VDRVERSNUM >= 20301 LOCK_CHANNELS_READ; for (const cChannel *channel = firstChannel; channel; channel = Channels->Next(channel)) { #else for (const cChannel *channel = firstChannel; channel; channel = Channels.Next(channel)) { #endif if (channelGroups->IsInLastGroup(channel)) { break; } if (!channel->GroupSep()) { next = channel; i++; } if (i == (config.jumpChannels+1)) { break; } } } if (next) { readChannels(next); if (columns.Count() > 0) { if (config.channelJumpMode == eGroupJump) drawGridsChannelJump(); else drawGridsChannelJump(currentCol); } osdManager.Flush(); } } eOSState cTvGuideOsd::processKeyBlue(bool *alreadyUnlocked) { if (config.blueKeyMode == eBlueKeySwitch) { return ChannelSwitch(alreadyUnlocked); } else if (config.blueKeyMode == eBlueKeyEPG) { DetailedEPG(); } else if (config.blueKeyMode == eBlueKeyFavorites) { recMenuView->StartFavorites(); } return osContinue; } eOSState cTvGuideOsd::processKeyOk(bool *alreadyUnlocked) { if (config.blueKeyMode == eBlueKeySwitch) { DetailedEPG(); } else if (config.blueKeyMode == eBlueKeyEPG) { return ChannelSwitch(alreadyUnlocked); } else if (config.blueKeyMode == eBlueKeyFavorites) { DetailedEPG(); } return osContinue; } eOSState cTvGuideOsd::ChannelSwitch(bool *alreadyUnlocked) { if (activeGrid == NULL) return osContinue; const cChannel *currentChannel = activeGrid->column->getChannel(); if (currentChannel) { cPixmap::Unlock(); *alreadyUnlocked = true; cDevice::PrimaryDevice()->SwitchChannel(currentChannel, true); if (config.closeOnSwitch) { if (detailView) { delete detailView; detailView = NULL; detailViewActive = false; } return osEnd; } } return osContinue; } void cTvGuideOsd::DetailedEPG() { if (!activeGrid->IsDummy()) { detailViewActive = true; detailView = new cDetailView(activeGrid->GetEvent(), footer); footer->SetDetailedViewMode(); osdManager.Flush(); detailView->Start(); osdManager.Flush(); } } void cTvGuideOsd::processNumKey(int numKey) { if (config.numkeyMode == 0) { //timely jumps with 1,3,4,6,7,9 TimeJump(numKey); } else { //jump to specific channel ChannelJump(numKey); } } void cTvGuideOsd::TimeJump(int mode) { switch (mode) { case 1: { timeManager->DelStep(((config.displayMode == eVertical) ? config.bigStepHours : config.bigStepHoursHorizontal) * 60); } break; case 3: { timeManager->AddStep(((config.displayMode == eVertical) ? config.bigStepHours : config.bigStepHoursHorizontal) * 60); } break; case 4: { timeManager->DelStep(((config.displayMode == eVertical) ? config.hugeStepHours : config.hugeStepHoursHorizontal) * 60); } break; case 6: { timeManager->AddStep(((config.displayMode == eVertical) ? config.hugeStepHours : config.hugeStepHoursHorizontal) * 60); } break; case 7: { cTimeManager primeChecker; primeChecker.Now(); time_t prevPrime = primeChecker.getPrevPrimetime(timeManager->GetStart()); if (primeChecker.tooFarInPast(prevPrime)) return; timeManager->SetTime(prevPrime); } break; case 9: { cTimeManager primeChecker; time_t nextPrime = primeChecker.getNextPrimetime(timeManager->GetStart()); timeManager->SetTime(nextPrime); } break; default: return; } drawGridsTimeJump(); timeLine->DrawDateViewer(); timeLine->DrawClock(); timeLine->DrawTimeline(); osdManager.Flush(); } int cTvGuideOsd::GetLastValidChannel(void) { return channelGroups->GetLastValidChannel(); } void cTvGuideOsd::ChannelJump(int num) { if (!channelJumper) { int lastValidChannel = GetLastValidChannel(); channelJumper = new cChannelJump(channelGroups, lastValidChannel); } channelJumper->Set(num); channelJumper->DrawText(); osdManager.Flush(); } void cTvGuideOsd::CheckTimeout(void) { if (!channelJumper) return; if (channelJumper->TimeOut()) { int newChannelNum = channelJumper->GetChannel(); delete channelJumper; channelJumper = NULL; const cChannel *newChannel; #if VDRVERSNUM >= 20301 { LOCK_CHANNELS_READ; newChannel = Channels->GetByNumber(newChannelNum); } #else newChannel = Channels.GetByNumber(newChannelNum); #endif if (newChannel) { readChannels(newChannel); if (columns.Count() > 0) { drawGridsChannelJump(); } } osdManager.Flush(); } } void cTvGuideOsd::SetTimers() { for (cChannelEpg *column = columns.First(); column; column = columns.Next(column)) { column->SetTimers(); } } eOSState cTvGuideOsd::ProcessKey(eKeys Key) { eOSState state = osContinue; cPixmap::Lock(); bool alreadyUnlocked = false; if (recMenuView->IsActive()) { state = recMenuView->ProcessKey(Key); if (state == osEnd) { SetTimers(); osdManager.Flush(); } state = osContinue; } else if (detailViewActive) { if ((Key & ~k_Repeat) == kRed) { delete detailView; detailView = NULL; detailViewActive = false; processKeyRed(); } else if ((Key & ~k_Repeat) == kBlue) { delete detailView; detailView = NULL; detailViewActive = false; if ((config.blueKeyMode == eBlueKeySwitch) || (config.blueKeyMode == eBlueKeyFavorites)) { state = ChannelSwitch(&alreadyUnlocked); } else { osdManager.Flush(); state = osContinue; } } else if ((Key & ~k_Repeat) == kOk && (config.blueKeyMode == eBlueKeyEPG)) { delete detailView; detailView = NULL; detailViewActive = false; state = ChannelSwitch(&alreadyUnlocked); } else { state = detailView->ProcessKey(Key); if (state == osEnd) { delete detailView; detailView = NULL; detailViewActive = false; osdManager.Flush(); state = osContinue; } } } else { switch (Key & ~k_Repeat) { case kUp: processKeyUp(); break; case kDown: processKeyDown(); break; case kLeft: processKeyLeft(); break; case kRight: processKeyRight(); break; case kRed: processKeyRed(); break; case kGreen: processKeyGreen(); break; case kYellow: processKeyYellow(); break; case kBlue: state = processKeyBlue(&alreadyUnlocked); break; case kOk: state = processKeyOk(&alreadyUnlocked); break; case kBack: state = osEnd; break; case k0 ... k9: processNumKey(Key - k0); break; case kFastRew: TimeJump(1); break; // Doesnt work, if used from timeshiftmode case kFastFwd: TimeJump(3); break; case kPrev: TimeJump(4); break; case kNext: TimeJump(6); break; case kNone: if (channelJumper) CheckTimeout(); break; default: break; } if (timeLine->DrawClock()) { osdManager.Flush(); } } if (!alreadyUnlocked) { cPixmap::Unlock(); } return state; } void cTvGuideOsd::dump() { esyslog("tvguide: ------Dumping Content---------"); activeGrid->debug(); // int i=1; for (cChannelEpg *col = columns.First(); col; col = columns.Next(col)) { col->dumpGrids(); } }