vdr/PLUGINS/src/skincurses/skincurses.c
Klaus Schmidinger 83d7a4b783 Version 1.5.16
- Fixed setting the current subtitle track in Transfer-Mode (reported by Petri Helin,
  thanks to Reinhard Nissl for pointing out that cDevice::Transferring() doesn't
  return the right value in the early stage of channel switching).
- Updated the Danish OSD texts (thanks to Mogens Elneff).
- Updated the Dutch OSD texts (thanks to Carel Willemse).
- Fixed various spelling errors and improved PLUGINS.html (thanks to Ville Skyttä).
- Updated the Italian OSD texts (thanks to Diego Pierotto).
- Fixed the format in cRemote::Put() to use "%016llX" instead of "%016LX" (thanks
  to Ludwig Nussel for pointing this out).
- Revised the fix of calculating the scrollbar height in the skins. The scrollbar
  handle now always has a height that is at least the width of the scrollbar.
- When switching the device that's used for live viewing away from the current
  transponder in favor of an upcoming recording, an attempt is now made to stay
  on the current channel by possibly going into 'Transfer Mode'.
- The CAM menu now stays open as long as it is automatically updated, even without
  pressing a remote control key. This is important when updating the CAM firmware
  from the transponder.
- No longer trying to switch to an available channel if the primary device has
  no valid programme and a menu is open (avoids interference with the CAM in
  case a CAM menu is open).
- Increased the valid range of the "Subtitle offset" setup option to -100...100
  (thanks to Rolf Ahrenberg).
