/*
 * skinclassic.c: The 'classic' VDR skin
 *
 * See the main source file 'vdr.c' for copyright information and
 * how to reach the author.
 *
 * $Id: skinclassic.c 1.11 2005/01/09 11:56:29 kls Exp $
 */

#include "skinclassic8col.h"
#include "common.h"
#include <vdr/font.h>
#include <vdr/i18n.h>
#include <vdr/osd.h>
#include <vdr/themes.h>

#define ScrollWidth  5

#define EMCOLOR_BACKGROUND    clrBlack
#define EMCOLOR_BACKGROUND2      clrGray50

static cTheme Theme4col;

THEME_CLR(Theme4col, clrButtonGreenFgNew,       clrBlack);
THEME_CLR(Theme4col, clrButtonYellowFgNew,      clrBlack);
THEME_CLR(Theme4col, clrButtonBlueFgNew,        clrBlack);
THEME_CLR(Theme4col, clrButtonRedFgNew,         clrBlack);
THEME_CLR(Theme4col, clrChannelEpgTimeBgNew,    clrRed);
THEME_CLR(Theme4col, clrChannelBackgroundNew,   clrGray50);
THEME_CLR(Theme4col, clrVolumePromptNew,        clrCyan);
THEME_CLR(Theme4col, clrVolumeBarUpperNew,      clrWhite);
THEME_CLR(Theme4col, clrVolumeBarLowerNew,      clrCyan);
THEME_CLR(Theme4col, clrVolumeBackgroundNew,    clrGray50);
THEME_CLR(Theme4col, clrMenuBackgroundNew,      clrGray50);
THEME_CLR(Theme4col, clrTracksBackgroundNew,    clrGray50);
THEME_CLR(Theme4col, clrReplayBackgroundNew,    clrGray50);
THEME_CLR(Theme4col, clrReplayProgressMarkNew,  clrRed);
THEME_CLR(Theme4col, clrReplayProgressCurrentNew,  clrRed);
THEME_CLR(Theme4col, clrMessageNewFg,           clrBlack);
THEME_CLR(Theme4col, clrMessageNewBg,           clrCyan);

THEME_CLR(Theme4col, clrButtonGreenBgNew,       clrGreen);
THEME_CLR(Theme4col, clrButtonYellowBgNew,      clrYellow);
THEME_CLR(Theme4col, clrButtonRedBgNew,         clrRed);

THEME_CLR(Theme4col, clrBackground,             clrBlack);
THEME_CLR(Theme4col, clrButtonRedFg,            clrBlack);
THEME_CLR(Theme4col, clrButtonRedBg,            clrCyan);
THEME_CLR(Theme4col, clrButtonGreenFg,          clrBlack);
THEME_CLR(Theme4col, clrButtonYellowFg,         clrBlack);
THEME_CLR(Theme4col, clrButtonYellowBg,         clrCyan);
THEME_CLR(Theme4col, clrButtonBlueFg,           clrBlack);
THEME_CLR(Theme4col, clrButtonBlueBg,           clrCyan);
THEME_CLR(Theme4col, clrMessageStatusFg,        clrWhite);
THEME_CLR(Theme4col, clrMessageStatusBg,        clrCyan);
THEME_CLR(Theme4col, clrMessageInfoFg,          clrWhite);
THEME_CLR(Theme4col, clrMessageInfoBg,          clrCyan);
THEME_CLR(Theme4col, clrMessageWarningFg,       clrWhite);
THEME_CLR(Theme4col, clrMessageWarningBg,       clrCyan);
THEME_CLR(Theme4col, clrMessageErrorFg,         clrWhite);
THEME_CLR(Theme4col, clrMessageErrorBg,         clrCyan);
THEME_CLR(Theme4col, clrVolumePrompt,           clrCyan);
THEME_CLR(Theme4col, clrVolumeBarUpper,         clrCyan);
THEME_CLR(Theme4col, clrVolumeBarLower,         clrWhite);
THEME_CLR(Theme4col, clrChannelName,            clrWhite);
THEME_CLR(Theme4col, clrChannelDate,            clrWhite);
THEME_CLR(Theme4col, clrChannelEpgTimeFg,       clrWhite);
THEME_CLR(Theme4col, clrChannelEpgTimeBg,       clrRed);
THEME_CLR(Theme4col, clrChannelEpgTitle,        clrCyan);
THEME_CLR(Theme4col, clrChannelEpgShortText,    clrWhite);
THEME_CLR(Theme4col, clrMenuTitleFg,            clrBlack);
THEME_CLR(Theme4col, clrMenuTitleBg,            clrCyan);
THEME_CLR(Theme4col, clrMenuDate,               clrBlack);
THEME_CLR(Theme4col, clrMenuItemCurrentFg,      clrBlack);
THEME_CLR(Theme4col, clrMenuItemCurrentBg,      clrCyan);
THEME_CLR(Theme4col, clrMenuItemSelectable,     clrWhite);
THEME_CLR(Theme4col, clrMenuItemNonSelectable,  clrCyan);
THEME_CLR(Theme4col, clrMenuEventTime,          clrWhite);
THEME_CLR(Theme4col, clrMenuEventVpsFg,         clrBlack);
THEME_CLR(Theme4col, clrMenuEventVpsBg,         clrWhite);
THEME_CLR(Theme4col, clrMenuEventTitle,         clrCyan);
THEME_CLR(Theme4col, clrMenuEventShortText,     clrWhite);
THEME_CLR(Theme4col, clrMenuEventDescription,   clrCyan);
THEME_CLR(Theme4col, clrMenuScrollbarTotal,     clrWhite);
THEME_CLR(Theme4col, clrMenuScrollbarShown,     clrCyan);
THEME_CLR(Theme4col, clrMenuText,               clrWhite);
THEME_CLR(Theme4col, clrReplayTitle,            clrWhite);
THEME_CLR(Theme4col, clrReplayCurrent,          clrWhite);
THEME_CLR(Theme4col, clrReplayTotal,            clrWhite);
THEME_CLR(Theme4col, clrReplayModeJump,         clrWhite);
THEME_CLR(Theme4col, clrReplayProgressSeen,     clrCyan);
THEME_CLR(Theme4col, clrReplayProgressRest,     clrWhite);
THEME_CLR(Theme4col, clrReplayProgressSelected, clrCyan);
THEME_CLR(Theme4col, clrReplayProgressMark,     clrGreen);
THEME_CLR(Theme4col, clrReplayProgressCurrent,  clrCyan);


