Logo Search packages:      
Sourcecode: vdr-plugin-osdteletext version File versions

menu.c

 /***************************************************************************
 *                                                                         *
 *   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 "menu.h"
#include "txtbitmap.h"
#include "display.h"
#include "setup.h"
#include "txtrecv.h"


#define TXTROOT "/vtx"

#define GET_HUNDREDS(x) ( ( (x) - ((x)%100) ) /100 )
#define GET_TENS(x)  ( (( (x) - ((x)%10) )%100 ) /10 )
#define GET_ONES(x)   ( (x)%10 )

using namespace std;
   
int Stretch = true;
typedef map<int,int> IntMap;
IntMap channelPageMap;

//static variables
int TeletextBrowser::currentPage=100;
int TeletextBrowser::currentSubPage=0;
int TeletextBrowser::channelNumber=-1;
DisplayMode TeletextBrowser::mode=Full;
TeletextBrowser* TeletextBrowser::self=0;


TeletextBrowser::TeletextBrowser(cTxtStatus *txtSt) {
   cursorPos=0;
   txtbitmap=0;
   pageFound=true;
   selectingChannel=false;
   selectingChannelNumber=-1;
   self=this;
   txtStatus=txtSt;
   if (txtStatus)
      txtStatus->ForceReceiving(true);
   suspendedReceiving=false;  
   previousPage=currentPage;
   previousSubPage=currentSubPage;
}


TeletextBrowser::~TeletextBrowser() {
   if (txtbitmap)
      delete txtbitmap;
   self=0;
   DisplayClose();
   if (txtStatus) {
      if (suspendedReceiving)
         txtStatus->ForceSuspending(false);
      txtStatus->ForceReceiving(false);
   }
}

void TeletextBrowser::Show(void) {
   DisplaySetBackground((eDvbColor)ttSetup.configuredClrBackground);
   DisplayOpen(2, mode);
   //channelNumber=cDevice::CurrentChannel();
   ShowPage();
   ShowPageNumber();
  // DisplayDrawRect(15,10,490,506, BLU);
  // DisplayUpdate();
}

void TeletextBrowser::ChannelSwitched(int ChannelNumber) {
   //store page number of current channel
   IntMap::iterator it;
   channelPageMap.insert(IntMap::value_type(channelNumber, currentPage));
   
   currentPage=100;
   currentSubPage=0;
      
   //see if last page number on this channel was stored
   it=channelPageMap.find(ChannelNumber);
   if (it != channelPageMap.end()) { //found
      currentPage=(*it).second;
   }
   
   channelNumber=ChannelNumber;
   //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();
      self->ShowPageNumber();
   }
}


eOSState TeletextBrowser::ProcessKey(eKeys Key) {  
   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();
            ShowPageNumber();
         } else
            SetNumber(0);
         break;
      case kOk: 
         if (selectingChannel) {
            selectingChannel=false;
            if (selectingChannelNumber>0) {
               ChannelSwitched(selectingChannelNumber);
            } else {
               ShowPage();
               ShowPageNumber(); 
            }
         }
         break;        
      case kBack: return osEnd; 
      case kNone: //approx. every second
         //checking if page changed
         if ( ttSetup.autoUpdatePage && cursorPos==0 && (PageCheckSum() != checkSum) ) {
            ShowPage();
            ShowPageNumber(); 
         }
         //updating clock
         if ( mode != ZoomLower && mode != HalfLower)
            UpdateClock();
         break;
      case kUp:
         if (selectingChannel)
             selectingChannel=false;
         ChangePageRelative();
         if (mode==ZoomLower)
            mode=ZoomUpper;
         if (mode==HalfLower)
            mode=HalfUpper;
         ShowPage();
         ShowPageNumber(); 
         UpdateClock();
         break;        
      case kDown:
         if (selectingChannel)
             selectingChannel=false;
         ChangePageRelative(true);
         if (mode==ZoomLower)
            mode=ZoomUpper;
         if (mode==HalfLower)
            mode=HalfUpper;
         ShowPage();
         ShowPageNumber();  
         UpdateClock();
         break;       
      case kRight:
         if (selectingChannel)
             selectingChannel=false;
         ChangeSubPageRelative();
         if (mode==ZoomLower)
            mode=ZoomUpper;
         if (mode==HalfLower)
            mode=HalfUpper;
         ShowPage();
         ShowPageNumber();  
         UpdateClock();
         break;       
      case kLeft:
         if (selectingChannel)
             selectingChannel=false;
         ChangeSubPageRelative(true);
         if (mode==ZoomLower)
            mode=ZoomUpper;
         if (mode==HalfLower)
            mode=HalfUpper;
         ShowPage();
         ShowPageNumber();   
         UpdateClock();
         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:
         ExecuteAction(TranslateKey(Key));
         break;             
      default: break;
   }
   return osContinue;
}

void TeletextBrowser::ExecuteAction(eTeletextAction e) {
         switch (e) {
            case Zoom:
               if (selectingChannel)
                  selectingChannel=false;
               if (mode==ZoomUpper)
                  mode=ZoomLower;
               else if (mode==ZoomLower)
                  mode=Full;
               else
                  mode=ZoomUpper;
               DisplayCheckMode(2, mode);
               ShowPage();
               if (mode!=ZoomLower) {
                  ShowPageNumber();
                  UpdateClock();                
               }
               break;
            case HalfPage:
               if (selectingChannel)
                  selectingChannel=false;
               if (mode==HalfUpper)
                  mode=HalfLower;
               else if (mode==HalfLower)
                  mode=Full;
               else
                  mode=HalfUpper;
               DisplayCheckMode(2, mode);
               ShowPage();
               if (mode!=HalfLower) {
                  ShowPageNumber();
                  UpdateClock();
               }
               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:
               DisplayClose(); //necessary to change color
               if (DisplayGetBackground() == clrBlack)
                  DisplaySetBackground((eDvbColor)ttSetup.configuredClrBackground);
               else
                  DisplaySetBackground(clrBlack);
               DisplayOpen(2, mode);
               ShowPage();
               if (mode!=ZoomLower) {
                  ShowPageNumber();
                  UpdateClock();                
               }
               break;
            default:
               int pageNr=(int)e;
               if (100<=pageNr<=899) {
                  if (selectingChannel)
                     selectingChannel=false;
                  SetPreviousPage(currentPage, currentSubPage, pageNr);
                  currentPage=pageNr;
                  cursorPos=0;
                  currentSubPage=0;
                  if (mode==ZoomLower)
                     mode=ZoomUpper;
                  if (mode==HalfLower)
                     mode=HalfUpper;
                  ShowPage();
                  ShowPageNumber();
                  UpdateClock();
               }
               break;
         }
}

eTeletextAction TeletextBrowser::TranslateKey(eKeys Key) {
   switch(Key) {
      case kRed:     return (eTeletextAction)ttSetup.mapKeyToAction[0];
      case kGreen:   return (eTeletextAction)ttSetup.mapKeyToAction[1];
      case kYellow:  return (eTeletextAction)ttSetup.mapKeyToAction[2];
      case kBlue:    return (eTeletextAction)ttSetup.mapKeyToAction[3];
      case kPlay:   return (eTeletextAction)ttSetup.mapKeyToAction[4];
      case kPause:   return (eTeletextAction)ttSetup.mapKeyToAction[5];
      case kStop:   return (eTeletextAction)ttSetup.mapKeyToAction[6];
      case kRecord:   return (eTeletextAction)ttSetup.mapKeyToAction[7];
      case kFastFwd:   return (eTeletextAction)ttSetup.mapKeyToAction[8];
      case kFastRew:   return (eTeletextAction)ttSetup.mapKeyToAction[9];
      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;
   }
   
   static int tempPage;
   switch (cursorPos) {
   case 0:
      if (i<1) i=1;
      if (i>8) i=8;
      //set previous only when cursorPos==0!
      tempPage= currentPage;
      currentPage = currentPage-100*GET_HUNDREDS(currentPage)+100*i;
      break;
   case 1:
      if (i<0) i=0;
      if (i>9) i=9;
      currentPage = currentPage-10*GET_TENS(currentPage)+10*i;
      break;
   case 2:
      if (i<0) i=0;
      if (i>9) i=9;
      currentPage = currentPage-GET_ONES(currentPage)+i;
      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;
      FindFirstSubPage(0);
      if (mode==ZoomLower)
         mode=ZoomUpper;
      if (mode==HalfLower)
         mode=HalfUpper;
      ShowPage();
   }
   ShowPageNumber();
   UpdateClock();
}

void TeletextBrowser::ChangePageRelative(bool back)
{
   int oldpage = currentPage;
   int oldSubPage = currentSubPage;

   do  {
      if (back)
         currentPage--;
      else
         currentPage++;
      if (currentPage>899) currentPage=100;
      if (currentPage<100) currentPage=899;
      // sub page is always 0 if you change the page
      FindFirstSubPage(0);
      if (CheckPage()) {
         SetPreviousPage(oldpage, oldSubPage, currentPage);
         return;
      }
   } while (currentPage != oldpage);

   return;
}

void TeletextBrowser::ChangeSubPageRelative(bool back)
{
   int oldsubpage = currentSubPage;

   do  {
      if (back)
         currentSubPage--;
      else
         currentSubPage++;
      if (currentSubPage > 99) currentSubPage=0;
      if (currentSubPage < 0) currentSubPage=99;

      if (CheckPage())
         return;
   } while (currentSubPage != oldsubpage);

   return;
}

void TeletextBrowser::FindFirstSubPage(int startWith) {
   int oldsubpage = currentSubPage;

   do  {
      if (CheckPage())
         return;
      currentSubPage++;
      
      if (currentSubPage > 99) currentSubPage=0;
      if (currentSubPage < 0) currentSubPage=99;

   } while (currentSubPage != oldsubpage);
   
}

bool TeletextBrowser::CheckPage()
{
#ifndef ALTERNATIVE_STORAGE
   FILE *fd;
   
   FillFileName(currentPage,currentSubPage);
   if (!(fd=fopen(fileName,"rb")))
      return false;

   fclose(fd);
   return true;
#else
   int page=0;
   SET_PAGE(page,    currentPage);
   SET_SUBPAGE(page, currentSubPage);
   SET_CHANNEL(page, channelNumber);
   return (teletextPages.find(page) == teletextPages.end());
#endif
}

//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()) && txtbitmap) {
      txtbitmap->Display(mode, 0/*cOsd::LineHeight()*/);
      if (ttSetup.autoUpdatePage)
         checkSum=PageCheckSum();
   }
}

