mirror of
https://github.com/vdr-projects/vdr.git
synced 2025-03-01 10:50:46 +00:00
VDR developer version 2.1.3 is now available at ftp://ftp.tvdr.de/vdr/Developer/vdr-2.1.3.tar.bz2 A 'diff' against the previous version is available at ftp://ftp.tvdr.de/vdr/Developer/vdr-2.1.2-2.1.3.diff MD5 checksums: 054f80e0045aa6fad118e9285b52f4f2 vdr-2.1.3.tar.bz2 3c5ab05d5c4d0b984b34e84190e80949 vdr-2.1.2-2.1.3.diff WARNING: ======== This is a *developer* version. Even though *I* use it in my productive environment, I strongly recommend that you only use it under controlled conditions and for testing and debugging. Originally I intended to release this version only after the new DiSEqC configuration dialog was finished. But in the meantime quite a few other things have come up, so I decided to postpone that dialog and first release what has piled up so far. From the HISTORY file: - Changed the return value of cPositioner::HorizonLongitude() to 0 in case the latitude of the antenna location is beyond +/-81 degrees. - Updated the Finnish OSD texts (thanks to Rolf Ahrenberg). - Fixed some compiler warnings with gcc-4.6.3 (thanks to Rolf Ahrenberg). - Changed the name of the SVDRP command RENR to MOVR (suggested by Rolf Ahrenberg). - When cutting a recording it is now checked whether there is already an edited version of this recording (with the same name, but starting with '%'), and the user is prompted for confirmation to overwrite it (suggested by Rolf Ahrenberg). - Revoked "Added maximum signal strength value for TechniSat SkyStar 2 DVB-S rev 2.3P" because it broke things for the "TechniSat AirStar 2" DVB-T card. - The LIRC remote control now connects to the socket even if it doesn't yet exist when VDR is started (thanks to Lars Hanisch). - Changed the absolute latitude limit for visible satellites to 81.2 degrees. - Added code for parsing LCN and AVC descriptors to libsi (thanks to Rolf Ahrenberg). - In the "Select folder" menu pressing Ok now selects the folder, even if this is a folder that contains sub folders (marked with "..."). To open such a folder you can press the Red key. - Fixed a possible access to uninitialized data in cEIT::cEIT() (reported by Dominik Strasser). - The new menu category mcRecordingEdit is now used to mark menus that edit recording properties (suggested by Stefan Braun). - Changes in the teletext PID no longer cause retuning (and thus interrupting a recording). - Removed '_' from the FileNameChars and CharMap translations in uk_UA.po. - Updated the Italian OSD texts (thanks to Diego Pierotto). - Fixed a missing initialization in the c'tor of cSkinLCARSDisplayChannel (thanks to Marko Mäkelä). - Simplified some conditional expressions in skinlcars.c and skinsttng.c (suggested by Marko Mäkelä). - Fixed uninitialized item area coordinates in cSkinLCARSDisplayMenu (reported by Marko Mäkelä). - Fixed a possible crash if the recordings list is updated externally while the Recordings menu is open (reported by Lars Hanisch). - Added a missing closing ')' in the help and man page entry of the --vfat option (reported by Lars Hanisch). - Fixed setting the name of the video directory to avoid a crash when using --genindex, and also to use the correct directory with --edit (the latter reported by Marko Mäkelä). - The Recordings menu can now be called with a cRecordingFilter, which allows the caller to have it display only a certain subset of the recordings (thanks to Lars Hanisch). - Added handling UTF-8 'umlaut' characters to cKbdRemote (thanks to Lars Hanisch). - Made it clear that the Data parameter in cDevice::StillPicture() may point to a series of packets, not just a single one (thanks to Thomas Reufer). - cDevice::TrickSpeed() now has an additional parameter named Forward, which indicates the direction in which replay is being done (suggested by Thomas Reufer). This information may be necessary for some output devices in order to properly implement trick modes. Authors of plugins that implement output devices will need to add this parameter to their derived cDevice class, regardless of whether they will make use of it or not. - Added a note to ePlayMode in device.h that VDR itself always uses pmAudioVideo when replaying a recording (suggested by Thomas Reufer). - Fixed some spellings in positioner.h and Doxyfile (thanks to Ville Skyttä). - Changed '%a' to the POSIX compliant '%m' in all scanf() calls (thanks to Ville Skyttä). - The new function cCamSlot::Decrypt() can be used by derived classes to implement a CAM slot that can be freely assigned to any device, without being directly inserted into the full TS data stream in hardware. A derived class that implements Decrypt() will also need to set the new parameter ReceiveCaPids in the call to the cCamSlot base class constructor to true, in order to receive the CA pid TS packets that contain data necessary for decrypting. - Many member functions of cCamSlot have been made virtual to allow for easier implementation of derived classes. - cTSBuffer now provides the number of available bytes in its Get() function. - cDvbDevice::GetTSPacket() now calls CamSlot()->Decrypt() in order to allow CAM slots that can be freely assigned to any device access to the TS data stream. - Added a check to avoid a possible NULL pointer dereference in cCiSession::SendData() (reported by Ville Skyttä). - Deleted a superfluous assignment in cPipe::Open() (reported by Ville Skyttä). - The script given to VDR with the '-r' option is now also called after the recording process has actually started (thanks to Christian Kaiser). - Avoiding unnecessary pkg-config warnings in plugin Makefiles (thanks to Ville Skyttä). Plugin authors may want to apply the following change to their Makefile: -PKGCFG = $(if $(VDRDIR),$(shell pkg-config --variable=$(1) $(VDRDIR)/vdr.pc),$(shell pkg-config --variable=$(1) vdr || pkg-config --variable=$(1) ../../../vdr.pc)) +PKGCFG = $(if $(VDRDIR),$(shell pkg-config --variable=$(1) $(VDRDIR)/vdr.pc),$(shell PKG_CONFIG_PATH="$$PKG_CONFIG_PATH:../../.." pkg-config --variable=$(1) vdr)) - Eliminated MAXDVBDEVICES (suggested by Oliver Endriss). - Channels that are no longer contained in the current SDT of a transponder are now marked with the keyword OBSOLETE in their name and provider fields. That way you can identify obsolete channels when you switch to them, and you can get the complete overview of all obsolete channels by sorting the Channels list by provider (by pressing the 0 key twice). Automatic deletion of obsolete channels may follow later.
1215 lines
34 KiB
C
1215 lines
34 KiB
C
/*
|
|
* menuitems.c: General purpose menu items
|
|
*
|
|
* See the main source file 'vdr.c' for copyright information and
|
|
* how to reach the author.
|
|
*
|
|
* $Id: menuitems.c 3.2 2013/11/03 14:48:21 kls Exp $
|
|
*/
|
|
|
|
#include "menuitems.h"
|
|
#include <ctype.h>
|
|
#include <math.h>
|
|
#include <wctype.h>
|
|
#include "i18n.h"
|
|
#include "plugin.h"
|
|
#include "remote.h"
|
|
#include "skins.h"
|
|
#include "status.h"
|
|
|
|
#define AUTO_ADVANCE_TIMEOUT 1500 // ms before auto advance when entering characters via numeric keys
|
|
|
|
const char *FileNameChars = trNOOP("FileNameChars$ abcdefghijklmnopqrstuvwxyz0123456789-.,#~\\^$[]|()*+?{}/:%@&");
|
|
|
|
// --- cMenuEditItem ---------------------------------------------------------
|
|
|
|
cMenuEditItem::cMenuEditItem(const char *Name)
|
|
{
|
|
name = strdup(Name ? Name : "???");
|
|
SetHelp(NULL);
|
|
}
|
|
|
|
cMenuEditItem::~cMenuEditItem()
|
|
{
|
|
free(name);
|
|
}
|
|
|
|
void cMenuEditItem::SetValue(const char *Value)
|
|
{
|
|
cString buffer = cString::sprintf("%s:\t%s", name, Value);
|
|
SetText(buffer);
|
|
cStatus::MsgOsdCurrentItem(buffer);
|
|
}
|
|
|
|
void cMenuEditItem::SetHelp(const char *Red, const char *Green, const char *Yellow, const char *Blue)
|
|
{
|
|
// strings are NOT copied - must be constants!!!
|
|
helpRed = Red;
|
|
helpGreen = Green;
|
|
helpYellow = Yellow;
|
|
helpBlue = Blue;
|
|
helpDisplayed = false;
|
|
}
|
|
|
|
bool cMenuEditItem::DisplayHelp(bool Current)
|
|
{
|
|
bool HasHelp = helpRed || helpGreen || helpYellow || helpBlue;
|
|
if (HasHelp && !helpDisplayed && Current) {
|
|
cSkinDisplay::Current()->SetButtons(helpRed, helpGreen, helpYellow, helpBlue);
|
|
cStatus::MsgOsdHelpKeys(helpRed, helpGreen, helpYellow, helpBlue);
|
|
}
|
|
helpDisplayed = Current;
|
|
return HasHelp;
|
|
}
|
|
|
|
// --- cMenuEditIntItem ------------------------------------------------------
|
|
|
|
cMenuEditIntItem::cMenuEditIntItem(const char *Name, int *Value, int Min, int Max, const char *MinString, const char *MaxString)
|
|
:cMenuEditItem(Name)
|
|
{
|
|
value = Value;
|
|
min = Min;
|
|
max = Max;
|
|
minString = MinString;
|
|
maxString = MaxString;
|
|
if (*value < min)
|
|
*value = min;
|
|
else if (*value > max)
|
|
*value = max;
|
|
Set();
|
|
}
|
|
|
|
void cMenuEditIntItem::Set(void)
|
|
{
|
|
if (minString && *value == min)
|
|
SetValue(minString);
|
|
else if (maxString && *value == max)
|
|
SetValue(maxString);
|
|
else {
|
|
char buf[16];
|
|
snprintf(buf, sizeof(buf), "%d", *value);
|
|
SetValue(buf);
|
|
}
|
|
}
|
|
|
|
eOSState cMenuEditIntItem::ProcessKey(eKeys Key)
|
|
{
|
|
eOSState state = cMenuEditItem::ProcessKey(Key);
|
|
|
|
if (state == osUnknown) {
|
|
int newValue = *value;
|
|
bool IsRepeat = Key & k_Repeat;
|
|
Key = NORMALKEY(Key);
|
|
switch (Key) {
|
|
case kNone: break;
|
|
case k0 ... k9:
|
|
if (fresh) {
|
|
newValue = 0;
|
|
fresh = false;
|
|
}
|
|
newValue = newValue * 10 + (Key - k0);
|
|
break;
|
|
case kLeft: // TODO might want to increase the delta if repeated quickly?
|
|
newValue = *value - 1;
|
|
fresh = true;
|
|
if (!IsRepeat && newValue < min && max != INT_MAX)
|
|
newValue = max;
|
|
break;
|
|
case kRight:
|
|
newValue = *value + 1;
|
|
fresh = true;
|
|
if (!IsRepeat && newValue > max && min != INT_MIN)
|
|
newValue = min;
|
|
break;
|
|
default:
|
|
if (*value < min) { *value = min; Set(); }
|
|
if (*value > max) { *value = max; Set(); }
|
|
return state;
|
|
}
|
|
if (newValue != *value && (!fresh || min <= newValue) && newValue <= max) {
|
|
*value = newValue;
|
|
Set();
|
|
}
|
|
state = osContinue;
|
|
}
|
|
return state;
|
|
}
|
|
|
|
// --- cMenuEditBoolItem -----------------------------------------------------
|
|
|
|
cMenuEditBoolItem::cMenuEditBoolItem(const char *Name, int *Value, const char *FalseString, const char *TrueString)
|
|
:cMenuEditIntItem(Name, Value, 0, 1)
|
|
{
|
|
falseString = FalseString ? FalseString : tr("no");
|
|
trueString = TrueString ? TrueString : tr("yes");
|
|
Set();
|
|
}
|
|
|
|
void cMenuEditBoolItem::Set(void)
|
|
{
|
|
char buf[16];
|
|
snprintf(buf, sizeof(buf), "%s", *value ? trueString : falseString);
|
|
SetValue(buf);
|
|
}
|
|
|
|
// --- cMenuEditBitItem ------------------------------------------------------
|
|
|
|
cMenuEditBitItem::cMenuEditBitItem(const char *Name, uint *Value, uint Mask, const char *FalseString, const char *TrueString)
|
|
:cMenuEditBoolItem(Name, &bit, FalseString, TrueString)
|
|
{
|
|
value = Value;
|
|
bit = (*value & Mask) != 0;
|
|
mask = Mask;
|
|
Set();
|
|
}
|
|
|
|
void cMenuEditBitItem::Set(void)
|
|
{
|
|
*value = bit ? *value | mask : *value & ~mask;
|
|
cMenuEditBoolItem::Set();
|
|
}
|
|
|
|
// --- cMenuEditNumItem ------------------------------------------------------
|
|
|
|
cMenuEditNumItem::cMenuEditNumItem(const char *Name, char *Value, int Length, bool Blind)
|
|
:cMenuEditItem(Name)
|
|
{
|
|
value = Value;
|
|
length = Length;
|
|
blind = Blind;
|
|
Set();
|
|
}
|
|
|
|
void cMenuEditNumItem::Set(void)
|
|
{
|
|
if (blind) {
|
|
char buf[length + 1];
|
|
int i;
|
|
for (i = 0; i < length && value[i]; i++)
|
|
buf[i] = '*';
|
|
buf[i] = 0;
|
|
SetValue(buf);
|
|
}
|
|
else
|
|
SetValue(value);
|
|
}
|
|
|
|
eOSState cMenuEditNumItem::ProcessKey(eKeys Key)
|
|
{
|
|
eOSState state = cMenuEditItem::ProcessKey(Key);
|
|
|
|
if (state == osUnknown) {
|
|
Key = NORMALKEY(Key);
|
|
switch (Key) {
|
|
case kLeft: {
|
|
int l = strlen(value);
|
|
if (l > 0)
|
|
value[l - 1] = 0;
|
|
}
|
|
break;
|
|
case k0 ... k9: {
|
|
int l = strlen(value);
|
|
if (l < length) {
|
|
value[l] = Key - k0 + '0';
|
|
value[l + 1] = 0;
|
|
}
|
|
}
|
|
break;
|
|
default: return state;
|
|
}
|
|
Set();
|
|
state = osContinue;
|
|
}
|
|
return state;
|
|
}
|
|
|
|
// --- cMenuEditIntxItem -----------------------------------------------------
|
|
|
|
cMenuEditIntxItem::cMenuEditIntxItem(const char *Name, int *Value, int Min, int Max, int Factor, const char *NegString, const char *PosString)
|
|
:cMenuEditIntItem(Name, Value, Min, Max)
|
|
{
|
|
factor = ::max(Factor, 1);
|
|
negString = NegString;
|
|
posString = PosString;
|
|
Set();
|
|
}
|
|
|
|
void cMenuEditIntxItem::SetHelpKeys(void)
|
|
{
|
|
if (negString && posString)
|
|
SetHelp(NULL, (*value < 0) ? posString : negString);
|
|
}
|
|
|
|
void cMenuEditIntxItem::Set(void)
|
|
{
|
|
const char *s = (*value < 0) ? negString : posString;
|
|
int v = *value;
|
|
if (negString && posString)
|
|
v = abs(v);
|
|
SetValue(cString::sprintf(s ? "%.*f %s" : "%.*f", factor / 10, double(v) / factor, s));
|
|
SetHelpKeys();
|
|
}
|
|
|
|
eOSState cMenuEditIntxItem::ProcessKey(eKeys Key)
|
|
{
|
|
eOSState state = cMenuEditIntItem::ProcessKey(Key);
|
|
if (state == osUnknown) {
|
|
switch (Key) {
|
|
case kGreen: if (negString && posString) {
|
|
*value = -*value;
|
|
Set();
|
|
state = osContinue;
|
|
}
|
|
break;
|
|
default: ;
|
|
}
|
|
}
|
|
return state;
|
|
}
|
|
|
|
// --- cMenuEditPrcItem ------------------------------------------------------
|
|
|
|
cMenuEditPrcItem::cMenuEditPrcItem(const char *Name, double *Value, double Min, double Max, int Decimals)
|
|
:cMenuEditItem(Name)
|
|
{
|
|
value = Value;
|
|
min = Min;
|
|
max = Max;
|
|
decimals = Decimals;
|
|
factor = 100;
|
|
while (Decimals-- > 0)
|
|
factor *= 10;
|
|
if (*value < min)
|
|
*value = min;
|
|
else if (*value > max)
|
|
*value = max;
|
|
Set();
|
|
}
|
|
|
|
void cMenuEditPrcItem::Set(void)
|
|
{
|
|
char buf[16];
|
|
snprintf(buf, sizeof(buf), "%.*f", decimals, *value * 100);
|
|
SetValue(buf);
|
|
}
|
|
|
|
eOSState cMenuEditPrcItem::ProcessKey(eKeys Key)
|
|
{
|
|
eOSState state = cMenuEditItem::ProcessKey(Key);
|
|
|
|
if (state == osUnknown) {
|
|
double newValue = round(*value * factor); // avoids precision problems
|
|
Key = NORMALKEY(Key);
|
|
switch (Key) {
|
|
case kNone: break;
|
|
case k0 ... k9:
|
|
if (fresh) {
|
|
newValue = 0;
|
|
fresh = false;
|
|
}
|
|
newValue = newValue * 10 + (Key - k0);
|
|
break;
|
|
case kLeft: // TODO might want to increase the delta if repeated quickly?
|
|
newValue--;
|
|
fresh = true;
|
|
break;
|
|
case kRight:
|
|
newValue++;
|
|
fresh = true;
|
|
break;
|
|
default:
|
|
if (*value < min) { *value = min; Set(); }
|
|
if (*value > max) { *value = max; Set(); }
|
|
return state;
|
|
}
|
|
newValue /= factor;
|
|
if (!DoubleEqual(newValue, *value) && (!fresh || min <= newValue) && newValue <= max) {
|
|
*value = newValue;
|
|
Set();
|
|
}
|
|
state = osContinue;
|
|
}
|
|
return state;
|
|
}
|
|
|
|
// --- cMenuEditChrItem ------------------------------------------------------
|
|
|
|
cMenuEditChrItem::cMenuEditChrItem(const char *Name, char *Value, const char *Allowed)
|
|
:cMenuEditItem(Name)
|
|
{
|
|
value = Value;
|
|
allowed = strdup(Allowed ? Allowed : "");
|
|
current = strchr(allowed, *Value);
|
|
if (!current)
|
|
current = allowed;
|
|
Set();
|
|
}
|
|
|
|
cMenuEditChrItem::~cMenuEditChrItem()
|
|
{
|
|
free(allowed);
|
|
}
|
|
|
|
void cMenuEditChrItem::Set(void)
|
|
{
|
|
char buf[2];
|
|
buf[0] = *value;
|
|
buf[1] = '\0';
|
|
SetValue(buf);
|
|
}
|
|
|
|
eOSState cMenuEditChrItem::ProcessKey(eKeys Key)
|
|
{
|
|
eOSState state = cMenuEditItem::ProcessKey(Key);
|
|
|
|
if (state == osUnknown) {
|
|
if (NORMALKEY(Key) == kLeft) {
|
|
if (current > allowed)
|
|
current--;
|
|
}
|
|
else if (NORMALKEY(Key) == kRight) {
|
|
if (*(current + 1))
|
|
current++;
|
|
}
|
|
else
|
|
return state;
|
|
*value = *current;
|
|
Set();
|
|
state = osContinue;
|
|
}
|
|
return state;
|
|
}
|
|
|
|
// --- cMenuEditStrItem ------------------------------------------------------
|
|
|
|
cMenuEditStrItem::cMenuEditStrItem(const char *Name, char *Value, int Length, const char *Allowed)
|
|
:cMenuEditItem(Name)
|
|
{
|
|
value = Value;
|
|
length = Length;
|
|
allowed = Allowed ? Allowed : tr(FileNameChars);
|
|
pos = -1;
|
|
offset = 0;
|
|
insert = uppercase = false;
|
|
newchar = true;
|
|
lengthUtf8 = 0;
|
|
valueUtf8 = NULL;
|
|
allowedUtf8 = NULL;
|
|
charMapUtf8 = NULL;
|
|
currentCharUtf8 = NULL;
|
|
lastKey = kNone;
|
|
Set();
|
|
}
|
|
|
|
cMenuEditStrItem::~cMenuEditStrItem()
|
|
{
|
|
delete[] valueUtf8;
|
|
delete[] allowedUtf8;
|
|
delete[] charMapUtf8;
|
|
}
|
|
|
|
void cMenuEditStrItem::EnterEditMode(void)
|
|
{
|
|
if (!valueUtf8) {
|
|
valueUtf8 = new uint[length];
|
|
lengthUtf8 = Utf8ToArray(value, valueUtf8, length);
|
|
int l = strlen(allowed) + 1;
|
|
allowedUtf8 = new uint[l];
|
|
Utf8ToArray(allowed, allowedUtf8, l);
|
|
const char *charMap = tr("CharMap$ 0\t-.,1#~\\^$[]|()*+?{}/:%@&\tabc2\tdef3\tghi4\tjkl5\tmno6\tpqrs7\ttuv8\twxyz9");
|
|
l = strlen(charMap) + 1;
|
|
charMapUtf8 = new uint[l];
|
|
Utf8ToArray(charMap, charMapUtf8, l);
|
|
currentCharUtf8 = charMapUtf8;
|
|
AdvancePos();
|
|
}
|
|
}
|
|
|
|
void cMenuEditStrItem::LeaveEditMode(bool SaveValue)
|
|
{
|
|
if (valueUtf8) {
|
|
if (SaveValue) {
|
|
Utf8FromArray(valueUtf8, value, length);
|
|
stripspace(value);
|
|
}
|
|
lengthUtf8 = 0;
|
|
delete[] valueUtf8;
|
|
valueUtf8 = NULL;
|
|
delete[] allowedUtf8;
|
|
allowedUtf8 = NULL;
|
|
delete[] charMapUtf8;
|
|
charMapUtf8 = NULL;
|
|
pos = -1;
|
|
offset = 0;
|
|
newchar = true;
|
|
}
|
|
}
|
|
|
|
void cMenuEditStrItem::SetHelpKeys(void)
|
|
{
|
|
if (InEditMode())
|
|
SetHelp(tr("Button$ABC/abc"), insert ? tr("Button$Overwrite") : tr("Button$Insert"), tr("Button$Delete"));
|
|
else
|
|
SetHelp(NULL);
|
|
}
|
|
|
|
uint *cMenuEditStrItem::IsAllowed(uint c)
|
|
{
|
|
if (allowedUtf8) {
|
|
for (uint *a = allowedUtf8; *a; a++) {
|
|
if (c == *a)
|
|
return a;
|
|
}
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
void cMenuEditStrItem::AdvancePos(void)
|
|
{
|
|
if (pos < length - 2 && pos < lengthUtf8) {
|
|
if (++pos >= lengthUtf8) {
|
|
if (pos >= 2 && valueUtf8[pos - 1] == ' ' && valueUtf8[pos - 2] == ' ')
|
|
pos--; // allow only two blanks at the end
|
|
else {
|
|
valueUtf8[pos] = ' ';
|
|
valueUtf8[pos + 1] = 0;
|
|
lengthUtf8++;
|
|
}
|
|
}
|
|
}
|
|
newchar = true;
|
|
if (!insert && Utf8is(alpha, valueUtf8[pos]))
|
|
uppercase = Utf8is(upper, valueUtf8[pos]);
|
|
}
|
|
|
|
void cMenuEditStrItem::Set(void)
|
|
{
|
|
if (InEditMode()) {
|
|
// This is an ugly hack to make editing strings work with the 'skincurses' plugin.
|
|
const cFont *font = dynamic_cast<cSkinDisplayMenu *>(cSkinDisplay::Current())->GetTextAreaFont(false);
|
|
if (!font || font->Width("W") != 1) // all characters have width == 1 in the font used by 'skincurses'
|
|
font = cFont::GetFont(fontOsd);
|
|
|
|
int width = cSkinDisplay::Current()->EditableWidth();
|
|
width -= font->Width("[]");
|
|
width -= font->Width("<>"); // reserving this anyway makes the whole thing simpler
|
|
|
|
if (pos < offset)
|
|
offset = pos;
|
|
int WidthFromOffset = 0;
|
|
int EndPos = lengthUtf8;
|
|
for (int i = offset; i < lengthUtf8; i++) {
|
|
WidthFromOffset += font->Width(valueUtf8[i]);
|
|
if (WidthFromOffset > width) {
|
|
if (pos >= i) {
|
|
do {
|
|
WidthFromOffset -= font->Width(valueUtf8[offset]);
|
|
offset++;
|
|
} while (WidthFromOffset > width && offset < pos);
|
|
EndPos = pos + 1;
|
|
}
|
|
else {
|
|
EndPos = i;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
char buf[1000];
|
|
char *p = buf;
|
|
if (offset)
|
|
*p++ = '<';
|
|
p += Utf8FromArray(valueUtf8 + offset, p, sizeof(buf) - (p - buf), pos - offset);
|
|
*p++ = '[';
|
|
if (insert && newchar)
|
|
*p++ = ']';
|
|
p += Utf8FromArray(&valueUtf8[pos], p, sizeof(buf) - (p - buf), 1);
|
|
if (!(insert && newchar))
|
|
*p++ = ']';
|
|
p += Utf8FromArray(&valueUtf8[pos + 1], p, sizeof(buf) - (p - buf), EndPos - pos - 1);
|
|
if (EndPos != lengthUtf8)
|
|
*p++ = '>';
|
|
*p = 0;
|
|
|
|
SetValue(buf);
|
|
}
|
|
else
|
|
SetValue(value);
|
|
}
|
|
|
|
uint cMenuEditStrItem::Inc(uint c, bool Up)
|
|
{
|
|
uint *p = IsAllowed(c);
|
|
if (!p)
|
|
p = allowedUtf8;
|
|
if (Up) {
|
|
if (!*++p)
|
|
p = allowedUtf8;
|
|
}
|
|
else if (--p < allowedUtf8) {
|
|
p = allowedUtf8;
|
|
while (*p && *(p + 1))
|
|
p++;
|
|
}
|
|
return *p;
|
|
}
|
|
|
|
void cMenuEditStrItem::Type(uint c)
|
|
{
|
|
if (insert && lengthUtf8 < length - 1)
|
|
Insert();
|
|
valueUtf8[pos] = c;
|
|
if (pos < length - 2)
|
|
pos++;
|
|
if (pos >= lengthUtf8) {
|
|
valueUtf8[pos] = ' ';
|
|
valueUtf8[pos + 1] = 0;
|
|
lengthUtf8 = pos + 1;
|
|
}
|
|
}
|
|
|
|
void cMenuEditStrItem::Insert(void)
|
|
{
|
|
memmove(valueUtf8 + pos + 1, valueUtf8 + pos, (lengthUtf8 - pos + 1) * sizeof(*valueUtf8));
|
|
lengthUtf8++;
|
|
valueUtf8[pos] = ' ';
|
|
}
|
|
|
|
void cMenuEditStrItem::Delete(void)
|
|
{
|
|
memmove(valueUtf8 + pos, valueUtf8 + pos + 1, (lengthUtf8 - pos) * sizeof(*valueUtf8));
|
|
lengthUtf8--;
|
|
}
|
|
|
|
eOSState cMenuEditStrItem::ProcessKey(eKeys Key)
|
|
{
|
|
bool SameKey = NORMALKEY(Key) == lastKey;
|
|
if (Key != kNone)
|
|
lastKey = NORMALKEY(Key);
|
|
else if (!newchar && k0 <= lastKey && lastKey <= k9 && autoAdvanceTimeout.TimedOut()) {
|
|
AdvancePos();
|
|
newchar = true;
|
|
currentCharUtf8 = NULL;
|
|
Set();
|
|
return osContinue;
|
|
}
|
|
switch (int(Key)) {
|
|
case kRed: // Switch between upper- and lowercase characters
|
|
if (InEditMode()) {
|
|
if (!insert || !newchar) {
|
|
uppercase = !uppercase;
|
|
valueUtf8[pos] = uppercase ? Utf8to(upper, valueUtf8[pos]) : Utf8to(lower, valueUtf8[pos]);
|
|
}
|
|
}
|
|
else
|
|
return osUnknown;
|
|
break;
|
|
case kGreen: // Toggle insert/overwrite modes
|
|
if (InEditMode()) {
|
|
insert = !insert;
|
|
newchar = true;
|
|
SetHelpKeys();
|
|
}
|
|
else
|
|
return osUnknown;
|
|
break;
|
|
case kYellow|k_Repeat:
|
|
case kYellow: // Remove the character at the current position; in insert mode it is the character to the right of the cursor
|
|
if (InEditMode()) {
|
|
if (lengthUtf8 > 1) {
|
|
if (!insert || pos < lengthUtf8 - 1)
|
|
Delete();
|
|
else if (insert && pos == lengthUtf8 - 1)
|
|
valueUtf8[pos] = ' '; // in insert mode, deleting the last character replaces it with a blank to keep the cursor position
|
|
// reduce position, if we removed the last character
|
|
if (pos == lengthUtf8)
|
|
pos--;
|
|
}
|
|
else if (lengthUtf8 == 1)
|
|
valueUtf8[0] = ' '; // This is the last character in the string, replace it with a blank
|
|
if (Utf8is(alpha, valueUtf8[pos]))
|
|
uppercase = Utf8is(upper, valueUtf8[pos]);
|
|
newchar = true;
|
|
}
|
|
else
|
|
return osUnknown;
|
|
break;
|
|
case kBlue|k_Repeat:
|
|
case kBlue: // consume the key only if in edit-mode
|
|
if (!InEditMode())
|
|
return osUnknown;
|
|
break;
|
|
case kLeft|k_Repeat:
|
|
case kLeft: if (pos > 0) {
|
|
if (!insert || newchar)
|
|
pos--;
|
|
newchar = true;
|
|
if (!insert && Utf8is(alpha, valueUtf8[pos]))
|
|
uppercase = Utf8is(upper, valueUtf8[pos]);
|
|
}
|
|
break;
|
|
case kRight|k_Repeat:
|
|
case kRight: if (InEditMode())
|
|
AdvancePos();
|
|
else {
|
|
EnterEditMode();
|
|
SetHelpKeys();
|
|
}
|
|
break;
|
|
case kUp|k_Repeat:
|
|
case kUp:
|
|
case kDown|k_Repeat:
|
|
case kDown: if (InEditMode()) {
|
|
if (insert && newchar) {
|
|
// create a new character in insert mode
|
|
if (lengthUtf8 < length - 1)
|
|
Insert();
|
|
}
|
|
if (uppercase)
|
|
valueUtf8[pos] = Utf8to(upper, Inc(Utf8to(lower, valueUtf8[pos]), NORMALKEY(Key) == kUp));
|
|
else
|
|
valueUtf8[pos] = Inc( valueUtf8[pos], NORMALKEY(Key) == kUp);
|
|
newchar = false;
|
|
}
|
|
else
|
|
return cMenuEditItem::ProcessKey(Key);
|
|
break;
|
|
case k0|k_Repeat ... k9|k_Repeat:
|
|
case k0 ... k9: {
|
|
if (InEditMode()) {
|
|
if (Setup.NumberKeysForChars) {
|
|
if (!SameKey) {
|
|
if (!newchar)
|
|
AdvancePos();
|
|
currentCharUtf8 = NULL;
|
|
}
|
|
if (!currentCharUtf8 || !*currentCharUtf8 || *currentCharUtf8 == '\t') {
|
|
// find the beginning of the character map entry for Key
|
|
int n = NORMALKEY(Key) - k0;
|
|
currentCharUtf8 = charMapUtf8;
|
|
while (n > 0 && *currentCharUtf8) {
|
|
if (*currentCharUtf8++ == '\t')
|
|
n--;
|
|
}
|
|
// find first allowed character
|
|
while (*currentCharUtf8 && *currentCharUtf8 != '\t' && !IsAllowed(*currentCharUtf8))
|
|
currentCharUtf8++;
|
|
}
|
|
if (*currentCharUtf8 && *currentCharUtf8 != '\t') {
|
|
if (insert && newchar) {
|
|
// create a new character in insert mode
|
|
if (lengthUtf8 < length - 1)
|
|
Insert();
|
|
}
|
|
valueUtf8[pos] = *currentCharUtf8;
|
|
if (uppercase)
|
|
valueUtf8[pos] = Utf8to(upper, valueUtf8[pos]);
|
|
// find next allowed character
|
|
do {
|
|
currentCharUtf8++;
|
|
} while (*currentCharUtf8 && *currentCharUtf8 != '\t' && !IsAllowed(*currentCharUtf8));
|
|
newchar = false;
|
|
autoAdvanceTimeout.Set(AUTO_ADVANCE_TIMEOUT);
|
|
}
|
|
}
|
|
else
|
|
Type('0' + NORMALKEY(Key) - k0);
|
|
}
|
|
else
|
|
return cMenuEditItem::ProcessKey(Key);
|
|
}
|
|
break;
|
|
case kBack:
|
|
case kOk: if (InEditMode()) {
|
|
LeaveEditMode(Key == kOk);
|
|
SetHelpKeys();
|
|
break;
|
|
}
|
|
// run into default
|
|
default: if (InEditMode() && BASICKEY(Key) == kKbd) {
|
|
int c = KEYKBD(Key);
|
|
if (c <= 0xFF) { // FIXME what about other UTF-8 characters?
|
|
if (IsAllowed(Utf8to(lower, c)))
|
|
Type(c);
|
|
else {
|
|
switch (c) {
|
|
case 0x7F: // backspace
|
|
if (pos > 0) {
|
|
pos--;
|
|
return ProcessKey(kYellow);
|
|
}
|
|
break;
|
|
default: ;
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
switch (c) {
|
|
case kfHome: pos = 0; break;
|
|
case kfEnd: pos = lengthUtf8 - 1; break;
|
|
case kfIns: return ProcessKey(kGreen);
|
|
case kfDel: return ProcessKey(kYellow);
|
|
default: ;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
return cMenuEditItem::ProcessKey(Key);
|
|
}
|
|
Set();
|
|
return osContinue;
|
|
}
|
|
|
|
// --- cMenuEditStraItem -----------------------------------------------------
|
|
|
|
cMenuEditStraItem::cMenuEditStraItem(const char *Name, int *Value, int NumStrings, const char * const *Strings)
|
|
:cMenuEditIntItem(Name, Value, 0, NumStrings - 1)
|
|
{
|
|
strings = Strings;
|
|
Set();
|
|
}
|
|
|
|
void cMenuEditStraItem::Set(void)
|
|
{
|
|
SetValue(strings[*value]);
|
|
}
|
|
|
|
// --- cMenuEditChanItem -----------------------------------------------------
|
|
|
|
cMenuEditChanItem::cMenuEditChanItem(const char *Name, int *Value, const char *NoneString)
|
|
:cMenuEditIntItem(Name, Value, NoneString ? 0 : 1, Channels.MaxNumber())
|
|
{
|
|
channelID = NULL;
|
|
noneString = NoneString;
|
|
dummyValue = 0;
|
|
Set();
|
|
}
|
|
|
|
cMenuEditChanItem::cMenuEditChanItem(const char *Name, cString *ChannelID, const char *NoneString)
|
|
:cMenuEditIntItem(Name, &dummyValue, NoneString ? 0 : 1, Channels.MaxNumber())
|
|
{
|
|
channelID = ChannelID;
|
|
noneString = NoneString;
|
|
cChannel *channel = Channels.GetByChannelID(tChannelID::FromString(*ChannelID));
|
|
dummyValue = channel ? channel->Number() : 0;
|
|
Set();
|
|
}
|
|
|
|
void cMenuEditChanItem::Set(void)
|
|
{
|
|
if (*value > 0) {
|
|
char buf[255];
|
|
cChannel *channel = Channels.GetByNumber(*value);
|
|
snprintf(buf, sizeof(buf), "%d %s", *value, channel ? channel->Name() : "");
|
|
SetValue(buf);
|
|
if (channelID)
|
|
*channelID = channel ? channel->GetChannelID().ToString() : "";
|
|
}
|
|
else if (noneString) {
|
|
SetValue(noneString);
|
|
if (channelID)
|
|
*channelID = "";
|
|
}
|
|
}
|
|
|
|
eOSState cMenuEditChanItem::ProcessKey(eKeys Key)
|
|
{
|
|
int delta = 1;
|
|
|
|
switch (int(Key)) {
|
|
case kLeft|k_Repeat:
|
|
case kLeft: delta = -1;
|
|
case kRight|k_Repeat:
|
|
case kRight:
|
|
{
|
|
cChannel *channel = Channels.GetByNumber(*value + delta, delta);
|
|
if (channel)
|
|
*value = channel->Number();
|
|
else if (delta < 0 && noneString)
|
|
*value = 0;
|
|
if (channelID)
|
|
*channelID = channel ? channel->GetChannelID().ToString() : "";
|
|
Set();
|
|
}
|
|
break;
|
|
default: return cMenuEditIntItem::ProcessKey(Key);
|
|
}
|
|
return osContinue;
|
|
}
|
|
|
|
// --- cMenuEditTranItem -----------------------------------------------------
|
|
|
|
cMenuEditTranItem::cMenuEditTranItem(const char *Name, int *Value, int *Source)
|
|
:cMenuEditChanItem(Name, &number, "-")
|
|
{
|
|
number = 0;
|
|
source = Source;
|
|
transponder = Value;
|
|
cChannel *channel = Channels.First();
|
|
while (channel) {
|
|
if (!channel->GroupSep() && *source == channel->Source() && ISTRANSPONDER(channel->Transponder(), *Value)) {
|
|
number = channel->Number();
|
|
break;
|
|
}
|
|
channel = (cChannel *)channel->Next();
|
|
}
|
|
Set();
|
|
}
|
|
|
|
eOSState cMenuEditTranItem::ProcessKey(eKeys Key)
|
|
{
|
|
eOSState state = cMenuEditChanItem::ProcessKey(Key);
|
|
cChannel *channel = Channels.GetByNumber(number);
|
|
if (channel) {
|
|
*source = channel->Source();
|
|
*transponder = channel->Transponder();
|
|
}
|
|
else {
|
|
*source = 0;
|
|
*transponder = 0;
|
|
}
|
|
return state;
|
|
}
|
|
|
|
// --- cMenuEditDateItem -----------------------------------------------------
|
|
|
|
static int ParseWeekDays(const char *s)
|
|
{
|
|
time_t day;
|
|
int weekdays;
|
|
return cTimer::ParseDay(s, day, weekdays) ? weekdays : 0;
|
|
}
|
|
|
|
int cMenuEditDateItem::days[] = { ParseWeekDays("M------"),
|
|
ParseWeekDays("-T-----"),
|
|
ParseWeekDays("--W----"),
|
|
ParseWeekDays("---T---"),
|
|
ParseWeekDays("----F--"),
|
|
ParseWeekDays("-----S-"),
|
|
ParseWeekDays("------S"),
|
|
ParseWeekDays("MTWTF--"),
|
|
ParseWeekDays("MTWTFS-"),
|
|
ParseWeekDays("MTWTFSS"),
|
|
ParseWeekDays("-----SS"),
|
|
0 };
|
|
|
|
cMenuEditDateItem::cMenuEditDateItem(const char *Name, time_t *Value, int *WeekDays)
|
|
:cMenuEditItem(Name)
|
|
{
|
|
value = Value;
|
|
weekdays = WeekDays;
|
|
oldvalue = 0;
|
|
oldweekdays = 0;
|
|
dayindex = weekdays ? FindDayIndex(*weekdays) : 0;
|
|
Set();
|
|
}
|
|
|
|
int cMenuEditDateItem::FindDayIndex(int WeekDays)
|
|
{
|
|
for (unsigned int i = 0; i < sizeof(days) / sizeof(int); i++)
|
|
if (WeekDays == days[i])
|
|
return i;
|
|
return 0;
|
|
}
|
|
|
|
void cMenuEditDateItem::Set(void)
|
|
{
|
|
#define DATEBUFFERSIZE 32
|
|
char buf[DATEBUFFERSIZE];
|
|
if (weekdays && *weekdays) {
|
|
SetValue(cTimer::PrintDay(0, *weekdays, false));
|
|
return;
|
|
}
|
|
else if (*value) {
|
|
struct tm tm_r;
|
|
localtime_r(value, &tm_r);
|
|
strftime(buf, DATEBUFFERSIZE, "%Y-%m-%d ", &tm_r);
|
|
strcat(buf, WeekDayName(tm_r.tm_wday));
|
|
}
|
|
else
|
|
*buf = 0;
|
|
SetValue(buf);
|
|
}
|
|
|
|
void cMenuEditDateItem::ToggleRepeating(void)
|
|
{
|
|
if (weekdays) {
|
|
if (*weekdays) {
|
|
*value = cTimer::SetTime(oldvalue ? oldvalue : time(NULL), 0);
|
|
oldvalue = 0;
|
|
oldweekdays = *weekdays;
|
|
*weekdays = 0;
|
|
}
|
|
else {
|
|
*weekdays = oldweekdays ? oldweekdays : days[cTimer::GetWDay(*value)];
|
|
oldweekdays = 0;
|
|
dayindex = FindDayIndex(*weekdays);
|
|
oldvalue = *value;
|
|
*value = 0;
|
|
}
|
|
Set();
|
|
}
|
|
}
|
|
|
|
eOSState cMenuEditDateItem::ProcessKey(eKeys Key)
|
|
{
|
|
eOSState state = cMenuEditItem::ProcessKey(Key);
|
|
|
|
if (state == osUnknown) {
|
|
time_t now = time(NULL);
|
|
if (NORMALKEY(Key) == kLeft) { // TODO might want to increase the delta if repeated quickly?
|
|
if (!weekdays || !*weekdays) {
|
|
// Decrement single day:
|
|
time_t v = *value;
|
|
v -= SECSINDAY;
|
|
if (v < now) {
|
|
if (now <= v + SECSINDAY) { // switched from tomorrow to today
|
|
if (!weekdays)
|
|
v = 0;
|
|
}
|
|
else if (weekdays) { // switched from today to yesterday, so enter weekdays mode
|
|
v = 0;
|
|
dayindex = sizeof(days) / sizeof(int) - 2;
|
|
*weekdays = days[dayindex];
|
|
}
|
|
else // don't go before today
|
|
v = *value;
|
|
}
|
|
*value = v;
|
|
}
|
|
else {
|
|
// Decrement weekday index:
|
|
if (dayindex > 0)
|
|
*weekdays = days[--dayindex];
|
|
}
|
|
}
|
|
else if (NORMALKEY(Key) == kRight) {
|
|
if (!weekdays || !*weekdays) {
|
|
// Increment single day:
|
|
if (!*value)
|
|
*value = cTimer::SetTime(now, 0);
|
|
*value += SECSINDAY;
|
|
}
|
|
else {
|
|
// Increment weekday index:
|
|
*weekdays = days[++dayindex];
|
|
if (!*weekdays) { // was last weekday entry, so switch to today
|
|
*value = cTimer::SetTime(now, 0);
|
|
dayindex = 0;
|
|
}
|
|
}
|
|
}
|
|
else if (weekdays) {
|
|
if (Key == k0) {
|
|
// Toggle between weekdays and single day:
|
|
ToggleRepeating();
|
|
return osContinue; // ToggleRepeating) has already called Set()
|
|
}
|
|
else if (k1 <= Key && Key <= k7) {
|
|
// Toggle individual weekdays:
|
|
if (*weekdays) {
|
|
int v = *weekdays ^ (1 << (Key - k1));
|
|
if (v != 0)
|
|
*weekdays = v; // can't let this become all 0
|
|
}
|
|
}
|
|
else
|
|
return state;
|
|
}
|
|
else
|
|
return state;
|
|
Set();
|
|
state = osContinue;
|
|
}
|
|
return state;
|
|
}
|
|
|
|
// --- cMenuEditTimeItem -----------------------------------------------------
|
|
|
|
cMenuEditTimeItem::cMenuEditTimeItem(const char *Name, int *Value)
|
|
:cMenuEditItem(Name)
|
|
{
|
|
value = Value;
|
|
hh = *value / 100;
|
|
mm = *value % 100;
|
|
pos = 0;
|
|
Set();
|
|
}
|
|
|
|
void cMenuEditTimeItem::Set(void)
|
|
{
|
|
char buf[10];
|
|
switch (pos) {
|
|
case 1: snprintf(buf, sizeof(buf), "%01d-:--", hh / 10); break;
|
|
case 2: snprintf(buf, sizeof(buf), "%02d:--", hh); break;
|
|
case 3: snprintf(buf, sizeof(buf), "%02d:%01d-", hh, mm / 10); break;
|
|
default: snprintf(buf, sizeof(buf), "%02d:%02d", hh, mm);
|
|
}
|
|
SetValue(buf);
|
|
}
|
|
|
|
eOSState cMenuEditTimeItem::ProcessKey(eKeys Key)
|
|
{
|
|
eOSState state = cMenuEditItem::ProcessKey(Key);
|
|
|
|
if (state == osUnknown) {
|
|
if (k0 <= Key && Key <= k9) {
|
|
if (fresh || pos > 3) {
|
|
pos = 0;
|
|
fresh = false;
|
|
}
|
|
int n = Key - k0;
|
|
switch (pos) {
|
|
case 0: if (n <= 2) {
|
|
hh = n * 10;
|
|
mm = 0;
|
|
pos++;
|
|
}
|
|
break;
|
|
case 1: if (hh + n <= 23) {
|
|
hh += n;
|
|
pos++;
|
|
}
|
|
break;
|
|
case 2: if (n <= 5) {
|
|
mm += n * 10;
|
|
pos++;
|
|
}
|
|
break;
|
|
case 3: if (mm + n <= 59) {
|
|
mm += n;
|
|
pos++;
|
|
}
|
|
break;
|
|
default: ;
|
|
}
|
|
}
|
|
else if (NORMALKEY(Key) == kLeft) { // TODO might want to increase the delta if repeated quickly?
|
|
if (--mm < 0) {
|
|
mm = 59;
|
|
if (--hh < 0)
|
|
hh = 23;
|
|
}
|
|
fresh = true;
|
|
}
|
|
else if (NORMALKEY(Key) == kRight) {
|
|
if (++mm > 59) {
|
|
mm = 0;
|
|
if (++hh > 23)
|
|
hh = 0;
|
|
}
|
|
fresh = true;
|
|
}
|
|
else
|
|
return state;
|
|
*value = hh * 100 + mm;
|
|
Set();
|
|
state = osContinue;
|
|
}
|
|
return state;
|
|
}
|
|
|
|
// --- cMenuEditMapItem ------------------------------------------------------
|
|
|
|
cMenuEditMapItem::cMenuEditMapItem(const char *Name, int *Value, const tDvbParameterMap *Map, const char *ZeroString)
|
|
:cMenuEditItem(Name)
|
|
{
|
|
value = Value;
|
|
map = Map;
|
|
zeroString = ZeroString;
|
|
Set();
|
|
}
|
|
|
|
void cMenuEditMapItem::Set(void)
|
|
{
|
|
const char *s = NULL;
|
|
int n = MapToUser(*value, map, &s);
|
|
if (n == 0 && zeroString)
|
|
SetValue(zeroString);
|
|
else if (n >= 0) {
|
|
if (s)
|
|
SetValue(s);
|
|
else {
|
|
char buf[16];
|
|
snprintf(buf, sizeof(buf), "%d", n);
|
|
SetValue(buf);
|
|
}
|
|
}
|
|
else
|
|
SetValue("???");
|
|
}
|
|
|
|
eOSState cMenuEditMapItem::ProcessKey(eKeys Key)
|
|
{
|
|
eOSState state = cMenuEditItem::ProcessKey(Key);
|
|
|
|
if (state == osUnknown) {
|
|
int newValue = *value;
|
|
int n = DriverIndex(*value, map);
|
|
if (NORMALKEY(Key) == kLeft) { // TODO might want to increase the delta if repeated quickly?
|
|
if (n-- > 0)
|
|
newValue = map[n].driverValue;
|
|
}
|
|
else if (NORMALKEY(Key) == kRight) {
|
|
if (map[++n].userValue >= 0)
|
|
newValue = map[n].driverValue;
|
|
}
|
|
else
|
|
return state;
|
|
if (newValue != *value) {
|
|
*value = newValue;
|
|
Set();
|
|
}
|
|
state = osContinue;
|
|
}
|
|
return state;
|
|
}
|
|
|
|
// --- cMenuSetupPage --------------------------------------------------------
|
|
|
|
cMenuSetupPage::cMenuSetupPage(void)
|
|
:cOsdMenu("", 33)
|
|
{
|
|
SetMenuCategory(mcSetup);
|
|
plugin = NULL;
|
|
}
|
|
|
|
void cMenuSetupPage::SetSection(const char *Section)
|
|
{
|
|
SetTitle(cString::sprintf("%s - %s", tr("Setup"), Section));
|
|
}
|
|
|
|
eOSState cMenuSetupPage::ProcessKey(eKeys Key)
|
|
{
|
|
eOSState state = cOsdMenu::ProcessKey(Key);
|
|
|
|
if (state == osUnknown) {
|
|
switch (Key) {
|
|
case kOk: Store();
|
|
state = osBack;
|
|
break;
|
|
default: break;
|
|
}
|
|
}
|
|
return state;
|
|
}
|
|
|
|
void cMenuSetupPage::SetPlugin(cPlugin *Plugin)
|
|
{
|
|
SetMenuCategory(mcPluginSetup);
|
|
plugin = Plugin;
|
|
SetSection(cString::sprintf("%s '%s'", tr("Plugin"), plugin->Name()));
|
|
}
|
|
|
|
void cMenuSetupPage::SetupStore(const char *Name, const char *Value)
|
|
{
|
|
if (plugin)
|
|
plugin->SetupStore(Name, Value);
|
|
}
|
|
|
|
void cMenuSetupPage::SetupStore(const char *Name, int Value)
|
|
{
|
|
if (plugin)
|
|
plugin->SetupStore(Name, Value);
|
|
}
|