// --- cSkinClassicDisplayChannel --------------------------------------------

class cSkinClassic8colDisplayChannel : public cSkinDisplayChannel {
private:
   cOsd *osd;
   int lineHeight;
   int timeWidth;
   bool message;
public:
   cSkinClassic8colDisplayChannel(bool WithInfo);
   virtual ~cSkinClassic8colDisplayChannel();
   virtual void SetChannel(const cChannel *Channel, int Number);
   virtual void SetEvents(const cEvent *Present, const cEvent *Following);
   virtual void SetMessage(eMessageType Type, const char *Text);
   virtual void Flush(void);
};

cSkinClassic8colDisplayChannel::cSkinClassic8colDisplayChannel(bool WithInfo)
{
   int Lines = WithInfo ? 5 : 1;
   const cFont *font = cFont::GetFont(fontOsd);
   lineHeight = font->Height();
   message = false;
   osd = cOsdProvider::NewOsd(Setup.OSDLeft, Setup.OSDTop + (Setup.ChannelInfoPos ? 0 : Setup.OSDHeight - Lines * lineHeight));
   timeWidth = font->Width("00:00") + 4;
   tArea Areas[] = { { 0, 0, Setup.OSDWidth - 1, Lines * lineHeight - 1, 2}};
   osd->SetAreas(Areas, sizeof(Areas) / sizeof(tArea));
   osd->DrawRectangle(0, 0, osd->Width() - 1, osd->Height() - 1, Theme4col.Color(clrChannelBackgroundNew));
}

cSkinClassic8colDisplayChannel::~cSkinClassic8colDisplayChannel()
{
   delete osd;
}

void cSkinClassic8colDisplayChannel::SetChannel(const cChannel *Channel, int Number)
{
   osd->DrawRectangle(0, 0, osd->Width() - 1, lineHeight - 1, Theme4col.Color(clrChannelBackgroundNew));
   osd->DrawText(2, 0, ChannelString(Channel, Number), Theme4col.Color(clrChannelName), Theme4col.Color(clrChannelBackgroundNew), cFont::GetFont(fontOsd));
}

/*void cSkinClassic8colDisplayChannel::SetEvents(const cEvent *Present, const cEvent *Following)
{
  int duration = -1;

  osd->DrawRectangle(0, lineHeight, timeWidth - 1, osd->Height(), Theme4col.Color(clrChannelEpgTimeBgNew));
  osd->DrawRectangle(timeWidth, lineHeight, osd->Width() - 1, osd->Height(), Theme4col.Color(clrChannelBackgroundNew));
  for (int i = 0; i < 2; i++)
  {
    const cEvent *e = !i ? Present : Following;
    if (e)
    {
      if (i==0)
        duration= int((osd->Height() - lineHeight) * difftime(time(NULL), e->StartTime()) / e->Duration() );

      osd->DrawText(             2, (2 * i + 1) * lineHeight, e->GetTimeString(), Theme4col.Color(clrChannelEpgTimeFg), Theme4col.Color(clrChannelEpgTimeBgNew), cFont::GetFont(fontOsd));
      osd->DrawText(timeWidth + 10, (2 * i + 1) * lineHeight, e->Title(), Theme4col.Color(clrChannelEpgTitle), Theme4col.Color(clrChannelBackgroundNew), cFont::GetFont(fontOsd));
      osd->DrawText(timeWidth + 10, (2 * i + 2) * lineHeight, e->ShortText(), Theme4col.Color(clrChannelEpgShortText), Theme4col.Color(clrChannelBackgroundNew), cFont::GetFont(fontSml));
    }
  }
  if (duration > -1)
  {
    osd->DrawRectangle(timeWidth + 3, lineHeight, timeWidth + 10, osd->Height() , Theme4col.Color(clrChannelEpgTimeBgNew));
    osd->DrawRectangle(timeWidth + 4, lineHeight + 1 + duration, timeWidth + 8, osd->Height() - 2, Theme4col.Color(clrChannelBackgroundNew));
  }
}*/

