/**
 *  GraphTFT plugin for the Video Disk Recorder 
 * 
 *  display.c - A plugin for the Video Disk Recorder
 *
 *  (c) 2004 Lars Tegeler, Sascha Volkenandt  
 *
 * This code is distributed under the terms and conditions of the
 * GNU GENERAL PUBLIC LICENSE. See the file COPYING for details.
 *
 * $Id: display.c,v 1.23 2004/05/26 11:34:33 tegeler Exp $
 * 
 **/

#include <algorithm>
#include <sstream>

#include "display.h"
#include "theme.h"
#include "setup.h"
#include "common.h"

// the renderdevices
#ifdef HAVE_IMLIB 
#include "fbrenderer.h"
#include "dvbrenderer.h"
#endif

#ifdef HAVE_DFB
#include "dfbrenderer.h"
#endif

#include <vdr/menu.h>

#define SECONDS(x) ((x)*1000)

cGraphTFTDisplay::cGraphTFTDisplay()
#if VDRVERSNUM >= 10300
		: cThread("GraphTFT display update")
#endif
{
	// init renderer
	_render = NULL;

	// init thread stuff
	_active = false;
	_updateIn = SECONDS(60);
	_recordingIn = 0;
	_volumeIn = 0;
	_messageIn = 0;
	_delayIn = 0;

	// init animation
	_animation = false;
	_displayFrame = 0;

	// init contents
	SetTabs(0);
	charInTabs[0] = charInTabs[1] = charInTabs[2] = charInTabs[3] = charInTabs[4] = charInTabs[5] = charInTabs[6] =  0;
	_mode = NormalTV;
	_channel = 0;
	_presentTime = 0;
	_followingTime = 0;
	_volume = cDevice::CurrentVolume();
	_mute = cDevice::PrimaryDevice()->IsMute();
	_showRecording = 0;
	_replay.control = NULL;
	_replay.lastMode = (DisplayMode)0;
	_menu.currentPosLast = 0;
	_menu.currentPos = 0;
	_menu.topPos = 0;
	_pSelect = NULL;
	_Dumped =  timeMs.Elapsed();

	// init pbp stuff
	_pbpActive = false;
}

cGraphTFTDisplay::~cGraphTFTDisplay() {
	Stop();
	delete _render;
}
	
int cGraphTFTDisplay::Init( const char * dev, const char * cfgDir) {
	char * pos = NULL;
	int devnum = -1;

#ifdef HAVE_IMLIB
	pos = strstr(dev, "/dev/fb");
	if (pos)
	{
		devnum = atoi(pos+7);
	 	_render = new FbRenderer();
 	}
 
	pos = strstr(dev, "vdr/");
 	if (pos)
 	{	 
		devnum = atoi(pos+4);
	 	_render = new DvbRenderer();
 	}
#endif
#ifdef HAVE_DFB
	pos = strstr(dev, "directFB");
	if (pos)
	{
		devnum = 0;
		_render = new DFbRenderer();
	}
#endif
	if ( devnum == -1 ) return 0;	
	_render->init(devnum);
	_render->clear();
	//Show fist black Background
	cGraphTFTThemeItem *p = GraphTFTTheme.Get(itemTheme);
	_render->image( p->Path().c_str(), 0,0);
	_render->refresh();
	_render->setPlayMode(false);

        for (cGraphTFTThemeItem *p = GraphTFTTheme.First(); p; p = GraphTFTTheme.Next(p)) {
		if ( p->Section() == sectionMenu ){
			if ( p->Item() == itemMenuImageMap ){
				_menuImageMap[tr(p->Path().c_str())] = p->Path2();
			}
		}
	}	
	Start();
	return 1;
}

void cGraphTFTDisplay::Stop() {
	if (_active) {
		_active = false;
		_doUpdate.Broadcast();
		Cancel(3);
	}
}

void cGraphTFTDisplay::SetTabs(int Tab1, int Tab2, int Tab3, int Tab4, int Tab5)
{
	d(6,"SetTabs - Tab1: %d, Tab2, %d, Tab3 %d, Tab4 %d, Tab5 %d\n",Tab1, Tab2, Tab3, Tab4, Tab5);
	tabs[0] = 0;
	tabs[1] = Tab1 ? tabs[0] + Tab1 : 0;
	tabs[2] = Tab2 ? tabs[1] + Tab2 : 0;
	tabs[3] = Tab3 ? tabs[2] + Tab3 : 0;
	tabs[4] = Tab4 ? tabs[3] + Tab4 : 0;
	tabs[5] = Tab5 ? tabs[4] + Tab5 : 0;
	tabs[6] = 100;
}

const char *cGraphTFTDisplay::GetTabbedText(const char *s, int Tab)
{
	if (!s)
		return NULL;
	static char buffer[1000];
	const char *a = s;
	const char *b = strchrnul(a, '\t');
	while (*b && Tab-- > 0) {
		a = b + 1;
		b = strchrnul(a, '\t');
	}
	if (!*b)
		return (Tab <= 0) ? a : NULL;
	unsigned int n = b - a;
	if (n >= sizeof(buffer))
		n = sizeof(buffer) - 1;
	strncpy(buffer, a, n);
	buffer[n] = 0;
	return buffer;
}


void cGraphTFTDisplay::Action() {
	int wait = 0, elapsed;

#if VDRVERSNUM < 10300
	isyslog("GraphTFT display update thread started (pid=%d)", getpid());
#endif

	// give the plugin time to collect some data AND give vdr some time to
	// finish initialization before acquiring the lock
	usleep(500000);

	_active = true;
	_mutex.Lock(); // mutex gets ONLY unlocked when sleeping
	while (_active) {
		d(4, "updating display\n");

		// milliseconds elapsed since last update
		elapsed = wait ? timeMs.Elapsed() - wait : 0;

		// check for volumebar
		if (_volumeIn < 0)
			_volumeIn *= -1;
		else if (_volumeIn > 0)
			_volumeIn -= elapsed;

		// check for osdmessage 
		if (_messageIn < 0)
			_messageIn *= -1;
		else if (_messageIn > 0)
			_messageIn -= elapsed;

		// check for animation
		if (_animation && _frameIn > 0)
			_frameIn -= elapsed;

		// check if there is another recording to show
		if (_recordings.size() > 1) {
			if (_recordingIn < 0)
				_recordingIn *= -1;
			else {
				_recordingIn -= elapsed;
				if (_recordingIn <= 0) {
					_showRecording = (_showRecording + 1) % _recordings.size();
					_recordingIn = SECONDS(5);
				}
			}
		}

		// here do the update
		wait = timeMs.Elapsed();
		switch (_mode) {
		case NormalTV:
			Display(sectionNormalTV);
			break;
		case NormalRadio:
			Display(sectionNormalRadio);
			break;
		case ReplayNormal:
			Display(sectionReplayNormal);
			break;
		case ReplayMP3:
			Display(sectionReplayMP3);
			break;
		case ReplayDVD:
			Display(sectionReplayDVD);
			break;
		case OsdMenu:
			Display(sectionMenu);
			break;
		default:
			break;
		}
		elapsed = timeMs.Elapsed() - wait;
		d(4, "update took %d ms\n", elapsed);
		
		// next update in...?
		if (_mode & ReplayMask)
			_updateIn = SECONDS(1) - elapsed; // one second minus update time
		else if (_recordings.size() > 1)
			_updateIn = _recordingIn; // use time calculated above
		else
			_updateIn = SECONDS(60); // one minute

		// possibly updating osdmessage 
		if (_messageIn > 0 && _messageIn < _updateIn)
			_updateIn = _messageIn;
		
		// possibly updating volume bar
		if (_volumeIn > 0 && _volumeIn < _updateIn)
			_updateIn = _volumeIn;

		// possibly animating
		if (_animation && _mode != OsdMenu) {
			_frameIn -= elapsed;
			if (_frameIn < 0)
				_updateIn = 0;
			else if (_frameIn < _updateIn)
				_updateIn = _frameIn;
		}

		// possibly program changes earlier
		/*int curTime = time(NULL);
		if (_followingTime > curTime) {
			int nextIn = (_followingTime - curTime) * 1000; // we want ms
			if (_updateIn < nextIn)
				_updateIn = nextIn;
		}*/

		// wait for event or timeout
		wait = timeMs.Elapsed();
		_doUpdate.TimedWait(_mutex, _updateIn);

		while (_delayIn > 0) { // a delayed update was requested
			int delay = _delayIn;
			d(5, "delayed update in max. %d ms\n", _delayIn);
			_delayIn = 0;
			_doUpdate.TimedWait(_mutex, delay);
		}
	}

#if VDRVERSNUM < 10300
	isyslog("GraphTFT display update thread stopped");
#endif
}

