diff options
author | Tobias Grimm <tobias@e-tobi.loc> | 2008-12-02 21:00:33 +0100 |
---|---|---|
committer | Tobias Grimm <tobias@e-tobi.loc> | 2008-12-02 21:00:33 +0100 |
commit | b451fdb5a36c0f749d63d53165cdf4e84a8f476a (patch) | |
tree | aa3b6548ea52ef133028098c8fbaebbe47ed8a5d /menu.c | |
download | vdr-plugin-osdteletext-b451fdb5a36c0f749d63d53165cdf4e84a8f476a.tar.gz vdr-plugin-osdteletext-b451fdb5a36c0f749d63d53165cdf4e84a8f476a.tar.bz2 |
Initial commit of version 0.5.1v0.5.1release/v0.5.1
Diffstat (limited to 'menu.c')
-rw-r--r-- | menu.c | 681 |
1 files changed, 681 insertions, 0 deletions
@@ -0,0 +1,681 @@ +/*************************************************************************** + * Copyright (c) 2003,2004 by Marcel Wiesweg * + * * + * 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. * + * * + ***************************************************************************/ + +#include <map> +#include <time.h> + +#include <vdr/interface.h> +#include <vdr/i18n.h> +#include <vdr/config.h> + +#include "menu.h" +#include "display.h" +#include "setup.h" +#include "txtrecv.h" + + +#define TXTROOT "/vtx" + +#define GET_HUNDREDS(x) ( ( (x) - ((x)%256) ) /256 ) +#define GET_TENS(x) ( (( (x) - ((x)%16) )%256 ) /16 ) +#define GET_ONES(x) ( (x)%16 ) + +#define GET_HUNDREDS_DECIMAL(x) ( ( (x) - ((x)%100) ) /100 ) +#define GET_TENS_DECIMAL(x) ( (( (x) - ((x)%10) )%100 ) /10 ) +#define GET_ONES_DECIMAL(x) ( (x)%10 ) + +#define PSEUDO_HEX_TO_DECIMAL(x) ( (GET_HUNDREDS_DECIMAL(x))*256 + (GET_TENS_DECIMAL(x))*16 + (GET_ONES_DECIMAL(x)) ) + +using namespace std; + +int Stretch = true; +typedef map<int,int> IntMap; +IntMap channelPageMap; + +//static variables +int TeletextBrowser::currentPage=0x100; //Believe it or not, the teletext numbers are somehow hexadecimal +int TeletextBrowser::currentSubPage=0; +tChannelID TeletextBrowser::channel; +int TeletextBrowser::currentChannelNumber=0; +TeletextBrowser* TeletextBrowser::self=0; + + +TeletextBrowser::TeletextBrowser(cTxtStatus *txtSt) { + cursorPos=0; + pageFound=true; + selectingChannel=false; + needClearMessage=false; + selectingChannelNumber=-1; + self=this; + txtStatus=txtSt; + //if (txtStatus) + // txtStatus->ForceReceiving(true); + suspendedReceiving=false; + previousPage=currentPage; + previousSubPage=currentSubPage; + pageBeforeNumberInput=currentPage; + lastActivity=time(NULL); + inactivityTimeout=-1; +} + + +TeletextBrowser::~TeletextBrowser() { + Display::Delete(); + + self=0; + /*if (txtStatus) { + if (suspendedReceiving) + txtStatus->ForceSuspending(false); + txtStatus->ForceReceiving(false); + }*/ +} + +void TeletextBrowser::Show(void) { + Display::SetMode(Display::mode); + ShowPage(); +} + +bool TeletextBrowser::CheckIsValidChannel(int number) { + return (Channels.GetByNumber(number) != 0); +} + +void TeletextBrowser::ChannelSwitched(int ChannelNumber) { + cChannel *chan=Channels.GetByNumber(ChannelNumber); + + if (!chan) + return; + + tChannelID chid=chan->GetChannelID(); + if (chid==channel || chid==tChannelID::InvalidID) + return; + + channel=chid; + + //store page number of current channel + IntMap::iterator it; + channelPageMap[currentChannelNumber] = currentPage; + currentChannelNumber=ChannelNumber; + + currentPage=0x100; + currentSubPage=0; + + //see if last page number on this channel was stored + it=channelPageMap.find(ChannelNumber); + if (it != channelPageMap.end()) { //found + currentPage=(*it).second; + } + + //on the one hand this must work in background mode, when the plugin is not active. + //on the other hand, if active, the page should be shown. + //so this self-Pointer. + if (self) { + self->ShowPage(); + } +} + + +eOSState TeletextBrowser::ProcessKey(eKeys Key) { + if (Key != kNone) + lastActivity = time(NULL); + + switch (Key) { + case k1: SetNumber(1);break; + case k2: SetNumber(2);break; + case k3: SetNumber(3);break; + case k4: SetNumber(4);break; + case k5: SetNumber(5);break; + case k6: SetNumber(6);break; + case k7: SetNumber(7);break; + case k8: SetNumber(8);break; + case k9: SetNumber(9);break; + case k0: + //same behavior for 0 as VDR does it with channels + if ((cursorPos==0) && (!selectingChannel)) { + //swap variables + int tempPage=currentPage; + int tempSubPage=currentSubPage; + currentPage=previousPage; + currentSubPage=previousSubPage; + previousPage=tempPage; + previousSubPage=tempSubPage; + ShowPage(); + } else + SetNumber(0); + break; + case kOk: + if (selectingChannel) { + selectingChannel=false; + Display::ClearMessage(); + if (selectingChannelNumber>0) { + if (CheckIsValidChannel(selectingChannelNumber)) + ChannelSwitched(selectingChannelNumber); + else { + needClearMessage=true; + //string tranlated in VDR's i18n.c + Display::DrawMessage(tr("*** Invalid Channel ***")); + } + } else { + ShowPage(); + } + } + break; + case kBack: return osEnd; + case kNone: //approx. every second + //checking if page changed + if ( pageFound && ttSetup.autoUpdatePage && cursorPos==0 && !selectingChannel && (PageCheckSum() != checkSum) ) { + ShowPage(); + //check if page was previously not found and is available now + } else if (!pageFound && CheckFirstSubPage(0)) { + ShowPage(); + } else { + if (needClearMessage) { + needClearMessage=false; + Display::ClearMessage(); + } + //updating clock + UpdateClock(); + } + //check for activity timeout + if (ttSetup.inactivityTimeout && (time(NULL) - lastActivity > ttSetup.inactivityTimeout*60)) + return osEnd; + break; + case kUp: + if (selectingChannel) { + selectingChannel=false; + Display::ClearMessage(); + } + + if (cursorPos != 0) { + //fully revert cursor + SetNumber(-3); + } + ChangePageRelative(DirectionForward); + Display::ShowUpperHalf(); + ShowPage(); + break; + case kDown: + if (selectingChannel) { + selectingChannel=false; + Display::ClearMessage(); + } + if (cursorPos != 0) { + //fully reset + SetNumber(-3); + } + ChangePageRelative(DirectionBackward); + Display::ShowUpperHalf(); + ShowPage(); + break; + case kRight: + if (selectingChannel) { + selectingChannel=false; + Display::ClearMessage(); + } + if (cursorPos != 0) { + //fully reset + SetNumber(-3); + } + ChangeSubPageRelative(DirectionForward); + Display::ShowUpperHalf(); + ShowPage(); + break; + case kLeft: + if (selectingChannel) { + selectingChannel=false; + Display::ClearMessage(); + } + if (cursorPos != 0) { + //revert cursor + SetNumber(-1); + break; + } + ChangeSubPageRelative(DirectionBackward); + Display::ShowUpperHalf(); + ShowPage(); + break; + + + case kRed: + case kGreen: + case kBlue: + case kYellow: + //case kUser1:case kUser2:case kUser3:case kUser4:case kUser5: + //case kUser6:case kUser7:case kUser8:case kUser9: + case kPlay:case kPause:case kStop: case kRecord:case kFastFwd:case kFastRew: + if (cursorPos != 0) { + //fully reset + SetNumber(-3); + } + ExecuteAction(TranslateKey(Key)); + break; + default: break; + } + return osContinue; +} + +void TeletextBrowser::ExecuteAction(eTeletextAction e) { + switch (e) { + case Zoom: + if (selectingChannel) { + selectingChannel=false; + Display::ClearMessage(); + } + + switch (Display::GetZoom()) { + case cDisplay::Zoom_Off: + Display::SetZoom(cDisplay::Zoom_Upper); + break; + case cDisplay::Zoom_Upper: + Display::SetZoom(cDisplay::Zoom_Lower); + break; + case cDisplay::Zoom_Lower: + Display::SetZoom(cDisplay::Zoom_Off); + break; + } + + break; + case HalfPage: + if (selectingChannel) { + selectingChannel=false; + Display::ClearMessage(); + } + + switch (Display::mode) { + case Display::HalfUpper: + Display::SetMode(Display::HalfLower); + break; + case Display::HalfLower: + Display::SetMode(Display::Full); + break; + case Display::Full: + Display::SetMode(Display::HalfUpper); + break; + } + ShowPage(); + break; + case SwitchChannel: + selectingChannelNumber=0; + selectingChannel=true; + ShowAskForChannel(); + break; + /*case SuspendReceiving: + if (!txtStatus) + break; + //if (suspendedReceiving) + // txtStatus->ForceSuspending(false); + //else + // txtStatus->ForceSuspending(true); + //suspendedReceiving=(!suspendedReceiving); + break;*/ + case DarkScreen: + if (Display::GetBackgroundColor() == clrBlack) + Display::SetBackgroundColor((tColor)ttSetup.configuredClrBackground); + else + Display::SetBackgroundColor(clrBlack); + break; + default: + //In osdteletext.c, numbers are thought to be decimal, the setup page + //entries will display them in this way. It is a lot easier to do the + //conversion to hexadecimal here. + //This means, we convert the number to what it would be if the string + //had been parsed with hexadecimal base. + int pageNr=PSEUDO_HEX_TO_DECIMAL((int)e); + if (0x100<=pageNr<=0x899) { + if (selectingChannel) { + selectingChannel=false; + Display::ClearMessage(); + } + SetPreviousPage(currentPage, currentSubPage, pageNr); + currentPage=pageNr; + cursorPos=0; + currentSubPage=0; + + Display::ShowUpperHalf(); + ShowPage(); + } + break; + } +} + +eTeletextAction TeletextBrowser::TranslateKey(eKeys Key) { + switch(Key) { + case kRed: return (eTeletextAction)ttSetup.mapKeyToAction[ActionKeyRed]; + case kGreen: return (eTeletextAction)ttSetup.mapKeyToAction[ActionKeyGreen]; + case kYellow: return (eTeletextAction)ttSetup.mapKeyToAction[ActionKeyYellow]; + case kBlue: return (eTeletextAction)ttSetup.mapKeyToAction[ActionKeyBlue]; + case kPlay: return (eTeletextAction)ttSetup.mapKeyToAction[ActionKeyPlay]; + //case kPause: return (eTeletextAction)ttSetup.mapKeyToAction[ActionKeyPause]; + case kStop: return (eTeletextAction)ttSetup.mapKeyToAction[ActionKeyStop]; + //case kRecord: return (eTeletextAction)ttSetup.mapKeyToAction[ActionKeyRecord]; + case kFastFwd: return (eTeletextAction)ttSetup.mapKeyToAction[ActionKeyFastFwd]; + case kFastRew: return (eTeletextAction)ttSetup.mapKeyToAction[ActionKeyFastRew]; + default: return (eTeletextAction)100; //just to keep gcc quiet + } +} + + +void TeletextBrowser::SetNumber(int i) { + //cursorPos means insertion after, 0<=cursorPos<=2 + if (selectingChannel) { + selectingChannelNumber = selectingChannelNumber*10+i; + ShowAskForChannel(); + return; + } + + //i<0 means revert cursor position + if (i<0) { + for (;i<0;i++) { + switch (cursorPos) { + case 0: + return; + case 1: + currentPage = currentPage-256*GET_HUNDREDS(currentPage)+256*GET_HUNDREDS(pageBeforeNumberInput); + break; + case 2: + currentPage = currentPage-16*GET_TENS(currentPage)+16*GET_TENS(pageBeforeNumberInput); + break; + } + cursorPos--; + } + ShowPageNumber(); + return; + } + + + static int tempPage; + switch (cursorPos) { + case 0: + if (i<1) i=1; + //accept no 9 when cursorPos==0 + if (i>8) i=8; + tempPage= currentPage; + pageBeforeNumberInput = currentPage; + currentPage = currentPage-256*GET_HUNDREDS(currentPage)+256*i; + break; + case 1: + if (i<0) i=0; + if (i>9) i=9; + currentPage = currentPage-16*GET_TENS(currentPage)+16*i; + break; + case 2: + if (i<0) i=0; + if (i>9) i=9; + currentPage = currentPage-GET_ONES(currentPage)+i; + pageBeforeNumberInput = currentPage; + SetPreviousPage(tempPage, currentSubPage, currentPage); + break; + } + pageFound=true; //so that "page ... not found" is not displayed, but e.g. 1**-00 + if (++cursorPos>2) { + cursorPos=0; + CheckFirstSubPage(0); + Display::ShowUpperHalf(); + ShowPage(); + } else { + ShowPageNumber(); + } +} + +//returns whether x, when written in hexadecimal form, +//will only contain the digits 0...9 and not A...F +//in the first three digits. +static inline bool onlyDecimalDigits(int x) { + return (( x & 0xE) < 0xA) && + (( (x>>4) & 0xE) < 0xA) && + (( (x>>8) & 0xE) < 0xA); +} + +//after 199 comes 1A0, but if these pages exist, they contain no useful data, so filter them out +int TeletextBrowser::nextValidPageNumber(int start, Direction direction) { + do { + switch (direction) { + case DirectionForward: + start++; + break; + case DirectionBackward: + start--; + break; + } + } while (!onlyDecimalDigits(start)); + return start; +} + +void TeletextBrowser::ChangePageRelative(Direction direction) +{ + int oldpage = currentPage; + int oldSubPage = currentSubPage; + + do { + /*if (back) + currentPage--; + else + currentPage++;*/ + currentPage=nextValidPageNumber(currentPage, direction); + if (currentPage>0x899) currentPage=0x100; + if (currentPage<0x100) currentPage=0x899; + // sub page is always 0 if you change the page + if (CheckFirstSubPage(0)) { + SetPreviousPage(oldpage, oldSubPage, currentPage); + return; + } + } while (currentPage != oldpage); + + return; +} + +void TeletextBrowser::ChangeSubPageRelative(Direction direction) +{ + int oldsubpage = currentSubPage; + + do { + /*if (back) + currentSubPage--; + else + currentSubPage++;*/ + currentSubPage=nextValidPageNumber(currentSubPage, direction); + if (currentSubPage > 0x99) currentSubPage=0; + if (currentSubPage < 0) currentSubPage=0x99; + + if (CheckPage()) + return; + } while (currentSubPage != oldsubpage); + + return; +} + +bool TeletextBrowser::CheckFirstSubPage(int startWith) { + int oldsubpage = currentSubPage; + + do { + if (CheckPage()) + return true; + //currentSubPage++; + currentSubPage=nextValidPageNumber(currentSubPage, DirectionForward); + + if (currentSubPage > 0x99) currentSubPage=0; + if (currentSubPage < 0) currentSubPage=0x99; + + } while (currentSubPage != oldsubpage); + + return false; +} + +bool TeletextBrowser::CheckPage() +{ + StorageHandle fd; + + Storage *s=Storage::instance(); + if (!(fd=s->openForReading(PageID(channel, currentPage, currentSubPage), false)) ) + return false; + + s->close(fd); + return true; +} + +//sets the previousPage variables if and only if new page is different from old page +void TeletextBrowser::SetPreviousPage(int oldPage, int oldSubPage, int newPage) { + if (oldPage != newPage) { + previousPage=oldPage; + previousSubPage=oldSubPage; + } +} + + + + +void TeletextBrowser::ShowPage() { + if ((pageFound=DecodePage())) { + if (ttSetup.autoUpdatePage) + checkSum=PageCheckSum(); + } +} + +void TeletextBrowser::ShowPageNumber() { + char str[8]; + sprintf(str, "%3x-%02x", currentPage, currentSubPage); + if (cursorPos>0) { + str[2]='*'; + if (cursorPos==1) + str[1]='*'; + } + Display::DrawPageId(str); +} + +void TeletextBrowser::ShowAskForChannel() { + if (selectingChannel) { + char *str; + if (selectingChannelNumber>0) + asprintf(&str,"%s%d", tr("Channel (press OK): "), selectingChannelNumber); + else + asprintf(&str,"%s", tr("Channel (press OK): ") ); + Display::DrawMessage(str); + free(str); + } +} + +//this is taken and adapted from the teletext plugin since it uses its data +bool TeletextBrowser::DecodePage() { + // Load the page and decodes it + #ifdef timingdebug + cTime t; + t.Start(); + #endif + + unsigned char cache[40*24+12]; + StorageHandle fd; + // Take a look if there is a xxx-00 page + Storage *s=Storage::instance(); + if (currentSubPage==0) { + if ( !(fd=s->openForReading(PageID(channel, currentPage,currentSubPage), false)) ) { + // There is no subpage 0 so look if there is subpage 1 + currentSubPage++; + // Generate file string + } else { + // yes file exists + s->close(fd); + } + } + + if ( (fd=s->openForReading(PageID(channel, currentPage, currentSubPage), true)) ) + { + s->read(cache,sizeof cache,fd); // Read full page data + s->close(fd); + + Display::HoldFlush(); + Display::ClearMessage(); + Display::RenderTeletextCode(cache); + ShowPageNumber(); + UpdateClock(); + Display::ReleaseFlush(); + + #ifdef timingdebug + t.Stop("Full Page Update"); + #endif + } else { + // page doesn't exist + currentSubPage--; + + Display::HoldFlush(); + ShowPageNumber(); + char str[80]; + snprintf(str,80, "%s %3x-%02x %s",tr("Page"),currentPage, currentSubPage,tr("not found")); + Display::DrawMessage(str); + Display::ReleaseFlush(); + + return false; + } + return true; +} + + + +int TeletextBrowser::PageCheckSum() { + int retSum=0; + StorageHandle fd; + + CheckFirstSubPage(currentSubPage); + + Storage *s=Storage::instance(); + if ((fd=s->openForReading(PageID(channel, currentPage, currentSubPage), false)) ) { + uchar cache[960]; + s->read(cache, 12, fd); //skip + s->read(cache, sizeof(cache), fd); + s->close(fd); + memset(cache+12, 0, 8); //it seems that there the clock is transmitted, ignore changes + for (uint i=0;i<sizeof(cache); i++) + retSum+=cache[i]; + } + return retSum; +} + +void TeletextBrowser::UpdateClock() { + if ( ttSetup.showClock ) + Display::DrawClock(); +} + + +ChannelStatus::ChannelStatus() +{ +} + + +void ChannelStatus::ChannelSwitch(const cDevice *Device, int ChannelNumber) { + if (Device->IsPrimaryDevice() && ChannelNumber>0) + TeletextBrowser::ChannelSwitched(ChannelNumber); +} + +TeletextSetup ttSetup; + +TeletextSetup::TeletextSetup() { + //Set default values for setup options + + configuredClrBackground=clrGray50; + + //init key bindings + for (int i=0;i<10;i++) + mapKeyToAction[0]=(eTeletextAction)0; + mapKeyToAction[3]=Zoom; + mapKeyToAction[2]=HalfPage; + mapKeyToAction[0]=SwitchChannel; + + showClock=true; + suspendReceiving=false; + autoUpdatePage=true; + //OSDHeight+width default values given in Start() + OSDHAlign=50; + OSDVAlign=50; + + //use the value set for VDR's min user inactivity. + //Initially this value could be changed via the plugin's setup, but I removed that + //because there is no advantage, but a possible problem when VDR's value is change + //after the plugin has stored its own value. + inactivityTimeout=Setup.MinUserInactivity; +} + |