vdr  1.7.27
skincurses.c
Go to the documentation of this file.
00001 /*
00002  * skincurses.c: A plugin for the Video Disk Recorder
00003  *
00004  * See the README file for copyright information and how to reach the author.
00005  *
00006  * $Id: skincurses.c 2.8 2012/03/11 14:42:52 kls Exp $
00007  */
00008 
00009 #include <ncurses.h>
00010 #include <vdr/osd.h>
00011 #include <vdr/plugin.h>
00012 #include <vdr/skins.h>
00013 
00014 static const char *VERSION        = "0.1.11";
00015 static const char *DESCRIPTION    = trNOOP("A text only skin");
00016 static const char *MAINMENUENTRY  = NULL;
00017 
00018 // --- cCursesFont -----------------------------------------------------------
00019 
00020 class cCursesFont : public cFont {
00021 public:
00022   virtual int Width(uint c) const { return 1; }
00023   virtual int Width(const char *s) const { return s ? Utf8StrLen(s) : 0; }
00024   virtual int Height(void) const { return 1; }
00025   virtual void DrawText(cBitmap *Bitmap, int x, int y, const char *s, tColor ColorFg, tColor ColorBg, int Width) const {}
00026   virtual void DrawText(cPixmap *Pixmap, int x, int y, const char *s, tColor ColorFg, tColor ColorBg, int Width) const {}
00027   };
00028 
00029 static const cCursesFont Font = cCursesFont(); // w/o the '= cCursesFont()' gcc 4.6 complains - can anybody explain why this is necessary?
00030 
00031 // --- cCursesOsd ------------------------------------------------------------
00032 
00033 #define clrBackground   COLOR_BLACK
00034 #define clrTransparent  clrBackground
00035 #define clrBlack        clrBackground
00036 #define clrRed          COLOR_RED
00037 #define clrGreen        COLOR_GREEN
00038 #define clrYellow       COLOR_YELLOW
00039 #define clrBlue         COLOR_BLUE
00040 #define clrMagenta      COLOR_MAGENTA
00041 #define clrCyan         COLOR_CYAN
00042 #define clrWhite        COLOR_WHITE
00043 
00044 static int clrMessage[] = {
00045   clrBlack,
00046   clrCyan,
00047   clrBlack,
00048   clrGreen,
00049   clrBlack,
00050   clrYellow,
00051   clrWhite,
00052   clrRed
00053   };
00054 
00055 static int ScOsdWidth = 50;
00056 static int ScOsdHeight = 20;
00057 
00058 class cCursesOsd : public cOsd {
00059 private:
00060   WINDOW *savedRegion;
00061   WINDOW *window;
00062   enum { MaxColorPairs = 16 };
00063   int colorPairs[MaxColorPairs];
00064   void SetColor(int colorFg, int colorBg = clrBackground);
00065 public:
00066   cCursesOsd(int Left, int Top);
00067   virtual ~cCursesOsd();
00068   virtual void SaveRegion(int x1, int y1, int x2, int y2);
00069   virtual void RestoreRegion(void);
00070   virtual void DrawText(int x, int y, const char *s, tColor ColorFg, tColor ColorBg, const cFont *Font, int Width = 0, int Height = 0, int Alignment = taDefault);
00071   virtual void DrawRectangle(int x1, int y1, int x2, int y2, tColor Color);
00072   virtual void Flush(void);
00073   };
00074 
00075 cCursesOsd::cCursesOsd(int Left, int Top)
00076 :cOsd(Left, Top, 0)
00077 {
00078   savedRegion = NULL;
00079 
00080   memset(colorPairs, 0x00, sizeof(colorPairs));
00081   start_color();
00082   leaveok(stdscr, true);
00083 
00084   window = subwin(stdscr, ScOsdHeight, ScOsdWidth, 0, 0);
00085   syncok(window, true);
00086 }
00087 
00088 cCursesOsd::~cCursesOsd()
00089 {
00090   if (window) {
00091      werase(window);
00092      Flush();
00093      delwin(window);
00094      window = NULL;
00095      }
00096 }
00097 
00098 void cCursesOsd::SetColor(int colorFg, int colorBg)
00099 {
00100   int color = (colorBg << 16) | colorFg | 0x80000000;
00101   for (int i = 0; i < MaxColorPairs; i++) {
00102       if (!colorPairs[i]) {
00103          colorPairs[i] = color;
00104          init_pair(i + 1, colorFg, colorBg);
00105          //XXX??? attron(COLOR_PAIR(WHITE_ON_BLUE));
00106          wattrset(window, COLOR_PAIR(i + 1));
00107          break;
00108          }
00109       else if (color == colorPairs[i]) {
00110          wattrset(window, COLOR_PAIR(i + 1));
00111          break;
00112          }
00113       }
00114 }
00115 
00116 void cCursesOsd::SaveRegion(int x1, int y1, int x2, int y2)
00117 {
00118   if (savedRegion) {
00119      delwin(savedRegion);
00120      savedRegion = NULL;
00121      }
00122   savedRegion = newwin(y2 - y1 + 1, x2 - x1 + 1, y1, x1);
00123   copywin(window, savedRegion, y1, x1, 0, 0, y2 - y1, x2 - x1, false);
00124 }
00125 
00126 void cCursesOsd::RestoreRegion(void)
00127 {
00128   if (savedRegion) {
00129      copywin(savedRegion, window, 0, 0, savedRegion->_begy, savedRegion->_begx, savedRegion->_maxy - savedRegion->_begy, savedRegion->_maxx - savedRegion->_begx, false);
00130      delwin(savedRegion);
00131      savedRegion = NULL;
00132      }
00133 }
00134 
00135 void cCursesOsd::DrawText(int x, int y, const char *s, tColor ColorFg, tColor ColorBg, const cFont *Font, int Width, int Height, int Alignment)
00136 {
00137   int w = Font->Width(s);
00138   int h = Font->Height();
00139   if (Width || Height) {
00140      int cw = Width ? Width : w;
00141      int ch = Height ? Height : h;
00142      DrawRectangle(x, y, x + cw - 1, y + ch - 1, ColorBg);
00143      if (Width) {
00144         if ((Alignment & taLeft) != 0)
00145            ;
00146         else if ((Alignment & taRight) != 0) {
00147            if (w < Width)
00148               x += Width - w;
00149            }
00150         else { // taCentered
00151            if (w < Width)
00152               x += (Width - w) / 2;
00153            }
00154         }
00155      if (Height) {
00156         if ((Alignment & taTop) != 0)
00157            ;
00158         else if ((Alignment & taBottom) != 0) {
00159            if (h < Height)
00160               y += Height - h;
00161            }
00162         else { // taCentered
00163            if (h < Height)
00164               y += (Height - h) / 2;
00165            }
00166         }
00167      }
00168   SetColor(ColorFg, ColorBg);
00169   wmove(window, y, x); // ncurses wants 'y' before 'x'!
00170   waddnstr(window, s, Width ? Width : ScOsdWidth - x);
00171 }
00172 
00173 void cCursesOsd::DrawRectangle(int x1, int y1, int x2, int y2, tColor Color)
00174 {
00175   SetColor(Color, Color);
00176   for (int y = y1; y <= y2; y++) {
00177       wmove(window, y, x1); // ncurses wants 'y' before 'x'!
00178       whline(window, ' ', x2 - x1 + 1);
00179       }
00180   wsyncup(window); // shouldn't be necessary because of 'syncok()', but w/o it doesn't work
00181 }
00182 
00183 void cCursesOsd::Flush(void)
00184 {
00185   refresh();
00186 }
00187 
00188 // --- cSkinCursesDisplayChannel ---------------------------------------------
00189 
00190 class cSkinCursesDisplayChannel : public cSkinDisplayChannel {
00191 private:
00192   cOsd *osd;
00193   int timeWidth;
00194   bool message;
00195 public:
00196   cSkinCursesDisplayChannel(bool WithInfo);
00197   virtual ~cSkinCursesDisplayChannel();
00198   virtual void SetChannel(const cChannel *Channel, int Number);
00199   virtual void SetEvents(const cEvent *Present, const cEvent *Following);
00200   virtual void SetMessage(eMessageType Type, const char *Text);
00201   virtual void Flush(void);
00202   };
00203 
00204 cSkinCursesDisplayChannel::cSkinCursesDisplayChannel(bool WithInfo)
00205 {
00206   int Lines = WithInfo ? 5 : 1;
00207   message = false;
00208   osd = new cCursesOsd(0, Setup.ChannelInfoPos ? 0 : ScOsdHeight - Lines);
00209   timeWidth = strlen("00:00");
00210   osd->DrawRectangle(0, 0, ScOsdWidth - 1, Lines - 1, clrBackground);
00211 }
00212 
00213 cSkinCursesDisplayChannel::~cSkinCursesDisplayChannel()
00214 {
00215   delete osd;
00216 }
00217 
00218 void cSkinCursesDisplayChannel::SetChannel(const cChannel *Channel, int Number)
00219 {
00220   osd->DrawRectangle(0, 0, ScOsdWidth - 1, 0, clrBackground);
00221   osd->DrawText(0, 0, ChannelString(Channel, Number), clrWhite, clrBackground, &Font);
00222 }
00223 
00224 void cSkinCursesDisplayChannel::SetEvents(const cEvent *Present, const cEvent *Following)
00225 {
00226   osd->DrawRectangle(0, 1, timeWidth - 1, 4, clrRed);
00227   osd->DrawRectangle(timeWidth, 1, ScOsdWidth - 1, 4, clrBackground);
00228   for (int i = 0; i < 2; i++) {
00229       const cEvent *e = !i ? Present : Following;
00230       if (e) {
00231          osd->DrawText(            0, 2 * i + 1, e->GetTimeString(), clrWhite, clrRed, &Font);
00232          osd->DrawText(timeWidth + 1, 2 * i + 1, e->Title(), clrCyan, clrBackground, &Font);
00233          osd->DrawText(timeWidth + 1, 2 * i + 2, e->ShortText(), clrYellow, clrBackground, &Font);
00234          }
00235       }
00236 }
00237 
00238 void cSkinCursesDisplayChannel::SetMessage(eMessageType Type, const char *Text)
00239 {
00240   if (Text) {
00241      osd->SaveRegion(0, 0, ScOsdWidth - 1, 0);
00242      osd->DrawText(0, 0, Text, clrMessage[2 * Type], clrMessage[2 * Type + 1], &Font, ScOsdWidth, 0, taCenter);
00243      message = true;
00244      }
00245   else {
00246      osd->RestoreRegion();
00247      message = false;
00248      }
00249 }
00250 
00251 void cSkinCursesDisplayChannel::Flush(void)
00252 {
00253   if (!message) {
00254      cString date = DayDateTime();
00255      osd->DrawText(ScOsdWidth - Utf8StrLen(date), 0, date, clrWhite, clrBackground, &Font);
00256      }
00257   osd->Flush();
00258 }
00259 
00260 // --- cSkinCursesDisplayMenu ------------------------------------------------
00261 
00262 class cSkinCursesDisplayMenu : public cSkinDisplayMenu {
00263 private:
00264   cOsd *osd;
00265   void DrawScrollbar(int Total, int Offset, int Shown, int Top, int Height, bool CanScrollUp, bool CanScrollDown);
00266   void SetTextScrollbar(void);
00267 public:
00268   cSkinCursesDisplayMenu(void);
00269   virtual ~cSkinCursesDisplayMenu();
00270   virtual void Scroll(bool Up, bool Page);
00271   virtual int MaxItems(void);
00272   virtual void Clear(void);
00273   virtual void SetTitle(const char *Title);
00274   virtual void SetButtons(const char *Red, const char *Green = NULL, const char *Yellow = NULL, const char *Blue = NULL);
00275   virtual void SetMessage(eMessageType Type, const char *Text);
00276   virtual void SetItem(const char *Text, int Index, bool Current, bool Selectable);
00277   virtual void SetScrollbar(int Total, int Offset);
00278   virtual void SetEvent(const cEvent *Event);
00279   virtual void SetRecording(const cRecording *Recording);
00280   virtual void SetText(const char *Text, bool FixedFont);
00281   virtual const cFont *GetTextAreaFont(bool FixedFont) const { return &Font; }
00282   virtual void Flush(void);
00283   };
00284 
00285 cSkinCursesDisplayMenu::cSkinCursesDisplayMenu(void)
00286 {
00287   osd = new cCursesOsd(0, 0);
00288   osd->DrawRectangle(0, 0, ScOsdWidth - 1, ScOsdHeight - 1, clrBackground);
00289 }
00290 
00291 cSkinCursesDisplayMenu::~cSkinCursesDisplayMenu()
00292 {
00293   delete osd;
00294 }
00295 
00296 void cSkinCursesDisplayMenu::DrawScrollbar(int Total, int Offset, int Shown, int Top, int Height, bool CanScrollUp, bool CanScrollDown)
00297 {
00298   if (Total > 0 && Total > Shown) {
00299      int yt = Top;
00300      int yb = yt + Height;
00301      int st = yt;
00302      int sb = yb;
00303      int th = max(int((sb - st) * double(Shown) / Total + 0.5), 1);
00304      int tt = min(int(st + (sb - st) * double(Offset) / Total + 0.5), sb - th);
00305      int tb = min(tt + th, sb);
00306      int xl = ScOsdWidth - 1;
00307      osd->DrawRectangle(xl, st, xl, sb - 1, clrWhite);
00308      osd->DrawRectangle(xl, tt, xl, tb - 1, clrCyan);
00309      }
00310 }
00311 
00312 void cSkinCursesDisplayMenu::SetTextScrollbar(void)
00313 {
00314   if (textScroller.CanScroll())
00315      DrawScrollbar(textScroller.Total(), textScroller.Offset(), textScroller.Shown(), textScroller.Top(), textScroller.Height(), textScroller.CanScrollUp(), textScroller.CanScrollDown());
00316 }
00317 
00318 void cSkinCursesDisplayMenu::Scroll(bool Up, bool Page)
00319 {
00320   cSkinDisplayMenu::Scroll(Up, Page);
00321   SetTextScrollbar();
00322 }
00323 
00324 int cSkinCursesDisplayMenu::MaxItems(void)
00325 {
00326   return ScOsdHeight - 4;
00327 }
00328 
00329 void cSkinCursesDisplayMenu::Clear(void)
00330 {
00331   osd->DrawRectangle(0, 1, ScOsdWidth - 1, ScOsdHeight - 2, clrBackground);
00332   textScroller.Reset();
00333 }
00334 
00335 void cSkinCursesDisplayMenu::SetTitle(const char *Title)
00336 {
00337   osd->DrawText(0, 0, Title, clrBlack, clrCyan, &Font, ScOsdWidth);
00338 }
00339 
00340 void cSkinCursesDisplayMenu::SetButtons(const char *Red, const char *Green, const char *Yellow, const char *Blue)
00341 {
00342   int w = ScOsdWidth;
00343   int t0 = 0;
00344   int t1 = 0 + w / 4;
00345   int t2 = 0 + w / 2;
00346   int t3 = w - w / 4;
00347   int t4 = w;
00348   int y = ScOsdHeight - 1;
00349   osd->DrawText(t0, y, Red,    clrWhite, Red    ? clrRed    : clrBackground, &Font, t1 - t0, 0, taCenter);
00350   osd->DrawText(t1, y, Green,  clrBlack, Green  ? clrGreen  : clrBackground, &Font, t2 - t1, 0, taCenter);
00351   osd->DrawText(t2, y, Yellow, clrBlack, Yellow ? clrYellow : clrBackground, &Font, t3 - t2, 0, taCenter);
00352   osd->DrawText(t3, y, Blue,   clrWhite, Blue   ? clrBlue   : clrBackground, &Font, t4 - t3, 0, taCenter);
00353 }
00354 
00355 void cSkinCursesDisplayMenu::SetMessage(eMessageType Type, const char *Text)
00356 {
00357   if (Text)
00358      osd->DrawText(0, ScOsdHeight - 2, Text, clrMessage[2 * Type], clrMessage[2 * Type + 1], &Font, ScOsdWidth, 0, taCenter);
00359   else
00360      osd->DrawRectangle(0, ScOsdHeight - 2, ScOsdWidth - 1, ScOsdHeight - 2, clrBackground);
00361 }
00362 
00363 void cSkinCursesDisplayMenu::SetItem(const char *Text, int Index, bool Current, bool Selectable)
00364 {
00365   int y = 2 + Index;
00366   int ColorFg, ColorBg;
00367   if (Current) {
00368      ColorFg = clrBlack;
00369      ColorBg = clrCyan;
00370      }
00371   else {
00372      ColorFg = Selectable ? clrWhite : clrCyan;
00373      ColorBg = clrBackground;
00374      }
00375   for (int i = 0; i < MaxTabs; i++) {
00376       const char *s = GetTabbedText(Text, i);
00377       if (s) {
00378          int xt = Tab(i) / AvgCharWidth();// Tab() is in "pixel" - see also skins.c!!!
00379          osd->DrawText(xt, y, s, ColorFg, ColorBg, &Font, ScOsdWidth - 2 - xt);
00380          }
00381       if (!Tab(i + 1))
00382          break;
00383       }
00384   SetEditableWidth(ScOsdWidth - 2 - Tab(1) / AvgCharWidth()); // Tab() is in "pixel" - see also skins.c!!!
00385 }
00386 
00387 void cSkinCursesDisplayMenu::SetScrollbar(int Total, int Offset)
00388 {
00389   DrawScrollbar(Total, Offset, MaxItems(), 2, MaxItems(), Offset > 0, Offset + MaxItems() < Total);
00390 }
00391 
00392 void cSkinCursesDisplayMenu::SetEvent(const cEvent *Event)
00393 {
00394   if (!Event)
00395      return;
00396   int y = 2;
00397   cTextScroller ts;
00398   char t[32];
00399   snprintf(t, sizeof(t), "%s  %s - %s", *Event->GetDateString(), *Event->GetTimeString(), *Event->GetEndTimeString());
00400   ts.Set(osd, 0, y, ScOsdWidth, ScOsdHeight - y - 2, t, &Font, clrYellow, clrBackground);
00401   if (Event->Vps() && Event->Vps() != Event->StartTime()) {
00402      cString buffer = cString::sprintf(" VPS: %s", *Event->GetVpsString());
00403      osd->DrawText(ScOsdWidth - Utf8StrLen(buffer), y, buffer, clrBlack, clrYellow, &Font);
00404      }
00405   y += ts.Height();
00406   if (Event->ParentalRating()) {
00407      cString buffer = cString::sprintf(" %s ", *Event->GetParentalRatingString());
00408      osd->DrawText(ScOsdWidth - Utf8StrLen(buffer), y, buffer, clrBlack, clrYellow, &Font);
00409      }
00410   y += 1;
00411   ts.Set(osd, 0, y, ScOsdWidth, ScOsdHeight - y - 2, Event->Title(), &Font, clrCyan, clrBackground);
00412   y += ts.Height();
00413   if (!isempty(Event->ShortText())) {
00414      ts.Set(osd, 0, y, ScOsdWidth, ScOsdHeight - y - 2, Event->ShortText(), &Font, clrYellow, clrBackground);
00415      y += ts.Height();
00416      }
00417   for (int i = 0; Event->Contents(i); i++) {
00418       const char *s = Event->ContentToString(Event->Contents(i));
00419       if (!isempty(s)) {
00420          ts.Set(osd, 0, y, ScOsdWidth, ScOsdHeight - y - 2, s, &Font, clrYellow, clrBackground);
00421          y += 1;
00422          }
00423       }
00424   y += 1;
00425   if (!isempty(Event->Description())) {
00426      textScroller.Set(osd, 0, y, ScOsdWidth - 2, ScOsdHeight - y - 2, Event->Description(), &Font, clrCyan, clrBackground);
00427      SetTextScrollbar();
00428      }
00429 }
00430 
00431 void cSkinCursesDisplayMenu::SetRecording(const cRecording *Recording)
00432 {
00433   if (!Recording)
00434      return;
00435   const cRecordingInfo *Info = Recording->Info();
00436   int y = 2;
00437   cTextScroller ts;
00438   char t[32];
00439   snprintf(t, sizeof(t), "%s  %s", *DateString(Recording->Start()), *TimeString(Recording->Start()));
00440   ts.Set(osd, 0, y, ScOsdWidth, ScOsdHeight - y - 2, t, &Font, clrYellow, clrBackground);
00441   y += ts.Height();
00442   if (Info->GetEvent()->ParentalRating()) {
00443      cString buffer = cString::sprintf(" %s ", *Info->GetEvent()->GetParentalRatingString());
00444      osd->DrawText(ScOsdWidth - Utf8StrLen(buffer), y, buffer, clrBlack, clrYellow, &Font);
00445      }
00446   y += 1;
00447   const char *Title = Info->Title();
00448   if (isempty(Title))
00449      Title = Recording->Name();
00450   ts.Set(osd, 0, y, ScOsdWidth, ScOsdHeight - y - 2, Title, &Font, clrCyan, clrBackground);
00451   y += ts.Height();
00452   if (!isempty(Info->ShortText())) {
00453      ts.Set(osd, 0, y, ScOsdWidth, ScOsdHeight - y - 2, Info->ShortText(), &Font, clrYellow, clrBackground);
00454      y += ts.Height();
00455      }
00456   for (int i = 0; Info->GetEvent()->Contents(i); i++) {
00457       const char *s = Info->GetEvent()->ContentToString(Info->GetEvent()->Contents(i));
00458       if (!isempty(s)) {
00459          ts.Set(osd, 0, y, ScOsdWidth, ScOsdHeight - y - 2, s, &Font, clrYellow, clrBackground);
00460          y += 1;
00461          }
00462       }
00463   y += 1;
00464   if (!isempty(Info->Description())) {
00465      textScroller.Set(osd, 0, y, ScOsdWidth - 2, ScOsdHeight - y - 2, Info->Description(), &Font, clrCyan, clrBackground);
00466      SetTextScrollbar();
00467      }
00468 }
00469 
00470 void cSkinCursesDisplayMenu::SetText(const char *Text, bool FixedFont)
00471 {
00472   textScroller.Set(osd, 0, 2, ScOsdWidth - 2, ScOsdHeight - 4, Text, &Font, clrWhite, clrBackground);
00473   SetTextScrollbar();
00474 }
00475 
00476 void cSkinCursesDisplayMenu::Flush(void)
00477 {
00478   cString date = DayDateTime();
00479   osd->DrawText(ScOsdWidth - Utf8StrLen(date) - 2, 0, date, clrBlack, clrCyan, &Font);
00480   osd->Flush();
00481 }
00482 
00483 // --- cSkinCursesDisplayReplay ----------------------------------------------
00484 
00485 class cSkinCursesDisplayReplay : public cSkinDisplayReplay {
00486 private:
00487   cOsd *osd;
00488   bool message;
00489 public:
00490   cSkinCursesDisplayReplay(bool ModeOnly);
00491   virtual ~cSkinCursesDisplayReplay();
00492   virtual void SetTitle(const char *Title);
00493   virtual void SetMode(bool Play, bool Forward, int Speed);
00494   virtual void SetProgress(int Current, int Total);
00495   virtual void SetCurrent(const char *Current);
00496   virtual void SetTotal(const char *Total);
00497   virtual void SetJump(const char *Jump);
00498   virtual void SetMessage(eMessageType Type, const char *Text);
00499   virtual void Flush(void);
00500   };
00501 
00502 cSkinCursesDisplayReplay::cSkinCursesDisplayReplay(bool ModeOnly)
00503 {
00504   message = false;
00505   osd = new cCursesOsd(0, ScOsdHeight - 3);
00506   osd->DrawRectangle(0, 0, ScOsdWidth - 1, 2, ModeOnly ? clrTransparent : clrBackground);
00507 }
00508 
00509 cSkinCursesDisplayReplay::~cSkinCursesDisplayReplay()
00510 {
00511   delete osd;
00512 }
00513 
00514 void cSkinCursesDisplayReplay::SetTitle(const char *Title)
00515 {
00516   osd->DrawText(0, 0, Title, clrWhite, clrBackground, &Font, ScOsdWidth);
00517 }
00518 
00519 void cSkinCursesDisplayReplay::SetMode(bool Play, bool Forward, int Speed)
00520 {
00521   if (Setup.ShowReplayMode) {
00522      const char *Mode;
00523      if (Speed == -1) Mode = Play    ? "  >  " : " ||  ";
00524      else if (Play)   Mode = Forward ? " X>> " : " <<X ";
00525      else             Mode = Forward ? " X|> " : " <|X ";
00526      char buf[16];
00527      strn0cpy(buf, Mode, sizeof(buf));
00528      char *p = strchr(buf, 'X');
00529      if (p)
00530         *p = Speed > 0 ? '1' + Speed - 1 : ' ';
00531      SetJump(buf);
00532      }
00533 }
00534 
00535 void cSkinCursesDisplayReplay::SetProgress(int Current, int Total)
00536 {
00537   int p = Total > 0 ? ScOsdWidth * Current / Total : 0;
00538   osd->DrawRectangle(0, 1, p, 1, clrGreen);
00539   osd->DrawRectangle(p, 1, ScOsdWidth, 1, clrWhite);
00540 }
00541 
00542 void cSkinCursesDisplayReplay::SetCurrent(const char *Current)
00543 {
00544   osd->DrawText(0, 2, Current, clrWhite, clrBackground, &Font, Utf8StrLen(Current) + 3);
00545 }
00546 
00547 void cSkinCursesDisplayReplay::SetTotal(const char *Total)
00548 {
00549   osd->DrawText(ScOsdWidth - Utf8StrLen(Total), 2, Total, clrWhite, clrBackground, &Font);
00550 }
00551 
00552 void cSkinCursesDisplayReplay::SetJump(const char *Jump)
00553 {
00554   osd->DrawText(ScOsdWidth / 4, 2, Jump, clrWhite, clrBackground, &Font, ScOsdWidth / 2, 0, taCenter);
00555 }
00556 
00557 void cSkinCursesDisplayReplay::SetMessage(eMessageType Type, const char *Text)
00558 {
00559   if (Text) {
00560      osd->SaveRegion(0, 2, ScOsdWidth - 1, 2);
00561      osd->DrawText(0, 2, Text, clrMessage[2 * Type], clrMessage[2 * Type + 1], &Font, ScOsdWidth, 0, taCenter);
00562      message = true;
00563      }
00564   else {
00565      osd->RestoreRegion();
00566      message = false;
00567      }
00568 }
00569 
00570 void cSkinCursesDisplayReplay::Flush(void)
00571 {
00572   osd->Flush();
00573 }
00574 
00575 // --- cSkinCursesDisplayVolume ----------------------------------------------
00576 
00577 class cSkinCursesDisplayVolume : public cSkinDisplayVolume {
00578 private:
00579   cOsd *osd;
00580 public:
00581   cSkinCursesDisplayVolume(void);
00582   virtual ~cSkinCursesDisplayVolume();
00583   virtual void SetVolume(int Current, int Total, bool Mute);
00584   virtual void Flush(void);
00585   };
00586 
00587 cSkinCursesDisplayVolume::cSkinCursesDisplayVolume(void)
00588 {
00589   osd = new cCursesOsd(0, ScOsdHeight - 1);
00590 }
00591 
00592 cSkinCursesDisplayVolume::~cSkinCursesDisplayVolume()
00593 {
00594   delete osd;
00595 }
00596 
00597 void cSkinCursesDisplayVolume::SetVolume(int Current, int Total, bool Mute)
00598 {
00599   if (Mute) {
00600      osd->DrawRectangle(0, 0, ScOsdWidth - 1, 0, clrTransparent);
00601      osd->DrawText(0, 0, tr("Key$Mute"), clrGreen, clrBackground, &Font);
00602      }
00603   else {
00604      const char *Prompt = tr("Volume ");
00605      int l = Utf8StrLen(Prompt);
00606      int p = (ScOsdWidth - l) * Current / Total;
00607      osd->DrawText(0, 0, Prompt, clrGreen, clrBackground, &Font);
00608      osd->DrawRectangle(l, 0, l + p - 1, 0, clrGreen);
00609      osd->DrawRectangle(l + p, 0, ScOsdWidth - 1, 0, clrWhite);
00610      }
00611 }
00612 
00613 void cSkinCursesDisplayVolume::Flush(void)
00614 {
00615   osd->Flush();
00616 }
00617 
00618 // --- cSkinCursesDisplayTracks ----------------------------------------------
00619 
00620 class cSkinCursesDisplayTracks : public cSkinDisplayTracks {
00621 private:
00622   cOsd *osd;
00623   int itemsWidth;
00624   int currentIndex;
00625   void SetItem(const char *Text, int Index, bool Current);
00626 public:
00627   cSkinCursesDisplayTracks(const char *Title, int NumTracks, const char * const *Tracks);
00628   virtual ~cSkinCursesDisplayTracks();
00629   virtual void SetTrack(int Index, const char * const *Tracks);
00630   virtual void SetAudioChannel(int AudioChannel) {}
00631   virtual void Flush(void);
00632   };
00633 
00634 cSkinCursesDisplayTracks::cSkinCursesDisplayTracks(const char *Title, int NumTracks, const char * const *Tracks)
00635 {
00636   currentIndex = -1;
00637   itemsWidth = Font.Width(Title);
00638   for (int i = 0; i < NumTracks; i++)
00639       itemsWidth = max(itemsWidth, Font.Width(Tracks[i]));
00640   itemsWidth = min(itemsWidth, ScOsdWidth);
00641   osd = new cCursesOsd(0, 0);
00642   osd->DrawRectangle(0, 0, ScOsdWidth - 1, ScOsdHeight - 1, clrBackground);
00643   osd->DrawText(0, 0, Title, clrBlack, clrCyan, &Font, itemsWidth);
00644   for (int i = 0; i < NumTracks; i++)
00645       SetItem(Tracks[i], i, false);
00646 }
00647 
00648 cSkinCursesDisplayTracks::~cSkinCursesDisplayTracks()
00649 {
00650   delete osd;
00651 }
00652 
00653 void cSkinCursesDisplayTracks::SetItem(const char *Text, int Index, bool Current)
00654 {
00655   int y = 1 + Index;
00656   int ColorFg, ColorBg;
00657   if (Current) {
00658      ColorFg = clrBlack;
00659      ColorBg = clrCyan;
00660      currentIndex = Index;
00661      }
00662   else {
00663      ColorFg = clrWhite;
00664      ColorBg = clrBackground;
00665      }
00666   osd->DrawText(0, y, Text, ColorFg, ColorBg, &Font, itemsWidth);
00667 }
00668 
00669 void cSkinCursesDisplayTracks::SetTrack(int Index, const char * const *Tracks)
00670 {
00671   if (currentIndex >= 0)
00672      SetItem(Tracks[currentIndex], currentIndex, false);
00673   SetItem(Tracks[Index], Index, true);
00674 }
00675 
00676 void cSkinCursesDisplayTracks::Flush(void)
00677 {
00678   osd->Flush();
00679 }
00680 
00681 // --- cSkinCursesDisplayMessage ---------------------------------------------
00682 
00683 class cSkinCursesDisplayMessage : public cSkinDisplayMessage {
00684 private:
00685   cOsd *osd;
00686 public:
00687   cSkinCursesDisplayMessage(void);
00688   virtual ~cSkinCursesDisplayMessage();
00689   virtual void SetMessage(eMessageType Type, const char *Text);
00690   virtual void Flush(void);
00691   };
00692 
00693 cSkinCursesDisplayMessage::cSkinCursesDisplayMessage(void)
00694 {
00695   osd = new cCursesOsd(0, ScOsdHeight - 1);
00696 }
00697 
00698 cSkinCursesDisplayMessage::~cSkinCursesDisplayMessage()
00699 {
00700   delete osd;
00701 }
00702 
00703 void cSkinCursesDisplayMessage::SetMessage(eMessageType Type, const char *Text)
00704 {
00705   osd->DrawText(0, 0, Text, clrMessage[2 * Type], clrMessage[2 * Type + 1], &Font, ScOsdWidth, 0, taCenter);
00706 }
00707 
00708 void cSkinCursesDisplayMessage::Flush(void)
00709 {
00710   osd->Flush();
00711 }
00712 
00713 // --- cSkinCurses -----------------------------------------------------------
00714 
00715 class cSkinCurses : public cSkin {
00716 public:
00717   cSkinCurses(void);
00718   virtual const char *Description(void);
00719   virtual cSkinDisplayChannel *DisplayChannel(bool WithInfo);
00720   virtual cSkinDisplayMenu *DisplayMenu(void);
00721   virtual cSkinDisplayReplay *DisplayReplay(bool ModeOnly);
00722   virtual cSkinDisplayVolume *DisplayVolume(void);
00723   virtual cSkinDisplayTracks *DisplayTracks(const char *Title, int NumTracks, const char * const *Tracks);
00724   virtual cSkinDisplayMessage *DisplayMessage(void);
00725   };
00726 
00727 cSkinCurses::cSkinCurses(void)
00728 :cSkin("curses")
00729 {
00730 }
00731 
00732 const char *cSkinCurses::Description(void)
00733 {
00734   return tr("Text mode");
00735 }
00736 
00737 cSkinDisplayChannel *cSkinCurses::DisplayChannel(bool WithInfo)
00738 {
00739   return new cSkinCursesDisplayChannel(WithInfo);
00740 }
00741 
00742 cSkinDisplayMenu *cSkinCurses::DisplayMenu(void)
00743 {
00744   return new cSkinCursesDisplayMenu;
00745 }
00746 
00747 cSkinDisplayReplay *cSkinCurses::DisplayReplay(bool ModeOnly)
00748 {
00749   return new cSkinCursesDisplayReplay(ModeOnly);
00750 }
00751 
00752 cSkinDisplayVolume *cSkinCurses::DisplayVolume(void)
00753 {
00754   return new cSkinCursesDisplayVolume;
00755 }
00756 
00757 cSkinDisplayTracks *cSkinCurses::DisplayTracks(const char *Title, int NumTracks, const char * const *Tracks)
00758 {
00759   return new cSkinCursesDisplayTracks(Title, NumTracks, Tracks);
00760 }
00761 
00762 cSkinDisplayMessage *cSkinCurses::DisplayMessage(void)
00763 {
00764   return new cSkinCursesDisplayMessage;
00765 }
00766 
00767 // --- cPluginSkinCurses -----------------------------------------------------
00768 
00769 class cPluginSkinCurses : public cPlugin {
00770 private:
00771   // Add any member variables or functions you may need here.
00772 public:
00773   cPluginSkinCurses(void);
00774   virtual ~cPluginSkinCurses();
00775   virtual const char *Version(void) { return VERSION; }
00776   virtual const char *Description(void) { return tr(DESCRIPTION); }
00777   virtual const char *CommandLineHelp(void);
00778   virtual bool ProcessArgs(int argc, char *argv[]);
00779   virtual bool Initialize(void);
00780   virtual bool Start(void);
00781   virtual void Housekeeping(void);
00782   virtual const char *MainMenuEntry(void) { return tr(MAINMENUENTRY); }
00783   virtual cOsdObject *MainMenuAction(void);
00784   virtual cMenuSetupPage *SetupMenu(void);
00785   virtual bool SetupParse(const char *Name, const char *Value);
00786   };
00787 
00788 cPluginSkinCurses::cPluginSkinCurses(void)
00789 {
00790   // Initialize any member variables here.
00791   // DON'T DO ANYTHING ELSE THAT MAY HAVE SIDE EFFECTS, REQUIRE GLOBAL
00792   // VDR OBJECTS TO EXIST OR PRODUCE ANY OUTPUT!
00793 }
00794 
00795 cPluginSkinCurses::~cPluginSkinCurses()
00796 {
00797   // Clean up after yourself!
00798   endwin();
00799 }
00800 
00801 const char *cPluginSkinCurses::CommandLineHelp(void)
00802 {
00803   // Return a string that describes all known command line options.
00804   return NULL;
00805 }
00806 
00807 bool cPluginSkinCurses::ProcessArgs(int argc, char *argv[])
00808 {
00809   // Implement command line argument processing here if applicable.
00810   return true;
00811 }
00812 
00813 bool cPluginSkinCurses::Initialize(void)
00814 {
00815   // Initialize any background activities the plugin shall perform.
00816   WINDOW *w = initscr();
00817   if (w) {
00818      ScOsdWidth  = w->_maxx - w->_begx + 1;
00819      ScOsdHeight = w->_maxy - w->_begy + 1;
00820      return true;
00821      }
00822   return false;
00823 }
00824 
00825 bool cPluginSkinCurses::Start(void)
00826 {
00827   // Start any background activities the plugin shall perform.
00828   cSkin *Skin = new cSkinCurses;
00829   // This skin is normally used for debugging, so let's make it the current one:
00830   Skins.SetCurrent(Skin->Name());
00831   return true;
00832 }
00833 
00834 void cPluginSkinCurses::Housekeeping(void)
00835 {
00836   // Perform any cleanup or other regular tasks.
00837 }
00838 
00839 cOsdObject *cPluginSkinCurses::MainMenuAction(void)
00840 {
00841   // Perform the action when selected from the main VDR menu.
00842   return NULL;
00843 }
00844 
00845 cMenuSetupPage *cPluginSkinCurses::SetupMenu(void)
00846 {
00847   // Return a setup menu in case the plugin supports one.
00848   return NULL;
00849 }
00850 
00851 bool cPluginSkinCurses::SetupParse(const char *Name, const char *Value)
00852 {
00853   // Parse your own setup parameters and store their values.
00854   return false;
00855 }
00856 
00857 VDRPLUGINCREATOR(cPluginSkinCurses); // Don't touch this!