mirror of
https://github.com/VDR4Arch/vdr.git
synced 2023-10-10 13:36:52 +02:00
Improved implementation of setup menus for plugins
This commit is contained in:
parent
0fac78954c
commit
51eb880da0
173
PLUGINS.html
173
PLUGINS.html
@ -15,7 +15,10 @@ VDR code (and all the problems of correlating various patches).
|
||||
This document describes the "outside" interface of the plugin system.
|
||||
It handles everything necessary for a plugin to get hooked into the core
|
||||
VDR program and present itself to the user.
|
||||
|
||||
<p>
|
||||
<!--X1.1.1--><table width=100%><tr><td bgcolor=red> </td><td width=100%>
|
||||
Important modifications introduced in version 1.1.1 are marked like this.
|
||||
<!--X1.1.1--></td></tr></table>
|
||||
<!--<p>TODO: Link to the document about VDR base classes to use when implementing actual functionality (yet to be written).-->
|
||||
|
||||
<hr><h2>Quick start</h2>
|
||||
@ -25,12 +28,12 @@ VDR program and present itself to the user.
|
||||
Actually you should read this entire document before starting to work with VDR plugins,
|
||||
but you probably want to see something happening right away <tt>;-)</tt>
|
||||
<p>
|
||||
So, for a quick demonstration of the plugin system, there is a demo plugin called
|
||||
So, for a quick demonstration of the plugin system, there is a sample plugin called
|
||||
"hello" that comes with the VDR source. To test drive this one, do the following:
|
||||
<ul>
|
||||
<li>change into the VDR source directory
|
||||
<li><b><tt>make</tt></b> the VDR program with your usual <tt>REMOTE=...</tt> (and maybe other) options
|
||||
<li>do <b><tt>make plugins</tt></b> to build the demo plugin
|
||||
<li>do <b><tt>make plugins</tt></b> to build the plugin
|
||||
<li>run VDR with <b><tt>vdr -V</tt></b> to see the version information
|
||||
<li>run VDR with <b><tt>vdr -h</tt></b> to see the command line options
|
||||
<li>run VDR with <b><tt>vdr -Phello</tt></b>
|
||||
@ -74,16 +77,14 @@ is used:
|
||||
|
||||
<p><table><tr><td bgcolor=#F0F0F0><pre><br>
|
||||
VDR/PLUGINS/src
|
||||
VDR/PLUGINS/src/demo
|
||||
VDR/PLUGINS/src/hello
|
||||
VDR/PLUGINS/lib
|
||||
VDR/PLUGINS/lib/libvdr-demo.so.1.1.0
|
||||
VDR/PLUGINS/lib/libvdr-hello.so.1.1.0
|
||||
</pre></td></tr></table><p>
|
||||
|
||||
The <tt>src</tt> directory contains one subdirectory for each plugin, which carries
|
||||
the name of that plugin (in the above example that would be <tt>demo</tt> and
|
||||
<tt>hello</tt>, respectively). What's inside the individual source directory of a
|
||||
the name of that plugin (in the above example that would be <tt>hello</tt>).
|
||||
What's inside the individual source directory of a
|
||||
plugin is entirely up to the author of that plugin. The only prerequisites are
|
||||
that there is a <tt>Makefile</tt> that provides the targets <tt>all</tt> and
|
||||
<tt>clean</tt>, and that a call to <tt>make all</tt> actually produces a dynamically
|
||||
@ -93,7 +94,7 @@ The <tt>lib</tt> directory contains the dynamically loadable libraries of all
|
||||
available plugins. Note that the names of these files are created by concatenating
|
||||
<p>
|
||||
<table border=2>
|
||||
<tr><td align=center><b><tt>libvdr-</tt></b></td><td align=center><b><tt>demo</tt></b></td><td align=center><b><tt>.so.</tt></b></td><td align=center><b><tt>1.1.0</tt></b></td></tr>
|
||||
<tr><td align=center><b><tt>libvdr-</tt></b></td><td align=center><b><tt>hello</tt></b></td><td align=center><b><tt>.so.</tt></b></td><td align=center><b><tt>1.1.0</tt></b></td></tr>
|
||||
<tr><td align=center><font size=-1>VDR plugin<br>library prefix</font></td><td align=center><font size=-1>name of<br>the plugin</font></td><td align=center><font size=-1>shared object<br>indicator</font></td><td align=center><font size=-1>VDR version number<br>this plugin was<br>compiled for</font></td></tr>
|
||||
</table>
|
||||
<p>
|
||||
@ -109,25 +110,25 @@ each of these directories.
|
||||
If you download a plugin <a href="#Building the distribution package">package</a>
|
||||
from the web, it will typically have a name like
|
||||
<p>
|
||||
<tt>vdr-demo-0.0.1.tgz</tt>
|
||||
<tt>vdr-hello-0.0.1.tgz</tt>
|
||||
<p>
|
||||
and will unpack into a directory named
|
||||
<p>
|
||||
<tt>vdr-demo-0.0.1</tt>
|
||||
<tt>vdr-hello-0.0.1</tt>
|
||||
<p>
|
||||
To use the <tt>plugins</tt> and <tt>plugins-clean</tt> targets from the VDR <tt>Makefile</tt>
|
||||
you need to unpack such an archive into the <tt>VDR/PLUGINS/src</tt> directory and
|
||||
create a symbolic link with the basic plugin name, as in
|
||||
|
||||
<p><table><tr><td bgcolor=#F0F0F0><pre><br>
|
||||
ln -s vdr-demo-0.0.1 demo
|
||||
ln -s vdr-hello-0.0.1 hello
|
||||
</pre></td></tr></table><p>
|
||||
|
||||
Since the VDR <tt>Makefile</tt> only searches for directories with names consisting
|
||||
of only lowercase characters and digits, it will only follow the symbolic links, which
|
||||
should lead to the current version of the plugin you want to use. This way you can
|
||||
have several different versions of a plugin source (like <tt>vdr-demo-0.0.1</tt> and
|
||||
<tt>vdr-demo-0.0.2</tt>) and define which one to actually use through the symbolic link.
|
||||
have several different versions of a plugin source (like <tt>vdr-hello-0.0.1</tt> and
|
||||
<tt>vdr-hello-0.0.2</tt>) and define which one to actually use through the symbolic link.
|
||||
|
||||
<a name="Initializing a new plugin directory"><hr><h2>Initializing a new plugin directory</h2>
|
||||
|
||||
@ -174,7 +175,7 @@ If your plugin shall not be accessible through VDR's main menu, simply remove
|
||||
At the end of the plugin's source file you will find a line that looks like this:
|
||||
|
||||
<p><table><tr><td bgcolor=#F0F0F0><pre><br>
|
||||
VDRPLUGINCREATOR(cPluginDemo);
|
||||
VDRPLUGINCREATOR(cPluginHello);
|
||||
</pre></td></tr></table><p>
|
||||
|
||||
This is the "magic" hook that allows VDR to actually load the plugin into
|
||||
@ -230,9 +231,7 @@ Here's an example:
|
||||
<p><table><tr><td bgcolor=#F0F0F0><pre><br>
|
||||
static const char *VERSION = "0.0.1";
|
||||
|
||||
...
|
||||
|
||||
const char *cPluginDemo::Version(void)
|
||||
const char *cPluginHello::Version(void)
|
||||
{
|
||||
return VERSION;
|
||||
}
|
||||
@ -265,15 +264,20 @@ In order to tell the user what exactly a plugin does, it must implement the func
|
||||
virtual const char *Description(void) = 0;
|
||||
</pre></td></tr></table><p>
|
||||
|
||||
which returns a short, one line description of the plugin's purpose.
|
||||
which returns a short, one line description of the plugin's purpose:
|
||||
|
||||
<p><table><tr><td bgcolor=#F0F0F0><pre><br>
|
||||
static const char *DESCRIPTION = "A friendly greeting";
|
||||
|
||||
virtual const char *Description(void)
|
||||
{
|
||||
return "A simple demo plugin";
|
||||
return tr(DESCRIPTION);
|
||||
}
|
||||
</pre></td></tr></table><p>
|
||||
|
||||
Note the <tt>tr()</tt> around the <tt>DESCRIPTION</tt>, which allows the description
|
||||
to be <a href="#Internationalization">internationalized</a>.
|
||||
|
||||
<hr><h2>Command line arguments</h2>
|
||||
|
||||
<center><i><b>Taking orders</b></i></center><p>
|
||||
@ -300,20 +304,21 @@ will survive the entire lifetime of the plugin, so it is safe to store pointers
|
||||
these values inside the plugin. Here's an example:
|
||||
|
||||
<p><table><tr><td bgcolor=#F0F0F0><pre><br>
|
||||
bool cPluginDemo::ProcessArgs(int argc, char *argv[])
|
||||
{
|
||||
bool cPluginHello::ProcessArgs(int argc, char *argv[])
|
||||
{
|
||||
// Implement command line argument processing here if applicable.
|
||||
static struct option long_options[] = {
|
||||
{ "aaa", required_argument, NULL, 'a' },
|
||||
{ "bbb", no_argument, NULL, 'b' },
|
||||
{ NULL }
|
||||
};
|
||||
|
||||
{ "aaa", required_argument, NULL, 'a' },
|
||||
{ "bbb", no_argument, NULL, 'b' },
|
||||
{ NULL }
|
||||
};
|
||||
|
||||
int c;
|
||||
while ((c = getopt_long(argc, argv, "a:b", long_options, NULL)) != -1) {
|
||||
switch (c) {
|
||||
case 'a': fprintf(stderr, "option -a = %s\n", optarg);
|
||||
case 'a': option_a = optarg;
|
||||
break;
|
||||
case 'b': fprintf(stderr, "option -b\n");
|
||||
case 'b': option_b = true;
|
||||
break;
|
||||
default: return false;
|
||||
}
|
||||
@ -342,8 +347,9 @@ The returned string should contain the command line help for this plugin, format
|
||||
in the same way as done by VDR itself:
|
||||
|
||||
<p><table><tr><td bgcolor=#F0F0F0><pre><br>
|
||||
const char *cPluginDemo::CommandLineHelp(void)
|
||||
const char *cPluginHello::CommandLineHelp(void)
|
||||
{
|
||||
// Return a string that describes all known command line options.
|
||||
return " -a ABC, --aaa=ABC do something nice with ABC\n"
|
||||
" -b, --bbb activate 'plan B'\n";
|
||||
}
|
||||
@ -392,9 +398,11 @@ this plugin will not have an item in the main menu. Here's an example of a
|
||||
plugin that will have a main menu item:
|
||||
|
||||
<p><table><tr><td bgcolor=#F0F0F0><pre><br>
|
||||
const char *cPluginDemo::MainMenuEntry(void)
|
||||
static const char *MAINMENUENTRY = "Hello";
|
||||
|
||||
const char *cPluginHello::MainMenuEntry(void)
|
||||
{
|
||||
return "Demo";
|
||||
return tr(MAINMENUENTRY);
|
||||
}
|
||||
</pre></td></tr></table><p>
|
||||
|
||||
@ -440,7 +448,7 @@ virtual cMenuSetupPage *SetupMenu(void);
|
||||
virtual bool SetupParse(const char *Name, const char *Value);
|
||||
</pre></td></tr></table><p>
|
||||
|
||||
The <tt>SetupMenu()</tt> function shall return the plugin's "Setup" menu
|
||||
The <tt>SetupMenu()</tt> function shall return the plugin's <a href="#The Setup menu"><i>Setup</i> menu</a>
|
||||
page, where the user can adjust all the parameters known to this plugin.
|
||||
<p>
|
||||
<tt>SetupParse()</tt> will be called for each parameter the plugin has
|
||||
@ -448,13 +456,30 @@ previously stored in the global setup data (see below). It shall return
|
||||
<i>true</i> if the parameter was parsed correctly, <i>false</i> in case of
|
||||
an error. If <i>false</i> is returned, an error message will be written to
|
||||
the log file (and program execution will continue).
|
||||
<!--X1.1.1--><table width=100%><tr><td bgcolor=red> </td><td width=100%>
|
||||
A possible implementation of <tt>SetupParse()</tt> could look like this:
|
||||
|
||||
<p><table><tr><td bgcolor=#F0F0F0><pre><br>
|
||||
bool cPluginHello::SetupParse(const char *Name, const char *Value)
|
||||
{
|
||||
// Parse your own setup parameters and store their values.
|
||||
if (!strcasecmp(Name, "GreetingTime")) GreetingTime = atoi(Value);
|
||||
else if (!strcasecmp(Name, "UseAlternateGreeting")) UseAlternateGreeting = atoi(Value);
|
||||
else
|
||||
return false;
|
||||
return true;
|
||||
</pre></td></tr></table><p>
|
||||
|
||||
It is important to make sure that the parameter names are exactly the same as
|
||||
used in the <a href="#The Setup menu"><i>Setup</i> menu</a>'s <tt>Store()</tt> function.
|
||||
<!--X1.1.1--></td></tr></table>
|
||||
<p>
|
||||
The plugin's setup parameters are stored in the same file as VDR's parameters.
|
||||
In order to allow each plugin (and VDR itself) to have its own set of parameters,
|
||||
the <tt>Name</tt> of each parameter will be preceeded with the plugin's
|
||||
name, as in
|
||||
<p>
|
||||
<tt>demo.SomeParameter = 123</tt>
|
||||
<tt>hello.GreetingTime = 3</tt>
|
||||
<p>
|
||||
The prefix will be handled by the core VDR setup code, so the individual
|
||||
plugins need not worry about this.
|
||||
@ -465,8 +490,8 @@ To store its values in the global setup, a plugin has to call the function
|
||||
void SetupStore(const char *Name, <i>type</i> Value);
|
||||
</pre></td></tr></table><p>
|
||||
|
||||
where <tt>Name</tt> is the name of the parameter (<tt>"SomeParameter"</tt> in the above
|
||||
example, without the prefix <tt>"demo."</tt>) and <tt>Value</tt> is a simple data type (like
|
||||
where <tt>Name</tt> is the name of the parameter (<tt>"GreetingTime"</tt> in the above
|
||||
example, without the prefix <tt>"hello."</tt>) and <tt>Value</tt> is a simple data type (like
|
||||
<tt>char *</tt>, <tt>int</tt> etc).
|
||||
Note that this is not a function that the individual plugin class needs to implement!
|
||||
<tt>SetupStore()</tt> is a non-virtual member function of the <tt>cPlugin</tt> class.
|
||||
@ -474,7 +499,7 @@ Note that this is not a function that the individual plugin class needs to imple
|
||||
To remove a parameter from the setup data, call <tt>SetupStore()</tt> with the appropriate
|
||||
name and without any value, as in
|
||||
<p>
|
||||
<tt>SetupStore("SomeParameter");</tt>
|
||||
<tt>SetupStore("GreetingTime");</tt>
|
||||
<p>
|
||||
The VDR menu "Setup/Plugins" will list all loaded plugins with their name,
|
||||
version number and description. Selecting an item in this list will bring up
|
||||
@ -486,6 +511,66 @@ needs setup parameters that are not directly user adjustable. It can use
|
||||
<tt>SetupStore()</tt> and <tt>SetupParse()</tt> without presenting these
|
||||
parameters to the user.
|
||||
|
||||
<!--X1.1.1--><table width=100%><tr><td bgcolor=red> </td><td width=100%>
|
||||
<a name="The Setup menu"><hr><h2>The Setup menu</h2>
|
||||
|
||||
<center><i><b>Have it your way!</b></i></center><p>
|
||||
|
||||
To implement a <i>Setup</i> menu, a plugin needs to derive a class from
|
||||
<tt>cMenuSetupPage</tt> and implement its constructor and the pure virtual
|
||||
<tt>Store()</tt> member function:
|
||||
|
||||
<p><table><tr><td bgcolor=#F0F0F0><pre><br>
|
||||
int GreetingTime = 3;
|
||||
int UseAlternateGreeting = false;
|
||||
|
||||
class cMenuSetupHello : public cMenuSetupPage {
|
||||
private:
|
||||
int newGreetingTime;
|
||||
int newUseAlternateGreeting;
|
||||
protected:
|
||||
virtual void Store(void);
|
||||
public:
|
||||
cMenuSetupHello(void);
|
||||
};
|
||||
|
||||
cMenuSetupHello::cMenuSetupHello(void)
|
||||
{
|
||||
newGreetingTime = GreetingTime;
|
||||
newUseAlternateGreeting = UseAlternateGreeting;
|
||||
Add(new cMenuEditIntItem( tr("Greeting time (s)"), &newGreetingTime));
|
||||
Add(new cMenuEditBoolItem(tr("Use alternate greeting"), &newUseAlternateGreeting));
|
||||
}
|
||||
|
||||
void cMenuSetupHello::Store(void)
|
||||
{
|
||||
SetupStore("GreetingTime", GreetingTime = newGreetingTime);
|
||||
SetupStore("UseAlternateGreeting", UseAlternateGreeting = newUseAlternateGreeting);
|
||||
}
|
||||
</pre></td></tr></table><p>
|
||||
|
||||
In this example we have two global setup parameters (<tt>GreetingTime</tt> and <tt>UseAlternateGreeting</tt>).
|
||||
The constructor initializes two private members with the values of these parameters, so
|
||||
that the <i>Setup</i> menu can work with temporary copies (in order to discard any changes
|
||||
if the user doesn't confirm them by pressing the "Ok" button).
|
||||
After this the constructor adds the appropriate menu items, using internationalized texts
|
||||
and the addresses of the temporary variables. That's all there is to inizialize a <i>Setup</i>
|
||||
menu - the rest will be done by the core VDR code.
|
||||
<p>
|
||||
Once the user has pressed the "Ok" button to confirm the changes, the <tt>Store()</tt> function will
|
||||
be called, in which all setup parameters must be actually stored in VDR's global setup data.
|
||||
This is done by calling the <tt>SetupStore()</tt> function for each of the parameters.
|
||||
The <i>Name</i> string given here will be used to identify the parameter in VDR's
|
||||
<tt>setup.conf</tt> file, and will be automatically prepended with the plugin's name.
|
||||
<p>
|
||||
Note that in this small example the new values of the parameters are copied into the
|
||||
global variables within each <tt>SetupStore()</tt> call. This is not mandatory, however.
|
||||
You can first assign the temporary values to the global variables and then do the
|
||||
<tt>SetupStore()</tt> calls, or you can define a class or struct that contains all
|
||||
your setup parameters and use that one to copy all parameters with one single statement
|
||||
(like VDR does with its cSetup class).
|
||||
<!--X1.1.1--></td></tr></table>
|
||||
|
||||
<a name="Internationalization"><hr><h2>Internationalization</h2>
|
||||
|
||||
<center><i><b>Welcome to Babylon!</b></i></center><p>
|
||||
@ -519,7 +604,7 @@ const tI18nPhrase Phrases[] = {
|
||||
{ NULL }
|
||||
};
|
||||
|
||||
void cPluginDemo::Start(void)
|
||||
void cPluginHello::Start(void)
|
||||
{
|
||||
RegisterI18n(Phrases);
|
||||
}
|
||||
@ -557,20 +642,20 @@ core VDR code.
|
||||
Plugins are loaded into VDR using the command line option <b><tt>-P</tt></b>, as in
|
||||
|
||||
<p><table><tr><td bgcolor=#F0F0F0><pre><br>
|
||||
vdr -Pdemo
|
||||
vdr -Phello
|
||||
</pre></td></tr></table><p>
|
||||
|
||||
If the plugin accepts command line options, they are given as part of the argument
|
||||
to the <b><tt>-P</tt></b> option, which then has to be enclosed in quotes:
|
||||
|
||||
<p><table><tr><td bgcolor=#F0F0F0><pre><br>
|
||||
vdr -P"demo -a abc -b"
|
||||
vdr -P"hello -a abc -b"
|
||||
</pre></td></tr></table><p>
|
||||
|
||||
Any number of plugins can be loaded this way, each with its own <b><tt>-P</tt></b> option:
|
||||
|
||||
<p><table><tr><td bgcolor=#F0F0F0><pre><br>
|
||||
vdr -P"demo -a abc -b" -Pdvd -Pmp3
|
||||
vdr -P"hello -a abc -b" -Pdvd -Pmp3
|
||||
</pre></td></tr></table><p>
|
||||
|
||||
If you are not starting VDR from the VDR source directory (and thus your plugins
|
||||
@ -578,7 +663,7 @@ cannot be found at their default location) you need to tell VDR the location of
|
||||
the plugins through the <b><tt>-L</tt></b> option:
|
||||
|
||||
<p><table><tr><td bgcolor=#F0F0F0><pre><br>
|
||||
vdr -L/usr/lib/vdr -Pdemo
|
||||
vdr -L/usr/lib/vdr -Phello
|
||||
</pre></td></tr></table><p>
|
||||
|
||||
There can be any number of <b><tt>-L</tt></b> options, and each of them will apply to the
|
||||
@ -603,17 +688,17 @@ provides the target <tt>package</tt>, which does this for you.
|
||||
Simply change into your source directory and execute <tt>make package</tt>:
|
||||
|
||||
<p><table><tr><td bgcolor=#F0F0F0><pre><br>
|
||||
cd VDR/PLUGINS/src/demo
|
||||
cd VDR/PLUGINS/src/hello
|
||||
make package
|
||||
</pre></td></tr></table><p>
|
||||
|
||||
After this you should find a file named like
|
||||
|
||||
<p><table><tr><td bgcolor=#F0F0F0><pre><br>
|
||||
vdr-demo-0.0.1.tgz
|
||||
vdr-hello-0.0.1.tgz
|
||||
</pre></td></tr></table><p>
|
||||
|
||||
in your source directory, where <tt>demo</tt> will be replaced with your actual
|
||||
in your source directory, where <tt>hello</tt> will be replaced with your actual
|
||||
plugin's name, and <tt>0.0.1</tt> will be your plugin's current version number.
|
||||
|
||||
</body>
|
||||
|
11
config.c
11
config.c
@ -4,7 +4,7 @@
|
||||
* See the main source file 'vdr.c' for copyright information and
|
||||
* how to reach the author.
|
||||
*
|
||||
* $Id: config.c 1.99 2002/05/05 12:00:00 kls Exp $
|
||||
* $Id: config.c 1.100 2002/05/11 12:05:22 kls Exp $
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
@ -1073,14 +1073,19 @@ bool cSetup::Load(const char *FileName)
|
||||
if (cConfig<cSetupLine>::Load(FileName, true)) {
|
||||
bool result = true;
|
||||
for (cSetupLine *l = First(); l; l = Next(l)) {
|
||||
bool error = false;
|
||||
if (l->Plugin()) {
|
||||
cPlugin *p = cPluginManager::GetPlugin(l->Plugin());
|
||||
if (p && !p->SetupParse(l->Name(), l->Value()))
|
||||
result = false;
|
||||
error = true;
|
||||
}
|
||||
else {
|
||||
if (!Parse(l->Name(), l->Value()))
|
||||
result = false;
|
||||
error = true;
|
||||
}
|
||||
if (error) {
|
||||
esyslog(LOG_ERR, "ERROR: unknown config parameter: %s%s%s = %s", l->Plugin() ? l->Plugin() : "", l->Plugin() ? "." : "", l->Name(), l->Value());
|
||||
result = false;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
|
15
i18n.c
15
i18n.c
@ -4,7 +4,7 @@
|
||||
* See the main source file 'vdr.c' for copyright information and
|
||||
* how to reach the author.
|
||||
*
|
||||
* $Id: i18n.c 1.87 2002/05/09 13:40:51 kls Exp $
|
||||
* $Id: i18n.c 1.88 2002/05/11 11:43:38 kls Exp $
|
||||
*
|
||||
* Translations provided by:
|
||||
*
|
||||
@ -1270,6 +1270,19 @@ const tI18nPhrase Phrases[] = {
|
||||
"Plugins",
|
||||
"Plugins",
|
||||
},
|
||||
{ "Plugin",
|
||||
"Plugin",
|
||||
"Plugin",
|
||||
"Plugin",
|
||||
"Plugin",
|
||||
"Plugin",
|
||||
"Plugin",
|
||||
"Plugin",
|
||||
"Plugin",
|
||||
"Plugin",
|
||||
"Plugin",
|
||||
"Plugin",
|
||||
},
|
||||
{ "Restart",
|
||||
"Neustart",
|
||||
"Ponoven zagon",
|
||||
|
192
menu.c
192
menu.c
@ -4,7 +4,7 @@
|
||||
* See the main source file 'vdr.c' for copyright information and
|
||||
* how to reach the author.
|
||||
*
|
||||
* $Id: menu.c 1.190 2002/05/09 10:13:47 kls Exp $
|
||||
* $Id: menu.c 1.191 2002/05/11 11:16:32 kls Exp $
|
||||
*/
|
||||
|
||||
#include "menu.h"
|
||||
@ -1525,19 +1525,41 @@ eOSState cMenuRecordings::ProcessKey(eKeys Key)
|
||||
return state;
|
||||
}
|
||||
|
||||
// --- cMenuSetupBase --------------------------------------------------------
|
||||
|
||||
class cMenuSetupBase : public cMenuSetupPage {
|
||||
protected:
|
||||
cSetup data;
|
||||
virtual void Store(void);
|
||||
public:
|
||||
cMenuSetupBase(void);
|
||||
};
|
||||
|
||||
cMenuSetupBase::cMenuSetupBase(void)
|
||||
{
|
||||
data = Setup;
|
||||
}
|
||||
|
||||
void cMenuSetupBase::Store(void)
|
||||
{
|
||||
Setup = data;
|
||||
Setup.Save();
|
||||
}
|
||||
|
||||
// --- cMenuSetupOSD ---------------------------------------------------------
|
||||
|
||||
class cMenuSetupOSD : public cMenuSetupPage {
|
||||
class cMenuSetupOSD : public cMenuSetupBase {
|
||||
private:
|
||||
virtual void Set(void);
|
||||
public:
|
||||
cMenuSetupOSD(void) { Set(); }
|
||||
virtual eOSState ProcessKey(eKeys Key);
|
||||
};
|
||||
|
||||
void cMenuSetupOSD::Set(void)
|
||||
{
|
||||
Clear();
|
||||
SetupTitle("OSD");
|
||||
SetSection(tr("OSD"));
|
||||
Add(new cMenuEditStraItem(tr("Setup.OSD$Language"), &data.OSDLanguage, I18nNumLanguages, I18nLanguages()));
|
||||
Add(new cMenuEditIntItem( tr("Setup.OSD$Width"), &data.OSDwidth, MINOSDWIDTH, MAXOSDWIDTH));
|
||||
Add(new cMenuEditIntItem( tr("Setup.OSD$Height"), &data.OSDheight, MINOSDHEIGHT, MAXOSDHEIGHT));
|
||||
@ -1549,19 +1571,31 @@ void cMenuSetupOSD::Set(void)
|
||||
Add(new cMenuEditBoolItem(tr("Setup.OSD$Recording directories"), &data.RecordingDirs));
|
||||
}
|
||||
|
||||
eOSState cMenuSetupOSD::ProcessKey(eKeys Key)
|
||||
{
|
||||
int osdLanguage = data.OSDLanguage;
|
||||
eOSState state = cMenuSetupBase::ProcessKey(Key);
|
||||
|
||||
if (data.OSDLanguage != osdLanguage) {
|
||||
int OriginalOSDLanguage = Setup.OSDLanguage;
|
||||
Setup.OSDLanguage = data.OSDLanguage;
|
||||
Set();
|
||||
Display();
|
||||
Setup.OSDLanguage = OriginalOSDLanguage;
|
||||
}
|
||||
return state;
|
||||
}
|
||||
|
||||
// --- cMenuSetupEPG ---------------------------------------------------------
|
||||
|
||||
class cMenuSetupEPG : public cMenuSetupPage {
|
||||
private:
|
||||
virtual void Set(void);
|
||||
class cMenuSetupEPG : public cMenuSetupBase {
|
||||
public:
|
||||
cMenuSetupEPG(void) { Set(); }
|
||||
cMenuSetupEPG(void);
|
||||
};
|
||||
|
||||
void cMenuSetupEPG::Set(void)
|
||||
cMenuSetupEPG::cMenuSetupEPG(void)
|
||||
{
|
||||
Clear();
|
||||
SetupTitle("EPG");
|
||||
SetSection(tr("EPG"));
|
||||
Add(new cMenuEditIntItem( tr("Setup.EPG$EPG scan timeout (h)"), &data.EPGScanTimeout));
|
||||
Add(new cMenuEditIntItem( tr("Setup.EPG$EPG bugfix level"), &data.EPGBugfixLevel, 0, MAXEPGBUGFIXLEVEL));
|
||||
Add(new cMenuEditBoolItem(tr("Setup.EPG$Set system time"), &data.SetSystemTime));
|
||||
@ -1570,34 +1604,43 @@ void cMenuSetupEPG::Set(void)
|
||||
|
||||
// --- cMenuSetupDVB ---------------------------------------------------------
|
||||
|
||||
class cMenuSetupDVB : public cMenuSetupPage {
|
||||
private:
|
||||
virtual void Set(void);
|
||||
class cMenuSetupDVB : public cMenuSetupBase {
|
||||
public:
|
||||
cMenuSetupDVB(void) { Set(); }
|
||||
cMenuSetupDVB(void);
|
||||
virtual eOSState ProcessKey(eKeys Key);
|
||||
};
|
||||
|
||||
void cMenuSetupDVB::Set(void)
|
||||
cMenuSetupDVB::cMenuSetupDVB(void)
|
||||
{
|
||||
Clear();
|
||||
SetupTitle("DVB");
|
||||
SetSection(tr("DVB"));
|
||||
Add(new cMenuEditIntItem( tr("Setup.DVB$Primary DVB interface"), &data.PrimaryDVB, 1, cDvbApi::NumDvbApis));
|
||||
Add(new cMenuEditBoolItem(tr("Setup.DVB$Video format"), &data.VideoFormat, "4:3", "16:9"));
|
||||
}
|
||||
|
||||
eOSState cMenuSetupDVB::ProcessKey(eKeys Key)
|
||||
{
|
||||
int oldPrimaryDVB = Setup.PrimaryDVB;
|
||||
eOSState state = cMenuSetupBase::ProcessKey(Key);
|
||||
|
||||
if (state == osBack && Key == kOk) {
|
||||
if (Setup.PrimaryDVB != oldPrimaryDVB) {
|
||||
state = osSwitchDvb;
|
||||
cDvbApi::PrimaryDvbApi->SetVideoFormat(Setup.VideoFormat ? VIDEO_FORMAT_16_9 : VIDEO_FORMAT_4_3);
|
||||
}
|
||||
}
|
||||
return state;
|
||||
}
|
||||
|
||||
// --- cMenuSetupLNB ---------------------------------------------------------
|
||||
|
||||
class cMenuSetupLNB : public cMenuSetupPage {
|
||||
private:
|
||||
virtual void Set(void);
|
||||
class cMenuSetupLNB : public cMenuSetupBase {
|
||||
public:
|
||||
cMenuSetupLNB(void) { Set(); }
|
||||
cMenuSetupLNB(void);
|
||||
};
|
||||
|
||||
void cMenuSetupLNB::Set(void)
|
||||
cMenuSetupLNB::cMenuSetupLNB(void)
|
||||
{
|
||||
Clear();
|
||||
SetupTitle("LNB");
|
||||
SetSection(tr("LNB"));
|
||||
Add(new cMenuEditIntItem( tr("Setup.LNB$SLOF (MHz)"), &data.LnbSLOF));
|
||||
Add(new cMenuEditIntItem( tr("Setup.LNB$Low LNB frequency (MHz)"), &data.LnbFrequLo));
|
||||
Add(new cMenuEditIntItem( tr("Setup.LNB$High LNB frequency (MHz)"), &data.LnbFrequHi));
|
||||
@ -1606,17 +1649,15 @@ void cMenuSetupLNB::Set(void)
|
||||
|
||||
// --- cMenuSetupCICAM -------------------------------------------------------
|
||||
|
||||
class cMenuSetupCICAM : public cMenuSetupPage {
|
||||
private:
|
||||
virtual void Set(void);
|
||||
class cMenuSetupCICAM : public cMenuSetupBase {
|
||||
public:
|
||||
cMenuSetupCICAM(void) { Set(); }
|
||||
cMenuSetupCICAM(void);
|
||||
virtual eOSState ProcessKey(eKeys Key);
|
||||
};
|
||||
|
||||
void cMenuSetupCICAM::Set(void)
|
||||
cMenuSetupCICAM::cMenuSetupCICAM(void)
|
||||
{
|
||||
Clear();
|
||||
SetupTitle("CICAM");
|
||||
SetSection(tr("CICAM"));
|
||||
for (int d = 0; d < cDvbApi::NumDvbApis; d++) {
|
||||
for (int i = 0; i < 2; i++) {
|
||||
char buffer[32];
|
||||
@ -1626,19 +1667,25 @@ void cMenuSetupCICAM::Set(void)
|
||||
}
|
||||
}
|
||||
|
||||
eOSState cMenuSetupCICAM::ProcessKey(eKeys Key)
|
||||
{
|
||||
eOSState state = cMenuSetupBase::ProcessKey(Key);
|
||||
|
||||
if (state == osBack && Key == kOk)
|
||||
cDvbApi::SetCaCaps();
|
||||
return state;
|
||||
}
|
||||
|
||||
// --- cMenuSetupRecord ------------------------------------------------------
|
||||
|
||||
class cMenuSetupRecord : public cMenuSetupPage {
|
||||
private:
|
||||
virtual void Set(void);
|
||||
class cMenuSetupRecord : public cMenuSetupBase {
|
||||
public:
|
||||
cMenuSetupRecord(void) { Set(); }
|
||||
cMenuSetupRecord(void);
|
||||
};
|
||||
|
||||
void cMenuSetupRecord::Set(void)
|
||||
cMenuSetupRecord::cMenuSetupRecord(void)
|
||||
{
|
||||
Clear();
|
||||
SetupTitle("Recording");
|
||||
SetSection(tr("Recording"));
|
||||
Add(new cMenuEditIntItem( tr("Setup.Recording$Margin at start (min)"), &data.MarginStart));
|
||||
Add(new cMenuEditIntItem( tr("Setup.Recording$Margin at stop (min)"), &data.MarginStop));
|
||||
Add(new cMenuEditIntItem( tr("Setup.Recording$Primary limit"), &data.PrimaryLimit, 0, MAXPRIORITY));
|
||||
@ -1655,34 +1702,28 @@ void cMenuSetupRecord::Set(void)
|
||||
|
||||
// --- cMenuSetupReplay ------------------------------------------------------
|
||||
|
||||
class cMenuSetupReplay : public cMenuSetupPage {
|
||||
private:
|
||||
virtual void Set(void);
|
||||
class cMenuSetupReplay : public cMenuSetupBase {
|
||||
public:
|
||||
cMenuSetupReplay(void) { Set(); }
|
||||
cMenuSetupReplay(void);
|
||||
};
|
||||
|
||||
void cMenuSetupReplay::Set(void)
|
||||
cMenuSetupReplay::cMenuSetupReplay(void)
|
||||
{
|
||||
Clear();
|
||||
SetupTitle("Replay");
|
||||
SetSection(tr("Replay"));
|
||||
Add(new cMenuEditBoolItem(tr("Setup.Replay$Multi speed mode"), &data.MultiSpeedMode));
|
||||
Add(new cMenuEditBoolItem(tr("Setup.Replay$Show replay mode"), &data.ShowReplayMode));
|
||||
}
|
||||
|
||||
// --- cMenuSetupMisc --------------------------------------------------------
|
||||
|
||||
class cMenuSetupMisc : public cMenuSetupPage {
|
||||
private:
|
||||
virtual void Set(void);
|
||||
class cMenuSetupMisc : public cMenuSetupBase {
|
||||
public:
|
||||
cMenuSetupMisc(void) { Set(); }
|
||||
cMenuSetupMisc(void);
|
||||
};
|
||||
|
||||
void cMenuSetupMisc::Set(void)
|
||||
cMenuSetupMisc::cMenuSetupMisc(void)
|
||||
{
|
||||
Clear();
|
||||
SetupTitle("Miscellaneous");
|
||||
SetSection(tr("Miscellaneous"));
|
||||
Add(new cMenuEditIntItem( tr("Setup.Miscellaneous$Min. event timeout (min)"), &data.MinEventTimeout));
|
||||
Add(new cMenuEditIntItem( tr("Setup.Miscellaneous$Min. user inactivity (min)"), &data.MinUserInactivity));
|
||||
Add(new cMenuEditIntItem( tr("Setup.Miscellaneous$SVDRP timeout (s)"), &data.SVDRPTimeout));
|
||||
@ -1706,18 +1747,15 @@ cMenuSetupPluginItem::cMenuSetupPluginItem(const char *Name, int Index)
|
||||
|
||||
// --- cMenuSetupPlugins -----------------------------------------------------
|
||||
|
||||
class cMenuSetupPlugins : public cMenuSetupPage {
|
||||
private:
|
||||
virtual void Set(void);
|
||||
class cMenuSetupPlugins : public cMenuSetupBase {
|
||||
public:
|
||||
cMenuSetupPlugins(void) { Set(); }
|
||||
cMenuSetupPlugins(void);
|
||||
virtual eOSState ProcessKey(eKeys Key);
|
||||
};
|
||||
|
||||
void cMenuSetupPlugins::Set(void)
|
||||
cMenuSetupPlugins::cMenuSetupPlugins(void)
|
||||
{
|
||||
Clear();
|
||||
SetupTitle("Plugins");
|
||||
SetSection(tr("Plugins"));
|
||||
SetHasHotkeys();
|
||||
for (int i = 0; ; i++) {
|
||||
cPlugin *p = cPluginManager::GetPlugin(i);
|
||||
@ -1734,25 +1772,25 @@ void cMenuSetupPlugins::Set(void)
|
||||
|
||||
eOSState cMenuSetupPlugins::ProcessKey(eKeys Key)
|
||||
{
|
||||
eOSState state = cOsdMenu::ProcessKey(Key); // not cMenuSetupPage::ProcessKey()!
|
||||
eOSState state = HasSubMenu() ? cMenuSetupBase::ProcessKey(Key) : cOsdMenu::ProcessKey(Key);
|
||||
|
||||
if (state == osUnknown) {
|
||||
switch (Key) {
|
||||
case kOk: {
|
||||
cMenuSetupPluginItem *item = (cMenuSetupPluginItem *)Get(Current());
|
||||
if (item) {
|
||||
cPlugin *p = cPluginManager::GetPlugin(item->PluginIndex());
|
||||
if (p) {
|
||||
cOsdMenu *menu = p->SetupMenu();
|
||||
if (menu)
|
||||
return AddSubMenu(menu);
|
||||
Interface->Info(tr("This plugin has no setup parameters!"));
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
default: break;
|
||||
}
|
||||
if (Key == kOk) {
|
||||
if (state == osUnknown) {
|
||||
cMenuSetupPluginItem *item = (cMenuSetupPluginItem *)Get(Current());
|
||||
if (item) {
|
||||
cPlugin *p = cPluginManager::GetPlugin(item->PluginIndex());
|
||||
if (p) {
|
||||
cMenuSetupPage *menu = p->SetupMenu();
|
||||
if (menu) {
|
||||
menu->SetPlugin(p);
|
||||
return AddSubMenu(menu);
|
||||
}
|
||||
Interface->Info(tr("This plugin has no setup parameters!"));
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (state == osContinue)
|
||||
Store();
|
||||
}
|
||||
return state;
|
||||
}
|
||||
|
48
menuitems.c
48
menuitems.c
@ -4,12 +4,13 @@
|
||||
* See the main source file 'vdr.c' for copyright information and
|
||||
* how to reach the author.
|
||||
*
|
||||
* $Id: menuitems.c 1.1 2002/05/09 10:10:12 kls Exp $
|
||||
* $Id: menuitems.c 1.2 2002/05/11 10:49:45 kls Exp $
|
||||
*/
|
||||
|
||||
#include "menuitems.h"
|
||||
#include <ctype.h>
|
||||
#include "i18n.h"
|
||||
#include "plugin.h"
|
||||
|
||||
// --- cMenuEditItem ---------------------------------------------------------
|
||||
|
||||
@ -437,15 +438,13 @@ eOSState cMenuTextItem::ProcessKey(eKeys Key)
|
||||
cMenuSetupPage::cMenuSetupPage(void)
|
||||
:cOsdMenu("", 33)
|
||||
{
|
||||
data = Setup;
|
||||
osdLanguage = Setup.OSDLanguage;
|
||||
plugin = NULL;
|
||||
}
|
||||
|
||||
void cMenuSetupPage::SetupTitle(const char *s)
|
||||
void cMenuSetupPage::SetSection(const char *Section)
|
||||
{
|
||||
char buf[40]; // can't call tr() for more than one string at a time!
|
||||
char *q = buf + snprintf(buf, sizeof(buf), "%s - ", tr("Setup"));
|
||||
snprintf(q, sizeof(buf) - strlen(buf), "%s", tr(s));
|
||||
char buf[40];
|
||||
snprintf(buf, sizeof(buf), "%s - %s", tr("Setup"), Section);
|
||||
SetTitle(buf);
|
||||
}
|
||||
|
||||
@ -455,22 +454,31 @@ eOSState cMenuSetupPage::ProcessKey(eKeys Key)
|
||||
|
||||
if (state == osUnknown) {
|
||||
switch (Key) {
|
||||
case kOk: state = (Setup.PrimaryDVB != data.PrimaryDVB) ? osSwitchDvb : osBack;
|
||||
cDvbApi::PrimaryDvbApi->SetVideoFormat(data.VideoFormat ? VIDEO_FORMAT_16_9 : VIDEO_FORMAT_4_3);
|
||||
Setup = data;
|
||||
Setup.Save();
|
||||
cDvbApi::SetCaCaps();
|
||||
case kOk: Store();
|
||||
state = osBack;
|
||||
break;
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
if (data.OSDLanguage != osdLanguage) {
|
||||
int OriginalOSDLanguage = Setup.OSDLanguage;
|
||||
Setup.OSDLanguage = data.OSDLanguage;
|
||||
Set();
|
||||
Display();
|
||||
osdLanguage = data.OSDLanguage;
|
||||
Setup.OSDLanguage = OriginalOSDLanguage;
|
||||
}
|
||||
return state;
|
||||
}
|
||||
|
||||
void cMenuSetupPage::SetPlugin(cPlugin *Plugin)
|
||||
{
|
||||
plugin = Plugin;
|
||||
char buf[40];
|
||||
snprintf(buf, sizeof(buf), "%s '%s'", tr("Plugin"), plugin->Name());
|
||||
SetSection(buf);
|
||||
}
|
||||
|
||||
void cMenuSetupPage::SetupStore(const char *Name, const char *Value = NULL)
|
||||
{
|
||||
if (plugin)
|
||||
plugin->SetupStore(Name, Value);
|
||||
}
|
||||
|
||||
void cMenuSetupPage::SetupStore(const char *Name, int Value)
|
||||
{
|
||||
if (plugin)
|
||||
plugin->SetupStore(Name, Value);
|
||||
}
|
||||
|
15
menuitems.h
15
menuitems.h
@ -4,7 +4,7 @@
|
||||
* See the main source file 'vdr.c' for copyright information and
|
||||
* how to reach the author.
|
||||
*
|
||||
* $Id: menuitems.h 1.1 2002/05/09 09:41:06 kls Exp $
|
||||
* $Id: menuitems.h 1.2 2002/05/11 10:48:28 kls Exp $
|
||||
*/
|
||||
|
||||
#ifndef __MENUITEMS_H
|
||||
@ -96,15 +96,20 @@ public:
|
||||
virtual eOSState ProcessKey(eKeys Key);
|
||||
};
|
||||
|
||||
class cPlugin;
|
||||
|
||||
class cMenuSetupPage : public cOsdMenu {
|
||||
private:
|
||||
cPlugin *plugin;
|
||||
protected:
|
||||
cSetup data;
|
||||
int osdLanguage;
|
||||
void SetupTitle(const char *s);
|
||||
virtual void Set(void) = 0;
|
||||
void SetSection(const char *Section);
|
||||
virtual void Store(void) = 0;
|
||||
void SetupStore(const char *Name, const char *Value = NULL);
|
||||
void SetupStore(const char *Name, int Value);
|
||||
public:
|
||||
cMenuSetupPage(void);
|
||||
virtual eOSState ProcessKey(eKeys Key);
|
||||
void SetPlugin(cPlugin *Plugin);
|
||||
};
|
||||
|
||||
#endif //__MENUITEMS_H
|
||||
|
10
vdr.c
10
vdr.c
@ -22,7 +22,7 @@
|
||||
*
|
||||
* The project's page is at http://www.cadsoft.de/people/kls/vdr
|
||||
*
|
||||
* $Id: vdr.c 1.104 2002/05/05 12:00:00 kls Exp $
|
||||
* $Id: vdr.c 1.105 2002/05/11 11:46:40 kls Exp $
|
||||
*/
|
||||
|
||||
#include <getopt.h>
|
||||
@ -578,14 +578,14 @@ int main(int argc, char *argv[])
|
||||
}
|
||||
if (Interrupted)
|
||||
isyslog(LOG_INFO, "caught signal %d", Interrupted);
|
||||
Setup.CurrentChannel = cDvbApi::CurrentChannel();
|
||||
Setup.CurrentVolume = cDvbApi::CurrentVolume();
|
||||
Setup.Save();
|
||||
PluginManager.Shutdown(true);
|
||||
cVideoCutter::Stop();
|
||||
delete Menu;
|
||||
delete ReplayControl;
|
||||
delete Interface;
|
||||
PluginManager.Shutdown(true);
|
||||
Setup.CurrentChannel = cDvbApi::CurrentChannel();
|
||||
Setup.CurrentVolume = cDvbApi::CurrentVolume();
|
||||
Setup.Save();
|
||||
cDvbApi::Cleanup();
|
||||
if (WatchdogTimeout > 0)
|
||||
dsyslog(LOG_INFO, "max. latency time %d seconds", MaxLatencyTime);
|
||||
|
Loading…
Reference in New Issue
Block a user