mirror of
https://github.com/vdr-projects/vdr.git
synced 2025-03-01 10:50:46 +00:00
- Fixed handling broken PMT records (thanks to Marcel Wiesweg for pointing out how to detect these). - Added a missing "Button$" for the Timer button and "Key$" in skinclassic.c (thanks to Rolf Ahrenberg). - Fixed broken entry 'A111.1W' in sources.conf (reported by Luca Olivetti). - Replaced the obsolete entry 'S21.5E' in the default 'diseqc.conf' with 'S13.0E' (reported by Ville Skyttä). - Fixed learning keys when VDR is already running (thanks to Jurij Retzlaff). - Fixed handling the system time transponder setting in the Setup/EPG menu, which was broken by the min/max fix in cMenuEditIntItem. - VPS timers now record only events that have exactly the given start time. This fix also implements recording several subsequent events that have the same VPS time (like a sports event with intermittent news breaks). - When checking for timers that have entered the "VPS margin", any free devices are now used to switch to the needed transponder. This improves cases where more than one VPS timer is about to start. - Fixed handling the VPS margin in case the event's duration is shorter than the margin. - Fixed handling VPS timers in case the primary device needs to switch to the timer's transponder. - Now avoiding the 'actual' device when starting a recording, so that a Transfer Mode for live tv isn't interrupted. - Fixed a typo in skins.h (thanks to Alexander Rieger). - cSkins::QueueMessage() called from a background thread with an empty message now clears all messages that have been previously queued by that thread and have not yet beed displayed (thanks to Alexander Rieger). - Fixed handling the color button texts when switching from the 'Schedule' menu of a channel without EPG info to the 'What's on now' menu (reported by Rolf Ahrenberg). - cMenuEditIntItem and cMenuEditChanItem can now be given strings to label the minimum and maximum values, and the case that no channel has been selected, respectively. - The initial channel and volume can now be defined in the "Setup/Miscellaneous" menu (based on a patch from Thomas Keil). - When hitting the end of a recording in fast forward mode, VDR no longer switches back to normal speed if the recording is already finished (thanks to Reinhard Nissl). - No longer calling cPlugin::ProcessArgs() if VDR is run with the --help or --version option, to avoid error messages from plugins (reported by Udo Richter). - Now checking whether there is any text before calling cStatus::MsgOsdTextItem() (reported by Joachim Wilke).
906 lines
25 KiB
C
906 lines
25 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 1.36 2006/04/09 13:10:02 kls Exp $
|
|
*/
|
|
|
|
#include "menuitems.h"
|
|
#include <ctype.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 = " abcdefghijklmnopqrstuvwxyz0123456789-.#~,/_@";
|
|
|
|
// --- cMenuEditItem ---------------------------------------------------------
|
|
|
|
cMenuEditItem::cMenuEditItem(const char *Name)
|
|
{
|
|
name = strdup(Name);
|
|
value = NULL;
|
|
}
|
|
|
|
cMenuEditItem::~cMenuEditItem()
|
|
{
|
|
free(name);
|
|
free(value);
|
|
}
|
|
|
|
void cMenuEditItem::SetValue(const char *Value)
|
|
{
|
|
free(value);
|
|
value = strdup(Value);
|
|
char *buffer = NULL;
|
|
asprintf(&buffer, "%s:\t%s", name, value);
|
|
SetText(buffer, false);
|
|
cStatus::MsgOsdCurrentItem(buffer);
|
|
}
|
|
|
|
// --- 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;
|
|
Key = NORMALKEY(Key);
|
|
switch (Key) {
|
|
case kNone: break;
|
|
case k0 ... k9:
|
|
if (fresh) {
|
|
*value = 0;
|
|
fresh = false;
|
|
}
|
|
newValue = *value * 10 + (Key - k0);
|
|
break;
|
|
case kLeft: // TODO might want to increase the delta if repeated quickly?
|
|
newValue = *value - 1;
|
|
fresh = true;
|
|
break;
|
|
case kRight:
|
|
newValue = *value + 1;
|
|
fresh = true;
|
|
break;
|
|
default:
|
|
if (*value < min) { *value = min; Set(); }
|
|
if (*value > max) { *value = max; Set(); }
|
|
return state;
|
|
}
|
|
if ((!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;
|
|
}
|
|
|
|
// --- cMenuEditChrItem ------------------------------------------------------
|
|
|
|
cMenuEditChrItem::cMenuEditChrItem(const char *Name, char *Value, const char *Allowed)
|
|
:cMenuEditItem(Name)
|
|
{
|
|
value = Value;
|
|
allowed = strdup(Allowed);
|
|
current = strchr(allowed, *Value);
|
|
if (!current)
|
|
current = allowed;
|
|
Set();
|
|
}
|
|
|
|
cMenuEditChrItem::~cMenuEditChrItem()
|
|
{
|
|
free(allowed);
|
|
}
|
|
|
|
void cMenuEditChrItem::Set(void)
|
|
{
|
|
char buf[2];
|
|
snprintf(buf, sizeof(buf), "%c", *value);
|
|
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)
|
|
{
|
|
orgValue = NULL;
|
|
value = Value;
|
|
length = Length;
|
|
allowed = strdup(Allowed);
|
|
pos = -1;
|
|
insert = uppercase = false;
|
|
newchar = true;
|
|
charMap = tr(" 0\t-.#~,/_@1\tabc2\tdef3\tghi4\tjkl5\tmno6\tpqrs7\ttuv8\twxyz9");
|
|
currentChar = NULL;
|
|
lastKey = kNone;
|
|
Set();
|
|
}
|
|
|
|
cMenuEditStrItem::~cMenuEditStrItem()
|
|
{
|
|
free(orgValue);
|
|
free(allowed);
|
|
}
|
|
|
|
void cMenuEditStrItem::SetHelpKeys(void)
|
|
{
|
|
if (InEditMode())
|
|
cSkinDisplay::Current()->SetButtons(tr("Button$ABC/abc"), tr(insert ? "Button$Overwrite" : "Button$Insert"), tr("Button$Delete"));
|
|
else
|
|
cSkinDisplay::Current()->SetButtons(NULL);
|
|
}
|
|
|
|
void cMenuEditStrItem::AdvancePos(void)
|
|
{
|
|
if (pos < length - 2 && pos < int(strlen(value)) ) {
|
|
if (++pos >= int(strlen(value))) {
|
|
if (pos >= 2 && value[pos - 1] == ' ' && value[pos - 2] == ' ')
|
|
pos--; // allow only two blanks at the end
|
|
else {
|
|
value[pos] = ' ';
|
|
value[pos + 1] = 0;
|
|
}
|
|
}
|
|
}
|
|
newchar = true;
|
|
if (!insert && isalpha(value[pos]))
|
|
uppercase = isupper(value[pos]);
|
|
}
|
|
|
|
void cMenuEditStrItem::Set(void)
|
|
{
|
|
char buf[1000];
|
|
|
|
if (InEditMode()) {
|
|
const cFont *font = cFont::GetFont(fontOsd);
|
|
strncpy(buf, value, pos);
|
|
snprintf(buf + pos, sizeof(buf) - pos - 2, insert && newchar ? "[]%c%s" : "[%c]%s", *(value + pos), value + pos + 1);
|
|
int width = cSkinDisplay::Current()->EditableWidth();
|
|
if (font->Width(buf) <= width) {
|
|
// the whole buffer fits on the screen
|
|
SetValue(buf);
|
|
return;
|
|
}
|
|
width -= font->Width('>'); // assuming '<' and '>' have the same with
|
|
int w = 0;
|
|
int i = 0;
|
|
int l = strlen(buf);
|
|
while (i < l && w <= width)
|
|
w += font->Width(buf[i++]);
|
|
if (i >= pos + 4) {
|
|
// the cursor fits on the screen
|
|
buf[i - 1] = '>';
|
|
buf[i] = 0;
|
|
SetValue(buf);
|
|
return;
|
|
}
|
|
// the cursor doesn't fit on the screen
|
|
w = 0;
|
|
if (buf[i = pos + 3]) {
|
|
buf[i] = '>';
|
|
buf[i + 1] = 0;
|
|
}
|
|
else
|
|
i--;
|
|
while (i >= 0 && w <= width)
|
|
w += font->Width(buf[i--]);
|
|
buf[++i] = '<';
|
|
SetValue(buf + i);
|
|
}
|
|
else
|
|
SetValue(value);
|
|
}
|
|
|
|
char cMenuEditStrItem::Inc(char c, bool Up)
|
|
{
|
|
const char *p = strchr(allowed, c);
|
|
if (!p)
|
|
p = allowed;
|
|
if (Up) {
|
|
if (!*++p)
|
|
p = allowed;
|
|
}
|
|
else if (--p < allowed)
|
|
p = allowed + strlen(allowed) - 1;
|
|
return *p;
|
|
}
|
|
|
|
eOSState cMenuEditStrItem::ProcessKey(eKeys Key)
|
|
{
|
|
bool SameKey = Key == lastKey;
|
|
if (Key != kNone)
|
|
lastKey = Key;
|
|
else if (!newchar && k0 <= NORMALKEY(lastKey) && NORMALKEY(lastKey) <= k9 && autoAdvanceTimeout.TimedOut()) {
|
|
AdvancePos();
|
|
newchar = true;
|
|
currentChar = NULL;
|
|
Set();
|
|
return osContinue;
|
|
}
|
|
switch (Key) {
|
|
case kRed: // Switch between upper- and lowercase characters
|
|
if (InEditMode()) {
|
|
if (!insert || !newchar) {
|
|
uppercase = !uppercase;
|
|
value[pos] = uppercase ? toupper(value[pos]) : tolower(value[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 current position; in insert mode it is the character to the right of cursor
|
|
if (InEditMode()) {
|
|
if (strlen(value) > 1) {
|
|
if (!insert || pos < int(strlen(value)) - 1)
|
|
memmove(value + pos, value + pos + 1, strlen(value) - pos);
|
|
// reduce position, if we removed the last character
|
|
if (pos == int(strlen(value)))
|
|
pos--;
|
|
}
|
|
else if (strlen(value) == 1)
|
|
value[0] = ' '; // This is the last character in the string, replace it with a blank
|
|
if (isalpha(value[pos]))
|
|
uppercase = isupper(value[pos]);
|
|
newchar = true;
|
|
}
|
|
else
|
|
return osUnknown;
|
|
break;
|
|
case kBlue|k_Repeat:
|
|
case kBlue: // consume the key only if in edit-mode
|
|
if (InEditMode())
|
|
;
|
|
else
|
|
return osUnknown;
|
|
break;
|
|
case kLeft|k_Repeat:
|
|
case kLeft: if (pos > 0) {
|
|
if (!insert || newchar)
|
|
pos--;
|
|
newchar = true;
|
|
}
|
|
if (!insert && isalpha(value[pos]))
|
|
uppercase = isupper(value[pos]);
|
|
break;
|
|
case kRight|k_Repeat:
|
|
case kRight: AdvancePos();
|
|
if (pos == 0) {
|
|
orgValue = strdup(value);
|
|
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 (int(strlen(value)) < length - 1) {
|
|
memmove(value + pos + 1, value + pos, strlen(value) - pos + 1);
|
|
value[pos] = ' ';
|
|
}
|
|
}
|
|
if (uppercase)
|
|
value[pos] = toupper(Inc(tolower(value[pos]), NORMALKEY(Key) == kUp));
|
|
else
|
|
value[pos] = Inc( value[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 (!SameKey) {
|
|
if (!newchar)
|
|
AdvancePos();
|
|
currentChar = NULL;
|
|
}
|
|
if (insert && newchar) {
|
|
// create a new character in insert mode
|
|
if (int(strlen(value)) < length - 1) {
|
|
memmove(value + pos + 1, value + pos, strlen(value) - pos + 1);
|
|
value[pos] = ' ';
|
|
}
|
|
}
|
|
if (!currentChar || !*currentChar || *currentChar == '\t') {
|
|
// find the beginning of the character map entry for Key
|
|
int n = Key - k0;
|
|
currentChar = charMap;
|
|
while (n > 0 && *currentChar) {
|
|
if (*currentChar++ == '\t')
|
|
n--;
|
|
}
|
|
}
|
|
if (*currentChar && *currentChar != '\t') {
|
|
value[pos] = *currentChar;
|
|
if (uppercase)
|
|
value[pos] = toupper(value[pos]);
|
|
currentChar++;
|
|
}
|
|
newchar = false;
|
|
autoAdvanceTimeout.Set(AUTO_ADVANCE_TIMEOUT);
|
|
}
|
|
else
|
|
return cMenuEditItem::ProcessKey(Key);
|
|
}
|
|
break;
|
|
case kBack:
|
|
case kOk: if (InEditMode()) {
|
|
if (Key == kBack && orgValue) {
|
|
strcpy(value, orgValue);
|
|
free(orgValue);
|
|
orgValue = NULL;
|
|
}
|
|
pos = -1;
|
|
newchar = true;
|
|
stripspace(value);
|
|
SetHelpKeys();
|
|
break;
|
|
}
|
|
// run into default
|
|
default: if (InEditMode() && BASICKEY(Key) == kKbd) {
|
|
int c = KEYKBD(Key);
|
|
if (c <= 0xFF) {
|
|
const char *p = strchr(allowed, tolower(c));
|
|
if (p) {
|
|
int l = strlen(value);
|
|
if (insert && l < length - 1)
|
|
memmove(value + pos + 1, value + pos, l - pos + 1);
|
|
value[pos] = c;
|
|
if (pos < length - 2)
|
|
pos++;
|
|
if (pos >= l) {
|
|
value[pos] = ' ';
|
|
value[pos + 1] = 0;
|
|
}
|
|
}
|
|
else {
|
|
switch (c) {
|
|
case 0x7F: // backspace
|
|
if (pos > 0) {
|
|
pos--;
|
|
return ProcessKey(kYellow);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
switch (c) {
|
|
case kfHome: pos = 0; break;
|
|
case kfEnd: pos = strlen(value) - 1; break;
|
|
case kfIns: return ProcessKey(kGreen);
|
|
case kfDel: return ProcessKey(kYellow);
|
|
}
|
|
}
|
|
}
|
|
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())
|
|
{
|
|
noneString = NoneString;
|
|
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);
|
|
}
|
|
else
|
|
SetValue(noneString);
|
|
}
|
|
|
|
eOSState cMenuEditChanItem::ProcessKey(eKeys Key)
|
|
{
|
|
int delta = 1;
|
|
|
|
switch (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;
|
|
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();
|
|
}
|
|
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;
|
|
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));
|
|
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);
|
|
}
|
|
|
|
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:
|
|
if (*weekdays) {
|
|
*value = cTimer::SetTime(oldvalue ? oldvalue : now, 0);
|
|
oldvalue = 0;
|
|
*weekdays = 0;
|
|
}
|
|
else {
|
|
*weekdays = days[cTimer::GetWDay(*value)];
|
|
dayindex = FindDayIndex(*weekdays);
|
|
oldvalue = *value;
|
|
*value = 0;
|
|
}
|
|
}
|
|
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;
|
|
}
|
|
}
|
|
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;
|
|
}
|
|
|
|
// --- cMenuSetupPage --------------------------------------------------------
|
|
|
|
cMenuSetupPage::cMenuSetupPage(void)
|
|
:cOsdMenu("", 33)
|
|
{
|
|
plugin = NULL;
|
|
}
|
|
|
|
void cMenuSetupPage::SetSection(const char *Section)
|
|
{
|
|
char buf[40];
|
|
snprintf(buf, sizeof(buf), "%s - %s", tr("Setup"), Section);
|
|
SetTitle(buf);
|
|
}
|
|
|
|
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)
|
|
{
|
|
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)
|
|
{
|
|
if (plugin)
|
|
plugin->SetupStore(Name, Value);
|
|
}
|
|
|
|
void cMenuSetupPage::SetupStore(const char *Name, int Value)
|
|
{
|
|
if (plugin)
|
|
plugin->SetupStore(Name, Value);
|
|
}
|