bool cGraphTFTDisplay::StoppedTimer(const char *Name) 
{
	cTimer *timer = Timers.First();
	while (timer) {
		if (strcmp(Name, timer->File()) == 0)
			break;
		timer = Timers.Next(timer);
	}
	return timer == NULL || !timer->Recording();
}

void cGraphTFTDisplay::UpdateProgramme()
{
	const cChannel *channel = Channels.GetByNumber(_channel);
	if (channel) {
#if VDRVERSNUM < 10300
		const cEventInfo *present = NULL, *following = NULL;
		cMutexLock mutexLock;
		const cSchedules *schedules = cSIProcessor::Schedules(mutexLock);
#else
		const cEvent *present = NULL, *following = NULL;
		cSchedulesLock schedulesLock;
		const cSchedules *schedules = cSchedules::Schedules(schedulesLock);
#endif
		if (schedules) {
			const cSchedule *schedule = schedules->GetSchedule(channel->GetChannelID());
			if (schedule) {
				if ((present = schedule->GetPresentEvent()) != NULL) {
#if VDRVERSNUM < 10300
					_presentTime = present->GetTime();
					_presentTitle = present->GetTitle() ? present->GetTitle() : "";
					_presentSubtitle = present->GetSubtitle() ? present->GetSubtitle() : "";
#else
					_presentTime = present->StartTime();
					_presentTitle = present->Title() ? present->Title() : "";
					_presentSubtitle = present->ShortText() ? present->ShortText() : "";
#endif
				}
				if ((following = schedule->GetFollowingEvent()) != NULL) {
#if VDRVERSNUM < 10300
					_followingTime = following->GetTime();
					_followingTitle = following->GetTitle() ? following->GetTitle() : "";
					_followingSubtitle = following->GetSubtitle() ? following->GetSubtitle() : "";
#else
					_followingTime = following->StartTime();
					_followingTitle = following->Title() ? following->Title() : "";
					_followingSubtitle = following->ShortText() ? following->ShortText() : "";
#endif
				}
			}
		}
	}
}

void cGraphTFTDisplay::ChannelSwitch(const cDevice *Device, int ChannelNumber) 
{
	d(5, "ChannelSwitch on %p: %d\n", Device, ChannelNumber);
	if (Device->IsPrimaryDevice() && _channel != ChannelNumber && cDevice::PrimaryDevice()->CurrentChannel() == ChannelNumber) {
		const cChannel *channel;
		cMutexLock lock(&_mutex);
		_channel = ChannelNumber;
		if ((channel = Channels.GetByNumber(_channel)) != NULL) {
			char *temp;
			int pos;
			asprintf(&temp, "%d %s", channel->Number(), channel->Name());
			_channelText = temp;
                        if ((pos = _channelText.rfind(';')) != -1)
				_channelText.erase(pos);
			if ((pos = _channelText.rfind(',')) != -1)
				_channelText.erase(pos);
			free(temp);
			if (_mode != OsdMenu) {
				switch (channel->Vpid()) {
				case 0:
				case 1:
				case 0x1fff:
					_mode = NormalRadio;
					break;

				default:
					_mode = NormalTV;
					break;
				}
			}
		}
		_delayIn = 100;
		_doUpdate.Broadcast();
	}
}

void cGraphTFTDisplay::OsdChannel(const char *Text) 
{
	d(5, "OsdChannel: %s\n", Text);
	if (_channelInfo != Text) {
		int pos;
		string temp = Text;
		cMutexLock lock(&_mutex);
		// workaround for some osd themes (Elchi)
		_channelInfo = "";
		_presentTitle = "";
		_presentSubtitle = "";
		_followingTitle = "";
		_followingSubtitle = "";
		if ((pos = temp.find(' ')) != -1) {
			_channelInfo += temp.substr(0, pos) + " ";
			while (pos < (int)temp.length() && temp[pos] == ' ')
				++pos;
			int l = temp.length();
			while (temp[l - 1] == ' ')
				--l;
			_channelInfo += temp.substr(pos, l - pos);
		} else
			_channelInfo = Text;
                if ((pos = _channelInfo.rfind(';')) != -1)
			_channelInfo.erase(pos);
		if ((pos = _channelInfo.rfind(',')) != -1)
			_channelInfo.erase(pos);
		_delayIn = 100;
		_doUpdate.Broadcast();
	}
}
	
void cGraphTFTDisplay::OsdProgramme(time_t PresentTime, const char *PresentTitle, const char *PresentSubtitle, time_t FollowingTime, const char * FollowingTitle, const char * FollowingSubtitle)
{
	d(5, "OsdProgramme at %u: (Present)   %s, %s\n", (uint)PresentTime, PresentTitle, PresentSubtitle);
	d(5, "OsdProgramme at %u: (Following) %s, %s\n", (uint)FollowingTime, FollowingTitle, FollowingSubtitle);
	// check all pointers before (STL doesn't like comparing against NULL)
	if (PresentTitle == NULL)    
		PresentTitle = "";
	if (PresentSubtitle == NULL) 
		PresentSubtitle = "";
	if (FollowingTitle == NULL)    
		FollowingTitle = "";
	if (FollowingSubtitle == NULL) 
		FollowingSubtitle = "";
	if (_presentTime != PresentTime || _presentTitle != PresentTitle || _presentSubtitle != PresentSubtitle || _followingTime != FollowingTime || _followingTitle == FollowingTitle || _followingSubtitle != FollowingSubtitle) {
		cMutexLock lock(&_mutex);
		_presentTime = PresentTime;
		_presentTitle = PresentTitle ? PresentTitle : "";
		_presentSubtitle = PresentSubtitle ? PresentSubtitle : "";
		_followingTime = FollowingTime;
		_followingTitle = FollowingTitle ? FollowingTitle : "";
		_followingSubtitle = FollowingSubtitle ? FollowingSubtitle : "";
		_doUpdate.Broadcast();
	}
}

