1
0
mirror of https://github.com/VDR4Arch/vdr.git synced 2023-10-10 13:36:52 +02:00

Menu uses colors; support for RGYB buttons; fixed DEBUG_REMOTE; Add, Del and Move for channels and timers; basic record/play file handling

This commit is contained in:
Klaus Schmidinger 2000-03-11 11:22:37 +01:00
parent 4a9d9c5876
commit 571686d909
23 changed files with 1378 additions and 366 deletions

12
HISTORY Normal file
View File

@ -0,0 +1,12 @@
Video Disk Recorder OSM Revision History
----------------------------------------
2000-02-19: Version 0.01 (Initial revision).
2000-03-11: Version 0.02
- Fixed compilation with only DEBUG_REMOTE=1.
- Menus now use colors.
- Support for "Red", "Green", "Yellow", "Blue" buttons.
- Channels and Timers can now be added, deleted and moved.
- Basic record/play file handling support (no actual record/playback yet).

View File

@ -4,9 +4,9 @@
# See the main source file 'osm.c' for copyright information and # See the main source file 'osm.c' for copyright information and
# how to reach the author. # how to reach the author.
# #
# $Id: Makefile 1.1 2000/02/19 13:36:48 kls Exp $ # $Id: Makefile 1.2 2000/03/05 13:51:57 kls Exp $
OBJS = config.o dvbapi.o interface.o menu.o osd.o remote.o tools.o osm.o OBJS = config.o dvbapi.o interface.o menu.o osd.o recording.o remote.o tools.o osm.o
ifdef DEBUG_REMOTE ifdef DEBUG_REMOTE
DEFINES += -DDEBUG_REMOTE DEFINES += -DDEBUG_REMOTE
@ -24,9 +24,10 @@ all: osm
config.o : config.c config.h dvbapi.h interface.h tools.h config.o : config.c config.h dvbapi.h interface.h tools.h
dvbapi.o : dvbapi.c config.h dvbapi.h interface.h tools.h dvbapi.o : dvbapi.c config.h dvbapi.h interface.h tools.h
interface.o: interface.c config.h dvbapi.h interface.h remote.h tools.h interface.o: interface.c config.h dvbapi.h interface.h remote.h tools.h
menu.o : menu.c config.h dvbapi.h interface.h menu.h osd.h tools.h menu.o : menu.c config.h dvbapi.h interface.h menu.h osd.h recording.h tools.h
osd.o : osd.c config.h interface.h osd.h tools.h osd.o : osd.c config.h dvbapi.h interface.h osd.h tools.h
osm.o : osm.c config.h dvbapi.h interface.h menu.h osd.h tools.h osm.o : osm.c config.h dvbapi.h interface.h menu.h osd.h recording.h tools.h
recording.o: recording.c config.h dvbapi.h interface.h recording.h tools.h
remote.o : remote.c remote.h tools.h remote.o : remote.c remote.h tools.h
tools.o : tools.c tools.h tools.o : tools.c tools.h

36
README
View File