void cSkinClassic8colDisplayChannel::SetEvents(const cEvent *Present, const cEvent *Following)
{
   osd->DrawRectangle(0, lineHeight, timeWidth - 1, osd->Height(), Theme4col.Color(clrChannelEpgTimeBgNew));
   osd->DrawRectangle(timeWidth, lineHeight, osd->Width() - 1, osd->Height(), Theme4col.Color(clrChannelBackgroundNew));
   int duration = -1;
   for (int i = 0; i < 2; i++) {
      const cEvent *e = !i ? Present : Following;
      if (e) {
         if (i==0) duration= int((osd->Height() - lineHeight) * difftime(time(NULL), e->StartTime()) / e->Duration() );
         osd->DrawText(             2, (2 * i + 1) * lineHeight, e->GetTimeString(), Theme4col.Color(clrChannelEpgTimeFg), Theme4col.Color(clrChannelEpgTimeBgNew), cFont::GetFont(fontOsd));
         osd->DrawText(timeWidth + 20, (2 * i + 1) * lineHeight, e->Title(), Theme4col.Color(clrChannelEpgTitle), Theme4col.Color(clrChannelBackgroundNew), cFont::GetFont(fontOsd));
         osd->DrawText(timeWidth + 20, (2 * i + 2) * lineHeight, e->ShortText(), Theme4col.Color(clrChannelEpgShortText), Theme4col.Color(clrChannelBackgroundNew), cFont::GetFont(fontSml));
      }
   }
   if (duration > -1) {
      osd->DrawRectangle(timeWidth + 3, lineHeight, timeWidth + 10, osd->Height() , Theme4col.Color(clrChannelEpgTimeBgNew));
      osd->DrawRectangle(timeWidth + 4, lineHeight + 1 + duration, timeWidth + 8, osd->Height() - 2, Theme4col.Color(clrChannelBackgroundNew));
   }
}

void cSkinClassic8colDisplayChannel::SetMessage(eMessageType Type, const char *Text)
{
   const cFont *font = cFont::GetFont(fontOsd);
   if (Text) {
      osd->SaveRegion(0, 0, osd->Width() - 1, lineHeight - 1);
      osd->DrawText(0, 0, Text, Theme4col.Color(clrMessageNewFg), Theme4col.Color(clrMessageNewBg), font, osd->Width(), 0, taCenter);
      //osd->DrawText(0, 0, Text, Theme4col.Color(clrMessageStatusFg + 2 * Type), Theme4col.Color(clrMessageStatusBg + 2 * Type), font, osd->Width(), 0, taCenter);
      message = true;
   }
   else {
      osd->RestoreRegion();
      message = false;
   }
}

void cSkinClassic8colDisplayChannel::Flush(void)
{
   if (!message) {
      cString date = DayDateTime();
      osd->DrawText(osd->Width() - cFont::GetFont(fontSml)->Width(date) - 2, 0, date, Theme4col.Color(clrChannelDate), Theme4col.Color(clrChannelBackgroundNew), cFont::GetFont(fontSml));
   }
   osd->Flush();
}

// --- cSkinClassicDisplayMenu -----------------------------------------------

class cSkinClassic8colDisplayMenu : public cSkinDisplayMenu {
private:
   cOsd *osd;
   int x0, x1;
   int y0, y1, y2, y3, y4, y5;
   int lineHeight;
   void SetScrollbar(void);
public:
   cSkinClassic8colDisplayMenu(void);
   virtual ~cSkinClassic8colDisplayMenu();
   virtual void Scroll(bool Up, bool Page);
   virtual int MaxItems(void);
   virtual void Clear(void);
   virtual void SetTitle(const char *Title);
   virtual void SetButtons(const char *Red, const char *Green = NULL, const char *Yellow = NULL, const char *Blue = NULL);
   virtual void SetMessage(eMessageType Type, const char *Text);
   virtual void SetItem(const char *Text, int Index, bool Current, bool Selectable);
   virtual void SetEvent(const cEvent *Event);
   virtual void SetRecording(const cRecording *Recording);
   virtual void SetText(const char *Text, bool FixedFont);
   virtual void Flush(void);
};

