/* Neutrino-GUI - DBoxII-Project Copyright (C) 2001 Steffen Hehn 'McClean' Copyright (C) 2007-2016 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 #endif #include #include "channellist.h" #include #include #include #include #include #include #include #include #include #include #include "color.h" #include "color_custom.h" #include "epgview.h" #include "eventlist.h" #include "infoviewer.h" #include "osd_setup.h" #include "components/cc.h" #include "widget/stringinput.h" #include "widget/keyboard_input.h" #include "widget/buttons.h" #include "widget/icons.h" #include "movieplayer.h" #include "infoclock.h" #if 0 #include "widget/messagebox.h" #include "widget/hintbox.h" #else #include "widget/msgbox.h" #endif #include #include #include #include "bouquetlist.h" #include #include #include "pictureviewer.h" #include "bedit/bouqueteditor_chanselect.h" #include #include #include #include #include #include #ifdef ENABLE_LCD4LINUX #include "driver/lcd4l.h" #endif extern CBouquetList * bouquetList; /* neutrino.cpp */ extern CRemoteControl * g_RemoteControl; /* neutrino.cpp */ extern CBouquetList * AllFavBouquetList; extern CBouquetList * TVfavList; extern CBouquetList * RADIOfavList; extern bool autoshift; static CComponentsPIP *cc_minitv = NULL; extern CBouquetManager *g_bouquetManager; extern int old_b_id; static CComponentsHeader *header = NULL; extern bool timeset; 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_MENU_FOOT]->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 = g_settings.channellist_additional; eventFont = SNeutrinoSettings::FONT_TYPE_CHANNELLIST_EVENT; dline = NULL; minitv_is_active = false; headerNew = true; bouquet = NULL; chanlist = &channels; move_state = beDefault; edit_state = false; channelsChanged = false; liveBouquet = false; displayMode = DISPLAY_MODE_NOW; // always start with current events descMode = false; // always start with event list paint_events_index = -2; CFrameBuffer::getInstance()->OnAfterSetPallette.connect(sigc::mem_fun(this, &CChannelList::ResetModules)); CNeutrinoApp::getInstance()->OnAfterSetupFonts.connect(sigc::mem_fun(this, &CChannelList::ResetModules)); } CChannelList::~CChannelList() { ResetModules(); } void CChannelList::SetChannelList(ZapitChannelList* zlist) { channels = *zlist; } void CChannelList::addChannel(CZapitChannel* channel) { (*chanlist).push_back(channel); } /* update 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) { if ((*chanlist).empty()) return; if (to == 0 || to > (*chanlist).size()) to = (*chanlist).size(); if (from > (*chanlist).size() || from >= to) return; size_t chanlist_size = to - from; if (chanlist_size <= 0) // WTF??? return; CChannelEventList events; if (displayMode == DISPLAY_MODE_NEXT || displayMode == DISPLAY_MODE_PRIME) { time_t atime = time(NULL); if (displayMode == DISPLAY_MODE_PRIME) { struct tm * timeinfo; timeinfo = localtime(&atime); if ((timeinfo->tm_hour > 20) || (timeinfo->tm_hour == 20 && timeinfo->tm_min >= 30)) timeinfo->tm_mday += 1; timeinfo->tm_hour = 20; timeinfo->tm_min = 0; atime = mktime(timeinfo); } unsigned int count; for (count = from; count < to; count++) { CEitManager::getInstance()->getEventsServiceKey((*chanlist)[count]->getEpgID(), 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]->getEpgID(); 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]->getEpgID()&0xFFFFFFFFFFFFULL) == e->get_channel_id()) { (*chanlist)[count + from]->currentEvent = *e; break; } } } levents.clear(); delete[] p_requested_channels; } } 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) { if(channel_id != std::numeric_limits::max() && !(*chanlist).empty()){ for (uint32_t i=0; i< (*chanlist).size(); i++) { if ((*chanlist)[i]->getChannelID() == 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; } const std::string CChannelList::getActiveChannelName(void) const { static const std::string empty_string; if (selected < (*chanlist).size()) return (*chanlist)[selected]->getName(); 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()) return (*chanlist)[selected]->getChannelID(); 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 select = -1; int shortcut = 0; static int old_selected = 0; char cnt[5]; int ret = 0; if(g_settings.minimode) return 0; CMenuWidget* menu = new CMenuWidget(LOCALE_CHANNELLIST_EDIT, NEUTRINO_ICON_SETTINGS); menu->enableFade(false); menu->enableSaveScreen(true); // we don't show introitems, so we add a separator for a smoother view menu->addItem(GenericMenuSeparator); //ensure stop info clock before paint context menu CInfoClock::getInstance()->block(); //ensure stop header clock before paint context menu if (g_settings.menu_pos == CMenuWidget::MENU_POS_TOP_RIGHT){ //using native callback to ensure stop header clock before paint this menu window menu->OnBeforePaint.connect(sigc::mem_fun(header->getClockObject(), &CComponentsFrmClock::block)); //... and start header clock after hide menu window menu->OnAfterHide.connect(sigc::mem_fun(header->getClockObject(), &CComponentsFrmClock::unblock)); } CMenuSelectorTarget * selector = new CMenuSelectorTarget(&select); bool empty = (*chanlist).empty(); bool allow_edit = (bouquet && bouquet->zapitBouquet && !bouquet->zapitBouquet->bOther && (!bouquet->zapitBouquet->bWebtv && !bouquet->zapitBouquet->bWebradio)); bool got_history = (CNeutrinoApp::getInstance()->channelList->getLastChannels().size() > 1); int i = 0; snprintf(cnt, sizeof(cnt), "%d", i); menu->addItem(new CMenuForwarder(LOCALE_BOUQUETEDITOR_NAME, allow_edit, NULL, selector, cnt, CRCInput::RC_red), old_selected == i++); snprintf(cnt, sizeof(cnt), "%d", i); menu->addItem(new CMenuForwarder(LOCALE_EXTRA_ADD_TO_BOUQUET, !empty, NULL, selector, cnt, CRCInput::RC_green), old_selected == i++); snprintf(cnt, sizeof(cnt), "%d", i); menu->addItem(new CMenuForwarder(LOCALE_FAVORITES_MENUEADD, !empty, NULL, selector, cnt, CRCInput::RC_yellow), old_selected == i++); bool reset_enabled = empty ? false : (*chanlist)[selected]->flags & CZapitChannel::NEW; snprintf(cnt, sizeof(cnt), "%d", i); menu->addItem(new CMenuForwarder(LOCALE_CHANNELLIST_RESET_FLAGS, reset_enabled, NULL, selector, cnt, CRCInput::convertDigitToKey(shortcut++)), old_selected == i++); bool reset_all = !empty && (name == g_Locale->getText(LOCALE_BOUQUETNAME_NEW)); snprintf(cnt, sizeof(cnt), "%d", i); menu->addItem(new CMenuForwarder(LOCALE_CHANNELLIST_RESET_ALL, reset_all, NULL, selector, cnt, CRCInput::convertDigitToKey(shortcut++)), old_selected == i++); menu->addItem(GenericMenuSeparator); snprintf(cnt, sizeof(cnt), "%d", i); menu->addItem(new CMenuForwarder(LOCALE_CHANNELLIST_HISTORY_CLEAR, got_history, NULL, selector, cnt, CRCInput::convertDigitToKey(shortcut++)), old_selected == i++); menu->addItem(new CMenuSeparator(CMenuSeparator::LINE)); snprintf(cnt, sizeof(cnt), "%d", i); 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_selected = select; t_channel_id channel_id = empty ? 0 : (*chanlist)[selected]->getChannelID(); bool tvmode = CZapit::getInstance()->getMode() & CZapitClient::MODE_TV; CBouquetList *blist = tvmode ? TVfavList : RADIOfavList; bool fav_found = true; switch(select) { case 0: // edit mode { bool unlocked = true; if (g_settings.parentallock_prompt == PARENTALLOCK_PROMPT_CHANGETOLOCKED) { int pl_z = g_settings.parentallock_zaptime * 60; if (g_settings.personalize[SNeutrinoSettings::P_MSER_BOUQUET_EDIT] == CPersonalizeGui::PERSONALIZE_MODE_PIN) { unlocked = false; } else if (bouquet && bouquet->zapitBouquet && bouquet->zapitBouquet->bLocked) { /* on locked bouquet, enough to check any channel */ unlocked = ((*chanlist)[selected]->last_unlocked_time + pl_z > time_monotonic()); } else { /* check all locked channels for last_unlocked_time, overwrite only if already unlocked */ for (unsigned int j = 0 ; j < (*chanlist).size(); j++) { if ((*chanlist)[j]->bLocked) unlocked = unlocked && ((*chanlist)[j]->last_unlocked_time + pl_z > time_monotonic()); } } if (!unlocked) { CZapProtection *zp = new CZapProtection(g_settings.parentallock_pincode, 0x100); unlocked = zp->check(); delete zp; } } if (unlocked) editMode(true); ret = -1; break; } case 1: // add to if (!addChannelToBouquet()) return -1; ret = 1; break; case 2: // add to my favorites for (unsigned n = 0; n < AllFavBouquetList->Bouquets.size(); n++) { if (AllFavBouquetList->Bouquets[n]->zapitBouquet && AllFavBouquetList->Bouquets[n]->zapitBouquet->bFav) { CZapitChannel *ch = AllFavBouquetList->Bouquets[n]->zapitBouquet->getChannelByChannelID(channel_id); if (ch == NULL) { AllFavBouquetList->Bouquets[n]->zapitBouquet->addService((*chanlist)[selected]); fav_found = false; } break; } } for (unsigned n = 0; n < blist->Bouquets.size() && !fav_found; n++) { if (blist->Bouquets[n]->zapitBouquet && blist->Bouquets[n]->zapitBouquet->bFav) { blist->Bouquets[n]->zapitBouquet->getChannels(blist->Bouquets[n]->channelList->channels, tvmode); saveChanges(); fav_found = true; break; } } if (!fav_found) { CNeutrinoApp::getInstance()->MarkFavoritesChanged(); CNeutrinoApp::getInstance()->MarkChannelsInit(); } ret = 1; break; case 3: // reset new case 4: // reset all new if (select == 3) { (*chanlist)[selected]->flags = CZapitChannel::UPDATED; } else { for (unsigned int j = 0 ; j < (*chanlist).size(); j++) (*chanlist)[j]->flags = CZapitChannel::UPDATED; } CNeutrinoApp::getInstance()->MarkChannelsChanged(); /* if make_new_list == ON, signal to re-init services */ if(g_settings.make_new_list) CNeutrinoApp::getInstance()->MarkChannelsInit(); break; case 5: // clear channel history { CNeutrinoApp::getInstance()->channelList->getLastChannels().clear(); printf("%s:%d lastChList cleared\n", __FUNCTION__, __LINE__); ret = -2; // exit channellist } break; case 6: // settings { previous_channellist_additional = g_settings.channellist_additional; COsdSetup osd_setup; osd_setup.showContextChanlistMenu(this); hide(); ResetModules(); //FIXME check font/options changed ? calcSize(); ret = -1; } break; default: break; } } return ret; } int CChannelList::exec() { displayMode = g_settings.channellist_displaymode; descMode = g_settings.channellist_descmode; 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]->getChannelID()); 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_MENU_FOOT]->getHeight()+6; minitv_is_active = ( (g_settings.channellist_additional == SNeutrinoSettings::CHANNELLIST_ADDITIONAL_MODE_MINITV) && (CNeutrinoApp::getInstance()->getMode() != NeutrinoModes::mode_ts) ); // calculate width full_width = frameBuffer->getWindowWidth(); if (g_settings.channellist_additional) width = full_width / 3 * 2; else width = full_width; // calculate height (the infobox below mainbox is handled outside height) if (g_settings.channellist_show_infobox) info_height = 2*fheight + fdescrheight + 2*OFFSET_INNER_SMALL; else info_height = 0; height = frameBuffer->getWindowHeight(); height = height - OFFSET_INTER - info_height; // calculate x position x = getScreenStartX(full_width); if (x < DETAILSLINE_WIDTH) x = DETAILSLINE_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 + OFFSET_INTER + info_height); // calculate width/height of right info_zone and pip-box infozone_width = full_width - width; pig_width = infozone_width; if (minitv_is_active) 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) return actzap; int prev_selected = selected; selected = newpos; if (move_state == beMoving) { internalMoveChannel(prev_selected, selected); } else { unsigned int oldliststart = liststart; liststart = (selected/listmaxshow)*listmaxshow; if (oldliststart != liststart) { paintBody(); updateVfd(); } else { paintItem(prev_selected - liststart); paintItem(selected - liststart); showChannelLogo(); } if(!edit_state && (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 = CHANLIST_CANCEL; neutrino_msg_t msg; neutrino_msg_data_t data; bool actzap = 0; new_zap_mode = g_settings.channellist_new_zap_mode; calcSize(); displayMode = g_settings.channellist_displaymode; descMode = g_settings.channellist_descmode; COSDFader fader(g_settings.theme.menu_Content_alpha); fader.StartFadeIn(); CInfoClock::getInstance()->ClearDisplay(); paint(); int oldselected = selected; int zapOnExit = false; bool bShowBouquetList = false; int timeout = g_settings.timing[SNeutrinoSettings::TIMING_CHANLIST]; uint64_t timeoutEnd = CRCInput::calcTimeoutEnd(timeout); bool loop=true; bool dont_hide = false; while (loop) { g_RCInput->getMsgAbsoluteTimeout(&msg, &data, &timeoutEnd, true); if ( msg <= CRCInput::RC_MaxRC ) timeoutEnd = CRCInput::calcTimeoutEnd(timeout); bool empty = (*chanlist).empty(); 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 (move_state == beMoving) { cancelMoveChannel(); } else if (edit_state) { editMode(false); paint(); } else { res = CHANLIST_CANCEL; if(!actzap) { selected = oldselected; } else { res = CHANLIST_NO_RESTORE; selected = selected_in_new_mode; } if(fader.StartFadeOut()) { timeoutEnd = CRCInput::calcTimeoutEnd(1); msg = 0; } else loop=false; } } else if(!edit_state && !empty && msg == (neutrino_msg_t) g_settings.key_record) { //start direct recording from channellist if((g_settings.recording_type != CNeutrinoApp::RECORDING_OFF) && SameTP() /* && !IS_WEBCHAN((*chanlist)[selected]->getChannelID()) */) { printf("[neutrino channellist] start direct recording...\n"); hide(); if (!CRecordManager::getInstance()->Record((*chanlist)[selected]->getChannelID())) { paint(); } else { selected = oldselected; loop=false; } } } else if(!edit_state && !empty && msg == CRCInput::RC_stop ) { //stop recording if(CRecordManager::getInstance()->RecordingStatus((*chanlist)[selected]->getChannelID())){ int recmode = CRecordManager::getInstance()->GetRecordMode((*chanlist)[selected]->getChannelID()); bool timeshift = recmode & CRecordManager::RECMODE_TSHIFT; bool tsplay = CMoviePlayerGui::getInstance().timeshift; if (recmode && !(timeshift && tsplay)) { if (CRecordManager::getInstance()->AskToStop((*chanlist)[selected]->getChannelID())) { CRecordManager::getInstance()->Stop((*chanlist)[selected]->getChannelID()); calcSize(); paintBody(); } }else{ // stop TSHIFT: go to play mode g_RCInput->postMsg (msg, data); res = CHANLIST_CANCEL_ALL; loop = false; } } } else if (!empty && ((msg == CRCInput::RC_red) || (msg == CRCInput::RC_epg))) { if (edit_state) { if (move_state != beMoving && msg == CRCInput::RC_red) deleteChannel(); } else { hide(); /* RETURN_EXIT_ALL on FAV/SAT buttons or messages_return::cancel_all from CNeutrinoApp::getInstance()->handleMsg() */ if ( g_EventList->exec((*chanlist)[selected]->getChannelID(), (*chanlist)[selected]->getName()) == menu_return::RETURN_EXIT_ALL) { res = CHANLIST_CANCEL_ALL; loop = false; } else { paint(); timeoutEnd = CRCInput::calcTimeoutEnd(timeout); } } } else if (!empty && msg == CRCInput::RC_yellow) { if (edit_state) { beginMoveChannel(); paintItem(selected - liststart); } else { bShowBouquetList = true; loop = false; } } else if (CNeutrinoApp::getInstance()->listModeKey(msg)) { if (!edit_state) { //FIXME: what about LIST_MODE_WEB? int newmode = msg == CRCInput::RC_sat ? LIST_MODE_SAT : LIST_MODE_FAV; CNeutrinoApp::getInstance()->SetChannelMode(newmode); res = CHANLIST_CHANGE_MODE; loop = false; } } else if (!edit_state && msg == CRCInput::RC_setup) { fader.StopFade(); int ret = doChannelMenu(); if (ret > 0) { /* select next entry */ if (selected + 1 < (*chanlist).size()) selected++; } if (ret == -2) // exit channellist loop = false; else { if (ret != 0) paint(); timeoutEnd = CRCInput::calcTimeoutEnd(timeout); } } else if (!empty && msg == (neutrino_msg_t) g_settings.key_list_start) { actzap = updateSelection(0); } else if (!empty && msg == (neutrino_msg_t) g_settings.key_list_end) { actzap = updateSelection((*chanlist).size()-1); } else if (!empty && (msg == CRCInput::RC_up || (int)msg == g_settings.key_pageup || msg == CRCInput::RC_down || (int)msg == g_settings.key_pagedown)) { //descMode = false; int new_selected = UpDownKey((*chanlist), msg, listmaxshow, selected); if (new_selected >= 0) actzap = updateSelection(new_selected); } else if (!edit_state && /* !liveBouquet && */ (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 (!empty) { if (move_state == beMoving) { finishMoveChannel(); } else if (edit_state) { zapTo(selected); actzap = true; oldselected = selected; paintBody(); // refresh zapped vs selected } else if(SameTP()) { zapOnExit = true; loop=false; } } } else if (!edit_state && ( msg == CRCInput::RC_spkr ) && new_zap_mode ) { if(CNeutrinoApp::getInstance()->getMode() != NeutrinoModes::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; } paintButtonBar(SameTP()); } } else if (!empty && 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()) updateSelection(i); smsInput.resetOldKey(); } } } else if(CRCInput::isNumeric(msg)) { if (!edit_state) { //pushback key if... selected = oldselected; g_RCInput->postMsg( msg, data ); loop = false; } } else if (!empty && msg == CRCInput::RC_blue ) { if (edit_state) { // rename if (move_state != beMoving) renameChannel(); } else { displayMode++; if (displayMode == DISPLAY_MODE_MAX) displayMode = DISPLAY_MODE_NOW; g_settings.channellist_displaymode = displayMode; if (g_settings.channellist_additional) { // show event description per default in primetime mode only descMode = (displayMode == DISPLAY_MODE_PRIME) ? true : false; g_settings.channellist_descmode = descMode; } paint(); } } else if (msg == CRCInput::RC_green ) { if (edit_state) { if (move_state != beMoving) addChannel(); } else { 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; paint(); } else { if (g_settings.channellist_additional) { descMode = !descMode; g_settings.channellist_descmode = descMode; paint(); } } } } else if (!empty && edit_state && move_state != beMoving && msg == CRCInput::RC_stop ) { lockChannel(); } else if (!empty && edit_state && move_state != beMoving && msg == CRCInput::RC_forward ) { moveChannelToBouquet(); } #if ENABLE_PIP else if (!empty && ((msg == CRCInput::RC_play) || (msg == CRCInput::RC_playpause) || (msg == (neutrino_msg_t) g_settings.key_pip_close))) { int boxmode = getBoxMode(); if (boxmode > -1 && boxmode != 12) ShowMsg(LOCALE_MESSAGEBOX_ERROR, LOCALE_BOXMODE12_NOT_ACTIVATED, CMsgBox::mbrOk, CMsgBox::mbOk, NEUTRINO_ICON_ERROR); else { if(SameTP()) { if (CZapit::getInstance()->GetPipChannelID() == (*chanlist)[selected]->getChannelID()) { g_Zapit->stopPip(); calcSize(); paintBody(); } else { handleMsg(NeutrinoMessages::EVT_PROGRAMLOCKSTATUS, 0x100, true); } } } } #endif else if (!empty && ((msg == CRCInput::RC_info) || (msg == CRCInput::RC_help))) { hide(); CChannelEvent *p_event=NULL; // TODO: fix primetime if (displayMode == DISPLAY_MODE_NOW) p_event = &((*chanlist)[selected]->currentEvent); else p_event = &((*chanlist)[selected]->nextEvent); if(p_event && p_event->eventID) g_EpgData->show((*chanlist)[selected]->getChannelID(), p_event->eventID, &(p_event->startTime)); else g_EpgData->show((*chanlist)[selected]->getChannelID()); paint(); } else if (msg == NeutrinoMessages::EVT_SERVICESCHANGED || msg == NeutrinoMessages::EVT_BOUQUETSCHANGED) { g_RCInput->postMsg(msg, data); loop = false; res = CHANLIST_CANCEL_ALL; } else { if ( CNeutrinoApp::getInstance()->handleMsg( msg, data ) & messages_return::cancel_all ) { loop = false; res = CHANLIST_CANCEL_ALL; } } } paint_events(-2); // cancel paint_events thread if (move_state == beMoving) cancelMoveChannel(); if (edit_state) editMode(false); #ifdef ENABLE_GRAPHLCD cGLCD::unlockChannel(); #endif #ifdef ENABLE_LCD4LINUX CLCD4l::getInstance()->RemoveMenuFile(); #endif 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(zapOnExit) res = selected; printf("CChannelList::show *********** res %d\n", res); return(res); } void CChannelList::hide() { paint_events(-2); // cancel paint_events thread if ((g_settings.channellist_additional == SNeutrinoSettings::CHANNELLIST_ADDITIONAL_MODE_MINITV) || (previous_channellist_additional == SNeutrinoSettings::CHANNELLIST_ADDITIONAL_MODE_MINITV)) // with miniTV { if (cc_minitv){ delete cc_minitv; cc_minitv = NULL; } } if(header) header->kill(); frameBuffer->paintBackgroundBoxRel(x, y, full_width, height + OFFSET_INTER + info_height); //remove details line if (dline) dline->kill(); CInfoClock::getInstance()->enableInfoClock(!CInfoClock::getInstance()->isBlocked()); } 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 pip) { if (msg != NeutrinoMessages::EVT_PROGRAMLOCKSTATUS) // right now the only message handled here. return messages_return::unhandled; checkLockStatus(data, pip); return messages_return::handled; } bool CChannelList::checkLockStatus(neutrino_msg_data_t data, bool pip) { bool startvideo = true; //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. */ if (data >= 0x100 && (*chanlist)[selected]->last_unlocked_time + g_settings.parentallock_zaptime * 60 > time_monotonic()) goto out; if (pip && (*chanlist)[selected]->Locked() == g_settings.parentallock_defaultlocked) goto out; /* OK, let's ask for a PIN */ if (!pip) { g_RemoteControl->is_video_started = true; 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(); /* unlock only real locked bouquet, not whole satellite or all channels! */ if (bnum >= 0 && bouquetList->Bouquets[bnum]->zapitBouquet && bouquetList->Bouquets[bnum]->zapitBouquet->bLocked != g_settings.parentallock_defaultlocked) { /* 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) { #if ENABLE_PIP if (pip) { if (CNeutrinoApp::getInstance()->StartPip((*chanlist)[selected]->getChannelID())) { calcSize(); paintBody(); } } else #endif g_RemoteControl->startvideo(); return true; } return false; } bool CChannelList::adjustToChannelID(const t_channel_id channel_id) { printf("CChannelList::adjustToChannelID me %p [%s] list size %d channel_id %" PRIx64 "\n", this, getName(), (int)(*chanlist).size(), channel_id); selected_chid = channel_id; for (unsigned int i = 0; i < (*chanlist).size(); i++) { if ((*chanlist)[i]->getChannelID() == channel_id) { selected = i; tuned = i; 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]->getChannelID() == 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]->getChannelID() == channel_id) { zapTo(i, force); return true; } } return false; } bool CChannelList::showEmptyError() { if ((*chanlist).empty()) { /* No error message when the frontend is only simulated */ if (!getenv("SIMULATE_FE")) 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(edit_state || 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; if (CNeutrinoApp::getInstance()->getMode() == NeutrinoModes::mode_ts) { ShowHint(LOCALE_MESSAGEBOX_INFO, LOCALE_MOVIEPLAYER_ZAP); 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->getChannelID()); if(tuned < (*chanlist).size()) selected_chid = (*chanlist)[tuned]->getChannelID(); if(force || (selected_chid != channel->getChannelID())) { if ((g_settings.radiotext_enable) && ((CNeutrinoApp::getInstance()->getMode()) == NeutrinoModes::mode_radio) && (g_Radiotext)) { // stop radiotext PES decoding before zapping g_Radiotext->radiotext_stop(); } selected_chid = channel->getChannelID(); bool startvideo = (g_settings.parentallock_prompt == PARENTALLOCK_PROMPT_NEVER) || (channel->Locked() == g_settings.parentallock_defaultlocked); g_RemoteControl->zapTo_ChannelID(selected_chid, channel->getName(), channel->number, startvideo); CNeutrinoApp::getInstance()->adjustToChannelID(channel->getChannelID()); } if(new_zap_mode != 2 /* not active */) { /* remove recordModeActive from infobar */ if(g_settings.timeshift_auto && !CNeutrinoApp::getInstance()->recordingstatus) g_InfoViewer->handleMsg(NeutrinoMessages::EVT_RECORDMODE, 0); g_RCInput->postMsg( NeutrinoMessages::SHOW_INFOBAR, 0 ); CNeutrinoApp::getInstance()->channelList->getLastChannels().set_mode(channel->getChannelID()); } } int CChannelList::showLiveBouquet(int key) { int res = -1; if (showEmptyError()) return res; // zap history bouquet if (key == g_settings.key_zaphistory) { if (this->lastChList.size() > 1) { CChannelList liveList(g_Locale->getText(LOCALE_CHANNELLIST_HISTORY), true, true); liveList.setLiveBouquet(); 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) liveList.addChannel(channel); } } if (!liveList.isEmpty()) { this->frameBuffer->paintBackground(); res = liveList.exec(); CVFD::getInstance()->setMode(CVFD::MODE_TVRADIO); } } else ShowHint(LOCALE_MESSAGEBOX_INFO, LOCALE_CHANNELLIST_HISTORY_EMPTY); return res; } // current transponder bouquet if (key == g_settings.key_current_transponder) { bool isRecord = (!autoshift && CNeutrinoApp::getInstance()->recordingstatus); CChannelList * origList = CNeutrinoApp::getInstance()->channelList; CChannelList liveList(isRecord ? g_Locale->getText(LOCALE_CHANNELLIST_RECORDABLE_CHANNELS) : g_Locale->getText(LOCALE_CHANNELLIST_CURRENT_TP), false, true); liveList.setLiveBouquet(); if (isRecord) { for (unsigned int i = 0 ; i < (*origList->chanlist).size(); i++) { if (SameTP((*origList->chanlist)[i])) liveList.addChannel((*origList->chanlist)[i]); } } else { t_channel_id recid = (*chanlist)[selected]->getChannelID() >> 16; for (unsigned int i = 0; i < (*origList->chanlist).size(); i++) { if (((*origList->chanlist)[i]->getChannelID() >> 16) == recid) liveList.addChannel((*origList->chanlist)[i]); } } if (!liveList.isEmpty()) { liveList.adjustToChannelID(origList->getActiveChannel_ChannelID()); this->frameBuffer->paintBackground(); res = liveList.exec(); CVFD::getInstance()->setMode(CVFD::MODE_TVRADIO); } return res; } return res; } /* 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; } // numeric zap size_t maxchansize = MaxChanNr().size(); int fw = g_Font[SNeutrinoSettings::FONT_TYPE_CHANNEL_NUM_ZAP]->getMaxDigitWidth(); int fh = g_Font[SNeutrinoSettings::FONT_TYPE_CHANNEL_NUM_ZAP]->getHeight(); int sx = maxchansize*fw + 2*OFFSET_INNER_MID; int sy = fh + 2*OFFSET_INNER_SMALL; int ox = getScreenStartX(sx); int oy = getScreenStartY(sy); 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; g_InfoViewer->setSwitchMode(CInfoViewer::IV_MODE_NUMBER_ZAP); while(1) { if (lastchan != chn) { snprintf(valstr, sizeof(valstr), "%d", chn); while(strlen(valstr) < maxchansize) strcat(valstr,"-"); //"_" CVFD::getInstance()->setMode(CVFD::MODE_MENU_UTF8); CVFD::getInstance()->showMenuText(0, valstr, -1, true); PaintBoxRel(ox, oy, sx, sy, COL_INFOBAR_PLUS_0, RADIUS_LARGE, CORNER_ALL, CC_SHADOW_ON); for (int i = maxchansize-1; i >= 0; i--) { valstr[i+ 1] = 0; g_Font[SNeutrinoSettings::FONT_TYPE_CHANNEL_NUM_ZAP]->RenderString(ox + OFFSET_INNER_MID + i*fw, oy + OFFSET_INNER_SMALL + fh, fw, &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 (CNeutrinoApp::getInstance()->listModeKey(msg) || msg == CRCInput::RC_right) { // do nothing } else if (CRCInput::isNumeric(msg)) { if (pos == (int) maxchansize) { 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 (CNeutrinoApp::getInstance()->backKey(msg)) { break; } else if (msg == CRCInput::RC_red) { showEPG = true; break; } else if (CNeutrinoApp::getInstance()->handleMsg( msg, data ) & messages_return::cancel_all) { break; } } ClearBoxRel(ox, oy, sx, sy, CC_SHADOW_ON); CVFD::getInstance()->setMode(CVFD::MODE_TVRADIO); CZapitChannel* chan = getChannel(chn); if (doZap) { if (!g_InfoViewer->hasTimeout()) g_InfoViewer->killTitle(); if(chan && SameTP(chan)) { zapToChannel(chan); res = 0; } else g_InfoViewer->killTitle(); } else { g_InfoViewer->showTitle(getActiveChannel(), true); g_InfoViewer->killTitle(); if (chan && showEPG) g_EventList->exec(chan->getChannelID(), chan->getName()); } g_InfoViewer->resetSwitchMode(); return res; } CZapitChannel* CChannelList::getPrevNextChannel(int key, unsigned int &sl) { if(sl >= (*chanlist).size()) sl = (*chanlist).size()-1; CZapitChannel* channel = NULL; 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 %d total %d active bouquet %d total %d channel %p (%s)\n", (int)cactive, (int)(*chanlist).size(), bactive, bsize, 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)) { if (!bouquetList->Bouquets.empty()) channel = bouquetList->Bouquets[bactive]->channelList->getPrevNextChannel(msg, sl); else channel = CNeutrinoApp::getInstance()->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) || (CNeutrinoApp::getInstance()->backKey(msg)) || (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->resetSwitchMode(); //disable virtual_zap_mode if (doZap) { if (!g_InfoViewer->hasTimeout()) 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->getChannelID(), 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) { if (!g_settings.channellist_show_infobox) return; int ypos = y + height + OFFSET_INTER; int ypos_a = ypos + OFFSET_INNER_SMALL; frameBuffer->paintBoxRel(x, ypos, full_width, info_height, COL_MENUCONTENTDARK_PLUS_0, RADIUS_LARGE); frameBuffer->paintBoxFrame(x, ypos, full_width, info_height, 2, COL_FRAME_PLUS_0, RADIUS_LARGE); if ((*chanlist).empty()) return; //colored_events init bool colored_event_C = (g_settings.theme.colored_events_channellist == 1); bool colored_event_N = (g_settings.theme.colored_events_channellist == 2); CChannelEvent *p_event = NULL; if (displayMode == DISPLAY_MODE_NOW) p_event = &(*chanlist)[index]->currentEvent; else p_event = &(*chanlist)[index]->nextEvent; if (/* !IS_WEBCHAN((*chanlist)[index]->getChannelID()) && */ p_event && !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 + 30) / 60; snprintf(cSeit, sizeof(cSeit), "%s %02d:%02d",(displayMode == DISPLAY_MODE_NOW) ? g_Locale->getText(LOCALE_CHANNELLIST_SINCE) : g_Locale->getText(LOCALE_CHANNELLIST_START), pStartZeit->tm_hour, pStartZeit->tm_min); if (displayMode == DISPLAY_MODE_NOW) { 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); } else { snprintf(cNoch, sizeof(cNoch), "(%d %s)", p_event->duration / 60, 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 = OFFSET_INNER_MID; if (g_Font[SNeutrinoSettings::FONT_TYPE_CHANNELLIST]->getRenderWidth(text1) > (full_width - 3*OFFSET_INNER_MID - 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 - 3*OFFSET_INNER_MID - 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 + OFFSET_INNER_MID, ypos_a + 2*fheight, full_width - 3*OFFSET_INNER_MID - noch_len, text3, colored_event_C ? COL_COLORED_EVENTS_TEXT : COL_MENUCONTENTDARK_TEXT); } if (!(text2.empty())) { text2 = str_replace("\\n", " ", text2); 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 - 3*OFFSET_INNER_MID - 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, ypos_a + fdescrheight+ fheight, full_width- xstart- 3*OFFSET_INNER_MID- noch_len, text2, colored_event_C ? COL_COLORED_EVENTS_TEXT : COL_MENUCONTENTDARK_TEXT); } g_Font[SNeutrinoSettings::FONT_TYPE_CHANNELLIST]->RenderString(x+ OFFSET_INNER_MID, ypos_a + fheight, full_width - 3*OFFSET_INNER_MID - seit_len, text1, colored_event_C ? COL_COLORED_EVENTS_TEXT : COL_MENUCONTENTDARK_TEXT); g_Font[SNeutrinoSettings::FONT_TYPE_CHANNELLIST_DESCR]->RenderString(x+ full_width- OFFSET_INNER_MID- seit_len, ypos_a + 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- OFFSET_INNER_MID- noch_len, ypos_a + fdescrheight+ fheight, noch_len, cNoch, colored_event_C ? COL_COLORED_EVENTS_TEXT : COL_MENUCONTENTDARK_TEXT); } else if (IS_WEBCHAN((*chanlist)[index]->getChannelID())) { g_Font[SNeutrinoSettings::FONT_TYPE_CHANNELLIST]->RenderString(x+ OFFSET_INNER_MID, ypos_a + fheight, full_width - 3*OFFSET_INNER_MID, (*chanlist)[index]->getDesc(), colored_event_C ? COL_COLORED_EVENTS_TEXT : COL_MENUCONTENTDARK_TEXT, 0, true); } if(g_settings.channellist_foot == 0) { std::string desc = ""; if (IS_WEBCHAN((*chanlist)[index]->getChannelID())) { desc = (*chanlist)[index]->getUrl(); } else { transponder t; CServiceManager::getInstance()->GetTransponder((*chanlist)[index]->getTransponderId(), t); 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+ OFFSET_INNER_MID, ypos_a + 2*fheight +fdescrheight, full_width - 3*OFFSET_INNER_MID, desc.c_str(), COL_MENUCONTENTDARK_TEXT); } else if (displayMode == DISPLAY_MODE_NOW && g_settings.channellist_foot == 1) { // next Event CSectionsdClient::CurrentNextInfo CurrentNext; CEitManager::getInstance()->getCurrentNextServiceKey((*chanlist)[index]->getEpgID(), CurrentNext); if (!CurrentNext.next_name.empty()) { char buf[128] = {0}; char cFrom[50] = {0}; // UTF-8 time_t next_start_time = CurrentNext.next_zeit.startzeit; struct tm *pStartZeit = localtime (&next_start_time); 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+ OFFSET_INNER_MID, ypos_a + 2*fheight+ fdescrheight, full_width - 3*OFFSET_INNER_MID - from_len, buf, colored_event_N ? COL_COLORED_EVENTS_TEXT :COL_MENUCONTENTDARK_TEXT); g_Font[SNeutrinoSettings::FONT_TYPE_CHANNELLIST_DESCR]->RenderString(x+ full_width- OFFSET_INNER_MID- from_len, ypos_a + 2*fheight+ fdescrheight, from_len, cFrom, colored_event_N ? COL_COLORED_EVENTS_TEXT : COL_MENUCONTENTDARK_TEXT); } } } void CChannelList::clearItem2DetailsLine() { paintItem2DetailsLine (-1); } void CChannelList::paintItem2DetailsLine (int pos) { if (!g_settings.channellist_show_infobox) return; int xpos = x - DETAILSLINE_WIDTH; int ypos1 = y + theight + pos*fheight + (fheight/2); int ypos2 = y + height + OFFSET_INTER + (info_height/2); // paint Line if detail info (and not valid list pos) if (pos >= 0) { if (!dline){ dline = new CComponentsDetailsLine(xpos, ypos1, ypos2, fheight/2, info_height-RADIUS_LARGE*2); }else{ dline->setPos(xpos, ypos1); dline->setYPosDown(ypos2); dline->setHMarkTop(fheight/2); dline->setHMarkDown(info_height-RADIUS_LARGE*2); } dline->paint(); } } void CChannelList::paintAdditionals(int index) { if (g_settings.channellist_additional) { if (descMode) showdescription(selected); else paint_events(index); } } void CChannelList::showChannelLogo() { if ((*chanlist).empty()) return; if(g_settings.channellist_show_channellogo){ header->setChannelLogo((*chanlist)[selected]->getChannelID(), (*chanlist)[selected]->getName(), (CCHeaderTypes::cc_logo_alignment_t)g_settings.channellist_show_channellogo); header->getChannelLogoObject()->hide(); header->getChannelLogoObject()->clearSavedScreen(); header->getChannelLogoObject()->paint(); } else header->setChannelLogo(0, std::string()); } struct button_label SChannelListButtons_SMode[] = { { NEUTRINO_ICON_BUTTON_RED, LOCALE_MISCSETTINGS_EPG_HEAD}, { 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} }; int NUM_LIST_BUTTONS_SORT = sizeof(SChannelListButtons_SMode)/sizeof(SChannelListButtons_SMode[0]); const struct button_label SChannelListButtons_Edit[] = { { NEUTRINO_ICON_BUTTON_RED , LOCALE_BOUQUETEDITOR_DELETE }, { NEUTRINO_ICON_BUTTON_GREEN , LOCALE_BOUQUETEDITOR_ADD }, { NEUTRINO_ICON_BUTTON_YELLOW, LOCALE_BOUQUETEDITOR_MOVE }, { NEUTRINO_ICON_BUTTON_BLUE , LOCALE_BOUQUETEDITOR_RENAME }, { NEUTRINO_ICON_BUTTON_FORWARD , LOCALE_BOUQUETEDITOR_MOVE_TO }, { NEUTRINO_ICON_BUTTON_STOP , LOCALE_BOUQUETEDITOR_LOCK } }; int NUM_LIST_BUTTONS_EDIT = sizeof(SChannelListButtons_Edit)/sizeof(SChannelListButtons_Edit[0]); void CChannelList::paintButtonBar(bool is_current) { //printf("[neutrino channellist] %s...%d, selected %d\n", __FUNCTION__, __LINE__, selected); unsigned int smode = CNeutrinoApp::getInstance()->GetChannelMode(); int y_foot = y + (height - footerHeight); if (edit_state) { ::paintButtons(x, y_foot, full_width, NUM_LIST_BUTTONS_EDIT, SChannelListButtons_Edit, full_width, footerHeight); return; } t_channel_id channel_id = 0; if (!(*chanlist).empty()) channel_id = (*chanlist)[selected]->getChannelID(); 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 (!channel_id && i != 2 && i != 7) continue; if (i == 1) { /* check green / sort */ if(smode != LIST_MODE_FAV) { 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 { if (g_settings.channellist_additional) { if (descMode) Button[bcnt].locale = LOCALE_CHANNELLIST_ADDITIONAL_LIST; else Button[bcnt].locale = LOCALE_CHANNELLIST_ADDITIONAL_DESC; } else continue; } } if (i == 3) { //manage now/next/prime button if (displayMode == DISPLAY_MODE_NOW) Button[bcnt].locale = LOCALE_INFOVIEWER_NEXT; else if (displayMode == DISPLAY_MODE_NEXT) Button[bcnt].locale = LOCALE_CHANNELLIST_PRIMETIME; else if (displayMode == DISPLAY_MODE_PRIME) Button[bcnt].locale = LOCALE_INFOVIEWER_NOW; } if (i == 4) { //manage record button if (g_settings.recording_type == CNeutrinoApp::RECORDING_OFF) continue; if (IS_WEBCHAN(channel_id)) continue; if (displayMode == DISPLAY_MODE_NOW) { 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 #if ENABLE_PIP if (!is_current || IS_WEBCHAN(channel_id)) #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 ::paintButtons(x, y_foot, full_width, bcnt, Button, full_width, footerHeight); } void CChannelList::paintItem(int pos, const bool firstpaint) { if( (*chanlist).empty() ){ return; } int ypos = y+ theight + pos*fheight; bool is_available = true; bool paintbuttons = false; unsigned int curr = liststart + pos; if (curr < (*chanlist).size()) { if (edit_state) is_available = !((*chanlist)[curr]->flags & CZapitChannel::NOT_PRESENT); else is_available = SameTP((*chanlist)[curr]); } if (selected >= (*chanlist).size()) selected = (*chanlist).size()-1; bool i_selected = curr == selected; bool i_marked = getKey(curr) == CNeutrinoApp::getInstance()->channelList->getActiveChannelNumber() && new_zap_mode != 2 /*active*/; int i_radius = RADIUS_NONE; fb_pixel_t color; fb_pixel_t bgcolor; getItemColors(color, bgcolor, i_selected, i_marked); fb_pixel_t ecolor = color; // we need one more color for DISPLAY_MODE_NEXT fb_pixel_t dcolor = COL_CHANNELLIST_DESCRIPTION_TEXT; // description color if (i_selected || i_marked) { dcolor = ecolor; i_radius = RADIUS_LARGE; } if (i_selected) { paintItem2DetailsLine (pos); paintDetails(curr); paintAdditionals(curr); paintbuttons = true; } #if 0 if (displayMode != DISPLAY_MODE_NOW) { /* I think it's unnecessary to change colors in this case. The user should know when he has pressed the blue button. */ if (g_settings.theme.colored_events_channellist == 2 /* next */) ecolor = COL_COLORED_EVENTS_TEXT; else ecolor = COL_MENUCONTENTINACTIVE_TEXT; } #endif if (!is_available) color = COL_MENUCONTENTINACTIVE_TEXT; if (!firstpaint || i_selected || getKey(curr) == CNeutrinoApp::getInstance()->channelList->getActiveChannelNumber()) frameBuffer->paintBoxRel(x,ypos, width - SCROLLBAR_WIDTH, fheight, bgcolor, i_radius); if(curr < (*chanlist).size()) { char chan_name[255]; int chan_name_offset = 0; char chan_desc[255]; char tmp[10]; CZapitChannel* chan = (*chanlist)[curr]; int rec_mode; int pb_offset = 0; int pb_width = 0; if (g_settings.theme.progressbar_design_channellist != CProgressBar::PB_OFF) { if (edit_state || g_settings.channellist_show_numbers || this->historyMode) pb_offset = OFFSET_INNER_MID; pb_width = g_Font[SNeutrinoSettings::FONT_TYPE_CHANNELLIST_NUMBER]->getRenderWidth("00:00"); } if (edit_state || g_settings.channellist_show_numbers || pb_width) chan_name_offset = OFFSET_INNER_MID; CChannelEvent *p_event=NULL; if (displayMode == DISPLAY_MODE_NOW) p_event = &chan->currentEvent; else p_event = &chan->nextEvent; //record check rec_mode = CRecordManager::getInstance()->GetRecordMode((*chanlist)[curr]->getChannelID()); //set recording icon const char *record_icon = NULL; if (rec_mode & CRecordManager::RECMODE_REC) record_icon = NEUTRINO_ICON_MARKER_RECORD; else if (rec_mode & CRecordManager::RECMODE_TSHIFT) record_icon = NEUTRINO_ICON_MARKER_TIMESHIFT; #if ENABLE_PIP //set pip icon const char *pip_icon = NULL; if ((*chanlist)[curr]->getChannelID() == CZapit::getInstance()->GetPipChannelID()) pip_icon = NEUTRINO_ICON_MARKER_PIP; #endif //set resolution icon const char *res_icon = NULL; if (g_settings.channellist_show_res_icon) { if (chan->isHD()) res_icon = NEUTRINO_ICON_MARKER_HD; else if (chan->isUHD()) res_icon = NEUTRINO_ICON_MARKER_UHD; else res_icon = NEUTRINO_ICON_MARKER_SD; } //set webtv icon const char *webtv_icon = NULL; if (!chan->getUrl().empty()) webtv_icon = NEUTRINO_ICON_MARKER_STREAMING; //set lock icon const char *lock_icon = NULL; if (chan->bLocked) lock_icon = NEUTRINO_ICON_MARKER_LOCK; //set scramble icon const char *scramble_icon = NULL; if (chan->scrambled) scramble_icon = NEUTRINO_ICON_MARKER_SCRAMBLED; //calculate and paint right status icons int icon_w = 0; int icon_h = 0; int offset_right = OFFSET_INNER_MID; int icon_x_right = x + width - SCROLLBAR_WIDTH - offset_right; if (res_icon) { frameBuffer->getIconSize(res_icon, &icon_w, &icon_h); if (frameBuffer->paintIcon(res_icon, icon_x_right - icon_w, ypos, fheight)) { offset_right += icon_w + OFFSET_INNER_MID; icon_x_right -= icon_w + OFFSET_INNER_MID; } } if (lock_icon) { frameBuffer->getIconSize(lock_icon, &icon_w, &icon_h); if (frameBuffer->paintIcon(lock_icon, icon_x_right - icon_w, ypos, fheight)) { offset_right += icon_w + OFFSET_INNER_MID; icon_x_right -= icon_w + OFFSET_INNER_MID; } } if (scramble_icon) { frameBuffer->getIconSize(scramble_icon, &icon_w, &icon_h); if (frameBuffer->paintIcon(scramble_icon, icon_x_right - icon_w, ypos, fheight)) { offset_right += icon_w + OFFSET_INNER_MID; icon_x_right -= icon_w + OFFSET_INNER_MID; } } if (webtv_icon) { frameBuffer->getIconSize(webtv_icon, &icon_w, &icon_h); if (frameBuffer->paintIcon(webtv_icon, icon_x_right - icon_w, ypos, fheight)) { offset_right += icon_w + OFFSET_INNER_MID; icon_x_right -= icon_w + OFFSET_INNER_MID; } } #if ENABLE_PIP if (pip_icon) { frameBuffer->getIconSize(pip_icon, &icon_w, &icon_h); if (frameBuffer->paintIcon(pip_icon, icon_x_right - icon_w, ypos, fheight)) { offset_right += icon_w + OFFSET_INNER_MID; icon_x_right -= icon_w + OFFSET_INNER_MID; } } #endif if (record_icon) { frameBuffer->getIconSize(record_icon, &icon_w, &icon_h); if (frameBuffer->paintIcon(record_icon, icon_x_right - icon_w, ypos, fheight)) { offset_right += icon_w + OFFSET_INNER_MID; } } //paint buttons if (paintbuttons) paintButtonBar(is_available); snprintf(tmp, sizeof(tmp), "%d", chan->number); //channel numbers if (curr == selected && move_state == beMoving) { //frameBuffer->getIconSize(NEUTRINO_ICON_BUTTON_YELLOW, &icon_w, &icon_h); frameBuffer->paintIcon(NEUTRINO_ICON_BUTTON_YELLOW, x + OFFSET_INNER_MID /*+ numwidth - icon_w*/, ypos, fheight); } else if (this->historyMode) { // history mode only uses digits 0..9 as hotkeys if (pos >= 0 && pos <= 9) { std::string h = to_string(pos); //frameBuffer->getIconSize(h.c_str(), &icon_w, &icon_h); frameBuffer->paintIcon(h.c_str(), x + OFFSET_INNER_MID /*+ numwidth - icon_w*/, ypos, fheight); } else { //frameBuffer->getIconSize(NEUTRINO_ICON_BUTTON_DUMMY_SMALL, &icon_w, &icon_h); frameBuffer->paintIcon(NEUTRINO_ICON_BUTTON_DUMMY_SMALL, x + OFFSET_INNER_MID /*+ numwidth - icon_w*/, ypos, fheight); } } else if (edit_state || g_settings.channellist_show_numbers) { int numpos = x + OFFSET_INNER_MID + numwidth - g_Font[SNeutrinoSettings::FONT_TYPE_CHANNELLIST_NUMBER]->getRenderWidth(tmp); g_Font[SNeutrinoSettings::FONT_TYPE_CHANNELLIST_NUMBER]->RenderString(numpos, ypos + fheight, numwidth, tmp, color, fheight); } /* if (this->historyMode && g_settings.channellist_show_numbers) snprintf(chan_name, sizeof(chan_name), "%d: %s", chan->number, chan->getName().c_str()); else */ snprintf(chan_name, sizeof(chan_name), "%s", chan->getName().c_str()); int pb_height = g_Font[SNeutrinoSettings::FONT_TYPE_CHANNELLIST_NUMBER]->getDigitHeight(); CProgressBar pb(x + OFFSET_INNER_MID + numwidth + pb_offset, ypos + (fheight-pb_height)/2, pb_width, pb_height, COL_MENUCONTENT_PLUS_0); pb.setType(CProgressBar::PB_TIMESCALE); pb.setDesign(g_settings.theme.progressbar_design_channellist); pb.setCornerType(0); pb.setStatusColors(COL_PROGRESSBAR_ACTIVE_PLUS_0, COL_PROGRESSBAR_PASSIVE_PLUS_0); int pb_frame = FRAME_WIDTH_NONE; if (g_settings.theme.progressbar_design_channellist == CProgressBar::PB_MONO && !g_settings.theme.progressbar_gradient) { // add small frame to mono progressbars w/o gradient for a better visibility pb_frame = FRAME_WIDTH_MIN; } pb.setFrameThickness(pb_frame); pb.doPaintBg(false); unsigned int chan_name_len = g_Font[SNeutrinoSettings::FONT_TYPE_CHANNELLIST]->getRenderWidth(chan_name); int max_name_len = width - OFFSET_INNER_MID - numwidth - pb_offset - pb_width - OFFSET_INNER_MID - SCROLLBAR_WIDTH - offset_right; if (max_name_len < 0) max_name_len = 0; if ((int) chan_name_len > max_name_len) chan_name_len = max_name_len; if (!p_event->description.empty()) { if ((g_settings.channellist_epgtext_alignment == EPGTEXT_ALIGN_LEFT_MIDDLE) || (g_settings.channellist_epgtext_alignment == EPGTEXT_ALIGN_LEFT_BOTTOM)) snprintf(chan_desc, sizeof(chan_desc), " - %s", p_event->description.c_str()); else snprintf(chan_desc, sizeof(chan_desc), "%s", p_event->description.c_str()); unsigned int chan_desc_len = g_Font[SNeutrinoSettings::FONT_TYPE_CHANNELLIST_DESCR]->getRenderWidth(chan_desc); int max_desc_len = max_name_len - chan_name_len; if ((g_settings.channellist_epgtext_alignment == EPGTEXT_ALIGN_RIGHT_MIDDLE) || (g_settings.channellist_epgtext_alignment == EPGTEXT_ALIGN_RIGHT_BOTTOM)) max_desc_len -= OFFSET_INNER_MID; if (max_desc_len < 0) max_desc_len = 0; if ((int) chan_desc_len > max_desc_len) chan_desc_len = max_desc_len; if (g_settings.theme.progressbar_design_channellist != CProgressBar::PB_OFF) { if (displayMode == DISPLAY_MODE_NOW) { 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_width / p_event->duration; pb.setValues(runningPercent, pb_width); pb.paint(); } else { struct tm *pStartZeit = localtime(&p_event->startTime); snprintf(tmp, sizeof(tmp), "%02d:%02d", pStartZeit->tm_hour, pStartZeit->tm_min); g_Font[SNeutrinoSettings::FONT_TYPE_CHANNELLIST_NUMBER]->RenderString(x + OFFSET_INNER_MID + numwidth + pb_offset, ypos + fheight, pb_width, tmp, ecolor, fheight); } } // name g_Font[SNeutrinoSettings::FONT_TYPE_CHANNELLIST]->RenderString(x + OFFSET_INNER_MID + numwidth + pb_offset + pb_width + chan_name_offset, ypos + fheight, chan_name_len, chan_name, color); int chan_desc_x; if ((g_settings.channellist_epgtext_alignment == EPGTEXT_ALIGN_RIGHT_MIDDLE) || (g_settings.channellist_epgtext_alignment == EPGTEXT_ALIGN_RIGHT_BOTTOM)) chan_desc_x = x + width - SCROLLBAR_WIDTH - offset_right - chan_desc_len; else chan_desc_x = x + OFFSET_INNER_MID + numwidth + pb_offset + pb_width + chan_name_offset + chan_name_len; int chan_desc_y_off; if ((g_settings.channellist_epgtext_alignment == EPGTEXT_ALIGN_LEFT_MIDDLE) || (g_settings.channellist_epgtext_alignment == EPGTEXT_ALIGN_RIGHT_MIDDLE)) chan_desc_y_off = fheight/2 - g_Font[SNeutrinoSettings::FONT_TYPE_CHANNELLIST_DESCR]->getHeight()/2; else chan_desc_y_off = g_Font[SNeutrinoSettings::FONT_TYPE_CHANNELLIST]->getDescender() - g_Font[SNeutrinoSettings::FONT_TYPE_CHANNELLIST_DESCR]->getDescender(); // desc g_Font[SNeutrinoSettings::FONT_TYPE_CHANNELLIST_DESCR]->RenderString(chan_desc_x, ypos + fheight - chan_desc_y_off, chan_desc_len, chan_desc, dcolor); } else { if (g_settings.theme.progressbar_design_channellist != CProgressBar::PB_OFF) { if (displayMode == DISPLAY_MODE_NOW) { pb.setValues(0, pb_width); pb.paint(); } } // name g_Font[SNeutrinoSettings::FONT_TYPE_CHANNELLIST]->RenderString(x + OFFSET_INNER_MID + numwidth + pb_offset + pb_width + chan_name_offset, ypos + fheight, chan_name_len, chan_name, color); } if (!firstpaint && curr == selected) updateVfd(); } } void CChannelList::updateVfd() { if (selected >= (*chanlist).size()) return; CZapitChannel* chan = (*chanlist)[selected]; CChannelEvent *p_event=NULL; if (displayMode == DISPLAY_MODE_NOW) p_event = &chan->currentEvent; else p_event = &chan->nextEvent; if (!(chan->currentEvent.description.empty())) { char nameAndDescription[255]; 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 #ifdef ENABLE_GRAPHLCD if(g_settings.glcd_enable) cGLCD::lockChannel(g_Locale->getText(LOCALE_BOUQUETLIST_HEAD), chan->getName().c_str(), 0); #endif #ifdef ENABLE_LCD4LINUX if (g_settings.lcd4l_support) CLCD4l::getInstance()->CreateMenuFile(chan->getName().c_str(), g_settings.lcd4l_convert); #endif } void CChannelList::paint() { TIMER_START(); paintHead(); TIMER_STOP("CChannelList::paint() after paint head"); paintBody(); TIMER_STOP("CChannelList::paint() after paint body"); updateVfd(); TIMER_STOP("CChannelList::paint() paint total"); } void CChannelList::paintHead() { if (header == NULL){ header = new CComponentsHeader(); header->getTextObject()->enableTboxSaveScreen(g_settings.theme.menu_Head_gradient);//enable screen save for title text if color gradient is in use } header->setDimensionsAll(x, y, full_width, theight); header->setCorner(RADIUS_LARGE, CORNER_TOP); if ((g_settings.parentallock_prompt == PARENTALLOCK_PROMPT_CHANGETOLOCKED) && bouquet && bouquet->zapitBouquet && (bouquet->zapitBouquet->bLocked != g_settings.parentallock_defaultlocked)) header->setIcon(NEUTRINO_ICON_LOCK); else header->setIcon(edit_state ? NEUTRINO_ICON_EDIT : NULL); std::string header_txt; if (edit_state) { header_txt = std::string(g_Locale->getText(LOCALE_CHANNELLIST_EDIT)) + ": " + name; } else { header_txt = name; if (displayMode == DISPLAY_MODE_NEXT) header_txt += " - " + std::string(g_Locale->getText(LOCALE_INFOVIEWER_NEXT)); else if (displayMode == DISPLAY_MODE_PRIME) header_txt += " - " + std::string(g_Locale->getText(LOCALE_CHANNELLIST_PRIMETIME)); } header->setColorBody(COL_MENUHEAD_PLUS_0); header->setCaption(header_txt, DEFAULT_TITLE_ALIGN, edit_state ? COL_RED : COL_MENUHEAD_TEXT); if (timeset) { if(!edit_state){ if (header->getContextBtnObject()) if (!header->getContextBtnObject()->empty()) header->removeContextButtons(); header->enableClock(); if (header->getClockObject()) header->getClockObject()->setCorner(RADIUS_LARGE, CORNER_TOP_RIGHT); }else{ if (header->getClockObject()){ header->disableClock(); header->setContextButton(CComponentsHeader::CC_BTN_EXIT); } } } header->paint(CC_SAVE_SCREEN_NO); } CComponentsHeader* CChannelList::getHeaderObject() { if (header) return header; return NULL; } void CChannelList::ResetModules() { if (header){ delete header; header = NULL; } if(dline){ delete dline; dline = NULL; } if (cc_minitv){ delete cc_minitv; cc_minitv = NULL; } } void CChannelList::paintBody() { int icon_w = 0, icon_h = 0; if (this->historyMode) { // we assume NEUTRINO_ICON_BUTTON_DUMMY_SMALL has the same size as NEUTRINO_ICON_BUTTON_0..9 frameBuffer->getIconSize(NEUTRINO_ICON_BUTTON_DUMMY_SMALL, &icon_w, &icon_h); numwidth = icon_w; } else if (edit_state || g_settings.channellist_show_numbers) { numwidth = g_Font[SNeutrinoSettings::FONT_TYPE_CHANNELLIST_NUMBER]->getRenderWidth(MaxChanNr()); frameBuffer->getIconSize(NEUTRINO_ICON_BUTTON_YELLOW, &icon_w, &icon_h); numwidth = std::max(icon_w, (int) numwidth); frameBuffer->getIconSize(NEUTRINO_ICON_MARKER_LOCK, &icon_w, &icon_h); numwidth = std::max(icon_w, (int) numwidth); } else numwidth = 0; liststart = (selected/listmaxshow)*listmaxshow; updateEvents(this->historyMode ? 0:liststart, this->historyMode ? 0:(liststart + listmaxshow)); if (minitv_is_active) 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) { // 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); int total_pages; int current_page; getScrollBarData(&total_pages, ¤t_page, (*chanlist).size(), listmaxshow, selected); paintScrollBar(x + width - SCROLLBAR_WIDTH, y + theight, SCROLLBAR_WIDTH, height - theight - footerHeight, total_pages, current_page); showChannelLogo(); if ((*chanlist).empty()) paintButtonBar(false); } bool CChannelList::isEmpty() const { return (*chanlist).empty(); } int CChannelList::getSize() const { return (*chanlist).size(); } int CChannelList::getSelectedChannelIndex() const { return this->selected; } bool CChannelList::SameTP(t_channel_id channel_id) { bool iscurrent = true; if(CNeutrinoApp::getInstance()->recordingstatus) { if (IS_WEBCHAN(channel_id)) return true; 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]; if (IS_WEBCHAN(channel->getChannelID())) return true; // Usable CI channel while recording if(g_settings.ci_mode != 0 && channel->bUseCI && CRecordManager::getInstance()->getUseCI()) { if(g_settings.ci_mode == 1) return (CRecordManager::getInstance()->SameTransponder(channel->getChannelID())); // SameTransponder else return false; // No other CI channel } iscurrent = CFEManager::getInstance()->canTune(channel); } return iscurrent; } std::string CChannelList::MaxChanNr() { int n = 1; for (zapit_list_it_t it = (*chanlist).begin(); it != (*chanlist).end(); ++it) { n = std::max(n, (*it)->number); } return to_string(n); } 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(OFFSET_INNER_MID); } //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) { if (index == -2 && paint_events_index > -2) { pthread_mutex_lock(&paint_events_mutex); paint_events_index = index; sem_post(&paint_events_sem); pthread_join(paint_events_thr, NULL); sem_destroy(&paint_events_sem); pthread_mutex_unlock(&paint_events_mutex); } else if (paint_events_index == -2) { if (index == -2) return; // First paint_event. No need to lock. pthread_mutexattr_t attr; pthread_mutexattr_init(&attr); pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ERRORCHECK_NP); pthread_mutex_init(&paint_events_mutex, &attr); sem_init(&paint_events_sem, 0, 0); paint_events_index = index; if (!pthread_create(&paint_events_thr, NULL, paint_events, (void *) this)) sem_post(&paint_events_sem); else paint_events_index = -2; } else { pthread_mutex_lock(&paint_events_mutex); paint_events_index = index; pthread_mutex_unlock(&paint_events_mutex); sem_post(&paint_events_sem); } } void *CChannelList::paint_events(void *arg) { CChannelList *me = (CChannelList *) arg; me->paint_events(); pthread_exit(NULL); } void CChannelList::paint_events() { set_threadname(__func__); while (paint_events_index != -2) { sem_wait(&paint_events_sem); if (paint_events_index < 0) continue; while(!sem_trywait(&paint_events_sem)); int current_index = paint_events_index; CChannelEventList evtlist; readEvents((*chanlist)[current_index]->getEpgID(), evtlist); if (current_index == paint_events_index) { pthread_mutex_lock(&paint_events_mutex); if (current_index == paint_events_index) paint_events_index = -1; pthread_mutex_unlock(&paint_events_mutex); paint_events(evtlist); } } } void CChannelList::paint_events(CChannelEventList &evtlist) { ffheight = g_Font[eventFont]->getHeight(); frameBuffer->paintBoxRel(x+ width,y+ theight+pig_height, infozone_width, infozone_height,COL_MENUCONTENT_PLUS_0); #if ENABLE_ARM_ACC || ENABLE_MIPS_ACC usleep(300); // because of CFbAccelARM/MIPS::paintRect() #endif char startTime[10]; int eventStartTimeWidth = 4 * g_Font[eventFont]->getMaxDigitWidth() + g_Font[eventFont]->getRenderWidth(":") + OFFSET_INNER_SMALL; // 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; evt.duration = 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.theme.colored_events_channellist == 1 /* current */) || (!first && g_settings.theme.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+ OFFSET_INNER_MID, y+ theight+ pig_height + i*ffheight, startTimeWidth, startTime, color); } g_Font[eventFont]->RenderString(x+ width+ OFFSET_INNER_MID +startTimeWidth, y+ theight+ pig_height + i*ffheight, infozone_width - startTimeWidth - 2*OFFSET_INNER_MID, e->description, color); } else { break; } i++; } } static bool sortByDateTime (const CChannelEvent& a, const CChannelEvent& b) { return a.startTime < b.startTime; } void CChannelList::readEvents(const t_channel_id channel_id, CChannelEventList &evtlist) { 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); } void CChannelList::showdescription(int index) { std::string strEpisode = ""; // Episode title in case info1 gets stripped ffheight = g_Font[eventFont]->getHeight(); CZapitChannel* chan = (*chanlist)[index]; CChannelEvent *p_event=NULL; if (displayMode == DISPLAY_MODE_NOW) p_event = &chan->currentEvent; else p_event = &chan->nextEvent; epgData.info1.clear(); epgData.info2.clear(); epgText.clear(); CEitManager::getInstance()->getEPGid(p_event->eventID, p_event->startTime, &epgData); if (!epgData.info1.empty()) { bool bHide = false; if (false == epgData.info2.empty()) { // Look for the first . in info1, usually this is the title of an episode. std::string::size_type nPosDot = epgData.info1.find('.'); if (std::string::npos != nPosDot) { nPosDot += 2; // Skip dot and first blank if (nPosDot < epgData.info2.length() && nPosDot < epgData.info1.length()) { // Make sure we don't overrun the buffer // Check if the stuff after the dot equals the beginning of info2 if (epgData.info2.find(epgData.info1.substr(nPosDot, epgData.info1.length() - nPosDot)) == 0) { strEpisode = epgData.info1.substr(0, nPosDot) + "\n"; bHide = true; } } } // Compare strings normally if not positively found to be equal before if (false == bHide && epgData.info2.find(epgData.info1) == 0) { bHide = true; } } if (false == bHide) { processTextToArray(epgData.info1); } } //scan epg-data - sort to list if (((epgData.info2.empty())) && (!(strEpisode.empty()))) processTextToArray(g_Locale->getText(LOCALE_EPGVIEWER_NODETAILED)); // UTF-8 else processTextToArray(strEpisode + epgData.info2); // UTF-8 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 + OFFSET_INNER_MID, y+ theight+ pig_height + i*ffheight, infozone_width - 2*OFFSET_INNER_MID, 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; if(!text.empty()) text = str_replace("\\n", "\n", text); text += ' '; const char *text_= 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 ); } void CChannelList::saveChanges(bool fav) { g_bouquetManager->renumServices(); if (fav) CNeutrinoApp::getInstance()->MarkFavoritesChanged(); else CNeutrinoApp::getInstance()->MarkBouquetsChanged(); } void CChannelList::editMode(bool enable) { if (!bouquet || !bouquet->zapitBouquet) return; // reset displaymode g_settings.channellist_displaymode = DISPLAY_MODE_NOW; displayMode = DISPLAY_MODE_NOW; // reset descmode g_settings.channellist_descmode = false; descMode = false; edit_state = enable; printf("STATE: %s\n", edit_state ? "EDIT" : "SHOW"); bool tvmode = CZapit::getInstance()->getMode() & CZapitClient::MODE_TV; if (edit_state) { chanlist = tvmode ? &bouquet->zapitBouquet->tvChannels : &bouquet->zapitBouquet->radioChannels; } else { chanlist = &channels; if (channelsChanged) { channelsChanged = false; bouquet->zapitBouquet->getChannels(channels, tvmode); saveChanges(bouquet->zapitBouquet->bUser); if (!g_settings.show_empty_favorites && (*chanlist).empty()) CNeutrinoApp::getInstance()->MarkChannelsInit(); } if (selected >= chanlist->size()) selected = chanlist->empty() ? 0 : (chanlist->size() - 1); } adjustToChannelID(selected_chid); } void CChannelList::beginMoveChannel() { move_state = beMoving; origPosition = selected; newPosition = selected; } void CChannelList::finishMoveChannel() { move_state = beDefault; paintBody(); } void CChannelList::cancelMoveChannel() { move_state = beDefault; internalMoveChannel(newPosition, origPosition); channelsChanged = false; } void CChannelList::internalMoveChannel( unsigned int fromPosition, unsigned int toPosition) { if ( (int) toPosition == -1 ) return; if ( toPosition == chanlist->size()) return; if (!bouquet || !bouquet->zapitBouquet) return; bool tvmode = CZapit::getInstance()->getMode() & CZapitClient::MODE_TV; bouquet->zapitBouquet->moveService(fromPosition, toPosition, tvmode ? 1 : 2); channelsChanged = true; chanlist = tvmode ? &bouquet->zapitBouquet->tvChannels : &bouquet->zapitBouquet->radioChannels; selected = toPosition; newPosition = toPosition; paintBody(); } void CChannelList::deleteChannel(bool ask) { if (selected >= chanlist->size()) return; if (!bouquet || !bouquet->zapitBouquet) return; if (ask && ShowMsg(LOCALE_FILEBROWSER_DELETE, (*chanlist)[selected]->getName(), CMsgBox::mbrNo, CMsgBox::mbYes|CMsgBox::mbNo)!=CMsgBox::mbrYes) return; bouquet->zapitBouquet->removeService((*chanlist)[selected]->getChannelID()); bool tvmode = CZapit::getInstance()->getMode() & CZapitClient::MODE_TV; chanlist = tvmode ? &bouquet->zapitBouquet->tvChannels : &bouquet->zapitBouquet->radioChannels; if (selected >= chanlist->size()) selected = chanlist->empty() ? 0 : (chanlist->size() - 1); channelsChanged = true; paintBody(); updateVfd(); } void CChannelList::addChannel() { if (!bouquet || !bouquet->zapitBouquet) return; hide(); bool tvmode = CZapit::getInstance()->getMode() & CZapitClient::MODE_TV; std::string caption = name + ": " + g_Locale->getText(LOCALE_BOUQUETEDITOR_ADD); CBEChannelSelectWidget* channelSelectWidget = new CBEChannelSelectWidget(caption, bouquet->zapitBouquet, tvmode ? CZapitClient::MODE_TV : CZapitClient::MODE_RADIO); channelSelectWidget->exec(NULL, ""); if (channelSelectWidget->hasChanged()) { channelsChanged = true; chanlist = tvmode ? &bouquet->zapitBouquet->tvChannels : &bouquet->zapitBouquet->radioChannels; if (selected >= chanlist->size()) selected = chanlist->empty() ? 0 : (chanlist->size() - 1); } delete channelSelectWidget; paint(); } void CChannelList::renameChannel() { std::string newName= inputName((*chanlist)[selected]->getName().c_str(), LOCALE_BOUQUETEDITOR_NEWBOUQUETNAME); if (newName != (*chanlist)[selected]->getName()) { if(newName.empty()) (*chanlist)[selected]->setUserName(""); else (*chanlist)[selected]->setUserName(newName); channelsChanged = true; } paint(); } void CChannelList::lockChannel() { (*chanlist)[selected]->bLocked = !(*chanlist)[selected]->bLocked; CNeutrinoApp::getInstance()->MarkFavoritesChanged(); if (selected + 1 < (*chanlist).size()) g_RCInput->postMsg((neutrino_msg_t) CRCInput::RC_down, 0); else paintItem(selected - liststart); } bool CChannelList::addChannelToBouquet() { bool fav_found = true; signed int bouquet_id = AllFavBouquetList->exec(false); hide(); if(bouquet_id < 0) return false; t_channel_id channel_id = (*chanlist)[selected]->getChannelID(); bool tvmode = CZapit::getInstance()->getMode() & CZapitClient::MODE_TV; CBouquetList *blist = tvmode ? TVfavList : RADIOfavList; if (AllFavBouquetList->Bouquets[bouquet_id]->zapitBouquet) { CZapitBouquet *zapitBouquet = AllFavBouquetList->Bouquets[bouquet_id]->zapitBouquet; CZapitChannel *ch = zapitBouquet->getChannelByChannelID(channel_id); if (ch == NULL) { fav_found = false; zapitBouquet->addService((*chanlist)[selected]); for (unsigned n = 0; n < blist->Bouquets.size(); n++) { if (blist->Bouquets[n]->zapitBouquet == zapitBouquet) { zapitBouquet->getChannels(blist->Bouquets[n]->channelList->channels, tvmode); saveChanges(); fav_found = true; break; } } } else { ShowMsg(LOCALE_EXTRA_ADD_TO_BOUQUET, LOCALE_EXTRA_CHALREADYINBQ, CMsgBox::mbrBack, CMsgBox::mbBack, NEUTRINO_ICON_INFO); return false; } } if (!fav_found) { CNeutrinoApp::getInstance()->MarkFavoritesChanged(); CNeutrinoApp::getInstance()->MarkChannelsInit(); } return true; } void CChannelList::moveChannelToBouquet() { if (addChannelToBouquet()) deleteChannel(false); else paintBody(); paintHead(); } std::string CChannelList::inputName(const char * const defaultName, const neutrino_locale_t caption) { std::string Name = defaultName; CKeyboardInput * nameInput = new CKeyboardInput(caption, &Name); nameInput->exec(NULL, ""); delete nameInput; return std::string(Name); }