void TeletextBrowser::ShowPageNumber() {
   if (pageFound) {
      char str[8];
      sprintf(str, "%3d-%02d", currentPage, currentSubPage);
      if (cursorPos>0) {
         str[2]='*';
         if (cursorPos==1)
            str[1]='*';
      }
      DisplayClearMessage();
      DisplayMessage(str);
      DisplayUpdate();
   } else {
      char str[80];
      snprintf(str,80, "%s %3d-%02d %s",tr("Page"),currentPage, currentSubPage,tr("not found"));      
      DisplayClearMessage();
      DisplayMessage(str);
      DisplayUpdate();
   }
}

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): ") );
      DisplayClearMessage();
      DisplayMessage(str);
      DisplayUpdate();
      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
 //char str[80];
 char lzeichen;
 char letztes_zeichen;
 int x,y;
 // Variablen zur Paramterspeicherung
 bool flashing=false;
 bool highdouble=false;
 bool conceal=false;
 bool sepgraph=false;
 bool hold_gfx=false;
 bool graph_mode=false;
 bool skipnextline=false;



#ifndef ALTERNATIVE_STORAGE
 char cache[100];
 FILE *fd;
 FillFileName(currentPage, currentSubPage); 
 // Take a look if there is a xxx-00 page
 if (currentSubPage==0) {
  if (!(fd=fopen(fileName,"rb"))) {
     // There is no subpage 0 so look if there is subpage 1
     currentSubPage++;
     // Generate file string
     FillFileName(currentPage, currentSubPage);
   }
  else
    // yes file exists
    fclose(fd);
 }
 
 if ((fd=fopen(fileName,"rb"))) 
  {
#else
 char *page=0;
 TextPages::iterator it;
 
 int pageNr=0;
 SET_PAGE(pageNr,    currentPage);
 SET_SUBPAGE(pageNr, currentSubPage);
 SET_CHANNEL(pageNr, channelNumber);
 it=teletextPages.find(pageNr);
 if (it == teletextPages.end() ) {
    SET_SUBPAGE(pageNr,++currentSubPage);
    it=teletextPages.find(pageNr);
 }
 if (it != teletextPages.end() ) {
   page=(*it).second;                                                                                                                  
#endif //ALTERNATIVE_STORAGE




   // generate a basis bitmap object
   if (txtbitmap)
      delete txtbitmap;

   txtbitmap = new cTxtBitmap(486,506, 2, /*Width(), Height(), */true); 

   
   
   
#ifndef ALTERNATIVE_STORAGE
   fread(cache,1,9,fd); //irgendwas davor
   fread(cache,1,1,fd); //Language
   //txtbitmap->SetLanguage((unsigned int)cache[0]);
   fread(cache,1,2,fd); //irgendwas wieder
   for (y=0;y<24;y++)
   {
#else
    page+=12;
    for (y=0;y<24;y++) {
#endif



    flashing=false;
    highdouble=false;
    conceal=false;
    sepgraph=false;
    hold_gfx=false;
    graph_mode=false;
    skipnextline=false;
    letztes_zeichen=' ';

    txtbitmap->SetFGColor(7);
    txtbitmap->SetBGColor(0);
    
    
    
#ifndef ALTERNATIVE_STORAGE
    for (x=0;x<40;x++)
    {
     lzeichen=fgetc(fd);
     lzeichen=lzeichen & 0x7F; //Parity Bit ist uninteressant!
    
     if ((y==0)&&(x<8))
      { // Die Daten sind uninteressant zur Anzeige!
       lzeichen=0x20;
      }
#else
    for (x=0;x<40;x++) {
     lzeichen=*page; page++;
     lzeichen=lzeichen & 0x7F; //Parity Bit ist uninteressant!
     
     if ((y==0)&&(x<8)) { // Die Daten sind uninteressant zur Anzeige!
        lzeichen=0x20;
       }
#endif




     // conceal = verdeckt!!!

     switch (lzeichen) {
      case 0x00 ... 0x07 :
                  conceal=false;
                  txtbitmap->SetChar(x,y,hold_gfx?letztes_zeichen:' ',graph_mode,highdouble,sepgraph);
                  graph_mode=false;
                  txtbitmap->SetFGColor((int)lzeichen);
                  break;
      case 0x08 : // Blinken einschalten (flashing)
                  txtbitmap->SetChar(x,y,hold_gfx?letztes_zeichen:' ',graph_mode,highdouble,sepgraph);
                  flashing=true;
                  break;
      case 0x09 : // Blinken ausschalten (steady)
                  flashing=false;
                  txtbitmap->SetChar(x,y,hold_gfx?letztes_zeichen:' ',graph_mode,highdouble,sepgraph);
      case 0x0A : // end box (nicht benutzt)
                  txtbitmap->SetChar(x,y,hold_gfx?letztes_zeichen:' ',graph_mode,highdouble,sepgraph);
                  break;
      case 0x0B : // start box (nicht benutzt)
                  txtbitmap->SetChar(x,y,hold_gfx?letztes_zeichen:' ',graph_mode,highdouble,sepgraph);
                  break;
      case 0x0C : // normal high
                  highdouble=false;
                  txtbitmap->SetChar(x,y,' ',graph_mode,highdouble,sepgraph);
                  break;
      case 0x0D : // double high
                  for (int frei=1;frei<40;frei++)
                     txtbitmap->SetChar(frei,y+1,' ',graph_mode,highdouble,sepgraph);
                  txtbitmap->SetChar(x,y,' ',graph_mode,highdouble,sepgraph);
                  highdouble=true;
                  skipnextline=true;
                  break;
      case 0x0E ... 0x0F : // keine Funktion
                  break;
      case 0x10 ... 0x17  :
                  txtbitmap->SetChar(x,y,hold_gfx?letztes_zeichen:' ',graph_mode,highdouble,sepgraph);
                  conceal=false;
                  graph_mode=true;
                  txtbitmap->SetFGColor((int)lzeichen-0x10);
                  break;
      case 0x18 : // verborgen
                  conceal=true;
                  txtbitmap->SetChar(x,y,hold_gfx?letztes_zeichen:' ',graph_mode,highdouble,sepgraph);
                  break;
      case 0x19 : // contigouous graphics
                  sepgraph=false;
                  txtbitmap->SetChar(x,y,hold_gfx?letztes_zeichen:' ',graph_mode,highdouble,sepgraph);
                  break;
      case 0x1A : // separated grphics
                  sepgraph=true;
                  txtbitmap->SetChar(x,y,hold_gfx?letztes_zeichen:' ',graph_mode,highdouble,sepgraph);
                  break;
      case 0x1B : // ESC
                  break;
      case 0x1C : // black background
                  txtbitmap->SetBGColor(0);
                  txtbitmap->SetChar(x,y,hold_gfx?letztes_zeichen:' ',graph_mode,highdouble,sepgraph);
                  break;
      case 0x1D : // new background
                  txtbitmap->ExchangeColor();
                  txtbitmap->SetChar(x,y,hold_gfx?letztes_zeichen:' ',graph_mode,highdouble,sepgraph);
                  break;
      case 0x1E : // hold graphics
                  hold_gfx=true;
                  txtbitmap->SetChar(x,y,hold_gfx?letztes_zeichen:' ',graph_mode,highdouble,sepgraph);
                  break;
      case 0x1F : // release grphics
                  txtbitmap->SetChar(x,y,hold_gfx?letztes_zeichen:' ',graph_mode,highdouble,sepgraph);
                  hold_gfx=false;
                  break;
      default:
              if (graph_mode==true) letztes_zeichen=lzeichen;
               txtbitmap->SetChar(x,y,lzeichen,graph_mode,highdouble,sepgraph);
     }
    }
    if (skipnextline==true)
        {
         y++;
  //Rolf Ahrenberg
//         skipnextline=false;
#ifndef ALTERNATIVE_STORAGE
         fseek(fd,40,SEEK_CUR);
#else
         page+=40;
#endif
  //
        }
   }
#ifndef ALTERNATIVE_STORAGE
   fclose(fd);
#endif
  }
 else
  {
   // page doesn't exist
   currentSubPage--;
   return false;
  }
 return true;
}



int TeletextBrowser::PageCheckSum() {
 int retSum=0;
#ifndef ALTERNATIVE_STORAGE
 FILE *fd;
 
 FindFirstSubPage(currentSubPage);
 FillFileName(currentPage, currentSubPage);
 
 if ((fd=fopen(fileName,"rb"))) {
    fseek(fd, 12, SEEK_SET);
    int cache[120];
    int read=fread(cache, sizeof(int), 120, fd);
    fclose(fd);
    cache[4]=cache[3]=0; //it seems that this broadcasts the clock, ignore changes there
    for (int i=0;i<read; i++)
       retSum+=cache[i];
 }
#else
 int *page;
 TextPages::iterator it; 
 int pageNr=0;
 currentSubPage=FindFirstSubPage(currentSubPage);
 SET_PAGE(pageNr,    currentPage);
 SET_SUBPAGE(pageNr, currentSubPage);
 SET_CHANNEL(pageNr, channelNumber);
 it=teletextPages.find(pageNr);
 if (it != teletextPages.end() ) {
   page=(int *)((*it).second+12);
   for (int i=0;i<120;i++)
      retSum+=page[i];
   retSum-=page[3];retSum-=page[4]; //it seems that this broadcasts the clock, ignore changes there
 }
#endif
 return retSum;

}

void TeletextBrowser::FillFileName(int pageNumber, int subpage) {
   sprintf(fileName, "%s/%0d/%3d_%02d.vtx", TXTROOT, channelNumber, pageNumber, subpage);
}

void TeletextBrowser::UpdateClock() {
   if ( !ttSetup.showClock || !txtbitmap) return;
   cBitmap osdBitmap(8*12+4 /*8 chars and 4 for safety*/, 24, 1, false);
   char str[9];
   time_t t=time(0);
   struct tm* loct=localtime(&t);
   sprintf(str, "%02d:%02d:%02d", loct->tm_hour, loct->tm_min, loct->tm_sec);
   txtbitmap->GenOsdBitmap(str, &osdBitmap);
   txtbitmap->DisplayClock(&osdBitmap);
}


ChannelStatus::ChannelStatus() 
{
}


void ChannelStatus::ChannelSwitch(const cDevice *Device, int ChannelNumber) {
   if (Device->IsPrimaryDevice() && ChannelNumber>0) 
      TeletextBrowser::ChannelSwitched(ChannelNumber);
}

TeletextSetup ttSetup;

TeletextSetup::TeletextSetup() {
   configuredClrBackground=clrBackground;
   
   //init key bindings with default values
   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()
#ifdef ALTERNATIVE_STORAGE
   savePages=true;
#endif
}


Generated by  Doxygen 1.6.0   Back to index