cSkinClassic8colDisplayMenu::cSkinClassic8colDisplayMenu(void)
{
//  int widthsizer = 1;
//  int heightsizer = 1;

   int xdif,ydif;
   const cFont *font = cFont::GetFont(fontOsd);
   lineHeight = font->Height();
   xdif = 0;
   ydif = 0;
   x0 = 0;
   x1 = Setup.OSDWidth;
   y0 = 0;
   y1 = lineHeight;
   y2 = y1 + lineHeight;
   y5 = Setup.OSDHeight;
   y4 = y5 - lineHeight;
   y3 = y4 - lineHeight;


   // WIDTH HEIGHT STRATEGY
//  if ((x1*y5) > (500*320)) {
//     while (((x1*y5) > (500*320)) || ((widthsizer > 0) && (x1%4 != 0))) {
//        y5 -= heightsizer;
//        x1 -= widthsizer;
//     }
//
//     y4 = y5 - lineHeight;
//     y3 = y4 - lineHeight;
//
//     xdif = (Setup.OSDWidth - x1)/2;
//     ydif = (Setup.OSDHeight - y5)/2;
//  }

   osd = cOsdProvider::NewOsd(Setup.OSDLeft+xdif, Setup.OSDTop+ydif);
   tArea Areas[] = { { x0, y0, x1 - 1, y5 - 1, 4 } };

   Dprintf("1st area at %d %d %d %d(x1,y1,x2,y2)\n",x0, y0, x1 - 1, y5 - 1);

   /*if (osd->CanHandleAreas(Areas, sizeof(Areas) / sizeof(tArea)) == oeOk)
      osd->SetAreas(Areas, sizeof(Areas) / sizeof(tArea));
   else {
      tArea Areas[] = { { x0, y0, x1 - 1, y1 - 1, 2 },
                        { x0, y1, x1 - 1, y3 - 1, 2 },
                        { x0, y3, x1 - 1, y5 - 1, 4 }
                      };
      osd->SetAreas(Areas, sizeof(Areas) / sizeof(tArea));
      }*/
   osd->SetAreas(Areas, sizeof(Areas) / sizeof(tArea));
   osd->DrawRectangle(x0, y0, x1 - 1, y5 - 1, Theme4col.Color(clrMenuBackgroundNew));
}

cSkinClassic8colDisplayMenu::~cSkinClassic8colDisplayMenu()
{
   delete osd;
}

void cSkinClassic8colDisplayMenu::SetScrollbar(void)
{
   if (textScroller.CanScroll()) {
      int yt = textScroller.Top();
      int yb = yt + textScroller.Height();
      int st = yt;
      int sb = yb;
      int tt = st + (sb - st) * textScroller.Offset() / textScroller.Total();
      int tb = tt + (sb - st) * textScroller.Shown() / textScroller.Total();
      int xl = x1 - ScrollWidth;
      osd->DrawRectangle(xl, st, x1 - 1, sb, Theme4col.Color(clrMenuScrollbarTotal));
      osd->DrawRectangle(xl, tt, x1 - 1, tb, Theme4col.Color(clrMenuScrollbarShown));
   }
}

void cSkinClassic8colDisplayMenu::Scroll(bool Up, bool Page)
{
   cSkinDisplayMenu::Scroll(Up, Page);
   SetScrollbar();
}

int cSkinClassic8colDisplayMenu::MaxItems(void)
{
   return(y3 - y2) / lineHeight;
}

void cSkinClassic8colDisplayMenu::Clear(void)
{
   textScroller.Reset();
   osd->DrawRectangle(x0, y1, x1 - 1, y4 - 1, Theme4col.Color(clrMenuBackgroundNew));
}

void cSkinClassic8colDisplayMenu::SetTitle(const char *Title)
{
   const cFont *font = cFont::GetFont(fontOsd);
   osd->DrawText(x0, y0, Title, Theme4col.Color(clrMenuTitleFg), Theme4col.Color(clrMenuTitleBg), font, x1 - x0);
}

void cSkinClassic8colDisplayMenu::SetButtons(const char *Red, const char *Green, const char *Yellow, const char *Blue)
{
   const cFont *font = cFont::GetFont(fontOsd);
   int w = x1 - x0;
   int t0 = x0;
   int t1 = x0 + w / 4;
   int t2 = x0 + w / 2;
   int t3 = x1 - w / 4;
   int t4 = x1;

   if (Red)
      osd->DrawText(t0, y5, Red,    Theme4col.Color(clrButtonRedFgNew),    Theme4col.Color(clrButtonRedBgNew), font, t1 - t0, 0, taCenter);
//else
//  osd->DrawRectangle(t0, y4, x1 - 1, t1 - 1, Theme4col.Color(clrButtonRedFgNew));
   if (Green)
      osd->DrawText(t1, y5, Green,  Theme4col.Color(clrButtonGreenFgNew),  Theme4col.Color(clrButtonGreenBgNew) , font, t2 - t1, 0, taCenter);
//else
//  osd->DrawRectangle(t1, y4, x1 - 1, t2 - 1, Theme4col.Color(clrButtonGreenFgNew));
   if (Yellow)
      osd->DrawText(t2, y5, Yellow, Theme4col.Color(clrButtonYellowFgNew), Theme4col.Color(clrButtonYellowBgNew), font, t3 - t2, 0, taCenter);
//else
//  osd->DrawRectangle(t2, y4, x1 - 1, t3 - 1, Theme4col.Color(clrButtonYellowFgNew));
   if (Blue)
      osd->DrawText(t3, y4, Blue,   Theme4col.Color(clrButtonBlueFgNew),   Theme4col.Color(clrButtonBlueBg) , font, t4 - t3, 0, taCenter);
//else
//  osd->DrawRectangle(t3, y4, x1 - 1, y5 - 1, Theme4col.Color(clrButtonBlueFgNew));
}