void cGraphTFTDisplay::SetVolume(int, bool) 
{
	d(5, "SetVolume to %d, muted is %s\n", cDevice::CurrentVolume(), cDevice::PrimaryDevice()->IsMute() ? "true" : "false");
	if (_volume != cDevice::CurrentVolume() || _mute != cDevice::PrimaryDevice()->IsMute()) {
		cMutexLock lock(&_mutex);
		_volume = cDevice::CurrentVolume();
		_mute = cDevice::PrimaryDevice()->IsMute();
		_volumeIn = -SECONDS(2);
		_doUpdate.Broadcast();
	}
}

#if VDRVERSNUM >= 10338
void cGraphTFTDisplay::Recording(const cDevice *Device, const char *Name, const char *FileName, bool On)
#else
void cGraphTFTDisplay::Recording(const cDevice *Device, const char *Name) 
#endif
{
	d(5, "Recording %s to %p\n", Name, Device);

#if VDRVERSNUM >= 10338
   if (On == false)
      _replay.control = 0;

	if (Name != NULL && On != false)
#else
   if (Name != NULL) 
#endif
   {
		RecordingInfo info;
		cMutexLock lock(&_mutex);
		info.device = Device;
		info.name = Name;
		_recordings.push_back(info);
		_recordingIn = -SECONDS(5);
		_doUpdate.Broadcast();
	} else {
		cMutexLock lock(&_mutex);
		Recordings::iterator it = _recordings.begin();
		for (; it != _recordings.end(); ++it) {
			if ((*it).device == Device && StoppedTimer((*it).name.c_str())) {
				d(5, "deleting recording %s\n", (*it).name.c_str());
				_recordings.erase(it);
				break;
			}
		}
		if (_recordings.size() > 0) {
			_showRecording = _showRecording % _recordings.size();
			_recordingIn = -SECONDS(5);
		}
		_doUpdate.Broadcast();
	}
}

#if VDRVERSNUM >= 10338
void cGraphTFTDisplay::Replaying(const cControl *Control, const char *Name, const char *FileName, bool On)
#else
void cGraphTFTDisplay::Replaying(const cControl *Control, const char *Name) 
#endif
{
	d(5, "Replaying %s from %p\n", Name, Control);

#if VDRVERSNUM >= 10338
   if (On == false)
      _replay.control = 0;

	if (Name != NULL && On != false)
#else
   if (Name != NULL) 
#endif
   {
		cMutexLock lock(&_mutex);
		_replay.control = (cControl *)Control;
		_replay.lastMode = _mode;
		_mode = ReplayNormal;
		if (strlen(Name) > 6 && Name[0]=='[' && Name[3]==']' && Name[5]=='(') {
			int i;
			for (i = 6; Name[i]; ++i) {
				if (Name[i] == ' ' && Name[i-1] == ')')
					break;
			}
			if (Name[i]) { // replaying mp3
				const char *name = skipspace(Name + i);
				_replay.name = *name ? name : tr("Unknown title");
				_mode = ReplayMP3;
			}
		} else if (strcmp(Name, "DVD") == 0) {
			_replay.name = Name;
			_mode = ReplayDVD;
		} else if (strlen(Name) > 7) {
			int i, n;
			for (i = 0, n = 0; Name[i]; ++i) {
				if (Name[i] == ' ' && Name[i-1] == ',' && ++n == 4)
					break;
			}
			if (Name[i]) { // replaying DVD
				const char *name = skipspace(Name + i);
				_replay.name = *name ? name : tr("Unknown title");
				replace(_replay.name.begin(), _replay.name.end(), '_', ' ');
				_mode = ReplayDVD;
			}
		}
		if (_mode == ReplayNormal) {
			int pos;
			_replay.name = Name;
			_replay.folder = Name;
			if ((pos = _replay.name.rfind('~')) != -1) {
				_replay.name.erase(0, pos + 1);
				_replay.folder.erase(pos);
			}
		}
		_doUpdate.Broadcast();
	} else {
		cMutexLock lock(&_mutex);
		_replay.control = NULL;
		_replay.name = "";
		_replay.folder = "";
		//if (_mode == ReplayMP3)
			_mode = NormalTV;
		//else
		//	_mode = _replay.lastMode;
		_doUpdate.Broadcast();
	}
}

void cGraphTFTDisplay::OsdStatusMessage(const char *Message) 
{
	d(5, "OsdStatusMessage %s\n", Message);
	if (Message == NULL) {
		cMutexLock lock(&_mutex);
		_message = "";
		_doUpdate.Broadcast();
	} else if (_message != Message) {
		cMutexLock lock(&_mutex);
		_message = Message;
		_messageIn = -SECONDS(GraphTFTSetup.OSDMessageTime);
		_doUpdate.Broadcast();
	}
}

void cGraphTFTDisplay::OsdTitle(const char *Title) 
{
	d(5, "OsdTitle %s\n", Title);
	if (Title) {
		int pos;
		cMutexLock lock(&_mutex);
		_message = "";
		_menu.title = Title;
		if ((pos = _menu.title.find('\t')) != -1)
			_menu.title.erase(pos);
		if (_mode != OsdMenu) {
			_menu.lastMode = _mode;
			_mode = OsdMenu;
		}
		// update at current item
	}
}

void cGraphTFTDisplay::OsdItem(const char *Text, int Index) 
{
	d(5, "OsdItem %s at %d\n", Text, Index);
	if (Text) {
		cMutexLock lock(&_mutex);
		MenuItem item;
		item.text = Text;
		_message = "";

		for (int i = 0; i < MaxTabs; ++i) {
			const char *tab = GetTabbedText(Text, i);
			if (tab){
				d(6,"Set Tabs: %d, %s\n", (int)strlen(tab) , tab);
				if ( charInTabs[i] < (int)strlen(tab) )
					charInTabs[i] = (int)strlen(tab);
				item.tabs[i] = tab;
			}
			if (GetTabbedText(Text, i+1) == NULL)
				break;
		}
		
		//replace(item.text.begin(), item.text.end(), '\t', ' ');
		_menu.items.push_back(item);
		// update at current item
	}
}

void cGraphTFTDisplay::OsdCurrentItem(const char *Text)
{
	d(5, "OsdCurrentItem %s\n", Text);
	if (Text) {
		cMutexLock lock(&_mutex);
		int posCounter;
		_message = "";
		_menu.current = Text;
		for (posCounter = 0; posCounter < (int)_menu.items.size(); ++posCounter) {
			if (_menu.items[posCounter].text == _menu.current){
				_menu.currentPos = posCounter;
				break;
			}
		}

		// If we found no current Pos it may be the old one with changed values
		if ( _menu.currentPos < (int)_menu.items.size() && posCounter == (int)_menu.items.size()  && strcmp(_menu.items[_menu.currentPos].tabs[0].c_str(), GetTabbedText(Text, 0 ))==0){
			d(5, "OsdCurrentItem %s new one\n", Text);

			#if __GNUC__ < 3
			MenuItem item = _menu.items[_menu.currentPos];
			#else
			MenuItem item = _menu.items.at(_menu.currentPos);
			#endif

			vector<MenuItem>::iterator tempIterator;
			tempIterator = _menu.items.begin();
			for ( int i = 0; i < _menu.currentPos; i++)
				tempIterator++;
			tempIterator = _menu.items.erase( tempIterator );
			
			item.text = Text;
                        for (int i = 0; i < MaxTabs; ++i) {
				const char *tab = GetTabbedText(Text, i);
				if (tab){
					item.tabs[i] = tab;
				}
				if (GetTabbedText(Text, i+1) == NULL)
					break;
			}

			_menu.items.insert( tempIterator, item);
			d(5, "OsdCurrentItem %s new addes\n", Text);
			
		}		
		_doUpdate.Broadcast();
	}
}

