vdr/interface.c
Klaus Schmidinger 48fea259ae Version 0.62
- The Makefile now defines DVBDIR to easily point to where the DVB driver
  source is located.
- When switching channels the current/next information is now displayed if
  available (thanks to Robert Schneider). Since there is now more information
  to read when switching channels, the timeout for displaying it has been
  increased from 2 to 5 seconds (remember that this info can always be recalled
  by pressing the "Ok" button).
  For this feature to work it is necessary that the 'Pnr' parameter in the
  channel setup ('channels.conf') is set to the proper value. This has been
  done for some of the channels in the default 'channels.conf'. Some other
  parameters in the default 'channels.conf' have also been updated, so please
  make sure your timers still use the correct channels!
2000-09-03 18:00:00 +02:00

360 lines
9.0 KiB
C

/*
* interface.c: Abstract user interface layer
*
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
* $Id: interface.c 1.11 2000/09/03 10:17:21 kls Exp $
*/
#include "interface.h"
#include <unistd.h>
#include "eit.h"
#include "remote.h"
cEIT EIT;
#if defined(REMOTE_RCU)
cRcIoRCU RcIo("/dev/ttyS1");
#elif defined(REMOTE_LIRC)
cRcIoLIRC RcIo("/dev/lircd");
#else
cRcIoKBD RcIo;
#endif
cInterface Interface;
cInterface::cInterface(void)
{
open = 0;
cols[0] = 0;
keyFromWait = kNone;
}
void cInterface::Init(void)
{
RcIo.SetCode(Keys.code, Keys.address);
}
void cInterface::Open(int NumCols, int NumLines)
{
if (!open++)
cDvbApi::PrimaryDvbApi->Open(NumCols, NumLines);
}
void cInterface::Close(void)
{
if (open == 1)
Clear();
if (!--open)
cDvbApi::PrimaryDvbApi->Close();
}
unsigned int cInterface::GetCh(bool Wait)
{
#ifdef DEBUG_OSD
timeout(0);
getch(); // just to make 'ncurses' display the window:
#endif
if (RcIo.InputAvailable(Wait)) {
unsigned int Command;
return RcIo.GetCommand(&Command, NULL) ? Command : 0;
}
return 0;
}
eKeys cInterface::GetKey(bool Wait)
{
eKeys Key = keyFromWait != kNone ? keyFromWait : Keys.Get(GetCh(Wait));
keyFromWait = kNone;
return Key;
}
eKeys cInterface::Wait(int Seconds, bool KeepChar)
{
int t0 = time_ms();
eKeys Key = kNone;
while (time_ms() - t0 < Seconds * 1000) {
Key = GetKey();
if (Key != kNone)
break;
}
if (KeepChar)
keyFromWait = Key;
return Key;
}
void cInterface::Clear(void)
{
if (open)
cDvbApi::PrimaryDvbApi->Clear();
}
void cInterface::ClearEol(int x, int y, eDvbColor Color)
{
if (open)
cDvbApi::PrimaryDvbApi->ClrEol(x, y, Color);
}
void cInterface::SetCols(int *c)
{
for (int i = 0; i < MaxCols; i++) {
cols[i] = *c++;
if (cols[i] == 0)
break;
}
}
void cInterface::Write(int x, int y, const char *s, eDvbColor FgColor, eDvbColor BgColor)
{
if (open)
cDvbApi::PrimaryDvbApi->Text(x, y, s, FgColor, BgColor);
}
void cInterface::WriteText(int x, int y, const char *s, bool Current)
{
if (open) {
eDvbColor FgColor = Current ? clrBlack : clrWhite;
eDvbColor BgColor = Current ? clrCyan : clrBackground;
ClearEol(x, y, BgColor);
int col = 0;
for (;;) {
const char *t = strchr(s, '\t');
const char *p = s;
char buf[1000];
if (t && col < MaxCols && cols[col] > 0) {
unsigned int n = t - s;
if (n >= sizeof(buf))
n = sizeof(buf) - 1;
strncpy(buf, s, n);
buf[n] = 0;
p = buf;
s = t + 1;
}
Write(x, y, p, FgColor, BgColor);
if (p == s)
break;
x += cols[col++];
}
}
}
void cInterface::Title(const char *s)
{
int x = (MenuColumns - strlen(s)) / 2;
if (x < 0)
x = 0;
ClearEol(0, 0, clrCyan);
Write(x, 0, s, clrBlack, clrCyan);
}
void cInterface::Status(const char *s, eDvbColor FgColor, eDvbColor BgColor)
{
ClearEol(0, -3, s ? BgColor : clrBackground);
if (s)
Write(0, -3, s, FgColor, BgColor);
}
void cInterface::Info(const char *s)
{
Open();
isyslog(LOG_INFO, s);
Status(s, clrWhite, clrGreen);
Wait();
Status(NULL);
Close();
}
void cInterface::Error(const char *s)
{
Open();
esyslog(LOG_ERR, s);
Status(s, clrWhite, clrRed);
Wait();
Status(NULL);
Close();
}
bool cInterface::Confirm(const char *s)
{
Open();
isyslog(LOG_INFO, "confirm: %s", s);
Status(s, clrBlack, clrGreen);
bool result = Wait(10) == kOk;
Status(NULL);
Close();
isyslog(LOG_INFO, "%sconfirmed", result ? "" : "not ");
return result;
}
void cInterface::HelpButton(int Index, const char *Text, eDvbColor FgColor, eDvbColor BgColor)
{
if (open && Text) {
const int w = MenuColumns / 4;
int l = (w - strlen(Text)) / 2;
if (l < 0)
l = 0;
cDvbApi::PrimaryDvbApi->Fill(Index * w, -1, w, 1, BgColor);
cDvbApi::PrimaryDvbApi->Text(Index * w + l, -1, Text, FgColor, BgColor);
}
}
void cInterface::Help(const char *Red, const char *Green, const char *Yellow, const char *Blue)
{
HelpButton(0, Red, clrBlack, clrRed);
HelpButton(1, Green, clrBlack, clrGreen);
HelpButton(2, Yellow, clrBlack, clrYellow);
HelpButton(3, Blue, clrWhite, clrBlue);
}
void cInterface::QueryKeys(void)
{
Keys.Clear();
WriteText(1, 1, "Learning Remote Control Keys");
WriteText(1, 3, "Phase 1: Detecting RC code type");
WriteText(1, 5, "Press any key on the RC unit");
#ifndef REMOTE_KBD
unsigned char Code = 0;
unsigned short Address;
#endif
for (;;) {
#ifdef REMOTE_KBD
if (GetCh())
break;
#else
//TODO on screen display...
if (RcIo.DetectCode(&Code, &Address)) {
Keys.code = Code;
Keys.address = Address;
WriteText(1, 5, "RC code detected!");
WriteText(1, 6, "Do not press any key...");
RcIo.Flush(3);
ClearEol(0, 5);
ClearEol(0, 6);
break;
}
#endif
}
WriteText(1, 3, "Phase 2: Learning specific key codes");
tKey *k = Keys.keys;
while (k->type != kNone) {
char *Prompt;
asprintf(&Prompt, "Press key for '%s'", k->name);
WriteText(1, 5, Prompt);
delete Prompt;
for (;;) {
unsigned int ch = GetCh();
if (ch != 0) {
switch (Keys.Get(ch)) {
case kUp: if (k > Keys.keys) {
k--;
break;
}
case kDown: if (k > Keys.keys + 1) {
WriteText(1, 5, "Press 'Up' to confirm");
WriteText(1, 6, "Press 'Down' to continue");
ClearEol(0, 7);
ClearEol(0, 8);
for (;;) {
eKeys key = GetKey();
if (key == kUp) {
Clear();
return;
}
else if (key == kDown) {
ClearEol(0, 6);
break;
}
}
break;
}
case kNone: k->code = ch;
k++;
break;
default: break;
}
break;
}
}
if (k > Keys.keys)
WriteText(1, 7, "(press 'Up' to go back)");
else
ClearEol(0, 7);
if (k > Keys.keys + 1)
WriteText(1, 8, "(press 'Down' to end key definition)");
else
ClearEol(0, 8);
}
}
void cInterface::LearnKeys(void)
{
isyslog(LOG_INFO, "learning keys");
Open();
for (;;) {
Clear();
QueryKeys();
Clear();
WriteText(1, 1, "Learning Remote Control Keys");
WriteText(1, 3, "Phase 3: Saving key codes");
WriteText(1, 5, "Press 'Up' to save, 'Down' to cancel");
for (;;) {
eKeys key = GetKey();
if (key == kUp) {
Keys.Save();
Close();
return;
}
else if (key == kDown) {
Keys.Load();
Close();
return;
}
}
}
}
void cInterface::DisplayChannel(int Number, const char *Name)
{
RcIo.Number(Number);
if (Name && !Recording()) {
Open(MenuColumns, EIT.IsValid() ? 5 : 1);
char buffer[MenuColumns + 1];
snprintf(buffer, sizeof(buffer), "%d %s", Number, Name ? Name : "");
Write(0, 0, buffer);
time_t t = time(NULL);
struct tm *now = localtime(&t);
snprintf(buffer, sizeof(buffer), "%02d:%02d", now->tm_hour, now->tm_min);
Write(-5, 0, buffer);
if (EIT.IsValid()) {
const int t = 7;
int w = MenuColumns - t;
Write(0, 1, EIT.GetRunningTime(), clrYellow, clrBackground);
snprintf(buffer, sizeof(buffer), "%.*s", w, EIT.GetRunningTitle());
Write(t, 1, buffer, clrCyan, clrBackground);
snprintf(buffer, sizeof(buffer), "%.*s", w, EIT.GetRunningSubtitle());
Write(t, 2, buffer, clrCyan, clrBackground);
Write(0, 3, EIT.GetNextTime(), clrYellow, clrBackground);
snprintf(buffer, sizeof(buffer), "%.*s", w, EIT.GetNextTitle());
Write(t, 3, buffer, clrCyan, clrBackground);
snprintf(buffer, sizeof(buffer), "%.*s", w, EIT.GetNextSubtitle());
Write(t, 4, buffer, clrCyan, clrBackground);
}
if (Wait(5, true) == kOk)
GetKey();
Close();
}
}
void cInterface::DisplayRecording(int Index, bool On)
{
RcIo.SetPoints(1 << Index, On);
}
bool cInterface::Recording(void)
{
// This is located here because the Interface has to do with the "PrimaryDvbApi" anyway
return cDvbApi::PrimaryDvbApi->Recording();
}