void cSkinClassic8colDisplayMenu::SetMessage(eMessageType Type, const char *Text)
{
   const cFont *font = cFont::GetFont(fontOsd);
   if (Text)
      osd->DrawText(x0, y3, Text, Theme4col.Color(clrMessageNewFg), Theme4col.Color(clrMessageNewBg), font, x1 - x0, 0, taCenter);
   //osd->DrawText(x0, y3, Text, Theme4col.Color(clrMessageStatusFg + 2 * Type), Theme4col.Color(clrMessageStatusBg + 2 * Type), font, x1 - x0, 0, taCenter);

   else
      osd->DrawRectangle(x0, y3, x1 - 1, y4 - 1, Theme4col.Color(clrMenuBackgroundNew));

}

void cSkinClassic8colDisplayMenu::SetItem(const char *Text, int Index, bool Current, bool Selectable)
{
   int y = y2 + Index * lineHeight;
   tColor ColorFg, ColorBg;
   if (Current) {
      ColorFg = Theme4col.Color(clrMenuItemCurrentFg);
      ColorBg = Theme4col.Color(clrMenuItemCurrentBg);
   }
   else {
      ColorFg = Theme4col.Color(Selectable ? clrMenuItemSelectable : clrMenuItemNonSelectable);
      ColorBg = Theme4col.Color(clrMenuBackgroundNew);
   }
   const cFont *font = cFont::GetFont(fontOsd);
   for (int i = 0; i < MaxTabs; i++) {
      const char *s = GetTabbedText(Text, i);
      if (s) {
         int xt = x0 + Tab(i);
         osd->DrawText(xt, y, s, ColorFg, ColorBg, font, x1 - xt);
      }
      if (!Tab(i + 1))
         break;
   }
   SetEditableWidth(x1 - x0 - Tab(1));
}

void cSkinClassic8colDisplayMenu::SetEvent(const cEvent *Event)
{
   if (!Event)
      return;
   const cFont *font = cFont::GetFont(fontOsd);
   int xl = x0 + 10;
   int y = y2;
   cTextScroller ts;
   char t[32];
   snprintf(t, sizeof(t), "%s  %s - %s", *Event->GetDateString(), *Event->GetTimeString(), *Event->GetEndTimeString());
   ts.Set(osd, xl, y, x1 - xl, y3 - y, t, font, Theme4col.Color(clrMenuEventTime), Theme4col.Color(clrMenuBackgroundNew));
   if (Event->Vps() && Event->Vps() != Event->StartTime()) {
      char *buffer;
      asprintf(&buffer, " VPS: %s", *Event->GetVpsString());
      const cFont *font = cFont::GetFont(fontSml);
      osd->DrawText(x1 - font->Width(buffer), y, buffer, Theme4col.Color(clrMenuEventVpsFg), Theme4col.Color(clrMenuEventVpsBg), font);
      free(buffer);
   }
   y += ts.Height();
   y += font->Height();
   ts.Set(osd, xl, y, x1 - xl, y3 - y, Event->Title(), font, Theme4col.Color(clrMenuEventTitle), Theme4col.Color(clrMenuBackgroundNew));
   y += ts.Height();
   if (!isempty(Event->ShortText())) {
      const cFont *font = cFont::GetFont(fontSml);
      ts.Set(osd, xl, y, x1 - xl, y3 - y, Event->ShortText(), font, Theme4col.Color(clrMenuEventShortText), Theme4col.Color(clrMenuBackgroundNew));
      y += ts.Height();
   }
   y += font->Height();
   if (!isempty(Event->Description())) {
      textScroller.Set(osd, xl, y, x1 - xl - 2 * ScrollWidth, y3 - y, Event->Description(), font, Theme4col.Color(clrMenuEventDescription), Theme4col.Color(clrMenuBackgroundNew));
      SetScrollbar();
   }
}

void cSkinClassic8colDisplayMenu::SetRecording(const cRecording *Recording)
{
   // added new recodringinfo-support from VDR >= 1.3.25
#if VDRVERSNUM <= 10324
   SetText(Recording->Summary(), false); //TODO
#else
   if (!Recording)
      return;
   const cRecordingInfo *Info = Recording->Info();
   const cFont *font = cFont::GetFont(fontOsd);
   int xl = x0 + 10;
   int y = y2;
   cTextScroller ts;
   char t[32];
   snprintf(t, sizeof(t), "%s  %s", *DateString(Recording->start), *TimeString(Recording->start));
   ts.Set(osd, xl, y, x1 - xl, y3 - y, t, font, Theme4col.Color(clrMenuEventTime), Theme4col.Color(clrMenuBackgroundNew));
   y += ts.Height();
   y += font->Height();
   const char *Title = Info->Title();
   if (isempty(Title))
      Title = Recording->Name();
   ts.Set(osd, xl, y, x1 - xl, y3 - y, Title, font, Theme4col.Color(clrMenuEventTitle), Theme4col.Color(clrMenuBackgroundNew));
   y += ts.Height();
   if (!isempty(Info->ShortText())) {
      const cFont *font = cFont::GetFont(fontSml);
      ts.Set(osd, xl, y, x1 - xl, y3 - y, Info->ShortText(), font, Theme4col.Color(clrMenuEventShortText), Theme4col.Color(clrMenuBackgroundNew));
      y += ts.Height();
   }
   y += font->Height();
   if (!isempty(Info->Description())) {
      textScroller.Set(osd, xl, y, x1 - xl - 2 * ScrollWidth, y3 - y, Info->Description(), font, Theme4col.Color(clrMenuEventDescription), Theme4col.Color(clrMenuBackgroundNew));
      SetScrollbar();
   }
#endif
}