void cGraphTFTDisplay::OsdClear(void) {
	d(5, "OsdClear\n");
	cMutexLock lock(&_mutex);
	_message = "";
	_menu.title = "";
	_menu.items.clear();
	charInTabs[0] = charInTabs[1] = charInTabs[2] = charInTabs[3] = charInTabs[4] = charInTabs[5] = 0;
	SetTabs(0,0,0,0,0);
	for (int i = 0; i < 4; ++i)
		_menu.buttons[i] = "";
	_menu.text = "";
	if (_mode == OsdMenu || _channelInfo != "") {
		_channelInfo = "";
		if (_mode == OsdMenu)
			_mode = _menu.lastMode;
		_delayIn = 100;
		_doUpdate.Broadcast();
	}
}

void cGraphTFTDisplay::OsdHelpKeys(const char *Red, const char *Green, const char *Yellow, const char *Blue) {
	d(5, "OsdHelpKeys: %s, %s, %s, %s\n", Red, Green, Yellow, Blue);
	cMutexLock lock(&_mutex);
	_menu.buttons[0] = Red ? Red : "";
	_menu.buttons[1] = Green ? Green : "";
	_menu.buttons[2] = Yellow ? Yellow : "";
	_menu.buttons[3] = Blue ? Blue : "";
	// update at current item
}

void cGraphTFTDisplay::OsdTextItem(const char *Text, bool Scroll) {
	d(5, "OsdTextItem: %s scroll %s\n", Text, Scroll ? "true" : "false");
	cMutexLock lock(&_mutex);
	if (Text){ 
		_menu.text = Text;
		_menu.textScroll = 0;
		replace(_menu.text.begin(), _menu.text.end(), '\n', ' ');
	}else{
		if (Scroll)
			_menu.textScroll--;
		else
			_menu.textScroll++;
	}
	_doUpdate.Broadcast();
}

///////////////////////////////////////////////////////////////////////////////
// Display