@ -36,10 +36,34 @@ about that driver). For example, if the DVB driver was
extracted into the directory /home/kls/vdr/DVB, then this extracted into the directory /home/kls/vdr/DVB, then this
package should be extracted into /home/kls/vdr/OSM. package should be extracted into /home/kls/vdr/OSM.
In order for the menu colors to work correctly you may want
to replace the function RGB2YUV() in DVB/driver/dvb.c with
static u32 RGB2YUV(u16 R, u16 G, u16 B)
{
u16 y, u, v;
u16 Y, Cr, Cb;
y = R * 77 + G * 150 + B * 29; // Luma=0.299R+0.587G+0.114B 0..65535
u = 2048+B * 8 -(y>>5); // Cr 0..4095
v = 2048+R * 8 -(y>>5); // Cb 0..4095
Y = y >> 8;
Cb= u >> 4;
Cr= v >> 4;
return Cr|(Cb<<16)|(Y<<8);
}
(this may no longer be necessary with driver versions after 0.03c).
After extracting the package, change into the OSM directory After extracting the package, change into the OSM directory
and type 'make'. This should produce an executable file and type 'make'. This should produce an executable file
named 'osm', which can be run after the DVB driver has been named 'osm', which can be run after the DVB driver has been
installed. installed. There may be several warnings about "implicit declaration
of function `int asprintf(...)'" during the compilation, which I was
unable to avoid (anybody know how to avoid them?). Just ignore them,
the program will work, anyway.
There are two macros you can use to customize the 'osm' program There are two macros you can use to customize the 'osm' program
at compile time. Adding "DEBUG_REMOTE=1" to the 'make' call at compile time. Adding "DEBUG_REMOTE=1" to the 'make' call
@ -75,10 +99,10 @@ this package contains the codes for the "d-box" remote control unit.
If you want to use a different remote control unit, simply delete If you want to use a different remote control unit, simply delete
the file 'keys.conf' and restart the 'osm' program. The program will the file 'keys.conf' and restart the 'osm' program. The program will
then start a key learning session in which it first attempts to determine then start a key learning session in which it first attempts to determine
the basic data tranfer mode and timing of your remote control unit, the basic data transfer mode and timing of your remote control unit,
and then will ask you to press one key after the other so that it can and then will ask you to press one key after the other so that it can
learn the various key codes. You will at least need to provide an "Up" learn the various key codes. You will at least need to provide an "Up"
and a "Down" key, so that you can switch channels. The rest os the key and a "Down" key, so that you can switch channels. The rest of the key
definitions is optional, but the more keys you define, the more you definitions is optional, but the more keys you define, the more you
will be able to navigate through the menus. will be able to navigate through the menus.
@ -97,9 +121,6 @@ confirms any changes (or switches to a channel in the "Channels" menu).
The "Back" key goes back one level in the menu structure, discarding The "Back" key goes back one level in the menu structure, discarding
any changes that might have been made in the current menu. any changes that might have been made in the current menu.
In the "Channels" menu, the current channel can be edited by pressing
the "Right" key.
In the "Timers" menu, the current timer can be enabled or disabled with In the "Timers" menu, the current timer can be enabled or disabled with
the "Right" or "Left" key, respectively (enabled timers are marked with ">"). the "Right" or "Left" key, respectively (enabled timers are marked with ">").
"Ok" here opens the "Edit timer" menu. "Ok" here opens the "Edit timer" menu.
@ -110,6 +131,9 @@ character as in "[R]TL"), selecting the desired character position with
"Left" and "Right", and changing the character with the "Up" and "Down" "Left" and "Right", and changing the character with the "Up" and "Down"
keys. "Ok" then confirms the changes. keys. "Ok" then confirms the changes.
The "Red", "Green", "Yellow" and "Blue" buttons have special meanings
in the various menus and are listed at the bottom of the on-screen-display.
At any point in the menu system, pressing the "Menu" key again will At any point in the menu system, pressing the "Menu" key again will
immediately leave the menu system. immediately leave the menu system.

5
TODO
View File

@ -1,13 +1,12 @@
TODO list for the Video Disk Recorder project TODO list for the Video Disk Recorder project
--------------------------------------------- ---------------------------------------------
* Implement a way to add and delete channels and timers.
* Implement recording to disk and playback from disk. * Implement recording to disk and playback from disk.
* Implement disk file management (delete old/viewed files to make
room for new recordings if necessary).
* Make it work with two DVB-S PCI cards to allow simultaneous * Make it work with two DVB-S PCI cards to allow simultaneous
recording of one programme, while replaying another programme recording of one programme, while replaying another programme
(or maybe the same one, but time delayed). (or maybe the same one, but time delayed).
Maybe we can do this with only a single card, if the card
driver/firmware allows simultaneuos record/playback?
* Implement "on-disk editing" to allow "cutting out" of certain * Implement "on-disk editing" to allow "cutting out" of certain
scenes in order to archive them (or, reversely, cut out scenes in order to archive them (or, reversely, cut out
commercial breaks). commercial breaks).

View File

@ -42,7 +42,7 @@ B1:12722:h:1:22000:601:602
ARD Online-Kanal:12722:h:1:22000:8191:701 ARD Online-Kanal:12722:h:1:22000:8191:701
Premiere World Promo:11798:h:1:27500:255:256 Premiere World Promo:11798:h:1:27500:255:256
TV Niepokalanow:11876:h:1:27500:305:321 TV Niepokalanow:11876:h:1:27500:305:321
test card:11876:h:1:27500:306:322 test card:11798:h:1:27500:511:512
Mosaico:11934:v:1:27500:165:100 Mosaico:11934:v:1:27500:165:100
Andalucia TV:11934:v:1:27500:166:104 Andalucia TV:11934:v:1:27500:166:104
TVC Internacional:11934:v:1:27500:167:108 TVC Internacional:11934:v:1:27500:167:108

View File

@ -4,13 +4,12 @@
* See the main source file 'osm.c' for copyright information and * See the main source file 'osm.c' for copyright information and
* how to reach the author. * how to reach the author.
* *
* $Id: config.c 1.1 2000/02/19 13:36:48 kls Exp $ * $Id: config.c 1.2 2000/03/05 16:14:27 kls Exp $
*/ */
#include "config.h" #include "config.h"
#include <ctype.h> #include <ctype.h>
#include <stdlib.h> #include <stdlib.h>
#include <time.h>
#include "dvbapi.h" #include "dvbapi.h"
#include "interface.h" #include "interface.h"
@ -34,6 +33,10 @@ tKey keyTable[] = { // "Up" and "Down" must be the first two keys!
{ k7, "7", 0 }, { k7, "7", 0 },
{ k8, "8", 0 }, { k8, "8", 0 },
{ k9, "9", 0 }, { k9, "9", 0 },
{ kRed, "Red", 0 },
{ kGreen, "Green", 0 },
{ kYellow, "Yellow", 0 },
{ kBlue, "Blue", 0 },
{ kNone, "", 0 }, { kNone, "", 0 },
}; };
@ -160,6 +163,17 @@ cChannel::cChannel(void)
*name = 0; *name = 0;
} }
cChannel::cChannel(const cChannel *Channel)
{
strcpy(name, Channel ? Channel->name : "Pro7");
frequency = Channel ? Channel->frequency : 12480;
polarization = Channel ? Channel->polarization : 'v';
diseqc = Channel ? Channel->diseqc : 1;
srate = Channel ? Channel->srate : 27500;
vpid = Channel ? Channel->vpid : 255;
apid = Channel ? Channel->apid : 256;
}
bool cChannel::Parse(char *s) bool cChannel::Parse(char *s)
{ {
char *buffer = NULL; char *buffer = NULL;
@ -203,6 +217,17 @@ bool cChannel::SwitchTo(int i)
cTimer::cTimer(void) cTimer::cTimer(void)
{ {
startTime = stopTime = 0;
recording = false;
active = 1;
channel = CurrentChannel + 1;
day = 1; //XXX today!
start = 0; //XXX now!
stop = 0; //XXX now + 2h!
//TODO VPS???
quality = 'H';
priority = 99;
lifetime = 99;
*file = 0; *file = 0;
} }
@ -211,6 +236,13 @@ int cTimer::TimeToInt(int t)
return (t / 100 * 60 + t % 100) * 60; return (t / 100 * 60 + t % 100) * 60;
} }
time_t cTimer::Day(time_t t)
{
struct tm d = *localtime(&t);
d.tm_hour = d.tm_min = d.tm_sec = 0;
return mktime(&d);
}
int cTimer::ParseDay(char *s) int cTimer::ParseDay(char *s)
{ {
char *tail; char *tail;
@ -270,13 +302,17 @@ bool cTimer::Save(FILE *f)
return fprintf(f, "%d:%d:%s:%d:%d:%c:%d:%d:%s\n", active, channel, PrintDay(day), start, stop, quality, priority, lifetime, file) > 0; return fprintf(f, "%d:%d:%s:%d:%d:%c:%d:%d:%s\n", active, channel, PrintDay(day), start, stop, quality, priority, lifetime, file) > 0;
} }
bool cTimer::IsSingleEvent(void)
{
return (day & 0x80000000) == 0;
}
bool cTimer::Matches(void) bool cTimer::Matches(void)
{ {
if (active) { if (active) {
time_t t = time(NULL); time_t t = time(NULL);
struct tm *now = localtime(&t); struct tm now = *localtime(&t);
int weekday = now->tm_wday == 0 ? 6 : now->tm_wday - 1; // we start with monday==0! int weekday = now.tm_wday == 0 ? 6 : now.tm_wday - 1; // we start with monday==0!
int current = (now->tm_hour * 60 + now->tm_min) * 60 + now->tm_sec;
int begin = TimeToInt(start); int begin = TimeToInt(start);
int end = TimeToInt(stop); int end = TimeToInt(stop);
bool twoDays = (end < begin); bool twoDays = (end < begin);
@ -291,20 +327,44 @@ bool cTimer::Matches(void)
yesterdayMatches = true; yesterdayMatches = true;
} }
} }
else if (day == now->tm_mday) else if (day == now.tm_mday)
todayMatches = true; todayMatches = true;
else if (twoDays) { else if (twoDays) {
t -= 86400; time_t ty = t - SECSINDAY;
now = localtime(&t); if (day == localtime(&ty)->tm_mday)
if (day == now->tm_mday)
yesterdayMatches = true; yesterdayMatches = true;
} }
return (todayMatches && current >= begin && (current <= end || twoDays)) if (todayMatches || (twoDays && yesterdayMatches)) {
|| (twoDays && yesterdayMatches && current <= end); startTime = Day(t - (yesterdayMatches ? SECSINDAY : 0)) + begin;
stopTime = startTime + (twoDays ? SECSINDAY - begin + end : end - begin);
}
else
startTime = stopTime = 0;
return startTime <= t && t <= stopTime;
} }
return false; return false;
} }
time_t cTimer::StartTime(void)
{
if (!startTime)
Matches();
return startTime;
}
time_t cTimer::StopTime(void)
{
if (!stopTime)
Matches();
return stopTime;
}
void cTimer::SetRecording(bool Recording)
{
recording = Recording;
isyslog(LOG_INFO, "timer %d %s", Index() + 1, recording ? "start" : "stop");
}
cTimer *cTimer::GetMatch(void) cTimer *cTimer::GetMatch(void)
{ {
cTimer *t = (cTimer *)Timers.First(); cTimer *t = (cTimer *)Timers.First();

View File

@ -4,7 +4,7 @@
* See the main source file 'osm.c' for copyright information and * See the main source file 'osm.c' for copyright information and
* how to reach the author. * how to reach the author.
* *
* $Id: config.h 1.1 2000/02/19 13:36:48 kls Exp $ * $Id: config.h 1.2 2000/03/05 14:58:23 kls Exp $
*/ */
#ifndef __CONFIG_H #ifndef __CONFIG_H
@ -12,6 +12,7 @@
#include <stdio.h> #include <stdio.h>
#include <string.h> #include <string.h>
#include <time.h>
#include "tools.h" #include "tools.h"
#define MaxBuffer 1000 #define MaxBuffer 1000
@ -25,6 +26,10 @@ enum eKeys { // "Up" and "Down" must be the first two keys!
kLeft, kLeft,
kRight, kRight,
k0, k1, k2, k3, k4, k5, k6, k7, k8, k9, k0, k1, k2, k3, k4, k5, k6, k7, k8, k9,
kRed,
kGreen,
kYellow,
kBlue,
kNone kNone
}; };
@ -60,6 +65,7 @@ public:
int vpid; int vpid;
int apid; int apid;
cChannel(void); cChannel(void);
cChannel(const cChannel *Channel);
bool Parse(char *s); bool Parse(char *s);
bool Save(FILE *f); bool Save(FILE *f);
bool Switch(void); bool Switch(void);
@ -67,8 +73,11 @@ public:
}; };
class cTimer : public cListObject { class cTimer : public cListObject {
private:
time_t startTime, stopTime;
public: public:
enum { MaxFileName = 256 }; enum { MaxFileName = 256 };
bool recording;
int active; int active;
int channel; int channel;
int day; int day;
@ -82,9 +91,14 @@ public:
cTimer(void); cTimer(void);
bool Parse(char *s); bool Parse(char *s);
bool Save(FILE *f); bool Save(FILE *f);
bool IsSingleEvent(void);
bool Matches(void); bool Matches(void);
time_t StartTime(void);
time_t StopTime(void);
void SetRecording(bool Recording);
static cTimer *GetMatch(void); static cTimer *GetMatch(void);
static int TimeToInt(int t); static int TimeToInt(int t);
static time_t Day(time_t t);
static int ParseDay(char *s); static int ParseDay(char *s);
static char *PrintDay(int d); static char *PrintDay(int d);
}; };

162
dvbapi.c
View File

@ -4,20 +4,14 @@
* See the main source file 'osm.c' for copyright information and * See the main source file 'osm.c' for copyright information and
* how to reach the author. * how to reach the author.
* *
* $Id: dvbapi.c 1.1 2000/02/19 13:36:48 kls Exp $ * $Id: dvbapi.c 1.2 2000/03/11 10:39:09 kls Exp $
*/ */
// FIXME: these should be defined in ../DVB/driver/dvb.h!!!
typedef unsigned int u32;
typedef unsigned short u16;
typedef unsigned char u8;
#include "dvbapi.h" #include "dvbapi.h"
#include <fcntl.h> #include <fcntl.h>
#include <stdio.h> #include <stdio.h>
#include <sys/ioctl.h> #include <sys/ioctl.h>
#include <unistd.h> #include <unistd.h>
#include "../DVB/driver/dvb.h"
#include "interface.h" #include "interface.h"
#include "tools.h" #include "tools.h"
@ -60,6 +54,7 @@ bool DvbSetChannel(int FrequencyMHz, char Polarization, int Diseqc, int Srate, i
cDvbRecorder::cDvbRecorder(void) cDvbRecorder::cDvbRecorder(void)
{ {
recording = false;
} }
cDvbRecorder::~cDvbRecorder() cDvbRecorder::~cDvbRecorder()
@ -67,18 +62,41 @@ cDvbRecorder::~cDvbRecorder()
Stop(); Stop();
} }
bool cDvbRecorder::Recording(void)
{
return recording;
}
bool cDvbRecorder::Record(const char *FileName, char Quality) bool cDvbRecorder::Record(const char *FileName, char Quality)
{ {
isyslog(LOG_INFO, "record %s (%c)", FileName, Quality); isyslog(LOG_INFO, "record %s (%c)", FileName, Quality);
if (MakeDirs(FileName)) {
FILE *f = fopen(FileName, "a");
if (f) {
fprintf(f, "%s, %c\n", FileName, Quality);
fclose(f);
recording = true;
// TODO
Interface.Error("Recording not yet implemented!");
return true; return true;
}
else {
Interface.Error("Can't write to file!");
return false;
}
}
// TODO // TODO
return false; return false;
} }
bool cDvbRecorder::Play(const char *FileName, int Frame) bool cDvbRecorder::Play(const char *FileName, int Frame)
{ {
if (!recording) {
isyslog(LOG_INFO, "play %s (%d)", FileName, Frame); isyslog(LOG_INFO, "play %s (%d)", FileName, Frame);
// TODO // TODO
Interface.Error("Playback not yet implemented!");
return true;
}
return false; return false;
} }
@ -106,6 +124,7 @@ bool cDvbRecorder::Pause(void)
void cDvbRecorder::Stop(void) void cDvbRecorder::Stop(void)
{ {
isyslog(LOG_INFO, "stop"); isyslog(LOG_INFO, "stop");
recording = false;
// TODO // TODO
} }
@ -116,9 +135,57 @@ int cDvbRecorder::Frame(void)
return 0; return 0;
} }
// --------------------------------------------------------------------------- // --- cDvbOsd ---------------------------------------------------------------
static void DvbOsdCmd(OSD_Command cmd, int color = 0, int x0 = 0, int y0 = 0, int x1 = 0, int y1 = 0, void *data = NULL) cDvbOsd::cDvbOsd(void)
{
cols = rows = 0;
#ifdef DEBUG_OSD
memset(&colorPairs, 0, sizeof(colorPairs));
initscr();
start_color();
keypad(stdscr, TRUE);
nonl();
cbreak();
noecho();
timeout(1000);
leaveok(stdscr, TRUE);
window = stdscr;
#endif
#ifdef DEBUG_REMOTE
initscr();
keypad(stdscr, TRUE);
nonl();
cbreak();
noecho();
timeout(1000);
#endif
}
cDvbOsd::~cDvbOsd()
{
Close();
}
#ifdef DEBUG_OSD
void cDvbOsd::SetColor(eDvbColor colorFg, eDvbColor 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);
wattrset(window, COLOR_PAIR(i + 1));
break;
}
else if (color == colorPairs[i]) {
wattrset(window, COLOR_PAIR(i + 1));
break;
}
}
}
#else
void cDvbOsd::Cmd(OSD_Command cmd, int color, int x0, int y0, int x1, int y1, const void *data)
{ {
int v = open(VIDEODEVICE, O_RDWR); int v = open(VIDEODEVICE, O_RDWR);
@ -130,37 +197,88 @@ static void DvbOsdCmd(OSD_Command cmd, int color = 0, int x0 = 0, int y0 = 0, in
dc.y0 = y0; dc.y0 = y0;
dc.x1 = x1; dc.x1 = x1;
dc.y1 = y1; dc.y1 = y1;
dc.data = data; dc.data = (void *)data;
ioctl(v, VIDIOCSOSDCOMMAND, &dc); ioctl(v, VIDIOCSOSDCOMMAND, &dc);
close(v); close(v);
} }
else else
Interface.Error("can't open VIDEODEVICE");//XXX Interface.Error("can't open VIDEODEVICE");//XXX
} }
#endif
void DvbOsdOpen(int x, int y, int w, int h) void cDvbOsd::Open(int w, int h)
{ {
DvbOsdCmd(OSD_Open, 1, x, y, x + w - 1, y + h - 1); cols = w;
DvbOsdCmd(OSD_SetColor, 0, 0, 0, 0, 127); // background 50% gray rows = h;
DvbOsdCmd(OSD_SetColor, 1, 255, 255, 255, 255); // text white #ifdef DEBUG_OSD
//XXX size...
#define B2C(b) (((b) * 1000) / 255)
#define SETCOLOR(n, r, g, b, o) init_color(n, B2C(r), B2C(g), B2C(b))
#else
w *= charWidth;
h *= lineHeight;
int x = (720 - w) / 2; //TODO PAL vs. NTSC???
int y = (576 - h) / 2;
Cmd(OSD_Open, 4, x, y, x + w - 1, y + h - 1);
#define SETCOLOR(n, r, g, b, o) Cmd(OSD_SetColor, n, r, g, b, o)
#endif
SETCOLOR(clrBackground, 0x00, 0x00, 0x00, 127); // background 50% gray
SETCOLOR(clrBlack, 0x00, 0x00, 0x00, 255);
SETCOLOR(clrRed, 0xFC, 0x14, 0x14, 255);
SETCOLOR(clrGreen, 0x24, 0xFC, 0x24, 255);
SETCOLOR(clrYellow, 0xFC, 0xC0, 0x24, 255);
SETCOLOR(clrBlue, 0x00, 0x00, 0xFC, 255);
SETCOLOR(clrCyan, 0x00, 0xFC, 0xFC, 255);
SETCOLOR(clrMagenta, 0xB0, 0x00, 0xFC, 255);
SETCOLOR(clrWhite, 0xFC, 0xFC, 0xFC, 255);
} }
void DvbOsdClose(void) void cDvbOsd::Close(void)
{ {
DvbOsdCmd(OSD_Close); #ifndef DEBUG_OSD
Cmd(OSD_Close);
#endif
} }
void DvbOsdClear(void) void cDvbOsd::Clear(void)
{ {
DvbOsdCmd(OSD_Clear); #ifdef DEBUG_OSD
SetColor(clrBackground, clrBackground);
Fill(0, 0, cols, rows, clrBackground);
#else
Cmd(OSD_Clear);
#endif
} }
void DvbOsdClrEol(int x, int y) void cDvbOsd::Fill(int x, int y, int w, int h, eDvbColor color)
{ {
DvbOsdCmd(OSD_FillBlock, 0, x, y * DvbOsdLineHeight, x + 490, (y + 1) * DvbOsdLineHeight);//XXX if (x < 0) x = cols + x;
if (y < 0) y = rows + y;
#ifdef DEBUG_OSD
SetColor(color, color);
for (int r = 0; r < h; r++) {
wmove(window, y + r, x); // ncurses wants 'y' before 'x'!
whline(window, ' ', w);
}
#else
Cmd(OSD_FillBlock, color, x * charWidth, y * lineHeight, (x + w) * charWidth - 1, (y + h) * lineHeight - 1);
#endif
} }
void DvbOsdText(int x, int y, char *s) void cDvbOsd::ClrEol(int x, int y, eDvbColor color)
{ {
DvbOsdCmd(OSD_Text, 1, x, y, 1, 0, s); Fill(x, y, cols - x, 1, color);
}
void cDvbOsd::Text(int x, int y, const char *s, eDvbColor colorFg, eDvbColor colorBg)
{
if (x < 0) x = cols + x;
if (y < 0) y = rows + y;
#ifdef DEBUG_OSD
SetColor(colorFg, colorBg);
wmove(window, y, x); // ncurses wants 'y' before 'x'!
waddstr(window, s);
#else
Cmd(OSD_Text, (int(colorBg) << 16) | colorFg, x * charWidth, y * lineHeight, 1, 0, s);
#endif
} }

View File

@ -4,23 +4,51 @@
* See the main source file 'osm.c' for copyright information and * See the main source file 'osm.c' for copyright information and
* how to reach the author. * how to reach the author.
* *
* $Id: dvbapi.h 1.1 2000/02/19 13:36:48 kls Exp $ * $Id: dvbapi.h 1.2 2000/03/06 19:47:20 kls Exp $
*/ */
#ifndef __DVBAPI_H #ifndef __DVBAPI_H
#define __DVBAPI_H #define __DVBAPI_H
const int DvbOsdCharWidth = 12; //XXX // FIXME: these should be defined in ../DVB/driver/dvb.h!!!
const int DvbOsdLineHeight = 25; typedef unsigned int u32;
typedef unsigned short u16;
typedef unsigned char u8;
#if defined(DEBUG_OSD) || defined(DEBUG_REMOTE)
#include <ncurses.h>
#endif
#include "../DVB/driver/dvb.h"
enum eDvbColor { clrBackground,
#ifndef DEBUG_OSD
clrOBSOLETE, //FIXME apparently color '1' can't be used as FgColor with e.g. clrRed as BgColor???
clrBlack,
#else
clrBlack = clrBackground,
#endif
clrRed,
clrGreen,
clrYellow,
clrBlue,
clrMagenta,
clrCyan,
clrWhite,
};
extern const char *DvbQuality; // Low, Medium, High extern const char *DvbQuality; // Low, Medium, High
bool DvbSetChannel(int FrequencyMHz, char Polarization, int Diseqc, int Srate, int Vpid, int Apid); bool DvbSetChannel(int FrequencyMHz, char Polarization, int Diseqc, int Srate, int Vpid, int Apid);
class cDvbRecorder { class cDvbRecorder {
private:
bool recording;
public: public:
cDvbRecorder(void); cDvbRecorder(void);
~cDvbRecorder(); ~cDvbRecorder();
bool Recording(void);
// Returns true if this recorder is currently recording, false if it
// is playing back or does nothing.
bool Record(const char *FileName, char Quality); bool Record(const char *FileName, char Quality);
// Starts recording the current channel into the given file, with the // Starts recording the current channel into the given file, with the
// given quality level. Any existing file will be overwritten. // given quality level. Any existing file will be overwritten.
@ -30,8 +58,9 @@ public:
bool Play(const char *FileName, int Frame = 0); bool Play(const char *FileName, int Frame = 0);
// Starts playback of the given file, at the optional Frame (default // Starts playback of the given file, at the optional Frame (default
// is the beginning of the file). If Frame is beyond the last recorded // is the beginning of the file). If Frame is beyond the last recorded
// frame in the file, or if it is negative, playback will be positioned // frame in the file (or if it is negative), playback will be positioned
// to the last frame in the file and will do an implicit Pause() there. // to the last frame in the file (or the frame with the absolute value of
// Frame) and will do an implicit Pause() there.
// If there is already a playback session active, it will be stopped // If there is already a playback session active, it will be stopped
// and the new file or frame (which may be in the same file) will // and the new file or frame (which may be in the same file) will
// be played back. // be played back.
@ -56,10 +85,29 @@ public:
// The very first frame has the number 1. // The very first frame has the number 1.
}; };
void DvbOsdOpen(int x, int y, int w, int h); class cDvbOsd {
void DvbOsdClose(void); private:
void DvbOsdClear(void); enum { charWidth = 12, // average character width
void DvbOsdClrEol(int x, int y); lineHeight = 27 // smallest text height
void DvbOsdText(int x, int y, char *s); };
#ifdef DEBUG_OSD
WINDOW *window;
enum { MaxColorPairs = 16 };
int colorPairs[MaxColorPairs];
void SetColor(eDvbColor colorFg, eDvbColor colorBg = clrBackground);
#else
void Cmd(OSD_Command cmd, int color = 0, int x0 = 0, int y0 = 0, int x1 = 0, int y1 = 0, const void *data = NULL);
#endif
int cols, rows;
public:
cDvbOsd(void);
~cDvbOsd();
void Open(int w, int h);
void Close(void);
void Clear(void);
void Fill(int x, int y, int w, int h, eDvbColor color = clrBackground);
void ClrEol(int x, int y, eDvbColor color = clrBackground);
void Text(int x, int y, const char *s, eDvbColor colorFg = clrWhite, eDvbColor colorBg = clrBackground);
};
#endif //__DVBAPI_H #endif //__DVBAPI_H

View File

@ -4,20 +4,21 @@
* See the main source file 'osm.c' for copyright information and * See the main source file 'osm.c' for copyright information and
* how to reach the author. * how to reach the author.
* *
* $Id: interface.c 1.1 2000/02/19 13:36:48 kls Exp $ * $Id: interface.c 1.2 2000/03/06 19:45:03 kls Exp $
*/ */
#include "interface.h" #include "interface.h"
#include <ncurses.h>
#include <unistd.h> #include <unistd.h>
#include "dvbapi.h"
#include "remote.h" #include "remote.h"
#define MenuLines 15
#define MenuColumns 40
#ifndef DEBUG_REMOTE #ifndef DEBUG_REMOTE
cRcIo RcIo("/dev/ttyS1");//XXX cRcIo RcIo("/dev/ttyS1");//XXX
#endif #endif
WINDOW *window; cDvbOsd DvbOsd; //XXX member of cInterface???
cInterface Interface; cInterface Interface;
@ -25,16 +26,6 @@ cInterface::cInterface(void)
{ {
open = 0; open = 0;
cols[0] = 0; cols[0] = 0;
#ifdef DEBUG_OSD
initscr();
keypad(stdscr, TRUE);
nonl();
cbreak();
noecho();
leaveok(stdscr, TRUE);
window = stdscr;
#else
#endif
} }
void cInterface::Init(void) void cInterface::Init(void)
@ -46,24 +37,14 @@ void cInterface::Init(void)
void cInterface::Open(void) void cInterface::Open(void)
{ {
if (!open++) { if (!open++)
#ifdef DEBUG_OSD DvbOsd.Open(MenuColumns, MenuLines);
#else
//TODO
DvbOsdOpen(100, 100, 500, 400);
#endif
}
} }
void cInterface::Close(void) void cInterface::Close(void)
{ {
if (!--open) { if (!--open)
#ifdef DEBUG_OSD DvbOsd.Close();
#else
//TODO
DvbOsdClose();
#endif
}
} }
unsigned int cInterface::GetCh(void) unsigned int cInterface::GetCh(void)
@ -71,9 +52,9 @@ unsigned int cInterface::GetCh(void)
#ifdef DEBUG_REMOTE #ifdef DEBUG_REMOTE
return getch(); return getch();
#else #else
#ifdef DEBUG_OSD //XXX #ifdef DEBUG_OSD
wrefresh(window);//XXX //XXX wrefresh(window);//XXX
#endif //XXX #endif
unsigned int Command; unsigned int Command;
return RcIo.GetCommand(&Command) ? Command : 0; return RcIo.GetCommand(&Command) ? Command : 0;
#endif #endif
@ -84,16 +65,28 @@ eKeys cInterface::GetKey(void)
return Keys.Get(GetCh()); return Keys.Get(GetCh());
} }
eKeys cInterface::Wait(int Seconds)
{
int t0 = time_ms();
while (time_ms() - t0 < Seconds * 1000) {
eKeys Key = GetKey();
if (Key != kNone)
return Key;
}
return kNone;
}
void cInterface::Clear(void) void cInterface::Clear(void)
{ {
if (open) { if (open)
#ifdef DEBUG_OSD DvbOsd.Clear();
wclear(window); }
#else
//TODO void cInterface::ClearEol(int x, int y, eDvbColor Color)
DvbOsdClear(); {
#endif if (open)
} DvbOsd.ClrEol(x, y, Color);
} }
void cInterface::SetCols(int *c) void cInterface::SetCols(int *c)
@ -105,34 +98,22 @@ void cInterface::SetCols(int *c)
} }
} }
void cInterface::Write(int x, int y, char *s) void cInterface::Write(int x, int y, const char *s, eDvbColor FgColor, eDvbColor BgColor)
{ {
if (open) { if (open)
#ifdef DEBUG_OSD DvbOsd.Text(x, y, s, FgColor, BgColor);
wmove(window, y, x); // ncurses wants 'y' before 'x'!
waddstr(window, s);
#else
DvbOsdText(x * DvbOsdCharWidth, y * DvbOsdLineHeight, s);
#endif
}
} }
void cInterface::WriteText(int x, int y, char *s, bool Current) void cInterface::WriteText(int x, int y, const char *s, bool Current)
{ {
if (open) { if (open) {
#ifdef DEBUG_OSD eDvbColor FgColor = Current ? clrBlack : clrWhite;
wmove(window, y, x); // ncurses wants 'y' before 'x'! eDvbColor BgColor = Current ? clrCyan : clrBackground;
wclrtoeol(window);//XXX ClearEol(x, y, BgColor);
#else
//TODO
DvbOsdClrEol(x * DvbOsdCharWidth, y);//XXX
#endif
Write(x, y, Current ? "*" : " ");
x++;
int col = 0; int col = 0;
for (;;) { for (;;) {
char *t = strchr(s, '\t'); const char *t = strchr(s, '\t');
char *p = s; const char *p = s;
char buf[1000]; char buf[1000];
if (t && col < MaxCols && cols[col] > 0) { if (t && col < MaxCols && cols[col] > 0) {
unsigned int n = t - s; unsigned int n = t - s;
@ -143,7 +124,7 @@ void cInterface::WriteText(int x, int y, char *s, bool Current)
p = buf; p = buf;
s = t + 1; s = t + 1;
} }
Write(x, y, p); Write(x, y, p, FgColor, BgColor);
if (p == s) if (p == s)
break; break;
x += cols[col++]; x += cols[col++];
@ -151,38 +132,74 @@ void cInterface::WriteText(int x, int y, char *s, bool Current)
} }
} }
void cInterface::Info(char *s) 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(); Open();
isyslog(LOG_ERR, s); isyslog(LOG_INFO, s);
WriteText(0, 11, s);//TODO Status(s, clrWhite, clrGreen);
#ifdef DEBUG_OSD Wait();
wrefresh(window);//XXX Status(NULL);
#endif
sleep(1);
WriteText(0, 11, "");//TODO
#ifdef DEBUG_OSD
wrefresh(window);//XXX
#endif
Close(); Close();
} }
void cInterface::Error(char *s) void cInterface::Error(const char *s)
{ {
Open(); Open();
esyslog(LOG_ERR, s); esyslog(LOG_ERR, s);
WriteText(0, 12, s);//TODO Status(s, clrWhite, clrRed);
#ifdef DEBUG_OSD Wait();
wrefresh(window);//XXX Status(NULL);
#endif
sleep(1);
WriteText(0, 12, "");//TODO
#ifdef DEBUG_OSD
wrefresh(window);//XXX
#endif
Close(); 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;
DvbOsd.Fill(Index * w, -1, w, 1, BgColor);
DvbOsd.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) void cInterface::QueryKeys(void)
{ {
Keys.Clear(); Keys.Clear();
@ -205,8 +222,8 @@ void cInterface::QueryKeys(void)
WriteText(1, 5, "RC code detected!"); WriteText(1, 5, "RC code detected!");
WriteText(1, 6, "Do not press any key..."); WriteText(1, 6, "Do not press any key...");
RcIo.Flush(3); RcIo.Flush(3);
WriteText(1, 5, ""); ClearEol(0, 5);
WriteText(1, 6, ""); ClearEol(0, 6);
break; break;
} }
#endif #endif
@ -229,8 +246,8 @@ void cInterface::QueryKeys(void)
case kDown: if (k > Keys.keys + 1) { case kDown: if (k > Keys.keys + 1) {
WriteText(1, 5, "Press 'Up' to confirm"); WriteText(1, 5, "Press 'Up' to confirm");
WriteText(1, 6, "Press 'Down' to continue"); WriteText(1, 6, "Press 'Down' to continue");
WriteText(1, 7, ""); ClearEol(0, 7);
WriteText(1, 8, ""); ClearEol(0, 8);
for (;;) { for (;;) {
eKeys key = GetKey(); eKeys key = GetKey();
if (key == kUp) { if (key == kUp) {
@ -238,7 +255,7 @@ void cInterface::QueryKeys(void)
return; return;
} }
else if (key == kDown) { else if (key == kDown) {
WriteText(1, 6, ""); ClearEol(0, 6);
break; break;
} }
} }
@ -255,17 +272,18 @@ void cInterface::QueryKeys(void)
if (k > Keys.keys) if (k > Keys.keys)
WriteText(1, 7, "(press 'Up' to go back)"); WriteText(1, 7, "(press 'Up' to go back)");
else else
WriteText(1, 7, ""); ClearEol(0, 7);
if (k > Keys.keys + 1) if (k > Keys.keys + 1)
WriteText(1, 8, "(press 'Down' to end key definition)"); WriteText(1, 8, "(press 'Down' to end key definition)");
else else
WriteText(1, 8, ""); ClearEol(0, 8);
} }
} }
void cInterface::LearnKeys(void) void cInterface::LearnKeys(void)
{ {
isyslog(LOG_INFO, "learning keys"); isyslog(LOG_INFO, "learning keys");
Open();
for (;;) { for (;;) {
Clear(); Clear();
QueryKeys(); QueryKeys();
@ -277,19 +295,19 @@ void cInterface::LearnKeys(void)
eKeys key = GetKey(); eKeys key = GetKey();
if (key == kUp) { if (key == kUp) {
Keys.Save(); Keys.Save();
Clear(); Close();
return; return;
} }
else if (key == kDown) { else if (key == kDown) {
Keys.Load(); Keys.Load();
Clear(); Close();
return; return;
} }
} }
} }
} }
void cInterface::DisplayChannel(int Number, char *Name) void cInterface::DisplayChannel(int Number, const char *Name)
{ {
//TODO //TODO
#ifndef DEBUG_REMOTE #ifndef DEBUG_REMOTE

View File

@ -4,13 +4,14 @@
* See the main source file 'osm.c' for copyright information and * See the main source file 'osm.c' for copyright information and
* how to reach the author. * how to reach the author.
* *
* $Id: interface.h 1.1 2000/02/19 13:36:48 kls Exp $ * $Id: interface.h 1.2 2000/02/27 14:54:02 kls Exp $
*/ */
#ifndef __INTERFACE_H #ifndef __INTERFACE_H
#define __INTERFACE_H #define __INTERFACE_H
#include "config.h" #include "config.h"
#include "dvbapi.h"
class cInterface { class cInterface {
public: public:
@ -20,7 +21,8 @@ private:
int cols[MaxCols]; int cols[MaxCols];
unsigned int GetCh(void); unsigned int GetCh(void);
void QueryKeys(void); void QueryKeys(void);
void Write(int x, int y, char *s); void HelpButton(int Index, const char *Text, eDvbColor FgColor, eDvbColor BgColor);
eKeys Wait(int Seconds = 1);
public: public:
cInterface(void); cInterface(void);
void Init(void); void Init(void);
@ -28,12 +30,18 @@ public:
void Close(void); void Close(void);
eKeys GetKey(void); eKeys GetKey(void);
void Clear(void); void Clear(void);
void ClearEol(int x, int y, eDvbColor Color = clrBackground);
void SetCols(int *c); void SetCols(int *c);
void WriteText(int x, int y, char *s, bool Current = false); void Write(int x, int y, const char *s, eDvbColor FgColor = clrWhite, eDvbColor BgColor = clrBackground);
void Info(char *s); void WriteText(int x, int y, const char *s, bool Current = false);
void Error(char *s); void Title(const char *s);
void Status(const char *s, eDvbColor FgColor = clrBlack, eDvbColor BgColor = clrCyan);
void Info(const char *s);
void Error(const char *s);
bool Confirm(const char *s);
void Help(const char *Red, const char *Green = NULL, const char *Yellow = NULL, const char *Blue = NULL);
void LearnKeys(void); void LearnKeys(void);
void DisplayChannel(int Number, char *Name); void DisplayChannel(int Number, const char *Name);
}; };
extern cInterface Interface; extern cInterface Interface;

Binary file not shown.

View File

@ -17,3 +17,7 @@ Right 000045E2
7 00000FE2 7 00000FE2
8 000077E2 8 000077E2
9 000037E2 9 000037E2
Red 000025E2
Green 00002AE2
Yellow 00005AE2
Blue 00000000

440
menu.c
View File

@ -4,7 +4,7 @@
* See the main source file 'osm.c' for copyright information and * See the main source file 'osm.c' for copyright information and
* how to reach the author. * how to reach the author.
* *
* $Id: menu.c 1.1 2000/02/19 13:36:48 kls Exp $ * $Id: menu.c 1.2 2000/03/05 15:37:31 kls Exp $
*/ */
#include "menu.h" #include "menu.h"
@ -13,8 +13,9 @@
#include <string.h> #include <string.h>
#include "config.h" #include "config.h"
#include "dvbapi.h" #include "dvbapi.h"
#include "recording.h"
const char *FileNameChars = "AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz0123456789/-.# ";//TODO more? const char *FileNameChars = "aAbBcCdDeEfFgGhHiIjJkKlLmMnNoOpPqQrRsStTuUvVwWxXyYzZ0123456789-.# ";
// --- cMenuEditItem --------------------------------------------------------- // --- cMenuEditItem ---------------------------------------------------------
@ -59,7 +60,7 @@ protected:
virtual void Set(void); virtual void Set(void);
public: public:
cMenuEditIntItem(const char *Name, int *Value, int Min = 0, int Max = INT_MAX); cMenuEditIntItem(const char *Name, int *Value, int Min = 0, int Max = INT_MAX);
virtual eOSStatus ProcessKey(eKeys Key); virtual eOSState ProcessKey(eKeys Key);
}; };
cMenuEditIntItem::cMenuEditIntItem(const char *Name, int *Value, int Min, int Max) cMenuEditIntItem::cMenuEditIntItem(const char *Name, int *Value, int Min, int Max)
@ -78,11 +79,11 @@ void cMenuEditIntItem::Set(void)
SetValue(buf); SetValue(buf);
} }
eOSStatus cMenuEditIntItem::ProcessKey(eKeys Key) eOSState cMenuEditIntItem::ProcessKey(eKeys Key)
{ {
eOSStatus status = cMenuEditItem::ProcessKey(Key); eOSState state = cMenuEditItem::ProcessKey(Key);
if (status == osUnknown) { if (state == osUnknown) {
int newValue; int newValue;
if (k0 <= Key && Key <= k9) { if (k0 <= Key && Key <= k9) {
if (fresh) { if (fresh) {
@ -100,14 +101,14 @@ eOSStatus cMenuEditIntItem::ProcessKey(eKeys Key)
fresh = true; fresh = true;
} }
else else
return status; return state;
if ((!fresh || min <= newValue) && newValue <= max) { if ((!fresh || min <= newValue) && newValue <= max) {
*value = newValue; *value = newValue;
Set(); Set();
} }
status = osContinue; state = osContinue;
} }
return status; return state;
} }
// --- cMenuEditBoolItem ----------------------------------------------------- // --- cMenuEditBoolItem -----------------------------------------------------
@ -167,7 +168,7 @@ protected:
virtual void Set(void); virtual void Set(void);
public: public:
cMenuEditDayItem(const char *Name, int *Value); cMenuEditDayItem(const char *Name, int *Value);
virtual eOSStatus ProcessKey(eKeys Key); virtual eOSState ProcessKey(eKeys Key);
}; };
int cMenuEditDayItem::days[] ={ cTimer::ParseDay("M------"), int cMenuEditDayItem::days[] ={ cTimer::ParseDay("M------"),
@ -205,7 +206,7 @@ void cMenuEditDayItem::Set(void)
SetValue(cTimer::PrintDay(*value)); SetValue(cTimer::PrintDay(*value));
} }
eOSStatus cMenuEditDayItem::ProcessKey(eKeys Key) eOSState cMenuEditDayItem::ProcessKey(eKeys Key)
{ {
switch (Key) { switch (Key) {
case kLeft: if (d > 0) case kLeft: if (d > 0)
@ -252,7 +253,7 @@ protected:
virtual void Set(void); virtual void Set(void);
public: public:
cMenuEditTimeItem(const char *Name, int *Value); cMenuEditTimeItem(const char *Name, int *Value);
virtual eOSStatus ProcessKey(eKeys Key); virtual eOSState ProcessKey(eKeys Key);
}; };
cMenuEditTimeItem::cMenuEditTimeItem(const char *Name, int *Value) cMenuEditTimeItem::cMenuEditTimeItem(const char *Name, int *Value)
@ -272,11 +273,11 @@ void cMenuEditTimeItem::Set(void)
SetValue(buf); SetValue(buf);
} }
eOSStatus cMenuEditTimeItem::ProcessKey(eKeys Key) eOSState cMenuEditTimeItem::ProcessKey(eKeys Key)
{ {
eOSStatus status = cMenuEditItem::ProcessKey(Key); eOSState state = cMenuEditItem::ProcessKey(Key);
if (status == osUnknown) { if (state == osUnknown) {
if (k0 <= Key && Key <= k9) { if (k0 <= Key && Key <= k9) {
if (fresh || pos > 3) { if (fresh || pos > 3) {
pos = 0; pos = 0;
@ -324,12 +325,12 @@ eOSStatus cMenuEditTimeItem::ProcessKey(eKeys Key)
fresh = true; fresh = true;
} }
else else
return status; return state;
*value = hh * 100 + mm; *value = hh * 100 + mm;
Set(); Set();
status = osContinue; state = osContinue;
} }
return status; return state;
} }
// --- cMenuEditChrItem ------------------------------------------------------ // --- cMenuEditChrItem ------------------------------------------------------
@ -343,7 +344,7 @@ private:
public: public:
cMenuEditChrItem(const char *Name, char *Value, const char *Allowed); cMenuEditChrItem(const char *Name, char *Value, const char *Allowed);
~cMenuEditChrItem(); ~cMenuEditChrItem();
virtual eOSStatus ProcessKey(eKeys Key); virtual eOSState ProcessKey(eKeys Key);
}; };
cMenuEditChrItem::cMenuEditChrItem(const char *Name, char *Value, const char *Allowed) cMenuEditChrItem::cMenuEditChrItem(const char *Name, char *Value, const char *Allowed)
@ -369,11 +370,11 @@ void cMenuEditChrItem::Set(void)
SetValue(buf); SetValue(buf);
} }
eOSStatus cMenuEditChrItem::ProcessKey(eKeys Key) eOSState cMenuEditChrItem::ProcessKey(eKeys Key)
{ {
eOSStatus status = cMenuEditItem::ProcessKey(Key); eOSState state = cMenuEditItem::ProcessKey(Key);
if (status == osUnknown) { if (state == osUnknown) {
if (Key == kLeft) { if (Key == kLeft) {
if (current > allowed) if (current > allowed)
current--; current--;
@ -383,12 +384,12 @@ eOSStatus cMenuEditChrItem::ProcessKey(eKeys Key)
current++; current++;
} }
else else
return status; return state;
*value = *current; *value = *current;
Set(); Set();
status = osContinue; state = osContinue;
} }
return status; return state;
} }
// --- cMenuEditStrItem ------------------------------------------------------ // --- cMenuEditStrItem ------------------------------------------------------
@ -404,7 +405,7 @@ private:
public: public:
cMenuEditStrItem(const char *Name, char *Value, int Length, const char *Allowed); cMenuEditStrItem(const char *Name, char *Value, int Length, const char *Allowed);
~cMenuEditStrItem(); ~cMenuEditStrItem();
virtual eOSStatus ProcessKey(eKeys Key); virtual eOSState ProcessKey(eKeys Key);
}; };
cMenuEditStrItem::cMenuEditStrItem(const char *Name, char *Value, int Length, const char *Allowed) cMenuEditStrItem::cMenuEditStrItem(const char *Name, char *Value, int Length, const char *Allowed)
@ -449,7 +450,7 @@ char cMenuEditStrItem::Inc(char c, bool Up)
return *p; return *p;
} }
eOSStatus cMenuEditStrItem::ProcessKey(eKeys Key) eOSState cMenuEditStrItem::ProcessKey(eKeys Key)
{ {
switch (Key) { switch (Key) {
case kLeft: if (pos > 0) { case kLeft: if (pos > 0) {
@ -492,11 +493,11 @@ private:
cChannel data; cChannel data;
public: public:
cMenuEditChannel(int Index); cMenuEditChannel(int Index);
virtual eOSStatus ProcessKey(eKeys Key); virtual eOSState ProcessKey(eKeys Key);
}; };
cMenuEditChannel::cMenuEditChannel(int Index) cMenuEditChannel::cMenuEditChannel(int Index)
:cOsdMenu("Edit channel", 14) :cOsdMenu("Edit Channel", 14)
{ {
channel = Channels.Get(Index); channel = Channels.Get(Index);
if (channel) { if (channel) {
@ -511,19 +512,19 @@ cMenuEditChannel::cMenuEditChannel(int Index)
} }
} }
eOSStatus cMenuEditChannel::ProcessKey(eKeys Key) eOSState cMenuEditChannel::ProcessKey(eKeys Key)
{ {
eOSStatus status = cOsdMenu::ProcessKey(Key); eOSState state = cOsdMenu::ProcessKey(Key);
if (status == osUnknown) { if (state == osUnknown) {
if (Key == kOk) { if (Key == kOk) {
if (channel) if (channel)
*channel = data; *channel = data;
Channels.Save(); Channels.Save();
status = osBack; state = osBack;
} }
} }
return status; return state;
} }
// --- cMenuChannelItem ------------------------------------------------------ // --- cMenuChannelItem ------------------------------------------------------
@ -535,6 +536,7 @@ private:
public: public:
cMenuChannelItem(int Index, cChannel *Channel); cMenuChannelItem(int Index, cChannel *Channel);
virtual void Set(void); virtual void Set(void);
void SetIndex(int Index);
}; };
cMenuChannelItem::cMenuChannelItem(int Index, cChannel *Channel) cMenuChannelItem::cMenuChannelItem(int Index, cChannel *Channel)
@ -551,12 +553,24 @@ void cMenuChannelItem::Set(void)
SetText(buffer, false); SetText(buffer, false);
} }
void cMenuChannelItem::SetIndex(int Index)
{
index = Index;
Set();
}
// --- cMenuChannels --------------------------------------------------------- // --- cMenuChannels ---------------------------------------------------------
class cMenuChannels : public cOsdMenu { class cMenuChannels : public cOsdMenu {
protected:
eOSState Switch(void);
eOSState Edit(void);
eOSState New(void);
eOSState Del(void);
virtual void Move(int From, int To);
public: public:
cMenuChannels(void); cMenuChannels(void);
virtual eOSStatus ProcessKey(eKeys Key); virtual eOSState ProcessKey(eKeys Key);
}; };
cMenuChannels::cMenuChannels(void) cMenuChannels::cMenuChannels(void)
@ -570,26 +584,124 @@ cMenuChannels::cMenuChannels(void)
Add(new cMenuChannelItem(i, channel), i == CurrentChannel); Add(new cMenuChannelItem(i, channel), i == CurrentChannel);
i++; i++;
} }
SetHelp("Edit", "New", "Delete", "Mark");
} }
eOSStatus cMenuChannels::ProcessKey(eKeys Key) eOSState cMenuChannels::Switch(void)
{ {
eOSStatus status = cOsdMenu::ProcessKey(Key);
if (status == osUnknown) {
switch (Key) {
//TODO need to block this if we are already editing a channel!
case kRight: return AddSubMenu(new cMenuEditChannel(Current()));
case kOk: {
cChannel *ch = Channels.Get(Current()); cChannel *ch = Channels.Get(Current());
if (ch) if (ch)
ch->Switch(); ch->Switch();
return osEnd; return osEnd;
}
eOSState cMenuChannels::Edit(void)
{
if (HasSubMenu() || Count() == 0)
return osContinue;
isyslog(LOG_INFO, "editing timer %d", Current() + 1);
return AddSubMenu(new cMenuEditChannel(Current()));
}
eOSState cMenuChannels::New(void)
{
if (HasSubMenu())
return osContinue;
cChannel *channel = new cChannel(Channels.Get(Current()));
Channels.Add(channel);
Add(new cMenuChannelItem(channel->Index()/*XXX*/, channel), true);
Channels.Save();
isyslog(LOG_INFO, "channel %d added", channel->Index() + 1);
return AddSubMenu(new cMenuEditChannel(Current()));
}
eOSState cMenuChannels::Del(void)
{
if (Count() > 0) {
int Index = Current();
// Check if there is a timer using this channel:
for (cTimer *ti = Timers.First(); ti; ti = (cTimer *)ti->Next()) {
if (ti->channel == Index + 1) {
Interface.Error("Channel is being used by a timer!");
return osContinue;
} }
}
if (Interface.Confirm("Delete Channel?")) {
// Move and renumber the channels:
Channels.Del(Channels.Get(Index));
cOsdMenu::Del(Index);
int i = 0;
for (cMenuChannelItem *ci = (cMenuChannelItem *)First(); ci; ci = (cMenuChannelItem *)ci->Next())
ci->SetIndex(i++);
Channels.Save();
isyslog(LOG_INFO, "channel %d deleted", Index + 1);
// Fix the timers:
bool TimersModified = false;
Index++; // user visible channel numbers start with '1'
for (cTimer *ti = Timers.First(); ti; ti = (cTimer *)ti->Next()) {
int OldChannel = ti->channel;
if (ti->channel > Index)
ti->channel--;
if (ti->channel != OldChannel) {
TimersModified = true;
isyslog(LOG_INFO, "timer %d: channel changed from %d to %d", ti->Index() + 1, OldChannel, ti->channel);
}
}
if (TimersModified)
Timers.Save();
Display();
}
}
return osContinue;
}
void cMenuChannels::Move(int From, int To)
{
// Move and renumber the channels:
Channels.Move(From, To);
cOsdMenu::Move(From, To);
int i = 0;
for (cMenuChannelItem *ci = (cMenuChannelItem *)First(); ci; ci = (cMenuChannelItem *)ci->Next())
ci->SetIndex(i++);
Channels.Save();
isyslog(LOG_INFO, "channel %d moved to %d", From + 1, To + 1);
// Fix the timers:
bool TimersModified = false;
From++; // user visible channel numbers start with '1'
To++;
for (cTimer *ti = Timers.First(); ti; ti = (cTimer *)ti->Next()) {
int OldChannel = ti->channel;
if (ti->channel == From)
ti->channel = To;
else if (ti->channel > From && ti->channel <= To)
ti->channel--;
else if (ti->channel < From && ti->channel >= To)
ti->channel++;
if (ti->channel != OldChannel) {
TimersModified = true;
isyslog(LOG_INFO, "timer %d: channel changed from %d to %d", ti->Index() + 1, OldChannel, ti->channel);
}
}
if (TimersModified)
Timers.Save();
Display();
}
eOSState cMenuChannels::ProcessKey(eKeys Key)
{
eOSState state = cOsdMenu::ProcessKey(Key);
if (state == osUnknown) {
switch (Key) {
case kOk: return Switch();
case kRed: return Edit();
case kGreen: return New();
case kYellow: return Del();
case kBlue: Mark(); break;
default: break; default: break;
} }
} }
return status; return state;
} }
// --- cMenuEditTimer -------------------------------------------------------- // --- cMenuEditTimer --------------------------------------------------------
@ -600,11 +712,11 @@ private:
cTimer data; cTimer data;
public: public:
cMenuEditTimer(int Index); cMenuEditTimer(int Index);
virtual eOSStatus ProcessKey(eKeys Key); virtual eOSState ProcessKey(eKeys Key);
}; };
cMenuEditTimer::cMenuEditTimer(int Index) cMenuEditTimer::cMenuEditTimer(int Index)
:cOsdMenu("Edit timer", 10) :cOsdMenu("Edit Timer", 10)
{ {
timer = Timers.Get(Index); timer = Timers.Get(Index);
if (timer) { if (timer) {
@ -622,21 +734,23 @@ cMenuEditTimer::cMenuEditTimer(int Index)
} }
} }
eOSStatus cMenuEditTimer::ProcessKey(eKeys Key) eOSState cMenuEditTimer::ProcessKey(eKeys Key)
{ {
eOSStatus status = cOsdMenu::ProcessKey(Key); eOSState state = cOsdMenu::ProcessKey(Key);
if (status == osUnknown) { if (state == osUnknown) {
if (Key == kOk) { if (Key == kOk) {
if (!*data.file)
strcpy(data.file, "unnamed");
if (timer && memcmp(timer, &data, sizeof(data)) != 0) { if (timer && memcmp(timer, &data, sizeof(data)) != 0) {
*timer = data; *timer = data;
Timers.Save(); Timers.Save();
isyslog(LOG_INFO, "timer %d modified (%s)", timer->Index() + 1, timer->active ? "active" : "inactive"); isyslog(LOG_INFO, "timer %d modified (%s)", timer->Index() + 1, timer->active ? "active" : "inactive");
} }
status = osBack; state = osBack;
} }
} }
return status; return state;
} }
// --- cMenuTimerItem -------------------------------------------------------- // --- cMenuTimerItem --------------------------------------------------------
@ -660,27 +774,34 @@ cMenuTimerItem::cMenuTimerItem(int Index, cTimer *Timer)
void cMenuTimerItem::Set(void) void cMenuTimerItem::Set(void)
{ {
char *buffer = NULL; char *buffer = NULL;
asprintf(&buffer, "%d\t%c\t%d\t%s\t%02d:%02d\t%02d:%02d", index + 1, asprintf(&buffer, "%c\t%d\t%s\t%02d:%02d\t%02d:%02d\t%s",
timer->active ? '>' : ' ', timer->active ? '>' : ' ',
timer->channel, timer->channel,
timer->PrintDay(timer->day), timer->PrintDay(timer->day),
timer->start / 100, timer->start / 100,
timer->start % 100, timer->start % 100,
timer->stop / 100, timer->stop / 100,
timer->stop % 100); // user visible timer numbers start with '1' timer->stop % 100,
timer->file);
SetText(buffer, false); SetText(buffer, false);
} }
// --- cMenuTimer ------------------------------------------------------------ // --- cMenuTimers -----------------------------------------------------------
class cMenuTimer : public cOsdMenu { class cMenuTimers : public cOsdMenu {
private:
eOSState Activate(bool On);
eOSState Edit(void);
eOSState New(void);
eOSState Del(void);
virtual void Move(int From, int To);
public: public:
cMenuTimer(void); cMenuTimers(void);
virtual eOSStatus ProcessKey(eKeys Key); virtual eOSState ProcessKey(eKeys Key);
}; };
cMenuTimer::cMenuTimer(void) cMenuTimers::cMenuTimers(void)
:cOsdMenu("Timer", 3, 2, 4, 10, 6) :cOsdMenu("Timer", 2, 4, 10, 6, 6)
{ {
int i = 0; int i = 0;
cTimer *timer; cTimer *timer;
@ -689,34 +810,190 @@ cMenuTimer::cMenuTimer(void)
Add(new cMenuTimerItem(i, timer)); Add(new cMenuTimerItem(i, timer));
i++; i++;
} }
SetHelp("Edit", "New", "Delete", "Mark");
} }
eOSStatus cMenuTimer::ProcessKey(eKeys Key) eOSState cMenuTimers::Activate(bool On)
{ {
eOSStatus status = cOsdMenu::ProcessKey(Key);
if (status == osUnknown) {
switch (Key) {
//TODO need to block this if we are already editing a channel!
case kOk: return AddSubMenu(new cMenuEditTimer(Current()));
//TODO new timer
//TODO delete timer
case kLeft:
case kRight:
{
cTimer *timer = Timers.Get(Current()); cTimer *timer = Timers.Get(Current());
if (timer) { if (timer && timer->active != On) {
timer->active = (Key == kRight); timer->active = On;
isyslog(LOG_INFO, "timer %d %sactivated", timer->Index() + 1, timer->active ? "" : "de");
RefreshCurrent(); RefreshCurrent();
DisplayCurrent(true); DisplayCurrent(true);
isyslog(LOG_INFO, "timer %d %sactivated", timer->Index() + 1, timer->active ? "" : "de");
Timers.Save(); Timers.Save();
} }
return osContinue;
}
eOSState cMenuTimers::Edit(void)
{
if (HasSubMenu() || Count() == 0)
return osContinue;
isyslog(LOG_INFO, "editing timer %d", Current() + 1);
return AddSubMenu(new cMenuEditTimer(Current()));
}
eOSState cMenuTimers::New(void)
{
if (HasSubMenu())
return osContinue;
cTimer *timer = new cTimer;
Timers.Add(timer);
Add(new cMenuTimerItem(timer->Index()/*XXX*/, timer), true);
Timers.Save();
isyslog(LOG_INFO, "timer %d added", timer->Index() + 1);
return AddSubMenu(new cMenuEditTimer(Current()));
}
eOSState cMenuTimers::Del(void)
{
// Check if this timer is active:
int Index = Current();
cTimer *ti = Timers.Get(Index);
if (ti) {
if (!ti->recording) {
if (Interface.Confirm("Delete Timer?")) {
Timers.Del(Timers.Get(Index));
cOsdMenu::Del(Index);
Timers.Save();
Display();
isyslog(LOG_INFO, "timer %d deleted", Index + 1);
} }
}
else
Interface.Error("Timer is recording!");
}
return osContinue;
}
void cMenuTimers::Move(int From, int To)
{
Timers.Move(From, To);
cOsdMenu::Move(From, To);
Timers.Save();
Display();
isyslog(LOG_INFO, "timer %d moved to %d", From + 1, To + 1);
}
eOSState cMenuTimers::ProcessKey(eKeys Key)
{
eOSState state = cOsdMenu::ProcessKey(Key);
if (state == osUnknown) {
switch (Key) {
case kLeft:
case kRight: return Activate(Key == kRight);
case kOk:
case kRed: return Edit();
case kGreen: return New();
case kYellow: return Del();
case kBlue: Mark(); break;
default: break; default: break;
} }
} }
return status; return state;
}
// --- cMenuRecordingItem ----------------------------------------------------
class cMenuRecordingItem : public cOsdItem {
public:
cRecording *recording;
cMenuRecordingItem(cRecording *Recording);
virtual void Set(void);
};
cMenuRecordingItem::cMenuRecordingItem(cRecording *Recording)
{
recording = Recording;
Set();
}
void cMenuRecordingItem::Set(void)
{
char *buffer = NULL;
struct tm *t = localtime(&recording->start);
asprintf(&buffer, "%02d.%02d.%04d\t%02d:%02d\t%s",
t->tm_mday,
t->tm_mon + 1,
t->tm_year + 1900,
t->tm_hour,
t->tm_min,
recording->name);
SetText(buffer, false);
}
// --- cMenuRecordings -------------------------------------------------------
class cMenuRecordings : public cOsdMenu {
private:
cRecordings Recordings;
eOSState Play(void);
eOSState Del(void);
public:
cMenuRecordings(void);
virtual eOSState ProcessKey(eKeys Key);
};
cMenuRecordings::cMenuRecordings(void)
:cOsdMenu("Recordings", 11, 6)
{
if (Recordings.Load()) {
cRecording *recording = Recordings.First();
while (recording) {
Add(new cMenuRecordingItem(recording));
recording = Recordings.Next(recording);
}
}
SetHelp("Play", NULL/*XXX"Resume"*/, "Delete");
}
eOSState cMenuRecordings::Play(void)
{
cMenuRecordingItem *ri = (cMenuRecordingItem *)Get(Current());
if (ri) {
//XXX what if this recording's file is currently in use???
if (ri->recording->Play())
return osEnd;
}
return osContinue;
}
eOSState cMenuRecordings::Del(void)
{
cMenuRecordingItem *ri = (cMenuRecordingItem *)Get(Current());
if (ri) {
//XXX what if this recording's file is currently in use???
//XXX if (!ti->recording) {
if (Interface.Confirm("Delete Recording?")) {
if (ri->recording->Delete()) {
cOsdMenu::Del(Current());
Display();
}
else
Interface.Error("Error while deleting recording!");
}
//XXX }
//XXX else
//XXX Interface.Error("Timer is recording!");
}
return osContinue;
}
eOSState cMenuRecordings::ProcessKey(eKeys Key)
{
eOSState state = cOsdMenu::ProcessKey(Key);
if (state == osUnknown) {
switch (Key) {
case kOk:
case kRed: return Play();
case kYellow: return Del();
default: break;
}
}
return state;
} }
// --- cMenuMain ------------------------------------------------------------- // --- cMenuMain -------------------------------------------------------------
@ -724,22 +1001,21 @@ eOSStatus cMenuTimer::ProcessKey(eKeys Key)
cMenuMain::cMenuMain(void) cMenuMain::cMenuMain(void)
:cOsdMenu("Main") :cOsdMenu("Main")
{ {
//TODO
Add(new cOsdItem("Channels", osChannels)); Add(new cOsdItem("Channels", osChannels));
Add(new cOsdItem("Timer", osTimer)); Add(new cOsdItem("Timer", osTimer));
Add(new cOsdItem("Recordings", osRecordings)); Add(new cOsdItem("Recordings", osRecordings));
} }
eOSStatus cMenuMain::ProcessKey(eKeys Key) eOSState cMenuMain::ProcessKey(eKeys Key)
{ {
eOSStatus status = cOsdMenu::ProcessKey(Key); eOSState state = cOsdMenu::ProcessKey(Key);
switch (status) { switch (state) {
case osChannels: return AddSubMenu(new cMenuChannels); case osChannels: return AddSubMenu(new cMenuChannels);
case osTimer: return AddSubMenu(new cMenuTimer); case osTimer: return AddSubMenu(new cMenuTimers);
//TODO Replay case osRecordings: return AddSubMenu(new cMenuRecordings);
default: break; default: break;
} }
return status; return state;
} }

4
menu.h
View File

@ -4,7 +4,7 @@
* See the main source file 'osm.c' for copyright information and * See the main source file 'osm.c' for copyright information and
* how to reach the author. * how to reach the author.
* *
* $Id: menu.h 1.1 2000/02/19 13:36:48 kls Exp $ * $Id: menu.h 1.2 2000/03/05 10:57:27 kls Exp $
*/ */
#ifndef _MENU_H #ifndef _MENU_H
@ -15,7 +15,7 @@
class cMenuMain : public cOsdMenu { class cMenuMain : public cOsdMenu {
public: public:
cMenuMain(void); cMenuMain(void);
virtual eOSStatus ProcessKey(eKeys Key); virtual eOSState ProcessKey(eKeys Key);
}; };
#endif //_MENU_H #endif //_MENU_H

101
osd.c
View File

@ -4,7 +4,7 @@
* See the main source file 'osm.c' for copyright information and * See the main source file 'osm.c' for copyright information and
* how to reach the author. * how to reach the author.
* *
* $Id: osd.c 1.1 2000/02/19 13:36:48 kls Exp $ * $Id: osd.c 1.2 2000/02/27 17:23:07 kls Exp $
*/ */
#include "osd.h" #include "osd.h"
@ -13,19 +13,19 @@
// --- cOsdItem -------------------------------------------------------------- // --- cOsdItem --------------------------------------------------------------
cOsdItem::cOsdItem(eOSStatus Status) cOsdItem::cOsdItem(eOSState State)
{ {
text = NULL; text = NULL;
offset = -1; offset = -1;
status = Status; state = State;
fresh = false; fresh = false;
} }
cOsdItem::cOsdItem(char *Text, eOSStatus Status) cOsdItem::cOsdItem(char *Text, eOSState State)
{ {
text = NULL; text = NULL;
offset = -1; offset = -1;
status = Status; state = State;
fresh = false; fresh = false;
SetText(Text); SetText(Text);
} }
@ -52,24 +52,27 @@ void cOsdItem::Display(int Offset, bool Current)
Interface.WriteText(0, offset + 2, text, Current); Interface.WriteText(0, offset + 2, text, Current);
} }
eOSStatus cOsdItem::ProcessKey(eKeys Key) eOSState cOsdItem::ProcessKey(eKeys Key)
{ {
return Key == kOk ? status : osUnknown; return Key == kOk ? state : osUnknown;
} }
// --- cOsdMenu -------------------------------------------------------------- // --- cOsdMenu --------------------------------------------------------------
cOsdMenu::cOsdMenu(char *Title, int c0, int c1, int c2, int c3, int c4) cOsdMenu::cOsdMenu(char *Title, int c0, int c1, int c2, int c3, int c4)
{ {
visible = false;
title = strdup(Title); title = strdup(Title);
cols[0] = c0; cols[0] = c0;
cols[1] = c1; cols[1] = c1;
cols[2] = c2; cols[2] = c2;
cols[3] = c3; cols[3] = c3;
cols[4] = c4; cols[4] = c4;
first = count = 0; first = 0;
current = -1; current = marked = -1;
subMenu = NULL; subMenu = NULL;
helpRed = helpGreen = helpYellow = helpBlue = NULL;
status = NULL;
Interface.Open(); Interface.Open();
} }
@ -77,24 +80,54 @@ cOsdMenu::~cOsdMenu()
{ {
delete title; delete title;
delete subMenu; delete subMenu;
delete status;
Interface.Clear(); Interface.Clear();
Interface.Close(); Interface.Close();
} }
void cOsdMenu::SetStatus(const char *s)
{
delete status;
status = s ? strdup(s) : NULL;
if (visible)
Interface.Status(status);
}
void cOsdMenu::SetHelp(const char *Red, const char *Green, const char *Yellow, const char *Blue)
{
// strings are NOT copied - must be constants!!!
helpRed = Red;
helpGreen = Green;
helpYellow = Yellow;
helpBlue = Blue;
}
void cOsdMenu::Del(int Index)
{
cList<cOsdItem>::Del(Get(Index));
if (current == Count())
current--;
if (Index == first && first > 0)
first--;
}
void cOsdMenu::Add(cOsdItem *Item, bool Current) void cOsdMenu::Add(cOsdItem *Item, bool Current)
{ {
cList<cOsdItem>::Add(Item); cList<cOsdItem>::Add(Item);
count++; if (Current)
if (Current && current < 0)
current = Item->Index(); current = Item->Index();
} }
void cOsdMenu::Display(void) void cOsdMenu::Display(void)
{ {
visible = true;
Interface.Clear(); Interface.Clear();
Interface.SetCols(cols); Interface.SetCols(cols);
Interface.WriteText(0, 0, title); Interface.Title(title);
if (current < 0 && count) Interface.Help(helpRed, helpGreen, helpYellow, helpBlue);
int count = Count();
if (count > 0) {
if (current < 0)
current = 0; // just for safety - there HAS to be a current item! current = 0; // just for safety - there HAS to be a current item!
int n = 0; int n = 0;
if (current - first >= MAXOSDITEMS) { if (current - first >= MAXOSDITEMS) {
@ -111,6 +144,8 @@ void cOsdMenu::Display(void)
if (++n == MAXOSDITEMS) //TODO get this from Interface!!! if (++n == MAXOSDITEMS) //TODO get this from Interface!!!
break; break;
} }
}
Interface.Status(status);
} }
void cOsdMenu::RefreshCurrent(void) void cOsdMenu::RefreshCurrent(void)
@ -144,6 +179,7 @@ void cOsdMenu::CursorUp(void)
void cOsdMenu::CursorDown(void) void cOsdMenu::CursorDown(void)
{ {
int count = Count();
if (current < count - 1) { if (current < count - 1) {
DisplayCurrent(false); DisplayCurrent(false);
if (++current >= first + MAXOSDITEMS) { if (++current >= first + MAXOSDITEMS) {
@ -157,7 +193,15 @@ void cOsdMenu::CursorDown(void)
} }
} }
eOSStatus cOsdMenu::AddSubMenu(cOsdMenu *SubMenu) void cOsdMenu::Mark(void)
{
if (Count() && marked < 0) {
marked = current;
SetStatus("Up/Dn for new location - OK to move");
}
}
eOSState cOsdMenu::AddSubMenu(cOsdMenu *SubMenu)
{ {
delete subMenu; delete subMenu;
subMenu = SubMenu; subMenu = SubMenu;
@ -165,31 +209,40 @@ eOSStatus cOsdMenu::AddSubMenu(cOsdMenu *SubMenu)
return osContinue; // convenience return value (see cMenuMain) return osContinue; // convenience return value (see cMenuMain)
} }
eOSStatus cOsdMenu::ProcessKey(eKeys Key) eOSState cOsdMenu::ProcessKey(eKeys Key)
{ {
if (subMenu) { if (subMenu) {
eOSStatus status = subMenu->ProcessKey(Key); eOSState state = subMenu->ProcessKey(Key);
if (status == osBack) { if (state == osBack) {
delete subMenu; delete subMenu;
subMenu = NULL; subMenu = NULL;
RefreshCurrent(); RefreshCurrent();
Display(); Display();
status = osContinue; state = osContinue;
} }
return status; return state;
} }
cOsdItem *item = Get(current); cOsdItem *item = Get(current);
if (item) { if (marked < 0 && item) {
eOSStatus status = item->ProcessKey(Key); eOSState state = item->ProcessKey(Key);
if (status != osUnknown) if (state != osUnknown)
return status; return state;
} }
switch (Key) { switch (Key) {
case kUp: CursorUp(); break; case kUp: CursorUp(); break;
case kDown: CursorDown(); break; case kDown: CursorDown(); break;
case kBack: return osBack; case kBack: return osBack;
default: return osUnknown; case kOk: if (marked >= 0) {
SetStatus(NULL);
if (marked != current)
Move(marked, current);
marked = -1;
break;
}
// else run into default
default: if (marked < 0)
return osUnknown;
} }
return osContinue; return osContinue;
} }

26
osd.h
View File

@ -4,7 +4,7 @@
* See the main source file 'osm.c' for copyright information and * See the main source file 'osm.c' for copyright information and
* how to reach the author. * how to reach the author.
* *
* $Id: osd.h 1.1 2000/02/19 13:36:48 kls Exp $ * $Id: osd.h 1.2 2000/03/05 11:33:11 kls Exp $
*/ */
#ifndef __OSD_H #ifndef __OSD_H
@ -16,7 +16,7 @@
#define MAXOSDITEMS 9 #define MAXOSDITEMS 9
enum eOSStatus { osUnknown, enum eOSState { osUnknown,
osContinue, osContinue,
osProcessed, osProcessed,
osChannels, osChannels,
@ -30,39 +30,47 @@ class cOsdItem : public cListObject {
private: private:
char *text; char *text;
int offset; int offset;
eOSStatus status; eOSState state;
protected: protected:
bool fresh; bool fresh;
public: public:
cOsdItem(eOSStatus Status = osUnknown); cOsdItem(eOSState State = osUnknown);
cOsdItem(char *Text, eOSStatus Status = osUnknown); cOsdItem(char *Text, eOSState State = osUnknown);
virtual ~cOsdItem(); virtual ~cOsdItem();
void SetText(char *Text, bool Copy = true); void SetText(char *Text, bool Copy = true);
char *Text(void) { return text; } char *Text(void) { return text; }
void Display(int Offset = -1, bool Current = false); void Display(int Offset = -1, bool Current = false);
virtual void Set(void) {} virtual void Set(void) {}
virtual eOSStatus ProcessKey(eKeys Key); virtual eOSState ProcessKey(eKeys Key);
}; };
class cOsdMenu : public cList<cOsdItem> { class cOsdMenu : public cList<cOsdItem> {
private: private:
char *title; char *title;
int cols[cInterface::MaxCols]; int cols[cInterface::MaxCols];
int first, current, count; int first, current, marked;
cOsdMenu *subMenu; cOsdMenu *subMenu;
const char *helpRed, *helpGreen, *helpYellow, *helpBlue;
const char *status;
protected: protected:
bool visible;
void RefreshCurrent(void); void RefreshCurrent(void);
void DisplayCurrent(bool Current); void DisplayCurrent(bool Current);
void CursorUp(void); void CursorUp(void);
void CursorDown(void); void CursorDown(void);
eOSStatus AddSubMenu(cOsdMenu *SubMenu); void Mark(void);
eOSState AddSubMenu(cOsdMenu *SubMenu);
bool HasSubMenu(void) { return subMenu; }
void SetStatus(const char *s);
void SetHelp(const char *Red, const char *Green = NULL, const char *Yellow = NULL, const char *Blue = NULL);
virtual void Del(int Index);
public: public:
cOsdMenu(char *Title, int c0 = 0, int c1 = 0, int c2 = 0, int c3 = 0, int c4 = 0); cOsdMenu(char *Title, int c0 = 0, int c1 = 0, int c2 = 0, int c3 = 0, int c4 = 0);
virtual ~cOsdMenu(); virtual ~cOsdMenu();
int Current(void) { return current; } int Current(void) { return current; }
void Add(cOsdItem *Item, bool Current = false); void Add(cOsdItem *Item, bool Current = false);
void Display(void); void Display(void);
virtual eOSStatus ProcessKey(eKeys Key); virtual eOSState ProcessKey(eKeys Key);
}; };
#endif //__OSD_H #endif //__OSD_H

55
osm.c
View File

@ -22,13 +22,13 @@
* *
* The project's page is at http://www.cadsoft.de/people/kls/vdr * The project's page is at http://www.cadsoft.de/people/kls/vdr
* *
* $Id: osm.c 1.1 2000/02/19 13:36:48 kls Exp $ * $Id: osm.c 1.2 2000/03/05 17:18:15 kls Exp $
*/ */
#include "config.h" #include "config.h"
#include "dvbapi.h"
#include "interface.h" #include "interface.h"
#include "menu.h" #include "menu.h"
#include "recording.h"
#include "tools.h" #include "tools.h"
#ifdef DEBUG_REMOTE #ifdef DEBUG_REMOTE
@ -52,39 +52,39 @@ int main(int argc, char *argv[])
cMenuMain *Menu = NULL; cMenuMain *Menu = NULL;
cTimer *Timer = NULL; cTimer *Timer = NULL;
cDvbRecorder *Recorder = NULL; cRecording *Recording = NULL;
for (;;) { for (;;) {
//TODO check for free disk space and delete files if necessary/possible AssertFreeDiskSpace();
// in case there is an ongoing recording if (!Recording && !Timer && (Timer = cTimer::GetMatch()) != NULL) {
if (!Timer && (Timer = cTimer::GetMatch()) != NULL) { DELETENULL(Menu);
// make sure the timer won't be deleted:
Timer->SetRecording(true);
// switch to channel: // switch to channel:
isyslog(LOG_INFO, "timer %d start", Timer->Index() + 1);
delete Menu;
Menu = NULL;
cChannel::SwitchTo(Timer->channel - 1); cChannel::SwitchTo(Timer->channel - 1);
ChannelLocked = true; ChannelLocked = true;
// start recording: // start recording:
delete Recorder; Recording = new cRecording(Timer);
Recorder = new cDvbRecorder; if (!Recording->Record())
//TODO special filename handling!!! DELETENULL(Recording);
if (!Recorder->Record(Timer->file, Timer->quality)) {
delete Recorder;
Recorder = NULL;
} }
} if (Timer && !Timer->Matches()) {
if (Timer) {
if (!Timer->Matches()) {
// stop recording: // stop recording:
if (Recorder) if (Recording) {
Recorder->Stop(); Recording->Stop();
// end timer: DELETENULL(Recording);
ChannelLocked = false;
isyslog(LOG_INFO, "timer %d stop", Timer->Index() + 1);
Timer = NULL;
//TODO switch back to the previous channel???
//TODO clear single event timer???
} }
// release channel and timer:
ChannelLocked = false;
Timer->SetRecording(false);
// clear single event timer:
if (Timer->IsSingleEvent()) {
DELETENULL(Menu); // must make sure no menu uses it
isyslog(LOG_INFO, "deleting timer %d", Timer->Index() + 1);
Timers.Del(Timer);
Timers.Save();
}
Timer = NULL;
} }
eKeys key = Interface.GetKey(); eKeys key = Interface.GetKey();
if (Menu) { if (Menu) {
@ -92,8 +92,7 @@ int main(int argc, char *argv[])
default: if (key != kMenu) default: if (key != kMenu)
break; break;
case osBack: case osBack:
case osEnd: delete Menu; case osEnd: DELETENULL(Menu);
Menu = NULL;
break; break;
} }
} }

238
recording.c Normal file
View File

@ -0,0 +1,238 @@
/*
* recording.h: Recording file handling
*
* See the main source file 'osm.c' for copyright information and
* how to reach the author.
*
* $Id: recording.c 1.1 2000/03/05 17:16:22 kls Exp $
*/
#include "recording.h"
#include <errno.h>
#include <stdio.h>
#include <string.h>
#include "interface.h"
#include "tools.h"
#define RECEXT ".rec"
#define DELEXT ".del"
#define DATAFORMAT "%4d-%02d-%02d.%02d:%02d.%c.%02d.%02d" RECEXT
#define NAMEFORMAT "%s/%s/" DATAFORMAT
#define FINDCMD "find %s -type f -name '%s'"
#define DFCMD "df -m %s"
#define MINDISKSPACE 1024 // MB
const char *BaseDir = "/video";//XXX
cDvbRecorder *Recorder = NULL;
static bool LowDiskSpace(void)
{
//TODO Find a simpler way to determine the amount of free disk space!
bool result = true;
char *cmd = NULL;
asprintf(&cmd, DFCMD, BaseDir);
FILE *p = popen(cmd, "r");
if (p) {
char *s;
while ((s = readline(p)) != NULL) {
if (*s == '/') {
int available;
sscanf(s, "%*s %*d %*d %d", &available);
result = available < MINDISKSPACE;
break;
}
}
pclose(p);
}
else
esyslog(LOG_ERR, "ERROR: can't open pipe for cmd '%s'", cmd);
delete cmd;
return result;
}
void AssertFreeDiskSpace(void)
{
// With every call to this function we try to actually remove
// a file, or mark a file for removal ("delete" it), so that
// it will get removed during the next call.
if (Recorder && Recorder->Recording() && LowDiskSpace()) {
// Remove the oldest file that has been "deleted":
cRecordings Recordings;
if (Recordings.Load(true)) {
cRecording *r = Recordings.First();
cRecording *r0 = r;
while (r) {
if (r->start < r0->start)
r0 = r;
r = Recordings.Next(r);
}
if (r0 && r0->Remove())
return;
}
// No "deleted" files to remove, so let's see if we can delete a recording:
if (Recordings.Load(false)) {
cRecording *r = Recordings.First();
cRecording *r0 = NULL;
while (r) {
if ((time(NULL) - r->start) / SECSINDAY > r->lifetime) {
if (r0) {
if (r->priority < r0->priority)
r0 = r;
}
else
r0 = r;
}
r = Recordings.Next(r);
}
if (r0 && r0->Delete())
return;
}
// Unable to free disk space, but there's nothing we can do about that...
//TODO maybe a log entry - but make sure it doesn't come too often
}
}
// --- cRecording ------------------------------------------------------------
cRecording::cRecording(const char *Name, time_t Start, char Quality, int Priority, int LifeTime)
{
fileName = NULL;
name = strdup(Name);
start = Start;
quality = Quality;
priority = Priority;
lifetime = LifeTime;
}
cRecording::cRecording(cTimer *Timer)
{
fileName = NULL;
name = strdup(Timer->file);
start = Timer->StartTime();
quality = Timer->quality;
priority = Timer->priority;
lifetime = Timer->lifetime;
}
cRecording::cRecording(const char *FileName)
{
fileName = strdup(FileName);
FileName += strlen(BaseDir) + 1;
char *p = strrchr(FileName, '/');
name = NULL;
if (p) {
time_t now = time(NULL);
struct tm t = *localtime(&now); // this initializes the time zone in 't'
if (8 == sscanf(p + 1, DATAFORMAT, &t.tm_year, &t.tm_mon, &t.tm_mday, &t.tm_hour, &t.tm_min, &quality, &priority, &lifetime)) {
t.tm_year -= 1900;
t.tm_mon--;
t.tm_sec = 0;
start = mktime(&t);
name = new char[p - FileName + 1];
strncpy(name, FileName, p - FileName);
name[p - FileName] = 0;
}
}
}
cRecording::~cRecording()
{
delete fileName;
delete name;
}
const char *cRecording::FileName(void)
{
if (!fileName) {
struct tm *t = localtime(&start);
asprintf(&fileName, NAMEFORMAT, BaseDir, name, t->tm_year + 1900, t->tm_mon + 1, t->tm_mday, t->tm_hour, t->tm_min, quality, priority, lifetime);
}
return fileName;
}
bool cRecording::Delete(void)
{
bool result = true;
char *NewName = strdup(FileName());
char *ext = strrchr(NewName, '.');
if (strcmp(ext, RECEXT) == 0) {
strncpy(ext, DELEXT, strlen(ext));
isyslog(LOG_INFO, "deleting recording %s", FileName());
if (rename(FileName(), NewName) == -1) {
esyslog(LOG_ERR, "ERROR: %s", strerror(errno));
result = false;
}
}
delete NewName;
return result;
}
bool cRecording::Remove(void)
{
bool result = true;
isyslog(LOG_INFO, "removing recording %s", FileName());
if (remove(FileName()) == -1) {
esyslog(LOG_ERR, "ERROR: %s", strerror(errno));
result = false;
}
return result;
}
bool cRecording::AssertRecorder(void)
{
if (!Recorder || !Recorder->Recording()) {
if (!Recorder)
Recorder = new cDvbRecorder;
return true;
}
Interface.Error("Recorder is in use!");
return false;
}
bool cRecording::Record(void)
{
return AssertRecorder() && Recorder->Record(FileName(), quality);
}
bool cRecording::Play(void)
{
return AssertRecorder() && Recorder->Play(FileName());
}
void cRecording::Stop(void)
{
if (Recorder)
Recorder->Stop();
}
// --- cRecordings -----------------------------------------------------------
bool cRecordings::Load(bool Deleted)
{
Clear();
bool result = false;
char *cmd = NULL;
asprintf(&cmd, FINDCMD, BaseDir, Deleted ? "*" DELEXT : "*" RECEXT);
FILE *p = popen(cmd, "r");
if (p) {
char *s;
while ((s = readline(p)) != NULL) {
cRecording *r = new cRecording(s);
if (r->name)
Add(r);
else
delete r;
}
pclose(p);
result = Count() > 0;
}
else
Interface.Error("Error while opening pipe!");
delete cmd;
return result;
}

56
recording.h Normal file
View File

@ -0,0 +1,56 @@
/*
* recording.h: Recording file handling
*
* See the main source file 'osm.c' for copyright information and
* how to reach the author.
*
* $Id: recording.h 1.1 2000/03/05 15:57:27 kls Exp $
*/
#ifndef __RECORDING_H
#define __RECORDING_H
#include <time.h>
#include "config.h"
#include "dvbapi.h"
#include "tools.h"
extern cDvbRecorder *Recorder;
void AssertFreeDiskSpace(void);
class cRecording : public cListObject {
private:
bool AssertRecorder(void);
public:
char *name;
char *fileName;
time_t start;
char quality;
int priority;
int lifetime;
cRecording(const char *Name, time_t Start, char Quality, int Priority, int LifeTime);
cRecording(cTimer *Timer);
cRecording(const char *FileName);
~cRecording();
const char *FileName(void);
bool Delete(void);
// Changes the file name so that it will no longer be visible in the OSM
// Returns false in case of error
bool Remove(void);
// Actually removes the file from the disk
// Returns false in case of error
bool Record(void);
// Starts recording of the file
bool Play(void);
// Starts playback of the file
void Stop(void);
// Stops recording or playback of the file
};
class cRecordings : public cList<cRecording> {
public:
bool Load(bool Deleted = false);
};
#endif //__RECORDING_H

View File

@ -1,9 +1,6 @@
1:2:-----S-:2210:2320:H:99:99:Wochenshow 1:2:-----S-:2205:2320:H:99:99:Wochenshow
1:3:M------:2125:2205:H:99:99:Neues 0:15:M------:2125:2205:H:99:99:Neues
1:15:MTWTF--:1828:1901:M:10:5:nano 1:15:MTWTF--:1828:1901:M:10:5:nano
1:2:-----S-:1737:1827:H:99:99:kls/StarTrek/DS9
1:3:M------:2110:2230:H:99:99:SevenDays 1:3:M------:2110:2230:H:99:99:SevenDays
1:3:---T---:2215:2300:H:99:99:SwItch 1:3:---T---:2215:2300:H:99:99:Switch
0:1:1:0:0:H:99:99:# 1:14:------S:2210:2255:H:99:99:Olli
0:1:1:0:0:H:99:99:#
0:1:1:0:0:L:0:5:#

71
tools.c
View File

@ -4,13 +4,30 @@
* See the main source file 'osm.c' for copyright information and * See the main source file 'osm.c' for copyright information and
* how to reach the author. * how to reach the author.
* *
* $Id: tools.c 1.1 2000/02/19 13:36:48 kls Exp $ * $Id: tools.c 1.2 2000/03/05 14:33:58 kls Exp $
*/ */
#include "tools.h" #include "tools.h"
#include <errno.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/time.h> #include <sys/time.h>
#define MaxBuffer 1000
char *readline(FILE *f)
{
static char buffer[MaxBuffer];
if (fgets(buffer, sizeof(buffer), f) > 0) {
int l = strlen(buffer) - 1;
if (l >= 0 && buffer[l] == '\n')
buffer[l] = 0;
return buffer;
}
return NULL;
}
int time_ms(void) int time_ms(void)
{ {
struct timeval t; struct timeval t;
@ -19,6 +36,30 @@ int time_ms(void)
return 0; return 0;
} }
bool MakeDirs(const char *FileName)
{
bool result = true;
char *s = strdup(FileName);
char *p = s;
if (*p == '/')
p++;
while ((p = strchr(p, '/')) != NULL) {
*p = 0;
struct stat fs;
if (stat(s, &fs) != 0 || !S_ISDIR(fs.st_mode)) {
isyslog(LOG_INFO, "creating directory %s", s);
if (mkdir(s, S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH) == -1) {
esyslog(LOG_ERR, "ERROR while creating directory %s: %s", s, strerror(errno));
result = false;
break;
}
}
*p++ = '/';
}
delete s;
return result;
}
// --- cListObject ----------------------------------------------------------- // --- cListObject -----------------------------------------------------------
cListObject::cListObject(void) cListObject::cListObject(void)
@ -42,6 +83,7 @@ void cListObject::Unlink(void)
next->prev = prev; next->prev = prev;
if (prev) if (prev)
prev->next = next; prev->next = next;
next = prev = NULL;
} }
int cListObject::Index(void) int cListObject::Index(void)
@ -92,6 +134,33 @@ void cListBase::Del(cListObject *Object)
delete Object; delete Object;
} }
void cListBase::Move(int From, int To)
{
Move(Get(From), Get(To));
}
void cListBase::Move(cListObject *From, cListObject *To)
{
if (From && To) {
if (From->Index() < To->Index())
To = To->Next();
if (From == objects)
objects = From->Next();
if (From == lastObject)
lastObject = From->Prev();
From->Unlink();
if (To) {
if (To->Prev())
To->Prev()->Append(From);
From->Append(To);
}
else
lastObject->Append(From);
if (!From->Prev())
objects = From;
}
}
void cListBase::Clear(void) void cListBase::Clear(void)
{ {
while (objects) { while (objects) {

16
tools.h
View File

@ -4,12 +4,13 @@
* See the main source file 'osm.c' for copyright information and * See the main source file 'osm.c' for copyright information and
* how to reach the author. * how to reach the author.
* *
* $Id: tools.h 1.1 2000/02/19 13:36:48 kls Exp $ * $Id: tools.h 1.2 2000/03/05 16:14:05 kls Exp $
*/ */
#ifndef __TOOLS_H #ifndef __TOOLS_H
#define __TOOLS_H #define __TOOLS_H
#include <stdio.h>
#include <syslog.h> #include <syslog.h>
//TODO //TODO
@ -17,6 +18,14 @@
#define esyslog syslog #define esyslog syslog
#define isyslog syslog #define isyslog syslog
#define SECSINDAY 86400
#define DELETENULL(p) (delete (p), p = NULL)
char *readline(FILE *f);
int time_ms(void);
bool MakeDirs(const char *FileName);
class cListObject { class cListObject {
private: private:
cListObject *prev, *next; cListObject *prev, *next;
@ -38,6 +47,8 @@ public:
virtual ~cListBase(); virtual ~cListBase();
void Add(cListObject *Object); void Add(cListObject *Object);
void Del(cListObject *Object); void Del(cListObject *Object);
void Move(int From, int To);
void Move(cListObject *From, cListObject *To);
void Clear(void); void Clear(void);
cListObject *Get(int Index); cListObject *Get(int Index);
int Count(void); int Count(void);
@ -47,8 +58,7 @@ template<class T> class cList : public cListBase {
public: public:
T *Get(int Index) { return (T *)cListBase::Get(Index); } T *Get(int Index) { return (T *)cListBase::Get(Index); }
T *First(void) { return (T *)objects; } T *First(void) { return (T *)objects; }
T *Next(T *object) { return (T *)object->Next(); }
}; };
int time_ms(void);
#endif //__TOOLS_H #endif //__TOOLS_H