- Added the backslash ('\') to the list of characters that need to be escaped
  when executing external commands (thanks to Peter Bieringer for reporting this one).
2008-02-24 18:00:00 +01:00

835 lines
24 KiB
C

/*
* skincurses.c: A plugin for the Video Disk Recorder
*
* See the README file for copyright information and how to reach the author.
*
* $Id: skincurses.c 1.22 2008/02/23 10:38:04 kls Exp $
*/
#include <ncurses.h>
#include <vdr/osd.h>
#include <vdr/plugin.h>
#include <vdr/skins.h>
static const char *VERSION = "0.1.6";
static const char *DESCRIPTION = trNOOP("A text only skin");
static const char *MAINMENUENTRY = NULL;
// --- cCursesFont -----------------------------------------------------------
class cCursesFont : public cFont {
public:
virtual int Width(uint c) const { return 1; }
virtual int Width(const char *s) const { return s ? Utf8StrLen(s) : 0; }
virtual int Height(void) const { return 1; }
virtual void DrawText(cBitmap *Bitmap, int x, int y, const char *s, tColor ColorFg, tColor ColorBg, int Width) const {}
};
static const cCursesFont Font;
// --- cCursesOsd ------------------------------------------------------------
#define clrBackground COLOR_BLACK
#define clrTransparent clrBackground
#define clrBlack clrBackground
#define clrRed COLOR_RED
#define clrGreen COLOR_GREEN
#define clrYellow COLOR_YELLOW
#define clrBlue COLOR_BLUE
#define clrMagenta COLOR_MAGENTA
#define clrCyan COLOR_CYAN
#define clrWhite COLOR_WHITE
static int clrMessage[] = {
clrBlack,
clrCyan,
clrBlack,
clrGreen,
clrBlack,
clrYellow,
clrWhite,
clrRed
};
static int ScOsdWidth = 50;
static int ScOsdHeight = 20;
class cCursesOsd : public cOsd {
private:
WINDOW *savedRegion;
WINDOW *window;
enum { MaxColorPairs = 16 };
int colorPairs[MaxColorPairs];
void SetColor(int colorFg, int colorBg = clrBackground);
public:
cCursesOsd(int Left, int Top);
virtual ~cCursesOsd();
virtual void SaveRegion(int x1, int y1, int x2, int y2);
virtual void RestoreRegion(void);
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);
virtual void DrawRectangle(int x1, int y1, int x2, int y2, tColor Color);
virtual void Flush(void);
};
cCursesOsd::cCursesOsd(int Left, int Top)
:cOsd(Left, Top, 0)
{
savedRegion = NULL;
memset(colorPairs, 0x00, sizeof(colorPairs));
start_color();
leaveok(stdscr, true);
window = subwin(stdscr, ScOsdHeight, ScOsdWidth, 0, 0);
syncok(window, true);
}
cCursesOsd::~cCursesOsd()
{
if (window) {
werase(window);
Flush();
delwin(window);
window = NULL;
}
}
void cCursesOsd::SetColor(int colorFg, int colorBg)
{
int color = (colorBg << 16) | colorFg | 0x80000000;
for (int i = 0; i < MaxColorPairs; i++) {
if (!colorPairs[i]) {
colorPairs[i] = color;
init_pair(i + 1, colorFg, colorBg);
//XXX??? attron(COLOR_PAIR(WHITE_ON_BLUE));
wattrset(window, COLOR_PAIR(i + 1));
break;
}
else if (color == colorPairs[i]) {
wattrset(window, COLOR_PAIR(i + 1));
break;
}
}
}
void cCursesOsd::SaveRegion(int x1, int y1, int x2, int y2)
{
if (savedRegion) {
delwin(savedRegion);
savedRegion = NULL;
}
savedRegion = newwin(y2 - y1 + 1, x2 - x1 + 1, y1, x1);
copywin(window, savedRegion, y1, x1, 0, 0, y2 - y1, x2 - x1, false);
}
void cCursesOsd::RestoreRegion(void)
{
if (savedRegion) {
copywin(savedRegion, window, 0, 0, savedRegion->_begy, savedRegion->_begx, savedRegion->_maxy - savedRegion->_begy, savedRegion->_maxx - savedRegion->_begx, false);
delwin(savedRegion);
savedRegion = NULL;
}
}
void cCursesOsd::DrawText(int x, int y, const char *s, tColor ColorFg, tColor ColorBg, const cFont *Font, int Width, int Height, int Alignment)
{
int w = Font->Width(s);
int h = Font->Height();
if (Width || Height) {
int cw = Width ? Width : w;
int ch = Height ? Height : h;
DrawRectangle(x, y, x + cw - 1, y + ch - 1, ColorBg);
if (Width) {
if ((Alignment & taLeft) != 0)
;
else if ((Alignment & taRight) != 0) {
if (w < Width)
x += Width - w;
}
else { // taCentered
if (w < Width)
x += (Width - w) / 2;
}
}
if (Height) {
if ((Alignment & taTop) != 0)
;
else if ((Alignment & taBottom) != 0) {
if (h < Height)
y += Height - h;
}
else { // taCentered
if (h < Height)
y += (Height - h) / 2;
}
}
}
SetColor(ColorFg, ColorBg);
wmove(window, y, x); // ncurses wants 'y' before 'x'!
waddnstr(window, s, Width ? Width : ScOsdWidth - x);
}
void cCursesOsd::DrawRectangle(int x1, int y1, int x2, int y2, tColor Color)
{
SetColor(Color, Color);
for (int y = y1; y <= y2; y++) {
wmove(window, y, x1); // ncurses wants 'y' before 'x'!
whline(window, ' ', x2 - x1 + 1);
}
wsyncup(window); // shouldn't be necessary because of 'syncok()', but w/o it doesn't work
}
void cCursesOsd::Flush(void)
{
refresh();
}
// --- cSkinCursesDisplayChannel ---------------------------------------------
class cSkinCursesDisplayChannel : public cSkinDisplayChannel {
private:
cOsd *osd;
int timeWidth;
bool message;
public:
cSkinCursesDisplayChannel(bool WithInfo);
virtual ~cSkinCursesDisplayChannel();
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);
};
cSkinCursesDisplayChannel::cSkinCursesDisplayChannel(bool WithInfo)
{
int Lines = WithInfo ? 5 : 1;
message = false;
osd = new cCursesOsd(0, Setup.ChannelInfoPos ? 0 : ScOsdHeight - Lines);
timeWidth = strlen("00:00");
osd->DrawRectangle(0, 0, ScOsdWidth - 1, Lines - 1, clrBackground);
}
cSkinCursesDisplayChannel::~cSkinCursesDisplayChannel()
{
delete osd;
}
void cSkinCursesDisplayChannel::SetChannel(const cChannel *Channel, int Number)
{
osd->DrawRectangle(0, 0, ScOsdWidth - 1, 0, clrBackground);
osd->DrawText(0, 0, ChannelString(Channel, Number), clrWhite, clrBackground, &Font);
}
void cSkinCursesDisplayChannel::SetEvents(const cEvent *Present, const cEvent *Following)
{
osd->DrawRectangle(0, 1, timeWidth - 1, 4, clrRed);
osd->DrawRectangle(timeWidth, 1, ScOsdWidth - 1, 4, clrBackground);
for (int i = 0; i < 2; i++) {
const cEvent *e = !i ? Present : Following;
if (e) {
osd->DrawText( 0, 2 * i + 1, e->GetTimeString(), clrWhite, clrRed, &Font);
osd->DrawText(timeWidth + 1, 2 * i + 1, e->Title(), clrCyan, clrBackground, &Font);
osd->DrawText(timeWidth + 1, 2 * i + 2, e->ShortText(), clrYellow, clrBackground, &Font);
}
}
}
void cSkinCursesDisplayChannel::SetMessage(eMessageType Type, const char *Text)
{
if (Text) {
osd->SaveRegion(0, 0, ScOsdWidth - 1, 0);
osd->DrawText(0, 0, Text, clrMessage[2 * Type], clrMessage[2 * Type + 1], &Font, ScOsdWidth, 0, taCenter);
message = true;
}
else {
osd->RestoreRegion();
message = false;
}
}
void cSkinCursesDisplayChannel::Flush(void)
{
if (!message) {
cString date = DayDateTime();
osd->DrawText(ScOsdWidth - Utf8StrLen(date), 0, date, clrWhite, clrBackground, &Font);
}
osd->Flush();
}
// --- cSkinCursesDisplayMenu ------------------------------------------------
class cSkinCursesDisplayMenu : public cSkinDisplayMenu {
private:
cOsd *osd;
void DrawScrollbar(int Total, int Offset, int Shown, int Top, int Height, bool CanScrollUp, bool CanScrollDown);
void SetTextScrollbar(void);
public:
cSkinCursesDisplayMenu(void);
virtual ~cSkinCursesDisplayMenu();
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 SetScrollbar(int Total, int Offset);
virtual void SetEvent(const cEvent *Event);
virtual void SetRecording(const cRecording *Recording);
virtual void SetText(const char *Text, bool FixedFont);
virtual const cFont *GetTextAreaFont(bool FixedFont) const { return &Font; }
virtual void Flush(void);
};
cSkinCursesDisplayMenu::cSkinCursesDisplayMenu(void)
{
osd = new cCursesOsd(0, 0);
osd->DrawRectangle(0, 0, ScOsdWidth - 1, ScOsdHeight - 1, clrBackground);
}
cSkinCursesDisplayMenu::~cSkinCursesDisplayMenu()
{
delete osd;
}
void cSkinCursesDisplayMenu::DrawScrollbar(int Total, int Offset, int Shown, int Top, int Height, bool CanScrollUp, bool CanScrollDown)
{
if (Total > 0 && Total > Shown) {
int yt = Top;
int yb = yt + Height;
int st = yt;
int sb = yb;
int th = max(int((sb - st) * double(Shown) / Total + 0.5), 1);
int tt = min(int(st + (sb - st) * double(Offset) / Total + 0.5), sb - th);
int tb = min(tt + th, sb);
int xl = ScOsdWidth - 1;
osd->DrawRectangle(xl, st, xl, sb - 1, clrWhite);
osd->DrawRectangle(xl, tt, xl, tb - 1, clrCyan);
}
}
void cSkinCursesDisplayMenu::SetTextScrollbar(void)
{
if (textScroller.CanScroll())
DrawScrollbar(textScroller.Total(), textScroller.Offset(), textScroller.Shown(), textScroller.Top(), textScroller.Height(), textScroller.CanScrollUp(), textScroller.CanScrollDown());
}
void cSkinCursesDisplayMenu::Scroll(bool Up, bool Page)
{
cSkinDisplayMenu::Scroll(Up, Page);
SetTextScrollbar();
}
int cSkinCursesDisplayMenu::MaxItems(void)
{
return ScOsdHeight - 4;
}
void cSkinCursesDisplayMenu::Clear(void)
{
osd->DrawRectangle(0, 1, ScOsdWidth - 1, ScOsdHeight - 2, clrBackground);
textScroller.Reset();
}
void cSkinCursesDisplayMenu::SetTitle(const char *Title)
{
osd->DrawText(0, 0, Title, clrBlack, clrCyan, &Font, ScOsdWidth);
}
void cSkinCursesDisplayMenu::SetButtons(const char *Red, const char *Green, const char *Yellow, const char *Blue)
{
int w = ScOsdWidth;
int t0 = 0;
int t1 = 0 + w / 4;
int t2 = 0 + w / 2;
int t3 = w - w / 4;
int t4 = w;
int y = ScOsdHeight - 1;
osd->DrawText(t0, y, Red, clrWhite, Red ? clrRed : clrBackground, &Font, t1 - t0, 0, taCenter);
osd->DrawText(t1, y, Green, clrBlack, Green ? clrGreen : clrBackground, &Font, t2 - t1, 0, taCenter);
osd->DrawText(t2, y, Yellow, clrBlack, Yellow ? clrYellow : clrBackground, &Font, t3 - t2, 0, taCenter);
osd->DrawText(t3, y, Blue, clrWhite, Blue ? clrBlue : clrBackground, &Font, t4 - t3, 0, taCenter);
}
void cSkinCursesDisplayMenu::SetMessage(eMessageType Type, const char *Text)
{
if (Text)
osd->DrawText(0, ScOsdHeight - 2, Text, clrMessage[2 * Type], clrMessage[2 * Type + 1], &Font, ScOsdWidth, 0, taCenter);
else
osd->DrawRectangle(0, ScOsdHeight - 2, ScOsdWidth - 1, ScOsdHeight - 2, clrBackground);
}
void cSkinCursesDisplayMenu::SetItem(const char *Text, int Index, bool Current, bool Selectable)
{
int y = 2 + Index;
int ColorFg, ColorBg;
if (Current) {
ColorFg = clrBlack;
ColorBg = clrCyan;
}
else {
ColorFg = Selectable ? clrWhite : clrCyan;
ColorBg = clrBackground;
}
for (int i = 0; i < MaxTabs; i++) {
const char *s = GetTabbedText(Text, i);
if (s) {
int xt = Tab(i) / 12;// Tab() is in "pixel" - see also skins.c!!!
osd->DrawText(xt, y, s, ColorFg, ColorBg, &Font, ScOsdWidth - 2 - xt);
}
if (!Tab(i + 1))
break;
}
SetEditableWidth(ScOsdWidth - 2 - Tab(1) / 12); // Tab() is in "pixel" - see also skins.c!!!
}
void cSkinCursesDisplayMenu::SetScrollbar(int Total, int Offset)
{
DrawScrollbar(Total, Offset, MaxItems(), 2, MaxItems(), Offset > 0, Offset + MaxItems() < Total);
}
void cSkinCursesDisplayMenu::SetEvent(const cEvent *Event)
{
if (!Event)
return;
int y = 2;
cTextScroller ts;
char t[32];
snprintf(t, sizeof(t), "%s %s - %s", *Event->GetDateString(), *Event->GetTimeString(), *Event->GetEndTimeString());
ts.Set(osd, 0, y, ScOsdWidth, ScOsdHeight - y - 2, t, &Font, clrYellow, clrBackground);
if (Event->Vps() && Event->Vps() != Event->StartTime()) {
cString buffer = cString::sprintf(" VPS: %s", *Event->GetVpsString());
osd->DrawText(ScOsdWidth - Utf8StrLen(buffer), y, buffer, clrBlack, clrYellow, &Font);
}
y += ts.Height();
y += 1;
ts.Set(osd, 0, y, ScOsdWidth, ScOsdHeight - y - 2, Event->Title(), &Font, clrCyan, clrBackground);
y += ts.Height();
if (!isempty(Event->ShortText())) {
ts.Set(osd, 0, y, ScOsdWidth, ScOsdHeight - y - 2, Event->ShortText(), &Font, clrYellow, clrBackground);
y += ts.Height();
}
y += 1;
if (!isempty(Event->Description())) {
textScroller.Set(osd, 0, y, ScOsdWidth - 2, ScOsdHeight - y - 2, Event->Description(), &Font, clrCyan, clrBackground);
SetTextScrollbar();
}
}
void cSkinCursesDisplayMenu::SetRecording(const cRecording *Recording)
{
if (!Recording)
return;
const cRecordingInfo *Info = Recording->Info();
int y = 2;
cTextScroller ts;
char t[32];
snprintf(t, sizeof(t), "%s %s", *DateString(Recording->start), *TimeString(Recording->start));
ts.Set(osd, 0, y, ScOsdWidth, ScOsdHeight - y - 2, t, &Font, clrYellow, clrBackground);
y += ts.Height();
y += 1;
const char *Title = Info->Title();
if (isempty(Title))
Title = Recording->Name();
ts.Set(osd, 0, y, ScOsdWidth, ScOsdHeight - y - 2, Title, &Font, clrCyan, clrBackground);
y += ts.Height();
if (!isempty(Info->ShortText())) {
ts.Set(osd, 0, y, ScOsdWidth, ScOsdHeight - y - 2, Info->ShortText(), &Font, clrYellow, clrBackground);
y += ts.Height();
}
y += 1;
if (!isempty(Info->Description())) {
textScroller.Set(osd, 0, y, ScOsdWidth - 2, ScOsdHeight - y - 2, Info->Description(), &Font, clrCyan, clrBackground);
SetTextScrollbar();
}
}
void cSkinCursesDisplayMenu::SetText(const char *Text, bool FixedFont)
{
textScroller.Set(osd, 0, 2, ScOsdWidth - 2, ScOsdHeight - 4, Text, &Font, clrWhite, clrBackground);
SetTextScrollbar();
}
void cSkinCursesDisplayMenu::Flush(void)
{
cString date = DayDateTime();
osd->DrawText(ScOsdWidth - Utf8StrLen(date) - 2, 0, date, clrBlack, clrCyan, &Font);
osd->Flush();
}
// --- cSkinCursesDisplayReplay ----------------------------------------------
class cSkinCursesDisplayReplay : public cSkinDisplayReplay {
private:
cOsd *osd;
bool message;
public:
cSkinCursesDisplayReplay(bool ModeOnly);
virtual ~cSkinCursesDisplayReplay();
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);
};
cSkinCursesDisplayReplay::cSkinCursesDisplayReplay(bool ModeOnly)
{
message = false;
osd = new cCursesOsd(0, ScOsdHeight - 3);
osd->DrawRectangle(0, 0, ScOsdWidth - 1, 2, ModeOnly ? clrTransparent : clrBackground);
}
cSkinCursesDisplayReplay::~cSkinCursesDisplayReplay()
{
delete osd;
}
void cSkinCursesDisplayReplay::SetTitle(const char *Title)
{
osd->DrawText(0, 0, Title, clrWhite, clrBackground, &Font, ScOsdWidth);
}
void cSkinCursesDisplayReplay::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 cSkinCursesDisplayReplay::SetProgress(int Current, int Total)
{
int p = Total > 0 ? ScOsdWidth * Current / Total : 0;
osd->DrawRectangle(0, 1, p, 1, clrGreen);
osd->DrawRectangle(p, 1, ScOsdWidth, 1, clrWhite);
}
void cSkinCursesDisplayReplay::SetCurrent(const char *Current)
{
osd->DrawText(0, 2, Current, clrWhite, clrBackground, &Font, Utf8StrLen(Current) + 3);
}
void cSkinCursesDisplayReplay::SetTotal(const char *Total)
{
osd->DrawText(ScOsdWidth - Utf8StrLen(Total), 2, Total, clrWhite, clrBackground, &Font);
}
void cSkinCursesDisplayReplay::SetJump(const char *Jump)
{
osd->DrawText(ScOsdWidth / 4, 2, Jump, clrWhite, clrBackground, &Font, ScOsdWidth / 2, 0, taCenter);
}
void cSkinCursesDisplayReplay::SetMessage(eMessageType Type, const char *Text)
{
if (Text) {
osd->SaveRegion(0, 2, ScOsdWidth - 1, 2);
osd->DrawText(0, 2, Text, clrMessage[2 * Type], clrMessage[2 * Type + 1], &Font, ScOsdWidth, 0, taCenter);
message = true;
}
else {
osd->RestoreRegion();
message = false;
}
}
void cSkinCursesDisplayReplay::Flush(void)
{
osd->Flush();
}
// --- cSkinCursesDisplayVolume ----------------------------------------------
class cSkinCursesDisplayVolume : public cSkinDisplayVolume {
private:
cOsd *osd;
public:
cSkinCursesDisplayVolume(void);
virtual ~cSkinCursesDisplayVolume();
virtual void SetVolume(int Current, int Total, bool Mute);
virtual void Flush(void);
};
cSkinCursesDisplayVolume::cSkinCursesDisplayVolume(void)
{
osd = new cCursesOsd(0, ScOsdHeight - 1);
}
cSkinCursesDisplayVolume::~cSkinCursesDisplayVolume()
{
delete osd;
}
void cSkinCursesDisplayVolume::SetVolume(int Current, int Total, bool Mute)
{
if (Mute) {
osd->DrawRectangle(0, 0, ScOsdWidth - 1, 0, clrTransparent);
osd->DrawText(0, 0, tr("Key$Mute"), clrGreen, clrBackground, &Font);
}
else {
const char *Prompt = tr("Volume ");
int l = Utf8StrLen(Prompt);
int p = (ScOsdWidth - l) * Current / Total;
osd->DrawText(0, 0, Prompt, clrGreen, clrBackground, &Font);
osd->DrawRectangle(l, 0, l + p - 1, 0, clrGreen);
osd->DrawRectangle(l + p, 0, ScOsdWidth - 1, 0, clrWhite);
}
}
void cSkinCursesDisplayVolume::Flush(void)
{
osd->Flush();
}
// --- cSkinCursesDisplayTracks ----------------------------------------------
class cSkinCursesDisplayTracks : public cSkinDisplayTracks {
private:
cOsd *osd;
int itemsWidth;
int currentIndex;
void SetItem(const char *Text, int Index, bool Current);
public:
cSkinCursesDisplayTracks(const char *Title, int NumTracks, const char * const *Tracks);
virtual ~cSkinCursesDisplayTracks();
virtual void SetTrack(int Index, const char * const *Tracks);
virtual void SetAudioChannel(int AudioChannel) {}
virtual void Flush(void);
};
cSkinCursesDisplayTracks::cSkinCursesDisplayTracks(const char *Title, int NumTracks, const char * const *Tracks)
{
currentIndex = -1;
itemsWidth = Font.Width(Title);
for (int i = 0; i < NumTracks; i++)
itemsWidth = max(itemsWidth, Font.Width(Tracks[i]));
itemsWidth = min(itemsWidth, ScOsdWidth);
osd = new cCursesOsd(0, 0);
osd->DrawRectangle(0, 0, ScOsdWidth - 1, ScOsdHeight - 1, clrBackground);
osd->DrawText(0, 0, Title, clrBlack, clrCyan, &Font, itemsWidth);
for (int i = 0; i < NumTracks; i++)
SetItem(Tracks[i], i, false);
}
cSkinCursesDisplayTracks::~cSkinCursesDisplayTracks()
{
delete osd;
}
void cSkinCursesDisplayTracks::SetItem(const char *Text, int Index, bool Current)
{
int y = 1 + Index;
int ColorFg, ColorBg;
if (Current) {
ColorFg = clrBlack;
ColorBg = clrCyan;
currentIndex = Index;
}
else {
ColorFg = clrWhite;
ColorBg = clrBackground;
}
osd->DrawText(0, y, Text, ColorFg, ColorBg, &Font, itemsWidth);
}
void cSkinCursesDisplayTracks::SetTrack(int Index, const char * const *Tracks)
{
if (currentIndex >= 0)
SetItem(Tracks[currentIndex], currentIndex, false);
SetItem(Tracks[Index], Index, true);
}
void cSkinCursesDisplayTracks::Flush(void)
{
osd->Flush();
}
// --- cSkinCursesDisplayMessage ---------------------------------------------
class cSkinCursesDisplayMessage : public cSkinDisplayMessage {
private:
cOsd *osd;
public:
cSkinCursesDisplayMessage(void);
virtual ~cSkinCursesDisplayMessage();
virtual void SetMessage(eMessageType Type, const char *Text);
virtual void Flush(void);
};
cSkinCursesDisplayMessage::cSkinCursesDisplayMessage(void)
{
osd = new cCursesOsd(0, ScOsdHeight - 1);
}
cSkinCursesDisplayMessage::~cSkinCursesDisplayMessage()
{
delete osd;
}
void cSkinCursesDisplayMessage::SetMessage(eMessageType Type, const char *Text)
{
osd->DrawText(0, 0, Text, clrMessage[2 * Type], clrMessage[2 * Type + 1], &Font, ScOsdWidth, 0, taCenter);
}
void cSkinCursesDisplayMessage::Flush(void)
{
osd->Flush();
}
// --- cSkinCurses -----------------------------------------------------------
class cSkinCurses : public cSkin {
public:
cSkinCurses(void);
virtual const char *Description(void);
virtual cSkinDisplayChannel *DisplayChannel(bool WithInfo);
virtual cSkinDisplayMenu *DisplayMenu(void);
virtual cSkinDisplayReplay *DisplayReplay(bool ModeOnly);
virtual cSkinDisplayVolume *DisplayVolume(void);
virtual cSkinDisplayTracks *DisplayTracks(const char *Title, int NumTracks, const char * const *Tracks);
virtual cSkinDisplayMessage *DisplayMessage(void);
};
cSkinCurses::cSkinCurses(void)
:cSkin("curses")
{
}
const char *cSkinCurses::Description(void)
{
return tr("Text mode");
}
cSkinDisplayChannel *cSkinCurses::DisplayChannel(bool WithInfo)
{
return new cSkinCursesDisplayChannel(WithInfo);
}
cSkinDisplayMenu *cSkinCurses::DisplayMenu(void)
{
return new cSkinCursesDisplayMenu;
}
cSkinDisplayReplay *cSkinCurses::DisplayReplay(bool ModeOnly)
{
return new cSkinCursesDisplayReplay(ModeOnly);
}
cSkinDisplayVolume *cSkinCurses::DisplayVolume(void)
{
return new cSkinCursesDisplayVolume;
}
cSkinDisplayTracks *cSkinCurses::DisplayTracks(const char *Title, int NumTracks, const char * const *Tracks)
{
return new cSkinCursesDisplayTracks(Title, NumTracks, Tracks);
}
cSkinDisplayMessage *cSkinCurses::DisplayMessage(void)
{
return new cSkinCursesDisplayMessage;
}
// --- cPluginSkinCurses -----------------------------------------------------
class cPluginSkinCurses : public cPlugin {
private:
// Add any member variables or functions you may need here.
public:
cPluginSkinCurses(void);
virtual ~cPluginSkinCurses();
virtual const char *Version(void) { return VERSION; }
virtual const char *Description(void) { return tr(DESCRIPTION); }
virtual const char *CommandLineHelp(void);
virtual bool ProcessArgs(int argc, char *argv[]);
virtual bool Initialize(void);
virtual bool Start(void);
virtual void Housekeeping(void);
virtual const char *MainMenuEntry(void) { return tr(MAINMENUENTRY); }
virtual cOsdObject *MainMenuAction(void);
virtual cMenuSetupPage *SetupMenu(void);
virtual bool SetupParse(const char *Name, const char *Value);
};
cPluginSkinCurses::cPluginSkinCurses(void)
{
// Initialize any member variables here.
// DON'T DO ANYTHING ELSE THAT MAY HAVE SIDE EFFECTS, REQUIRE GLOBAL
// VDR OBJECTS TO EXIST OR PRODUCE ANY OUTPUT!
}
cPluginSkinCurses::~cPluginSkinCurses()
{
// Clean up after yourself!
endwin();
}
const char *cPluginSkinCurses::CommandLineHelp(void)
{
// Return a string that describes all known command line options.
return NULL;
}
bool cPluginSkinCurses::ProcessArgs(int argc, char *argv[])
{
// Implement command line argument processing here if applicable.
return true;
}
bool cPluginSkinCurses::Initialize(void)
{
// Initialize any background activities the plugin shall perform.
WINDOW *w = initscr();
if (w) {
ScOsdWidth = w->_maxx - w->_begx + 1;
ScOsdHeight = w->_maxy - w->_begy + 1;
return true;
}
return false;
}
bool cPluginSkinCurses::Start(void)
{
// Start any background activities the plugin shall perform.
cSkin *Skin = new cSkinCurses;
// This skin is normally used for debugging, so let's make it the current one:
Skins.SetCurrent(Skin->Name());
return true;
}
void cPluginSkinCurses::Housekeeping(void)
{
// Perform any cleanup or other regular tasks.
}
cOsdObject *cPluginSkinCurses::MainMenuAction(void)
{
// Perform the action when selected from the main VDR menu.
return NULL;
}
cMenuSetupPage *cPluginSkinCurses::SetupMenu(void)
{
// Return a setup menu in case the plugin supports one.
return NULL;
}
bool cPluginSkinCurses::SetupParse(const char *Name, const char *Value)
{
// Parse your own setup parameters and store their values.
return false;
}
VDRPLUGINCREATOR(cPluginSkinCurses); // Don't touch this!