void cGraphTFTDisplay::Display(int section)
{
	DisplayClear();
	if (_mode & NormalMask)
		UpdateProgramme();
	for (cGraphTFTThemeItem *p = GraphTFTTheme.First(); p; p = GraphTFTTheme.Next(p)) {

		if ( p->Section() == section ){
			switch ( p->Item() ){
	
			case itemImage:
				DisplayImage( p->X(), p->Y(), p->Width(),p->Height(),p->Transperents(),p->Path() );
				break;

			case itemImageCover:
				DisplayImageCover(  p->X(), p->Y(), p->Width(),p->Height(),p->Transperents(),p->Path() );
				break;

			case itemImageFile:
				DisplayImageFile(  p->X(), p->Y(), p->Width(),p->Height(),p->Transperents(),p->Path(), p->Path2() );
				break;

			case itemText:
				DisplayText( p->X(), p->Y(), p->Width(),p->Height(),p->Red(), p->Green(), p->Blue(), p->Transperents(), p->Font(), p->Size(), p->Align(), p->Lines(), p->Text() );
				 break;

			case itemTimebar:
				 DisplayTimebar( p->X(), p->Y() ,p->Width(),p->Height(),p->Red(), p->Green(), p->Blue(),p->Transperents(),p->Switch());
				 break;

			case itemDate:
				DisplayDate( p->X(), p->Y(), p->Width(),p->Height(),p->Red(), p->Green(), p->Blue(), p->Transperents(), p->Font(), p->Size(), p->Align(), p->Lines() );
				break;

			case itemDateOnly:
				DisplayDateOnly( p->X(), p->Y(), p->Width(),p->Height(),p->Red(), p->Green(), p->Blue(), p->Transperents(), p->Font(), p->Size(),p->Align(), p->Lines() );
				break;

			case itemTimeOnly:
				DisplayTimeOnly( p->X(), p->Y(), p->Width(),p->Height(),p->Red(), p->Green(), p->Blue(), p->Transperents(), p->Font(), p->Size(),p->Align(), p->Lines() );
				break;

			case itemLogo:
				DisplayLogo(p->X(), p->Y(), p->Width(),p->Height(),p->Transperents(),p->Path(), p->Type(), p->Animated(), p->Delay(), p->Count() );
				break;

			case itemSymRecording:
				DisplayRecordingSymbol(p->X(), p->Y(), p->Width(),p->Height(),p->Transperents(),p->Path(),p->Path2());
				break;

			case itemSym2ch:
			case itemSymDD:		 
			case itemSymVTX:		 
			case itemSymCrypt:
			case itemSymRepPlay:
			case itemSymRepPause:
			case itemSymRepFF:
			case itemSymRepFB:
			case itemSymRepSF:
			case itemSymRepSB:
				DisplaySymbols(p->X(), p->Y(), p->Width(), p->Height(), p->Transperents(),p->Path(), p->Path2(), p->Item());
				break;

			case itemChannel:
				DisplayChannelName( p->X(), p->Y(), p->Width(),p->Height(),p->Red(), p->Green(), p->Blue(), p->Transperents(), p->Font(), p->Size(), p->Align(), p->Lines() );
				break;

			case itemChannelOnly:
				DisplayChannelNameOnly( p->X(), p->Y(), p->Width(),p->Height(),p->Red(), p->Green(), p->Blue(), p->Transperents(), p->Font(), p->Size(), p->Align(), p->Lines() );
				break;

			case itemChannelNumber:
				DisplayChannelNumber( p->X(), p->Y(), p->Width(),p->Height(),p->Red(), p->Green(), p->Blue(), p->Transperents(), p->Font(), p->Size(), p->Align(), p->Lines() );
				break;

			case itemRectangle:
				DisplayRectangle( p->X(), p->Y(), p->Width(),p->Height(),p->Red(), p->Green(), p->Blue(), p->Transperents());
				break;

			case itemPresentTitle:
				DisplayPresentTitle( p->X(), p->Y(), p->Width(),p->Height(),p->Red(), p->Green(), p->Blue(), p->Transperents(), p->Font(), p->Size(), p->Align(),p->Lines() );
				break;
				
			case itemPresentSubtitle:
				DisplayPresentSubtitle( p->X(), p->Y(), p->Width(),p->Height(),p->Red(), p->Green(), p->Blue(), p->Transperents(), p->Font(), p->Size(), p->Align(),p->Lines() );
				break;

			case itemPresentTime:
				DisplayPresentTime( p->X(), p->Y(), p->Width(),p->Height(),p->Red(), p->Green(), p->Blue(), p->Transperents(), p->Font(), p->Size(), p->Align(),p->Lines() );
				break;

			case itemFollowingTitle:
				DisplayFollowingTitle( p->X(), p->Y(), p->Width(),p->Height(),p->Red(), p->Green(), p->Blue(), p->Transperents(), p->Font(), p->Size(), p->Align(),p->Lines() );
				break;
				
			case itemFollowingSubtitle:
				DisplayFollowingSubtitle( p->X(), p->Y(), p->Width(),p->Height(),p->Red(), p->Green(), p->Blue(), p->Transperents(), p->Font(), p->Size(), p->Align(),p->Lines() );
				break;

			case itemFollowingTime:
				DisplayFollowingTime( p->X(), p->Y(), p->Width(),p->Height(),p->Red(), p->Green(), p->Blue(), p->Transperents(), p->Font(), p->Size(), p->Align(),p->Lines() );
				break;

			case itemRecording:
				DisplayRecording( p->X(), p->Y(), p->Width(),p->Height(),p->Red(), p->Green(), p->Blue(), p->Transperents(), p->Font(), p->Size(), p->Align(),p->Lines() );
				break;

			case itemVolumeBackground:
				DisplayVolumeBackground( p->X(), p->Y(), p->Width(),p->Height(),p->Transperents(),p->Path() );
				break;

			case itemVolumebar:
				DisplayVolumebar(p->X(), p->Y() ,p->Width(),p->Height(), p->Red(), p->Green(), p->Blue(),p->Transperents());
				break;

			case itemVolumeMuteSymbol:
				DisplayVolumeMuteSymbole(p->X(), p->Y(), p->Width(),p->Height(),p->Transperents(),p->Path(), p->Path2());
				break;

			case itemMessageBackground:
				DisplayMessageBackground( p->X(), p->Y(), p->Width(),p->Height(),p->Transperents(),p->Path() );
				break;

			case itemMessage:
				DisplayMessage( p->X(), p->Y(), p->Width(),p->Height(),p->Red(), p->Green(), p->Blue(), p->Transperents(), p->Font(), p->Size(), p->Align(), p->Lines() );
				break;

			case itemReplayName:
				DisplayReplayName( p->X(), p->Y(), p->Width(),p->Height(),p->Red(), p->Green(), p->Blue(), p->Transperents(), p->Font(), p->Size(), p->Align(), p->Lines() );
				break;
				
			case itemReplayFolder:
				DisplayReplayFolder( p->X(), p->Y(), p->Width(),p->Height(),p->Red(), p->Green(), p->Blue(), p->Transperents(), p->Font(), p->Size(), p->Align(), p->Lines() );
				break;
				
			case itemReplayProcessbar:
				DisplayReplayProcessBar(p->X(), p->Y() ,p->Width(),p->Height(), p->Red(), p->Green(), p->Blue(),p->Transperents());
				break;

			case itemReplayCurrent:
				DisplayReplayCurrent( p->X(), p->Y(), p->Width(),p->Height(),p->Red(), p->Green(), p->Blue(), p->Transperents(), p->Font(), p->Size(), p->Align(),p->Lines() );
				break;

			case itemReplayTotal:
				DisplayReplayTotal( p->X(), p->Y(), p->Width(),p->Height(),p->Red(), p->Green(), p->Blue(), p->Transperents(), p->Font(), p->Size(), p->Align(), p->Lines() );
				break;

			case itemReplayRemaining:
				DisplayReplayRemaining( p->X(), p->Y(), p->Width(),p->Height(),p->Red(), p->Green(), p->Blue(), p->Transperents(), p->Font(), p->Size(), p->Align(), p->Lines() );
				break;

			case itemMenuTitle:
				DisplayMenuTitle( p->X(), p->Y(), p->Width(),p->Height(),p->Red(), p->Green(), p->Blue(), p->Transperents(), p->Font(), p->Size(), p->Align(), p->Lines() );
				break;
			
			case itemMenuText:
				DisplayMenuText( p->X(), p->Y(), p->Width(),p->Height(),p->Red(), p->Green(), p->Blue(), p->Transperents(), p->Font(), p->Size(), p->Align(), p->Lines() );
				break;
			case itemMenuTextBackground:
				DisplayMenuTextBackground( p->X(), p->Y(), p->Width(),p->Height(), p->Transperents(), p->Path() );
				break;
			case itemMenuSelected:
				_pSelect = p;
				break;
			case itemMenu:
				if (!_pSelect) _pSelect = p;
				DisplayMenu(p->X(), p->Y(), p->Width(),p->Height(),p->Red(), p->Green(), p->Blue(), p->Transperents(), p->Font(), p->Size(), p->Align(), p->Lines(), _pSelect->Red(), _pSelect->Green(), _pSelect->Blue(), _pSelect->Transperents(), _pSelect->Font(), _pSelect->Size(), _pSelect->Align(), _pSelect->Lines(), p->Path(), _pSelect->Path2(), _pSelect->Path());
				break;
			case itemMenuButtonRed:
				DisplayMenuButton(  p->X(), p->Y(), p->Width(),p->Height(),p->Red(), p->Green(), p->Blue(), p->Transperents(), p->Font(), p->Size(), p->Align(), p->Lines(), 0);
				break;
                        case itemMenuButtonGreen:
				DisplayMenuButton(  p->X(), p->Y(), p->Width(),p->Height(),p->Red(), p->Green(), p->Blue(), p->Transperents(), p->Font(), p->Size(), p->Align(), p->Lines(), 1);
				break;
                        case itemMenuButtonYellow:
				DisplayMenuButton(  p->X(), p->Y(), p->Width(),p->Height(),p->Red(), p->Green(), p->Blue(), p->Transperents(), p->Font(), p->Size(), p->Align(), p->Lines(), 2);
				break;
			case itemMenuButtonBlue:
				DisplayMenuButton(  p->X(), p->Y(), p->Width(),p->Height(),p->Red(), p->Green(), p->Blue(), p->Transperents(), p->Font(), p->Size(), p->Align(), p->Lines(), 3);
				break;
			case itemMenuButtonBackgroundRed:
				DisplayMenuButtonBackground( p->X(), p->Y(), p->Width(),p->Height(), p->Transperents(),p->Path(), p->Path2(), 0);
				break;
                        case itemMenuButtonBackgroundGreen:
				DisplayMenuButtonBackground( p->X(), p->Y(), p->Width(),p->Height(), p->Transperents(),p->Path(), p->Path2(), 1);
				break;
                        case itemMenuButtonBackgroundYellow:
				DisplayMenuButtonBackground( p->X(), p->Y(), p->Width(),p->Height(), p->Transperents(),p->Path(), p->Path2(), 2);
				break;
			case itemMenuButtonBackgroundBlue:
				DisplayMenuButtonBackground( p->X(), p->Y(), p->Width(),p->Height(), p->Transperents(),p->Path(), p->Path2(), 3);
				break;
			default:
				break;
			}
		}
	}
	DisplayShow();
}


void
cGraphTFTDisplay::DisplayClear(){
	_render->clear();
}

void
cGraphTFTDisplay::DisplayShow(){
	_render->refresh();
	if (GraphTFTSetup.DumpImage) 
	{
		int lastDumpDiff = _Dumped ? timeMs.Elapsed() - _Dumped : 0;
		d(6,"DisplayShow: lastDumpDiff: %d  DumpRefresh: %d\n", lastDumpDiff, GraphTFTSetup.DumpRefresh * 100 );
		if ( lastDumpDiff > ( GraphTFTSetup.DumpRefresh * 1000) ){
			_Dumped =  timeMs.Elapsed();
			_render->dumpImage2File("", GraphTFTSetup.DumpImageX, GraphTFTSetup.DumpImageY);
	
		}
	}
}

// ---Items---------------------------------------------------------

void
cGraphTFTDisplay::DisplayImage(int x, int y, int width, int height, int transperent, string image)
{
	_render->image(image.c_str(), x, y);
}

void
cGraphTFTDisplay::DisplayImageCover(int x, int y, int width, int height, int transperent, string image)
{
        d(6,"DisplayImageCover: begin \n");
	if ( GraphTFTSetup.CoverImage != NULL  )
		_render->image(GraphTFTSetup.CoverImage, x, y, true);
	else
		_render->image(image.c_str(), x, y);
	d(6,"DisplayImageCover: end \n");
}

