Files
recycled-ni-neutrino/src/gui/channellist.cpp
Thilo Graf f271c801de COSDFader: rename member functions, adapt implementations
Stop() is not exactly attributable if fader class used as inherited and
Fade() don't tell really what done and related to return value 'bool'...
especially as the fader class members have been not documented.


Origin commit data
------------------
Commit: 69e2debb02
Author: Thilo Graf <dbt@novatux.de>
Date: 2014-05-30 (Fri, 30 May 2014)
2014-06-23 18:43:47 +02:00

2451 lines
78 KiB
C++

/*
Neutrino-GUI - DBoxII-Project
Copyright (C) 2001 Steffen Hehn 'McClean'
Copyright (C) 2007-2012 Stefan Seyfried
Kommentar:
Diese GUI wurde von Grund auf neu programmiert und sollte nun vom
Aufbau und auch den Ausbaumoeglichkeiten gut aussehen. Neutrino basiert
auf der Client-Server Idee, diese GUI ist also von der direkten DBox-
Steuerung getrennt. Diese wird dann von Daemons uebernommen.
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, write to the
Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
Boston, MA 02110-1301, USA.
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <sstream>
#include <gui/channellist.h>
#include <global.h>
#include <neutrino.h>
#include <driver/fontrenderer.h>
#include <driver/screen_max.h>
#include <driver/rcinput.h>
#include <driver/abstime.h>
#include <driver/record.h>
#include <driver/fade.h>
#include <gui/color.h>
#include <gui/eventlist.h>
#include <gui/infoviewer.h>
#include <gui/osd_setup.h>
#include <gui/widget/buttons.h>
#include <gui/widget/icons.h>
#include <gui/widget/messagebox.h>
#include <system/settings.h>
#include <gui/customcolor.h>
#include <gui/bouquetlist.h>
#include <daemonc/remotecontrol.h>
#include <zapit/client/zapittools.h>
#include <gui/pictureviewer.h>
#include <zapit/zapit.h>
#include <zapit/satconfig.h>
#include <zapit/getservices.h>
#include <zapit/femanager.h>
#include <zapit/debug.h>
#include <eitd/sectionsd.h>
extern CBouquetList * bouquetList; /* neutrino.cpp */
extern CRemoteControl * g_RemoteControl; /* neutrino.cpp */
extern CPictureViewer * g_PicViewer;
extern CBouquetList * TVbouquetList;
extern CBouquetList * TVsatList;
extern CBouquetList * TVfavList;
extern CBouquetList * TVallList;
extern CBouquetList * RADIObouquetList;
extern CBouquetList * RADIOsatList;
extern CBouquetList * RADIOfavList;
extern CBouquetList * RADIOallList;
extern CBouquetList * AllFavBouquetList;
extern bool autoshift;
extern CBouquetManager *g_bouquetManager;
extern int old_b_id;
static CComponentsFrmClock *headerClock = NULL;
static int headerClockWidth = 0;
CChannelList::CChannelList(const char * const pName, bool phistoryMode, bool _vlist)
{
frameBuffer = CFrameBuffer::getInstance();
x = y = 0;
info_height = 0;
name = pName;
selected = 0;
selected_in_new_mode = 0;
liststart = 0;
tuned = 0xfffffff;
zapProtection = NULL;
this->historyMode = phistoryMode;
vlist = _vlist;
new_zap_mode = 0;
selected_chid = 0;
footerHeight = g_Font[SNeutrinoSettings::FONT_TYPE_INFOBAR_SMALL]->getHeight()+6; //initial height value for buttonbar
theight = g_Font[SNeutrinoSettings::FONT_TYPE_MENU_TITLE]->getHeight();
fheight = g_Font[SNeutrinoSettings::FONT_TYPE_CHANNELLIST]->getHeight();
fdescrheight = g_Font[SNeutrinoSettings::FONT_TYPE_CHANNELLIST_DESCR]->getHeight();
previous_channellist_additional = -1;
eventFont = SNeutrinoSettings::FONT_TYPE_CHANNELLIST_EVENT;
dline = NULL;
cc_minitv = NULL;
logo_off = 0;
pig_on_win = false;
//printf("************ NEW LIST %s : %x\n", name.c_str(), (int) this);fflush(stdout);
}
CChannelList::~CChannelList()
{
//printf("************ DELETE LIST %s : %x\n", name.c_str(), this);fflush(stdout);
chanlist.clear();
if(dline){
delete dline;
dline = NULL;
}
if (cc_minitv){
delete cc_minitv;
cc_minitv = NULL;
}
if (headerClock) {
headerClock->Stop();
if (headerClock->isPainted())
headerClock->hide();
if (headerClock->isClockRun())
headerClock->stopThread();
}
}
void CChannelList::ClearList(void)
{
//printf("************ CLEAR LIST %s : %x\n", name.c_str(), this);fflush(stdout);
chanlist.clear();
chanlist.resize(1);
}
void CChannelList::setSize(int newsize)
{
//chanlist.reserve(newsize);
chanlist.resize(newsize);
}
void CChannelList::SetChannelList(ZapitChannelList* channels)
{
chanlist = *channels;
}
void CChannelList::addChannel(CZapitChannel* channel, int num)
{
//printf("************ %s : addChannel: %s %x\n", name.c_str(), channel->getName().c_str(), channel);fflush(stdout);
if(num)
channel->number = num;
chanlist.push_back(channel);
}
void CChannelList::putChannel(CZapitChannel* channel)
{
int num = channel->number - 1;
if(num < 0) {
printf("%s error inserting at %d\n", __FUNCTION__, num);
return;
}
if(num >= (int) chanlist.size()) {
chanlist.resize((unsigned) num + 1);
}
chanlist[num] = channel;
//printf("************ %s : me %x putChannel: %d: %s %x -> %x [0] %x\n", name.c_str(), this, num, channel->getName().c_str(), channel, chanlist[num], chanlist[0]);fflush(stdout);
}
/* uodate the events for the visible channel list entries
from = start entry, to = end entry. If both = zero, update all */
void CChannelList::updateEvents(unsigned int from, unsigned int to)
{
CChannelEventList events;
if (to == 0 || to > chanlist.size())
to = chanlist.size();
size_t chanlist_size = to - from;
if (chanlist_size <= 0) // WTF???
return;
if (displayNext) {
time_t atime = time(NULL);
unsigned int count;
for (count = from; count < to; count++) {
events.clear();
CEitManager::getInstance()->getEventsServiceKey(chanlist[count]->channel_id, events);
chanlist[count]->nextEvent.startTime = (long)0x7fffffff;
for ( CChannelEventList::iterator e= events.begin(); e != events.end(); ++e ) {
if ((long)e->startTime > atime &&
(e->startTime < (long)chanlist[count]->nextEvent.startTime))
{
chanlist[count]->nextEvent = *e;
break;
}
}
}
} else {
t_channel_id *p_requested_channels;
p_requested_channels = new t_channel_id[chanlist_size];
if (! p_requested_channels) {
fprintf(stderr,"%s:%d allocation failed!\n", __FUNCTION__, __LINE__);
return;
}
for (uint32_t count = 0; count < chanlist_size; count++)
p_requested_channels[count] = chanlist[count + from]->channel_id;
CChannelEventList levents;
CEitManager::getInstance()->getChannelEvents(levents, p_requested_channels, chanlist_size);
for (uint32_t count=0; count < chanlist_size; count++) {
chanlist[count + from]->currentEvent = CChannelEvent();
for (CChannelEventList::iterator e = levents.begin(); e != levents.end(); ++e) {
if ((chanlist[count + from]->channel_id&0xFFFFFFFFFFFFULL) == e->get_channel_id()) {
chanlist[count + from]->currentEvent = *e;
break;
}
}
}
delete[] p_requested_channels;
}
events.clear();
}
void CChannelList::SortAlpha(void)
{
sort(chanlist.begin(), chanlist.end(), CmpChannelByChName());
}
void CChannelList::SortSat(void)
{
sort(chanlist.begin(), chanlist.end(), CmpChannelBySat());
}
void CChannelList::SortTP(void)
{
sort(chanlist.begin(), chanlist.end(), CmpChannelByFreq());
}
void CChannelList::SortChNumber(void)
{
sort(chanlist.begin(), chanlist.end(), CmpChannelByChNum());
}
CZapitChannel* CChannelList::getChannel(int number)
{
for (uint32_t i=0; i< chanlist.size(); i++) {
if (chanlist[i]->number == number)
return chanlist[i];
}
return(NULL);
}
CZapitChannel* CChannelList::getChannel(t_channel_id channel_id)
{
for (uint32_t i=0; i< chanlist.size(); i++) {
if (chanlist[i]->channel_id == channel_id)
return chanlist[i];
}
return(NULL);
}
int CChannelList::getKey(int id)
{
if (id > -1 && id < (int)chanlist.size())
return chanlist[id]->number;
return 0;
}
static const std::string empty_string;
const std::string CChannelList::getActiveChannelName(void) const
{
if (selected < chanlist.size())
return chanlist[selected]->getName();
else
return empty_string;
}
t_satellite_position CChannelList::getActiveSatellitePosition(void) const
{
if (selected < chanlist.size())
return chanlist[selected]->getSatellitePosition();
return 0;
}
t_channel_id CChannelList::getActiveChannel_ChannelID(void) const
{
if (selected < chanlist.size()) {
//printf("CChannelList::getActiveChannel_ChannelID me %x selected = %d %llx\n", (int) this, selected, chanlist[selected]->channel_id);
return chanlist[selected]->channel_id;
} else
return 0;
}
int CChannelList::getActiveChannelNumber(void) const
{
if (selected < chanlist.size())
return chanlist[selected]->number;
return 0;
}
CZapitChannel * CChannelList::getActiveChannel(void) const
{
static CZapitChannel channel("Channel not found", 0, 0, 0, 0);
if (selected < chanlist.size())
return chanlist[selected];
return &channel;
}
int CChannelList::doChannelMenu(void)
{
int i = 0;
int select = -1;
int shortcut = 0;
static int old_selected = 0;
char cnt[5];
bool enabled = true;
bool unlocked = true;
if(g_settings.minimode)
return 0;
if(vlist)
{
enabled = false;
if(old_selected < 2)//FIXME take care if some items added before 0, 1
old_selected = 2;
}
CMenuWidget* menu = new CMenuWidget(LOCALE_CHANNELLIST_EDIT, NEUTRINO_ICON_SETTINGS);
menu->enableFade(false);
menu->enableSaveScreen(true);
CMenuSelectorTarget * selector = new CMenuSelectorTarget(&select);
/* Allow bouquet manipulation only if the bouquet is unlocked. Without this,
* a channel could be added/removed to/from an unlocked bouquet and so made
* accessible. */
if (g_settings.parentallock_prompt == PARENTALLOCK_PROMPT_CHANGETOLOCKED &&
!!chanlist[selected]->bLockCount != g_settings.parentallock_defaultlocked)
unlocked = (chanlist[selected]->last_unlocked_time + 3600 > time_monotonic());
snprintf(cnt, sizeof(cnt), "%d", i);
menu->addItem(new CMenuForwarder(LOCALE_BOUQUETEDITOR_DELETE, enabled && unlocked, NULL, selector, cnt, CRCInput::RC_red, NEUTRINO_ICON_BUTTON_RED), old_selected == i++);
snprintf(cnt, sizeof(cnt), "%d", i);
menu->addItem(new CMenuForwarder(LOCALE_BOUQUETEDITOR_MOVE, enabled && unlocked, NULL, selector, cnt, CRCInput::RC_green, NEUTRINO_ICON_BUTTON_GREEN), old_selected == i++);
snprintf(cnt, sizeof(cnt), "%d", i);
menu->addItem(new CMenuForwarder(LOCALE_EXTRA_ADD_TO_BOUQUET, unlocked, NULL, selector, cnt, CRCInput::RC_yellow, NEUTRINO_ICON_BUTTON_YELLOW), old_selected == i++);
snprintf(cnt, sizeof(cnt), "%d", i);
menu->addItem(new CMenuForwarder(LOCALE_FAVORITES_MENUEADD, unlocked, NULL, selector, cnt, CRCInput::RC_blue, NEUTRINO_ICON_BUTTON_BLUE), old_selected == i++);
snprintf(cnt, sizeof(cnt), "%d", i);
bool reset_enabled = chanlist[selected]->flags & CZapitChannel::NEW;
menu->addItem(new CMenuForwarder(LOCALE_CHANNELLIST_RESET_FLAGS, reset_enabled, NULL, selector, cnt, CRCInput::convertDigitToKey(shortcut++)), old_selected == i++);
snprintf(cnt, sizeof(cnt), "%d", i);
bool reset_all = (name == g_Locale->getText(LOCALE_BOUQUETNAME_NEW));
menu->addItem(new CMenuForwarder(LOCALE_CHANNELLIST_RESET_ALL, reset_all, NULL, selector, cnt, CRCInput::convertDigitToKey(shortcut++)), old_selected == i++);
snprintf(cnt, sizeof(cnt), "%d", i);
menu->addItem(new CMenuSeparator(CMenuSeparator::LINE));
menu->addItem(new CMenuForwarder(LOCALE_MAINMENU_SETTINGS, true, NULL, selector, cnt, CRCInput::convertDigitToKey(shortcut++)), old_selected == i++);
menu->exec(NULL, "");
delete menu;
delete selector;
if(select >= 0) {
signed int bouquet_id = 0, old_bouquet_id = 0, new_bouquet_id = 0;
old_selected = select;
t_channel_id channel_id = chanlist[selected]->channel_id;
switch(select) {
case 0: {
hide();
int result = ShowMsg ( LOCALE_BOUQUETEDITOR_DELETE, g_Locale->getText(LOCALE_BOUQUETEDITOR_DELETE_QUESTION), CMessageBox::mbrNo, CMessageBox::mbYes | CMessageBox::mbNo );
if(result == CMessageBox::mbrYes) {
bouquet_id = bouquetList->getActiveBouquetNumber();
/* FIXME if bouquet name not unique, this is bad,
* existsBouquet can find wrong bouquet */
if(!strcmp(bouquetList->Bouquets[bouquet_id]->channelList->getName(), g_Locale->getText(LOCALE_FAVORITES_BOUQUETNAME)))
bouquet_id = g_bouquetManager->existsUBouquet(g_Locale->getText(LOCALE_FAVORITES_BOUQUETNAME), true);
else
bouquet_id = g_bouquetManager->existsBouquet(bouquetList->Bouquets[bouquet_id]->channelList->getName());
if (bouquet_id == -1)
return 0;
if(g_bouquetManager->existsChannelInBouquet(bouquet_id, channel_id)) {
g_bouquetManager->Bouquets[bouquet_id]->removeService(channel_id);
return 1;
}
}
break;
}
case 1: // move
old_bouquet_id = bouquetList->getActiveBouquetNumber();
old_bouquet_id = g_bouquetManager->existsBouquet(bouquetList->Bouquets[old_bouquet_id]->channelList->getName());
do {
new_bouquet_id = bouquetList->exec(false);
} while(new_bouquet_id == -3);
hide();
if(new_bouquet_id < 0)
return 0;
new_bouquet_id = g_bouquetManager->existsBouquet(bouquetList->Bouquets[new_bouquet_id]->channelList->getName());
if ((new_bouquet_id == -1) || (new_bouquet_id == old_bouquet_id))
return 0;
if(!g_bouquetManager->existsChannelInBouquet(new_bouquet_id, channel_id)) {
CZapit::getInstance()->addChannelToBouquet(new_bouquet_id, channel_id);
}
if(g_bouquetManager->existsChannelInBouquet(old_bouquet_id, channel_id)) {
g_bouquetManager->Bouquets[old_bouquet_id]->removeService(channel_id);
}
return 1;
break;
case 2: // add to
#if 0
/* default to favorites list, it makes no sense to add to autogenerated bouquets */
if (CNeutrinoApp::getInstance()->GetChannelMode() != LIST_MODE_FAV)
CNeutrinoApp::getInstance()->SetChannelMode(LIST_MODE_FAV);
do {
bouquet_id = bouquetList->exec(false);
} while(bouquet_id == -3);
bouquet_id = bouquetList->exec(false);
hide();
if(bouquet_id < 0)
return 0;
if(!strcmp(bouquetList->Bouquets[bouquet_id]->channelList->getName(), g_Locale->getText(LOCALE_FAVORITES_BOUQUETNAME)))
bouquet_id = g_bouquetManager->existsUBouquet(g_Locale->getText(LOCALE_FAVORITES_BOUQUETNAME), true);
else
bouquet_id = g_bouquetManager->existsBouquet(bouquetList->Bouquets[bouquet_id]->channelList->getName());
#endif
bouquet_id = AllFavBouquetList->exec(false);
hide();
if(bouquet_id < 0)
return 0;
if(!strcmp(AllFavBouquetList->Bouquets[bouquet_id]->channelList->getName(), g_Locale->getText(LOCALE_FAVORITES_BOUQUETNAME)))
bouquet_id = g_bouquetManager->existsUBouquet(g_Locale->getText(LOCALE_FAVORITES_BOUQUETNAME), true);
else
bouquet_id = g_bouquetManager->existsUBouquet(AllFavBouquetList->Bouquets[bouquet_id]->channelList->getName());
if (bouquet_id == -1)
return 0;
if(!g_bouquetManager->existsChannelInBouquet(bouquet_id, channel_id)) {
CZapit::getInstance()->addChannelToBouquet(bouquet_id, channel_id);
return 2;
}
break;
case 3: // add to my favorites
bouquet_id = g_bouquetManager->existsUBouquet(g_Locale->getText(LOCALE_FAVORITES_BOUQUETNAME), true);
if(bouquet_id == -1) {
g_bouquetManager->addBouquet(g_Locale->getText(LOCALE_FAVORITES_BOUQUETNAME), true);
bouquet_id = g_bouquetManager->existsUBouquet(g_Locale->getText(LOCALE_FAVORITES_BOUQUETNAME), true);
}
if(!g_bouquetManager->existsChannelInBouquet(bouquet_id, channel_id)) {
CZapit::getInstance()->addChannelToBouquet(bouquet_id, channel_id);
return 2;
}
break;
case 4: // reset new
chanlist[selected]->flags = CZapitChannel::UPDATED;
CServiceManager::getInstance()->SetServicesChanged(true);
/* if make_new_list == ON, signal to re-init services */
if(g_settings.make_new_list)
return 2;
break;
case 5: // reset all new
for (unsigned int j = 0 ; j < chanlist.size(); j++) {
chanlist[j]->flags = CZapitChannel::UPDATED;
}
if (g_settings.make_new_list)
return 2;
break;
case 6: // settings
{
previous_channellist_additional = g_settings.channellist_additional;
COsdSetup osd_setup;
osd_setup.showContextChanlistMenu();
//FIXME check font/options changed ?
hide();
calcSize();
}
break;
default:
break;
}
}
return 0;
}
int CChannelList::exec()
{
displayNext = 0; // always start with current events
displayList = 1; // always start with event list
int nNewChannel = show();
if ( nNewChannel > -1 && nNewChannel < (int) chanlist.size()) {
if(this->historyMode && chanlist[nNewChannel]) {
int new_mode = CNeutrinoApp::getInstance()->channelList->getLastChannels().get_mode(chanlist[nNewChannel]->channel_id);
if(new_mode >= 0)
CNeutrinoApp::getInstance()->SetChannelMode(new_mode);
}
CNeutrinoApp::getInstance()->channelList->zapToChannel(chanlist[nNewChannel]);
}
return nNewChannel;
}
void CChannelList::calcSize()
{
CVFD::getInstance()->setMode(CVFD::MODE_MENU_UTF8 /*, name.c_str()*/);
// recalculate theight, fheight and footerHeight for a possilble change of fontsize factor
theight = g_Font[SNeutrinoSettings::FONT_TYPE_MENU_TITLE]->getHeight();
fheight = g_Font[SNeutrinoSettings::FONT_TYPE_CHANNELLIST]->getHeight();
fdescrheight = g_Font[SNeutrinoSettings::FONT_TYPE_CHANNELLIST_DESCR]->getHeight();
if (fheight == 0)
fheight = 1; /* avoid div-by-zero crash on invalid font */
footerHeight = g_Font[SNeutrinoSettings::FONT_TYPE_INFOBAR_SMALL]->getHeight()+6;
pig_on_win = ( (g_settings.channellist_additional == 2) /* with miniTV */ && (CNeutrinoApp::getInstance()->getMode() != NeutrinoMessages::mode_ts) );
// calculate width
full_width = pig_on_win ? (frameBuffer->getScreenWidth()-2*ConnectLineBox_Width) : frameBuffer->getScreenWidthRel();
if (g_settings.channellist_additional)
width = full_width / 3 * 2;
else
width = full_width;
// calculate height (the infobox below mainbox is handled outside height)
info_height = 2*fheight + fdescrheight + 10;
height = pig_on_win ? frameBuffer->getScreenHeight(): frameBuffer->getScreenHeightRel();
height = height - info_height;
// calculate x position
x = getScreenStartX(full_width);
if (x < ConnectLineBox_Width)
x = ConnectLineBox_Width;
// calculate header height
const int pic_h = 39;
theight = std::max(theight, pic_h);
// calculate max entrys in mainbox
listmaxshow = (height - theight - footerHeight) / fheight;
// recalculate height to avoid spaces between last entry in mainbox and footer
height = theight + listmaxshow*fheight + footerHeight;
// calculate y position
y = getScreenStartY(height + info_height);
// calculate width/height of right info_zone and pip-box
infozone_width = full_width - width;
pig_width = infozone_width;
if ( pig_on_win /* with miniTV */ )
pig_height = (pig_width * 9) / 16;
else
pig_height = 0;
infozone_height = height - theight - pig_height - footerHeight;
}
bool CChannelList::updateSelection(int newpos)
{
bool actzap = false;
if((int) selected != newpos) {
int prev_selected = selected;
unsigned int oldliststart = liststart;
selected = newpos;
liststart = (selected/listmaxshow)*listmaxshow;
if (oldliststart != liststart)
paint();
else {
paintItem(prev_selected - liststart);
paintItem(selected - liststart);
showChannelLogo();
}
if((new_zap_mode == 2 /* active */) && SameTP()) {
actzap = true;
zapTo(selected);
}
}
return actzap;
}
int CChannelList::getPrevNextBouquet(bool next)
{
bool found = true;
int dir = next ? 1 : -1;
int b_size = bouquetList->Bouquets.size(); /* bigger than 0 */
int nNext = (bouquetList->getActiveBouquetNumber() + b_size + dir) % b_size;
if(bouquetList->Bouquets[nNext]->channelList->isEmpty() ) {
found = false;
int n_old = nNext;
nNext = (nNext + b_size + dir) % b_size;
for (int i = nNext; i != n_old; i = (i + b_size + dir) % b_size) {
if( !bouquetList->Bouquets[i]->channelList->isEmpty() ) {
found = true;
nNext = i;
break;
}
}
}
if (found)
return nNext;
return -1;
}
#define CHANNEL_SMSKEY_TIMEOUT 800
/* return: >= 0 to zap, -1 on cancel, -3 on list mode change, -4 list edited, -2 zap but no restore old list/chan ?? */
int CChannelList::show()
{
int res = -1;
if (chanlist.empty()) {
return res;
}
/* temporary debugging stuff */
struct timeval t1, t2;
gettimeofday(&t1, NULL);
neutrino_msg_t msg;
neutrino_msg_data_t data;
bool actzap = 0;
new_zap_mode = g_settings.channellist_new_zap_mode;
calcSize();
displayNext = false;
COSDFader fader(g_settings.menu_Content_alpha);
fader.StartFadeIn();
paintHead();
paint();
gettimeofday(&t2, NULL);
fprintf(stderr, "CChannelList::show(): %llu ms to paint channellist\n",
((t2.tv_sec * 1000000ULL + t2.tv_usec) - (t1.tv_sec * 1000000ULL + t1.tv_usec)) / 1000ULL);
int oldselected = selected;
int zapOnExit = false;
bool bShowBouquetList = false;
uint64_t timeoutEnd = CRCInput::calcTimeoutEnd(g_settings.timing[SNeutrinoSettings::TIMING_CHANLIST]);
bool bouquet_changed = false;
bool loop=true;
bool dont_hide = false;
while (loop) {
g_RCInput->getMsgAbsoluteTimeout(&msg, &data, &timeoutEnd, true);
if ( msg <= CRCInput::RC_MaxRC )
timeoutEnd = CRCInput::calcTimeoutEnd(g_settings.timing[SNeutrinoSettings::TIMING_CHANLIST]);
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) ) {
res = -1;
if(!actzap) {
selected = oldselected;
}
else {
res = -4;
selected = selected_in_new_mode;
}
if(fader.StartFadeOut()) {
timeoutEnd = CRCInput::calcTimeoutEnd( 1 );
msg = 0;
} else
loop=false;
}
else if( msg == CRCInput::RC_record) { //start direct recording from channellist
#if 0
if(!CRecordManager::getInstance()->RecordingStatus(chanlist[selected]->channel_id))
{
printf("[neutrino channellist] start direct recording...\n");
hide();
if (CRecordManager::getInstance()->Record(chanlist[selected]->channel_id))
{
if(SameTP())
{
zapOnExit = true;
loop=false;
}
else
DisplayInfoMessage(g_Locale->getText(LOCALE_CHANNELLIST_RECORDING_NOT_POSSIBLE)); // UTF-8
}
}
#endif
if((g_settings.recording_type != CNeutrinoApp::RECORDING_OFF) && SameTP()) {
printf("[neutrino channellist] start direct recording...\n");
hide();
if (!CRecordManager::getInstance()->Record(chanlist[selected]->channel_id)) {
paintHead();
paint();
} else {
selected = oldselected;
loop=false;
}
}
}
else if( msg == CRCInput::RC_stop ) { //stopp recording
if(CRecordManager::getInstance()->RecordingStatus(chanlist[selected]->channel_id))
{
if (CRecordManager::getInstance()->AskToStop(chanlist[selected]->channel_id))
{
CRecordManager::getInstance()->Stop(chanlist[selected]->channel_id);
paint();
}
}
}
else if ((msg == CRCInput::RC_red) || (msg == CRCInput::RC_epg)) {
hide();
/* RETURN_EXIT_ALL on FAV/SAT buttons or messages_return::cancel_all from CNeutrinoApp::getInstance()->handleMsg() */
if ( g_EventList->exec(chanlist[selected]->channel_id, chanlist[selected]->getName()) == menu_return::RETURN_EXIT_ALL) {
res = -2;
loop = false;
} else {
paintHead();
paint();
timeoutEnd = CRCInput::calcTimeoutEnd(g_settings.timing[SNeutrinoSettings::TIMING_CHANLIST]);
}
}
else if (msg == CRCInput::RC_yellow) {
bShowBouquetList = true;
loop=false;
}
else if (msg == CRCInput::RC_sat || msg == CRCInput::RC_favorites) {
g_RCInput->postMsg (msg, 0);
loop = false;
res = -1;
}
else if ( msg == CRCInput::RC_setup) {
old_b_id = bouquetList->getActiveBouquetNumber();
fader.StopFade();
int ret = doChannelMenu();
if (ret != 0)
CNeutrinoApp::getInstance()->MarkChannelListChanged();
if (ret == 1) {
res = -3 - ret; /* -5 == add to fav or bouquet, -4 == all other change */
loop = false;
} else {
if (ret > 1) {
bouquet_changed = true;
/* select next entry */
if (selected + 1 < chanlist.size())
selected++;
}
old_b_id = -1;
paintHead();
paint();
}
timeoutEnd = CRCInput::calcTimeoutEnd(g_settings.timing[SNeutrinoSettings::TIMING_CHANLIST]);
}
else if (msg == (neutrino_msg_t) g_settings.key_list_start) {
actzap = updateSelection(0);
}
else if (msg == (neutrino_msg_t) g_settings.key_list_end) {
actzap = updateSelection(chanlist.size()-1);
}
else if (msg == CRCInput::RC_up || (int) msg == g_settings.key_channelList_pageup)
{
displayList = 1;
int step = ((int) msg == g_settings.key_channelList_pageup) ? listmaxshow : 1; // browse or step 1
int new_selected = selected - step;
if (new_selected < 0) {
if (selected != 0 && step != 1)
new_selected = 0;
else
new_selected = chanlist.size() - 1;
}
actzap = updateSelection(new_selected);
}
else if (msg == CRCInput::RC_down || (int) msg == g_settings.key_channelList_pagedown)
{
displayList = 1;
int step = ((int) msg == g_settings.key_channelList_pagedown) ? listmaxshow : 1; // browse or step 1
int new_selected = selected + step;
if (new_selected >= (int) chanlist.size()) {
if ((chanlist.size() - listmaxshow -1 < selected) && (selected != (chanlist.size() - 1)) && (step != 1))
new_selected = chanlist.size() - 1;
else if (((chanlist.size() / listmaxshow) + 1) * listmaxshow == chanlist.size() + listmaxshow) // last page has full entries
new_selected = 0;
else
new_selected = ((step == (int) listmaxshow) && (new_selected < (int) (((chanlist.size() / listmaxshow)+1) * listmaxshow))) ? (chanlist.size() - 1) : 0;
}
actzap = updateSelection(new_selected);
}
else if (msg == (neutrino_msg_t)g_settings.key_bouquet_up ||
msg == (neutrino_msg_t)g_settings.key_bouquet_down) {
if (dline)
dline->kill(); //kill details line on change to next page
if (!bouquetList->Bouquets.empty()) {
int nNext = getPrevNextBouquet(msg == (neutrino_msg_t)g_settings.key_bouquet_up);
if(nNext >= 0) {
bouquetList->activateBouquet(nNext, false);
res = bouquetList->showChannelList();
loop = false;
}
dont_hide = true;
}
}
else if ( msg == CRCInput::RC_ok ) {
if(SameTP()) {
zapOnExit = true;
loop=false;
}
}
else if (( msg == CRCInput::RC_spkr ) && new_zap_mode ) {
if(CNeutrinoApp::getInstance()->getMode() != NeutrinoMessages::mode_ts) {
switch (new_zap_mode) {
case 2: /* active */
new_zap_mode = 1; /* allow */
break;
case 1: /* allow */
new_zap_mode = 2; /* active */
break;
default:
break;
}
#if 0
paintHead();
showChannelLogo();
#endif
paintButtonBar(SameTP());
}
}
else if (CRCInput::isNumeric(msg) && (this->historyMode || g_settings.sms_channel)) {
if (this->historyMode) { //numeric zap
selected = CRCInput::getNumericValue(msg);
zapOnExit = true;
loop = false;
}
else if(g_settings.sms_channel) {
unsigned char smsKey = 0;
SMSKeyInput smsInput;
smsInput.setTimeout(CHANNEL_SMSKEY_TIMEOUT);
do {
smsKey = smsInput.handleMsg(msg);
//printf("SMS new key: %c\n", smsKey);
g_RCInput->getMsg_ms(&msg, &data, CHANNEL_SMSKEY_TIMEOUT-100);
} while ((msg >= CRCInput::RC_1) && (msg <= CRCInput::RC_9));
if (msg == CRCInput::RC_timeout || msg == CRCInput::RC_nokey) {
uint32_t i;
for(i = selected+1; i < chanlist.size(); i++) {
char firstCharOfTitle = chanlist[i]->getName().c_str()[0];
if(tolower(firstCharOfTitle) == smsKey) {
//printf("SMS chan found was= %d selected= %d i= %d %s\n", was_sms, selected, i, chanlist[i]->channel->getName().c_str());
break;
}
}
if(i >= chanlist.size()) {
for(i = 0; i < chanlist.size(); i++) {
char firstCharOfTitle = chanlist[i]->getName().c_str()[0];
if(tolower(firstCharOfTitle) == smsKey) {
//printf("SMS chan found was= %d selected= %d i= %d %s\n", was_sms, selected, i, chanlist[i]->channel->getName().c_str());
break;
}
}
}
if(i < chanlist.size()) {
int prevselected=selected;
selected=i;
paintItem(prevselected - liststart);
unsigned int oldliststart = liststart;
liststart = (selected/listmaxshow)*listmaxshow;
if(oldliststart!=liststart) {
paint();
} else {
paintItem(selected - liststart);
showChannelLogo();
}
}
smsInput.resetOldKey();
}
}
}
else if(CRCInput::isNumeric(msg)) {
//pushback key if...
selected = oldselected;
g_RCInput->postMsg( msg, data );
loop=false;
}
else if ( msg == CRCInput::RC_blue )
{
if (g_settings.channellist_additional)
displayList = !displayList;
else
displayNext = !displayNext;
paintHead(); // update button bar
paint();
}
else if ( msg == CRCInput::RC_green )
{
int mode = CNeutrinoApp::getInstance()->GetChannelMode();
if(mode != LIST_MODE_FAV) {
g_settings.channellist_sort_mode++;
if(g_settings.channellist_sort_mode > SORT_MAX-1)
g_settings.channellist_sort_mode = SORT_ALPHA;
CNeutrinoApp::getInstance()->SetChannelMode(mode);
oldselected = selected;
paintHead(); // update button bar
paint();
}
}
#ifdef ENABLE_PIP
else if ((msg == CRCInput::RC_play) || (msg == (neutrino_msg_t) g_settings.key_pip_close)) {
if(SameTP()) {
if (CZapit::getInstance()->GetPipChannelID() == chanlist[selected]->getChannelID()) {
g_Zapit->stopPip();
paint();
} else {
if(CNeutrinoApp::getInstance()->StartPip(chanlist[selected]->getChannelID()))
paint();
}
}
}
#endif
else if ((msg == CRCInput::RC_info) || (msg == CRCInput::RC_help)) {
hide();
CChannelEvent *p_event=NULL;
if (displayNext)
{
p_event = &(chanlist[selected]->nextEvent);
}
if(p_event && p_event->eventID)
{
g_EpgData->show(chanlist[selected]->channel_id,p_event->eventID,&(p_event->startTime));
}
else
{
g_EpgData->show(chanlist[selected]->channel_id);
}
paintHead();
paint();
} else {
if ( CNeutrinoApp::getInstance()->handleMsg( msg, data ) & messages_return::cancel_all ) {
loop = false;
res = - 2;
}
}
}
if (bouquet_changed)
res = -5; /* in neutrino.cpp: -5 == "don't change bouquet after adding a channel to fav" */
if(!dont_hide){
if (new_zap_mode && (g_settings.channellist_new_zap_mode != new_zap_mode))
g_settings.channellist_new_zap_mode = new_zap_mode;
new_zap_mode = 0;
hide();
fader.StopFade();
}
if (bShowBouquetList) {
res = bouquetList->exec(true);
printf("CChannelList:: bouquetList->exec res %d\n", res);
}
if (headerClock)
headerClock->Stop();
if(NeutrinoMessages::mode_ts == CNeutrinoApp::getInstance()->getMode())
return -1;
if(zapOnExit) {
res = selected;
//selected_chid = chanlist[selected]->channel_id;
}
printf("CChannelList::show *********** res %d\n", res);
return(res);
}
void CChannelList::hide()
{
if ((g_settings.channellist_additional == 2) || (previous_channellist_additional == 2)) // with miniTV
{
if (cc_minitv)
delete cc_minitv;
cc_minitv = NULL;
}
if (headerClock) {
if (headerClock->Stop())
headerClock->kill();
}
frameBuffer->paintBackgroundBoxRel(x, y, full_width, height + info_height);
clearItem2DetailsLine();
}
bool CChannelList::showInfo(int number, int epgpos)
{
CZapitChannel* channel = getChannel(number);
if(channel == NULL)
return false;
g_InfoViewer->showTitle(channel, true, epgpos); // UTF-8
return true;
}
int CChannelList::handleMsg(const neutrino_msg_t msg, neutrino_msg_data_t data)
{
bool startvideo = true;
if (msg != NeutrinoMessages::EVT_PROGRAMLOCKSTATUS) // right now the only message handled here.
return messages_return::unhandled;
//printf("===> program-lock-status: %d zp: %d\n", data, zapProtection != NULL);
if (g_settings.parentallock_prompt == PARENTALLOCK_PROMPT_NEVER)
goto out;
// 0x100 als FSK-Status zeigt an, dass (noch) kein EPG zu einem Kanal der NICHT angezeigt
// werden sollte (vorgesperrt) da ist
// oder das bouquet des Kanals ist vorgesperrt
if (zapProtection != NULL) {
zapProtection->fsk = data;
startvideo = false;
goto out;
}
// require password if either
// CHANGETOLOCK mode and channel/bouquet is pre locked (0x100)
// ONSIGNAL mode and fsk(data) is beyond configured value
// if program has already been unlocked, dont require pin
if (data < (neutrino_msg_data_t)g_settings.parentallock_lockage)
goto out;
/* already unlocked */
if (chanlist[selected]->last_unlocked_EPGid == g_RemoteControl->current_EPGid && g_RemoteControl->current_EPGid != 0)
goto out;
/* PARENTALLOCK_PROMPT_CHANGETOLOCKED: only pre-locked channels, don't care for fsk sent in SI */
if (g_settings.parentallock_prompt == PARENTALLOCK_PROMPT_CHANGETOLOCKED && data < 0x100)
goto out;
/* if a pre-locked channel is inside the zap time, open it. Hardcoded to one hour for now. */
if (data >= 0x100 && chanlist[selected]->last_unlocked_time + 3600 > time_monotonic())
goto out;
/* OK, let's ask for a PIN */
g_RemoteControl->stopvideo();
//printf("stopped video\n");
zapProtection = new CZapProtection(g_settings.parentallock_pincode, data);
if (zapProtection->check())
{
// remember it for the next time
/* data < 0x100: lock age -> remember EPG ID */
if (data < 0x100)
chanlist[selected]->last_unlocked_EPGid = g_RemoteControl->current_EPGid;
else
{
/* data >= 0x100: pre-locked bouquet -> remember unlock time */
chanlist[selected]->last_unlocked_time = time_monotonic();
int bnum = bouquetList->getActiveBouquetNumber();
if (bnum >= 0)
{
/* unlock the whole bouquet */
int i;
for (i = 0; i < bouquetList->Bouquets[bnum]->channelList->getSize(); i++)
bouquetList->Bouquets[bnum]->channelList->getChannelFromIndex(i)->last_unlocked_time = chanlist[selected]->last_unlocked_time;
}
}
}
else
{
/* last_unlocked_time == 0 is the magic to tell zapTo() to not record the time.
Without that, zapping to a locked channel twice would open it without the PIN */
chanlist[selected]->last_unlocked_time = 0;
startvideo = false;
}
delete zapProtection;
zapProtection = NULL;
out:
if (startvideo)
g_RemoteControl->startvideo();
return messages_return::handled;
}
/* bToo default to true */
/* TODO make this member of CNeutrinoApp, because this only called from "whole" list ? */
bool CChannelList::adjustToChannelID(const t_channel_id channel_id, bool bToo)
{
unsigned int i;
selected_chid = channel_id;
printf("CChannelList::adjustToChannelID me %p [%s] list size %d channel_id %" PRIx64 "\n", this, getName(), (int)chanlist.size(), channel_id);
for (i = 0; i < chanlist.size(); i++) {
if(chanlist[i] == NULL) {
printf("CChannelList::adjustToChannelID REPORT BUG !! ******************************** %u is NULL !!\n", i);
continue;
}
if (chanlist[i]->channel_id == channel_id) {
selected = i;
tuned = i;
//lastChList.store (selected, channel_id, false);
if (bToo) {
lastChList.store (selected, channel_id, false);
int old_mode = CNeutrinoApp::getInstance()->GetChannelMode();
int new_mode = old_mode;
bool has_channel;
first_mode_found = -1;
if(CNeutrinoApp::getInstance()->getMode() == NeutrinoMessages::mode_tv) {
has_channel = TVfavList->adjustToChannelID(channel_id);
if (has_channel && first_mode_found < 0)
first_mode_found = LIST_MODE_FAV;
if(!has_channel && old_mode == LIST_MODE_FAV)
new_mode = LIST_MODE_PROV;
has_channel = TVbouquetList->adjustToChannelID(channel_id);
if (has_channel && first_mode_found < 0)
first_mode_found = LIST_MODE_PROV;
if(!has_channel && old_mode == LIST_MODE_PROV)
new_mode = LIST_MODE_SAT;
has_channel = TVsatList->adjustToChannelID(channel_id);
if (has_channel && first_mode_found < 0)
first_mode_found = LIST_MODE_SAT;
if(!has_channel && old_mode == LIST_MODE_SAT)
new_mode = LIST_MODE_ALL;
has_channel = TVallList->adjustToChannelID(channel_id);
}
else if(CNeutrinoApp::getInstance()->getMode() == NeutrinoMessages::mode_radio) {
has_channel = RADIOfavList->adjustToChannelID(channel_id);
if (has_channel && first_mode_found < 0)
first_mode_found = LIST_MODE_FAV;
if(!has_channel && old_mode == LIST_MODE_FAV)
new_mode = LIST_MODE_PROV;
has_channel = RADIObouquetList->adjustToChannelID(channel_id);
if (has_channel && first_mode_found < 0)
first_mode_found = LIST_MODE_PROV;
if(!has_channel && old_mode == LIST_MODE_PROV)
new_mode = LIST_MODE_SAT;
has_channel = RADIOsatList->adjustToChannelID(channel_id);
if (has_channel && first_mode_found < 0)
first_mode_found = LIST_MODE_SAT;
if(!has_channel && old_mode == LIST_MODE_SAT)
new_mode = LIST_MODE_ALL;
has_channel = RADIOallList->adjustToChannelID(channel_id);
}
if(old_mode != new_mode)
CNeutrinoApp::getInstance()->SetChannelMode(new_mode);
}
//printf("CChannelList::adjustToChannelID me %x to %llx bToo %s OK: %d\n", (int) this, channel_id, bToo ? "yes" : "no", i);fflush(stdout);
return true;
}
}
//printf("CChannelList::adjustToChannelID me %x to %llx bToo %s FAILED\n", (int) this, channel_id, bToo ? "yes" : "no");fflush(stdout);
return false;
}
#if 0
int CChannelList::hasChannel(int nChannelNr)
{
for (uint32_t i=0; i<chanlist.size(); i++) {
if (getKey(i) == nChannelNr)
return(i);
}
return(-1);
}
#endif
int CChannelList::hasChannelID(t_channel_id channel_id)
{
for (uint32_t i=0; i < chanlist.size(); i++) {
if(chanlist[i] == NULL) {
printf("CChannelList::hasChannelID REPORT BUG !! ******************************** %d is NULL !!\n", i);
continue;
}
if (chanlist[i]->channel_id == channel_id)
return i;
}
return -1;
}
// for adjusting bouquet's channel list after numzap or quickzap
void CChannelList::setSelected( int nChannelNr)
{
//printf("CChannelList::setSelected me %s %d -> %s\n", name.c_str(), nChannelNr, (nChannelNr < chanlist.size() && chanlist[nChannelNr] != NULL) ? chanlist[nChannelNr]->getName().c_str() : "********* NONE *********");
//FIXME real difference between tuned and selected ?!
selected_chid = 0;
tuned = nChannelNr;
if (nChannelNr < (int) chanlist.size()) {
selected = nChannelNr;
selected_chid = chanlist[tuned]->getChannelID();
}
}
// -- Zap to channel with channel_id
bool CChannelList::zapTo_ChannelID(const t_channel_id channel_id, bool force)
{
printf("**************************** CChannelList::zapTo_ChannelID %" PRIx64 "\n", channel_id);
for (unsigned int i = 0; i < chanlist.size(); i++) {
if (chanlist[i]->channel_id == channel_id) {
zapTo(i, force);
return true;
}
}
return false;
}
bool CChannelList::showEmptyError()
{
if (chanlist.empty()) {
DisplayErrorMessage(g_Locale->getText(LOCALE_CHANNELLIST_NONEFOUND)); // UTF-8
return true;
}
return false;
}
/* forceStoreToLastChannels defaults to false */
/* TODO make this private to call only from "current" list, where selected/pos not means channel number */
void CChannelList::zapTo(int pos, bool force)
{
if(showEmptyError())
return;
if ( (pos >= (signed int) chanlist.size()) || (pos < 0) ) {
pos = 0;
}
CZapitChannel* chan = chanlist[pos];
zapToChannel(chan, force);
tuned = pos;
if(new_zap_mode == 2 /* active */)
selected_in_new_mode = pos;
else
selected = pos;
}
/* to replace zapTo_ChannelID and zapTo from "whole" list ? */
void CChannelList::zapToChannel(CZapitChannel *channel, bool force)
{
if(showEmptyError())
return;
if(channel == NULL)
return;
/* we record when we switched away from a channel, so that the parental-PIN code can
check for timeout. last_unlocked_time == 0 means: the PIN was not entered
"tuned" is the *old* channel, before zap */
if (tuned < chanlist.size() && chanlist[tuned]->last_unlocked_time != 0)
chanlist[tuned]->last_unlocked_time = time_monotonic();
printf("**************************** CChannelList::zapToChannel me %p %s tuned %d new %s -> %" PRIx64 "\n", this, name.c_str(), tuned, channel->getName().c_str(), channel->channel_id);
if(tuned < chanlist.size())
selected_chid = chanlist[tuned]->getChannelID();
if(force || (selected_chid != channel->getChannelID())) {
if ((g_settings.radiotext_enable) && ((CNeutrinoApp::getInstance()->getMode()) == NeutrinoMessages::mode_radio) && (g_Radiotext))
{
// stop radiotext PES decoding before zapping
g_Radiotext->radiotext_stop();
}
selected_chid = channel->getChannelID();
g_RemoteControl->zapTo_ChannelID(selected_chid, channel->getName(), (!!channel->bLockCount == g_settings.parentallock_defaultlocked));
CNeutrinoApp::getInstance()->channelList->adjustToChannelID(channel->getChannelID());
}
if(new_zap_mode != 2 /* not active */) {
/* remove recordModeActive from infobar */
if(g_settings.auto_timeshift && !CNeutrinoApp::getInstance()->recordingstatus) {
g_InfoViewer->handleMsg(NeutrinoMessages::EVT_RECORDMODE, 0);
}
g_RCInput->postMsg( NeutrinoMessages::SHOW_INFOBAR, 0 );
CNeutrinoApp::getInstance()->channelList->getLastChannels().set_mode(channel->channel_id);
}
}
/* Called only from "all" channel list */
int CChannelList::numericZap(int key)
{
int res = -1;
if(showEmptyError())
return res;
// -- quickzap "0" to last seen channel...
if (key == g_settings.key_lastchannel) {
t_channel_id channel_id = lastChList.getlast(1);
if(channel_id && SameTP(channel_id)) {
lastChList.clear_storedelay(); // ignore store delay
int new_mode = lastChList.get_mode(channel_id);
if(new_mode >= 0)
CNeutrinoApp::getInstance()->SetChannelMode(new_mode);
zapTo_ChannelID(channel_id);
res = 0;
}
return res;
}
if ((key == g_settings.key_zaphistory) || (key == g_settings.key_current_transponder)) {
if((!autoshift && CNeutrinoApp::getInstance()->recordingstatus) || (key == g_settings.key_current_transponder)) {
CChannelList * orgList = CNeutrinoApp::getInstance()->channelList;
CChannelList * channelList = new CChannelList(g_Locale->getText(LOCALE_CHANNELLIST_CURRENT_TP), false, true);
if(key == g_settings.key_current_transponder) {
t_channel_id recid = chanlist[selected]->channel_id >> 16;
for ( unsigned int i = 0 ; i < orgList->chanlist.size(); i++) {
if((orgList->chanlist[i]->channel_id >> 16) == recid)
channelList->addChannel(orgList->chanlist[i]);
}
} else {
for ( unsigned int i = 0 ; i < orgList->chanlist.size(); i++) {
if(SameTP(orgList->chanlist[i]))
channelList->addChannel(orgList->chanlist[i]);
}
}
if ( !channelList->isEmpty()) {
channelList->adjustToChannelID(orgList->getActiveChannel_ChannelID(), false);
this->frameBuffer->paintBackground();
res = channelList->exec();
CVFD::getInstance()->setMode(CVFD::MODE_TVRADIO);
}
delete channelList;
return res;
}
// -- zap history bouquet, similar to "0" quickzap, but shows a menue of last channels
if (this->lastChList.size() > 1) {
CChannelList * channelList = new CChannelList(g_Locale->getText(LOCALE_CHANNELLIST_HISTORY), true, true);
for(unsigned int i = 1; i < this->lastChList.size() ; ++i) {
t_channel_id channel_id = this->lastChList.getlast(i);
if(channel_id) {
CZapitChannel* channel = getChannel(channel_id);
if(channel) channelList->addChannel(channel);
}
}
if ( !channelList->isEmpty() ) {
this->frameBuffer->paintBackground();
res = channelList->exec();
CVFD::getInstance()->setMode(CVFD::MODE_TVRADIO);
}
delete channelList;
}
return res;
}
size_t maxchansize = MaxChanNr().size();
int fw = g_Font[SNeutrinoSettings::FONT_TYPE_CHANNEL_NUM_ZAP]->getMaxDigitWidth();
int sx = maxchansize * fw + (fw/2);
int sy = g_Font[SNeutrinoSettings::FONT_TYPE_CHANNEL_NUM_ZAP]->getHeight() + 6;
int ox = frameBuffer->getScreenX() + (frameBuffer->getScreenWidth() - sx)/2;
int oy = frameBuffer->getScreenY() + (frameBuffer->getScreenHeight() - sy)/2;
char valstr[10];
int chn = CRCInput::getNumericValue(key);
int pos = 1;
int lastchan= -1;
bool doZap = false;
bool showEPG = false;
neutrino_msg_t msg;
neutrino_msg_data_t data;
while(1) {
if (lastchan != chn) {
snprintf((char*) &valstr, sizeof(valstr), "%d", chn);
while(strlen(valstr) < maxchansize)
strcat(valstr,"-"); //"_"
frameBuffer->paintBoxRel(ox, oy, sx, sy, COL_INFOBAR_PLUS_0);
for (int i = maxchansize-1; i >= 0; i--) {
valstr[i+ 1] = 0;
g_Font[SNeutrinoSettings::FONT_TYPE_CHANNEL_NUM_ZAP]->RenderString(ox+fw/3+ i*fw, oy+sy-3, sx, &valstr[i], COL_INFOBAR_TEXT);
}
showInfo(chn);
lastchan = chn;
}
g_RCInput->getMsg( &msg, &data, g_settings.timing[SNeutrinoSettings::TIMING_NUMERICZAP] * 10 );
if (msg == CRCInput::RC_timeout || msg == CRCInput::RC_ok) {
doZap = true;
break;
}
else if (msg == CRCInput::RC_favorites || msg == CRCInput::RC_sat || msg == CRCInput::RC_right) {
}
else if (CRCInput::isNumeric(msg)) {
if (pos == 4) {
chn = 0;
pos = 1;
} else {
chn *= 10;
pos++;
}
chn += CRCInput::getNumericValue(msg);
}
else if (msg == (neutrino_msg_t)g_settings.key_quickzap_down) {
if(chn > 1)
chn--;
}
else if (msg == (neutrino_msg_t)g_settings.key_quickzap_up) {
chn++;
}
else if (msg == CRCInput::RC_left) {
/* "backspace" */
if(pos > 0) {
pos--;
if(chn > 10)
chn /= 10;
}
}
else if (msg == CRCInput::RC_home)
{
break;
}
else if (msg == CRCInput::RC_red) {
showEPG = true;
break;
}
else if (CNeutrinoApp::getInstance()->handleMsg( msg, data ) & messages_return::cancel_all) {
break;
}
}
frameBuffer->paintBackgroundBoxRel(ox, oy, sx, sy);
CZapitChannel* chan = getChannel(chn);
if (doZap) {
if(g_settings.timing[SNeutrinoSettings::TIMING_INFOBAR] == 0)
g_InfoViewer->killTitle();
if(chan && SameTP(chan)) {
zapToChannel(chan);
if (g_settings.channellist_numeric_adjust && first_mode_found >= 0) {
CNeutrinoApp::getInstance()->SetChannelMode(first_mode_found);
CNeutrinoApp::getInstance()->channelList->getLastChannels().set_mode(chan->channel_id);
}
res = 0;
} else
g_InfoViewer->killTitle();
} else {
g_InfoViewer->showTitle(getActiveChannel(), true);
g_InfoViewer->killTitle();
if (chan && showEPG)
g_EventList->exec(chan->channel_id, chan->getName());
}
return res;
}
CZapitChannel* CChannelList::getPrevNextChannel(int key, unsigned int &sl)
{
CZapitChannel* channel = chanlist[sl];
int bsize = bouquetList->Bouquets.size();
int bactive = bouquetList->getActiveBouquetNumber();
if(!g_settings.zap_cycle && bsize > 1) {
size_t cactive = sl;
printf("CChannelList::getPrevNextChannel: selected %d total %d active bouquet %d total %d\n", (int)cactive, (int)chanlist.size(), bactive, bsize);
if ((key == g_settings.key_quickzap_down) || (key == CRCInput::RC_left)) {
if(cactive == 0) {
bactive = getPrevNextBouquet(false);
if (bactive >= 0) {
bouquetList->activateBouquet(bactive, false);
cactive = bouquetList->Bouquets[bactive]->channelList->getSize() - 1;
}
} else
--cactive;
}
else if ((key == g_settings.key_quickzap_up) || (key == CRCInput::RC_right)) {
cactive++;
if(cactive >= chanlist.size()) {
bactive = getPrevNextBouquet(true);
if (bactive >= 0) {
bouquetList->activateBouquet(bactive, false);
cactive = 0;
}
}
}
sl = cactive;
channel = bouquetList->Bouquets[bactive]->channelList->getChannelFromIndex(cactive);
printf("CChannelList::getPrevNextChannel: selected %u total %d active bouquet %d total %d channel %x (%s)\n",
cactive, chanlist.size(), bactive, bsize, (int) channel, channel ? channel->getName().c_str(): "");
} else {
if ((key == g_settings.key_quickzap_down) || (key == CRCInput::RC_left)) {
if(sl == 0)
sl = chanlist.size()-1;
else
sl--;
}
else if ((key==g_settings.key_quickzap_up) || (key == CRCInput::RC_right)) {
sl = (sl+1)%chanlist.size();
}
channel = chanlist[sl];
}
return channel;
}
void CChannelList::virtual_zap_mode(bool up)
{
if(showEmptyError())
return;
neutrino_msg_t msg;
neutrino_msg_data_t data;
unsigned int sl = selected;
int old_bactive = bouquetList->getActiveBouquetNumber();
int bactive = old_bactive;
CZapitChannel* channel = getPrevNextChannel(up ? CRCInput::RC_right : CRCInput::RC_left, sl);
bool doZap = false;
bool showEPG = false;
int epgpos = 0;
while(1) {
if (channel)
g_InfoViewer->showTitle(channel, true, epgpos);
epgpos = 0;
g_RCInput->getMsg(&msg, &data, 15*10); // 15 seconds, not user changable
if ((msg == CRCInput::RC_left) || (msg == CRCInput::RC_right)) {
channel = bouquetList->Bouquets[bactive]->channelList->getPrevNextChannel(msg, sl);
bactive = bouquetList->getActiveBouquetNumber();
}
else if (msg == CRCInput::RC_up || msg == CRCInput::RC_down) {
epgpos = (msg == CRCInput::RC_up) ? -1 : 1;
}
else if ((msg == CRCInput::RC_ok) || (msg == CRCInput::RC_home) || (msg == CRCInput::RC_timeout)) {
if(msg == CRCInput::RC_ok)
doZap = true;
break;
}
else if (msg == CRCInput::RC_red) {
showEPG = true;
break;
}
else if (CNeutrinoApp::getInstance()->handleMsg(msg, data) & messages_return::cancel_all) {
break;
}
}
g_InfoViewer->clearVirtualZapMode();
if (doZap) {
if(g_settings.timing[SNeutrinoSettings::TIMING_INFOBAR] == 0)
g_InfoViewer->killTitle();
if(channel && SameTP(channel))
zapToChannel(channel);
else
g_InfoViewer->killTitle();
} else {
g_InfoViewer->showTitle(getActiveChannel(), true);
g_InfoViewer->killTitle();
bouquetList->activateBouquet(old_bactive, false);
if (showEPG && channel)
g_EventList->exec(channel->channel_id, channel->getName());
}
}
bool CChannelList::quickZap(int key, bool /* cycle */)
{
if(chanlist.empty())
return true;
unsigned int sl = selected;
/* here selected value doesnt matter, zap will do adjust */
CZapitChannel* channel = getPrevNextChannel(key, sl);
bool ret = false;
if(channel && SameTP(channel)) {
CNeutrinoApp::getInstance()->channelList->zapToChannel(channel);
ret = true;
}
g_RCInput->clearRCMsg(); //FIXME test for n.103
return ret;
}
void CChannelList::paintDetails(int index)
{
CChannelEvent *p_event = NULL;
//colored_events init
bool colored_event_C = false;
bool colored_event_N = false;
if (g_settings.colored_events_channellist == 1)
colored_event_C = true;
if (g_settings.colored_events_channellist == 2)
colored_event_N = true;
if (displayNext) {
p_event = &chanlist[index]->nextEvent;
} else {
p_event = &chanlist[index]->currentEvent;
}
frameBuffer->paintBoxRel(x+1, y + height + 1, full_width-2, info_height - 2, COL_MENUCONTENTDARK_PLUS_0, RADIUS_LARGE);//round
frameBuffer->paintBoxFrame(x, y + height, full_width, info_height, 2, COL_MENUCONTENT_PLUS_6, RADIUS_LARGE);
if (!p_event->description.empty()) {
char cNoch[50] = {0}; // UTF-8
char cSeit[50] = {0}; // UTF-8
struct tm *pStartZeit = localtime(&p_event->startTime);
unsigned seit = ( time(NULL) - p_event->startTime ) / 60;
snprintf(cSeit, sizeof(cSeit), "%s %02d:%02d",(displayNext) ? g_Locale->getText(LOCALE_CHANNELLIST_START):g_Locale->getText(LOCALE_CHANNELLIST_SINCE), pStartZeit->tm_hour, pStartZeit->tm_min);
if (displayNext) {
snprintf(cNoch, sizeof(cNoch), "(%d %s)", p_event->duration / 60, unit_short_minute);
} else {
int noch = (p_event->startTime + p_event->duration - time(NULL)) / 60;
if ((noch< 0) || (noch>=10000))
noch= 0;
snprintf(cNoch, sizeof(cNoch), "(%u / %d %s)", seit, noch, unit_short_minute);
}
int seit_len = g_Font[SNeutrinoSettings::FONT_TYPE_CHANNELLIST_DESCR]->getRenderWidth(cSeit);
int noch_len = g_Font[SNeutrinoSettings::FONT_TYPE_CHANNELLIST_DESCR]->getRenderWidth(cNoch);
std::string text1= p_event->description;
std::string text2= p_event->text;
int xstart = 10;
if (g_Font[SNeutrinoSettings::FONT_TYPE_CHANNELLIST]->getRenderWidth(text1) > (full_width - 30 - seit_len) )
{
// zu breit, Umbruch versuchen...
int pos;
do {
pos = text1.find_last_of("[ -.]+");
if ( pos!=-1 )
text1 = text1.substr( 0, pos );
} while ( ( pos != -1 ) && (g_Font[SNeutrinoSettings::FONT_TYPE_CHANNELLIST]->getRenderWidth(text1) > (full_width - 30 - seit_len) ) );
std::string text3 = ""; /* not perfect, but better than crashing... */
if (p_event->description.length() > text1.length())
text3 = p_event->description.substr(text1.length()+ 1);
if (!text2.empty() && !text3.empty())
text3= text3+ " - ";
xstart += g_Font[SNeutrinoSettings::FONT_TYPE_CHANNELLIST]->getRenderWidth(text3);
g_Font[SNeutrinoSettings::FONT_TYPE_CHANNELLIST]->RenderString(x+ 10, y+ height+ 5+ 2* fheight, full_width - 30- noch_len, text3, colored_event_C ? COL_COLORED_EVENTS_TEXT : COL_MENUCONTENTDARK_TEXT);
}
if (!(text2.empty())) {
while ( text2.find_first_of("[ -.+*#?=!$%&/]+") == 0 )
text2 = text2.substr( 1 );
text2 = text2.substr( 0, text2.find('\n') );
#if 0 //FIXME: to discuss, eat too much cpu time if string long enough
int pos = 0;
while ( ( pos != -1 ) && (g_Font[SNeutrinoSettings::FONT_TYPE_CHANNELLIST]->getRenderWidth(text2) > (full_width - 30 - noch_len) ) ) {
pos = text2.find_last_of(" ");
if ( pos!=-1 ) {
text2 = text2.substr( 0, pos );
}
}
#endif
g_Font[SNeutrinoSettings::FONT_TYPE_CHANNELLIST_DESCR]->RenderString(x+ xstart, y+ height+ 5+ fdescrheight+ fheight, full_width- xstart- 30- noch_len, text2, colored_event_C ? COL_COLORED_EVENTS_TEXT : COL_MENUCONTENTDARK_TEXT);
}
g_Font[SNeutrinoSettings::FONT_TYPE_CHANNELLIST]->RenderString(x+ 10, y+ height+ 5+ fheight, full_width - 30 - seit_len, text1, colored_event_C ? COL_COLORED_EVENTS_TEXT : COL_MENUCONTENTDARK_TEXT);
g_Font[SNeutrinoSettings::FONT_TYPE_CHANNELLIST_DESCR]->RenderString(x+ full_width- 10- seit_len, y+ height+ 5+ fheight, seit_len, cSeit, colored_event_C ? COL_COLORED_EVENTS_TEXT : COL_MENUCONTENTDARK_TEXT);
g_Font[SNeutrinoSettings::FONT_TYPE_CHANNELLIST_DESCR]->RenderString(x+ full_width- 10- noch_len, y+ height+ 5+ fdescrheight+ fheight, noch_len, cNoch, colored_event_C ? COL_COLORED_EVENTS_TEXT : COL_MENUCONTENTDARK_TEXT);
}
if(g_settings.channellist_foot == 0) {
transponder t;
CServiceManager::getInstance()->GetTransponder(chanlist[index]->getTransponderId(), t);
std::string desc = t.description();
if(chanlist[index]->pname)
desc = desc + " (" + std::string(chanlist[index]->pname) + ")";
else
desc = desc + " (" + CServiceManager::getInstance()->GetSatelliteName(chanlist[index]->getSatellitePosition()) + ")";
g_Font[SNeutrinoSettings::FONT_TYPE_CHANNELLIST]->RenderString(x+ 10, y+ height+ 5+ 2*fheight +fdescrheight, full_width - 30, desc.c_str(), COL_MENUCONTENTDARK_TEXT);
}
else if( !displayNext && g_settings.channellist_foot == 1) { // next Event
CSectionsdClient::CurrentNextInfo CurrentNext;
CEitManager::getInstance()->getCurrentNextServiceKey(chanlist[index]->channel_id, CurrentNext);
if (!CurrentNext.next_name.empty()) {
char buf[128] = {0};
char cFrom[50] = {0}; // UTF-8
struct tm *pStartZeit = localtime (& CurrentNext.next_zeit.startzeit);
snprintf(cFrom, sizeof(cFrom), "%s %02d:%02d",g_Locale->getText(LOCALE_WORD_FROM),pStartZeit->tm_hour, pStartZeit->tm_min );
snprintf(buf, sizeof(buf), "%s", CurrentNext.next_name.c_str());
int from_len = g_Font[SNeutrinoSettings::FONT_TYPE_CHANNELLIST_DESCR]->getRenderWidth(cFrom);
g_Font[SNeutrinoSettings::FONT_TYPE_CHANNELLIST]->RenderString(x+ 10, y+ height+ 5+ 2*fheight+ fdescrheight, full_width - 30 - from_len, buf, colored_event_N ? COL_COLORED_EVENTS_TEXT :COL_MENUCONTENTDARK_TEXT);
g_Font[SNeutrinoSettings::FONT_TYPE_CHANNELLIST_DESCR]->RenderString(x+ full_width- 10- from_len, y+ height+ 5+ 2*fheight+ fdescrheight, from_len, cFrom, colored_event_N ? COL_COLORED_EVENTS_TEXT : COL_MENUCONTENTDARK_TEXT);
}
}
if ((g_settings.channellist_additional) && (p_event != NULL))
{
if (displayList)
paint_events(index);
else
showdescription(selected);
}
}
void CChannelList::clearItem2DetailsLine()
{
paintItem2DetailsLine (-1);
}
void CChannelList::paintItem2DetailsLine (int pos)
{
int xpos = x - ConnectLineBox_Width;
int ypos1 = y + theight + pos*fheight + (fheight/2)-2;
int ypos2 = y + height + (info_height/2)-2;
if (dline){
dline->kill(); //kill details line
delete dline;
dline = NULL;
}
// paint Line if detail info (and not valid list pos)
if (pos >= 0) {
if (dline == NULL)
dline = new CComponentsDetailLine(xpos, ypos1, ypos2, fheight/2+1, info_height-RADIUS_LARGE*2);
dline->paint(false);
}
}
void CChannelList::showChannelLogo()
{
if(g_settings.channellist_show_channellogo){
static int logo_w = 0;
static int logo_h = 0;
int logo_w_max = full_width / 4;
if (logo_w && logo_h)
frameBuffer->paintBoxRel(x + full_width - logo_off - logo_w, y+(theight-logo_h)/2, logo_w, logo_h, COL_MENUHEAD_PLUS_0);
std::string lname;
if(g_PicViewer->GetLogoName(chanlist[selected]->channel_id, chanlist[selected]->getName(), lname, &logo_w, &logo_h)) {
if((logo_h > theight) || (logo_w > logo_w_max))
g_PicViewer->rescaleImageDimensions(&logo_w, &logo_h, logo_w_max, theight);
g_PicViewer->DisplayImage(lname, x + full_width - logo_off - logo_w, y+(theight-logo_h)/2, logo_w, logo_h);
}
}
}
#define NUM_LIST_BUTTONS_SORT 9
struct button_label SChannelListButtons_SMode[NUM_LIST_BUTTONS_SORT] =
{
{ NEUTRINO_ICON_BUTTON_RED, LOCALE_INFOVIEWER_EVENTLIST},
{ NEUTRINO_ICON_BUTTON_GREEN, LOCALE_CHANNELLIST_FOOT_SORT_ALPHA},
{ NEUTRINO_ICON_BUTTON_YELLOW, LOCALE_BOUQUETLIST_HEAD},
{ NEUTRINO_ICON_BUTTON_BLUE, LOCALE_INFOVIEWER_NEXT},
{ NEUTRINO_ICON_BUTTON_RECORD_INACTIVE, NONEXISTANT_LOCALE},
{ NEUTRINO_ICON_BUTTON_PLAY, LOCALE_EXTRA_KEY_PIP_CLOSE},
{ NEUTRINO_ICON_BUTTON_INFO_SMALL, NONEXISTANT_LOCALE},
{ NEUTRINO_ICON_BUTTON_MENU_SMALL, NONEXISTANT_LOCALE},
{ NEUTRINO_ICON_BUTTON_MUTE_ZAP_ACTIVE, NONEXISTANT_LOCALE}
};
void CChannelList::paintButtonBar(bool is_current)
{
//printf("[neutrino channellist] %s...%d, selected %d\n", __FUNCTION__, __LINE__, selected);
unsigned int smode = CNeutrinoApp::getInstance()->GetChannelMode();
#if 0
int num_buttons = smode != LIST_MODE_FAV ? NUM_LIST_BUTTONS_SORT : NUM_LIST_BUTTONS;
struct button_label Button[num_buttons];
const neutrino_locale_t button_ids[] = {LOCALE_INFOVIEWER_NOW,LOCALE_INFOVIEWER_NEXT,LOCALE_MAINMENU_RECORDING,LOCALE_MAINMENU_RECORDING_STOP,LOCALE_EXTRA_KEY_PIP_CLOSE,
LOCALE_CHANNELLIST_FOOT_SORT_ALPHA,LOCALE_CHANNELLIST_FOOT_SORT_FREQ,LOCALE_CHANNELLIST_FOOT_SORT_SAT,LOCALE_CHANNELLIST_FOOT_SORT_CHNUM};
const std::vector<neutrino_locale_t> buttonID_rest (button_ids, button_ids + sizeof(button_ids) / sizeof(neutrino_locale_t) );
#endif
struct button_label Button[NUM_LIST_BUTTONS_SORT];
bool do_record = CRecordManager::getInstance()->RecordingStatus(getActiveChannel_ChannelID());
int bcnt = 0;
for (int i = 0; i < NUM_LIST_BUTTONS_SORT; i++) {
Button[bcnt] = SChannelListButtons_SMode[i];
if (i == 1) {
/* check green / sort */
if(smode) {
switch (g_settings.channellist_sort_mode) {
case SORT_ALPHA:
Button[bcnt].locale = LOCALE_CHANNELLIST_FOOT_SORT_ALPHA;
break;
case SORT_TP:
Button[bcnt].locale = LOCALE_CHANNELLIST_FOOT_SORT_FREQ;
break;
case SORT_SAT:
Button[bcnt].locale = LOCALE_CHANNELLIST_FOOT_SORT_SAT;
break;
case SORT_CH_NUMBER:
Button[bcnt].locale = LOCALE_CHANNELLIST_FOOT_SORT_CHNUM;
break;
default:
break;
}
} else
continue;
}
if (i == 3) {
//manage now/next button
if (g_settings.channellist_additional) {
if (displayList)
Button[bcnt].locale = LOCALE_FONTSIZE_CHANNELLIST_DESCR;
else
Button[bcnt].locale = LOCALE_FONTMENU_EVENTLIST;
} else {
if (displayNext)
Button[bcnt].locale = LOCALE_INFOVIEWER_NOW;
else
Button[bcnt].locale = LOCALE_INFOVIEWER_NEXT;
}
}
if (i == 4) {
//manage record button
if (g_settings.recording_type == RECORDING_OFF)
continue;
if (!displayNext){
if (do_record){
Button[bcnt].locale = LOCALE_MAINMENU_RECORDING_STOP;
Button[bcnt].button = NEUTRINO_ICON_BUTTON_STOP;
} else if (is_current) {
Button[bcnt].locale = LOCALE_MAINMENU_RECORDING;
Button[bcnt].button = NEUTRINO_ICON_BUTTON_RECORD_ACTIVE;
} else {
Button[bcnt].locale = NONEXISTANT_LOCALE;
Button[bcnt].button = NEUTRINO_ICON_BUTTON_RECORD_INACTIVE;
}
}
}
if (i == 5) {
//manage pip button
#ifdef ENABLE_PIP
if (!is_current)
#endif
continue;
}
if (i == 8) {
/* check mute / zap mode */
if (new_zap_mode)
Button[bcnt].button = new_zap_mode == 2 /* active */ ?
NEUTRINO_ICON_BUTTON_MUTE_ZAP_ACTIVE : NEUTRINO_ICON_BUTTON_MUTE_ZAP_INACTIVE;
else
continue;
}
bcnt++;
}
//paint buttons
int y_foot = y + (height - footerHeight);
::paintButtons(x, y_foot, full_width, bcnt, Button, full_width, footerHeight);
}
void CChannelList::paintItem(int pos, const bool firstpaint)
{
int ypos = y+ theight + pos*fheight;
fb_pixel_t color;
fb_pixel_t bgcolor;
bool iscurrent = true;
bool paintbuttons = false;
unsigned int curr = liststart + pos;
fb_pixel_t c_rad_small = 0;
#if 0
if(CNeutrinoApp::getInstance()->recordingstatus && !autoshift && curr < chanlist.size()) {
iscurrent = (chanlist[curr]->channel_id >> 16) == (rec_channel_id >> 16);
//printf("recording %llx current %llx current = %s\n", rec_channel_id, chanlist[liststart + pos]->channel_id, iscurrent? "yes" : "no");
}
#endif
if(curr < chanlist.size())
iscurrent = SameTP(chanlist[curr]);
if (curr == selected) {
color = COL_MENUCONTENTSELECTED_TEXT;
bgcolor = COL_MENUCONTENTSELECTED_PLUS_0;
paintItem2DetailsLine (pos);
paintDetails(curr);
c_rad_small = RADIUS_LARGE;
paintbuttons = true;
}
else if (getKey(curr) == CNeutrinoApp::getInstance()->channelList->getActiveChannelNumber() && new_zap_mode != 2/*active*/)
{
color = !displayNext ? COL_MENUCONTENT_TEXT : COL_MENUCONTENTINACTIVE_TEXT;
bgcolor = !displayNext ? COL_MENUCONTENT_PLUS_1 : COL_MENUCONTENTINACTIVE_PLUS_0;
c_rad_small = RADIUS_LARGE;
} else {
color = iscurrent ? COL_MENUCONTENT_TEXT : COL_MENUCONTENTINACTIVE_TEXT;
bgcolor = iscurrent ? COL_MENUCONTENT_PLUS_0 : COL_MENUCONTENTINACTIVE_PLUS_0;
}
if(!firstpaint || (curr == selected) || getKey(curr) == CNeutrinoApp::getInstance()->channelList->getActiveChannelNumber()){
frameBuffer->paintBoxRel(x,ypos, width- 15, fheight, bgcolor, c_rad_small);
}
if(curr < chanlist.size()) {
char nameAndDescription[255];
char tmp[10];
CZapitChannel* chan = chanlist[curr];
int prg_offset=0;
int title_offset=0;
fb_pixel_t tcolor=(liststart + pos == selected) ? color : COL_MENUCONTENTINACTIVE_TEXT;
int xtheight=fheight-2;
int rec_mode;
if(g_settings.channellist_extended)
{
prg_offset = g_Font[SNeutrinoSettings::FONT_TYPE_CHANNELLIST_NUMBER]->getRenderWidth("00:00");
title_offset=6;
}
snprintf((char*) tmp, sizeof(tmp), "%d", this->historyMode ? pos : chan->number);
CChannelEvent *p_event=NULL;
if (displayNext) {
p_event = &chan->nextEvent;
} else {
p_event = &chan->currentEvent;
}
if (pos == 0)
{
/* FIXME move to calcSize() ? */
int w_max, w_min, h;
ChannelList_Rec = 0;
int recmode_icon_max = CRecordManager::RECMODE_REC, recmode_icon_min = CRecordManager::RECMODE_TSHIFT;
frameBuffer->getIconSize(NEUTRINO_ICON_REC, &w_max, &h);
frameBuffer->getIconSize(NEUTRINO_ICON_AUTO_SHIFT, &w_min, &h);
if (w_max < w_min)
{
recmode_icon_max = CRecordManager::RECMODE_TSHIFT;
recmode_icon_min = CRecordManager::RECMODE_REC;
h = w_max;
w_max = w_min;
w_min = h;
}
for (uint32_t i = 0; i < chanlist.size(); i++)
{
rec_mode = CRecordManager::getInstance()->GetRecordMode(chanlist[i]->channel_id);
if (rec_mode & recmode_icon_max)
{
ChannelList_Rec = w_max;
break;
} else if (rec_mode & recmode_icon_min)
ChannelList_Rec = w_min;
}
if (ChannelList_Rec > 0)
ChannelList_Rec += 8;
}
//record check
rec_mode = CRecordManager::getInstance()->GetRecordMode(chanlist[curr]->channel_id);
//set recording icon
std::string rec_icon;
if (rec_mode & CRecordManager::RECMODE_REC)
rec_icon = NEUTRINO_ICON_REC;
else if (rec_mode & CRecordManager::RECMODE_TSHIFT)
rec_icon = NEUTRINO_ICON_AUTO_SHIFT;
#ifdef ENABLE_PIP
else if (chanlist[curr]->channel_id == CZapit::getInstance()->GetPipChannelID()) {
int h;
frameBuffer->getIconSize(NEUTRINO_ICON_PIP, &ChannelList_Rec, &h);
rec_icon = NEUTRINO_ICON_PIP;
ChannelList_Rec += 8;
}
#endif
//calculating icons
int icon_x = (x+width-15-2) - RADIUS_LARGE/2;
int r_icon_w; int s_icon_h=0; int s_icon_w=0;
frameBuffer->getIconSize(NEUTRINO_ICON_SCRAMBLED, &s_icon_w, &s_icon_h);
r_icon_w = ChannelList_Rec;
int r_icon_x = icon_x;
//paint scramble icon
if(chan->scrambled)
if (frameBuffer->paintIcon(NEUTRINO_ICON_SCRAMBLED, icon_x - s_icon_w, ypos, fheight))//ypos + (fheight - 16)/2);
r_icon_x = r_icon_x - s_icon_w;
//paint recording icon
//if (rec_mode != CRecordManager::RECMODE_OFF)
if (!rec_icon.empty())
frameBuffer->paintIcon(rec_icon, r_icon_x - r_icon_w, ypos, fheight);//ypos + (fheight - 16)/2);
//paint buttons
if (paintbuttons)
paintButtonBar(iscurrent);
int icon_space = r_icon_w+s_icon_w;
//number
int numpos = x+5+numwidth- g_Font[SNeutrinoSettings::FONT_TYPE_CHANNELLIST_NUMBER]->getRenderWidth(tmp);
g_Font[SNeutrinoSettings::FONT_TYPE_CHANNELLIST_NUMBER]->RenderString(numpos,ypos+fheight, numwidth+5, tmp, color, fheight);
int l=0;
if (this->historyMode)
l = snprintf(nameAndDescription, sizeof(nameAndDescription), ": %d %s", chan->number, chan->getName().c_str());
else
l = snprintf(nameAndDescription, sizeof(nameAndDescription), "%s", chan->getName().c_str());
int pb_space = prg_offset - title_offset;
bool pb_colored = ((g_settings.channellist_extended == 2) && g_settings.progressbar_color);
int pb_frame = pb_colored ? 0 : 1;
CProgressBar pb(x+5+numwidth + title_offset, ypos + fheight/4, pb_space, fheight/2,
color, bgcolor, COL_MENUCONTENTDARK_PLUS_0, color, COL_MENUCONTENT_PLUS_1,
pb_colored, 0, 100, 70);
pb.setCornerType(0);
pb.setFrameThickness(pb_frame);
int pb_max = pb_space - (2*pb_frame);
if (!(p_event->description.empty())) {
snprintf(nameAndDescription+l, sizeof(nameAndDescription)-l,g_settings.channellist_epgtext_align_right ? " ":" - ");
unsigned int ch_name_len = g_Font[SNeutrinoSettings::FONT_TYPE_CHANNELLIST]->getRenderWidth(nameAndDescription);
unsigned int ch_desc_len = g_Font[SNeutrinoSettings::FONT_TYPE_CHANNELLIST_DESCR]->getRenderWidth(p_event->description);
int max_desc_len = width - numwidth - prg_offset - ch_name_len - 15 - 20; // 15 = scrollbar, 20 = spaces
if (chan->scrambled || (g_settings.channellist_extended ||g_settings.channellist_epgtext_align_right))
max_desc_len -= icon_space+g_Font[SNeutrinoSettings::FONT_TYPE_CHANNELLIST_DESCR]->getWidth(); /* do we need space for the lock/rec icon? */
if (max_desc_len < 0)
max_desc_len = 0;
if ((int) ch_desc_len > max_desc_len)
ch_desc_len = max_desc_len;
if(g_settings.channellist_extended) {
if(displayNext)
{
struct tm *pStartZeit = localtime(&p_event->startTime);
snprintf((char*) tmp, sizeof(tmp), "%02d:%02d", pStartZeit->tm_hour, pStartZeit->tm_min);
// g_Font[SNeutrinoSettings::FONT_TYPE_IMAGEINFO_SMALL]->RenderString(x+ 5+ numwidth+ 6, ypos+ xtheight, width- numwidth- 20- 15 -poffs, tmp, COL_MENUCONTENT_TEXT);
g_Font[SNeutrinoSettings::FONT_TYPE_CHANNELLIST_NUMBER]->RenderString(x+ 5+ numwidth+ 6, ypos+ xtheight, width- numwidth- 20- 15 -prg_offset, tmp, tcolor);
}
else
{
time_t jetzt=time(NULL);
int runningPercent = 0;
if (((jetzt - p_event->startTime + 30) / 60) < 0 )
{
runningPercent= 0;
}
else
{
runningPercent=(jetzt-p_event->startTime) * pb_max / p_event->duration;
if (runningPercent > pb_max) // this would lead to negative value in paintBoxRel
runningPercent = pb_max; // later on which can be fatal...
}
if (liststart + pos != selected)
pb.setPassiveColor(COL_MENUCONTENT_PLUS_3);
else
pb.setPassiveColor(COL_MENUCONTENTSELECTED_PLUS_2);
pb.setValues(runningPercent, pb_max);
pb.paint();
}
}
g_Font[SNeutrinoSettings::FONT_TYPE_CHANNELLIST]->RenderString(x+ 5+ numwidth+ 10+prg_offset, ypos+ fheight, width- numwidth- 40- 15-prg_offset, nameAndDescription, color);
if (g_settings.channellist_epgtext_align_right) {
// align right
g_Font[SNeutrinoSettings::FONT_TYPE_CHANNELLIST_DESCR]->RenderString(x + width - 20 - ch_desc_len - icon_space - 4, ypos + fheight, ch_desc_len, p_event->description, (curr == selected)?COL_MENUCONTENTSELECTED_TEXT:(!displayNext ? COL_MENUCONTENT_TEXT : COL_MENUCONTENTINACTIVE_TEXT));
}
else {
// align left
g_Font[SNeutrinoSettings::FONT_TYPE_CHANNELLIST_DESCR]->RenderString(x+ 5+ numwidth+ 10+ ch_name_len+ 5+prg_offset, ypos+ fheight, ch_desc_len, p_event->description, (curr == selected)?COL_MENUCONTENTSELECTED_TEXT:(!displayNext ? COL_MENUCONTENT_TEXT : COL_MENUCONTENTINACTIVE_TEXT));
}
}
else {
if(g_settings.channellist_extended) {
if (liststart + pos != selected)
pb.setPassiveColor(COL_MENUCONTENT_PLUS_1);
else
pb.setPassiveColor(COL_MENUCONTENTSELECTED_PLUS_2);
pb.setValues(0, pb_max);
pb.setZeroLine();
pb.paint();
}
//name
g_Font[SNeutrinoSettings::FONT_TYPE_CHANNELLIST]->RenderString(x+ 5+ numwidth+ 10+prg_offset, ypos+ fheight, width- numwidth- 40- 15-prg_offset, nameAndDescription, color);
}
if (curr == selected) {
if (!(chan->currentEvent.description.empty())) {
snprintf(nameAndDescription, sizeof(nameAndDescription), "%s - %s",
chan->getName().c_str(), p_event->description.c_str());
CVFD::getInstance()->showMenuText(0, nameAndDescription, -1, true); // UTF-8
} else
CVFD::getInstance()->showMenuText(0, chan->getName().c_str(), -1, true); // UTF-8
}
}
}
void CChannelList::paintHead()
{
CComponentsHeader header(x, y, full_width, theight, name /*no header icon*/);
header.paint(CC_SAVE_SCREEN_NO);
if (g_Sectionsd->getIsTimeSet()) {
if (headerClock == NULL) {
headerClock = new CComponentsFrmClock(0, 0, 0, 0, "%H:%M", true);
headerClock->setClockBlink("%H %M");
headerClock->setClockIntervall(1);
}
headerClock->setClockFormat("%H:%M");
headerClock->setClockFont(SNeutrinoSettings::FONT_TYPE_MENU_TITLE);
headerClock->setCorner(RADIUS_LARGE, CORNER_TOP_RIGHT);
headerClock->setYPos(y);
headerClock->setHeight(theight);
headerClock->setTextColor(header.getTextObject()->getTextColor());
headerClock->setColorBody(header.getColorBody());
headerClock->refresh();
headerClockWidth = headerClock->getWidth();
headerClock->setXPos(x + full_width - headerClockWidth - 10);
headerClockWidth += 6;
headerClock->Start();
}
else
headerClockWidth = 0;
logo_off = headerClockWidth + 10;
}
void CChannelList::paint()
{
numwidth = g_Font[SNeutrinoSettings::FONT_TYPE_CHANNELLIST_NUMBER]->getRenderWidth(MaxChanNr());
liststart = (selected/listmaxshow)*listmaxshow;
updateEvents(this->historyMode ? 0:liststart, this->historyMode ? 0:(liststart + listmaxshow));
if (pig_on_win) // with miniTV
paintPig(x+width, y+theight, pig_width, pig_height);
// paint background for main box
frameBuffer->paintBoxRel(x, y+theight, width, height-footerHeight-theight, COL_MENUCONTENT_PLUS_0);
if (g_settings.channellist_additional)
{
// disable displayNext
displayNext = false;
// paint background for right box
frameBuffer->paintBoxRel(x+width,y+theight+pig_height,infozone_width,infozone_height,COL_MENUCONTENT_PLUS_0);
}
unit_short_minute = g_Locale->getText(LOCALE_UNIT_SHORT_MINUTE);
for(unsigned int count = 0; count < listmaxshow; count++) {
paintItem(count, true);
}
const int ypos = y+ theight;
const int sb = height - theight - footerHeight; // paint scrollbar over full height of main box
frameBuffer->paintBoxRel(x+ width- 15,ypos, 15, sb, COL_MENUCONTENT_PLUS_1);
int sbc= ((chanlist.size()- 1)/ listmaxshow)+ 1;
const int sbs= (selected/listmaxshow);
if (sbc < 1)
sbc = 1;
frameBuffer->paintBoxRel(x+ width- 13, ypos+ 2+ sbs*(sb-4)/sbc, 11, (sb-4)/sbc, COL_MENUCONTENT_PLUS_3);
showChannelLogo();
}
bool CChannelList::isEmpty() const
{
return this->chanlist.empty();
}
int CChannelList::getSize() const
{
return this->chanlist.size();
}
int CChannelList::getSelectedChannelIndex() const
{
return this->selected;
}
bool CChannelList::SameTP(t_channel_id channel_id)
{
bool iscurrent = true;
#if 0
if(CNeutrinoApp::getInstance()->recordingstatus && !autoshift)
iscurrent = (channel_id >> 16) == (rec_channel_id >> 16);
#endif
if(CNeutrinoApp::getInstance()->recordingstatus) {
#if 0
if(channel_id == 0)
channel_id = chanlist[selected]->channel_id;
iscurrent = CRecordManager::getInstance()->SameTransponder(channel_id);
#endif
CZapitChannel * channel = CServiceManager::getInstance()->FindChannel(channel_id);
if(channel)
iscurrent = SameTP(channel);
else
iscurrent = false;
}
return iscurrent;
}
bool CChannelList::SameTP(CZapitChannel * channel)
{
bool iscurrent = true;
if(CNeutrinoApp::getInstance()->recordingstatus) {
if(channel == NULL)
channel = chanlist[selected];
iscurrent = CFEManager::getInstance()->canTune(channel);
}
return iscurrent;
}
std::string CChannelList::MaxChanNr()
{
zapit_list_it_t chan_it;
std::stringstream ss;
std::string maxchansize;
int chan_nr_max = 1;
unsigned int nr = 0;
for (chan_it=chanlist.begin(); chan_it!=chanlist.end(); ++chan_it) {
chan_nr_max = std::max(chan_nr_max, chanlist[nr++]->number);
}
ss << chan_nr_max;
ss >> maxchansize;
return maxchansize;
}
void CChannelList::paintPig (int _x, int _y, int w, int h)
{
//init minitv object with basic properties
if (cc_minitv == NULL){
cc_minitv = new CComponentsPIP (0, 0);
cc_minitv->setPicture(NEUTRINO_ICON_AUDIOPLAY);
cc_minitv->setFrameThickness(5);
}
//set changeable minitv properties
cc_minitv->setDimensionsAll(_x, _y, w, h);
cc_minitv->setCorner(0);
cc_minitv->setColorFrame(COL_MENUCONTENT_PLUS_0);
cc_minitv->paint(false);
}
void CChannelList::paint_events(int index)
{
ffheight = g_Font[eventFont]->getHeight();
readEvents(chanlist[index]->channel_id);
frameBuffer->paintBoxRel(x+ width,y+ theight+pig_height, infozone_width, infozone_height,COL_MENUCONTENT_PLUS_0);
char startTime[10];
int eventStartTimeWidth = 4 * g_Font[eventFont]->getMaxDigitWidth() + g_Font[eventFont]->getRenderWidth(":") + 5; // use a fixed value
int startTimeWidth = 0;
CChannelEventList::iterator e;
time_t azeit;
time(&azeit);
unsigned int u_azeit = ( azeit > -1)? azeit:0;
if ( evtlist.empty() )
{
CChannelEvent evt;
evt.description = g_Locale->getText(LOCALE_EPGLIST_NOEVENTS);
evt.eventID = 0;
evt.startTime = 0;
evtlist.push_back(evt);
}
int i=1;
for (e=evtlist.begin(); e!=evtlist.end(); ++e )
{
//Remove events in the past
if ( (u_azeit > (e->startTime + e->duration)) && (!(e->eventID == 0)))
{
do
{
//printf("%d seconds in the past - deleted %s\n", dif, e->description.c_str());
e = evtlist.erase( e );
if (e == evtlist.end())
break;
}
while ( u_azeit > (e->startTime + e->duration));
}
if (e == evtlist.end())
break;
//Display the remaining events
if ((y+ theight+ pig_height + i*ffheight) < (y+ theight+ pig_height + infozone_height))
{
fb_pixel_t color = COL_MENUCONTENTDARK_TEXT;
if (e->eventID)
{
bool first = (i == 1);
if ((first && g_settings.colored_events_channellist == 1 /* current */) || (!first && g_settings.colored_events_channellist == 2 /* next */))
color = COL_COLORED_EVENTS_TEXT;
struct tm *tmStartZeit = localtime(&e->startTime);
strftime(startTime, sizeof(startTime), "%H:%M", tmStartZeit );
//printf("%s %s\n", startTime, e->description.c_str());
startTimeWidth = eventStartTimeWidth;
g_Font[eventFont]->RenderString(x+ width+5, y+ theight+ pig_height + i*ffheight, startTimeWidth, startTime, color);
}
g_Font[eventFont]->RenderString(x+ width+5+startTimeWidth, y+ theight+ pig_height + i*ffheight, infozone_width - startTimeWidth - 20, e->description, color);
}
else
{
break;
}
i++;
}
if ( !evtlist.empty() )
evtlist.clear();
}
static bool sortByDateTime (const CChannelEvent& a, const CChannelEvent& b)
{
return a.startTime < b.startTime;
}
void CChannelList::readEvents(const t_channel_id channel_id)
{
CEitManager::getInstance()->getEventsServiceKey(channel_id , evtlist);
if ( evtlist.empty() )
{
CChannelEvent evt;
evt.description = g_Locale->getText(LOCALE_EPGLIST_NOEVENTS);
evt.eventID = 0;
evt.startTime = 0;
evtlist.push_back(evt);
}
else
sort(evtlist.begin(),evtlist.end(),sortByDateTime);
return;
}
void CChannelList::showdescription(int index)
{
ffheight = g_Font[eventFont]->getHeight();
CZapitChannel* chan = chanlist[index];
CChannelEvent *p_event = &chan->currentEvent;
epgData.info2.clear();
epgText.clear();
CEitManager::getInstance()->getEPGid(p_event->eventID, p_event->startTime, &epgData);
if (!(epgData.info2.empty()))
processTextToArray(epgData.info2);
else
processTextToArray(g_Locale->getText(LOCALE_EPGVIEWER_NODETAILED));
frameBuffer->paintBoxRel(x+ width,y+ theight+pig_height, infozone_width, infozone_height,COL_MENUCONTENT_PLUS_0);
for (int i = 1; (i < (int)epgText.size()+1) && ((y+ theight+ pig_height + i*ffheight) < (y+ theight+ pig_height + infozone_height)); i++)
g_Font[eventFont]->RenderString(x+ width+5, y+ theight+ pig_height + i*ffheight, infozone_width - 20, epgText[i-1].first, COL_MENUCONTENTDARK_TEXT);
}
void CChannelList::addTextToArray(const std::string & text, int screening) // UTF-8
{
//printf("line: >%s<\n", text.c_str() );
if (text==" ")
{
emptyLineCount ++;
if (emptyLineCount<2)
{
epgText.push_back(epg_pair(text,screening));
}
}
else
{
emptyLineCount = 0;
epgText.push_back(epg_pair(text,screening));
}
}
void CChannelList::processTextToArray(std::string text, int screening) // UTF-8
{
std::string aktLine = "";
std::string aktWord = "";
int aktWidth = 0;
text += ' ';
char* text_= (char*) text.c_str();
while (*text_!=0)
{
if ( (*text_==' ') || (*text_=='\n') || (*text_=='-') || (*text_=='.') )
{
if (*text_!='\n')
aktWord += *text_;
int aktWordWidth = g_Font[eventFont]->getRenderWidth(aktWord);
if ((aktWordWidth+aktWidth)<(infozone_width - 20))
{//space ok, add
aktWidth += aktWordWidth;
aktLine += aktWord;
if (*text_=='\n')
{ //enter-handler
addTextToArray( aktLine, screening );
aktLine = "";
aktWidth= 0;
}
aktWord = "";
}
else
{//new line needed
addTextToArray( aktLine, screening);
aktLine = aktWord;
aktWidth = aktWordWidth;
aktWord = "";
if (*text_=='\n')
continue;
}
}
else
{
aktWord += *text_;
}
text_++;
}
//add the rest
addTextToArray( aktLine + aktWord, screening );
}