void cSkinClassic8colDisplayMenu::SetText(const char *Text, bool FixedFont)
{
   const cFont *font = cFont::GetFont(fontOsd);//FixedFont ? fontFix : fontOsd);
   textScroller.Set(osd, x0, y2, x1 - x0 - 2 * ScrollWidth, y3 - y2, Text, font, Theme4col.Color(clrMenuText), Theme4col.Color(clrMenuBackgroundNew));
   SetScrollbar();
}

void cSkinClassic8colDisplayMenu::Flush(void)
{
   cString date = DayDateTime();
   const cFont *font = cFont::GetFont(fontOsd);
   osd->DrawText(x1 - font->Width(date) - 2, y0, date, Theme4col.Color(clrMenuDate), Theme4col.Color(clrMenuTitleBg), font);
   osd->Flush();
}

// --- cSkinClassicDisplayReplay ---------------------------------------------

class cSkinClassic8colDisplayReplay : public cSkinDisplayReplay {
private:
   cOsd *osd;
   int x0, x1;
   int y0, y1, y2, y3;
   int lastCurrentWidth;
   bool message;
public:
   cSkinClassic8colDisplayReplay(bool ModeOnly);
   virtual ~cSkinClassic8colDisplayReplay();
   virtual void SetTitle(const char *Title);
   virtual void SetMode(bool Play, bool Forward, int Speed);
   virtual void SetProgress(int Current, int Total);
   virtual void SetCurrent(const char *Current);
   virtual void SetTotal(const char *Total);
   virtual void SetJump(const char *Jump);
   virtual void SetMessage(eMessageType Type, const char *Text);
   virtual void Flush(void);
};

cSkinClassic8colDisplayReplay::cSkinClassic8colDisplayReplay(bool ModeOnly)
{
   const cFont *font = cFont::GetFont(fontOsd);
   int lineHeight = font->Height();
   lastCurrentWidth = 0;
   message = false;
   x0 = 0;
   x1 = Setup.OSDWidth;
   y0 = 0;
   y1 = lineHeight;
   y2 = 2 * lineHeight;
   y3 = 3 * lineHeight;
   osd = cOsdProvider::NewOsd(Setup.OSDLeft, Setup.OSDTop + Setup.OSDHeight - y3);
   tArea Areas[] = { { x0, y0, x1 - 1, y3 - 1, 2}};
   osd->SetAreas(Areas, sizeof(Areas) / sizeof(tArea));
   osd->DrawRectangle(x0, y0, x1 - 1, y3 - 1, ModeOnly ? clrTransparent : Theme4col.Color(clrReplayBackgroundNew));
}

cSkinClassic8colDisplayReplay::~cSkinClassic8colDisplayReplay()
{
   delete osd;
}

void cSkinClassic8colDisplayReplay::SetTitle(const char *Title)
{
   osd->DrawText(x0, y0, Title, Theme4col.Color(clrReplayTitle), Theme4col.Color(clrReplayBackgroundNew), cFont::GetFont(fontOsd), x1 - x0);
}

void cSkinClassic8colDisplayReplay::SetMode(bool Play, bool Forward, int Speed)
{
   if (Setup.ShowReplayMode) {
      const char *Mode;
      if (Speed == -1) Mode = Play    ? "  >  " : " ||  ";
      else if (Play)   Mode = Forward ? " X>> " : " <<X ";
      else             Mode = Forward ? " X|> " : " <|X ";
      char buf[16];
      strn0cpy(buf, Mode, sizeof(buf));
      char *p = strchr(buf, 'X');
      if (p)
         *p = Speed > 0 ? '1' + Speed - 1 : ' ';
      SetJump(buf);
   }
}

void cSkinClassic8colDisplayReplay::SetProgress(int Current, int Total)
{
   cProgressBar pb(x1 - x0, y2 - y1, Current, Total, marks, Theme4col.Color(clrReplayProgressSeen), Theme4col.Color(clrReplayProgressRest), Theme4col.Color(clrReplayProgressSelected), Theme4col.Color(clrReplayProgressMarkNew), Theme4col.Color(clrReplayProgressCurrentNew));
   osd->DrawBitmap(x0, y1, pb);
}

void cSkinClassic8colDisplayReplay::SetCurrent(const char *Current)
{
   const cFont *font = cFont::GetFont(fontOsd);
   int w = font->Width(Current);
   osd->DrawText(x0, y2, Current, Theme4col.Color(clrReplayCurrent), Theme4col.Color(clrReplayBackgroundNew), font, lastCurrentWidth > w ? lastCurrentWidth : 0);
   lastCurrentWidth = w;
}