void
cGraphTFTDisplay::DisplayImageFile(int x, int y, int width, int height, int transperent, string file, string image)
{
	d(6,"DisplayImageFile\n");
	FILE *fp1;
	char oneline[100];
	char *c = NULL;
	fp1 = fopen(file.c_str(),"r"); 
	if (fp1){
		c = fgets(oneline, 100 ,fp1);
		if ( c != NULL ){
			oneline[strlen(oneline) -1 ] = '\0';
			d(6,"DisplayImageFile fgest: %s\n",oneline);
		}
		fclose(fp1);
	}
	d(6,"DisplayImageFile: fclosed \n");
	if ( c != NULL  ) 
		_render->image(oneline, x, y, true);
	else
		_render->image(image.c_str(), x, y);
}

void
cGraphTFTDisplay::DisplayMessageBackground(int x, int y, int width, int height, int transperents, string image)
{
	if (_messageIn <= 0 )
	{
		_messageIn = 0;
		_message = "";
	}

	if (_message.length() > 0)
	 	DisplayImage(x, y, width, height, transperents, image);
}

void
cGraphTFTDisplay::DisplayVolumeBackground(int x, int y, int width, int height, int transperents, string image)
{
	if (_volumeIn <= 0 || _mute)
		_volumeIn = 0;
	else
		DisplayImage(x, y, width, height, transperents, image );
}

void
cGraphTFTDisplay::DisplayVolumeMuteSymbole(int x, int y, int width, int height, int transperents, string image, string image2)
{
	if (_mute && (GraphTFTSetup.ShowMutePermanent || _volumeIn > 0))
		DisplayImage(x, y, width, height, transperents, image );	// is Muted
	else if (image2 != "")
		DisplayImage(x, y, width, height, transperents, image2 );
}



void
cGraphTFTDisplay::DisplayDate(int x, int y, int width, int height,int red, int green, int blue, int transperents, string font, int size, int align, int lines)
{
	string date = *DayDateTime(time(NULL));
	DisplayText( x, y, width, height, red, green, blue, transperents, font, size, align, lines, date);
}

void
cGraphTFTDisplay::DisplayDateOnly(int x, int y, int width, int height,int red, int green, int blue, int transperents, string font, int size, int align, int lines)
{
	string date = *DayDateTime(time(NULL));
	date = date.substr(4,5);
	DisplayText( x, y, width, height, red, green, blue, transperents, font, size, align, lines, date);
}

void
cGraphTFTDisplay::DisplayTimeOnly(int x, int y, int width, int height,int red, int green, int blue, int transperents, string font, int size, int align, int lines)
{
	string date = *DayDateTime(time(NULL));
	date = date.substr(10,5);
	DisplayText( x, y, width, height, red, green, blue, transperents, font, size, align, lines, date);
}

void
cGraphTFTDisplay::DisplayText(int x, int y, int width, int height,int red, int green, int blue, int transperents, string font, int size,	int align, int lines, string text)
{
	if ( width == 0 ) width = 720 - x;
	if ( height == 0 ) height = 576 - y;

	_render->text(text.c_str(), font.c_str(), size, align, x, y, red, green, blue, width, height, lines);
}

void
cGraphTFTDisplay::DisplayChannelName(int x, int y, int width, int height,int red, int green, int blue, int transperents, string font, int size, int align, int lines)
{
	string text = _channelInfo != "" ? _channelInfo : _channelText;
	DisplayText(x, y, width, height, red, green, blue, transperents, font, size, align, lines, skipspace(text.c_str()));
}

void
cGraphTFTDisplay::DisplayChannelNumber(int x, int y, int width, int height,int red, int green, int blue, int transperents, string font, int size, int align, int lines)
{
	string text = _channelInfo != "" ? _channelInfo : _channelText;
	DisplayText( x, y, width, height, red, green, blue, transperents, font, size, align, lines, text.substr(0, text.find(' ')));
}

void
cGraphTFTDisplay::DisplayRectangle(int x, int y, int width, int height,int red, int green, int blue, int transperents)
{
	_render->rectangle(x, y, width, height, red, green, blue, transperents);
}

void
cGraphTFTDisplay::DisplayChannelNameOnly(int x, int y, int width, int height,int red, int green, int blue, int transperents, string font, int size, int align, int lines)
{
	string text = _channelInfo != "" ? _channelInfo : _channelText;
	DisplayText( x, y, width, height, red, green, blue, transperents, font, size, align, lines, text.substr(text.find(' ') + 1));
}

void
cGraphTFTDisplay::DisplayLogo(int x, int y, int width, int height, int transperents, string image, string type, int animated, int delay, int count)
{
	string path;
	if (_mode & NormalMask && type != "") {
		string text = _channelInfo != "" ? _channelInfo : _channelText;
		path = image.substr(0,image.rfind('/') + 1) + text.substr(text.find(' ') + 1) + "." + type;
		std::ostringstream fullpath; fullpath << GraphTFTSetup.PluginConfPath << "/graphTFT/themes/" << GraphTFTTheme.getDir() << "/" << path; 
		if ( !file_exists( fullpath.str() ) ) path = image;
	} else
		path = image;

	if (animated) {
		if (!_animation) {
			_animation = true;
			_displayFrame = 0;
			_frameIn = delay;
		} else if (_frameIn < 0) {
			_displayFrame = (_displayFrame + 1) % count;
			_frameIn = delay;
		}
		int pos;
		if ((pos = path.rfind('.')) != -1) {
			char *temp;
			asprintf(&temp, "%s%d%s", path.substr(0, pos).c_str(), _displayFrame, path.substr(pos).c_str());
			path = temp;
			free(temp);
		}
	} else
		_animation = false;

	DisplayImage(x, y, width, height, transperents, path);
}

void
cGraphTFTDisplay::DisplayPresentTitle(int x, int y, int width, int height,int red, int green, int blue, int transperents, string font, int size, int align, int lines)
{
	if (_channelInfo == "" || _channelInfo == _channelText)
		DisplayText( x, y, width, height, red, green, blue, transperents, font, size, align, lines, _presentTitle);
}

void
cGraphTFTDisplay::DisplayPresentTime(int x, int y, int width, int height,int red, int green, int blue, int transperents, string font, int size, int align, int lines)
{
	string presentTime = *DayDateTime(_presentTime);
	presentTime = presentTime.substr(10);
	if (_channelInfo == "" || _channelInfo == _channelText)
		DisplayText( x, y, width, height, red, green, blue, transperents, font, size, align, lines, presentTime);
}

void
cGraphTFTDisplay::DisplayPresentSubtitle(int x, int y, int width, int height,int red, int green, int blue, int transperents, string font, int size, int align, int lines)
{
	if (_channelInfo == "" || _channelInfo == _channelText)
		DisplayText( x, y, width, height, red, green, blue, transperents, font, size, align, lines, _presentSubtitle);
}

void
cGraphTFTDisplay::DisplayFollowingTitle(int x, int y, int width, int height,int red, int green, int blue, int transperents, string font, int size, int align, int lines)
{
	if (_channelInfo == "" || _channelInfo == _channelText)
		DisplayText( x, y, width, height, red, green, blue, transperents, font, size, align, lines, _followingTitle);
}

