/* Neutrino-GUI - DBoxII-Project Copyright (C) 2001 Steffen Hehn 'McClean' Copyright (C) 2004 Martin Griep 'vivamiga' Copyright (C) 2009-2014 Stefan Seyfried Copyright (C) 2017 Sven Hoefer License: GPL This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifdef HAVE_CONFIG_H #include #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "bouquetlist.h" #include #include #include #include #include #include #include #include #include #include #include extern CBouquetList *bouquetList; int sizes[EpgPlus::NumberOfSizeSettings]; time_t EpgPlus::duration = 0; int EpgPlus::sliderWidth = 0; int EpgPlus::channelsTableWidth = 0; int EpgPlus::entryFontSize = 0; int EpgPlus::channelNumberOffset = 0; // negative size means "screen width in percent" static EpgPlus::SizeSetting sizeSettingTable[] = { { EpgPlus::EPGPlus_channelentry_width, -15 }, { EpgPlus::EPGPlus_separationline_thickness, 1 } }; static bool bigfont = false; static int current_bouquet; Font *EpgPlus::Header::font = NULL; EpgPlus::Header::Header(CFrameBuffer *pframeBuffer __attribute__((unused)), int px, int py, int pwidth) { //this->frameBuffer = pframeBuffer; this->x = px; this->y = py; this->width = pwidth; this->head = NULL; } EpgPlus::Header::~Header() { if (this->head) { delete this->head; this->head = NULL; } } void EpgPlus::Header::init() { font = g_Font[SNeutrinoSettings::FONT_TYPE_MENU_TITLE]; } void EpgPlus::Header::paint(const char *Name) { std::string caption = Name ? Name : g_Locale->getText(LOCALE_EPGPLUS_HEAD); if (this->head == NULL) { this->head = new CComponentsHeader(); this->head->setContextButton(CComponentsHeader::CC_BTN_HELP | CComponentsHeader::CC_BTN_EXIT); this->head->enableClock(); this->head->enableShadow(CC_SHADOW_RIGHT | CC_SHADOW_CORNER_TOP_RIGHT | CC_SHADOW_CORNER_BOTTOM_RIGHT, -1, true); } if (this->head) { if (g_settings.channellist_show_channellogo) { // ensure to have clean background this->logo = this->head->getChannelLogoObject(); this->logo->hide(); this->logo->allowPaint(false); } this->head->setDimensionsAll(this->x, this->y, this->width, this->font->getHeight()); this->head->setCaption(caption); this->head->paint(CC_SAVE_SCREEN_NO); } } void EpgPlus::Header::paintChannelLogo(const CZapitChannel *Channel) { if (!g_settings.channellist_show_channellogo) return; if (this->head) { this->logo->hide(); this->logo->clearSavedScreen(); if (Channel) { this->head->setChannelLogo(Channel->getChannelID(), Channel->getName(), (CCHeaderTypes::cc_logo_alignment_t)g_settings.channellist_show_channellogo); } this->logo->allowPaint(true); this->logo->paint(); } } int EpgPlus::Header::getUsedHeight() { return font->getHeight(); } Font *EpgPlus::TimeLine::font = NULL; int EpgPlus::TimeLine::separationLineThickness = 0; EpgPlus::TimeLine::TimeLine(CFrameBuffer *pframeBuffer, int px, int py, int pwidth, int pstartX, int pdurationX) { this->frameBuffer = pframeBuffer; this->x = px; this->y = py; this->width = pwidth; this->startX = pstartX; this->durationX = pdurationX; } void EpgPlus::TimeLine::init() { font = g_Font[SNeutrinoSettings::FONT_TYPE_EPG_DATE]; separationLineThickness = sizes[EPGPlus_separationline_thickness]; } EpgPlus::TimeLine::~TimeLine() { } void EpgPlus::TimeLine::paint(time_t _startTime, int pduration) { this->clearMark(); int xPos = this->startX; this->currentDuration = pduration; int numberOfTicks = this->currentDuration / (60 * 60) * 2; int tickDist = (this->durationX) / numberOfTicks; time_t tickTime = _startTime; bool toggleColor = false; // display date of begin this->frameBuffer->paintBoxRel(this->x, this->y, this->width, this->font->getHeight(), COL_MENUCONTENT_PLUS_0); this->font->RenderString(this->x + OFFSET_INNER_MID, this->y + this->font->getHeight(), this->width, EpgPlus::getTimeString(_startTime, "%d-%b"), COL_MENUCONTENT_TEXT); // paint ticks for (int i = 0; i < numberOfTicks; ++i, xPos += tickDist, tickTime += pduration / numberOfTicks) { int xWidth = tickDist; if (xPos + xWidth > this->x + width) xWidth = this->x + width - xPos; this->frameBuffer->paintBoxRel(xPos, this->y, xWidth, this->font->getHeight(), toggleColor ? COL_MENUCONTENT_PLUS_0 : COL_MENUCONTENT_PLUS_1); std::string timeStr = EpgPlus::getTimeString(tickTime, "%H"); int textWidth = this->font->getRenderWidth(timeStr); this->font->RenderString(xPos - textWidth - OFFSET_INNER_MIN, this->y + this->font->getHeight(), textWidth, timeStr, COL_MENUCONTENT_TEXT); timeStr = EpgPlus::getTimeString(tickTime, "%M"); textWidth = this->font->getRenderWidth(timeStr); this->font->RenderString(xPos + OFFSET_INNER_MIN, this->y + this->font->getHeight(), textWidth, timeStr, COL_MENUCONTENT_TEXT); toggleColor = !toggleColor; } // shadow this->frameBuffer->paintBoxRel(this->x + this->width, this->y + OFFSET_SHADOW, OFFSET_SHADOW, this->getUsedHeight(), COL_SHADOW_PLUS_0); } void EpgPlus::TimeLine::paintGrid() { int xPos = this->startX; int numberOfTicks = this->currentDuration / (60 * 60) * 2; int tickDist = (this->durationX) / numberOfTicks; // paint ticks for (int i = 0; i < numberOfTicks; ++i, xPos += tickDist) { // display a line for the tick this->frameBuffer->paintVLineRel(xPos, this->y, this->font->getHeight(), COL_MENUCONTENTDARK_PLUS_0); } } void EpgPlus::TimeLine::paintMark(time_t _startTime, int pduration, int px, int pwidth) { // clear old mark this->clearMark(); // paint new mark CProgressBar pbbar = CProgressBar(px, this->y + this->font->getHeight(), pwidth, this->font->getHeight()); //pbbar.setActiveColor(COL_MENUCONTENTSELECTED_PLUS_0); pbbar.setType(CProgressBar::PB_TIMESCALE); time_t currentTime; time(¤tTime); if ((currentTime > _startTime) && (currentTime < _startTime + pduration)) { pbbar.setValues((currentTime - _startTime), pduration); } else { pbbar.setValues(0, pduration); } pbbar.paint(); // display start time before mark std::string timeStr = EpgPlus::getTimeString(_startTime, "%H:%M"); int textWidth = this->font->getRenderWidth(timeStr); this->font->RenderString(px - textWidth - OFFSET_INNER_MIN, this->y + this->font->getHeight() + this->font->getHeight(), textWidth, timeStr, COL_MENUCONTENT_TEXT); // display end time timeStr = EpgPlus::getTimeString(_startTime + pduration, "%H:%M"); textWidth = font->getRenderWidth(timeStr); int textX = 0; if (px + pwidth + textWidth + OFFSET_INNER_MIN < this->x + this->width) { // display end time after mark textX = px + pwidth + OFFSET_INNER_MIN; } else if (textWidth < pwidth - 2 * OFFSET_INNER_MIN) { // display end time before mark textX = px + pwidth - textWidth - OFFSET_INNER_MIN; } if (textX) this->font->RenderString(textX, this->y + this->font->getHeight() + this->font->getHeight(), textWidth, timeStr, COL_MENUCONTENT_TEXT); // paint the separation line if (separationLineThickness > 0) { this->frameBuffer->paintBoxRel(this->x, this->y + this->font->getHeight() + this->font->getHeight(), this->width, this->separationLineThickness, COL_MENUCONTENTDARK_PLUS_0); } } void EpgPlus::TimeLine::clearMark() { this->frameBuffer->paintBoxRel(this->x, this->y + this->font->getHeight(), this->width, this->font->getHeight(), COL_MENUCONTENT_PLUS_0); // paint the separation line if (separationLineThickness > 0) { this->frameBuffer->paintBoxRel(this->x, this->y + this->font->getHeight() + this->font->getHeight(), this->width, this->separationLineThickness, COL_MENUCONTENTDARK_PLUS_0); } } int EpgPlus::TimeLine::getUsedHeight() { return 2 * font->getHeight() + separationLineThickness; } Font *EpgPlus::ChannelEventEntry::font = NULL; int EpgPlus::ChannelEventEntry::separationLineThickness = 0; EpgPlus::ChannelEventEntry::ChannelEventEntry(const CChannelEvent *pchannelEvent, CFrameBuffer *pframeBuffer, TimeLine *ptimeLine, Footer *pfooter, int px, int py, int pwidth) { // copy neccessary? if (pchannelEvent != NULL) this->channelEvent = *pchannelEvent; this->frameBuffer = pframeBuffer; this->timeLine = ptimeLine; this->footer = pfooter; this->x = px; this->y = py; this->width = pwidth; } void EpgPlus::ChannelEventEntry::init() { font = g_Font[SNeutrinoSettings::FONT_TYPE_EPGPLUS_ITEM]; separationLineThickness = sizes[EPGPlus_separationline_thickness]; } EpgPlus::ChannelEventEntry::~ChannelEventEntry() { } bool EpgPlus::ChannelEventEntry::isSelected(time_t _selectedTime) const { return (_selectedTime >= this->channelEvent.startTime) && (_selectedTime < this->channelEvent.startTime + time_t (this->channelEvent.duration)); } void EpgPlus::ChannelEventEntry::paint(bool pisSelected, bool toggleColor) { bool selected = this->channelEvent.description.empty() ? false : pisSelected; fb_pixel_t color; fb_pixel_t bgcolor; getItemColors(color, bgcolor, selected, false, toggleColor, true /* toggle enlighten */); this->frameBuffer->paintBoxRel(this->x, this->y, this->width, this->font->getHeight(), bgcolor); this->font->RenderString(this->x + OFFSET_INNER_SMALL, this->y + this->font->getHeight(), this->width - 2 * OFFSET_INNER_SMALL > 0 ? this->width - 2 * OFFSET_INNER_SMALL : 0, this->channelEvent.description, color); // paint the separation lines if (separationLineThickness > 0) { // left side this->frameBuffer->paintBoxRel(this->x, this->y, this->separationLineThickness, this->font->getHeight(), COL_MENUCONTENTDARK_PLUS_0); // bottom this->frameBuffer->paintBoxRel(this->x, this->y + this->font->getHeight(), this->width, this->separationLineThickness, COL_MENUCONTENTDARK_PLUS_0); } if (pisSelected) { if (this->channelEvent.description.empty()) { // dummy channel event this->timeLine->clearMark(); } else { this->timeLine->paintMark(this->channelEvent.startTime, this->channelEvent.duration, this->x, this->width); } CShortEPGData shortEpgData; bool ret = CEitManager::getInstance()->getEPGidShort(this->channelEvent.eventID, &shortEpgData); std::string shortepg = shortEpgData.info1; if(!shortepg.empty()) { shortepg = str_replace("\\n", " ", shortepg); shortepg = str_replace("\n", " ", shortepg); shortepg = str_replace("\t", " ", shortepg); } this->footer->paintEventDetails(this->channelEvent.description, ret ? shortepg : ""); this->timeLine->paintGrid(); } } int EpgPlus::ChannelEventEntry::getUsedHeight() { return font->getHeight() + separationLineThickness; } Font *EpgPlus::ChannelEntry::font = NULL; int EpgPlus::ChannelEntry::separationLineThickness = 0; EpgPlus::ChannelEntry::ChannelEntry(const CZapitChannel *pchannel, int pindex, CFrameBuffer *pframeBuffer, Header *pheader, Footer *pfooter, CBouquetList *pbouquetList, int px, int py, int pwidth) { this->channel = pchannel; this->displayNumber = ""; this->displayName = ""; if (pchannel != NULL) { this->displayNumber = to_string(pchannel->number); this->displayName = pchannel->getName(); } this->index = pindex; this->frameBuffer = pframeBuffer; this->header = pheader; this->footer = pfooter; this->bouquetList = pbouquetList; this->x = px; this->y = py; this->width = pwidth; this->detailsLine = NULL; } void EpgPlus::ChannelEntry::init() { font = g_Font[SNeutrinoSettings::FONT_TYPE_EPGPLUS_ITEM]; separationLineThickness = sizes[EPGPlus_separationline_thickness]; } EpgPlus::ChannelEntry::~ChannelEntry() { for (TCChannelEventEntries::iterator It = this->channelEventEntries.begin(); It != this->channelEventEntries.end(); ++It) { delete *It; } this->channelEventEntries.clear(); if (this->detailsLine) { this->detailsLine->kill(); delete this->detailsLine; this->detailsLine = NULL; } } void EpgPlus::ChannelEntry::paint(bool isSelected, time_t _selectedTime) { fb_pixel_t color; fb_pixel_t bgcolor; int radius = isSelected ? RADIUS_MID : RADIUS_NONE; getItemColors(color, bgcolor, isSelected); this->frameBuffer->paintBoxRel(this->x, this->y, this->width, this->font->getHeight(), bgcolor, radius, CORNER_LEFT); int xPos = this->x + OFFSET_INNER_MID; int numberWidth = 0; if (g_settings.channellist_show_numbers) { // display channelnumber int xOffset = EpgPlus::channelNumberOffset - this->font->getRenderWidth(this->displayNumber); this->font->RenderString(xPos + xOffset, this->y + this->font->getHeight(), this->width - 2 * OFFSET_INNER_MID, this->displayNumber, color); numberWidth = EpgPlus::channelNumberOffset + OFFSET_INNER_SMALL; xPos += numberWidth; } // display channelname this->font->RenderString(xPos, this->y + this->font->getHeight(), this->width - numberWidth - 2 * OFFSET_INNER_MID, this->displayName, color); if (isSelected) { #if 0 for (uint32_t i = 0; i < this->bouquetList->Bouquets.size(); ++i) { CBouquet *bouquet = this->bouquetList->Bouquets[i]; for (int j = 0; j < bouquet->channelList->getSize(); ++j) { if ((*bouquet->channelList)[j]->number == this->channel->number) { this->footer->setBouquetChannelName(bouquet->channelList->getName(), this->channel->getName()); bouquet = NULL; break; } } if (bouquet == NULL) break; } #endif if (this->channel->pname) { this->footer->setBouquetChannelName(this->channel->pname, this->channel->getName()); } else { this->footer->setBouquetChannelName(CServiceManager::getInstance()->GetSatelliteName(this->channel->getSatellitePosition()), this->channel->getName()); } } // paint the separation line if (separationLineThickness > 0) { this->frameBuffer->paintBoxRel(this->x, this->y + this->font->getHeight(), this->width, this->separationLineThickness, COL_MENUCONTENTDARK_PLUS_0); } bool toggleColor = false; for (TCChannelEventEntries::iterator It = this->channelEventEntries.begin(); It != this->channelEventEntries.end(); ++It) { (*It)->paint(isSelected && (*It)->isSelected(_selectedTime), toggleColor); toggleColor = !toggleColor; } // kill detailsline if (detailsLine) { detailsLine->kill(); delete detailsLine; detailsLine = NULL; } // paint detailsline if (isSelected) { xPos = this->x - DETAILSLINE_WIDTH; int yPosTop = this->y + this->font->getHeight() / 2; int yPosBottom = this->footer->y + this->footer->getUsedHeight() / 2; if (detailsLine == NULL) detailsLine = new CComponentsDetailsLine(); detailsLine->setDimensionsAll(xPos, yPosTop, yPosBottom, this->font->getHeight() / 2, this->footer->getUsedHeight() - RADIUS_LARGE * 2); detailsLine->paint(false); this->header->paintChannelLogo(this->channel); } } int EpgPlus::ChannelEntry::getUsedHeight() { return font->getHeight() + separationLineThickness; } Font *EpgPlus::Footer::fontBouquetChannelName = NULL; Font *EpgPlus::Footer::fontEventDescription = NULL; Font *EpgPlus::Footer::fontEventInfo1 = NULL; EpgPlus::Footer::Footer(CFrameBuffer *pframeBuffer, int px, int py, int pwidth, int pbuttonHeight) { this->frameBuffer = pframeBuffer; this->x = px; this->y = py; this->width = pwidth; this->foot = NULL; this->buttonHeight = pbuttonHeight; this->buttonY = this->y - OFFSET_INTER - OFFSET_SHADOW - this->buttonHeight; } EpgPlus::Footer::~Footer() { delete foot; foot = NULL; } void EpgPlus::Footer::init() { fontBouquetChannelName = g_Font[SNeutrinoSettings::FONT_TYPE_EVENTLIST_ITEMSMALL]; fontEventDescription = g_Font[SNeutrinoSettings::FONT_TYPE_EVENTLIST_ITEMLARGE]; fontEventInfo1 = g_Font[SNeutrinoSettings::FONT_TYPE_EVENTLIST_EVENT]; } void EpgPlus::Footer::setBouquetChannelName(const std::string &newBouquetName, const std::string &newChannelName) { this->currentBouquetName = newBouquetName; this->currentChannelName = newChannelName; } int EpgPlus::Footer::getUsedHeight() { return fontBouquetChannelName->getHeight() + fontEventDescription->getHeight() + fontEventInfo1->getHeight() + 2 * OFFSET_INNER_SMALL; } void EpgPlus::Footer::paintEventDetails(const std::string &description, const std::string &info1) { int yPos = this->y; int frame_thickness = 1; // clear the whole footer this->frameBuffer->paintBoxRel(this->x + OFFSET_SHADOW, yPos + OFFSET_SHADOW, this->width, this->getUsedHeight(), COL_SHADOW_PLUS_0, RADIUS_LARGE); this->frameBuffer->paintBoxRel(this->x, yPos, this->width, this->getUsedHeight(), COL_MENUCONTENTDARK_PLUS_0, RADIUS_LARGE); this->frameBuffer->paintBoxFrame(this->x, yPos, this->width, this->getUsedHeight(), frame_thickness, COL_FRAME_PLUS_0, RADIUS_LARGE); // display bouquet and channel name yPos += OFFSET_INNER_SMALL + this->fontBouquetChannelName->getHeight(); this->fontBouquetChannelName->RenderString(this->x + OFFSET_INNER_MID, yPos, this->width - 2 * OFFSET_INNER_MID, this->currentBouquetName + ": " + this->currentChannelName, COL_MENUCONTENT_TEXT); // display event's descrition yPos += this->fontEventDescription->getHeight(); this->fontEventDescription->RenderString(this->x + OFFSET_INNER_MID, yPos, this->width - 2 * OFFSET_INNER_MID, description, COL_MENUCONTENT_TEXT); // display event's info1 yPos += this->fontEventInfo1->getHeight(); this->fontEventInfo1->RenderString(this->x + OFFSET_INNER_MID, yPos, this->width - 2 * OFFSET_INNER_MID, info1, COL_MENUCONTENT_TEXT); } struct button_label buttonLabels[] = { { NEUTRINO_ICON_BUTTON_RED, LOCALE_EPGPLUS_ACTIONS }, { NEUTRINO_ICON_BUTTON_GREEN, LOCALE_EPGPLUS_PREV_BOUQUET }, { NEUTRINO_ICON_BUTTON_YELLOW, LOCALE_EPGPLUS_NEXT_BOUQUET }, { NEUTRINO_ICON_BUTTON_BLUE, LOCALE_EPGPLUS_OPTIONS }, { NEUTRINO_ICON_BUTTON_INFO_SMALL, LOCALE_EPGMENU_EVENTINFO } }; void EpgPlus::Footer::paintButtons(button_label *pbuttonLabels, int numberOfButtons) { int buttonWidth = (this->width); if (!foot) foot = new CComponentsFooter(); foot->enableShadow(CC_SHADOW_ON, -1, true); if (!foot->isPainted()) foot->paintButtons(this->x, this->buttonY, buttonWidth, buttonHeight, numberOfButtons, pbuttonLabels, buttonWidth / numberOfButtons); } EpgPlus::EpgPlus() { selectedChannelEntry = NULL; this->init(); } EpgPlus::~EpgPlus() { this->free(); } void EpgPlus::createChannelEntries(int selectedChannelEntryIndex) { for (TChannelEntries::iterator It = this->displayedChannelEntries.begin(); It != this->displayedChannelEntries.end(); ++It) { delete *It; } this->displayedChannelEntries.clear(); this->selectedChannelEntry = NULL; if (selectedChannelEntryIndex < this->channelList->getSize()) { for (;;) { if (selectedChannelEntryIndex < this->channelListStartIndex) { this->channelListStartIndex -= this->maxNumberOfDisplayableEntries; if (this->channelListStartIndex < 0) this->channelListStartIndex = 0; } else if (selectedChannelEntryIndex >= this->channelListStartIndex + this->maxNumberOfDisplayableEntries) { this->channelListStartIndex += this->maxNumberOfDisplayableEntries; } else break; } int yPosChannelEntry = this->channelsTableY; int yPosEventEntry = this->eventsTableY; for (int i = this->channelListStartIndex; (i < this->channelListStartIndex + this->maxNumberOfDisplayableEntries) && (i < this->channelList->getSize()); ++i, yPosChannelEntry += this->entryHeight, yPosEventEntry += this->entryHeight) { CZapitChannel *channel = (*this->channelList)[i]; ChannelEntry *channelEntry = new ChannelEntry(channel, i, this->frameBuffer, this->header, this->footer, this->bouquetList, this->channelsTableX, yPosChannelEntry, this->channelsTableWidth); //printf("Going to get getEventsServiceKey for %llx\n", (channel->getChannelID() & 0xFFFFFFFFFFFFULL)); CChannelEventList channelEventList; CEitManager::getInstance()->getEventsServiceKey(channel->getEpgID(), channelEventList); //printf("channelEventList size %d\n", channelEventList.size()); int widthEventEntry = 0; time_t lastEndTime = this->startTime; CChannelEventList::const_iterator lastIt(channelEventList.end()); //for (CChannelEventList::const_iterator It = channelEventList.begin(); (It != channelEventList.end()) && (It->startTime < (this->startTime + this->duration)); ++It) for (CChannelEventList::const_iterator It = channelEventList.begin(); It != channelEventList.end(); ++It) { //if (0x2bc000b004b7ULL == (channel->getChannelID() & 0xFFFFFFFFFFFFULL)) printf("*** Check1 event %s event start %ld this start %ld\n", It->description.c_str(), It->startTime, (this->startTime + this->duration)); if (!(It->startTime < (this->startTime + this->duration))) continue; if ((lastIt == channelEventList.end()) || (lastIt->startTime != It->startTime)) { int startTimeDiff = It->startTime - this->startTime; int endTimeDiff = this->startTime + time_t (this->duration) - It->startTime - time_t (It->duration); //if (0x2bc000b004b7ULL == (channel->getChannelID() & 0xFFFFFFFFFFFFULL)) printf("*** Check event %s\n", It->description.c_str()); if ((startTimeDiff >= 0) && (endTimeDiff >= 0)) { // channel event fits completely in the visible part of time line startTimeDiff = 0; endTimeDiff = 0; } else if ((startTimeDiff < 0) && (endTimeDiff < 0)) { // channel event starts and ends outside visible part of the time line but covers complete visible part } else if ((startTimeDiff < 0) && (endTimeDiff < this->duration)) { // channel event starts before visible part of the time line but ends in the visible part endTimeDiff = 0; } else if ((endTimeDiff < 0) && (startTimeDiff < this->duration)) { // channel event ends after visible part of the time line but starts in the visible part startTimeDiff = 0; } else if (startTimeDiff > 0) { // channel event starts and ends after visible part of the time line => break the loop //if (0x2bc000b004b7ULL == (channel->getChannelID() & 0xFFFFFFFFFFFFULL)) printf("*** break 1\n"); break; } else { // channel event starts and ends after visible part of the time line => ignore the channel event //if (0x2bc000b004b7ULL == (channel->getChannelID() & 0xFFFFFFFFFFFFULL)) printf("*** continue 1 startTimeDiff %ld endTimeDiff %ld\n", startTimeDiff, endTimeDiff); continue; } if (lastEndTime < It->startTime) { // there is a gap between last end time and new start time => fill it with a new event entry CChannelEvent channelEvent; channelEvent.startTime = lastEndTime; channelEvent.duration = It->startTime - channelEvent.startTime; ChannelEventEntry *channelEventEntry = new ChannelEventEntry(&channelEvent, this->frameBuffer, this->timeLine, this->footer, this->eventsTableX + ((channelEvent.startTime - this->startTime) * this->eventsTableWidth) / this->duration, yPosEventEntry, (channelEvent.duration * this->eventsTableWidth) / this->duration + 1); channelEntry->channelEventEntries.push_back(channelEventEntry); } // correct position int xPosEventEntry = this->eventsTableX + ((It->startTime - startTimeDiff - this->startTime) * this->eventsTableWidth) / this->duration; // correct width widthEventEntry = ((It->duration + startTimeDiff + endTimeDiff) * this->eventsTableWidth) / this->duration + 1; if (widthEventEntry < 0) widthEventEntry = 0; if (xPosEventEntry + widthEventEntry > this->eventsTableX + this->eventsTableWidth) widthEventEntry = this->eventsTableX + this->eventsTableWidth - xPosEventEntry; ChannelEventEntry *channelEventEntry = new ChannelEventEntry(&(*It), this->frameBuffer, this->timeLine, this->footer, xPosEventEntry, yPosEventEntry, widthEventEntry); channelEntry->channelEventEntries.push_back(channelEventEntry); lastEndTime = It->startTime + It->duration; } lastIt = It; } if (lastEndTime < this->startTime + time_t (this->duration)) { // there is a gap between last end time and end of the timeline => fill it with a new event entry CChannelEvent channelEvent; channelEvent.startTime = lastEndTime; channelEvent.duration = this->startTime + this->duration - channelEvent.startTime; ChannelEventEntry *channelEventEntry = new ChannelEventEntry(&channelEvent, this->frameBuffer, this->timeLine, this->footer, this->eventsTableX + ((channelEvent.startTime - this->startTime) * this->eventsTableWidth) / this->duration, yPosEventEntry, (channelEvent.duration * this->eventsTableWidth) / this->duration + 1); channelEntry->channelEventEntries.push_back(channelEventEntry); } this->displayedChannelEntries.push_back(channelEntry); } this->selectedChannelEntry = this->displayedChannelEntries[selectedChannelEntryIndex - this->channelListStartIndex]; } // get largest channelnumber int n = 1; for (TChannelEntries::iterator It = this->displayedChannelEntries.begin(); It != this->displayedChannelEntries.end(); ++It) { n = std::max(n, (*It)->channel->number); } channelNumberOffset = ChannelEntry::font->getRenderWidth(to_string(n)); } void EpgPlus::init() { frameBuffer = CFrameBuffer::getInstance(); #if 0 currentViewMode = ViewMode_Scroll; currentSwapMode = SwapMode_ByPage; #endif usableScreenWidth = frameBuffer->getWindowWidth(); usableScreenHeight = frameBuffer->getWindowHeight(); for (size_t i = 0; i < NumberOfSizeSettings; ++i) { int size = sizeSettingTable[i].size; if (size < 0) /* size < 0 == width in percent x -1 */ size = usableScreenWidth * size / -100; sizes[i] = size; } if (entryFontSize == 0) entryFontSize = g_Font[SNeutrinoSettings::FONT_TYPE_EPGPLUS_ITEM]->getSize(); // reset possible bigfont g_Font[SNeutrinoSettings::FONT_TYPE_EPGPLUS_ITEM]->setSize(entryFontSize); if (bigfont) g_Font[SNeutrinoSettings::FONT_TYPE_EPGPLUS_ITEM]->setSize((int)(entryFontSize * BIGFONT_FACTOR)); Header::init(); TimeLine::init(); ChannelEntry::init(); ChannelEventEntry::init(); Footer::init(); channelsTableWidth = sizes[EPGPlus_channelentry_width]; sliderWidth = SCROLLBAR_WIDTH; int headerHeight = Header::getUsedHeight(); int timeLineHeight = TimeLine::getUsedHeight(); this->entryHeight = ChannelEntry::getUsedHeight(); int buttonHeight = headerHeight; int footerHeight = Footer::getUsedHeight(); this->maxNumberOfDisplayableEntries = (this->usableScreenHeight - headerHeight - timeLineHeight - buttonHeight - OFFSET_SHADOW - OFFSET_INTER - footerHeight - OFFSET_SHADOW) / this->entryHeight; this->bodyHeight = this->maxNumberOfDisplayableEntries * entryHeight; this->usableScreenHeight = headerHeight + timeLineHeight + this->bodyHeight + buttonHeight + OFFSET_SHADOW + OFFSET_INTER + footerHeight + OFFSET_SHADOW; // recalc deltaY this->usableScreenX = getScreenStartX(this->usableScreenWidth); if (this->usableScreenX < DETAILSLINE_WIDTH) this->usableScreenX = DETAILSLINE_WIDTH; this->usableScreenY = getScreenStartY(this->usableScreenHeight); this->headerX = this->usableScreenX; this->headerY = this->usableScreenY; this->headerWidth = this->usableScreenWidth; this->timeLineX = this->usableScreenX; this->timeLineY = this->usableScreenY + headerHeight; this->timeLineWidth = this->usableScreenWidth; this->footerX = usableScreenX; this->footerY = this->usableScreenY + this->usableScreenHeight - OFFSET_SHADOW - footerHeight; this->footerWidth = this->usableScreenWidth; this->channelsTableX = this->usableScreenX; this->channelsTableY = this->timeLineY + timeLineHeight; this->channelsTableHeight = this->bodyHeight; this->eventsTableX = this->channelsTableX + channelsTableWidth; this->eventsTableY = this->channelsTableY; this->eventsTableWidth = this->usableScreenWidth - this->channelsTableWidth - this->sliderWidth; this->eventsTableHeight = this->bodyHeight; this->sliderX = this->usableScreenX + this->usableScreenWidth - this->sliderWidth; this->sliderY = this->eventsTableY; this->sliderHeight = this->bodyHeight; this->channelListStartIndex = 0; this->startTime = 0; this->duration = 2 * 60 * 60; this->refreshAll = false; this->currentViewMode = ViewMode_Scroll; this->currentSwapMode = SwapMode_ByBouquet; //SwapMode_ByPage; this->header = new Header(this->frameBuffer, this->headerX, this->headerY, this->headerWidth); this->timeLine = new TimeLine(this->frameBuffer, this->timeLineX, this->timeLineY, this->timeLineWidth, this->eventsTableX, this->eventsTableWidth); this->footer = new Footer(this->frameBuffer, this->footerX, this->footerY, this->footerWidth, buttonHeight); } void EpgPlus::free() { delete this->header; delete this->timeLine; delete this->footer; } int EpgPlus::exec(CChannelList *pchannelList, int selectedChannelIndex, CBouquetList *pbouquetList) { this->channelList = pchannelList; this->channelListStartIndex = int (selectedChannelIndex / maxNumberOfDisplayableEntries) * maxNumberOfDisplayableEntries; this->bouquetList = pbouquetList; int res = menu_return::RETURN_REPAINT; COSDFader fader(g_settings.theme.menu_Content_alpha); do { this->refreshFooterButtons = false; time_t currentTime = time(NULL); tm tmStartTime = *localtime(¤tTime); tmStartTime.tm_sec = 0; tmStartTime.tm_min = int (tmStartTime.tm_min / 15) * 15; this->startTime = mktime(&tmStartTime); this->selectedTime = this->startTime; this->firstStartTime = this->startTime; if (this->selectedChannelEntry != NULL) { selectedChannelIndex = this->selectedChannelEntry->index; } neutrino_msg_t msg; neutrino_msg_data_t data; this->createChannelEntries(selectedChannelIndex); if (!this->refreshAll) fader.StartFadeIn(); this->refreshAll = false; this->header->paint(this->channelList->getName()); this->footer->paintButtons(buttonLabels, sizeof(buttonLabels) / sizeof(button_label)); this->paint(); int timeout = g_settings.timing[SNeutrinoSettings::TIMING_CHANLIST]; uint64_t timeoutEnd = CRCInput::calcTimeoutEnd(timeout); bool loop = true; while (loop) { g_RCInput->getMsgAbsoluteTimeout(&msg, &data, &timeoutEnd); if (msg <= CRCInput::RC_MaxRC) timeoutEnd = CRCInput::calcTimeoutEnd(timeout); if ((msg == NeutrinoMessages::EVT_TIMER) && (data == fader.GetFadeTimer())) { if (fader.FadeDone()) loop = false; } else if ((msg == CRCInput::RC_timeout) || (msg == (neutrino_msg_t) g_settings.key_channelList_cancel)) { if (fader.StartFadeOut()) { timeoutEnd = CRCInput::calcTimeoutEnd(1); msg = 0; } else loop = false; } else if (msg == CRCInput::RC_epg) { loop = false; } else if (msg == CRCInput::RC_help) { //fprintf(stderr, "RC_help, bigfont = %d\n", bigfont); hide(); bigfont = !bigfont; free(); init(); refreshAll = true; break; } else if (msg == CRCInput::RC_page_down && this->selectedChannelEntry != NULL) { int selected = this->selectedChannelEntry->index; int prev_selected = selected; int step = this->maxNumberOfDisplayableEntries; int listSize = this->channelList->getSize(); selected += step; if (selected >= listSize) { if ((listSize - step - 1 < prev_selected) && (prev_selected != (listSize - 1))) selected = listSize - 1; else if (((listSize / step) + 1) * step == listSize + step) // last page has full entries selected = 0; else selected = ((selected < (((listSize / step) + 1) * step))) ? (listSize - 1) : 0; } this->createChannelEntries(selected); this->paint(); } else if (msg == CRCInput::RC_page_up && this->selectedChannelEntry != NULL) { int selected = this->selectedChannelEntry->index; int prev_selected = selected; int step = this->maxNumberOfDisplayableEntries; selected -= step; if ((prev_selected - step) < 0) { if (prev_selected != 0 && step != 1) selected = 0; else selected = this->channelList->getSize() - 1; } this->createChannelEntries(selected); this->paint(); } if (msg == CRCInput::RC_yellow) { if (!bouquetList->Bouquets.empty()) { bool found = true; uint32_t nNext = (bouquetList->getActiveBouquetNumber() + 1) % bouquetList->Bouquets.size(); //printf("EpgPlus::exec current bouquet %d new %d\n", bouquetList->getActiveBouquetNumber(), nNext); if (bouquetList->Bouquets[nNext]->channelList->isEmpty()) { found = false; nNext = nNext < bouquetList->Bouquets.size() - 1 ? nNext + 1 : 0; for (uint32_t i = nNext; i < bouquetList->Bouquets.size(); i++) { if (!bouquetList->Bouquets[i]->channelList->isEmpty()) { found = true; nNext = i; break; } } } //printf("EpgPlus::exec found %d new %d\n", found, nNext); if (found) { pbouquetList->activateBouquet(nNext, false); this->channelList = bouquetList->Bouquets[nNext]->channelList; this->channelListStartIndex = int (channelList->getSelectedChannelIndex() / maxNumberOfDisplayableEntries) * maxNumberOfDisplayableEntries; this->createChannelEntries(channelList->getSelectedChannelIndex()); this->header->paint(this->channelList->getName()); this->paint(); } } } else if (msg == CRCInput::RC_green) { if (!bouquetList->Bouquets.empty()) { bool found = true; int nNext = (bouquetList->getActiveBouquetNumber() + bouquetList->Bouquets.size() - 1) % bouquetList->Bouquets.size(); if (bouquetList->Bouquets[nNext]->channelList->isEmpty()) { found = false; nNext = nNext > 0 ? nNext - 1 : bouquetList->Bouquets.size() - 1; for (int i = nNext; i > 0; i--) { if (!bouquetList->Bouquets[i]->channelList->isEmpty()) { found = true; nNext = i; break; } } } if (found) { pbouquetList->activateBouquet(nNext, false); this->channelList = bouquetList->Bouquets[nNext]->channelList; this->channelListStartIndex = int (channelList->getSelectedChannelIndex() / maxNumberOfDisplayableEntries) * maxNumberOfDisplayableEntries; this->createChannelEntries(channelList->getSelectedChannelIndex()); this->header->paint(this->channelList->getName()); this->paint(); } } } else if (msg == CRCInput::RC_ok) { if (selectedChannelEntry) { CNeutrinoApp::getInstance()->channelList->zapTo_ChannelID(selectedChannelEntry->channel->getChannelID()); } current_bouquet = bouquetList->getActiveBouquetNumber(); } else if (CRCInput::isNumeric(msg) && !bouquetList->Bouquets.empty()) { this->hide(); CNeutrinoApp::getInstance()->channelList->numericZap(msg); //printf("numericZap: prev bouquet %d new %d\n", current_bouquet, bouquetList->getActiveBouquetNumber()); current_bouquet = bouquetList->getActiveBouquetNumber(); this->channelList = bouquetList->Bouquets[current_bouquet]->channelList; this->channelListStartIndex = int (channelList->getSelectedChannelIndex() / maxNumberOfDisplayableEntries) * maxNumberOfDisplayableEntries; g_InfoViewer->killTitle(); int selectedChannelEntryIndex = this->channelList->getSelectedChannelIndex(); if (selectedChannelEntryIndex < this->channelList->getSize()) { this->hide(); this->createChannelEntries(selectedChannelEntryIndex); this->header->paint(this->channelList->getName()); this->footer->paintButtons(buttonLabels, sizeof(buttonLabels) / sizeof(button_label)); this->paint(); } } else if (msg == CRCInput::RC_up && this->selectedChannelEntry != NULL) { int selectedChannelEntryIndex = this->selectedChannelEntry->index; int prevSelectedChannelEntryIndex = selectedChannelEntryIndex; --selectedChannelEntryIndex; if (selectedChannelEntryIndex < 0) { selectedChannelEntryIndex = this->channelList->getSize() - 1; } int oldChannelListStartIndex = this->channelListStartIndex; this->channelListStartIndex = (selectedChannelEntryIndex / this->maxNumberOfDisplayableEntries) * this->maxNumberOfDisplayableEntries; if (oldChannelListStartIndex != this->channelListStartIndex) { this->createChannelEntries(selectedChannelEntryIndex); this->paint(); } else { this->selectedChannelEntry = this->displayedChannelEntries[selectedChannelEntryIndex - this->channelListStartIndex]; this->paintChannelEntry(prevSelectedChannelEntryIndex - this->channelListStartIndex); this->paintChannelEntry(selectedChannelEntryIndex - this->channelListStartIndex); } } else if (msg == CRCInput::RC_down && this->selectedChannelEntry != NULL) { int selectedChannelEntryIndex = this->selectedChannelEntry->index; int prevSelectedChannelEntryIndex = this->selectedChannelEntry->index; selectedChannelEntryIndex = (selectedChannelEntryIndex + 1) % this->channelList->getSize(); int oldChannelListStartIndex = this->channelListStartIndex; this->channelListStartIndex = (selectedChannelEntryIndex / this->maxNumberOfDisplayableEntries) * this->maxNumberOfDisplayableEntries; if (oldChannelListStartIndex != this->channelListStartIndex) { this->createChannelEntries(selectedChannelEntryIndex); this->paint(); } else { this->selectedChannelEntry = this->displayedChannelEntries[selectedChannelEntryIndex - this->channelListStartIndex]; this->paintChannelEntry(prevSelectedChannelEntryIndex - this->channelListStartIndex); this->paintChannelEntry(this->selectedChannelEntry->index - this->channelListStartIndex); } } else if (msg == CRCInput::RC_red) { CMenuWidget menuWidgetActions(LOCALE_EPGPLUS_ACTIONS, NEUTRINO_ICON_FEATURES); menuWidgetActions.enableFade(false); MenuTargetAddRecordTimer record(this); MenuTargetRefreshEpg refresh(this); MenuTargetAddReminder remind(this); if (!g_settings.minimode) menuWidgetActions.addItem(new CMenuForwarder(LOCALE_EPGPLUS_RECORD, true, NULL, &record, NULL, CRCInput::RC_red), false); menuWidgetActions.addItem(new CMenuForwarder(LOCALE_EPGPLUS_REFRESH_EPG, true, NULL, &refresh, NULL, CRCInput::RC_green), false); menuWidgetActions.addItem(new CMenuForwarder(LOCALE_EPGPLUS_REMIND, true, NULL, &remind, NULL, CRCInput::RC_yellow), false); if (selectedChannelEntry) menuWidgetActions.exec(NULL, ""); this->refreshAll = true; } else if (msg == CRCInput::RC_blue) { CMenuWidget menuWidgetOptions(LOCALE_EPGPLUS_OPTIONS, NEUTRINO_ICON_FEATURES); menuWidgetOptions.enableFade(false); //menuWidgetOptions.addItem(new MenuOptionChooserSwitchSwapMode(this)); menuWidgetOptions.addItem(new MenuOptionChooserSwitchViewMode(this)); int result = menuWidgetOptions.exec(NULL, ""); if (result == menu_return::RETURN_REPAINT) { this->refreshAll = true; } else if (result == menu_return::RETURN_EXIT_ALL) { this->refreshAll = true; } } else if (msg == CRCInput::RC_left) { switch (this->currentViewMode) { case ViewMode_Stretch: { if (this->duration - 30 * 60 > 30 * 60) { this->duration -= 30 * 60; this->hide(); this->refreshAll = true; } break; } case ViewMode_Scroll: { if (this->selectedChannelEntry == NULL) break; TCChannelEventEntries::const_iterator It = this->getSelectedEvent(); if ((It != this->selectedChannelEntry->channelEventEntries.begin()) && (It != this->selectedChannelEntry->channelEventEntries.end())) { --It; this->selectedTime = (*It)->channelEvent.startTime + (*It)->channelEvent.duration / 2; if (this->selectedTime < this->startTime) this->selectedTime = this->startTime; this->selectedChannelEntry->paint(true, this->selectedTime); } else { if (this->startTime != this->firstStartTime) { if (this->startTime - this->duration > this->firstStartTime) { this->startTime -= this->duration; } else { this->startTime = this->firstStartTime; } this->selectedTime = this->startTime + this->duration - 1; // select last event this->createChannelEntries(this->selectedChannelEntry->index); this->paint(); } } break; } } } else if (msg == CRCInput::RC_right) { switch (this->currentViewMode) { case ViewMode_Stretch: { if (this->duration + 30 * 60 < 4 * 60 * 60) { this->duration += 60 * 60; this->hide(); this->refreshAll = true; } break; } case ViewMode_Scroll: { if (this->selectedChannelEntry == NULL) break; TCChannelEventEntries::const_iterator It = this->getSelectedEvent(); if ((It != this->selectedChannelEntry->channelEventEntries.end() - 1) && (It != this->selectedChannelEntry->channelEventEntries.end())) { ++It; this->selectedTime = (*It)->channelEvent.startTime + (*It)->channelEvent.duration / 2; if (this->selectedTime > this->startTime + time_t (this->duration)) this->selectedTime = this->startTime + this->duration; this->selectedChannelEntry->paint(true, this->selectedTime); } else { this->startTime += this->duration; this->selectedTime = this->startTime; this->createChannelEntries(this->selectedChannelEntry->index); this->paint(); } break; } } } else if (msg == CRCInput::RC_info && this->selectedChannelEntry != NULL) { TCChannelEventEntries::const_iterator It = this->getSelectedEvent(); if (It != this->selectedChannelEntry->channelEventEntries.end()) { if ((*It)->channelEvent.eventID != 0) { this->hide(); time_t startTime2 = (*It)->channelEvent.startTime; res = g_EpgData->show(this->selectedChannelEntry->channel->getChannelID(), (*It)->channelEvent.eventID, &startTime2); if (res == menu_return::RETURN_EXIT_ALL) { loop = false; } else { g_RCInput->getMsg(&msg, &data, 0); if ((msg != CRCInput::RC_red) && (msg != CRCInput::RC_timeout)) { // RC_red schlucken g_RCInput->postMsg(msg, data); } this->header->paint(this->channelList->getName()); this->footer->paintButtons(buttonLabels, sizeof(buttonLabels) / sizeof(button_label)); this->paint(); } } } } else if (CNeutrinoApp::getInstance()->backKey(msg)) { loop = false; res = menu_return::RETURN_EXIT_ALL; } else if (CNeutrinoApp::getInstance()->listModeKey(msg)) { g_RCInput->postMsg(msg, 0); res = menu_return::RETURN_EXIT_ALL; loop = false; } else if (msg == NeutrinoMessages::EVT_SERVICESCHANGED || msg == NeutrinoMessages::EVT_BOUQUETSCHANGED) { g_RCInput->postMsg(msg, data); loop = false; res = menu_return::RETURN_EXIT_ALL; } else { if (CNeutrinoApp::getInstance()->handleMsg(msg, data) & messages_return::cancel_all) { loop = false; res = menu_return::RETURN_EXIT_ALL; } } if (this->refreshAll) loop = false; else if (this->refreshFooterButtons) this->footer->paintButtons(buttonLabels, sizeof(buttonLabels) / sizeof(button_label)); } this->hide(); fader.StopFade(); #if 0 for (TChannelEntries::iterator It = this->displayedChannelEntries.begin(); It != this->displayedChannelEntries.end(); It++) { delete *It; } this->displayedChannelEntries.clear(); #endif } while (this->refreshAll); for (TChannelEntries::iterator It = this->displayedChannelEntries.begin(); It != this->displayedChannelEntries.end(); ++It) { delete *It; } this->displayedChannelEntries.clear(); // reset possible bigfont g_Font[SNeutrinoSettings::FONT_TYPE_EPGPLUS_ITEM]->setSize(entryFontSize); return res; } EpgPlus::TCChannelEventEntries::const_iterator EpgPlus::getSelectedEvent() const { for (TCChannelEventEntries::const_iterator It = this->selectedChannelEntry->channelEventEntries.begin(); It != this->selectedChannelEntry->channelEventEntries.end(); ++It) { if ((*It)->isSelected(this->selectedTime)) { return It; } } return this->selectedChannelEntry->channelEventEntries.end(); } void EpgPlus::hide() { if (this->header->head) { this->header->head->kill(); delete this->header->head; this->header->head = NULL; } if (this->selectedChannelEntry && this->selectedChannelEntry->detailsLine) { this->selectedChannelEntry->detailsLine->kill(); delete this->selectedChannelEntry->detailsLine; this->selectedChannelEntry->detailsLine = NULL; } if (this->footer->foot) { this->footer->foot->kill(); delete this->footer->foot; this->footer->foot = NULL; } this->frameBuffer->paintBackgroundBoxRel(this->usableScreenX, this->usableScreenY, this->usableScreenWidth + OFFSET_SHADOW, this->usableScreenHeight + OFFSET_SHADOW); } void EpgPlus::paintChannelEntry(int position) { ChannelEntry *channelEntry = this->displayedChannelEntries[position]; bool currentChannelIsSelected = false; if (this->channelListStartIndex + position == this->selectedChannelEntry->index) { currentChannelIsSelected = true; } channelEntry->paint(currentChannelIsSelected, this->selectedTime); } std::string EpgPlus::getTimeString(const time_t &time, const std::string &format) { char tmpstr[256]; struct tm *tmStartTime = localtime(&time); strftime(tmpstr, sizeof(tmpstr), format.c_str(), tmStartTime); return tmpstr; } void EpgPlus::paint() { // clear //this->frameBuffer->paintBackgroundBoxRel(this->channelsTableX, this->channelsTableY, this->usableScreenWidth, this->channelsTableHeight); this->frameBuffer->paintBoxRel(this->channelsTableX, this->channelsTableY, this->usableScreenWidth, this->channelsTableHeight, COL_MENUCONTENT_PLUS_0); // paint the time line timeLine->paint(this->startTime, this->duration); // paint the channel entries for (int i = 0; i < (int) this->displayedChannelEntries.size(); ++i) { this->paintChannelEntry(i); } // paint the time line grid this->timeLine->paintGrid(); // paint slider int total_pages; int current_page; getScrollBarData(&total_pages, ¤t_page, this->channelList->getSize(), this->maxNumberOfDisplayableEntries, this->selectedChannelEntry == NULL ? 0 : this->selectedChannelEntry->index); paintScrollBar(this->sliderX, this->sliderY, this->sliderWidth, this->sliderHeight, total_pages, current_page, CC_SHADOW_RIGHT_CORNER_ALL); } EpgPlus::MenuTargetAddReminder::MenuTargetAddReminder(EpgPlus *pepgPlus) { this->epgPlus = pepgPlus; } int EpgPlus::MenuTargetAddReminder::exec(CMenuTarget * /*parent*/, const std::string & /*actionKey*/) { TCChannelEventEntries::const_iterator It = this->epgPlus->getSelectedEvent(); if ((It != this->epgPlus->selectedChannelEntry->channelEventEntries.end()) && (!(*It)->channelEvent.description.empty())) { if (g_Timerd->isTimerdAvailable()) { g_Timerd->addZaptoTimerEvent(this->epgPlus->selectedChannelEntry->channel->getChannelID(), (*It)->channelEvent.startTime - (g_settings.zapto_pre_time * 60), (*It)->channelEvent.startTime - ANNOUNCETIME - (g_settings.zapto_pre_time * 60), 0, (*It)->channelEvent.eventID, (*It)->channelEvent.startTime, 0); ShowMsg(LOCALE_TIMER_EVENTTIMED_TITLE, g_Locale->getText(LOCALE_TIMER_EVENTTIMED_MSG), CMsgBox::mbrBack, CMsgBox::mbBack, NEUTRINO_ICON_INFO); } else printf("timerd not available\n"); } return menu_return::RETURN_EXIT_ALL; } EpgPlus::MenuTargetAddRecordTimer::MenuTargetAddRecordTimer(EpgPlus *pepgPlus) { this->epgPlus = pepgPlus; } static bool sortByDateTime(const CChannelEvent &a, const CChannelEvent &b) { return a.startTime < b.startTime; } int EpgPlus::MenuTargetAddRecordTimer::exec(CMenuTarget * /*parent*/, const std::string & /*actionKey*/) { TCChannelEventEntries::const_iterator It = this->epgPlus->getSelectedEvent(); if ((It != this->epgPlus->selectedChannelEntry->channelEventEntries.end()) && (!(*It)->channelEvent.description.empty())) { bool doRecord = true; if (g_settings.recording_already_found_check) { CHintBox loadBox(LOCALE_RECORDING_ALREADY_FOUND_CHECK, LOCALE_MOVIEBROWSER_SCAN_FOR_MOVIES); loadBox.paint(); CMovieBrowser moviebrowser; const char *rec_title = (*It)->channelEvent.description.c_str(); bool already_found = moviebrowser.gotMovie(rec_title); loadBox.hide(); if (already_found) { printf("already found in moviebrowser: %s\n", rec_title); char message[1024]; snprintf(message, sizeof(message) - 1, g_Locale->getText(LOCALE_RECORDING_ALREADY_FOUND), rec_title); doRecord = (ShowMsg(LOCALE_RECORDING_ALREADY_FOUND_CHECK, message, CMsgBox::mbrYes, CMsgBox::mbYes | CMsgBox::mbNo) == CMsgBox::mbrYes); } } if (g_Timerd->isTimerdAvailable() && doRecord) { CChannelEventList evtlist; CEitManager::getInstance()->getEventsServiceKey(this->epgPlus->selectedChannelEntry->channel->channel_id, evtlist); sort(evtlist.begin(), evtlist.end(), sortByDateTime); CFollowScreenings m(this->epgPlus->selectedChannelEntry->channel->channel_id, (*It)->channelEvent.startTime, (*It)->channelEvent.startTime + (*It)->channelEvent.duration, (*It)->channelEvent.description, (*It)->channelEvent.eventID, TIMERD_APIDS_CONF, true, "", &evtlist); m.exec(NULL, ""); } else printf("timerd not available\n"); } return menu_return::RETURN_EXIT_ALL; } EpgPlus::MenuTargetRefreshEpg::MenuTargetRefreshEpg(EpgPlus *pepgPlus) { this->epgPlus = pepgPlus; } int EpgPlus::MenuTargetRefreshEpg::exec(CMenuTarget * /*parent*/, const std::string & /*actionKey*/) { this->epgPlus->refreshAll = true; return menu_return::RETURN_EXIT_ALL; } struct CMenuOptionChooser::keyval menuOptionChooserSwitchSwapModes[] = { { EpgPlus::SwapMode_ByPage, LOCALE_EPGPLUS_BYPAGE_MODE }, { EpgPlus::SwapMode_ByBouquet, LOCALE_EPGPLUS_BYBOUQUET_MODE } }; EpgPlus::MenuOptionChooserSwitchSwapMode::MenuOptionChooserSwitchSwapMode(EpgPlus *pepgPlus) : CMenuOptionChooser(LOCALE_EPGPLUS_SWAP_MODE, (int *) & pepgPlus->currentSwapMode, menuOptionChooserSwitchSwapModes, sizeof(menuOptionChooserSwitchSwapModes) / sizeof(CMenuOptionChooser::keyval), true, NULL, CRCInput::RC_yellow, NEUTRINO_ICON_BUTTON_YELLOW, 0) { this->epgPlus = pepgPlus; this->oldSwapMode = epgPlus->currentSwapMode; this->oldTimingMenuSettings = g_settings.timing[SNeutrinoSettings::TIMING_MENU]; } EpgPlus::MenuOptionChooserSwitchSwapMode::~MenuOptionChooserSwitchSwapMode() { g_settings.timing[SNeutrinoSettings::TIMING_MENU] = this->oldTimingMenuSettings; if (this->epgPlus->currentSwapMode != this->oldSwapMode) { switch (this->epgPlus->currentSwapMode) { case SwapMode_ByPage: { buttonLabels[1].locale = LOCALE_EPGPLUS_PAGE_DOWN; buttonLabels[2].locale = LOCALE_EPGPLUS_PAGE_UP; break; } case SwapMode_ByBouquet: { buttonLabels[1].locale = LOCALE_EPGPLUS_PREV_BOUQUET; buttonLabels[2].locale = LOCALE_EPGPLUS_NEXT_BOUQUET; break; } } this->epgPlus->refreshAll = true; } } int EpgPlus::MenuOptionChooserSwitchSwapMode::exec(CMenuTarget *parent) { // change time out settings temporary g_settings.timing[SNeutrinoSettings::TIMING_MENU] = 1; CMenuOptionChooser::exec(parent); return menu_return::RETURN_REPAINT; } struct CMenuOptionChooser::keyval menuOptionChooserSwitchViewModes[] = { { EpgPlus::ViewMode_Scroll, LOCALE_EPGPLUS_STRETCH_MODE }, { EpgPlus::ViewMode_Stretch, LOCALE_EPGPLUS_SCROLL_MODE } }; EpgPlus::MenuOptionChooserSwitchViewMode::MenuOptionChooserSwitchViewMode(EpgPlus *epgPlus) : CMenuOptionChooser(LOCALE_EPGPLUS_VIEW_MODE, (int *) & epgPlus->currentViewMode, menuOptionChooserSwitchViewModes, sizeof(menuOptionChooserSwitchViewModes) / sizeof(CMenuOptionChooser::keyval), true, NULL, CRCInput::RC_blue, NEUTRINO_ICON_BUTTON_BLUE) { this->oldTimingMenuSettings = g_settings.timing[SNeutrinoSettings::TIMING_MENU]; } EpgPlus::MenuOptionChooserSwitchViewMode::~MenuOptionChooserSwitchViewMode() { g_settings.timing[SNeutrinoSettings::TIMING_MENU] = this->oldTimingMenuSettings; } int EpgPlus::MenuOptionChooserSwitchViewMode::exec(CMenuTarget *parent) { // change time out settings temporary g_settings.timing[SNeutrinoSettings::TIMING_MENU] = 1; CMenuOptionChooser::exec(parent); return menu_return::RETURN_REPAINT; } // -- EPG+ Menu Handler Class // -- to be used for calls from Menu int CEPGplusHandler::exec(CMenuTarget *parent, const std::string & /*actionKey*/) { int res = menu_return::RETURN_EXIT_ALL; EpgPlus *e; CChannelList *channelList; if (parent) parent->hide(); e = new EpgPlus; //channelList = CNeutrinoApp::getInstance()->channelList; int bnum = bouquetList->getActiveBouquetNumber(); current_bouquet = bnum; if (!bouquetList->Bouquets.empty() && !bouquetList->Bouquets[bnum]->channelList->isEmpty()) channelList = bouquetList->Bouquets[bnum]->channelList; else channelList = CNeutrinoApp::getInstance()->channelList; e->exec(channelList, channelList->getSelectedChannelIndex(), bouquetList); delete e; // FIXME //printf("CEPGplusHandler::exec old bouquet %d new %d current %d\n", bnum, bouquetList->getActiveBouquetNumber(), current_bouquet); bouquetList->activateBouquet(current_bouquet, false); return res; }