mirror of
https://github.com/VDR4Arch/vdr.git
synced 2023-10-10 13:36:52 +02:00
Implemented 'Schedules' menu
This commit is contained in:
parent
92d3e366ba
commit
e6999e9b3a
2
BUGS
2
BUGS
@ -4,3 +4,5 @@ Video Disk Recorder - Known Bugs
|
||||
* Sometimes the picture "jumps" as if a frame is skipped.
|
||||
Presumably this is a problem in the card driver or firmware?
|
||||
|
||||
* The first picture captured with the GRAB command in SVDRP
|
||||
is empty. Also, these pictures appear to be too dark.
|
||||
|
@ -26,6 +26,7 @@ Guido Fiala <gfiala@s.netic.de>
|
||||
|
||||
Robert Schneider <Robert.Schneider@lotus.com>
|
||||
for implementing EIT support for displaying the current/next info
|
||||
for extending EIT support to implement a complete EPG
|
||||
|
||||
Niels de Carpentier <niels@casema.net>
|
||||
for adding a workaround for a driver timing problem in cDvbApi::Cmd()
|
||||
|
25
HISTORY
25
HISTORY
@ -241,3 +241,28 @@ Video Disk Recorder Revision History
|
||||
- The "Blue" button in the "Main" menu can now be used to "Resume" a previously
|
||||
stopped replay session (suggested by Martin Hammerschmid).
|
||||
- The low and high LNB frequencies can now be changed in the "Setup" menu.
|
||||
|
||||
2000-10-29: Version 0.67
|
||||
|
||||
- The EIT information is now gathered in a separate thread.
|
||||
- While the "current/next" information is being displayed (either after switching
|
||||
channels or due to pressing the "Ok" button in normal viewing mode), the "Green"
|
||||
and "Yellow" button display detailed information about the current/next broad-
|
||||
cast (if such information is available).
|
||||
- The sytem time can now be synchronized to the time broadcast in the DVB data
|
||||
stream. This can be enabled in the "Setup" menu by setting "SetSystemTime" to
|
||||
1. Note that this works only if VDR is running under a user id that has
|
||||
permisson to set the system time.
|
||||
- The new item "Schedule" in the "Main" menu opens VDR's EPG (thanks to Robert
|
||||
Schneider). See the MANUAL file for a detailed description.
|
||||
- The new setup parameters MarginStart and MarginStop define how long (in
|
||||
minutes) before the official start time of a broadcast VDR shall begin
|
||||
recording, and how long after the official end time it shall stop recording.
|
||||
These are used when a recording is programmed from the "Schedules" menu.
|
||||
- The delay value in the dvb.c.071.diff patch to the driver has been increased
|
||||
to '3', because on some systems the OSD was not displayed correctly. If you
|
||||
are running an already patched version 0.71 driver and encounter problems
|
||||
with the OSD, please make sure the parameter in the ddelay call is '3', not
|
||||
'2'.
|
||||
- Fixed initializing the RCU remote control code (didn't work after switching
|
||||
on the system).
|
||||
|
64
MANUAL
64
MANUAL
@ -53,20 +53,60 @@ Video Disk Recorder User's Manual
|
||||
At any point in the menu system, pressing the "Menu" key again will
|
||||
immediately leave the menu system (discarding any pending changes).
|
||||
|
||||
* The "Schedule" Menu
|
||||
|
||||
The "Schedule" menu implements VDR's "Electronic Program Guide" (EPG).
|
||||
|
||||
Select "Schedule" from the "Main" menu and you get a list of all upcoming
|
||||
broadcasts on the current channel.
|
||||
|
||||
"Up" and "Down" can be used to scroll through this list, and pressing "Ok"
|
||||
displays detailed information about the selected programme. Pressing "Ok"
|
||||
again (or pressing "Back") gets you back into the "Schedule" menu.
|
||||
|
||||
From the "Schedule" menu, the "Green" button opens the "What's on now?"
|
||||
menu, which displays all programmes that are currently running on all
|
||||
channels that broadcast their programme information on the current
|
||||
transponder, or from channels that have been current lately (VDR stores
|
||||
all information it gathers in an internal list). The more channels you
|
||||
have been switching through lately, the longer this list will be.
|
||||
The "Yellow" button opens the "What's on next?" menu, which lists all
|
||||
programmes that will start next on all channels.
|
||||
|
||||
Inside the "What's on now/next?" menus the "Green" button toggles between
|
||||
the "Now" and "Next" display, and the "Yellow" button gets you back to the
|
||||
"Schedule" menu of the current channel.
|
||||
|
||||
The "Red" button allows you to instantly program a timer to record the
|
||||
selected programme. You will get into the "Edit Timer" menu in which
|
||||
everything has already been filled in, and you can make any modifications
|
||||
you may want to apply. Note that the Start and Stop time are offset by the
|
||||
MarginStart and MarginStop parameters (see Setup) in order to make sure the
|
||||
entire programme is recorded in case it doesn't exactly adhere to its
|
||||
published start/stop times. Of course, no guarantee can be given that the
|
||||
default margin values will be sufficient, so in case this recording is
|
||||
really important you may want to add an extra margin ;-)
|
||||
|
||||
The "Blue" button can be pressed to switch to the channel with the selected
|
||||
programme.
|
||||
|
||||
* Selecting a Channel
|
||||
|
||||
There are three ways to select a channel:
|
||||
There are four ways to select a channel:
|
||||
|
||||
1. With no On Screen Menu displayed press the "Up" or "Down" key to switch
|
||||
to the next higher or lower channel.
|
||||
2. Press the "Menu" button to bring up the On Screen Menu, select "Channels"
|
||||
and browse through the list with the "Up" and "Down" key; to switch to the
|
||||
selected channel press "Ok".
|
||||
2. Directly type in the channel number with the numeric keys ('0'..'9');
|
||||
3. Directly type in the channel number with the numeric keys ('0'..'9');
|
||||
if no key is pressed for about half a second, the digits collected so
|
||||
far will define the channel number.
|
||||
4. From the "Now", "Next" and "Event" menus (accessible through the "Schedule"
|
||||
menu) by pressing the "Blue" button.
|
||||
|
||||
Pressing the '0' key toggles between the current and the previous channel.
|
||||
Pressing the '0' key in normal viewing mode toggles between the current and
|
||||
the previous channel.
|
||||
|
||||
After switching to a different channel the channel number and name, as well
|
||||
as the current time are displayed at the top of the screen. If available, the
|
||||
@ -75,6 +115,11 @@ Video Disk Recorder User's Manual
|
||||
To bring up the channel display without switching channels you can press
|
||||
the "Ok" button.
|
||||
|
||||
When the "current/next" information is being displayed, pressing the "Green"
|
||||
button will display the detailed information about the current broadcast,
|
||||
if such information is available. The "Yellow" button will do the same thing
|
||||
for the next broadcast.
|
||||
|
||||
* Switching through channel groups
|
||||
|
||||
If the 'channels.conf' file contains "group separators" you can switch
|
||||
@ -178,6 +223,9 @@ Video Disk Recorder User's Manual
|
||||
If this field is left blank, the channel name will be used to form
|
||||
the name of the recording.
|
||||
|
||||
A timer can also be programmed by pressing the "Red" button on the "Schedule",
|
||||
"Now", "Next" or "Event" menus.
|
||||
|
||||
* Parameters in the "Setup" menu
|
||||
|
||||
Select "Setup" from the "Main" menu to enter the setup menu. From there you can
|
||||
@ -216,3 +264,13 @@ Video Disk Recorder User's Manual
|
||||
|
||||
LnbFrequLo = 9750 The low and high LNB frequencies (in MHz)
|
||||
LnbFrequHi = 10600
|
||||
|
||||
SetSystemTime = 0 Defines whether the system time will be set according to
|
||||
the time received from the DVB data stream.
|
||||
0 = system time will not be set
|
||||
1 = system time wil be set
|
||||
Note that this works only if VDR is running under a user
|
||||
id that has permisson to set the system time.
|
||||
MarginStart = 2 Defines how many minutes before the official start time
|
||||
MarginStop = 10 of a broadcast VDR shall start recording, and how long
|
||||
after the official end time it shall stop recording.
|
||||
|
20
Makefile
20
Makefile
@ -4,7 +4,7 @@
|
||||
# See the main source file 'vdr.c' for copyright information and
|
||||
# how to reach the author.
|
||||
#
|
||||
# $Id: Makefile 1.13 2000/10/07 16:24:08 kls Exp $
|
||||
# $Id: Makefile 1.14 2000/10/28 16:24:16 kls Exp $
|
||||
|
||||
DVBDIR = ../DVB
|
||||
|
||||
@ -35,20 +35,20 @@ font: genfontfile fontosd.c
|
||||
|
||||
# Dependencies:
|
||||
|
||||
config.o : config.c config.h dvbapi.h dvbosd.h eit.h font.h interface.h svdrp.h tools.h
|
||||
dvbapi.o : dvbapi.c config.h dvbapi.h dvbosd.h font.h interface.h svdrp.h tools.h videodir.h
|
||||
config.o : config.c config.h dvbapi.h dvbosd.h eit.h font.h interface.h remote.h svdrp.h thread.h tools.h
|
||||
dvbapi.o : dvbapi.c config.h dvbapi.h dvbosd.h eit.h font.h interface.h remote.h svdrp.h thread.h tools.h videodir.h
|
||||
dvbosd.o : dvbosd.c dvbosd.h font.h tools.h
|
||||
eit.o : eit.c eit.h tools.h
|
||||
eit.o : eit.c eit.h thread.h tools.h
|
||||
font.o : font.c font.h fontosd.c tools.h
|
||||
interface.o: interface.c config.h dvbapi.h dvbosd.h eit.h font.h interface.h remote.h svdrp.h thread.h tools.h
|
||||
menu.o : menu.c config.h dvbapi.h dvbosd.h font.h interface.h menu.h osd.h recording.h svdrp.h tools.h
|
||||
osd.o : osd.c config.h dvbapi.h dvbosd.h font.h interface.h osd.h svdrp.h tools.h
|
||||
recording.o: recording.c config.h dvbapi.h dvbosd.h font.h interface.h recording.h svdrp.h tools.h videodir.h
|
||||
remote.o : remote.c config.h dvbapi.h dvbosd.h font.h remote.h thread.h tools.h
|
||||
svdrp.o : svdrp.c config.h dvbapi.h dvbosd.h font.h interface.h svdrp.h tools.h
|
||||
menu.o : menu.c config.h dvbapi.h dvbosd.h eit.h font.h interface.h menu.h osd.h recording.h remote.h svdrp.h thread.h tools.h
|
||||
osd.o : osd.c config.h dvbapi.h dvbosd.h eit.h font.h interface.h osd.h remote.h svdrp.h thread.h tools.h
|
||||
recording.o: recording.c config.h dvbapi.h dvbosd.h eit.h font.h interface.h recording.h remote.h svdrp.h thread.h tools.h videodir.h
|
||||
remote.o : remote.c config.h dvbapi.h dvbosd.h eit.h font.h remote.h thread.h tools.h
|
||||
svdrp.o : svdrp.c config.h dvbapi.h dvbosd.h eit.h font.h interface.h remote.h svdrp.h thread.h tools.h
|
||||
thread.o : thread.c thread.h
|
||||
tools.o : tools.c tools.h
|
||||
vdr.o : vdr.c config.h dvbapi.h dvbosd.h font.h interface.h menu.h osd.h recording.h svdrp.h tools.h videodir.h
|
||||
vdr.o : vdr.c config.h dvbapi.h dvbosd.h eit.h font.h interface.h menu.h osd.h recording.h remote.h svdrp.h thread.h tools.h videodir.h
|
||||
videodir.o : videodir.c tools.h videodir.h
|
||||
|
||||
# The main program:
|
||||
|
89
config.c
89
config.c
@ -4,18 +4,15 @@
|
||||
* See the main source file 'vdr.c' for copyright information and
|
||||
* how to reach the author.
|
||||
*
|
||||
* $Id: config.c 1.26 2000/10/08 16:10:40 kls Exp $
|
||||
* $Id: config.c 1.27 2000/10/29 13:04:37 kls Exp $
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include <ctype.h>
|
||||
#include <stdlib.h>
|
||||
#include "dvbapi.h"
|
||||
#include "eit.h"
|
||||
#include "interface.h"
|
||||
|
||||
extern cEIT EIT;
|
||||
|
||||
// -- cKeys ------------------------------------------------------------------
|
||||
|
||||
tKey keyTable[] = { // "Up" and "Down" must be the first two keys!
|
||||
@ -267,10 +264,8 @@ bool cChannel::Switch(cDvbApi *DvbApi)
|
||||
isyslog(LOG_INFO, "switching to channel %d", number);
|
||||
CurrentChannel = number;
|
||||
for (int i = 3; i--;) {
|
||||
if (DvbApi->SetChannel(frequency, polarization, diseqc, srate, vpid, apid, ca, pnr)) {
|
||||
EIT.SetProgramNumber(pnr);
|
||||
if (DvbApi->SetChannel(frequency, polarization, diseqc, srate, vpid, apid, ca, pnr))
|
||||
return true;
|
||||
}
|
||||
esyslog(LOG_ERR, "retrying");
|
||||
}
|
||||
return false;
|
||||
@ -306,6 +301,47 @@ cTimer::cTimer(bool Instant)
|
||||
snprintf(file, sizeof(file), "%s%s", Setup.MarkInstantRecord ? "@" : "", ch->name);
|
||||
}
|
||||
|
||||
cTimer::cTimer(const cEventInfo *EventInfo)
|
||||
{
|
||||
startTime = stopTime = 0;
|
||||
recording = false;
|
||||
active = true;
|
||||
cChannel *ch = Channels.GetByServiceID(EventInfo->GetServiceID());
|
||||
channel = ch ? ch->number : 0;
|
||||
time_t tstart = EventInfo->GetTime();
|
||||
time_t tstop = tstart + EventInfo->GetDuration() + Setup.MarginStop * 60;
|
||||
tstart -= Setup.MarginStart * 60;
|
||||
struct tm *time = localtime(&tstart);
|
||||
day = time->tm_mday;
|
||||
start = time->tm_hour * 100 + time->tm_min;
|
||||
time = localtime(&tstop);
|
||||
stop = time->tm_hour * 100 + time->tm_min;
|
||||
if (stop >= 2400)
|
||||
stop -= 2400;
|
||||
priority = 99;
|
||||
lifetime = 99;
|
||||
*file = 0;
|
||||
const char *Title = EventInfo->GetTitle();
|
||||
if (!isempty(Title))
|
||||
strn0cpy(file, EventInfo->GetTitle(), sizeof(file));
|
||||
summary = NULL;
|
||||
const char *Subtitle = EventInfo->GetSubtitle();
|
||||
if (isempty(Subtitle))
|
||||
Subtitle = "";
|
||||
const char *Summary = EventInfo->GetExtendedDescription();
|
||||
if (isempty(Summary))
|
||||
Summary = "";
|
||||
if (*Subtitle || *Summary) {
|
||||
asprintf(&summary, "%s%s%s", Subtitle, (*Subtitle && *Summary) ? "\n\n" : "", Summary);
|
||||
char *p = summary;
|
||||
while (*p) {
|
||||
if (*p == '\n')
|
||||
*p = '|';
|
||||
p++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
cTimer::~cTimer()
|
||||
{
|
||||
delete summary;
|
||||
@ -388,14 +424,33 @@ bool cTimer::Parse(const char *s)
|
||||
char *buffer2 = NULL;
|
||||
delete summary;
|
||||
summary = NULL;
|
||||
//XXX Apparently sscanf() doesn't work correctly if the last %a argument
|
||||
//XXX results in an empty string (this firt occured when the EIT gathering
|
||||
//XXX was put into a separate thread - don't know why this happens...
|
||||
//XXX As a cure we copy the original string and add a blank.
|
||||
//XXX If anybody can shed some light on why sscanf() failes here, I'd love
|
||||
//XXX to hear about that!
|
||||
char *s2 = NULL;
|
||||
int l2 = strlen(s);
|
||||
if (s[l2 - 2] == ':') { // note that 's' has a trailing '\n'
|
||||
s2 = (char *)malloc(l2 + 2);
|
||||
strcat(strn0cpy(s2, s, l2), " \n");
|
||||
s = s2;
|
||||
}
|
||||
if (8 <= sscanf(s, "%d:%d:%a[^:]:%d:%d:%d:%d:%a[^:\n]:%a[^\n]", &active, &channel, &buffer1, &start, &stop, &priority, &lifetime, &buffer2, &summary)) {
|
||||
if (summary && !*skipspace(summary)) {
|
||||
delete summary;
|
||||
summary = NULL;
|
||||
}
|
||||
//TODO add more plausibility checks
|
||||
day = ParseDay(buffer1);
|
||||
strn0cpy(file, buffer2, MaxFileName);
|
||||
delete buffer1;
|
||||
delete buffer2;
|
||||
delete s2;
|
||||
return day != 0;
|
||||
}
|
||||
delete s2;
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -550,6 +605,17 @@ cChannel *cChannels::GetByNumber(int Number)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
cChannel *cChannels::GetByServiceID(unsigned short ServiceId)
|
||||
{
|
||||
cChannel *channel = (cChannel *)First();
|
||||
while (channel) {
|
||||
if (channel->pnr == ServiceId)
|
||||
return channel;
|
||||
channel = (cChannel *)channel->Next();
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bool cChannels::SwitchTo(int Number, cDvbApi *DvbApi)
|
||||
{
|
||||
cChannel *channel = GetByNumber(Number);
|
||||
@ -599,6 +665,9 @@ cSetup::cSetup(void)
|
||||
MarkInstantRecord = 1;
|
||||
LnbFrequLo = 9750;
|
||||
LnbFrequHi = 10600;
|
||||
SetSystemTime = 0;
|
||||
MarginStart = 2;
|
||||
MarginStop = 10;
|
||||
}
|
||||
|
||||
bool cSetup::Parse(char *s)
|
||||
@ -613,6 +682,9 @@ bool cSetup::Parse(char *s)
|
||||
else if (!strcasecmp(Name, "MarkInstantRecord")) MarkInstantRecord = atoi(Value);
|
||||
else if (!strcasecmp(Name, "LnbFrequLo")) LnbFrequLo = atoi(Value);
|
||||
else if (!strcasecmp(Name, "LnbFrequHi")) LnbFrequHi = atoi(Value);
|
||||
else if (!strcasecmp(Name, "SetSystemTime")) SetSystemTime = atoi(Value);
|
||||
else if (!strcasecmp(Name, "MarginStart")) MarginStart = atoi(Value);
|
||||
else if (!strcasecmp(Name, "MarginStop")) MarginStop = atoi(Value);
|
||||
else
|
||||
return false;
|
||||
return true;
|
||||
@ -660,6 +732,9 @@ bool cSetup::Save(const char *FileName)
|
||||
fprintf(f, "MarkInstantRecord = %d\n", MarkInstantRecord);
|
||||
fprintf(f, "LnbFrequLo = %d\n", LnbFrequLo);
|
||||
fprintf(f, "LnbFrequHi = %d\n", LnbFrequHi);
|
||||
fprintf(f, "SetSystemTime = %d\n", SetSystemTime);
|
||||
fprintf(f, "MarginStart = %d\n", MarginStart);
|
||||
fprintf(f, "MarginStop = %d\n", MarginStop);
|
||||
fclose(f);
|
||||
isyslog(LOG_INFO, "saved setup to %s", FileName);
|
||||
return true;
|
||||
|
9
config.h
9
config.h
@ -4,7 +4,7 @@
|
||||
* See the main source file 'vdr.c' for copyright information and
|
||||
* how to reach the author.
|
||||
*
|
||||
* $Id: config.h 1.27 2000/10/08 16:33:48 kls Exp $
|
||||
* $Id: config.h 1.28 2000/10/29 09:34:10 kls Exp $
|
||||
*/
|
||||
|
||||
#ifndef __CONFIG_H
|
||||
@ -15,9 +15,10 @@
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
#include "dvbapi.h"
|
||||
#include "eit.h"
|
||||
#include "tools.h"
|
||||
|
||||
#define VDRVERSION "0.66"
|
||||
#define VDRVERSION "0.67"
|
||||
|
||||
#define MaxBuffer 10000
|
||||
|
||||
@ -113,6 +114,7 @@ public:
|
||||
char file[MaxFileName];
|
||||
char *summary;
|
||||
cTimer(bool Instant = false);
|
||||
cTimer(const cEventInfo *EventInfo);
|
||||
~cTimer();
|
||||
cTimer& operator= (const cTimer &Timer);
|
||||
const char *ToText(void);
|
||||
@ -204,6 +206,7 @@ public:
|
||||
int GetNextNormal(int Idx); // Get next normal channel (not group)
|
||||
void ReNumber(void); // Recalculate 'number' based on channel type
|
||||
cChannel *GetByNumber(int Number);
|
||||
cChannel *GetByServiceID(unsigned short ServiceId);
|
||||
const char *GetChannelNameByNumber(int Number);
|
||||
bool SwitchTo(int Number, cDvbApi *DvbApi = NULL);
|
||||
int MaxNumber(void) { return maxNumber; }
|
||||
@ -234,6 +237,8 @@ public:
|
||||
int MarkInstantRecord;
|
||||
int LnbFrequLo;
|
||||
int LnbFrequHi;
|
||||
int SetSystemTime;
|
||||
int MarginStart, MarginStop;
|
||||
cSetup(void);
|
||||
bool Load(const char *FileName);
|
||||
bool Save(const char *FileName = NULL);
|
||||
|
47
dvbapi.c
47
dvbapi.c
@ -4,7 +4,7 @@
|
||||
* See the main source file 'vdr.c' for copyright information and
|
||||
* how to reach the author.
|
||||
*
|
||||
* $Id: dvbapi.c 1.32 2000/10/14 08:56:08 kls Exp $
|
||||
* $Id: dvbapi.c 1.33 2000/10/29 10:39:57 kls Exp $
|
||||
*/
|
||||
|
||||
#include "dvbapi.h"
|
||||
@ -25,6 +25,7 @@ extern "C" {
|
||||
#include "videodir.h"
|
||||
|
||||
#define VIDEODEVICE "/dev/video"
|
||||
#define VBIDEVICE "/dev/vbi"
|
||||
|
||||
// The size of the array used to buffer video data:
|
||||
#define VIDEOBUFSIZE (1024*1024)
|
||||
@ -1084,14 +1085,27 @@ int cDvbApi::NumDvbApis = 0;
|
||||
cDvbApi *cDvbApi::dvbApi[MAXDVBAPI] = { NULL };
|
||||
cDvbApi *cDvbApi::PrimaryDvbApi = NULL;
|
||||
|
||||
cDvbApi::cDvbApi(const char *FileName)
|
||||
cDvbApi::cDvbApi(const char *VideoFileName, const char *VbiFileName)
|
||||
{
|
||||
siProcessor = NULL;
|
||||
pidRecord = pidReplay = 0;
|
||||
fromRecord = toRecord = -1;
|
||||
fromReplay = toReplay = -1;
|
||||
videoDev = open(FileName, O_RDWR | O_NONBLOCK);
|
||||
if (videoDev < 0)
|
||||
LOG_ERROR;
|
||||
videoDev = open(VideoFileName, O_RDWR | O_NONBLOCK);
|
||||
if (videoDev >= 0) {
|
||||
siProcessor = new cSIProcessor(VbiFileName);
|
||||
if (!NumDvbApis) // only the first one shall set the system time
|
||||
siProcessor->SetUseTSTime(Setup.SetSystemTime);
|
||||
siProcessor->AddFilter(0x14, 0x70); // TDT
|
||||
siProcessor->AddFilter(0x14, 0x73); // TOT
|
||||
siProcessor->AddFilter(0x12, 0x4e); // event info, actual TS, present/following
|
||||
siProcessor->AddFilter(0x12, 0x4f); // event info, other TS, present/following
|
||||
siProcessor->AddFilter(0x12, 0x50); // event info, actual TS, schedule
|
||||
siProcessor->AddFilter(0x12, 0x60); // event info, other TS, schedule
|
||||
siProcessor->Start();
|
||||
}
|
||||
else
|
||||
LOG_ERROR_STR(VideoFileName);
|
||||
cols = rows = 0;
|
||||
|
||||
ovlGeoSet = ovlStat = ovlFbSet = false;
|
||||
@ -1121,6 +1135,7 @@ cDvbApi::cDvbApi(const char *FileName)
|
||||
cDvbApi::~cDvbApi()
|
||||
{
|
||||
if (videoDev >= 0) {
|
||||
delete siProcessor;
|
||||
Close();
|
||||
Stop();
|
||||
StopRecord();
|
||||
@ -1174,11 +1189,9 @@ int cDvbApi::Index(void)
|
||||
|
||||
bool cDvbApi::Init(void)
|
||||
{
|
||||
char fileName[strlen(VIDEODEVICE) + 10];
|
||||
int i;
|
||||
|
||||
NumDvbApis = 0;
|
||||
for (i = 0; i < MAXDVBAPI; i++) {
|
||||
for (int i = 0; i < MAXDVBAPI; i++) {
|
||||
char fileName[strlen(VIDEODEVICE) + 10];
|
||||
sprintf(fileName, "%s%d", VIDEODEVICE, i);
|
||||
if (access(fileName, F_OK | R_OK | W_OK) == 0) {
|
||||
dsyslog(LOG_INFO, "probing %s", fileName);
|
||||
@ -1188,7 +1201,9 @@ bool cDvbApi::Init(void)
|
||||
int r = ioctl(f, VIDIOCGCAP, &cap);
|
||||
close(f);
|
||||
if (r == 0 && (cap.type & VID_TYPE_DVB)) {
|
||||
dvbApi[i] = new cDvbApi(fileName);
|
||||
char vbiFileName[strlen(VBIDEVICE) + 10];
|
||||
sprintf(vbiFileName, "%s%d", VBIDEVICE, i);
|
||||
dvbApi[i] = new cDvbApi(fileName, vbiFileName);
|
||||
NumDvbApis++;
|
||||
}
|
||||
}
|
||||
@ -1223,6 +1238,13 @@ void cDvbApi::Cleanup(void)
|
||||
PrimaryDvbApi = NULL;
|
||||
}
|
||||
|
||||
const cSchedules *cDvbApi::Schedules(cThreadLock *ThreadLock) const
|
||||
{
|
||||
if (siProcessor && ThreadLock->Lock(siProcessor))
|
||||
return siProcessor->Schedules();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bool cDvbApi::GrabImage(const char *FileName, bool Jpeg, int Quality, int SizeX, int SizeY)
|
||||
{
|
||||
int result = 0;
|
||||
@ -1671,8 +1693,11 @@ bool cDvbApi::SetChannel(int FrequencyMHz, char Polarization, int Diseqc, int Sr
|
||||
front.fec = 8;
|
||||
front.AFC = 1;
|
||||
ioctl(videoDev, VIDIOCSFRONTEND, &front);
|
||||
if (front.sync & 0x1F == 0x1F)
|
||||
if (front.sync & 0x1F == 0x1F) {
|
||||
if (siProcessor)
|
||||
siProcessor->SetCurrentServiceID(Pnr);
|
||||
return true;
|
||||
}
|
||||
esyslog(LOG_ERR, "ERROR: channel not sync'ed (front.sync=%X)!", front.sync);
|
||||
}
|
||||
return false;
|
||||
|
14
dvbapi.h
14
dvbapi.h
@ -4,7 +4,7 @@
|
||||
* See the main source file 'vdr.c' for copyright information and
|
||||
* how to reach the author.
|
||||
*
|
||||
* $Id: dvbapi.h 1.18 2000/10/03 11:26:10 kls Exp $
|
||||
* $Id: dvbapi.h 1.19 2000/10/29 12:11:16 kls Exp $
|
||||
*/
|
||||
|
||||
#ifndef __DVBAPI_H
|
||||
@ -21,6 +21,7 @@ typedef unsigned char __u8;
|
||||
#include <stdio.h>
|
||||
#include <dvb.h>
|
||||
#include "dvbosd.h"
|
||||
#include "eit.h"
|
||||
|
||||
// Overlay facilities
|
||||
#define MAXCLIPRECTS 100
|
||||
@ -44,7 +45,8 @@ public:
|
||||
class cDvbApi {
|
||||
private:
|
||||
int videoDev;
|
||||
cDvbApi(const char *FileName);
|
||||
cSIProcessor *siProcessor;
|
||||
cDvbApi(const char *VideoFileName, const char *VbiFileName);
|
||||
public:
|
||||
~cDvbApi();
|
||||
|
||||
@ -71,6 +73,14 @@ public:
|
||||
// Closes down all DVB devices.
|
||||
// Must be called at the end of the program.
|
||||
|
||||
// EIT facilities
|
||||
|
||||
const cSchedules *Schedules(cThreadLock *ThreadLock) const;
|
||||
// Caller must provide a cThreadLock which has to survive the entire
|
||||
// time the returned cSchedules is accessed. Once the cSchedules is no
|
||||
// longer used, the cThreadLock must be destroyed.
|
||||
void SetUseTSTime(bool On) { if (siProcessor) siProcessor->SetUseTSTime(On); }
|
||||
|
||||
// Image Grab facilities
|
||||
|
||||
bool GrabImage(const char *FileName, bool Jpeg = true, int Quality = -1, int SizeX = -1, int SizeY = -1);
|
||||
|
179
eit.h
179
eit.h
@ -13,80 +13,127 @@
|
||||
* the Free Software Foundation; either version 2 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
* $Id: eit.h 1.1 2000/09/03 10:23:24 kls Exp $
|
||||
* $Id: eit.h 1.2 2000/10/29 10:21:56 kls Exp $
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef __EIT_H
|
||||
#define __EIT_H
|
||||
|
||||
#include <dvb_v4l.h>
|
||||
#include "thread.h"
|
||||
#include "tools.h"
|
||||
|
||||
typedef struct eit_event {
|
||||
|
||||
bool bIsValid;
|
||||
char szTitle[512];
|
||||
char szSubTitle[512];
|
||||
char szDate[12];
|
||||
char szTime[12];
|
||||
|
||||
}eit_event;
|
||||
|
||||
/**
|
||||
*@author Robert Schneider
|
||||
*/
|
||||
|
||||
class cEIT {
|
||||
class cEventInfo : public cListObject {
|
||||
friend class cSchedule;
|
||||
friend class cEIT;
|
||||
private:
|
||||
unsigned short uServiceID; // Service ID of program for that event
|
||||
bool bIsFollowing; // true if this is the next event on this channel
|
||||
bool bIsPresent; // true if this is the present event running
|
||||
char *pExtendedDescription; // Extended description of this event
|
||||
char *pSubtitle; // Subtitle of event
|
||||
char *pTitle; // Title of event
|
||||
unsigned short uEventID; // Event ID of this event
|
||||
long lDuration; // duration of event in seconds
|
||||
time_t tTime; // Start time
|
||||
u_char cExtendedDescriptorNumber; // current extended descriptor number that has to be inserted
|
||||
int nChannelNumber; // the actual channel number from VDR's channel list (used in cMenuSchedule for sorting by channel number)
|
||||
protected:
|
||||
void SetFollowing(bool foll);
|
||||
void SetPresent(bool pres);
|
||||
bool SetTitle(char *string);
|
||||
void SetServiceID(unsigned short servid);
|
||||
void SetEventID(unsigned short evid);
|
||||
void SetDuration(long l);
|
||||
void SetTime(time_t t);
|
||||
bool AddExtendedDescription(char *string);
|
||||
bool SetSubtitle(char *string);
|
||||
void IncreaseExtendedDescriptorNumber(void);
|
||||
cEventInfo(unsigned short serviceid, unsigned short eventid);
|
||||
public:
|
||||
cEIT();
|
||||
~cEIT();
|
||||
/** */
|
||||
int GetEIT();
|
||||
/** */
|
||||
int SetProgramNumber(unsigned short pnr);
|
||||
/** Retrieves the string representing the time of the current event */
|
||||
char * GetRunningTime();
|
||||
/** Retrieves the string representing the date of the current event */
|
||||
char * GetRunningDate();
|
||||
/** Retrieves the string for the running subtitle */
|
||||
char * GetRunningSubtitle();
|
||||
/** retrieves the string for the running title */
|
||||
char * GetRunningTitle();
|
||||
/** Retrieves the string representing the time of the next event */
|
||||
char * GetNextTime();
|
||||
/** Retrieves the string representing the date of the next event */
|
||||
char * GetNextDate();
|
||||
/** Retrieves the string for the next subtitle */
|
||||
char * GetNextSubtitle();
|
||||
/** retrieves the string for the next title */
|
||||
char * GetNextTitle();
|
||||
/** */
|
||||
bool IsValid();
|
||||
~cEventInfo();
|
||||
const char *GetTimeString(void) const;
|
||||
const char *GetEndTimeString(void) const;
|
||||
const char *GetDate(void) const;
|
||||
bool IsFollowing(void) const;
|
||||
bool IsPresent(void) const;
|
||||
const char *GetExtendedDescription(void) const;
|
||||
const char *GetSubtitle(void) const;
|
||||
const char *GetTitle(void) const;
|
||||
unsigned short GetEventID(void) const;
|
||||
long GetDuration(void) const;
|
||||
time_t GetTime(void) const;
|
||||
u_char GetExtendedDescriptorNumber(void) const;
|
||||
unsigned short GetServiceID(void) const;
|
||||
int GetChannelNumber(void) const { return nChannelNumber; }
|
||||
void SetChannelNumber(int ChannelNumber) const { ((cEventInfo *)this)->nChannelNumber = ChannelNumber; } // doesn't modify the EIT data, so it's ok to make it 'const'
|
||||
};
|
||||
|
||||
protected: // Protected attributes
|
||||
/** Device name of VBI device */
|
||||
const char * cszBitFilter;
|
||||
protected: // Protected attributes
|
||||
/** handle to VBI device (usually /dev/vbi) */
|
||||
int fsvbi;
|
||||
/** Describes the event next on */
|
||||
eit_event evtNext;
|
||||
/** Describes the running event */
|
||||
eit_event evtRunning;
|
||||
protected: // Protected methods
|
||||
/** Set the bitfilter in vbi device to return
|
||||
correct tables */
|
||||
int SetBitFilter(unsigned short pid, unsigned short section, unsigned short mode);
|
||||
/** */
|
||||
int GetSection(unsigned char *buf, ushort PID, unsigned char sec);
|
||||
/** */
|
||||
int CloseFilter(unsigned short handle);
|
||||
/** */
|
||||
char * mjd2string(unsigned short mjd);
|
||||
/** */
|
||||
int strdvbcpy(unsigned char *dst, unsigned char *src, int max);
|
||||
public: // Public attributes
|
||||
/** */
|
||||
unsigned short uProgramNumber;
|
||||
class cSchedule : public cListObject {
|
||||
friend class cSchedules;
|
||||
friend class cEIT;
|
||||
private:
|
||||
cEventInfo *pPresent;
|
||||
cEventInfo *pFollowing;
|
||||
unsigned short uServiceID;
|
||||
cList<cEventInfo> Events;
|
||||
protected:
|
||||
void SetServiceID(unsigned short servid);
|
||||
bool SetFollowingEvent(cEventInfo *pEvent);
|
||||
bool SetPresentEvent(cEventInfo *pEvent);
|
||||
void Cleanup(time_t tTime);
|
||||
void Cleanup(void);
|
||||
cSchedule(unsigned short servid = 0);
|
||||
public:
|
||||
~cSchedule();
|
||||
const cEventInfo *GetPresentEvent(void) const;
|
||||
const cEventInfo *GetFollowingEvent(void) const;
|
||||
unsigned short GetServiceID(void) const;
|
||||
const cEventInfo *GetEvent(unsigned short uEventID) const;
|
||||
const cEventInfo *GetEvent(time_t tTime) const;
|
||||
const cEventInfo *GetEventNumber(int n) const { return Events.Get(n); }
|
||||
int NumEvents(void) const { return Events.Count(); }
|
||||
};
|
||||
|
||||
class cSchedules : public cList<cSchedule> {
|
||||
friend class cSIProcessor;
|
||||
private:
|
||||
const cSchedule *pCurrentSchedule;
|
||||
unsigned short uCurrentServiceID;
|
||||
protected:
|
||||
bool SetCurrentServiceID(unsigned short servid);
|
||||
void Cleanup();
|
||||
public:
|
||||
cSchedules(void);
|
||||
~cSchedules();
|
||||
const cSchedule *GetSchedule(unsigned short servid) const;
|
||||
const cSchedule *GetSchedule(void) const;
|
||||
};
|
||||
|
||||
typedef struct sip_filter {
|
||||
|
||||
u_char pid;
|
||||
u_char tid;
|
||||
int handle;
|
||||
bool inuse;
|
||||
|
||||
}SIP_FILTER;
|
||||
|
||||
class cSIProcessor : public cThread {
|
||||
private:
|
||||
cSchedules *schedules;
|
||||
bool useTStime;
|
||||
SIP_FILTER *filters;
|
||||
int fsvbi;
|
||||
bool RefreshFilters(void);
|
||||
void Action(void);
|
||||
public:
|
||||
cSIProcessor(const char *FileName);
|
||||
~cSIProcessor();
|
||||
bool SetUseTSTime(bool use);
|
||||
bool AddFilter(u_char pid, u_char tid);
|
||||
bool ShutDownFilters(void);
|
||||
bool SetCurrentServiceID(unsigned short servid);
|
||||
const cSchedules *Schedules(void) { return schedules; }
|
||||
};
|
||||
|
||||
#endif
|
||||
|
164
interface.c
164
interface.c
@ -4,14 +4,11 @@
|
||||
* See the main source file 'vdr.c' for copyright information and
|
||||
* how to reach the author.
|
||||
*
|
||||
* $Id: interface.c 1.25 2000/10/08 16:34:17 kls Exp $
|
||||
* $Id: interface.c 1.26 2000/10/29 12:53:55 kls Exp $
|
||||
*/
|
||||
|
||||
#include "interface.h"
|
||||
#include <unistd.h>
|
||||
#include "eit.h"
|
||||
|
||||
cEIT EIT;
|
||||
|
||||
cInterface *Interface = NULL;
|
||||
|
||||
@ -355,46 +352,141 @@ eKeys cInterface::DisplayChannel(int Number, const char *Name, bool WithInfo)
|
||||
Write(-5, 0, buffer);
|
||||
cDvbApi::PrimaryDvbApi->Flush();
|
||||
|
||||
char *RunningTitle = "", *RunningSubtitle = "", *NextTitle = "", *NextSubtitle = "";
|
||||
int Lines = 0;
|
||||
if (Number && WithInfo && EIT.IsValid()) {
|
||||
if (*(RunningTitle = EIT.GetRunningTitle())) Lines++;
|
||||
if (*(RunningSubtitle = EIT.GetRunningSubtitle())) Lines++;
|
||||
if (*(NextTitle = EIT.GetNextTitle())) Lines++;
|
||||
if (*(NextSubtitle = EIT.GetNextSubtitle())) Lines++;
|
||||
#define INFO_TIMEOUT 5
|
||||
|
||||
const cEventInfo *Present = NULL, *Following = NULL;
|
||||
|
||||
int Tries = 0;
|
||||
if (Number && WithInfo) {
|
||||
for (; Tries < INFO_TIMEOUT; Tries++) {
|
||||
{
|
||||
cThreadLock ThreadLock;
|
||||
const cSchedules *Schedules = cDvbApi::PrimaryDvbApi->Schedules(&ThreadLock);
|
||||
if (Schedules) {
|
||||
const cSchedule *Schedule = Schedules->GetSchedule();
|
||||
if (Schedule) {
|
||||
const char *PresentTitle = NULL, *PresentSubtitle = NULL, *FollowingTitle = NULL, *FollowingSubtitle = NULL;
|
||||
int Lines = 0;
|
||||
if ((Present = Schedule->GetPresentEvent()) != NULL) {
|
||||
PresentTitle = Present->GetTitle();
|
||||
if (!isempty(PresentTitle))
|
||||
Lines++;
|
||||
PresentSubtitle = Present->GetSubtitle();
|
||||
if (!isempty(PresentSubtitle))
|
||||
Lines++;
|
||||
}
|
||||
if ((Following = Schedule->GetFollowingEvent()) != NULL) {
|
||||
FollowingTitle = Following->GetTitle();
|
||||
if (!isempty(FollowingTitle))
|
||||
Lines++;
|
||||
FollowingSubtitle = Following->GetSubtitle();
|
||||
if (!isempty(FollowingSubtitle))
|
||||
Lines++;
|
||||
}
|
||||
if (Lines > 0) {
|
||||
const int t = 6;
|
||||
int l = 1;
|
||||
cDvbApi::PrimaryDvbApi->Fill(0, 1, MenuColumns, Lines, clrBackground);
|
||||
if (!isempty(PresentTitle)) {
|
||||
Write(0, l, Present->GetTimeString(), clrYellow, clrBackground);
|
||||
Write(t, l, PresentTitle, clrCyan, clrBackground);
|
||||
l++;
|
||||
}
|
||||
if (!isempty(PresentSubtitle)) {
|
||||
Write(t, l, PresentSubtitle, clrCyan, clrBackground);
|
||||
l++;
|
||||
}
|
||||
if (!isempty(FollowingTitle)) {
|
||||
Write(0, l, Following->GetTimeString(), clrYellow, clrBackground);
|
||||
Write(t, l, FollowingTitle, clrCyan, clrBackground);
|
||||
l++;
|
||||
}
|
||||
if (!isempty(FollowingSubtitle)) {
|
||||
Write(t, l, FollowingSubtitle, clrCyan, clrBackground);
|
||||
}
|
||||
cDvbApi::PrimaryDvbApi->Flush();
|
||||
if (Lines == 4) {
|
||||
Tries = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
eKeys Key = Wait(1, true);
|
||||
if (Key != kNone)
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (Lines > 0) {
|
||||
const int t = 6;
|
||||
int l = 1;
|
||||
cDvbApi::PrimaryDvbApi->Fill(0, 1, MenuColumns, Lines, clrBackground);
|
||||
if (*RunningTitle) {
|
||||
Write(0, l, EIT.GetRunningTime(), clrYellow, clrBackground);
|
||||
Write(t, l, RunningTitle, clrCyan, clrBackground);
|
||||
l++;
|
||||
}
|
||||
if (*RunningSubtitle) {
|
||||
Write(t, l, RunningSubtitle, clrCyan, clrBackground);
|
||||
l++;
|
||||
}
|
||||
if (*NextTitle) {
|
||||
Write(0, l, EIT.GetNextTime(), clrYellow, clrBackground);
|
||||
Write(t, l, NextTitle, clrCyan, clrBackground);
|
||||
l++;
|
||||
}
|
||||
if (*NextSubtitle) {
|
||||
Write(t, l, NextSubtitle, clrCyan, clrBackground);
|
||||
}
|
||||
cDvbApi::PrimaryDvbApi->Flush();
|
||||
}
|
||||
eKeys Key = Wait(5, true);
|
||||
eKeys Key = Wait(INFO_TIMEOUT - Tries, true);
|
||||
Close();
|
||||
if (Key == kOk)
|
||||
GetKey();
|
||||
Close();
|
||||
if (Key == kGreen || Key == kYellow) {
|
||||
GetKey();
|
||||
do {
|
||||
Key = DisplayDescription((Key == kGreen) ? Present : Following);
|
||||
} while (Key == kGreen || Key == kYellow);
|
||||
Key = kNone;
|
||||
}
|
||||
return Key;
|
||||
}
|
||||
return kNone;
|
||||
}
|
||||
|
||||
eKeys cInterface::DisplayDescription(const cEventInfo *EventInfo)
|
||||
{
|
||||
eKeys Key = kNone;
|
||||
|
||||
if (EventInfo) {
|
||||
int line = 0;
|
||||
|
||||
Open();
|
||||
Clear();
|
||||
|
||||
char buffer[MenuColumns + 1];
|
||||
snprintf(buffer, sizeof(buffer), "%s %s", EventInfo->GetDate() ? EventInfo->GetDate() : "", EventInfo->GetTimeString() ? EventInfo->GetTimeString() : "");
|
||||
Write(-strlen(buffer), line, buffer, clrYellow);
|
||||
|
||||
line = WriteParagraph(line, EventInfo->GetTitle());
|
||||
line = WriteParagraph(line, EventInfo->GetSubtitle());
|
||||
line = WriteParagraph(line, EventInfo->GetExtendedDescription());
|
||||
|
||||
Key = Wait(300);
|
||||
Close();
|
||||
}
|
||||
return Key;
|
||||
}
|
||||
|
||||
int cInterface::WriteParagraph(int Line, const char *Text)
|
||||
{
|
||||
if (Line < MenuLines && Text) {
|
||||
Line++;
|
||||
char *s = strdup(Text);
|
||||
char *pStart = s, *pEnd;
|
||||
char *pEndText = &s[strlen(s) - 1];
|
||||
|
||||
while (pStart < pEndText) {
|
||||
if (strlen(pStart) > (unsigned)(MenuColumns - 2))
|
||||
pEnd = &pStart[MenuColumns - 2];
|
||||
else
|
||||
pEnd = &pStart[strlen(pStart)];
|
||||
|
||||
while (*pEnd != 0 && *pEnd != ' ' && pEnd > pStart)
|
||||
pEnd--;
|
||||
|
||||
//XXX what if there are no blanks???
|
||||
//XXX need to scroll if text is longer
|
||||
*pEnd = 0;
|
||||
Write(1, Line++, pStart, clrCyan);
|
||||
if (Line >= MenuLines)
|
||||
return Line;
|
||||
pStart = pEnd + 1;
|
||||
}
|
||||
}
|
||||
return Line;
|
||||
}
|
||||
|
||||
void cInterface::DisplayRecording(int Index, bool On)
|
||||
{
|
||||
rcIo->SetPoints(1 << Index, On);
|
||||
|
@ -4,7 +4,7 @@
|
||||
* See the main source file 'vdr.c' for copyright information and
|
||||
* how to reach the author.
|
||||
*
|
||||
* $Id: interface.h 1.16 2000/10/08 12:15:49 kls Exp $
|
||||
* $Id: interface.h 1.17 2000/10/29 12:32:12 kls Exp $
|
||||
*/
|
||||
|
||||
#ifndef __INTERFACE_H
|
||||
@ -28,6 +28,8 @@ private:
|
||||
void QueryKeys(void);
|
||||
void HelpButton(int Index, const char *Text, eDvbColor FgColor, eDvbColor BgColor);
|
||||
eKeys Wait(int Seconds = 1, bool KeepChar = false);
|
||||
eKeys DisplayDescription(const cEventInfo *EventInfo);
|
||||
int WriteParagraph(int Line, const char *Text);
|
||||
public:
|
||||
cInterface(int SVDRPport = 0);
|
||||
~cInterface();
|
||||
|
304
menu.c
304
menu.c
@ -4,15 +4,17 @@
|
||||
* See the main source file 'vdr.c' for copyright information and
|
||||
* how to reach the author.
|
||||
*
|
||||
* $Id: menu.c 1.36 2000/10/08 16:11:22 kls Exp $
|
||||
* $Id: menu.c 1.37 2000/10/29 11:23:33 kls Exp $
|
||||
*/
|
||||
|
||||
#include "menu.h"
|
||||
#include <ctype.h>
|
||||
#include <limits.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "config.h"
|
||||
#include "eit.h"
|
||||
|
||||
#define MENUTIMEOUT 120 // seconds
|
||||
|
||||
@ -973,6 +975,300 @@ eOSState cMenuTimers::ProcessKey(eKeys Key)
|
||||
return state;
|
||||
}
|
||||
|
||||
// --- cMenuEventItem --------------------------------------------------------
|
||||
|
||||
class cMenuEventItem : public cOsdItem {
|
||||
public:
|
||||
cMenuEventItem(const char *Text);
|
||||
};
|
||||
|
||||
cMenuEventItem::cMenuEventItem(const char *Text)
|
||||
:cOsdItem(Text, osBack)
|
||||
{
|
||||
}
|
||||
|
||||
// --- cMenuEvent ------------------------------------------------------------
|
||||
|
||||
class cMenuEvent : public cOsdMenu {
|
||||
private:
|
||||
void AddParagraph(const char *text);
|
||||
const cEventInfo *eventInfo;
|
||||
public:
|
||||
cMenuEvent(const cEventInfo *EventInfo, bool CanSwitch = false);
|
||||
};
|
||||
|
||||
cMenuEvent::cMenuEvent(const cEventInfo *EventInfo, bool CanSwitch)
|
||||
:cOsdMenu("Event", 1)
|
||||
{
|
||||
const char *p;
|
||||
char buffer[MenuColumns + 1];
|
||||
|
||||
eventInfo = EventInfo;
|
||||
|
||||
cChannel *channel = Channels.GetByServiceID(eventInfo->GetServiceID());
|
||||
|
||||
snprintf(buffer, sizeof(buffer), "\t%-17.*s %.*s %s - %s", 17, channel->name, 5, eventInfo->GetDate(), eventInfo->GetTimeString(), eventInfo->GetEndTimeString());
|
||||
Add(new cMenuEventItem(buffer));
|
||||
if ((p = eventInfo->GetTitle()) != NULL && *p) {
|
||||
Add(new cMenuEventItem(""));
|
||||
AddParagraph(p);
|
||||
}
|
||||
if ((p = eventInfo->GetSubtitle()) != NULL && *p) {
|
||||
Add(new cMenuEventItem(""));
|
||||
AddParagraph(p);
|
||||
}
|
||||
if ((p = eventInfo->GetExtendedDescription()) != NULL && *p) {
|
||||
Add(new cMenuEventItem(""));
|
||||
AddParagraph(p);
|
||||
}
|
||||
SetHelp("Record", NULL, NULL, CanSwitch ? "Switch" : NULL);
|
||||
}
|
||||
|
||||
void cMenuEvent::AddParagraph(const char *text)
|
||||
{
|
||||
char *ptextsave = strdup(text);
|
||||
|
||||
if (ptextsave) {
|
||||
|
||||
int column = 1;
|
||||
char buffer[MenuColumns + 1];
|
||||
char *pStart = ptextsave;
|
||||
char *pEndText = &ptextsave[strlen(text) - 1];
|
||||
|
||||
while (pStart < pEndText) {
|
||||
char *pEnd;
|
||||
if (strlen(pStart) > (unsigned)(MenuColumns - column - 2))
|
||||
pEnd = &pStart[MenuColumns - column - 2];
|
||||
else
|
||||
pEnd = &pStart[strlen(pStart)];
|
||||
|
||||
while (*pEnd && *pEnd != ' ' && pEnd > pStart)
|
||||
pEnd--;
|
||||
|
||||
*pEnd = 0;
|
||||
sprintf(buffer, "\t%s", pStart);
|
||||
Add(new cMenuEventItem(buffer));
|
||||
pStart = pEnd + 1;
|
||||
}
|
||||
}
|
||||
|
||||
delete ptextsave;
|
||||
}
|
||||
|
||||
// --- cMenuWhatsOnItem ------------------------------------------------------
|
||||
|
||||
class cMenuWhatsOnItem : public cOsdItem {
|
||||
public:
|
||||
const cEventInfo *eventInfo;
|
||||
cMenuWhatsOnItem(const cEventInfo *EventInfo);
|
||||
};
|
||||
|
||||
cMenuWhatsOnItem::cMenuWhatsOnItem(const cEventInfo *EventInfo)
|
||||
{
|
||||
eventInfo = EventInfo;
|
||||
char *buffer = NULL;
|
||||
cChannel *channel = Channels.GetByNumber(eventInfo->GetChannelNumber());
|
||||
asprintf(&buffer, "%d\t%.*s\t%.*s\t%s", eventInfo->GetChannelNumber(), 6, channel ? channel->name : "???", 5, eventInfo->GetTimeString(), eventInfo->GetTitle());
|
||||
SetText(buffer, false);
|
||||
}
|
||||
|
||||
// --- cMenuWhatsOn ----------------------------------------------------------
|
||||
|
||||
class cMenuWhatsOn : public cOsdMenu {
|
||||
private:
|
||||
eOSState Record(void);
|
||||
eOSState Switch(void);
|
||||
public:
|
||||
cMenuWhatsOn(const cSchedules *Schedules, bool Now);
|
||||
virtual eOSState ProcessKey(eKeys Key);
|
||||
};
|
||||
|
||||
static int CompareEventChannel(const void *p1, const void *p2)
|
||||
{
|
||||
return (int)( (*(const cEventInfo **)p1)->GetChannelNumber() - (*(const cEventInfo **)p2)->GetChannelNumber());
|
||||
}
|
||||
|
||||
cMenuWhatsOn::cMenuWhatsOn(const cSchedules *Schedules, bool Now)
|
||||
:cOsdMenu(Now ? "What's on now?" : "What's on next?", 4, 7, 6)
|
||||
{
|
||||
const cSchedule *Schedule = Schedules->First();
|
||||
const cEventInfo **pArray = NULL;
|
||||
int num = 0;
|
||||
|
||||
while (Schedule) {
|
||||
pArray = (const cEventInfo **)realloc(pArray, (num + 1) * sizeof(cEventInfo *));
|
||||
|
||||
pArray[num] = Now ? Schedule->GetPresentEvent() : Schedule->GetFollowingEvent();
|
||||
if (pArray[num]) {
|
||||
cChannel *channel = Channels.GetByServiceID(pArray[num]->GetServiceID());
|
||||
if (channel) {
|
||||
pArray[num]->SetChannelNumber(channel->number);
|
||||
num++;
|
||||
}
|
||||
}
|
||||
Schedule = (const cSchedule *)Schedules->Next(Schedule);
|
||||
}
|
||||
|
||||
qsort(pArray, num, sizeof(cEventInfo *), CompareEventChannel);
|
||||
|
||||
for (int a = 0; a < num; a++)
|
||||
Add(new cMenuWhatsOnItem(pArray[a]));
|
||||
|
||||
delete pArray;
|
||||
SetHelp("Record", Now ? "Next" : "Now", "Schedule", "Switch");
|
||||
}
|
||||
|
||||
eOSState cMenuWhatsOn::Switch(void)
|
||||
{
|
||||
cMenuWhatsOnItem *item = (cMenuWhatsOnItem *)Get(Current());
|
||||
if (item) {
|
||||
cChannel *channel = Channels.GetByServiceID(item->eventInfo->GetServiceID());
|
||||
if (channel && channel->Switch())
|
||||
return osEnd;
|
||||
}
|
||||
Interface->Error("Can't switch channel!");
|
||||
return osContinue;
|
||||
}
|
||||
|
||||
eOSState cMenuWhatsOn::Record(void)
|
||||
{
|
||||
cMenuWhatsOnItem *item = (cMenuWhatsOnItem *)Get(Current());
|
||||
if (item) {
|
||||
cTimer *timer = new cTimer(item->eventInfo);
|
||||
Timers.Add(timer);
|
||||
Timers.Save();
|
||||
isyslog(LOG_INFO, "timer %d added", timer->Index() + 1);
|
||||
return AddSubMenu(new cMenuEditTimer(timer->Index(), true));
|
||||
}
|
||||
return osContinue;
|
||||
}
|
||||
|
||||
eOSState cMenuWhatsOn::ProcessKey(eKeys Key)
|
||||
{
|
||||
eOSState state = cOsdMenu::ProcessKey(Key);
|
||||
|
||||
if (state == osUnknown) {
|
||||
switch (Key) {
|
||||
case kRed: return Record();
|
||||
case kYellow: return osBack;
|
||||
case kBlue: return Switch();
|
||||
case kOk: return AddSubMenu(new cMenuEvent(((cMenuWhatsOnItem *)Get(Current()))->eventInfo, true));
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
return state;
|
||||
}
|
||||
|
||||
// --- cMenuScheduleItem -----------------------------------------------------
|
||||
|
||||
class cMenuScheduleItem : public cOsdItem {
|
||||
public:
|
||||
const cEventInfo *eventInfo;
|
||||
cMenuScheduleItem(const cEventInfo *EventInfo);
|
||||
};
|
||||
|
||||
cMenuScheduleItem::cMenuScheduleItem(const cEventInfo *EventInfo)
|
||||
{
|
||||
eventInfo = EventInfo;
|
||||
char *buffer = NULL;
|
||||
asprintf(&buffer, "%.*s\t%.*s\t%s", 5, eventInfo->GetDate(), 5, eventInfo->GetTimeString(), eventInfo->GetTitle());
|
||||
SetText(buffer, false);
|
||||
}
|
||||
|
||||
// --- cMenuSchedule ---------------------------------------------------------
|
||||
|
||||
class cMenuSchedule : public cOsdMenu {
|
||||
private:
|
||||
cThreadLock threadLock;
|
||||
const cSchedules *schedules;
|
||||
bool now, next;
|
||||
eOSState Record(void);
|
||||
void PrepareSchedule(void);
|
||||
void PrepareWhatsOnNext(bool On);
|
||||
public:
|
||||
cMenuSchedule(void);
|
||||
virtual eOSState ProcessKey(eKeys Key);
|
||||
};
|
||||
|
||||
cMenuSchedule::cMenuSchedule(void)
|
||||
:cOsdMenu("Schedule", 6, 6)
|
||||
{
|
||||
now = next = false;
|
||||
cChannel *channel = Channels.GetByNumber(CurrentChannel);
|
||||
if (channel) {
|
||||
char *buffer = NULL;
|
||||
asprintf(&buffer, "Schedule - %s", channel->name);
|
||||
SetTitle(buffer, false);
|
||||
}
|
||||
PrepareSchedule();
|
||||
SetHelp("Record", "Now", "Next");
|
||||
}
|
||||
|
||||
static int CompareEventTime(const void *p1, const void *p2)
|
||||
{
|
||||
return (int)((*(cEventInfo **)p1)->GetTime() - (*(cEventInfo **)p2)->GetTime());
|
||||
}
|
||||
|
||||
void cMenuSchedule::PrepareSchedule(void)
|
||||
{
|
||||
schedules = cDvbApi::PrimaryDvbApi->Schedules(&threadLock);
|
||||
if (schedules) {
|
||||
const cSchedule *Schedule = schedules->GetSchedule();
|
||||
int num = Schedule->NumEvents();
|
||||
const cEventInfo **pArray = (const cEventInfo **)malloc(num * sizeof(cEventInfo *));
|
||||
if (pArray) {
|
||||
time_t now = time(NULL);
|
||||
int numreal = 0;
|
||||
for (int a = 0; a < num; a++) {
|
||||
const cEventInfo *EventInfo = Schedule->GetEventNumber(a);
|
||||
if (EventInfo->GetTime() + EventInfo->GetDuration() > now)
|
||||
pArray[numreal++] = EventInfo;
|
||||
}
|
||||
|
||||
qsort(pArray, numreal, sizeof(cEventInfo *), CompareEventTime);
|
||||
|
||||
for (int a = 0; a < numreal; a++)
|
||||
Add(new cMenuScheduleItem(pArray[a]));
|
||||
delete pArray;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
eOSState cMenuSchedule::Record(void)
|
||||
{
|
||||
cMenuScheduleItem *item = (cMenuScheduleItem *)Get(Current());
|
||||
if (item) {
|
||||
cTimer *timer = new cTimer(item->eventInfo);
|
||||
Timers.Add(timer);
|
||||
Timers.Save();
|
||||
isyslog(LOG_INFO, "timer %d added", timer->Index() + 1);
|
||||
return AddSubMenu(new cMenuEditTimer(timer->Index(), true));
|
||||
}
|
||||
return osContinue;
|
||||
}
|
||||
|
||||
eOSState cMenuSchedule::ProcessKey(eKeys Key)
|
||||
{
|
||||
eOSState state = cOsdMenu::ProcessKey(Key);
|
||||
|
||||
if (state == osUnknown) {
|
||||
switch (Key) {
|
||||
case kRed: return Record();
|
||||
case kGreen: if (!now && !next) {
|
||||
now = true;
|
||||
return AddSubMenu(new cMenuWhatsOn(schedules, true));
|
||||
}
|
||||
now = !now;
|
||||
next = !next;
|
||||
return AddSubMenu(new cMenuWhatsOn(schedules, now));
|
||||
case kYellow: return AddSubMenu(new cMenuWhatsOn(schedules, false));
|
||||
case kOk: return AddSubMenu(new cMenuEvent(((cMenuScheduleItem *)Get(Current()))->eventInfo));
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
return state;
|
||||
}
|
||||
|
||||
// --- cMenuRecordingItem ----------------------------------------------------
|
||||
|
||||
class cMenuRecordingItem : public cOsdItem {
|
||||
@ -1089,6 +1385,9 @@ cMenuSetup::cMenuSetup(void)
|
||||
Add(new cMenuEditBoolItem("MarkInstantRecord", &data.MarkInstantRecord));
|
||||
Add(new cMenuEditIntItem( "LnbFrequLo", &data.LnbFrequLo));
|
||||
Add(new cMenuEditIntItem( "LnbFrequHi", &data.LnbFrequHi));
|
||||
Add(new cMenuEditIntItem( "SetSystemTime", &data.SetSystemTime));
|
||||
Add(new cMenuEditIntItem( "MarginStart", &data.MarginStart));
|
||||
Add(new cMenuEditIntItem( "MarginStop", &data.MarginStop));
|
||||
}
|
||||
|
||||
eOSState cMenuSetup::ProcessKey(eKeys Key)
|
||||
@ -1098,6 +1397,7 @@ eOSState cMenuSetup::ProcessKey(eKeys Key)
|
||||
if (state == osUnknown) {
|
||||
switch (Key) {
|
||||
case kOk: state = (Setup.PrimaryDVB != data.PrimaryDVB) ? osSwitchDvb : osBack;
|
||||
cDvbApi::PrimaryDvbApi->SetUseTSTime(data.SetSystemTime);
|
||||
Setup = data;
|
||||
Setup.Save();
|
||||
break;
|
||||
@ -1114,6 +1414,7 @@ eOSState cMenuSetup::ProcessKey(eKeys Key)
|
||||
cMenuMain::cMenuMain(bool Replaying)
|
||||
:cOsdMenu("Main")
|
||||
{
|
||||
Add(new cOsdItem("Schedule", osSchedule));
|
||||
Add(new cOsdItem("Channels", osChannels));
|
||||
Add(new cOsdItem("Timer", osTimer));
|
||||
Add(new cOsdItem("Recordings", osRecordings));
|
||||
@ -1137,6 +1438,7 @@ eOSState cMenuMain::ProcessKey(eKeys Key)
|
||||
eOSState state = cOsdMenu::ProcessKey(Key);
|
||||
|
||||
switch (state) {
|
||||
case osSchedule: return AddSubMenu(new cMenuSchedule);
|
||||
case osChannels: return AddSubMenu(new cMenuChannels);
|
||||
case osTimer: return AddSubMenu(new cMenuTimers);
|
||||
case osRecordings: return AddSubMenu(new cMenuRecordings);
|
||||
|
12
osd.c
12
osd.c
@ -4,7 +4,7 @@
|
||||
* See the main source file 'vdr.c' for copyright information and
|
||||
* how to reach the author.
|
||||
*
|
||||
* $Id: osd.c 1.9 2000/10/08 12:20:34 kls Exp $
|
||||
* $Id: osd.c 1.10 2000/10/28 09:33:47 kls Exp $
|
||||
*/
|
||||
|
||||
#include "osd.h"
|
||||
@ -24,7 +24,7 @@ cOsdItem::cOsdItem(eOSState State)
|
||||
bgColor = clrBackground;
|
||||
}
|
||||
|
||||
cOsdItem::cOsdItem(char *Text, eOSState State)
|
||||
cOsdItem::cOsdItem(const char *Text, eOSState State)
|
||||
{
|
||||
text = NULL;
|
||||
offset = -1;
|
||||
@ -74,7 +74,7 @@ eOSState cOsdItem::ProcessKey(eKeys Key)
|
||||
|
||||
// --- cOsdMenu --------------------------------------------------------------
|
||||
|
||||
cOsdMenu::cOsdMenu(char *Title, int c0, int c1, int c2, int c3, int c4)
|
||||
cOsdMenu::cOsdMenu(const char *Title, int c0, int c1, int c2, int c3, int c4)
|
||||
{
|
||||
visible = false;
|
||||
title = strdup(Title);
|
||||
@ -108,6 +108,12 @@ void cOsdMenu::SetStatus(const char *s)
|
||||
Interface->Status(status);
|
||||
}
|
||||
|
||||
void cOsdMenu::SetTitle(const char *Title, bool Copy)
|
||||
{
|
||||
delete title;
|
||||
title = Copy ? strdup(Title) : Title;
|
||||
}
|
||||
|
||||
void cOsdMenu::SetHelp(const char *Red, const char *Green, const char *Yellow, const char *Blue)
|
||||
{
|
||||
// strings are NOT copied - must be constants!!!
|
||||
|
10
osd.h
10
osd.h
@ -4,7 +4,7 @@
|
||||
* See the main source file 'vdr.c' for copyright information and
|
||||
* how to reach the author.
|
||||
*
|
||||
* $Id: osd.h 1.11 2000/09/10 09:50:38 kls Exp $
|
||||
* $Id: osd.h 1.12 2000/10/28 09:32:59 kls Exp $
|
||||
*/
|
||||
|
||||
#ifndef __OSD_H
|
||||
@ -19,6 +19,7 @@
|
||||
enum eOSState { osUnknown,
|
||||
osMenu,
|
||||
osContinue,
|
||||
osSchedule,
|
||||
osChannels,
|
||||
osTimer,
|
||||
osRecordings,
|
||||
@ -43,7 +44,7 @@ protected:
|
||||
eDvbColor fgColor, bgColor;
|
||||
public:
|
||||
cOsdItem(eOSState State = osUnknown);
|
||||
cOsdItem(char *Text, eOSState State = osUnknown);
|
||||
cOsdItem(const char *Text, eOSState State = osUnknown);
|
||||
virtual ~cOsdItem();
|
||||
bool HasUserColor(void) { return userColor; }
|
||||
void SetText(const char *Text, bool Copy = true);
|
||||
@ -66,7 +67,7 @@ public:
|
||||
|
||||
class cOsdMenu : public cOsdBase, public cList<cOsdItem> {
|
||||
private:
|
||||
char *title;
|
||||
const char *title;
|
||||
int cols[cInterface::MaxCols];
|
||||
int first, current, marked;
|
||||
cOsdMenu *subMenu;
|
||||
@ -83,10 +84,11 @@ protected:
|
||||
eOSState AddSubMenu(cOsdMenu *SubMenu);
|
||||
bool HasSubMenu(void) { return subMenu; }
|
||||
void SetStatus(const char *s);
|
||||
void SetTitle(const char *Title, bool Copy = true);
|
||||
void SetHelp(const char *Red, const char *Green = NULL, const char *Yellow = NULL, const char *Blue = NULL);
|
||||
virtual void Del(int Index);
|
||||
public:
|
||||
cOsdMenu(char *Title, int c0 = 0, int c1 = 0, int c2 = 0, int c3 = 0, int c4 = 0);
|
||||
cOsdMenu(const char *Title, int c0 = 0, int c1 = 0, int c2 = 0, int c3 = 0, int c4 = 0);
|
||||
virtual ~cOsdMenu();
|
||||
int Current(void) { return current; }
|
||||
void Add(cOsdItem *Item, bool Current = false);
|
||||
|
19
thread.c
19
thread.c
@ -4,7 +4,7 @@
|
||||
* See the main source file 'vdr.c' for copyright information and
|
||||
* how to reach the author.
|
||||
*
|
||||
* $Id: thread.c 1.2 2000/10/08 16:45:50 kls Exp $
|
||||
* $Id: thread.c 1.3 2000/10/28 15:26:02 kls Exp $
|
||||
*/
|
||||
|
||||
#include "thread.h"
|
||||
@ -88,16 +88,27 @@ void cThread::WakeUp(void)
|
||||
|
||||
cThreadLock::cThreadLock(cThread *Thread)
|
||||
{
|
||||
thread = Thread;
|
||||
locked = Thread->Lock();
|
||||
thread = NULL;
|
||||
locked = false;
|
||||
Lock(Thread);
|
||||
}
|
||||
|
||||
cThreadLock::~cThreadLock()
|
||||
{
|
||||
if (locked)
|
||||
if (thread && locked)
|
||||
thread->Unlock();
|
||||
}
|
||||
|
||||
bool cThreadLock::Lock(cThread *Thread)
|
||||
{
|
||||
if (Thread && !thread) {
|
||||
thread = Thread;
|
||||
locked = Thread->Lock();
|
||||
return locked;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool cThreadLock::Locked(void)
|
||||
{
|
||||
return locked;
|
||||
|
5
thread.h
5
thread.h
@ -4,7 +4,7 @@
|
||||
* See the main source file 'vdr.c' for copyright information and
|
||||
* how to reach the author.
|
||||
*
|
||||
* $Id: thread.h 1.1 2000/10/08 08:36:21 kls Exp $
|
||||
* $Id: thread.h 1.2 2000/10/28 15:08:09 kls Exp $
|
||||
*/
|
||||
|
||||
#ifndef __THREAD_H
|
||||
@ -47,8 +47,9 @@ private:
|
||||
cThread *thread;
|
||||
bool locked;
|
||||
public:
|
||||
cThreadLock(cThread *Thread);
|
||||
cThreadLock(cThread *Thread = NULL);
|
||||
~cThreadLock();
|
||||
bool Lock(cThread *Thread);
|
||||
bool Locked(void);
|
||||
};
|
||||
|
||||
|
15
tools.c
15
tools.c
@ -4,7 +4,7 @@
|
||||
* See the main source file 'vdr.c' for copyright information and
|
||||
* how to reach the author.
|
||||
*
|
||||
* $Id: tools.c 1.21 2000/10/07 18:02:24 kls Exp $
|
||||
* $Id: tools.c 1.22 2000/10/29 11:21:55 kls Exp $
|
||||
*/
|
||||
|
||||
#define _GNU_SOURCE
|
||||
@ -85,11 +85,16 @@ char *strreplace(char *s, char c1, char c2)
|
||||
return s;
|
||||
}
|
||||
|
||||
char *skipspace(char *s)
|
||||
char *skipspace(const char *s)
|
||||
{
|
||||
while (*s && isspace(*s))
|
||||
s++;
|
||||
return s;
|
||||
return (char *)s;
|
||||
}
|
||||
|
||||
bool isempty(const char *s)
|
||||
{
|
||||
return !(s && *skipspace(s));
|
||||
}
|
||||
|
||||
int time_ms(void)
|
||||
@ -520,7 +525,7 @@ void cListBase::Clear(void)
|
||||
objects = lastObject = NULL;
|
||||
}
|
||||
|
||||
cListObject *cListBase::Get(int Index)
|
||||
cListObject *cListBase::Get(int Index) const
|
||||
{
|
||||
if (Index < 0)
|
||||
return NULL;
|
||||
@ -530,7 +535,7 @@ cListObject *cListBase::Get(int Index)
|
||||
return object;
|
||||
}
|
||||
|
||||
int cListBase::Count(void)
|
||||
int cListBase::Count(void) const
|
||||
{
|
||||
int n = 0;
|
||||
cListObject *object = objects;
|
||||
|
19
tools.h
19
tools.h
@ -4,7 +4,7 @@
|
||||
* See the main source file 'vdr.c' for copyright information and
|
||||
* how to reach the author.
|
||||
*
|
||||
* $Id: tools.h 1.17 2000/10/07 18:00:21 kls Exp $
|
||||
* $Id: tools.h 1.18 2000/10/29 11:19:20 kls Exp $
|
||||
*/
|
||||
|
||||
#ifndef __TOOLS_H
|
||||
@ -40,7 +40,8 @@ void purge(int filedes);
|
||||
char *readline(FILE *f);
|
||||
char *strn0cpy(char *dest, const char *src, size_t n);
|
||||
char *strreplace(char *s, char c1, char c2);
|
||||
char *skipspace(char *s);
|
||||
char *skipspace(const char *s);
|
||||
bool isempty(const char *s);
|
||||
int time_ms(void);
|
||||
void delay_ms(int ms);
|
||||
bool isnumber(const char *s);
|
||||
@ -80,8 +81,8 @@ public:
|
||||
void Append(cListObject *Object);
|
||||
void Unlink(void);
|
||||
int Index(void);
|
||||
cListObject *Prev(void) { return prev; }
|
||||
cListObject *Next(void) { return next; }
|
||||
cListObject *Prev(void) const { return prev; }
|
||||
cListObject *Next(void) const { return next; }
|
||||
};
|
||||
|
||||
class cListBase {
|
||||
@ -95,15 +96,15 @@ public:
|
||||
virtual void Move(int From, int To);
|
||||
void Move(cListObject *From, cListObject *To);
|
||||
void Clear(void);
|
||||
cListObject *Get(int Index);
|
||||
int Count(void);
|
||||
cListObject *Get(int Index) const;
|
||||
int Count(void) const;
|
||||
};
|
||||
|
||||
template<class T> class cList : public cListBase {
|
||||
public:
|
||||
T *Get(int Index) { return (T *)cListBase::Get(Index); }
|
||||
T *First(void) { return (T *)objects; }
|
||||
T *Next(T *object) { return (T *)object->Next(); }
|
||||
T *Get(int Index) const { return (T *)cListBase::Get(Index); }
|
||||
T *First(void) const { return (T *)objects; }
|
||||
T *Next(const T *object) const { return (T *)object->Next(); }
|
||||
};
|
||||
|
||||
#endif //__TOOLS_H
|
||||
|
Loading…
Reference in New Issue
Block a user