void
cGraphTFTDisplay::DisplayFollowingSubtitle(int x, int y, int width, int height,int red, int green, int blue, int transperents, string font, int size, int align, int lines)
{
	if (_channelInfo == "" || _channelInfo == _channelText)
		DisplayText( x, y, width, height, red, green, blue, transperents, font, size, align, lines, _followingSubtitle);
}

void
cGraphTFTDisplay::DisplayFollowingTime(int x, int y, int width, int height,int red, int green, int blue, int transperents, string font, int size, int align, int lines)
{
	string followingTime = *DayDateTime(_followingTime);
	followingTime = followingTime.substr(10);
	if (_channelInfo == "" || _channelInfo == _channelText)
		DisplayText( x, y, width, height, red, green, blue, transperents, font, size, align, lines, followingTime);
}

void
cGraphTFTDisplay::DisplayTimebar(int x, int y ,int width, int height, int red, int green, int blue, int transperents, int sw)
{
	float percent;
	int xDone;
	
	if ((_channelInfo == ""  || _channelInfo == _channelText) && _followingTime && _followingTime != _presentTime) {
		percent =	((float)(time(NULL) - _presentTime)) / ((float)(_followingTime - _presentTime));
		if (percent < 0) percent = 0;
		if (percent > 1.0) percent = 1.0;

		// colorchanging timebar
		if (sw) {
			if (percent < 0.5f) {
				red = (int)(255.0f * percent * 2.0f);
				green = 255;
			} else {
				red = 255;
				green = (int)(255.0f * (1-percent) * 2.0f);
			}
			blue=0;
		}
		
		xDone = (int)(percent*(float)(width > height ? width : height));	
		_render->rectangle(x, y, width, height, 0, 0, 0, transperents);
		if (width > height)
			_render->rectangle(x, y, xDone, height, red, green, blue, transperents);
		else
			_render->rectangle(x, y, width, xDone, red, green, blue, transperents);
	}
}

void cGraphTFTDisplay::DisplayMessage(int x, int y, int width, int height,int red, int green, int blue, int transperents, string font, int size, int align, int lines)
{
	if (_messageIn < 0 )
	{
		_message = "";
		_messageIn = 0;
	}

	if (_message.length() > 0)
		DisplayText( x, y, width, height, red, green, blue, transperents, font, size, align,	lines, _message);	
}

void cGraphTFTDisplay::DisplayRecording(int x, int y, int width, int height,int red, int green, int blue, int transperents, string font, int size, int align, int lines)
{
	if (_recordings.size() > 0)
		DisplayText(x, y, width, height, red, green, blue, transperents, font, size, align, lines, _recordings[_showRecording].name.c_str());
}

void cGraphTFTDisplay::DisplaySymbols(int x, int y, int width, int height, int transperents, string path, string path2, int symbol)
{
	const char *image = NULL;
	bool play, forward;
	int speed;
	cChannel *chan;
	
	if (_replay.control && _replay.control->GetReplayMode(play, forward, speed)) {
		switch (symbol) {
		case itemSymRepPlay:
			image = play && speed == -1 ? path.c_str() : path2.c_str();
			break;
		case itemSymRepPause:
			image = !play && speed == -1 ? path.c_str() : path2.c_str();
			break;
		case itemSymRepFF:
			image = play && forward && speed != -1 ? path.c_str() : path2.c_str();
			break;
		case itemSymRepFB:
			image = play && !forward && speed != -1 ? path.c_str() : path2.c_str();
			break;
		case itemSymRepSF:
			image = !play && forward && speed != -1 ? path.c_str() : path2.c_str();
			break;
		case itemSymRepSB:
			image = !play && !forward && speed != -1 ? path.c_str() : path2.c_str();
			break;
		}
	} else if (_mode & NormalMask && (chan = Channels.GetByNumber(_channel))) {
		switch (symbol) {
		case itemSym2ch:
			image = chan->Apid(1) ? path.c_str() : path2.c_str();
			break;
		case itemSymDD:
			image = chan->Dpid(0) ? path.c_str() : path2.c_str();
			break;
		case itemSymVTX:
			image = chan->Tpid() ? path.c_str() : path2.c_str();
			break;
		case itemSymCrypt:
			image = chan->Ca() ? path.c_str() : path2.c_str();
			break;
		}
	}

	if (image && *image)
		_render->image(image, x, y);
}

void cGraphTFTDisplay::DisplayRecordingSymbol(int x, int y, int width, int height, int transperents, string path, string path2)
{
	if (_recordings.size() > 0)
		_render->image(path.c_str(), x, y);
	else if (path2.length() > 0)
		_render->image(path2.c_str(), x, y);
}

void cGraphTFTDisplay::DisplayMenuTitle(int x, int y, int width, int height,int red, int green, int blue, int transperents, string font, int size, int align, int lines )
{
	DisplayText(x, y, width, height, red, green, blue, transperents, font, size, align, lines, _menu.title.c_str() );
}

void cGraphTFTDisplay::DisplayMenuText(int x, int y, int width, int height,int red, int green, int blue, int transperents, string font, int size, int align, int lines )
{
	if (_menu.text.length() != 0) {
		DisplayText(x, y, width, height, red, green, blue, transperents, font, size, align, lines, _menu.text.c_str() );
	}
}

void cGraphTFTDisplay::DisplayMenuTextBackground(int x, int y, int width, int height, int transperent, string image)
{
	if (_menu.text.length() != 0) {
		DisplayImage(x, y, width, height, transperent, image);
	}
}