void cSkinClassic8colDisplayReplay::SetTotal(const char *Total)
{
   const cFont *font = cFont::GetFont(fontOsd);
   osd->DrawText(x1 - font->Width(Total), y2, Total, Theme4col.Color(clrReplayTotal), Theme4col.Color(clrReplayBackgroundNew), font);
}

void cSkinClassic8colDisplayReplay::SetJump(const char *Jump)
{
   osd->DrawText(x0 + (x1 - x0) / 4, y2, Jump, Theme4col.Color(clrReplayModeJump), Theme4col.Color(clrReplayBackgroundNew), cFont::GetFont(fontOsd), (x1 - x0) / 2, 0, taCenter);
}

void cSkinClassic8colDisplayReplay::SetMessage(eMessageType Type, const char *Text)
{
   const cFont *font = cFont::GetFont(fontOsd);
   if (Text) {
      osd->SaveRegion(x0, y2, x1 - 1, y3 - 1);
      osd->DrawText(x0, y2, Text, Theme4col.Color(clrMessageNewFg), Theme4col.Color(clrMessageNewBg), font, x1 - x0, y3 - y2, taCenter);
      //osd->DrawText(x0, y2, Text, Theme4col.Color(clrMessageStatusFg + 2 * Type), Theme4col.Color(clrMessageStatusBg + 2 * Type), font, x1 - x0, y3 - y2, taCenter);
      message = true;
   }
   else {
      osd->RestoreRegion();
      message = false;
   }
}

void cSkinClassic8colDisplayReplay::Flush(void)
{
   osd->Flush();
}

// --- cSkinClassicDisplayVolume ---------------------------------------------

class cSkinClassic8colDisplayVolume : public cSkinDisplayVolume {
private:
   cOsd *osd;
public:
   cSkinClassic8colDisplayVolume(void);
   virtual ~cSkinClassic8colDisplayVolume();
   virtual void SetVolume(int Current, int Total, bool Mute);
   virtual void Flush(void);
};

cSkinClassic8colDisplayVolume::cSkinClassic8colDisplayVolume(void)
{
   const cFont *font = cFont::GetFont(fontOsd);
   int lineHeight = font->Height();
   osd = cOsdProvider::NewOsd(Setup.OSDLeft, Setup.OSDTop + Setup.OSDHeight - lineHeight);
   tArea Areas[] = { { 0, 0, Setup.OSDWidth - 1, lineHeight - 1, 2}};
   osd->SetAreas(Areas, sizeof(Areas) / sizeof(tArea));
}

cSkinClassic8colDisplayVolume::~cSkinClassic8colDisplayVolume()
{
   delete osd;
}

void cSkinClassic8colDisplayVolume::SetVolume(int Current, int Total, bool Mute)
{
   const cFont *font = cFont::GetFont(fontOsd);
   if (Mute) {
      osd->DrawRectangle(0, 0, osd->Width() - 1, osd->Height() - 1, clrTransparent);
      osd->DrawText(0, 0, tr("Mute"), Theme4col.Color(clrVolumePromptNew), Theme4col.Color(clrVolumeBackgroundNew), font);
   }
   else {
      const char *Prompt = tr("Volume ");
      int l = font->Width(Prompt);
      int p = (osd->Width() - l) * Current / Total;
      osd->DrawText(0, 0, Prompt, Theme4col.Color(clrVolumePromptNew), Theme4col.Color(clrVolumeBackgroundNew), font);
      osd->DrawRectangle(l, 0, l + p - 1, osd->Height() - 1, Theme4col.Color(clrVolumeBarLowerNew));
      osd->DrawRectangle(l + p, 0, osd->Width() - 1, osd->Height() - 1, Theme4col.Color(clrVolumeBarUpperNew));
   }
}

void cSkinClassic8colDisplayVolume::Flush(void)
{
   osd->Flush();
}

// --- cSkinClassicDisplayTracks ---------------------------------------------

class cSkinClassic8colDisplayTracks : public cSkinDisplayTracks {
private:
   cOsd *osd;
   int x0, x1;
   int y0, y1, y2;
   int lineHeight;
   int currentIndex;
   void SetItem(const char *Text, int Index, bool Current);
public:
   cSkinClassic8colDisplayTracks(const char *Title, int NumTracks, const char * const *Tracks);
   virtual ~cSkinClassic8colDisplayTracks();
   virtual void SetTrack(int Index, const char * const *Tracks);
   virtual void SetAudioChannel(int AudioChannel) {}
   virtual void Flush(void);
};