void cGraphTFTDisplay::DisplayMenu(int x, int y, int width, int height,int red, int green, int blue, int transperents, string font, int size, int align, int lines, int redSelect, int greenSelect, int blueSelect, int transperentsSelect, string fontSelect, int sizeSelect, int alignSelect, int linesSelect, string imageItem, string imageItemSelectFront, string imageItemSelectBack  )
{
	int lineHeight = size * 5 / 3;
	int lineHeightSelect = sizeSelect * 5 / 3;
	int afterSelect = 0;

	int tabChars = charInTabs[0] + charInTabs[1] + charInTabs[2] + charInTabs[3] + charInTabs[4] + charInTabs[5];
	d(6,"MenuTabs: %d, %d, %d, %d, %d, %d \n", charInTabs[0], charInTabs[1], charInTabs[2], charInTabs[3], charInTabs[4], charInTabs[5]);

	
	if (tabChars > 0 )
		
		
		if (charInTabs[1] == 0)  SetTabs(100,0,0,0,0);
		else if (charInTabs[0] == 6 && charInTabs[1] == 5 && charInTabs[2] == 3 && charInTabs[3] != 0 && charInTabs[4] == 0 && charInTabs[5] == 0 )
		{
			d(6, "Looks like the Programm menu! - SetTabs()\n");
			 SetTabs( 25 , 20, 15, 40, 0);
		}
                else if (charInTabs[0] == 1 && charInTabs[1] != 0 && charInTabs[2] < 8 && charInTabs[3] == 5 && charInTabs[4] == 5 && charInTabs[5] != 0 )
		{
			d(6, "Looks like the Timer menu! - SetTabs()\n");
			SetTabs( 7 , 10, 20, 20, 20);
		}
		else{

			int saveTabsProz[7] = {0,0,0,0,0,0,0};
			int total = 100;
			for (int i = 0; charInTabs[i] != 0; i++)
			{
				if (  charInTabs[i] < (tabChars/6) )
					saveTabsProz[i] = (int)( ((float)total / (float)width)  * (float)size * ((float)charInTabs[i]+1));
				else
					saveTabsProz[i] = (total*charInTabs[i])/tabChars;
				total -= saveTabsProz[i];
			
			}
			SetTabs(saveTabsProz[0],saveTabsProz[1],saveTabsProz[2],saveTabsProz[3],saveTabsProz[4]);

		}
	
	else
		SetTabs(0,0,0,0,0);
	
	int count = ( (height-lineHeightSelect) / lineHeight ) + 1;
	if (_menu.text.length() == 0) {

	int PosOnPage = 14;	
	int Page = _menu.currentPos / (PosOnPage - 1);
	int PageTop = Page * (PosOnPage - 1);
	
	int PagePercent = ((_menu.currentPos - PageTop) * 100 )/ (PosOnPage - 1);

	_menu.topPos = _menu.currentPos - ( ( PagePercent * count ) / 100);

	if (_menu.currentPos == PageTop && _menu.currentPos > _menu.currentPosLast)
		_menu.topPos = _menu.currentPos - count + 1;
	_menu.currentPosLast = _menu.currentPos;
	
		for (int i = _menu.topPos; i < min((int)_menu.items.size(), _menu.topPos + count); ++i) {
			if (i == _menu.currentPos){
				afterSelect = lineHeightSelect - lineHeight;
				if (imageItemSelectBack != "")
						_render->image(imageItemSelectBack.c_str(), x, y + (i - _menu.topPos ) * lineHeight);
				for (int t = 0; t < MaxTabs; ++t) {
	                          	if (_menu.items[i].tabs[t] != "") {
						_render->text(_menu.items[i].tabs[t].c_str(), fontSelect.c_str(), sizeSelect, alignSelect, x + int(width * Tab(t) / 100), y + ((i - _menu.topPos ) * lineHeight), redSelect, greenSelect, blueSelect, int(width * (Tab(t+1)-Tab(t)) / 100), lineHeightSelect, 1);
					}
					if ( !Tab(t + 1) || Tab(t+1) == 100 )
						break;
				}

				int cutPoint = _menu.items[i].text.rfind(' ') + 1;
				
				string temp;
				temp = _menu.items[i].text.substr(cutPoint);
					
				string temp2 =  _menuImageMap[temp].c_str();
				d(6,"MenuImageMap: %s, %s\n", temp.c_str(), temp2.c_str());
				if ( temp2 != "" )
					 DisplayImage(720-128, y - 20 + (i - _menu.topPos ) * lineHeight, 128, 128, 255, temp2);
				if (imageItemSelectFront != "")
					_render->image(imageItemSelectFront.c_str(), x, y + (i - _menu.topPos ) * lineHeight);
			}else{	
				if (imageItem != "")
						_render->image(imageItem.c_str(), x, y + ((i - _menu.topPos ) * lineHeight) + afterSelect);
				for (int t = 0; t < MaxTabs; ++t) {
					if (_menu.items[i].tabs[t] != "") {
						d(6,"DisplayMenu: Item-Text %d Tab %d: %s\n",i,t,_menu.items[i].tabs[t].c_str() );
						_render->text(_menu.items[i].tabs[t].c_str(), font.c_str(), size, align, x + int( width * Tab(t) / 100), y + ((i - _menu.topPos ) * lineHeight) + afterSelect , red, green, blue, int(width * (Tab(t+1)-Tab(t)) / 100), lineHeight, 1);
					}
					if (!Tab(t + 1) || Tab(t+1) == 100 ){
						break;
					}
				}
			}
		}
	}
}

void cGraphTFTDisplay::DisplayMenuButton(int x, int y, int width, int height,int red, int green, int blue, int transperents, string font, int size, int align, int lines, int buttonNumber)
{
	if (_menu.buttons[buttonNumber].length() > 0)
		DisplayText(x, y, width, height, red, green, blue, transperents, font, size, align, lines, _menu.buttons[buttonNumber].c_str());
}

void cGraphTFTDisplay::DisplayMenuButtonBackground(int x, int y, int width, int height, int transperent, string image, string imageOff, int buttonNumber)
{
	if (_menu.buttons[buttonNumber].length() > 0)
		DisplayImage(x, y, width, height, transperent, image);
	else
		DisplayImage(x, y, width, height, transperent, imageOff);
}

void cGraphTFTDisplay::DisplayVolumebar(int x, int y ,int width, int height, int red, int green, int blue, int transperents)
{
	int xVolume = (_volume * (width > height ? width : height)) / 255;
	if (_volumeIn > 0 && !_mute) {
		_render->rectangle(x, y, width, height, 0, 0, 0, transperents);
		if (width > height) 
			_render->rectangle(x, y, xVolume, height, red, green, blue, transperents);
		else
			_render->rectangle(x, y, width, xVolume, red, green, blue, transperents);
	}
}

void cGraphTFTDisplay::DisplayReplayName(int x, int y, int width, int height,int red, int green, int blue, int transperents, string font, int size, int align, int lines)
{
	if (_replay.name.length() > 0)
		DisplayText(x, y, width, height, red, green, blue, transperents, font, size, align, lines, _replay.name);
}

void cGraphTFTDisplay::DisplayReplayFolder(int x, int y, int width, int height,int red, int green, int blue, int transperents, string font, int size, int align, int lines)
{
	if (_replay.folder.length() > 0)
		DisplayText(x, y, width, height, red, green, blue, transperents, font, size, align, lines, _replay.folder);
}

void cGraphTFTDisplay::DisplayReplayProcessBar(int x, int y ,int width, int height, int red, int green, int blue, int transperents)
{
	int current, total;
	if (_replay.control && _replay.control->GetIndex(current, total)) {
		if (total == 0 && current == 0)
			current = total = 1;
		else if (total == 0)
			total = current;
		int xDone= (int)(((float)current / (float)total)*(float)(width > height ? width : height));
		_render->rectangle(x, y, width, height, 0, 0, 0, transperents);
		if (width > height)
			_render->rectangle(x, y, xDone, height, red, green, blue, transperents);
		else
			_render->rectangle(x, y, width, xDone, red, green, blue, transperents);
	}
}

void cGraphTFTDisplay::DisplayReplayCurrent(int x, int y, int width, int height,int red, int green, int blue, int transperents, string font, int size, int align, int lines)
{
	int current, total;
	if (_replay.control && _replay.control->GetIndex(current, total)) {
		if (total == 0 && current == 0)
			current = total = 1;
		DisplayText(x, y, width, height, red, green, blue, transperents, font, size, align, lines, *IndexToHMSF(current));
	}
}

void cGraphTFTDisplay::DisplayReplayTotal(int x, int y, int width, int height,int red, int green, int blue, int transperents, string font, int size, int align, int lines)
{
	int current, total;
	if (_replay.control && _replay.control->GetIndex(current, total)) {
		if (total == 0 && current == 0)
			current = total = 1;
		else if (total == 0)
			total = current;
		DisplayText( x, y, width, height, red, green, blue, transperents, font, size, align, lines, *IndexToHMSF(total));
	}
}

void cGraphTFTDisplay::DisplayReplayRemaining(int x, int y, int width, int height,int red, int green, int blue, int transperents, string font, int size, int align, int lines)
{
	int current, total;
	if (_replay.control && _replay.control->GetIndex(current, total)) {
		if (total == 0 && current == 0)
			current = total = 1;
		else if (total == 0)
			total = current;
		DisplayText( x, y, width, height, red, green, blue, transperents, font, size, align, lines, (string)"-" + *IndexToHMSF(total - current));
	}
}