cSkinClassic8colDisplayTracks::cSkinClassic8colDisplayTracks(const char *Title, int NumTracks, const char * const *Tracks)
{
   const cFont *font = cFont::GetFont(fontOsd);
   lineHeight = font->Height();
   currentIndex = -1;
   int ItemsWidth = font->Width(Title);
   for (int i = 0; i < NumTracks; i++)
      ItemsWidth = max(ItemsWidth, font->Width(Tracks[i]));
   ItemsWidth += 10;
   x0 = 0;
   x1 = Setup.OSDWidth;
   int d = x1 - x0;
   if (d > ItemsWidth) {
      d = (d - ItemsWidth) & ~0x07; // must be multiple of 8
      x1 -= d;
   }
   y0 = 0;
   y1 = lineHeight;
   y2 = y1 + NumTracks * lineHeight;
   osd = cOsdProvider::NewOsd(Setup.OSDLeft, Setup.OSDTop + Setup.OSDHeight - y2);
   tArea Areas[] = { { x0, y0, x1 - 1, y2 - 1, 2}};
   osd->SetAreas(Areas, sizeof(Areas) / sizeof(tArea));
   osd->DrawText(x0, y0, Title, Theme4col.Color(clrMenuTitleFg), Theme4col.Color(clrMenuTitleBg), font, x1 - x0);
   for (int i = 0; i < NumTracks; i++)
      SetItem(Tracks[i], i, false);
}

cSkinClassic8colDisplayTracks::~cSkinClassic8colDisplayTracks()
{
   delete osd;
}

void cSkinClassic8colDisplayTracks::SetItem(const char *Text, int Index, bool Current)
{
   int y = y1 + Index * lineHeight;
   tColor ColorFg, ColorBg;
   if (Current) {
      ColorFg = Theme4col.Color(clrMenuItemCurrentFg);
      ColorBg = Theme4col.Color(clrMenuItemCurrentBg);
      currentIndex = Index;
   }
   else {
      ColorFg = Theme4col.Color(clrMenuItemSelectable);
      ColorBg = Theme4col.Color(clrTracksBackgroundNew);
   }
   const cFont *font = cFont::GetFont(fontOsd);
   osd->DrawText(x0, y, Text, ColorFg, ColorBg, font, x1 - x0);
}

void cSkinClassic8colDisplayTracks::SetTrack(int Index, const char * const *Tracks)
{
   if (currentIndex >= 0)
      SetItem(Tracks[currentIndex], currentIndex, false);
   SetItem(Tracks[Index], Index, true);
}

void cSkinClassic8colDisplayTracks::Flush(void)
{
   osd->Flush();
}

// --- cSkinClassicDisplayMessage --------------------------------------------

class cSkinClassic8colDisplayMessage : public cSkinDisplayMessage {
private:
   cOsd *osd;
public:
   cSkinClassic8colDisplayMessage(void);
   virtual ~cSkinClassic8colDisplayMessage();
   virtual void SetMessage(eMessageType Type, const char *Text);
   virtual void Flush(void);
};

cSkinClassic8colDisplayMessage::cSkinClassic8colDisplayMessage(void)
{
   const cFont *font = cFont::GetFont(fontOsd);
   int lineHeight = font->Height();
   osd = cOsdProvider::NewOsd(Setup.OSDLeft, Setup.OSDTop + Setup.OSDHeight - lineHeight);
   tArea Areas[] = { { 0, 0, Setup.OSDWidth - 1, lineHeight - 1, 2}};
   osd->SetAreas(Areas, sizeof(Areas) / sizeof(tArea));
}

cSkinClassic8colDisplayMessage::~cSkinClassic8colDisplayMessage()
{
   delete osd;
}

void cSkinClassic8colDisplayMessage::SetMessage(eMessageType Type, const char *Text)
{
   const cFont *font = cFont::GetFont(fontOsd);
   osd->DrawText(0, 0, Text, Theme4col.Color(clrMessageNewFg), Theme4col.Color(clrMessageNewBg), font, Setup.OSDWidth, 0, taCenter);
//  osd->DrawText(0, 0, Text, Theme4col.Color(clrMessageStatusFg + 2 * Type), Theme4col.Color(clrMessageStatusBg + 2 * Type), font, Setup.OSDWidth, 0, taCenter);
}

void cSkinClassic8colDisplayMessage::Flush(void)
{
   osd->Flush();
}

// --- cSkinClassic ----------------------------------------------------------

cSkinClassic8col::cSkinClassic8col(void)
:cSkin("classic8col", &::Theme4col)//XXX naming problem???
{
}

const char *cSkinClassic8col::Description(void)
{
   return tr("classic8col - em84 2mb skin");
}

cSkinDisplayChannel *cSkinClassic8col::DisplayChannel(bool WithInfo)
{
   return new cSkinClassic8colDisplayChannel(WithInfo);
}

cSkinDisplayMenu *cSkinClassic8col::DisplayMenu(void)
{
   return new cSkinClassic8colDisplayMenu;
}

cSkinDisplayReplay *cSkinClassic8col::DisplayReplay(bool ModeOnly)
{
   return new cSkinClassic8colDisplayReplay(ModeOnly);
}

cSkinDisplayVolume *cSkinClassic8col::DisplayVolume(void)
{
   return new cSkinClassic8colDisplayVolume;
}


cSkinDisplayTracks *cSkinClassic8col::DisplayTracks(const char *Title, int NumTracks, const char * const *Tracks)
{
   return new cSkinClassic8colDisplayTracks(Title, NumTracks, Tracks);
}

cSkinDisplayMessage *cSkinClassic8col::DisplayMessage(void)
{
   return new cSkinClassic8colDisplayMessage;
}
