summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--HISTORY3
-rw-r--r--Makefile8
-rw-r--r--channelcolumn.c17
-rw-r--r--channelcolumn.h6
-rw-r--r--config.c18
-rw-r--r--config.h6
-rw-r--r--detailview.c53
-rw-r--r--detailview.h15
-rw-r--r--dummygrid.c1
-rw-r--r--epggrid.c24
-rw-r--r--epggrid.h6
-rw-r--r--footer.c4
-rw-r--r--grid.h7
-rw-r--r--headergrid.c4
-rw-r--r--icons/arrow_left.pngbin0 -> 428 bytes
-rw-r--r--icons/arrow_right.pngbin0 -> 438 bytes
-rw-r--r--icons/delete_active.pngbin0 -> 58636 bytes
-rw-r--r--icons/delete_inactive.pngbin0 -> 11721 bytes
-rw-r--r--icons/edit_active.pngbin0 -> 16127 bytes
-rw-r--r--icons/edit_inactive.pngbin0 -> 53216 bytes
-rw-r--r--icons/icon_backspace.pngbin0 -> 2012 bytes
-rw-r--r--icons/icon_del_ins.pngbin0 -> 1680 bytes
-rw-r--r--icons/icon_shift.pngbin0 -> 1484 bytes
-rw-r--r--icons/info_active.pngbin0 -> 11487 bytes
-rw-r--r--icons/info_inactive.pngbin0 -> 9034 bytes
-rw-r--r--icons/no.pngbin0 -> 52583 bytes
-rw-r--r--icons/record_active.pngbin0 -> 7098 bytes
-rw-r--r--icons/record_inactive.pngbin0 -> 5897 bytes
-rw-r--r--icons/yes.pngbin0 -> 35529 bytes
-rw-r--r--imageloader.c13
-rw-r--r--imageloader.h1
-rw-r--r--osdmanager.c31
-rwxr-xr-xpo/de_DE.po344
-rw-r--r--recmanager.c598
-rw-r--r--recmanager.h53
-rw-r--r--recmenu.c525
-rw-r--r--recmenu.h61
-rw-r--r--recmenuitem.c2016
-rw-r--r--recmenuitem.h465
-rw-r--r--recmenumanager.c521
-rw-r--r--recmenumanager.h38
-rw-r--r--services/epgsearch.h61
-rw-r--r--setup.c6
-rw-r--r--styledpixmap.c8
-rw-r--r--styledpixmap.h37
-rw-r--r--switchtimer.c109
-rw-r--r--switchtimer.h30
-rw-r--r--themes/tvguide-darkblue.theme12
-rw-r--r--themes/tvguide-default.theme12
-rw-r--r--themes/tvguide-keepitsimple.theme14
-rw-r--r--themes/tvguide-nOpacity.theme12
-rw-r--r--themes/tvguide-nOpacitydarkred.theme12
-rw-r--r--themes/tvguide-nOpacitygreen.theme12
-rw-r--r--themes/tvguide-nOpacityiceblue.theme15
-rw-r--r--timeline.c10
-rw-r--r--timer.c46
-rw-r--r--timer.h15
-rw-r--r--tools.c370
-rw-r--r--tvguide.c12
-rw-r--r--tvguideosd.c132
-rw-r--r--tvguideosd.h2
61 files changed, 5564 insertions, 201 deletions
diff --git a/HISTORY b/HISTORY
index 9950b38..4698d9f 100644
--- a/HISTORY
+++ b/HISTORY
@@ -43,7 +43,8 @@ VDR Plugin 'tvguide' Revision History
- Added setup option to switch functionality of keys "Blue" and "OK"
- Setup option to hide schedules time display in horizontal EPG grids
-Version 0.0.6
+2013-07-08: Version 0.0.6
- added frame around scaled video picture
- added theme "keep it simple" (thanks @saman)
- display of additional EPG pictures in detailed epg view
+- Introduction of "Search & Recording" Menu
diff --git a/Makefile b/Makefile
index df0ba33..b668830 100644
--- a/Makefile
+++ b/Makefile
@@ -21,6 +21,7 @@ LIBDIR = $(call PKGCFG,libdir)
LOCDIR = $(call PKGCFG,locdir)
PLGCFG = $(call PKGCFG,plgcfg)
VDRCONFDIR= $(call PKGCFG,configdir)
+PLGRESDIR = $(call PKGCFG,resdir)/plugins/$(PLUGIN)
TMPDIR ?= /tmp
### The compiler options:
@@ -100,6 +101,7 @@ i18n: $(I18Nmo) $(I18Npot)
install-i18n: $(I18Nmsgs)
### Targets:
+
$(SOFILE): $(OBJS)
$(CXX) $(CXXFLAGS) $(LDFLAGS) -shared $(OBJS) $(LIBS) -o $@
@@ -110,7 +112,11 @@ install-themes:
@mkdir -p $(DESTDIR)$(VDRCONFDIR)/themes
cp themes/* $(DESTDIR)$(VDRCONFDIR)/themes
-install: install-lib install-i18n install-themes
+install-icons:
+ mkdir -p $(DESTDIR)$(PLGRESDIR)/icons
+ cp -r icons/* $(DESTDIR)$(PLGRESDIR)/icons
+
+install: install-lib install-i18n install-themes install-icons
dist: $(I18Npo) clean
@-rm -rf $(TMPDIR)/$(ARCHIVE)
diff --git a/channelcolumn.c b/channelcolumn.c
index dae36a0..8ed34b0 100644
--- a/channelcolumn.c
+++ b/channelcolumn.c
@@ -5,6 +5,7 @@ cChannelColumn::cChannelColumn(int num, const cChannel *channel, cMyTime *myTime
this->num = num;
this->myTime = myTime;
hasTimer = channel->HasTimer();
+ hasSwitchTimer = SwitchTimers.ChannelInSwitchList(channel);
schedulesLock = new cSchedulesLock(false, 100);
header = NULL;
}
@@ -339,6 +340,22 @@ cGrid *cChannelColumn::addDummyGrid(time_t start, time_t end, cGrid *firstGrid,
return dummy;
}
+void cChannelColumn::SetTimers() {
+ hasTimer = channel->HasTimer();
+ hasSwitchTimer = SwitchTimers.ChannelInSwitchList(channel);
+ for (cGrid *grid = grids.First(); grid; grid = grids.Next(grid)) {
+ bool gridHadTimer = grid->HasTimer();
+ grid->SetTimer();
+ if (gridHadTimer != grid->HasTimer())
+ grid->SetDirty();
+ bool gridHadSwitchTimer = grid->HasSwitchTimer();
+ grid->SetSwitchTimer();
+ if (gridHadSwitchTimer != grid->HasSwitchTimer())
+ grid->SetDirty();
+ grid->Draw();
+ }
+}
+
void cChannelColumn::dumpGrids() {
esyslog("tvguide: ------Channel %s: %d entires ---------", channel->Name(), grids.Count());
int i=1;
diff --git a/channelcolumn.h b/channelcolumn.h
index a84f9a6..1dbd174 100644
--- a/channelcolumn.h
+++ b/channelcolumn.h
@@ -16,6 +16,7 @@ private:
cSchedulesLock *schedulesLock;
const cSchedules *schedules;
bool hasTimer;
+ bool hasSwitchTimer;
cGrid *addEpgGrid(const cEvent *event, cGrid *firstGrid, bool color);
cGrid *addDummyGrid(time_t start, time_t end, cGrid *firstGrid, bool color);
public:
@@ -42,8 +43,11 @@ public:
void ClearOutdatedEnd();
int GetNum() {return num;};
void SetNum(int num) {this->num = num;};
- void setTimer() {hasTimer = true;};
+ void setTimer() {hasTimer = channel->HasTimer();};
bool HasTimer() { return hasTimer; };
+ void setSwitchTimer() {hasSwitchTimer = SwitchTimers.ChannelInSwitchList(channel);};
+ bool HasSwitchTimer() { return hasSwitchTimer; };
+ void SetTimers();
void clearGrids();
void dumpGrids();
};
diff --git a/config.c b/config.c
index ac767fa..408374f 100644
--- a/config.c
+++ b/config.c
@@ -81,6 +81,8 @@ cTvguideConfig::cTvguideConfig() {
FontGridHorizontalSmallDelta = 0;
FontTimeLineDateHorizontalDelta = 0;
FontTimeLineTimeHorizontalDelta = 0;
+ FontRecMenuItemDelta = 0;
+ FontRecMenuItemSmallDelta = 0;
//Common Fonts
FontButton = NULL;
FontDetailView = NULL;
@@ -102,7 +104,9 @@ cTvguideConfig::cTvguideConfig() {
FontGridHorizontalSmall = NULL;
FontTimeLineDateHorizontal = NULL;
FontTimeLineTimeHorizontal = NULL;
-
+ //Fonts for RecMenu
+ FontRecMenuItem = NULL;
+ FontRecMenuItemSmall = NULL;
timeFormat = 1;
themeIndex = 4;
useBlending = 2;
@@ -133,6 +137,8 @@ cTvguideConfig::~cTvguideConfig() {
delete FontGridHorizontalSmall;
delete FontTimeLineDateHorizontal;
delete FontTimeLineTimeHorizontal;
+ delete FontRecMenuItem;
+ delete FontRecMenuItemSmall;
}
void cTvguideConfig::setDynamicValues(int width, int height) {
@@ -207,7 +213,9 @@ void cTvguideConfig::SetFonts(void){
FontGridHorizontalSmall = cFont::CreateFont(*fontname, rowHeight/4 + FontGridHorizontalSmallDelta);
FontTimeLineDateHorizontal = cFont::CreateFont(*fontname, timeLineHeight/2 + 5 + FontTimeLineDateHorizontalDelta);
FontTimeLineTimeHorizontal = cFont::CreateFont(*fontname, timeLineHeight/2 + FontTimeLineTimeHorizontalDelta);
-
+ //Fonts for RecMenu
+ FontRecMenuItem = cFont::CreateFont(*fontname, osdHeight/30 + FontRecMenuItemDelta);
+ FontRecMenuItemSmall = cFont::CreateFont(*fontname, osdHeight/40 + FontRecMenuItemSmallDelta);
}
void cTvguideConfig::SetBlending(void) {
@@ -228,6 +236,10 @@ void cTvguideConfig::SetImagesPath(cString path) {
epgImagePath = path;
}
+void cTvguideConfig::SetIconsPath(cString path) {
+ iconPath = path;
+}
+
void cTvguideConfig::loadTheme() {
cThemes themes;
themes.Load(*cString("tvguide"));
@@ -295,6 +307,8 @@ bool cTvguideConfig::SetupParse(const char *Name, const char *Value) {
else if (strcmp(Name, "FontGridHorizontalSmallDelta") == 0) FontGridHorizontalSmallDelta = atoi(Value);
else if (strcmp(Name, "FontTimeLineDateHorizontalDelta") == 0) FontTimeLineDateHorizontalDelta = atoi(Value);
else if (strcmp(Name, "FontTimeLineTimeHorizontalDelta") == 0) FontTimeLineTimeHorizontalDelta = atoi(Value);
+ else if (strcmp(Name, "FontRecMenuItemDelta") == 0) FontRecMenuItemDelta = atoi(Value);
+ else if (strcmp(Name, "FontRecMenuItemSmallDelta") == 0) FontRecMenuItemSmallDelta = atoi(Value);
else if (strcmp(Name, "displayRerunsDetailEPGView") == 0) displayRerunsDetailEPGView = atoi(Value);
else if (strcmp(Name, "numReruns") == 0) numReruns = atoi(Value);
else if (strcmp(Name, "useSubtitleRerun") == 0) useSubtitleRerun = atoi(Value);
diff --git a/config.h b/config.h
index 3269e50..3afd857 100644
--- a/config.h
+++ b/config.h
@@ -10,6 +10,7 @@ class cTvguideConfig {
~cTvguideConfig();
void SetLogoPath(cString path);
void SetImagesPath(cString path);
+ void SetIconsPath(cString path);
void SetBlending(void);
int showMainMenuEntry;
int osdWidth;
@@ -61,6 +62,7 @@ class cTvguideConfig {
int epgImageWidthLarge;
int epgImageHeightLarge;
cString epgImagePath;
+ cString iconPath;
int fontIndex;
const char *fontNameDefault;
int FontButtonDelta;
@@ -83,6 +85,8 @@ class cTvguideConfig {
int FontGridHorizontalSmallDelta;
int FontTimeLineDateHorizontalDelta;
int FontTimeLineTimeHorizontalDelta;
+ int FontRecMenuItemDelta;
+ int FontRecMenuItemSmallDelta;
const cFont *FontChannelHeader;
const cFont *FontChannelHeaderHorizontal;
const cFont *FontChannelGroups;
@@ -103,6 +107,8 @@ class cTvguideConfig {
const cFont *FontDetailHeader;
const cFont *FontMessageBox;
const cFont *FontMessageBoxLarge;
+ const cFont *FontRecMenuItem;
+ const cFont *FontRecMenuItemSmall;
int timeFormat;
int themeIndex;
int useBlending;
diff --git a/detailview.c b/detailview.c
index f06229f..0ce16f0 100644
--- a/detailview.c
+++ b/detailview.c
@@ -2,12 +2,9 @@
#include <sstream>
#include "detailview.h"
-cDetailView::cDetailView(cGrid *grid) {
- this->grid = grid;
- this->event = grid->GetEvent();
+cDetailView::cDetailView(const cEvent *event) {
+ this->event = event;
imgScrollBar = NULL;
- FrameTime = 40; // ms
- FadeTime = 500; // ms
borderWidth = 100; //px
scrollBarWidth = 40;
headerHeight = max (40 + 3 * tvguideConfig.FontDetailHeader->Height(), // border + 3 Lines
@@ -48,24 +45,18 @@ bool cDetailView::setContentDrawportHeight() {
void cDetailView::createPixmaps() {
header = new cStyledPixmap(osdManager.requestPixmap(5, cRect(borderWidth, borderWidth, tvguideConfig.osdWidth - 2*borderWidth, headerHeight), cRect::Null));
- header->SetAlpha(0);
headerLogo = osdManager.requestPixmap(6, cRect(borderWidth, borderWidth, tvguideConfig.osdWidth - 2*borderWidth, headerHeight), cRect::Null);
headerLogo->Fill(clrTransparent);
- headerLogo->SetAlpha(0);
headerBack = osdManager.requestPixmap(4, cRect(borderWidth, borderWidth, tvguideConfig.osdWidth - 2*borderWidth, headerHeight), cRect::Null);
- headerBack->SetAlpha(0);
headerBack->Fill(clrBlack);
header->setColor(theme.Color(clrHeader), theme.Color(clrHeaderBlending));
content = osdManager.requestPixmap(5, cRect(borderWidth, borderWidth + headerHeight, tvguideConfig.osdWidth - 2*borderWidth - scrollBarWidth, tvguideConfig.osdHeight-2*borderWidth-headerHeight),
cRect(0,0, tvguideConfig.osdWidth - 2*borderWidth - scrollBarWidth, max(heightContent, tvguideConfig.osdHeight-2*borderWidth-headerHeight)));
- content->SetAlpha(0);
header->setColor(theme.Color(clrHeader), theme.Color(clrHeaderBlending));
scrollBar = osdManager.requestPixmap(5, cRect(tvguideConfig.osdWidth-borderWidth-scrollBarWidth, borderWidth + headerHeight, scrollBarWidth, tvguideConfig.osdHeight-2*borderWidth-headerHeight));
- scrollBar->SetAlpha(0);
footer = osdManager.requestPixmap(5, cRect(borderWidth, borderWidth + headerHeight + content->ViewPort().Height(), tvguideConfig.osdWidth - 2*borderWidth, 3));
- footer->SetAlpha(0);
footer->Fill(theme.Color(clrBorder));
}
@@ -79,7 +70,8 @@ void cDetailView::drawHeader() {
cImageLoader imgLoader;
bool logoDrawn = false;
if (!tvguideConfig.hideChannelLogos) {
- if (imgLoader.LoadLogo(grid->column->getChannel()->Name(), logoWidth, logoHeight)) {
+ cString channelName = Channels.GetByChannelID(event->ChannelID())->Name();
+ if (imgLoader.LoadLogo(*channelName, logoWidth, logoHeight)) {
cImage logo = imgLoader.GetImage();
headerLogo->DrawImage(cPoint(10, (header->Height() - logoHeight)/2), logo);
logoDrawn = true;
@@ -293,28 +285,21 @@ void cDetailView::drawEPGPictures(int height) {
}
}
-void cDetailView::Action(void) {
- drawHeader();
- drawContent();
- drawScrollbar();
- uint64_t Start = cTimeMs::Now();
- while (true) {
- uint64_t Now = cTimeMs::Now();
- cPixmap::Lock();
- double t = min(double(Now - Start) / FadeTime, 1.0);
- int Alpha = t * ALPHA_OPAQUE;
- header->SetAlpha(Alpha);
- headerBack->SetAlpha(Alpha);
- headerLogo->SetAlpha(Alpha);
- content->SetAlpha(Alpha);
- scrollBar->SetAlpha(Alpha);
- footer->SetAlpha(Alpha);
- osdManager.flush();
- cPixmap::Unlock();
- int Delta = cTimeMs::Now() - Now;
- if (Delta < FrameTime)
- cCondWait::SleepMs(FrameTime - Delta);
- if ((Now - Start) > FadeTime)
+eOSState cDetailView::ProcessKey(eKeys Key) {
+ eOSState state = osContinue;
+ switch (Key & ~k_Repeat) {
+ case kUp:
+ scrollUp();
+ osdManager.flush();
+ break;
+ case kDown:
+ scrollDown();
+ osdManager.flush();
+ break;
+ case kOk:
+ case kBack:
+ state = osEnd;
break;
}
+ return state;
} \ No newline at end of file
diff --git a/detailview.h b/detailview.h
index 3d72795..6b59bbb 100644
--- a/detailview.h
+++ b/detailview.h
@@ -5,9 +5,8 @@
class cEpgGrid;
-class cDetailView : public cThread {
+class cDetailView {
private:
- cGrid *grid;
cStyledPixmap *header;
cPixmap *headerLogo;
cPixmap *headerBack;
@@ -16,8 +15,6 @@ private:
cPixmap *footer;
const cEvent *event;
cImage *imgScrollBar;
- int FrameTime;
- int FadeTime;
cTextWrapper description;
cTextWrapper reruns;
int borderWidth;
@@ -29,19 +26,19 @@ private:
int numEPGPics;
bool contentScrollable;
void loadReruns(void);
- void drawHeader();
- void drawContent();
- void drawScrollbar();
int heightEPGPics(void);
void drawEPGPictures(int height);
cImage *createScrollbar(int width, int height, tColor clrBgr, tColor clrBlend);
- virtual void Action(void);
public:
- cDetailView(cGrid *grid);
+ cDetailView(const cEvent *event);
virtual ~cDetailView(void);
void createPixmaps();
+ void drawHeader();
+ void drawContent();
+ void drawScrollbar();
void scrollUp();
void scrollDown();
+ eOSState ProcessKey(eKeys Key);
};
#endif //__TVGUIDE_DETAILVIEW_H \ No newline at end of file
diff --git a/dummygrid.c b/dummygrid.c
index 97a8d1a..42025e0 100644
--- a/dummygrid.c
+++ b/dummygrid.c
@@ -5,6 +5,7 @@ cDummyGrid::cDummyGrid(cChannelColumn *c, time_t start, time_t end) : cGrid(c) {
this->end = end;
strText = tr("No EPG Information available");
dummy = true;
+ hasTimer = false;
}
cDummyGrid::~cDummyGrid(void) {
diff --git a/epggrid.c b/epggrid.c
index 97a57f8..434a612 100644
--- a/epggrid.c
+++ b/epggrid.c
@@ -7,6 +7,9 @@ cEpgGrid::cEpgGrid(cChannelColumn *c, const cEvent *event) : cGrid(c) {
hasTimer = false;
if (column->HasTimer())
hasTimer = event->HasTimer();
+ hasSwitchTimer = false;
+ if (column->HasSwitchTimer())
+ hasSwitchTimer = SwitchTimers.EventInSwitchList(event);
dummy = false;
}
@@ -89,8 +92,6 @@ void cEpgGrid::drawText() {
pixmap->DrawText(cPoint(borderWidth, borderWidth + offset + i*textHeight), extText->GetLine(i), colorText, colorTextBack, tvguideConfig.FontGridSmall);
}
}
- if (hasTimer)
- drawRecIcon();
} else if (tvguideConfig.displayMode == eHorizontal) {
if (Width()/tvguideConfig.minutePixel < 10) {
int titleY = (tvguideConfig.rowHeight - tvguideConfig.FontGridHorizontal->Height())/2;
@@ -107,14 +108,21 @@ void cEpgGrid::drawText() {
}
pixmap->DrawText(cPoint(borderWidth, titleY), *strTitle, colorText, colorTextBack, tvguideConfig.FontGridHorizontal);
}
+ if (hasSwitchTimer)
+ drawIcon("Switch", theme.Color(clrButtonYellow));
+ if (hasTimer)
+ drawIcon("REC", theme.Color(clrButtonRed));
}
-void cEpgGrid::drawRecIcon() {
- cString recIconText("REC");
- int width = tvguideConfig.FontGrid->Width(*recIconText)+2*borderWidth;
- int height = tvguideConfig.FontGrid->Height()+10;
- pixmap->DrawRectangle( cRect(Width() - width - borderWidth, Height() - height - borderWidth, width, height), theme.Color(clrButtonRed));
- pixmap->DrawText(cPoint(Width() - width, Height() - height - borderWidth/2), *recIconText, theme.Color(clrFont), theme.Color(clrButtonRed), tvguideConfig.FontGrid);
+void cEpgGrid::drawIcon(cString iconText, tColor color) {
+
+ const cFont *font = (tvguideConfig.displayMode == eVertical)
+ ?tvguideConfig.FontGrid
+ :tvguideConfig.FontGridHorizontalSmall;
+ int textWidth = font->Width(*iconText)+2*borderWidth;
+ int textHeight = font->Height()+10;
+ pixmap->DrawRectangle( cRect(Width() - textWidth - borderWidth, Height() - textHeight - borderWidth, textWidth, textHeight), color);
+ pixmap->DrawText(cPoint(Width() - textWidth, Height() - textHeight - borderWidth/2), *iconText, theme.Color(clrFont), color, font);
}
cString cEpgGrid::getTimeString(void) {
diff --git a/epggrid.h b/epggrid.h
index d7cae70..0465d06 100644
--- a/epggrid.h
+++ b/epggrid.h
@@ -8,9 +8,8 @@ private:
const cEvent *event;
cTextWrapper *extText;
cString timeString;
- bool hasTimer;
void drawText();
- void drawRecIcon();
+ void drawIcon(cString iconText, tColor color);
time_t Duration(void) { return event->Duration(); };
public:
cEpgGrid(cChannelColumn *c, const cEvent *event);
@@ -21,7 +20,8 @@ public:
const cEvent *GetEvent() {return event;};
time_t StartTime() { return event->StartTime(); };
time_t EndTime() { return event->EndTime(); };
- void setTimer() {hasTimer = true;};
+ void SetTimer() {hasTimer = event->HasTimer();};
+ void SetSwitchTimer() {hasSwitchTimer = SwitchTimers.EventInSwitchList(event);};
cString getTimeString(void);
void debug();
};
diff --git a/footer.c b/footer.c
index 4c26336..7a19053 100644
--- a/footer.c
+++ b/footer.c
@@ -38,7 +38,7 @@ void cFooter::DrawButton(const char *text, tColor color, tColor borderColor, int
}
void cFooter::drawRedButton() {
- cString text(tr("Set Timer"));
+ cString text(tr("Search & Rec"));
DrawButton(*text, theme.Color(clrButtonRed), theme.Color(clrButtonRedBorder), 0);
}
@@ -78,4 +78,4 @@ void cFooter::UpdateGroupButtons(const cChannel *channel) {
drawGreenButton(channelGroups->GetPrev(group));
drawYellowButton(channelGroups->GetNext(group));
}
-} \ No newline at end of file
+}
diff --git a/grid.h b/grid.h
index 42ad41d..d51271b 100644
--- a/grid.h
+++ b/grid.h
@@ -12,6 +12,8 @@ protected:
bool isColor1;
bool active;
bool dirty;
+ bool hasTimer;
+ bool hasSwitchTimer;
bool intersects(cGrid *neighbor);
virtual time_t Duration(void) {};
virtual void drawText(void) {};
@@ -37,10 +39,13 @@ public:
virtual void SetStartTime(time_t start) {};
virtual void SetEndTime(time_t end) {};
int calcOverlap(cGrid *neighbor);
- virtual void setTimer() {};
+ virtual void SetTimer() {};
+ virtual void SetSwitchTimer() {};
virtual cString getText(void) { return cString("");};
virtual cString getTimeString(void) { return cString("");};
bool Active(void) { return active; };
+ bool HasTimer() {return hasTimer;};
+ bool HasSwitchTimer() {return hasSwitchTimer;};
bool isDummy() { return dummy; };
virtual void debug() {};
};
diff --git a/headergrid.c b/headergrid.c
index 280ea46..4bb25c8 100644
--- a/headergrid.c
+++ b/headergrid.c
@@ -24,8 +24,8 @@ void cHeaderGrid::createBackground(int num) {
width = tvguideConfig.channelHeaderWidth;
height = tvguideConfig.rowHeight;
}
- pixmap = osdManager.requestPixmap(2, cRect(x, y, width, height));
- pixmapLogo = osdManager.requestPixmap(3, cRect(x, y, width, height));
+ pixmap = osdManager.requestPixmap(1, cRect(x, y, width, height));
+ pixmapLogo = osdManager.requestPixmap(2, cRect(x, y, width, height));
if ((!pixmap) || (!pixmapLogo)){
return;
}
diff --git a/icons/arrow_left.png b/icons/arrow_left.png
new file mode 100644
index 0000000..a65e47d
--- /dev/null
+++ b/icons/arrow_left.png
Binary files differ
diff --git a/icons/arrow_right.png b/icons/arrow_right.png
new file mode 100644
index 0000000..97fa123
--- /dev/null
+++ b/icons/arrow_right.png
Binary files differ
diff --git a/icons/delete_active.png b/icons/delete_active.png
new file mode 100644
index 0000000..b01dc5c
--- /dev/null
+++ b/icons/delete_active.png
Binary files differ
diff --git a/icons/delete_inactive.png b/icons/delete_inactive.png
new file mode 100644
index 0000000..b327f07
--- /dev/null
+++ b/icons/delete_inactive.png
Binary files differ
diff --git a/icons/edit_active.png b/icons/edit_active.png
new file mode 100644
index 0000000..5b3b667
--- /dev/null
+++ b/icons/edit_active.png
Binary files differ
diff --git a/icons/edit_inactive.png b/icons/edit_inactive.png
new file mode 100644
index 0000000..d4f59a1
--- /dev/null
+++ b/icons/edit_inactive.png
Binary files differ
diff --git a/icons/icon_backspace.png b/icons/icon_backspace.png
new file mode 100644
index 0000000..e20b7bd
--- /dev/null
+++ b/icons/icon_backspace.png
Binary files differ
diff --git a/icons/icon_del_ins.png b/icons/icon_del_ins.png
new file mode 100644
index 0000000..3d06162
--- /dev/null
+++ b/icons/icon_del_ins.png
Binary files differ
diff --git a/icons/icon_shift.png b/icons/icon_shift.png
new file mode 100644
index 0000000..998d7fa
--- /dev/null
+++ b/icons/icon_shift.png
Binary files differ
diff --git a/icons/info_active.png b/icons/info_active.png
new file mode 100644
index 0000000..7f1ccf7
--- /dev/null
+++ b/icons/info_active.png
Binary files differ
diff --git a/icons/info_inactive.png b/icons/info_inactive.png
new file mode 100644
index 0000000..9a79e95
--- /dev/null
+++ b/icons/info_inactive.png
Binary files differ
diff --git a/icons/no.png b/icons/no.png
new file mode 100644
index 0000000..3630d29
--- /dev/null
+++ b/icons/no.png
Binary files differ
diff --git a/icons/record_active.png b/icons/record_active.png
new file mode 100644
index 0000000..8c42156
--- /dev/null
+++ b/icons/record_active.png
Binary files differ
diff --git a/icons/record_inactive.png b/icons/record_inactive.png
new file mode 100644
index 0000000..6720a6f
--- /dev/null
+++ b/icons/record_inactive.png
Binary files differ
diff --git a/icons/yes.png b/icons/yes.png
new file mode 100644
index 0000000..ec30010
--- /dev/null
+++ b/icons/yes.png
Binary files differ
diff --git a/imageloader.c b/imageloader.c
index 31e0d0c..292d183 100644
--- a/imageloader.c
+++ b/imageloader.c
@@ -59,8 +59,19 @@ bool cImageLoader::LoadAdditionalEPGImage(cString name) {
return true;
}
+bool cImageLoader::LoadIcon(const char *cIcon, int size) {
+ if (size==0)
+ return false;
+ bool success = false;
+ success = LoadImage(cString(cIcon), tvguideConfig.iconPath, "png");
+ if (!success)
+ return false;
+ buffer.sample(Geometry(size, size));
+ return true;
+}
+
bool cImageLoader::DrawBackground(tColor back, tColor blend, int width, int height) {
- if ((width < 1) || (height < 1))
+ if ((width < 1) || (height < 1) || (width > 1920) || (height > 1080))
return false;
Color Back = Argb2Color(back);
Color Blend = Argb2Color(blend);
diff --git a/imageloader.h b/imageloader.h
index a38a5a0..bc2b7dd 100644
--- a/imageloader.h
+++ b/imageloader.h
@@ -17,6 +17,7 @@ public:
bool LoadLogo(const char *logo, int width, int height);
bool LoadEPGImage(int eventID);
bool LoadAdditionalEPGImage(cString name);
+ bool LoadIcon(const char *cIcon, int size);
bool DrawBackground(tColor back, tColor blend, int width, int height);
private:
Image buffer;
diff --git a/osdmanager.c b/osdmanager.c
index 8fdd7f6..c74162d 100644
--- a/osdmanager.c
+++ b/osdmanager.c
@@ -1,6 +1,3 @@
-#include <string>
-#include <sstream>
-
#ifndef __TVGUIDE_OSDMANAGER_H
#define __TVGUIDE_OSDMANAGER_H
@@ -55,32 +52,4 @@ void cOsdManager::releasePixmap(cPixmap *pixmap) {
if (!pixmap)
return;
osd->DestroyPixmap(pixmap);
-}
-
-static std::string CutText(std::string text, int width, const cFont *font) {
- if (width <= font->Size())
- return text.c_str();
- if (font->Width(text.c_str()) < width)
- return text.c_str();
- cTextWrapper twText;
- twText.Set(text.c_str(), font, width);
- std::string cuttedTextNative = twText.GetLine(0);
- std::stringstream sstrText;
- sstrText << cuttedTextNative << "...";
- std::string cuttedText = sstrText.str();
- int actWidth = font->Width(cuttedText.c_str());
- if (actWidth > width) {
- int overlap = actWidth - width;
- int charWidth = font->Width(".");
- if (charWidth == 0)
- charWidth = 1;
- int cutChars = overlap / charWidth;
- if (cutChars > 0) {
- cuttedTextNative = cuttedTextNative.substr(0, cuttedTextNative.length() - cutChars);
- std::stringstream sstrText2;
- sstrText2 << cuttedTextNative << "...";
- cuttedText = sstrText2.str();
- }
- }
- return cuttedText;
} \ No newline at end of file
diff --git a/po/de_DE.po b/po/de_DE.po
index e075e74..d1a58c6 100755
--- a/po/de_DE.po
+++ b/po/de_DE.po
@@ -3,7 +3,7 @@ msgid ""
msgstr ""
"Project-Id-Version: vdr-tvguide 0.0.1\n"
"Report-Msgid-Bugs-To: <see README>\n"
-"POT-Creation-Date: 2013-06-03 09:00+0200\n"
+"POT-Creation-Date: 2013-07-07 13:43+0200\n"
"PO-Revision-Date: 2012-08-25 17:49+0200\n"
"Last-Translator: Horst\n"
"Language-Team: \n"
@@ -21,8 +21,8 @@ msgstr "Wiederholungen dieser Sendung"
msgid "No EPG Information available"
msgstr "Keine EPG Daten verfügbar"
-msgid "Set Timer"
-msgstr "Aufnehmen"
+msgid "Search & Rec"
+msgstr "Search & Rec"
msgid "Channels back"
msgstr "Kanäle zurück"
@@ -36,6 +36,336 @@ msgstr "Umschalten"
msgid "Detailed EPG"
msgstr "Detailiertes EPG"
+msgid "Transp."
+msgstr "Transp."
+
+msgid "Timer Conflict"
+msgstr "Timer Konflikt"
+
+msgid "all Channels"
+msgstr "alle Kanäle"
+
+msgid "unknown channel"
+msgstr "unbekannter Kanal"
+
+msgid "Duration"
+msgstr "Dauer"
+
+msgid "min"
+msgstr "min"
+
+msgid "recorded at"
+msgstr "aufgenommen am"
+
+msgid "from"
+msgstr "von"
+
+msgid "Instant Record"
+msgstr "Sofortaufnahme"
+
+msgid "Delete Timer"
+msgstr "Timer löschen"
+
+msgid "Edit Timer"
+msgstr "Timer bearbeiten"
+
+msgid "Create Series Timer"
+msgstr "Serientimer anlegen"
+
+msgid "Create Search Timer"
+msgstr "Suchtimer anlegen"
+
+msgid "Create Switch Timer"
+msgstr "Umschalttimer anlegen"
+
+msgid "Delete Switch Timer"
+msgstr "Umschalttimer löschen"
+
+msgid "Search"
+msgstr "Suchen"
+
+msgid "Search in Recordings"
+msgstr "In Aufnahmen suchen"
+
+msgid "Check for Timer Conflicts"
+msgstr "Auf Timerkoflikte prüfen"
+
+msgid "Timer created"
+msgstr "Timer angelegt"
+
+msgid "Timer NOT created"
+msgstr "Timer NICHT angelegt"
+
+msgid "OK"
+msgstr "OK"
+
+msgid "Timer deleted"
+msgstr "Timer gelöscht"
+
+msgid "Timer"
+msgstr "Timer"
+
+msgid "still recording - really delete?"
+msgstr "Aufzeichnung läuft - wirklich löschen?"
+
+msgid "Yes"
+msgstr "Ja"
+
+msgid "No"
+msgstr "Nein"
+
+msgid "One"
+msgstr "Ein"
+
+msgid "detected"
+msgstr "gefunden"
+
+msgid "Timer Conflicts"
+msgstr "Timerkonflikte"
+
+msgid "Show conflict"
+msgstr "Konflikt zeigen"
+
+msgid "timers involved"
+msgstr "Timer beteiligt"
+
+msgid "Ignore Conflicts"
+msgstr "Konflikte ignorieren"
+
+msgid "Ignore Conflict"
+msgstr "Konflikt ignorieren"
+
+msgid "No Timer Conflicts found"
+msgstr "Keine Timerkonflikte gefunden"
+
+msgid "Close"
+msgstr "Schließen"
+
+msgid "Timer Active"
+msgstr "Timer aktiv"
+
+msgid "Priority"
+msgstr "Priorität"
+
+msgid "Lifetime"
+msgstr "Lebensdauer"
+
+msgid "Day"
+msgstr "Tag"
+
+msgid "Timer start time"
+msgstr "Timer Start Zeit"
+
+msgid "Timer stop time"
+msgstr "Timer Stop Zeit"
+
+msgid "Save"
+msgstr "Speichern"
+
+msgid "Cancel"
+msgstr "Abbrechen"
+
+msgid "Create Series Timer based on"
+msgstr "Serientimer anlegen basierend auf"
+
+msgid "Channel"
+msgstr "Kanal"
+
+msgid "Series Timer start time"
+msgstr "Serientimer Start Zeit"
+
+msgid "Series Timer stop time"
+msgstr "Serientimer Stop Zeit"
+
+msgid "Days to record"
+msgstr "Tage"
+
+msgid "Day to start"
+msgstr "Beginnen am"
+
+msgid "Create Timer"
+msgstr "Timer anlegen"
+
+msgid "Series Timer created"
+msgstr "Serientimer angelegt"
+
+msgid "Start"
+msgstr "Start"
+
+msgid "Stop"
+msgstr "Stop"
+
+msgid "Configure Search Timer based on"
+msgstr "Suchtimer konfigurieren basierend auf"
+
+msgid "Search Expression:"
+msgstr "Suchausdruck:"
+
+msgid "Continue"
+msgstr "Weiter"
+
+msgid "Configure Search Timer for Search String"
+msgstr "Suchtimer konfigurieren für Suchbegriff"
+
+msgid "Manually configure Options"
+msgstr "Optionen manuell konfigurieren"
+
+msgid "Use Template"
+msgstr "Template benutzen"
+
+msgid "Creating Search Timer"
+msgstr "Suchtimer anlegen"
+
+msgid "Search Term"
+msgstr "Suchbegriff"
+
+msgid "Using Template"
+msgstr "Template"
+
+msgid "Display Results for Search Timer"
+msgstr "Ergebnisse für Suchtimer anzeigen"
+
+msgid "Use other Template"
+msgstr "Anderes Template benutzen"
+
+msgid "Configure Search Timer Options for Search String"
+msgstr "Suchtimer Optionen konfigurieren für Suchbegriff"
+
+msgid "whole term must appear"
+msgstr "vollständiger Ausdruck"
+
+msgid "all terms must exist"
+msgstr "alle Worte"
+
+msgid "one term must exist"
+msgstr "ein Wort"
+
+msgid "exact match"
+msgstr "exakt"
+
+msgid "regular expression"
+msgstr "Regulärer Ausdruck"
+
+msgid "Search Mode"
+msgstr "Suchmodus"
+
+msgid "Use Title"
+msgstr "Titel benutzen"
+
+msgid "Use Subtitle"
+msgstr "Untertitel benutzen"
+
+msgid "Use Description"
+msgstr "Beschreibung benutzen"
+
+msgid "Limit Channels"
+msgstr "Kanäle einschränken"
+
+msgid "Start Channel"
+msgstr "Startkanal"
+
+msgid "Stop Channel"
+msgstr "Stopkanal"
+
+msgid "Use Time"
+msgstr "Zeit benutzen"
+
+msgid "Start after"
+msgstr "Beginn nach"
+
+msgid "Start before"
+msgstr "Beginn vor"
+
+msgid "search results for Search Timer"
+msgstr "Treffer für Suchtimer"
+
+msgid "search result for Search Timer"
+msgstr "Treffer für Suchtimer"
+
+msgid "Nothing found for Search String"
+msgstr "Keine Treffer für Suchbegriff"
+
+msgid "Search Timer sucessfully created."
+msgstr "Suchtimer erfolgreich angelegt"
+
+msgid "Search Timer update initialised"
+msgstr "Suchtimer update initialisiert"
+
+msgid "Search Timer NOT sucessfully created"
+msgstr "Suchtimer NICHT erfolgreich angelegt"
+
+msgid "Configure Options for Switchtimer"
+msgstr "Optionen für Umschalttimer konfigurieren"
+
+msgid "Minutes before switching"
+msgstr "Minuten vor umschalten"
+
+msgid "switch"
+msgstr "umschalten"
+
+msgid "announce only"
+msgstr "nur ankündigen"
+
+msgid "ask for switch"
+msgstr "vor umschalten fragen"
+
+msgid "Switch Mode"
+msgstr "Umschaltmodus"
+
+msgid "Create"
+msgstr "Anlegen"
+
+msgid "Switch Timer sucessfully created"
+msgstr "Umschalttimer erfolgreich angelegt"
+
+msgid "Switch Timer NOT sucessfully created"
+msgstr "Umschalttimer NICHT erfolgreich angelegt"
+
+msgid "Switch Timer deleted"
+msgstr "Umschalttimer gelöscht"
+
+msgid "Show Search Options"
+msgstr "Suchoptionen anzeigen"
+
+msgid "Perform Search"
+msgstr "Suche ausführen"
+
+msgid "Channel to Search"
+msgstr "Suche auf Kanal"
+
+msgid "Search in title"
+msgstr "In Titel suchen"
+
+msgid "Search in Subtitle"
+msgstr "In Untertitel suchen"
+
+msgid "Search in Description"
+msgstr "In Beschreibung suchen"
+
+msgid "search results for"
+msgstr "Suchergebnisse für"
+
+msgid "search result for"
+msgstr "Suchergebnis für"
+
+msgid "Adapt Search"
+msgstr "Suche anpassen"
+
+msgid "Found"
+msgstr " "
+
+msgid "recording"
+msgstr "Aufnahme gefunden"
+
+msgid "recordings"
+msgstr "Aufnahmen gefunden"
+
+msgid "for"
+msgstr "für"
+
+msgid "No recordings found for"
+msgstr "Keine Aufnahmen gefunden für"
+
msgid "General Settings"
msgstr "Allgemeine Einstellungen"
@@ -234,8 +564,8 @@ msgstr "Zeitleiste Datum Schriftgröße"
msgid "Timeline Time Font Size"
msgstr "Zeitleiste Zeit Schriftgröße"
-msgid "Timer not set! There is already a timer for this item."
-msgstr "Timer wurde nicht gesetzt! Es existiert bereits ein Timer für diese Sendung"
+msgid "Search & Recording Menu Font Size"
+msgstr "Suchen & Aufnehmen Menu Schriftgröße"
-msgid "Timer set"
-msgstr "Timer gesetzt"
+msgid "Search & Recording Menu Small Font Size"
+msgstr "Suchen & Aufnehmen Menu kleine Schriftgröße"
diff --git a/recmanager.c b/recmanager.c
new file mode 100644
index 0000000..df65cc3
--- /dev/null
+++ b/recmanager.c
@@ -0,0 +1,598 @@
+#include <string>
+#include <vector>
+#include "recmanager.h"
+
+static int CompareRecording(const void *p1, const void *p2) {
+ return (int)((*(cRecording **)p1)->Start() - (*(cRecording **)p2)->Start());
+}
+
+bool TVGuideTimerConflict::timerInvolved(int involvedID) {
+ int numConflicts = timerIDs.size();
+ for (int i=0; i<numConflicts; i++) {
+ if (timerIDs[i] == involvedID)
+ return true;
+ }
+ return false;
+}
+
+cRecManager::cRecManager(void) {
+ epgSearchPlugin = NULL;
+ epgSearchAvailable = false;
+}
+
+cRecManager::~cRecManager(void) {
+}
+
+void cRecManager::SetEPGSearchPlugin(void) {
+ epgSearchPlugin = cPluginManager::GetPlugin("epgsearch");
+ if (epgSearchPlugin) {
+ epgSearchAvailable = true;
+ }
+}
+
+cTimer *cRecManager::createTimer(const cEvent *event) {
+ cTimer *timer = new cTimer(event);
+ Timers.Add(timer);
+ Timers.SetModified();
+ isyslog("timer %s added (active)", *timer->ToDescr());
+ return timer;
+}
+
+void cRecManager::DeleteTimer(const cEvent *event) {
+ cTimer *t = Timers.GetMatch(event);
+ if (!t)
+ return;
+ DeleteTimer(t);
+}
+
+void cRecManager::DeleteTimer(int timerID) {
+ cTimer *t = Timers.Get(timerID);
+ if (!t)
+ return;
+ DeleteTimer(t);
+}
+
+void cRecManager::DeleteTimer(cTimer *timer) {
+ if (timer->Recording()) {
+ timer->Skip();
+ cRecordControls::Process(time(NULL));
+ }
+ isyslog("timer %s deleted", *timer->ToDescr());
+ Timers.Del(timer, true);
+ Timers.SetModified();
+}
+
+void cRecManager::SaveTimer(cTimer *timer, cRecMenu *menu) {
+ if (!timer)
+ return;
+
+ bool active = menu->GetBoolValue(1);
+ int prio = menu->GetIntValue(2);
+ int lifetime = menu->GetIntValue(3);
+ time_t day = menu->GetTimeValue(4);
+ int start = menu->GetIntValue(5);
+ int stop = menu->GetIntValue(6);
+
+ timer->SetDay(day);
+ timer->SetStart(start);
+ timer->SetStop(stop);
+ timer->SetPriority(prio);
+ timer->SetLifetime(lifetime);
+
+ if (timer->HasFlags(tfActive) && !active)
+ timer->ClrFlags(tfActive);
+ else if (!timer->HasFlags(tfActive) && active)
+ timer->SetFlags(tfActive);
+
+ timer->SetEventFromSchedule();
+ Timers.SetModified();
+}
+
+bool cRecManager::IsRecorded(const cEvent *event) {
+ cTimer *timer = Timers.GetMatch(event);
+ if (!timer)
+ return false;
+ return timer->Recording();
+}
+
+std::vector<TVGuideTimerConflict> cRecManager::CheckTimerConflict(void) {
+ /* TIMERCONFLICT FORMAT:
+ The result list looks like this for example when we have 2 timer conflicts at one time:
+ 1190232780:152|30|50#152#45:45|10|50#152#45
+ '1190232780' is the time of the conflict in seconds since 1970-01-01.
+ It's followed by list of timers that have a conflict at this time:
+ '152|30|50#1 int editTimer(cTimer *timer, bool active, int prio, int start, int stop);
+ 52#45' is the description of the first conflicting timer. Here:
+ '152' is VDR's timer id of this timer as returned from VDR's LSTT command
+ '30' is the percentage of recording that would be done (0...100)
+ '50#152#45' is the list of concurrent timers at this conflict
+ '45|10|50#152#45' describes the next conflict
+ */
+ std::vector<TVGuideTimerConflict> results;
+ if (!epgSearchAvailable)
+ return results;
+ Epgsearch_services_v1_1 *epgSearch = new Epgsearch_services_v1_1;
+ if (epgSearchPlugin->Service("Epgsearch-services-v1.1", epgSearch)) {
+ std::list<std::string> conflicts = epgSearch->handler->TimerConflictList();
+ int numConflicts = conflicts.size();
+ if (numConflicts > 0) {
+ for (std::list<std::string>::iterator it=conflicts.begin(); it != conflicts.end(); ++it) {
+ TVGuideTimerConflict sConflict;
+ splitstring s(it->c_str());
+ std::vector<std::string> flds = s.split(':');
+ if (flds.size() < 2)
+ continue;
+ sConflict.time = atoi(flds[0].c_str());
+ splitstring s2(flds[1].c_str());
+ std::vector<std::string> flds2 = s2.split('|');
+ if (flds2.size() < 3)
+ continue;
+ sConflict.timerID = atoi(flds2[0].c_str());
+ sConflict.percentPossible = atoi(flds2[1].c_str());
+ splitstring s3(flds2[2].c_str());
+ std::vector<std::string> flds3 = s3.split('#');
+ std::vector<int> timerIDs;
+ for (int k = 0; k < flds3.size(); k++) {
+ timerIDs.push_back(atoi(flds3[k].c_str()) - 1);
+ }
+ sConflict.timerIDs = timerIDs;
+ results.push_back(sConflict);
+ }
+ }
+ }
+ delete epgSearch;
+
+ int numConflicts = results.size();
+ time_t startTime = 0;
+ time_t endTime = 0;
+ for (int i=0; i < numConflicts; i++) {
+ cTimeInterval *unionSet = NULL;
+ int numTimers = results[i].timerIDs.size();
+ for (int j=0; j < numTimers; j++) {
+ const cTimer *timer = Timers.Get(results[i].timerIDs[j]);
+ if (timer) {
+ if (!unionSet) {
+ unionSet = new cTimeInterval(timer->StartTime(), timer->StopTime());
+ } else {
+ cTimeInterval *timerInterval = new cTimeInterval(timer->StartTime(), timer->StopTime());
+ cTimeInterval *newUnion = unionSet->Union(timerInterval);
+ delete unionSet;
+ delete timerInterval;
+ unionSet = newUnion;
+ }
+ }
+ }
+ results[i].timeStart = unionSet->Start();
+ results[i].timeStop = unionSet->Stop();
+ delete unionSet;
+
+ cTimeInterval *intersect = NULL;
+ for (int j=0; j < numTimers; j++) {
+ const cTimer *timer = Timers.Get(results[i].timerIDs[j]);
+ if (timer) {
+ if (!intersect) {
+ intersect = new cTimeInterval(timer->StartTime(), timer->StopTime());
+ } else {
+ cTimeInterval *timerInterval = new cTimeInterval(timer->StartTime(), timer->StopTime());
+ cTimeInterval *newIntersect = intersect->Intersect(timerInterval);
+ if (newIntersect) {
+ delete intersect;
+ intersect = newIntersect;
+ }
+ delete timerInterval;
+ }
+ }
+ }
+ results[i].overlapStart = intersect->Start();
+ results[i].overlapStop = intersect->Stop();
+ delete intersect;
+ }
+
+ return results;
+}
+
+cTimer *cRecManager::CreateSeriesTimer(cRecMenu *menu) {
+ bool active = menu->GetBoolValue(1);
+ int channelNumber = menu->GetIntValue(2);
+ int start = menu->GetIntValue(3);
+ int stop = menu->GetIntValue(4);
+ int weekdays = menu->GetIntValue(5);
+ time_t tday = menu->GetTimeValue(6);
+ int prio = menu->GetIntValue(7);
+ int lifetime = menu->GetIntValue(8);
+
+ cChannel *channel = Channels.GetByNumber(channelNumber);
+ cTimer *seriesTimer = new cTimer(false, false, channel);
+
+ seriesTimer->SetDay(tday);
+ seriesTimer->SetStart(start);
+ seriesTimer->SetStop(stop);
+ seriesTimer->SetPriority(prio);
+ seriesTimer->SetLifetime(lifetime);
+ seriesTimer->SetWeekDays(weekdays);
+ seriesTimer->SetFile("TITLE EPISODE");
+ if (active)
+ seriesTimer->SetFlags(tfActive);
+ else
+ seriesTimer->SetFlags(tfNone);
+ seriesTimer->SetEventFromSchedule();
+ Timers.Add(seriesTimer);
+ Timers.SetModified();
+ return seriesTimer;
+}
+
+std::vector<TVGuideEPGSearchTemplate> cRecManager::ReadEPGSearchTemplates(void) {
+ cString ConfigDir = cPlugin::ConfigDirectory("epgsearch");
+ cString epgsearchConf = "epgsearchtemplates.conf";
+ cString fileName = AddDirectory(*ConfigDir, *epgsearchConf);
+ std::vector<TVGuideEPGSearchTemplate> epgTemplates;
+ if (access(fileName, F_OK) == 0) {
+ FILE *f = fopen(fileName, "r");
+ if (f) {
+ char *s;
+ cReadLine ReadLine;
+ while ((s = ReadLine.Read(f)) != NULL) {
+ char *p = strchr(s, '#');
+ if (p)
+ *p = 0;
+ stripspace(s);
+ try {
+ if (!isempty(s)) {
+ std::string templ = s;
+ int posID = templ.find_first_of(":");
+ int posName = templ.find_first_of(":", posID+1);
+ std::string name = templ.substr(posID+1, posName - posID - 1);
+ std::string templValue = templ.substr(posName);
+ TVGuideEPGSearchTemplate tmp;
+ tmp.name = name;
+ tmp.templValue = templValue;
+ epgTemplates.push_back(tmp);
+ }
+ } catch (...){}
+ }
+ }
+ }
+ return epgTemplates;
+}
+
+std::string cRecManager::BuildEPGSearchString(cString searchString, std::string templValue) {
+ std::stringstream searchTimerString;
+ searchTimerString << "0:";
+ searchTimerString << *searchString;
+ searchTimerString << templValue;
+ return searchTimerString.str();
+}
+
+std::string cRecManager::BuildEPGSearchString(cString searchString, cRecMenu *menu) {
+ int searchMode = menu->GetIntValue(0);
+ bool useTitle = menu->GetBoolValue(1);
+ bool useSubTitle = menu->GetBoolValue(2);
+ bool useDescription = menu->GetBoolValue(3);
+ bool limitChannels = menu->GetBoolValue(4);
+ int startChannel = -1;
+ int stopChannel = -1;
+ if (limitChannels) {
+ startChannel = menu->GetIntValue(5);
+ stopChannel = menu->GetIntValue(6);
+ }
+ int after = 0;
+ int before = 0;
+ bool limitTime = (limitChannels)?menu->GetBoolValue(7):menu->GetBoolValue(5);
+ if (limitTime) {
+ after = (limitChannels)?menu->GetIntValue(8):menu->GetIntValue(6);
+ before = (limitChannels)?menu->GetIntValue(9):menu->GetIntValue(7);
+ }
+
+ std::stringstream searchTimerString;
+ //1 - unique search timer id
+ searchTimerString << "0:";
+ //2 - the search term
+ searchTimerString << *searchString;
+ //3 - use time? 0/1
+ //4 - start time in HHMM
+ //5 - stop time in HHMM
+ if (limitTime) {
+ searchTimerString << ":1:" << after << ":" << before << ":";
+ } else {
+ searchTimerString << ":0:::";
+ }
+ //6 - use channel? 0 = no, 1 = Interval, 2 = Channel group, 3 = FTA only
+ //7 - if 'use channel' = 1 then channel id[|channel id] in VDR format,
+ // one entry or min/max entry separated with |, if 'use channel' = 2
+ // then the channel group name
+ if (limitChannels) {
+ searchTimerString << "1:";
+ cChannel *startChan = Channels.GetByNumber(startChannel);
+ cChannel *stopChan = Channels.GetByNumber(stopChannel);
+ searchTimerString << *(startChan->GetChannelID().ToString());
+ searchTimerString << "|";
+ searchTimerString << *(stopChan->GetChannelID().ToString()) << ":";
+ } else {
+ searchTimerString << "0::";
+ }
+ //8 - match case? 0/1
+ searchTimerString << ":0";
+ /*9 - search mode:
+ 0 - the whole term must appear as substring
+ 1 - all single terms (delimiters are blank,',', ';', '|' or '~')
+ must exist as substrings.
+ 2 - at least one term (delimiters are blank, ',', ';', '|' or '~')
+ must exist as substring.
+ 3 - matches exactly
+ 4 - regular expression */
+ searchTimerString << searchMode << ":";
+ //10 - use title? 0/1
+ if (useTitle)
+ searchTimerString << "1:";
+ else
+ searchTimerString << "0:";
+ //11 - use subtitle? 0/1
+ if (useSubTitle)
+ searchTimerString << "1:";
+ else
+ searchTimerString << "0:";
+ // 12 - use description? 0/1
+ if (useDescription)
+ searchTimerString << "1:";
+ else
+ searchTimerString << "0:";
+ //13 - use duration? 0/1
+ //14 - min duration in hhmm
+ //15 - max duration in hhmm
+ searchTimerString << "0:::";
+ //16 - use as search timer? 0/1
+ searchTimerString << "1:";
+ //17 - use day of week? 0/1
+ //18 - day of week (0 = Sunday, 1 = Monday...;
+ // -1 Sunday, -2 Monday, -4 Tuesday, ...; -7 Sun, Mon, Tue)
+ searchTimerString << "0::";
+ //19 - use series recording? 0/1
+ searchTimerString << "1:";
+ //20 - directory for recording
+ searchTimerString << ":";
+ //21 - priority of recording
+ //22 - lifetime of recording
+ searchTimerString << "99:99:";
+ //23 - time margin for start in minutes
+ //24 - time margin for stop in minutes
+ searchTimerString << "5:5:";
+ //25 - use VPS? 0/1
+ searchTimerString << "0:";
+ /*26 - action:
+ 0 = create a timer
+ 1 = announce only via OSD (no timer)
+ 2 = switch only (no timer)
+ 3 = announce via OSD and switch (no timer)
+ 4 = announce via mail*/
+ searchTimerString << "0:";
+ /*27 - use extended EPG info? 0/1
+ 28 - extended EPG info values. This entry has the following format
+ (delimiter is '|' for each category, '#' separates id and value):
+ 1 - the id of the extended EPG info category as specified in
+ epgsearchcats.conf
+ 2 - the value of the extended EPG info category
+ (a ':' will be translated to "!^colon^!", e.g. in "16:9") */
+ searchTimerString << "0::";
+ /*29 - avoid repeats? 0/1
+ 30 - allowed repeats
+ 31 - compare title when testing for a repeat? 0/1
+ 32 - compare subtitle when testing for a repeat? 0/1/2
+ 0 - no
+ 1 - yes
+ 2 - yes, if present
+ 33 - compare description when testing for a repeat? 0/1
+ 34 - compare extended EPG info when testing for a repeat?
+ This entry is a bit field of the category IDs.
+ 35 - accepts repeats only within x days */
+ searchTimerString << "1:1:1:2:1:::";
+ /*36 - delete a recording automatically after x days
+ 37 - but keep this number of recordings anyway
+ 38 - minutes before switch (if action = 2)
+ 39 - pause if x recordings already exist
+ 40 - blacklist usage mode (0 none, 1 selection, 2 all)
+ 41 - selected blacklist IDs separated with '|'
+ 42 - fuzzy tolerance value for fuzzy searching
+ 43 - use this search in favorites menu (0 no, 1 yes)
+ 44 - id of a menu search template
+ 45 - auto deletion mode (0 don't delete search timer, 1 delete after given
+ count of recordings, 2 delete after given days after first recording)
+ 46 - count of recordings after which to delete the search timer
+ 47 - count of days after the first recording after which to delete the search
+ timer
+ 48 - first day where the search timer is active (see parameter 16)
+ 49 - last day where the search timer is active (see parameter 16)
+ 50 - ignore missing EPG categories? 0/1
+ 51 - unmute sound if off when used as switch timer
+ 52 - percentage of match when comparing the summary of two events (with 'avoid repeats')
+ 53 - HEX representation of the content descriptors, each descriptor ID is represented with 2 chars
+ 54 - compare date when testing for a repeat? (0=no, 1=same day, 2=same week, 3=same month) */
+ searchTimerString << "0::::0:::0::0:::::::::0";
+
+ //esyslog("tvguide: epgsearch String: %s", searchTimerString.str().c_str());
+
+ return searchTimerString.str();
+}
+
+const cEvent **cRecManager::PerformSearchTimerSearch(std::string epgSearchString, int &numResults) {
+ if (!epgSearchAvailable)
+ return NULL;
+ const cEvent **searchResults = NULL;
+ Epgsearch_services_v1_1 *epgSearch = new Epgsearch_services_v1_1;
+ if (epgSearchPlugin->Service("Epgsearch-services-v1.1", epgSearch)) {
+ std::list<std::string> results = epgSearch->handler->QuerySearch(epgSearchString);
+ numResults = results.size();
+ if (numResults > 0) {
+ searchResults = new const cEvent *[numResults];
+ cSchedulesLock *schedulesLock;
+ const cSchedules *schedules;
+ schedules = cSchedules::Schedules(*schedulesLock);
+ const cEvent *event = NULL;
+ int index=0;
+ for (std::list<std::string>::iterator it=results.begin(); it != results.end(); ++it) {
+ try {
+ splitstring s(it->c_str());
+ std::vector<std::string> flds = s.split(':', 1);
+ int eventID = atoi(flds[1].c_str());
+ std::string channelID = flds[7];
+ tChannelID chanID = tChannelID::FromString(channelID.c_str());
+ cChannel *channel = Channels.GetByChannelID(chanID);
+ if (channel) {
+ const cSchedule *Schedule = NULL;
+ Schedule = schedules->GetSchedule(channel);
+ event = Schedule->GetEvent(eventID);
+ if (event) {
+ searchResults[index] = event;
+ } else
+ return NULL;
+ } else
+ return NULL;
+ index++;
+ } catch (...){}
+ }
+ }
+ }
+ return searchResults;
+}
+
+const cEvent **cRecManager::PerformSearch(cRecMenu *menu, bool withOptions, int &numResults) {
+ if (epgSearchAvailable) {
+ cString searchString = menu->GetStringValue(1);
+ Epgsearch_searchresults_v1_0 data;
+ data.query = (char *)*searchString;
+ int mode = 0;
+ int channelNr = 0;
+ bool useTitle = true;
+ bool useSubTitle = true;
+ bool useDescription = false;
+ if (withOptions) {
+ mode = menu->GetIntValue(2);
+ channelNr = menu->GetIntValue(3);
+ useTitle = menu->GetBoolValue(4);
+ useSubTitle = menu->GetBoolValue(5);
+ useDescription = menu->GetBoolValue(6);
+ }
+ data.mode = mode;
+ data.channelNr = channelNr;
+ data.useTitle = useTitle;
+ data.useSubTitle = useSubTitle;
+ data.useDescription = useDescription;
+
+ if (epgSearchPlugin->Service("Epgsearch-searchresults-v1.0", &data)) {
+ cList<Epgsearch_searchresults_v1_0::cServiceSearchResult> *list = data.pResultList;
+ int numElements = list->Count();
+ const cEvent **searchResults = NULL;
+ if (numElements > 0) {
+ searchResults = new const cEvent *[numElements];
+ numResults = numElements;
+ int index = 0;
+ for (Epgsearch_searchresults_v1_0::cServiceSearchResult *r = list->First(); r ; r = list->Next(r)) {
+ searchResults[index] = r->event;
+ index++;
+ }
+ }
+ delete list;
+ return searchResults;
+ }
+ }
+ return NULL;
+}
+
+int cRecManager::CreateSearchTimer(std::string epgSearchString) {
+ int timerID = -1;
+ if (!epgSearchAvailable)
+ return timerID;
+ Epgsearch_services_v1_1 *epgSearch = new Epgsearch_services_v1_1;
+ if (epgSearchPlugin->Service("Epgsearch-services-v1.1", epgSearch)) {
+ timerID = epgSearch->handler->AddSearchTimer(epgSearchString);
+ }
+ return timerID;
+}
+
+void cRecManager::UpdateSearchTimers(void) {
+ if (epgSearchAvailable) {
+ Epgsearch_updatesearchtimers_v1_0 data;
+ data.showMessage = false;
+ epgSearchPlugin->Service("Epgsearch-updatesearchtimers-v1.0", &data);
+ }
+}
+
+// announceOnly: 0 = switch, 1 = announce only, 2 = ask for switch
+bool cRecManager::CreateSwitchTimer(const cEvent *event, cRecMenu *menu) {
+ int switchMinsBefore = menu->GetIntValue(1);
+ int announceOnly = menu->GetIntValue(2);
+ if (epgSearchAvailable) {
+ Epgsearch_switchtimer_v1_0 data;
+ data.event = event;
+ data.mode = 1;
+ data.switchMinsBefore = switchMinsBefore;
+ data.announceOnly = announceOnly;
+ data.success = false;
+ epgSearchPlugin->Service("Epgsearch-switchtimer-v1.0", &data);
+ cSwitchTimer *t = new cSwitchTimer(event);
+ SwitchTimers.Add(t);
+ return data.success;
+ }
+ return false;
+}
+
+void cRecManager::DeleteSwitchTimer(const cEvent *event) {
+ SwitchTimers.DeleteSwitchTimer(event);
+ if (epgSearchAvailable) {
+ Epgsearch_switchtimer_v1_0 data;
+ data.event = event;
+ data.mode = 2;
+ data.switchMinsBefore = 0;
+ data.announceOnly = 0;
+ data.success = false;
+ epgSearchPlugin->Service("Epgsearch-switchtimer-v1.0", &data);
+ }
+}
+
+cRecording **cRecManager::SearchForRecordings(cString searchString, int &numResults) {
+
+ cRecording **matchingRecordings = NULL;
+ int num = 0;
+ numResults = 0;
+
+ for (cRecording *recording = Recordings.First(); recording; recording = Recordings.Next(recording)) {
+ std::string s1 = recording->Name();
+ std::string s2 = *searchString;
+ if (s1.empty() || s2.empty()) continue;
+
+ // tolerance for fuzzy searching: 90% of the shorter text length, but at least 1
+ int tolerance = std::max(1, (int)std::min(s1.size(), s2.size()) / 10);
+
+ bool match = FindIgnoreCase(s1, s2) >= 0 || FindIgnoreCase(s2, s1) >= 0;
+
+ if (!match) {
+ AFUZZY af = { NULL, NULL, NULL, NULL, NULL, NULL, { 0 }, { 0 }, 0, 0, 0, 0, 0, 0 };
+ if (s1.size() > 32) s1 = s1.substr(0, 32);
+ afuzzy_init(s1.c_str(), tolerance, 0, &af);
+ /* Checking substring */
+ int res = afuzzy_checkSUB(s2.c_str(), &af);
+ afuzzy_free(&af);
+ match = (res > 0);
+ }
+
+ if (!match) {
+ AFUZZY af = { NULL, NULL, NULL, NULL, NULL, NULL, { 0 }, { 0 }, 0, 0, 0, 0, 0, 0 };
+ if (s2.size() > 32) s2 = s2.substr(0, 32);
+ afuzzy_init(s2.c_str(), tolerance, 0, &af);
+ /* Checking substring */
+ int res = afuzzy_checkSUB(s1.c_str(), &af);
+ afuzzy_free(&af);
+ match = (res > 0);
+ }
+
+ if (match) {
+ matchingRecordings = (cRecording **)realloc(matchingRecordings, (num + 1) * sizeof(cRecording *));
+ matchingRecordings[num++] = recording;
+ }
+ }
+ if (num > 0) {
+ qsort(matchingRecordings, num, sizeof(cRecording *), CompareRecording);
+ numResults = num;
+ return matchingRecordings;
+ }
+ return NULL;
+} \ No newline at end of file
diff --git a/recmanager.h b/recmanager.h
new file mode 100644
index 0000000..0b010c4
--- /dev/null
+++ b/recmanager.h
@@ -0,0 +1,53 @@
+#ifndef __TVGUIDE_RECMMANAGER_H
+#define __TVGUIDE_RECMMANAGER_H
+
+class TVGuideTimerConflict {
+public:
+ time_t time;
+ time_t timeStart;
+ time_t timeStop;
+ time_t overlapStart;
+ time_t overlapStop;
+ int percentPossible;
+ int timerID;
+ std::vector<int> timerIDs;
+ bool timerInvolved(int involvedID);
+};
+
+struct TVGuideEPGSearchTemplate {
+public:
+ std::string name;
+ std::string templValue;
+};
+
+// --- cRecManager -------------------------------------------------------------
+class cRecManager {
+private:
+ cPlugin *epgSearchPlugin;
+ bool epgSearchAvailable;
+ void DeleteTimer(cTimer *timer);
+public:
+ cRecManager (void);
+ void SetEPGSearchPlugin(void);
+ bool EpgSearchAvailable(void) {return epgSearchAvailable;};
+ cTimer *createTimer(const cEvent *event);
+ void DeleteTimer(const cEvent *event);
+ void DeleteTimer(int timerID);
+ void SaveTimer(cTimer *timer, cRecMenu *menu);
+ bool IsRecorded(const cEvent *event);
+ std::vector<TVGuideTimerConflict> CheckTimerConflict(void);
+ cTimer *CreateSeriesTimer(cRecMenu *menu);
+ std::string BuildEPGSearchString(cString searchString, cRecMenu *menu);
+ std::string BuildEPGSearchString(cString searchString, std::string templValue);
+ const cEvent **PerformSearchTimerSearch(std::string epgSearchString, int &numResults);
+ const cEvent **PerformSearch(cRecMenu *menu, bool withOptions, int &numResults);
+ std::vector<TVGuideEPGSearchTemplate> ReadEPGSearchTemplates(void);
+ int CreateSearchTimer(std::string epgSearchString);
+ void UpdateSearchTimers(void);
+ bool CreateSwitchTimer(const cEvent *event, cRecMenu *menu);
+ void DeleteSwitchTimer(const cEvent *event);
+ cRecording **SearchForRecordings(cString searchString, int &numResults);
+ virtual ~cRecManager (void);
+};
+
+#endif //__TVGUIDE_RECMMANAGER_H \ No newline at end of file
diff --git a/recmenu.c b/recmenu.c
new file mode 100644
index 0000000..66a5a84
--- /dev/null
+++ b/recmenu.c
@@ -0,0 +1,525 @@
+#include "recmenu.h"
+
+// --- cRecMenu -------------------------------------------------------------
+
+cRecMenu::cRecMenu(void) {
+ border = 10;
+ height = 2*border;
+ headerHeight = 0;
+ footerHeight = 0;
+ scrollHeight = 0;
+ scrollItemHeight = 0;
+ scrollable = false;
+ scrollbarWidth = 3 * border;
+ pixmapScrollBar = NULL;
+ imgScrollBar = NULL;
+ startIndex = 0;
+ stopIndex = 0;
+ numItems = 0;
+ header = NULL;
+ footer = NULL;
+}
+
+cRecMenu::~cRecMenu(void) {
+ if (header)
+ delete header;
+ menuItems.Clear();
+ if (footer)
+ delete footer;
+ if (pixmapScrollBar)
+ osdManager.releasePixmap(pixmapScrollBar);
+ if (imgScrollBar)
+ delete imgScrollBar;
+}
+
+void cRecMenu::SetWidthPercent(int percentOSDWidth) {
+ width = tvguideConfig.osdWidth * percentOSDWidth / 100;
+ x = (tvguideConfig.osdWidth - width) / 2;
+}
+
+void cRecMenu::SetWidthPixel(int pixel) {
+ width = pixel;
+ x = (tvguideConfig.osdWidth - width) / 2;
+}
+
+int cRecMenu::CalculateOptimalWidth(void) {
+ int optWidth = 0;
+ for (cRecMenuItem *item = menuItems.First(); item; item = menuItems.Next(item)) {
+ int itemWidth = item->GetWidth();
+ if (itemWidth > optWidth)
+ optWidth = itemWidth;
+ }
+ return optWidth;
+}
+
+
+void cRecMenu::AddMenuItem(cRecMenuItem *item, cRecMenuItem *before) {
+ if (!before)
+ menuItems.Add(item);
+ else
+ menuItems.Ins(item, before);
+}
+
+void cRecMenu::AddMenuItemScroll(cRecMenuItem *item) {
+ scrollHeight += item->GetHeight();
+ stopIndex++;
+ numItems++;
+ if (scrollItemHeight == 0)
+ scrollItemHeight = item->GetHeight();
+ menuItems.Add(item);
+}
+
+bool cRecMenu::CheckHeight(void) {
+ int nextHeight = headerHeight + footerHeight + scrollHeight + 2*border + 150;
+ if (nextHeight > tvguideConfig.osdHeight) {
+ scrollable = true;
+ return false;
+ }
+ return true;
+}
+
+void cRecMenu::CalculateHeight(void) {
+ height = 2*border;
+ if (header)
+ height += headerHeight;
+ for (cRecMenuItem *item = menuItems.First(); item; item = menuItems.Next(item)) {
+ height += item->GetHeight();
+ }
+ if (footer)
+ height += footerHeight;
+ y = (tvguideConfig.osdHeight - height) / 2;
+
+ if (scrollable) {
+ width += scrollbarWidth + border;
+ }
+}
+
+void cRecMenu::CreatePixmap(void) {
+ pixmap = osdManager.requestPixmap(3, cRect(x, y, width, height));
+ if (scrollable) {
+ int scrollBarX = x + width - scrollbarWidth - border;
+ int scrollBarY = y + border + headerHeight;
+ int scrollBarHeight = height - headerHeight - footerHeight - 2 * border;
+ pixmapScrollBar = osdManager.requestPixmap(4, cRect(scrollBarX, scrollBarY, scrollbarWidth, scrollBarHeight));
+ }
+}
+
+void cRecMenu::SetFooter(cRecMenuItem *footer) {
+ this->footer = footer;
+ footerHeight = footer->GetHeight();
+ height += footerHeight;
+}
+
+void cRecMenu::SetHeader(cRecMenuItem *header) {
+ this->header = header;
+ headerHeight = header->GetHeight();
+ height += headerHeight;
+}
+
+cRecMenuItem *cRecMenu::GetActiveMenuItem(void) {
+ for (cRecMenuItem *item = menuItems.First(); item; item = menuItems.Next(item)) {
+ if (item->isActive())
+ return item;
+ }
+ if (footer && footer->isActive())
+ return footer;
+ return NULL;
+}
+
+int cRecMenu::GetActive(bool withOffset) {
+ int numActive = withOffset?startIndex:0;
+ int i = 0;
+ for (cRecMenuItem *item = menuItems.First(); item; item = menuItems.Next(item)) {
+ if (item->isActive()) {
+ numActive += i;
+ break;
+ }
+ i++;
+ }
+ return numActive;
+}
+
+bool cRecMenu::ActivatePrev(void) {
+ cRecMenuItem *activeItem = GetActiveMenuItem();
+ if (!scrollable && footer && footer->isActive()) {
+ Activate(footer, menuItems.Last());
+ return true;
+ } else if (activeItem) {
+ cRecMenuItem *prev = NULL;
+ for (cRecMenuItem *item = menuItems.Prev(activeItem); item; item = menuItems.Prev(item)) {
+ if (item->isSelectable()) {
+ prev = item;
+ break;
+ }
+ }
+ if (prev) {
+ Activate(activeItem , prev);
+ return true;
+ }
+ }
+ return false;
+}
+
+bool cRecMenu::ActivateNext(void) {
+ cRecMenuItem *activeItem = GetActiveMenuItem();
+ if (activeItem) {
+ cRecMenuItem *next = NULL;
+ for (cRecMenuItem *item = menuItems.Next(activeItem); item; item = menuItems.Next(item)) {
+ if (item->isSelectable()) {
+ next = item;
+ break;
+ }
+ }
+ if (next) {
+ Activate(activeItem , next);
+ return true;
+ } else if (!scrollable && footer && footer->isSelectable()) {
+ Activate(activeItem , footer);
+ return true;
+ }
+ }
+ return false;
+}
+
+void cRecMenu::Activate(cRecMenuItem *itemOld, cRecMenuItem *item) {
+ itemOld->setInactive();
+ itemOld->setBackground();
+ itemOld->Draw();
+ item->setActive();
+ item->setBackground();
+ item->Draw();
+}
+
+void cRecMenu::ScrollUp(void) {
+ if (footer && footer->isActive()) {
+ Activate(footer, menuItems.Last());
+ } else {
+ //get perv x items
+ int numNewItems = numItems / 2;
+ int numAdded = 0;
+ cRecMenuItem *newItem = NULL;
+ while (newItem = GetMenuItem(startIndex-1)) {
+ AddMenuItem(newItem, menuItems.First());
+ menuItems.Del(menuItems.Last(), true);
+ stopIndex--;
+ startIndex--;
+ numAdded++;
+ if (numAdded >= numNewItems)
+ break;
+ }
+ if (numAdded != 0) {
+ Arrange(true);
+ Display(true);
+ ActivatePrev();
+ }
+ }
+}
+
+void cRecMenu::ScrollDown(void) {
+ //get next x items
+ int numNewItems = numItems / 2;
+ int numAdded = 0;
+ cRecMenuItem *newItem = NULL;
+ while (newItem = GetMenuItem(stopIndex)) {
+ menuItems.Add(newItem);
+ menuItems.Del(menuItems.First(), true);
+ stopIndex++;
+ startIndex++;
+ numAdded++;
+ if (numAdded >= numNewItems)
+ break;
+ }
+ if (numAdded != 0) {
+ Arrange(true);
+ Display(true);
+ ActivateNext();
+ } else {
+ //last item reached, activate footer
+ if (footer) {
+ cRecMenuItem *activeItem = GetActiveMenuItem();
+ Activate(activeItem , footer);
+ }
+ }
+}
+
+void cRecMenu::JumpBegin(void) {
+ cRecMenuItem *activeItem = GetActiveMenuItem();
+ if (!scrollable) {
+ cRecMenuItem *firstSelectable= NULL;
+ for (cRecMenuItem *item = menuItems.First(); item; item = menuItems.Next(item)) {
+ if (item->isSelectable()) {
+ firstSelectable = item;
+ break;
+ }
+ }
+ if (activeItem && firstSelectable) {
+ Activate(activeItem , firstSelectable);
+ }
+ } else {
+ activeItem->setInactive();
+ activeItem->setBackground();
+ if (footer)
+ footer->Draw();
+ menuItems.Clear();
+ int currentItem = 0;
+ cRecMenuItem *newItem = NULL;
+ while (newItem = GetMenuItem(currentItem)) {
+ AddMenuItem(newItem);
+ currentItem++;
+ if (currentItem >= numItems)
+ break;
+ }
+ Arrange(true);
+ startIndex = 0;
+ stopIndex = numItems-1;
+ menuItems.First()->setActive();
+ menuItems.First()->setBackground();
+ menuItems.First()->Draw();
+ Display(true);
+ }
+}
+
+void cRecMenu::JumpEnd(void) {
+ cRecMenuItem *activeItem = GetActiveMenuItem();
+ if (!activeItem)
+ return;
+ if (!scrollable) {
+ cRecMenuItem *lastSelectable= NULL;
+ if (footer && footer->isSelectable()) {
+ lastSelectable = footer;
+ } else {
+ for (cRecMenuItem *item = menuItems.Last(); item; item = menuItems.Prev(item)) {
+ if (item->isSelectable()) {
+ lastSelectable = item;
+ break;
+ }
+ }
+ }
+ if (lastSelectable) {
+ Activate(activeItem , lastSelectable);
+ }
+ } else {
+ activeItem->setInactive();
+ activeItem->setBackground();
+ menuItems.Clear();
+ int totalNumItems = GetTotalNumMenuItems();
+ int currentItem = totalNumItems-1;
+ int itemsAdded = 0;
+ cRecMenuItem *newItem = NULL;
+ while (newItem = GetMenuItem(currentItem)) {
+ AddMenuItem(newItem, menuItems.First());
+ currentItem--;
+ itemsAdded++;
+ if (itemsAdded >= numItems)
+ break;
+ }
+ Arrange(true);
+ stopIndex = totalNumItems;
+ startIndex = stopIndex - numItems;
+ if (footer) {
+ footer->setActive();
+ footer->setBackground();
+ footer->Draw();
+ } else {
+ menuItems.Last()->setActive();
+ menuItems.Last()->setBackground();
+ menuItems.Last()->Draw();
+ }
+ Display(true);
+ }
+}
+
+void cRecMenu::Arrange(bool scroll) {
+ int xElement = x + border;
+ int yElement = y + border;
+ int widthElement = width - 2 * border;
+ if (scrollable)
+ widthElement -= scrollbarWidth + border;
+
+ if (header) {
+ if (!scroll) {
+ header->SetGeometry(xElement, yElement, widthElement);
+ header->SetPixmaps();
+ }
+ yElement += header->GetHeight();
+ }
+ for (cRecMenuItem *item = menuItems.First(); item; item = menuItems.Next(item)) {
+ item->SetGeometry(xElement, yElement, widthElement);
+ item->SetPixmaps();
+ yElement += item->GetHeight();
+ }
+ if (footer && !scroll) {
+ footer->SetGeometry(xElement, yElement, widthElement);
+ footer->SetPixmaps();
+ }
+}
+
+void cRecMenu::Display(bool scroll) {
+ pixmap->Fill(theme.Color(clrBackground));
+ drawBorder();
+ if (header && !scroll) {
+ header->setBackground();
+ header->Draw();
+ }
+ for (cRecMenuItem *item = menuItems.First(); item; item = menuItems.Next(item)) {
+ item->setBackground();
+ item->Draw();
+ }
+ if (footer && !scroll) {
+ footer->setBackground();
+ footer->Draw();
+ }
+ if (scrollable)
+ DrawScrollBar();
+}
+
+void cRecMenu::Hide(void) {
+ pixmap->SetLayer(-1);
+ if (pixmapScrollBar)
+ pixmapScrollBar->SetLayer(-1);
+ if (header)
+ header->Hide();
+ if (footer)
+ footer->Hide();
+ for (cRecMenuItem *item = menuItems.First(); item; item = menuItems.Next(item)) {
+ item->Hide();
+ }
+}
+
+void cRecMenu::Show(void) {
+ pixmap->SetLayer(3);
+ if (pixmapScrollBar)
+ pixmapScrollBar->SetLayer(3);
+ if (header)
+ header->Show();
+ if (footer)
+ footer->Show();
+ for (cRecMenuItem *item = menuItems.First(); item; item = menuItems.Next(item)) {
+ item->Show();
+ }
+}
+
+void cRecMenu::DrawScrollBar(void) {
+ pixmapScrollBar->Fill(theme.Color(clrBorder));
+ pixmapScrollBar->DrawRectangle(cRect(2,2,pixmapScrollBar->ViewPort().Width()-4, pixmapScrollBar->ViewPort().Height() - 4), theme.Color(clrBackground));
+
+ int totalNumItems = GetTotalNumMenuItems();
+ if (imgScrollBar == NULL) {
+ int scrollBarImgHeight = (pixmapScrollBar->ViewPort().Height() - 8) * numItems / totalNumItems;
+ imgScrollBar = createScrollbar(pixmapScrollBar->ViewPort().Width()-8, scrollBarImgHeight, theme.Color(clrHighlight), theme.Color(clrHighlightBlending));
+ }
+ int offset = (pixmapScrollBar->ViewPort().Height() - 8) * startIndex / totalNumItems;
+ pixmapScrollBar->DrawImage(cPoint(4, 2 + offset), *imgScrollBar);
+}
+
+int cRecMenu::GetIntValue(int itemNumber) {
+ cRecMenuItem *item = NULL;
+ item = menuItems.Get(itemNumber);
+ if (item) {
+ return item->GetIntValue();
+ }
+ return -1;
+}
+
+time_t cRecMenu::GetTimeValue(int itemNumber) {
+ cRecMenuItem *item = NULL;
+ item = menuItems.Get(itemNumber);
+ if (item) {
+ return item->GetTimeValue();
+ }
+ return 0;
+}
+
+bool cRecMenu::GetBoolValue(int itemNumber) {
+ cRecMenuItem *item = NULL;
+ item = menuItems.Get(itemNumber);
+ if (item) {
+ return item->GetBoolValue();
+ }
+ return false;
+}
+
+cString cRecMenu::GetStringValue(int itemNumber) {
+ cRecMenuItem *item = NULL;
+ item = menuItems.Get(itemNumber);
+ if (item) {
+ return item->GetStringValue();
+ }
+ return cString("");
+}
+
+const cEvent *cRecMenu::GetEventValue(int itemNumber) {
+ cRecMenuItem *item = NULL;
+ item = menuItems.Get(itemNumber);
+ if (item) {
+ return item->GetEventValue();
+ }
+ return NULL;
+}
+
+eRecMenuState cRecMenu::ProcessKey(eKeys Key) {
+ cRecMenuItem *activeItem = GetActiveMenuItem();
+ eRecMenuState state = rmsContinue;
+ if (!activeItem)
+ return state;
+
+ state = activeItem->ProcessKey(Key);
+ if (state == rmsRefresh) {
+ CreateMenuItems();
+ Display();
+ } else if (state == rmsNotConsumed) {
+ switch (Key & ~k_Repeat) {
+ case kUp:
+ if (!ActivatePrev() && scrollable)
+ ScrollUp();
+ state = rmsConsumed;
+ break;
+ case kDown:
+ if (!ActivateNext() && scrollable)
+ ScrollDown();
+ state = rmsConsumed;
+ break;
+ case kLeft:
+ JumpBegin();
+ state = rmsConsumed;
+ break;
+ case kRight:
+ JumpEnd();
+ state = rmsConsumed;
+ break;
+ default:
+ break;
+ }
+ }
+ return state;
+}
+
+cImage *cRecMenu::createScrollbar(int width, int height, tColor clrBgr, tColor clrBlend) {
+ cImage *image = new cImage(cSize(width, height));
+ image->Fill(clrBgr);
+ if (tvguideConfig.useBlending) {
+ int numSteps = 64;
+ int alphaStep = 0x03;
+ if (height < 30)
+ return image;
+ else if (height < 100) {
+ numSteps = 32;
+ alphaStep = 0x06;
+ }
+ int stepY = 0.5*height / numSteps;
+ if (stepY == 0)
+ stepY = 1;
+ int alpha = 0x40;
+ tColor clr;
+ for (int i = 0; i<numSteps; i++) {
+ clr = AlphaBlend(clrBgr, clrBlend, alpha);
+ for (int y = i*stepY; y < (i+1)*stepY; y++) {
+ for (int x=0; x<width; x++) {
+ image->SetPixel(cPoint(x,y), clr);
+ }
+ }
+ alpha += alphaStep;
+ }
+ }
+ return image;
+}
diff --git a/recmenu.h b/recmenu.h
new file mode 100644
index 0000000..87d3ef5
--- /dev/null
+++ b/recmenu.h
@@ -0,0 +1,61 @@
+#ifndef __TVGUIDE_RECMENU_H
+#define __TVGUIDE_RECMENU_H
+
+// --- cRecMenu -------------------------------------------------------------
+
+class cRecMenu : public cStyledPixmap {
+protected:
+ int x, y;
+ int width, height;
+ int headerHeight, footerHeight;
+ int scrollHeight;
+ int scrollItemHeight;
+ int scrollbarWidth;
+ cPixmap *pixmapScrollBar;
+ cImage *imgScrollBar;
+ int border;
+ bool scrollable;
+ int numItems;
+ int startIndex, stopIndex;
+ cRecMenuItem *header;
+ cRecMenuItem *footer;
+ cList<cRecMenuItem> menuItems;
+ void SetWidthPercent(int percentOSDWidth);
+ void SetWidthPixel(int pixel);
+ int CalculateOptimalWidth(void);
+ bool CheckHeight(void);
+ void CalculateHeight(void);
+ void CreatePixmap(void);
+ void SetHeader(cRecMenuItem *header);
+ void SetFooter(cRecMenuItem *footer);
+ void AddMenuItemScroll(cRecMenuItem *item);
+ void AddMenuItem(cRecMenuItem *item, cRecMenuItem *before = NULL);
+ cRecMenuItem *GetActiveMenuItem(void);
+ bool ActivateNext(void);
+ bool ActivatePrev(void);
+ void Activate(cRecMenuItem *itemOld, cRecMenuItem *item);
+ void ScrollUp(void);
+ void ScrollDown(void);
+ void JumpBegin(void);
+ void JumpEnd(void);
+ void DrawScrollBar(void);
+ cImage *createScrollbar(int width, int height, tColor clrBgr, tColor clrBlend);
+ void Arrange(bool scroll = false);
+ virtual cRecMenuItem *GetMenuItem(int number) { return NULL; };
+ virtual int GetTotalNumMenuItems(void) { return 0; };
+ virtual void CreateMenuItems(void) {};
+public:
+ cRecMenu(void);
+ virtual ~cRecMenu(void);
+ void Display(bool scroll = false);
+ void Hide(void);
+ void Show(void);
+ int GetActive(bool withOffset);
+ int GetIntValue(int itemNumber);
+ time_t GetTimeValue(int itemNumber);
+ bool GetBoolValue(int itemNumber);
+ cString GetStringValue(int itemNumber);
+ const cEvent *GetEventValue(int itemNumber);
+ eRecMenuState ProcessKey(eKeys Key);
+};
+#endif //__TVGUIDE_RECMENU_H \ No newline at end of file
diff --git a/recmenuitem.c b/recmenuitem.c
new file mode 100644
index 0000000..eb931e9
--- /dev/null
+++ b/recmenuitem.c
@@ -0,0 +1,2016 @@
+#include <math.h>
+#include <vdr/remote.h>
+#include "recmenuitem.h"
+
+// --- cRecMenuItem -------------------------------------------------------------
+
+cRecMenuItem::cRecMenuItem(void) {
+ height = 0;
+ action = rmsNotConsumed;
+ drawn = false;
+ font = tvguideConfig.FontRecMenuItem;
+ fontSmall = tvguideConfig.FontRecMenuItemSmall;
+}
+
+cRecMenuItem::~cRecMenuItem(void) {
+}
+
+void cRecMenuItem::SetGeometry(int x, int y, int width) {
+ this->x = x;
+ this->y = y;
+ this->width = width;
+
+}
+
+void cRecMenuItem::SetPixmaps(void) {
+ if (!pixmap)
+ pixmap = osdManager.requestPixmap(4, cRect(x, y, width, height));
+ else
+ pixmap->SetViewPort(cRect(x, y, width, height));
+}
+
+void cRecMenuItem::setBackground(void) {
+ if (active) {
+ color = theme.Color(clrHighlight);
+ colorBlending = theme.Color(clrHighlightBlending);
+ colorText = theme.Color(clrFontActive);
+ } else {
+ color = theme.Color(clrGrid1);
+ colorBlending = theme.Color(clrGrid1Blending);
+ colorText = theme.Color(clrFont);
+ }
+ colorTextBack = (tvguideConfig.useBlending==0)?color:clrTransparent;
+ drawBackground();
+ drawBorder();
+}
+
+// --- cRecMenuItemButton -------------------------------------------------------
+
+cRecMenuItemButton::cRecMenuItemButton(const char *text, eRecMenuState action, bool active, bool halfWidth) {
+ selectable = true;
+ this->text = text;
+ this->action = action;
+ this->active = active;
+ height = 3 * font->Height() / 2;
+ this->halfWidth = halfWidth;
+}
+
+cRecMenuItemButton::~cRecMenuItemButton(void) {
+}
+
+int cRecMenuItemButton::GetWidth(void) {
+ return font->Width(*text);
+}
+
+void cRecMenuItemButton::SetPixmaps(void) {
+ if (halfWidth) {
+ x += width / 4;
+ width = width / 2;
+ }
+ if (!pixmap)
+ pixmap = osdManager.requestPixmap(4, cRect(x, y, width, height));
+ else
+ pixmap->SetViewPort(cRect(x, y, width, height));
+}
+
+void cRecMenuItemButton::Draw(void) {
+ int y = (height - font->Height()) / 2;
+ int x = (width - font->Width(*text)) / 2;;
+ pixmap->DrawText(cPoint(x, y), *text, colorText, colorTextBack, font);
+}
+
+eRecMenuState cRecMenuItemButton::ProcessKey(eKeys Key) {
+ switch (Key & ~k_Repeat) {
+ case kOk:
+ return action;
+ break;
+ default:
+ break;
+ }
+ return rmsNotConsumed;
+}
+
+
+// --- cRecMenuItemButtonYesNo -------------------------------------------------------
+cRecMenuItemButtonYesNo::cRecMenuItemButtonYesNo(cString textYes,
+ cString textNo,
+ eRecMenuState actionYes,
+ eRecMenuState actionNo,
+ bool active) {
+ selectable = true;
+ this->textYes = textYes;
+ this->textNo = textNo;
+ this->action = actionYes;
+ this->actionNo = actionNo;
+ this->active = active;
+ yesActive = true;
+ height = 3 * font->Height() / 2;
+ pixmapNo = NULL;
+}
+
+cRecMenuItemButtonYesNo::~cRecMenuItemButtonYesNo(void) {
+ if (pixmapNo)
+ delete pixmapNo;
+}
+
+void cRecMenuItemButtonYesNo::SetPixmaps(void) {
+ int buttonWidth = 44 * width / 100;
+ int yesX = x + width / 25;
+ int noX = x + 52 * width / 100;
+ if (!pixmap) {
+ pixmap = osdManager.requestPixmap(4, cRect(yesX, y, buttonWidth, height));
+ pixmapNo = new cStyledPixmap(osdManager.requestPixmap(4, cRect(noX, y, buttonWidth, height)));
+ } else {
+ pixmap->SetViewPort(cRect(x, y, width, height));
+ pixmapNo->SetViewPort(cRect(x, y, width, height));
+ }
+}
+
+void cRecMenuItemButtonYesNo::Hide(void) {
+ pixmap->SetLayer(-1);
+ pixmapNo->SetLayer(-1);
+}
+
+void cRecMenuItemButtonYesNo::Show(void) {
+ pixmap->SetLayer(4);
+ pixmapNo->SetLayer(4);
+}
+
+void cRecMenuItemButtonYesNo::setBackground() {
+ if (active) {
+ if (yesActive) {
+ color = theme.Color(clrHighlight);
+ colorBlending = theme.Color(clrHighlightBlending);
+ colorText = theme.Color(clrFontActive);
+ pixmapNo->setColor( theme.Color(clrGrid1),
+ theme.Color(clrGrid1Blending));
+ colorTextNo = theme.Color(clrFont);
+ } else {
+ color = theme.Color(clrGrid1);
+ colorBlending = theme.Color(clrGrid1Blending);
+ colorText = theme.Color(clrFont);
+ pixmapNo->setColor( theme.Color(clrHighlight),
+ theme.Color(clrHighlightBlending));
+ colorTextNo = theme.Color(clrFontActive);
+ }
+ } else {
+ color = theme.Color(clrGrid1);
+ colorBlending = theme.Color(clrGrid1Blending);
+ colorText = theme.Color(clrFont);
+ pixmapNo->setColor( theme.Color(clrGrid1),
+ theme.Color(clrGrid1Blending));
+ colorTextNo = theme.Color(clrFont);
+ }
+ colorTextBack = (tvguideConfig.useBlending==0)?color:clrTransparent;
+ drawBackground();
+ drawBorder();
+ pixmapNo->drawBackground();
+ pixmapNo->drawBorder();
+}
+
+void cRecMenuItemButtonYesNo::Draw(void) {
+ int textYesX = (pixmap->ViewPort().Width() - font->Width(*textYes)) / 2;
+ int textNoX = (pixmapNo->Width() - font->Width(*textNo)) / 2;
+ int textY = (height - font->Height()) / 2;
+ pixmap->DrawText(cPoint(textYesX, textY), *textYes, colorText, clrTransparent, font);
+ pixmapNo->DrawText(cPoint(textNoX, textY), *textNo, colorTextNo, clrTransparent, font);
+}
+
+eRecMenuState cRecMenuItemButtonYesNo::ProcessKey(eKeys Key) {
+ switch (Key & ~k_Repeat) {
+ case kLeft:
+ if (!yesActive) {
+ yesActive = true;
+ setBackground();
+ Draw();
+ return rmsConsumed;
+ } else
+ return rmsNotConsumed;
+ break;
+ case kRight:
+ if (yesActive) {
+ yesActive = false;
+ setBackground();
+ Draw();
+ return rmsConsumed;
+ } else
+ return rmsNotConsumed;
+ break;
+ case kOk:
+ if (yesActive)
+ return action;
+ return actionNo;
+ break;
+ default:
+ break;
+ }
+ return rmsNotConsumed;
+}
+
+// --- cRecMenuItemInfo -------------------------------------------------------
+cRecMenuItemInfo::cRecMenuItemInfo(const char *text) {
+ selectable = false;
+ active = false;
+ this->text = text;
+ border = 10;
+}
+
+cRecMenuItemInfo::~cRecMenuItemInfo(void) {
+}
+
+void cRecMenuItemInfo::CalculateHeight(int textWidth) {
+ wrapper.Set(*text, font, textWidth);
+ height = font->Height() * wrapper.Lines() + 2*border;
+}
+
+void cRecMenuItemInfo::setBackground(void) {
+ pixmap->Fill(clrTransparent);
+}
+
+void cRecMenuItemInfo::Draw(void) {
+ int lines = wrapper.Lines();
+ int lineHeight = font->Height();
+ int x = 0;
+ int y = border;
+ for (int i = 0; i < lines; i++) {
+ x = (width - font->Width(wrapper.GetLine(i))) / 2;
+ pixmap->DrawText(cPoint(x,y), wrapper.GetLine(i), theme.Color(clrFont), clrTransparent, font);
+ y += lineHeight;
+ }
+}
+
+// --- cRecMenuItemInt -------------------------------------------------------
+cRecMenuItemInt::cRecMenuItemInt(cString text,
+ int initialVal,
+ int minVal,
+ int maxVal,
+ bool active) {
+ selectable = true;
+ this->text = text;
+ this->currentVal = initialVal;
+ this->minVal = minVal;
+ this->maxVal = maxVal;
+ this->active = active;
+ height = 3 * font->Height() / 2;
+ pixmapVal = NULL;
+ fresh = true;
+}
+
+cRecMenuItemInt::~cRecMenuItemInt(void) {
+ if (pixmapVal)
+ osdManager.releasePixmap(pixmapVal);
+}
+
+void cRecMenuItemInt::SetPixmaps(void) {
+ if (!pixmap) {
+ pixmap = osdManager.requestPixmap(4, cRect(x, y, width, height));
+ pixmapVal = osdManager.requestPixmap(5, cRect(x, y, width, height));
+ } else {
+ pixmap->SetViewPort(cRect(x, y, width, height));
+ pixmapVal->SetViewPort(cRect(x, y, width, height));
+ }
+}
+
+void cRecMenuItemInt::Hide(void) {
+ pixmap->SetLayer(-1);
+ pixmapVal->SetLayer(-1);
+}
+
+void cRecMenuItemInt::Show(void) {
+ pixmap->SetLayer(4);
+ pixmapVal->SetLayer(5);
+}
+
+void cRecMenuItemInt::setBackground() {
+ cRecMenuItem::setBackground();
+ fresh = true;
+}
+
+void cRecMenuItemInt::Draw(void) {
+ int textY = (height - font->Height()) / 2;
+ pixmap->DrawText(cPoint(10, textY), *text, colorText, colorTextBack, font);
+ DrawValue();
+}
+
+void cRecMenuItemInt::DrawValue(void) {
+ pixmapVal->Fill(clrTransparent);
+ cString textVal = cString::sprintf("%d", currentVal);
+ int textX = width - font->Width(*textVal) - 10;
+ int textY = (height - font->Height()) / 2;
+ pixmapVal->DrawText(cPoint(textX, textY), *textVal, colorText, clrTransparent, font);
+}
+
+eRecMenuState cRecMenuItemInt::ProcessKey(eKeys Key) {
+ int oldValue = currentVal;
+ switch (Key & ~k_Repeat) {
+ case kLeft:
+ fresh = true;
+ if (currentVal > minVal) {
+ currentVal--;
+ DrawValue();
+ }
+ return rmsConsumed;
+ break;
+ case kRight:
+ fresh = true;
+ if (currentVal < maxVal) {
+ currentVal++;
+ DrawValue();
+ }
+ return rmsConsumed;
+ break;
+ case k0 ... k9:
+ if (fresh) {
+ currentVal = 0;
+ fresh = false;
+ }
+ currentVal = currentVal * 10 + (Key - k0);
+ if (!((currentVal >= minVal) && (currentVal <= maxVal)))
+ currentVal = oldValue;
+ DrawValue();
+ return rmsConsumed;
+ break;
+ default:
+ break;
+ }
+ return rmsNotConsumed;
+}
+
+// --- cRecMenuItemBool -------------------------------------------------------
+cRecMenuItemBool::cRecMenuItemBool(cString text,
+ bool initialVal,
+ bool refresh,
+ bool active) {
+ selectable = true;
+ this->text = text;
+ this->yes = initialVal;
+ this->refresh = refresh;
+ this->active = active;
+ height = 3 * font->Height() / 2;
+ pixmapVal = NULL;
+}
+
+cRecMenuItemBool::~cRecMenuItemBool(void) {
+ if (pixmapVal)
+ osdManager.releasePixmap(pixmapVal);
+}
+
+void cRecMenuItemBool::SetPixmaps(void) {
+ if (!pixmap) {
+ pixmap = osdManager.requestPixmap(4, cRect(x, y, width, height));
+ pixmapVal = osdManager.requestPixmap(5, cRect(x, y, width, height));
+ } else {
+ pixmap->SetViewPort(cRect(x, y, width, height));
+ pixmapVal->SetViewPort(cRect(x, y, width, height));
+ }
+}
+
+void cRecMenuItemBool::Hide(void) {
+ pixmap->SetLayer(-1);
+ pixmapVal->SetLayer(-1);
+}
+
+void cRecMenuItemBool::Show(void) {
+ pixmap->SetLayer(4);
+ pixmapVal->SetLayer(5);
+}
+
+void cRecMenuItemBool::Draw(void) {
+ int textY = (height - font->Height()) / 2;
+ pixmap->DrawText(cPoint(10, textY), *text, colorText, colorTextBack, font);
+ DrawValue();
+}
+
+void cRecMenuItemBool::DrawValue(void) {
+ pixmapVal->Fill(clrTransparent);
+ cString strIcon = yes?"yes":"no";
+ int iconSize = height - 8;
+ int iconX = width - iconSize - 10;
+ int iconY = (height - iconSize) / 2;
+ cImageLoader imgLoader;
+ if (imgLoader.LoadIcon(strIcon, iconSize)) {
+ cImage icon = imgLoader.GetImage();
+ pixmapVal->DrawImage(cPoint(iconX, iconY), icon);
+ }
+}
+
+eRecMenuState cRecMenuItemBool::ProcessKey(eKeys Key) {
+ switch (Key & ~k_Repeat) {
+ case kLeft:
+ case kRight:
+ yes = !yes;
+ DrawValue();
+ if (refresh)
+ return rmsRefresh;
+ else
+ return rmsConsumed;
+ break;
+ default:
+ break;
+ }
+ return rmsNotConsumed;
+}
+
+// --- cRecMenuItemSelect -------------------------------------------------------
+cRecMenuItemSelect::cRecMenuItemSelect(cString text,
+ const char * const *Strings,
+ int initialVal,
+ int numValues,
+ bool active) {
+ selectable = true;
+ this->text = text;
+ strings = Strings;
+ this->numValues = numValues;
+ if ((initialVal < 0) || (initialVal > numValues-1))
+ this->currentVal = 0;
+ else
+ this->currentVal = initialVal;
+ this->active = active;
+ height = 3 * font->Height() / 2;
+ pixmapVal = NULL;
+}
+
+cRecMenuItemSelect::~cRecMenuItemSelect(void) {
+ if (pixmapVal)
+ osdManager.releasePixmap(pixmapVal);
+}
+
+void cRecMenuItemSelect::SetPixmaps(void) {
+ if (!pixmap) {
+ pixmap = osdManager.requestPixmap(4, cRect(x, y, width, height));
+ pixmapVal = osdManager.requestPixmap(5, cRect(x, y, width, height));
+ } else {
+ pixmap->SetViewPort(cRect(x, y, width, height));
+ pixmapVal->SetViewPort(cRect(x, y, width, height));
+ }
+}
+
+void cRecMenuItemSelect::Hide(void) {
+ pixmap->SetLayer(-1);
+ pixmapVal->SetLayer(-1);
+}
+
+void cRecMenuItemSelect::Show(void) {
+ pixmap->SetLayer(4);
+ pixmapVal->SetLayer(5);
+}
+
+void cRecMenuItemSelect::Draw(void) {
+ int textY = (height - font->Height()) / 2;
+ pixmap->DrawText(cPoint(10, textY), *text, colorText, colorTextBack, font);
+ DrawValue();
+}
+
+void cRecMenuItemSelect::DrawValue(void) {
+ pixmapVal->Fill(clrTransparent);
+ const char *textVal = strings[currentVal];
+ int iconSize = min(128, height);
+ int textX = width - font->Width(textVal) - iconSize;
+ int textY = (height - font->Height()) / 2;
+ pixmapVal->DrawText(cPoint(textX, textY), textVal, colorText, clrTransparent, font);
+ int iconLeftX = textX - iconSize;
+ int iconRightX = width - iconSize;
+ int iconY = (height - iconSize) / 2;
+ cImageLoader imgLoader;
+ if (imgLoader.LoadIcon("arrow_left", iconSize)) {
+ cImage icon = imgLoader.GetImage();
+ pixmapVal->DrawImage(cPoint(iconLeftX, iconY), icon);
+ }
+ if (imgLoader.LoadIcon("arrow_right", iconSize)) {
+ cImage icon = imgLoader.GetImage();
+ pixmapVal->DrawImage(cPoint(iconRightX, iconY), icon);
+ }
+}
+
+eRecMenuState cRecMenuItemSelect::ProcessKey(eKeys Key) {
+ int oldValue = currentVal;
+ switch (Key & ~k_Repeat) {
+ case kLeft:
+ currentVal--;
+ if (currentVal<0)
+ currentVal = numValues - 1;
+ DrawValue();
+ return rmsConsumed;
+ break;
+ case kRight:
+ currentVal = (currentVal+1)%numValues;
+ DrawValue();
+ return rmsConsumed;
+ break;
+ default:
+ break;
+ }
+ return rmsNotConsumed;
+}
+
+// --- cRecMenuItemText -------------------------------------------------------
+cRecMenuItemText::cRecMenuItemText(cString title,
+ char *initialVal,
+ int length,
+ bool active) {
+ selectable = true;
+ this->title = title;
+ value = initialVal;
+ this->active = active;
+ height = 3 * font->Height();
+ pixmapVal = NULL;
+ pixmapKeyboard = NULL;
+ pixmapKeyboardHighlight = NULL;
+ pixmapKeyboardIcons = NULL;
+ keyboardWidth = 50;
+ gridHeight = 3 * fontSmall->Height();
+ keyboardHeight = 5 * gridHeight;
+
+ this->length = length;
+ allowed = trVDR(FileNameChars);
+ pos = -1;
+ offset = 0;
+ insert = uppercase = false;
+ newchar = true;
+ lengthUtf8 = 0;
+ valueUtf8 = NULL;
+ allowedUtf8 = NULL;
+ charMapUtf8 = NULL;
+ currentCharUtf8 = NULL;
+ lastKey = kNone;
+ keyboardDrawn = false;
+}
+
+cRecMenuItemText::~cRecMenuItemText(void) {
+ if (pixmapVal)
+ osdManager.releasePixmap(pixmapVal);
+ if (pixmapKeyboard)
+ delete pixmapKeyboard;
+ if (pixmapKeyboardHighlight)
+ osdManager.releasePixmap(pixmapKeyboardHighlight);
+ if (pixmapKeyboardIcons)
+ osdManager.releasePixmap(pixmapKeyboardIcons);
+ delete[] valueUtf8;
+ delete[] allowedUtf8;
+ delete[] charMapUtf8;
+}
+
+void cRecMenuItemText::SetPixmaps(void) {
+ int xPixmapVal = x + 20;
+ int yPixmapVal = y + height / 2 + 10;
+ int widthPixmapVal = width - 40;
+ int heightPixmapVal = height / 2 - 20;
+ int keyboardX = x + (100 - keyboardWidth)*width / 100;
+ int keyboardY = y + height;
+ if (!pixmap) {
+ pixmap = osdManager.requestPixmap(4, cRect(x, y, width, height));
+ pixmapVal = osdManager.requestPixmap(5, cRect(xPixmapVal, yPixmapVal, widthPixmapVal, heightPixmapVal));
+ pixmapKeyboard = new cStyledPixmap(osdManager.requestPixmap(-1, cRect(keyboardX, keyboardY, keyboardWidth*width/100, keyboardHeight)));
+ pixmapKeyboardHighlight = osdManager.requestPixmap(-1, cRect(keyboardX, keyboardY, keyboardWidth*width/100, keyboardHeight));
+ pixmapKeyboardIcons = osdManager.requestPixmap(-1, cRect(keyboardX, keyboardY, keyboardWidth*width/100, keyboardHeight));
+ } else {
+ pixmap->SetViewPort(cRect(x, y, width, height));
+ pixmapVal->SetViewPort(cRect(xPixmapVal, yPixmapVal, widthPixmapVal, heightPixmapVal));
+ pixmapKeyboard->SetViewPort(cRect(keyboardX, keyboardY, keyboardWidth*width/100, keyboardHeight));
+ pixmapKeyboardHighlight->SetViewPort(cRect(keyboardX, keyboardY, keyboardWidth*width/100, keyboardHeight));
+ pixmapKeyboardIcons->SetViewPort(cRect(keyboardX, keyboardY, keyboardWidth*width/100, keyboardHeight));
+ }
+ pixmapKeyboardIcons->Fill(clrTransparent);
+}
+
+void cRecMenuItemText::Hide(void) {
+ pixmap->SetLayer(-1);
+ pixmapVal->SetLayer(-1);
+ pixmapKeyboard->SetLayer(-1);
+ pixmapKeyboardHighlight->SetLayer(-1);
+ pixmapKeyboardIcons->SetLayer(-1);
+}
+
+void cRecMenuItemText::Show(void) {
+ pixmap->SetLayer(4);
+ pixmapVal->SetLayer(5);
+}
+
+void cRecMenuItemText::setBackground() {
+ if (!active) {
+ DeactivateKeyboard();
+ }
+ cRecMenuItem::setBackground();
+}
+
+void cRecMenuItemText::Draw(void) {
+ int textY = (height/2 - font->Height()) / 2;
+ pixmap->DrawText(cPoint(10, textY), *title, colorText, colorTextBack, font);
+ DrawValue(value);
+}
+
+void cRecMenuItemText::DrawValue(char *newValue) {
+ tColor clrBack = InEditMode()?theme.Color(clrRecMenuTextActiveBack):theme.Color(clrRecMenuTextBack);
+ pixmapVal->Fill(clrBack);
+ int textX = pixmapVal->DrawPort().Width() - font->Width(newValue) - 10;
+ int textY = (pixmapVal->DrawPort().Height() - font->Height()) / 2;
+ pixmapVal->DrawText(cPoint(textX, textY), newValue, colorText, clrTransparent, font);
+}
+
+void cRecMenuItemText::ActivateKeyboard(void) {
+ pixmapKeyboard->SetLayer(6);
+ pixmapKeyboardHighlight->SetLayer(6);
+ pixmapKeyboardIcons->SetLayer(6);
+ pixmapKeyboardHighlight->Fill(clrTransparent);
+
+ if (keyboardDrawn)
+ return;
+
+ pixmapKeyboard->setColor(theme.Color(clrRecMenuKeyboardBack), theme.Color(clrRecMenuKeyboardBack));
+ pixmapKeyboard->drawBackground();
+
+ int widthKeyBoard = pixmapKeyboard->Width();
+ gridWidth = widthKeyBoard / 3;
+
+ pixmapKeyboard->DrawRectangle(cRect(0, 0, widthKeyBoard, keyboardHeight), theme.Color(clrRecMenuKeyboardBorder));
+ int num = 1;
+ for (int row = 0; row < 5; row++) {
+ for (int col = 0; col < 3; col++) {
+ int X = col*gridWidth;
+ int Y = row*gridHeight;
+ tColor clrBack = theme.Color(clrRecMenuKeyboardBack);
+ if (num==13)
+ clrBack = theme.Color(clrButtonRedKeyboard);
+ else if (num==14)
+ clrBack = theme.Color(clrButtonGreenKeyboard);
+ else if (num==15)
+ clrBack = theme.Color(clrButtonYellowKeyboard);
+ pixmapKeyboard->DrawRectangle(cRect(X+2, Y+2, gridWidth-4, gridHeight-4), clrBack);
+ pixmapKeyboard->DrawEllipse(cRect(X, Y, 20, 20), theme.Color(clrRecMenuKeyboardBorder),-2);
+ pixmapKeyboard->DrawEllipse(cRect(X, Y+gridHeight-20, 20, 20), theme.Color(clrRecMenuKeyboardBorder),-3);
+ pixmapKeyboard->DrawEllipse(cRect(X+gridWidth-20, Y+gridHeight-20, 20, 20), theme.Color(clrRecMenuKeyboardBorder),-4);
+ pixmapKeyboard->DrawEllipse(cRect(X+gridWidth-20, Y, 20, 20), theme.Color(clrRecMenuKeyboardBorder),-1);
+ bool draw = false;
+ bool drawIcon = false;
+ cString strNum;
+ cString strIcon;
+ cImageLoader imgLoader;
+ if (num<10) {
+ strNum = *cString::sprintf("%d", num);
+ draw = true;
+ } else if (num == 11) {
+ strNum = *cString::sprintf("%d", 0);
+ draw = true;
+ } else if (num==13) {
+ strIcon = "icon_shift";
+ drawIcon = true;
+ } else if (num==14) {
+ strIcon = "icon_del_ins";
+ drawIcon = true;
+ } else if (num==15) {
+ strIcon = "icon_backspace";
+ drawIcon = true;
+ }
+ if (draw) {
+ int numX = X + (gridWidth - font->Width(*strNum))/2;
+ int numY = Y + font->Height() / 4;
+ pixmapKeyboard->DrawText(cPoint(numX, numY), *strNum, colorText, colorTextBack, font);
+ char *smsKeys = GetSMSKeys(num);
+ int smsKeysX = X + (gridWidth - fontSmall->Width(smsKeys))/2;
+ int smsKeysY = Y + gridHeight - fontSmall->Height() - 10;
+ pixmapKeyboard->DrawText(cPoint(smsKeysX, smsKeysY), smsKeys, theme.Color(clrRecMenuKeyboardBorder), colorTextBack, fontSmall);
+ delete[] smsKeys;
+ }
+ if (drawIcon) {
+ int iconSize = gridHeight - 10;
+ if (imgLoader.LoadIcon(strIcon, iconSize)) {
+ cImage icon = imgLoader.GetImage();
+ int iconX = X + (gridWidth - iconSize) / 2;
+ pixmapKeyboardIcons->DrawImage(cPoint(iconX, Y + 5), icon);
+ }
+ }
+ num++;
+ }
+ }
+ keyboardDrawn = true;
+}
+
+void cRecMenuItemText::DeactivateKeyboard(void) {
+ pixmapKeyboard->SetLayer(-1);
+ pixmapKeyboardHighlight->SetLayer(-1);
+ pixmapKeyboardIcons->SetLayer(-1);
+}
+
+void cRecMenuItemText::HighlightSMSKey(int num) {
+ int x = 0;
+ int y = 0;
+ if (num == 0) {
+ x = gridWidth;
+ y = 3 * gridHeight;
+ } else {
+ x = (num-1)%3 * gridWidth;
+ y = (num-1)/3 * gridHeight;
+ }
+ pixmapKeyboardHighlight->DrawRectangle(cRect(x, y, gridWidth, gridHeight), theme.Color(clrRecMenuKeyboardHigh));
+}
+
+void cRecMenuItemText::ClearSMSKey(void) {
+ pixmapKeyboardHighlight->Fill(clrTransparent);
+}
+
+
+char *cRecMenuItemText::GetSMSKeys(int num) {
+ if (num == 11)
+ num = 0;
+ if (num > 9)
+ return NULL;
+
+ currentCharUtf8 = charMapUtf8;
+ int pos = num;
+ while (pos > 0 && *currentCharUtf8) {
+ if (*currentCharUtf8++ == '\t')
+ pos--;
+ }
+ while (*currentCharUtf8 && *currentCharUtf8 != '\t' && !IsAllowed(*currentCharUtf8)) {
+ currentCharUtf8++;
+ }
+ uint *startCharUtf8 = currentCharUtf8;
+ int numChars = 0;
+ bool specialChar = false;
+ while(*currentCharUtf8 && *currentCharUtf8 != '\t' && IsAllowed(*currentCharUtf8)) {
+ currentCharUtf8++;
+ if (Utf8CharSet(*currentCharUtf8) > 1)
+ specialChar = true;
+ numChars++;
+ }
+ char buf[100];
+ char *p = buf;
+ int addition = 0;
+ if (specialChar)
+ addition = 1;
+ Utf8FromArray(startCharUtf8, p, numChars+addition);
+ int maxChars = min(numChars+1+addition, 8);
+ char *smskey = new char[maxChars];
+ Utf8Strn0Cpy(smskey, p, maxChars);
+ return smskey;
+}
+
+void cRecMenuItemText::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 = trVDR("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 cRecMenuItemText::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 cRecMenuItemText::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]);
+}
+
+uint cRecMenuItemText::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 cRecMenuItemText::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 cRecMenuItemText::Insert(void) {
+ memmove(valueUtf8 + pos + 1, valueUtf8 + pos, (lengthUtf8 - pos + 1) * sizeof(*valueUtf8));
+ lengthUtf8++;
+ valueUtf8[pos] = ' ';
+}
+
+void cRecMenuItemText::Delete(void) {
+ memmove(valueUtf8 + pos, valueUtf8 + pos + 1, (lengthUtf8 - pos) * sizeof(*valueUtf8));
+ lengthUtf8--;
+}
+
+uint *cRecMenuItemText::IsAllowed(uint c) {
+ if (allowedUtf8) {
+ for (uint *a = allowedUtf8; *a; a++) {
+ if (c == *a)
+ return a;
+ }
+ }
+ return NULL;
+}
+
+void cRecMenuItemText::SetText(void) {
+ if (InEditMode()) {
+ int textAreaWidth = width - 20;
+ textAreaWidth -= font->Width("[]");
+ textAreaWidth -= font->Width("<>"); // reserving this anyway make 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 > textAreaWidth) {
+ if (pos >= i) {
+ do {
+ WidthFromOffset -= font->Width(valueUtf8[offset]);
+ offset++;
+ } while (WidthFromOffset > textAreaWidth && 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;
+ DrawValue(buf);
+ } else {
+ DrawValue(value);
+ }
+}
+
+eRecMenuState cRecMenuItemText::ProcessKey(eKeys Key) {
+ bool consumed = false;
+ bool SameKey = NORMALKEY(Key) == lastKey;
+ ClearSMSKey();
+ if (Key != kNone) {
+ lastKey = NORMALKEY(Key);
+ } else if (!newchar && k0 <= lastKey && lastKey <= k9 && autoAdvanceTimeout.TimedOut()) {
+ AdvancePos();
+ newchar = true;
+ currentCharUtf8 = NULL;
+ SetText();
+ return rmsConsumed;
+ }
+
+ 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]);
+ }
+ consumed = true;
+ }
+ break;
+ case kGreen: // Toggle insert/overwrite modes
+ if (InEditMode()) {
+ insert = !insert;
+ newchar = true;
+ consumed = true;
+ }
+ 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;
+ consumed = true;
+ }
+ 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]);
+ }
+ consumed = true;
+ break;
+ case kRight|k_Repeat:
+ case kRight:
+ if (InEditMode()) {
+ AdvancePos();
+ } else {
+ EnterEditMode();
+ ActivateKeyboard();
+ }
+ consumed = true;
+ 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;
+ consumed = true;
+ }
+ break;
+ case k0|k_Repeat ... k9|k_Repeat:
+ case k0 ... k9: {
+ if (InEditMode()) {
+ if (Setup.NumberKeysForChars) {
+ HighlightSMSKey(NORMALKEY(Key) - k0);
+ 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);
+ }
+ consumed = true;
+ }
+ break; }
+ case kBack:
+ case kOk:
+ if (InEditMode()) {
+ LeaveEditMode(Key == kOk);
+ DeactivateKeyboard();
+ } else {
+ EnterEditMode();
+ ActivateKeyboard();
+ }
+ consumed = true;
+ break;
+ default:
+ if (InEditMode() && BASICKEY(Key) == kKbd) {
+ int c = KEYKBD(Key);
+ if (c <= 0xFF) {
+ if (IsAllowed(Utf8to(lower, c)))
+ Type(c);
+ else {
+ switch (c) {
+ case 0x7F: // backspace
+ if (pos > 0) {
+ pos--;
+ ProcessKey(kYellow);
+ }
+ break;
+ default: ;
+ }
+ }
+ } else {
+ switch (c) {
+ case kfHome: pos = 0; break;
+ case kfEnd: pos = lengthUtf8 - 1; break;
+ case kfIns: ProcessKey(kGreen);
+ case kfDel: ProcessKey(kYellow);
+ default: ;
+ }
+ }
+ consumed = true;
+ }
+ break;
+ }
+ SetText();
+ if (consumed)
+ return rmsConsumed;
+ return rmsNotConsumed;
+}
+
+// --- cRecMenuItemTime -------------------------------------------------------
+cRecMenuItemTime::cRecMenuItemTime(cString text,
+ int initialVal,
+ bool active) {
+ selectable = true;
+ this->text = text;
+ this->value = initialVal;
+ hh = value / 100;
+ mm = value % 100;
+ pos = 0;
+ fresh = true;
+ this->active = active;
+ height = 3 * font->Height() / 2;
+ pixmapVal = NULL;
+}
+
+cRecMenuItemTime::~cRecMenuItemTime(void) {
+ if (pixmapVal)
+ osdManager.releasePixmap(pixmapVal);
+}
+
+void cRecMenuItemTime::SetPixmaps(void) {
+ if (!pixmap) {
+ pixmap = osdManager.requestPixmap(4, cRect(x, y, width, height));
+ pixmapVal = osdManager.requestPixmap(5, cRect(x, y, width, height));
+ } else {
+ pixmap->SetViewPort(cRect(x, y, width, height));
+ pixmapVal->SetViewPort(cRect(x, y, width, height));
+ }
+}
+
+void cRecMenuItemTime::Hide(void) {
+ pixmap->SetLayer(-1);
+ pixmapVal->SetLayer(-1);
+}
+
+void cRecMenuItemTime::Show(void) {
+ pixmap->SetLayer(4);
+ pixmapVal->SetLayer(5);
+}
+
+void cRecMenuItemTime::Draw(void) {
+ int textY = (height - font->Height()) / 2;
+ pixmap->DrawText(cPoint(10, textY), *text, colorText, colorTextBack, font);
+ DrawValue();
+}
+
+void cRecMenuItemTime::DrawValue(void) {
+ pixmapVal->Fill(clrTransparent);
+ 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);
+ }
+ int textX = width - font->Width(buf) - 10;
+ int textY = (height - font->Height()) / 2;
+ pixmapVal->DrawText(cPoint(textX, textY), buf, colorText, clrTransparent, font);
+}
+
+eRecMenuState cRecMenuItemTime::ProcessKey(eKeys Key) {
+ switch (Key & ~k_Repeat) {
+ case kLeft|k_Repeat:
+ case kLeft: {
+ if (--mm < 0) {
+ mm = 59;
+ if (--hh < 0)
+ hh = 23;
+ }
+ fresh = true;
+ value = hh * 100 + mm;
+ DrawValue();
+ return rmsConsumed;
+ break; }
+ case kRight|k_Repeat:
+ case kRight: {
+ if (++mm > 59) {
+ mm = 0;
+ if (++hh > 23)
+ hh = 0;
+ }
+ fresh = true;
+ value = hh * 100 + mm;
+ DrawValue();
+ return rmsConsumed;
+ break; }
+ case k0|k_Repeat ... k9|k_Repeat:
+ case k0 ... 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: ;
+ }
+ value = hh * 100 + mm;
+ DrawValue();
+ return rmsConsumed;
+ break; }
+ default:
+ break;
+ }
+ return rmsNotConsumed;
+}
+
+// --- cRecMenuItemDay -------------------------------------------------------
+cRecMenuItemDay::cRecMenuItemDay(cString text,
+ time_t initialVal,
+ bool active) {
+ selectable = true;
+ this->text = text;
+ this->currentVal = cTimer::SetTime(initialVal, 0);
+ this->active = active;
+ height = 3 * font->Height() / 2;
+ pixmapVal = NULL;
+}
+
+cRecMenuItemDay::~cRecMenuItemDay(void) {
+ if (pixmapVal)
+ osdManager.releasePixmap(pixmapVal);
+}
+
+void cRecMenuItemDay::SetPixmaps(void) {
+ if (!pixmap) {
+ pixmap = osdManager.requestPixmap(4, cRect(x, y, width, height));
+ pixmapVal = osdManager.requestPixmap(5, cRect(x, y, width, height));
+ } else {
+ pixmap->SetViewPort(cRect(x, y, width, height));
+ pixmapVal->SetViewPort(cRect(x, y, width, height));
+ }
+}
+
+void cRecMenuItemDay::Hide(void) {
+ pixmap->SetLayer(-1);
+ pixmapVal->SetLayer(-1);
+}
+
+void cRecMenuItemDay::Show(void) {
+ pixmap->SetLayer(4);
+ pixmapVal->SetLayer(5);
+}
+
+void cRecMenuItemDay::Draw(void) {
+ int textY = (height - font->Height()) / 2;
+ pixmap->DrawText(cPoint(10, textY), *text, colorText, colorTextBack, font);
+ DrawValue();
+}
+
+void cRecMenuItemDay::DrawValue(void) {
+ pixmapVal->Fill(clrTransparent);
+ cString textVal = DateString(currentVal);
+ int textX = width - font->Width(*textVal) - 10;
+ int textY = (height - font->Height()) / 2;
+ pixmapVal->DrawText(cPoint(textX, textY), *textVal, colorText, clrTransparent, font);
+}
+
+eRecMenuState cRecMenuItemDay::ProcessKey(eKeys Key) {
+ switch (Key & ~k_Repeat) {
+ case kLeft:
+ currentVal -= 60*60*24;
+ DrawValue();
+ return rmsConsumed;
+ break;
+ case kRight:
+ currentVal += 60*60*24;
+ DrawValue();
+ return rmsConsumed;
+ break;
+ default:
+ break;
+ }
+ return rmsNotConsumed;
+}
+
+// --- cRecMenuItemTimer -------------------------------------------------------
+cRecMenuItemTimer::cRecMenuItemTimer(const cTimer *timer,
+ eRecMenuState action1,
+ eRecMenuState action2,
+ eRecMenuState action3,
+ time_t conflictStart,
+ time_t conflictStop,
+ time_t overlapStart,
+ time_t overlapStop,
+ bool active) {
+ selectable = true;
+ this->timer = timer;
+ this->action = action1;
+ this->action2 = action2;
+ this->action3 = action3;
+ iconActive = 0;
+ this->conflictStart = conflictStart;
+ this->conflictStop = conflictStop;
+ this->overlapStart = overlapStart;
+ this->overlapStop = overlapStop;
+ this->active = active;
+ height = 3 * font->Height();
+ pixmapIcons = NULL;
+}
+
+cRecMenuItemTimer::~cRecMenuItemTimer(void) {
+ if (pixmapIcons)
+ osdManager.releasePixmap(pixmapIcons);
+ if (pixmapStatus)
+ osdManager.releasePixmap(pixmapStatus);
+}
+
+void cRecMenuItemTimer::SetPixmaps(void) {
+ if (!pixmap) {
+ pixmap = osdManager.requestPixmap(4, cRect(x, y, width, height));
+ pixmapStatus = osdManager.requestPixmap(5, cRect(x, y, width, height));
+ pixmapIcons = osdManager.requestPixmap(6, cRect(x, y, width, height));
+ } else {
+ pixmap->SetViewPort(cRect(x, y, width, height));
+ pixmapStatus->SetViewPort(cRect(x, y, width, height));
+ pixmapIcons->SetViewPort(cRect(x, y, width, height));
+ }
+ pixmapStatus->Fill(clrTransparent);
+ pixmapIcons->Fill(clrTransparent);
+}
+
+void cRecMenuItemTimer::Hide(void) {
+ pixmap->SetLayer(-1);
+ pixmapStatus->SetLayer(-1);
+ pixmapIcons->SetLayer(-1);
+}
+
+void cRecMenuItemTimer::Show(void) {
+ pixmap->SetLayer(4);
+ pixmapStatus->SetLayer(5);
+ pixmapIcons->SetLayer(6);
+}
+
+void cRecMenuItemTimer::Draw(void) {
+ const cChannel *channel = timer->Channel();
+ cString channelName("");
+ int channelTransponder = 0;
+ if (channel) {
+ channelName = channel->Name();
+ channelTransponder = channel->Transponder();
+ }
+ int logoX = DrawIcons();
+ int logoWidth = height * tvguideConfig.logoWidthRatio / tvguideConfig.logoHeightRatio;
+ cImageLoader imgLoader;
+ if (!tvguideConfig.hideChannelLogos) {
+ if (imgLoader.LoadLogo(*channelName, logoWidth, height)) {
+ cImage logo = imgLoader.GetImage();
+ pixmapIcons->DrawImage(cPoint(logoX, 0), logo);
+ logoX += logoWidth + 5;
+ }
+ }
+ int textX = logoX;
+ int textHeightLine1 = (height/2 - font->Height()) / 2;
+ int textHeightLine2 = height/2 - 5 + (height/4 - fontSmall->Height()) / 2;
+ int textHeightLine3 = 3*height/4 - 5 + (height/4 - fontSmall->Height()) / 2;
+ const cEvent *event = timer->Event();
+ cString timerTitle("");
+ if (event)
+ timerTitle = event->Title();
+ cString timeStart = DayDateTime(timer->StartTime());
+ cString timeEnd = TimeString(timer->StopTime());
+ cString timerTime = cString::sprintf("%s - %s", *timeStart, *timeEnd);
+ cString channelInfo = cString::sprintf("%s, %s %d", *channelName, tr("Transp."), channelTransponder);
+ pixmap->DrawText(cPoint(textX, textHeightLine1), *timerTitle, theme.Color(clrFont), clrTransparent, font);
+ pixmap->DrawText(cPoint(textX, textHeightLine2), *timerTime, theme.Color(clrFont), clrTransparent, fontSmall);
+ pixmap->DrawText(cPoint(textX, textHeightLine3), *channelInfo, theme.Color(clrFont), clrTransparent, fontSmall);
+
+ DrawTimerConflict();
+}
+
+int cRecMenuItemTimer::DrawIcons(void) {
+ int iconsX = 10;
+ int iconSize = 64;
+ int iconY = (height - iconSize) / 2;
+ cString iconInfo, iconDelete, iconEdit;
+ if (active) {
+ iconInfo = (iconActive==0)?"info_active":"info_inactive";
+ iconDelete = (iconActive==1)?"delete_active":"delete_inactive";
+ iconEdit = (iconActive==2)?"edit_active":"edit_inactive";
+ } else {
+ iconInfo = "info_inactive";
+ iconDelete = "delete_inactive";
+ iconEdit = "edit_inactive";
+ }
+ cImageLoader imgLoader;
+ if (imgLoader.LoadIcon(iconInfo, iconSize)) {
+ cImage icon = imgLoader.GetImage();
+ pixmapIcons->DrawImage(cPoint(iconsX, iconY), icon);
+ iconsX += iconSize + 5;
+ }
+ if (imgLoader.LoadIcon(iconDelete, iconSize)) {
+ cImage icon = imgLoader.GetImage();
+ pixmapIcons->DrawImage(cPoint(iconsX, iconY), icon);
+ iconsX += iconSize + 5;
+ }
+ if (imgLoader.LoadIcon(iconEdit, iconSize)) {
+ cImage icon = imgLoader.GetImage();
+ pixmapIcons->DrawImage(cPoint(iconsX, iconY), icon);
+ iconsX += iconSize + 5;
+ }
+ return iconsX;
+}
+
+void cRecMenuItemTimer::DrawTimerConflict(void) {
+ int widthConfl = 30 * width / 100;
+ int xConfl = width - widthConfl;
+ int heightConflBar = height / 4;
+ int yConflBar = (height - heightConflBar) / 2;
+ pixmapStatus->DrawRectangle(cRect(xConfl, 0, widthConfl, height), theme.Color(clrRecMenuTimerConflictBackground));
+
+ int completeWidthSecs = conflictStop - conflictStart;
+ int xConfBar = xConfl + (timer->StartTime() - conflictStart) * widthConfl / completeWidthSecs;
+ int widthConfBar = (timer->StopTime() - timer->StartTime()) * widthConfl / completeWidthSecs;
+ pixmapStatus->DrawRectangle(cRect(xConfBar, yConflBar, widthConfBar, heightConflBar), theme.Color(clrRecMenuTimerConflictBar));
+
+ int xOverlap = xConfl + (overlapStart - conflictStart) * widthConfl / completeWidthSecs;
+ int widthOverlap = (overlapStop - overlapStart) * widthConfl / completeWidthSecs;
+
+ pixmapIcons->DrawRectangle(cRect(xOverlap, 0, widthOverlap, height), theme.Color(clrRecMenuTimerConflictOverlap));
+
+ pixmapStatus->DrawRectangle(cRect(xConfl-3,2,1,height-4), theme.Color(clrBorder));
+ pixmapStatus->DrawRectangle(cRect(xConfl-2,0,2,height), theme.Color(clrBackground));
+}
+
+eRecMenuState cRecMenuItemTimer::ProcessKey(eKeys Key) {
+ switch (Key & ~k_Repeat) {
+ case kLeft:
+ if (iconActive > 0) {
+ iconActive--;
+ DrawIcons();
+ return rmsConsumed;
+ } else
+ return rmsNotConsumed;
+ break;
+ case kRight:
+ if (iconActive < 2) {
+ iconActive++;
+ DrawIcons();
+ return rmsConsumed;
+ } else
+ return rmsNotConsumed;
+ break;
+ case kOk:
+ if (iconActive == 0)
+ return action;
+ else if (iconActive == 1)
+ return action2;
+ else if (iconActive == 2)
+ return action3;
+ break;
+ default:
+ break;
+ }
+ return rmsNotConsumed;
+}
+
+// --- cRecMenuItemTimerConflictHeader -------------------------------------------------------
+
+cRecMenuItemTimerConflictHeader::cRecMenuItemTimerConflictHeader(time_t conflictStart,
+ time_t conflictStop,
+ time_t overlapStart,
+ time_t overlapStop) {
+ selectable = false;
+ active = false;
+ this->conflictStart = conflictStart;
+ this->conflictStop = conflictStop;
+ this->overlapStart = overlapStart;
+ this->overlapStop = overlapStop;
+ height = 3*font->Height()/2;
+ pixmapStatus = NULL;
+}
+
+cRecMenuItemTimerConflictHeader::~cRecMenuItemTimerConflictHeader(void) {
+ if (pixmapStatus)
+ osdManager.releasePixmap(pixmapStatus);
+}
+
+void cRecMenuItemTimerConflictHeader::SetPixmaps(void) {
+ pixmap = osdManager.requestPixmap(4, cRect(x, y, width, height));
+ pixmapStatus = osdManager.requestPixmap(5, cRect(x, y, width, height));
+ pixmapStatus->Fill(clrTransparent);
+}
+
+void cRecMenuItemTimerConflictHeader::Hide(void) {
+ pixmap->SetLayer(-1);
+ pixmapStatus->SetLayer(-1);
+}
+
+void cRecMenuItemTimerConflictHeader::Show(void) {
+ pixmap->SetLayer(4);
+ pixmapStatus->SetLayer(5);
+}
+
+void cRecMenuItemTimerConflictHeader::setBackground(void) {
+ pixmap->Fill(clrTransparent);
+}
+
+void cRecMenuItemTimerConflictHeader::Draw(void) {
+ int widthConfl = 30 * width / 100;
+ int xConfl = width - widthConfl;
+ cString headerText = tr("Timer Conflict");
+ int xHeader = (xConfl - font->Width(*headerText)) / 2;
+ int yHeader = (height - font->Height()) / 2;
+ pixmap->DrawText(cPoint(xHeader, yHeader), *headerText, theme.Color(clrFont), clrTransparent, font);
+
+ pixmap->DrawRectangle(cRect(xConfl, 0, widthConfl, height), theme.Color(clrRecMenuTimerConflictBackground));
+
+ int completeWidthSecs = conflictStop - conflictStart;
+ int xOverlap = xConfl + (overlapStart - conflictStart) * widthConfl / completeWidthSecs;
+ int yOverlap = height - fontSmall->Height();
+ int widthOverlap = (overlapStop - overlapStart) * widthConfl / completeWidthSecs;
+
+ pixmapStatus->DrawRectangle(cRect(xOverlap, yOverlap, widthOverlap, height), theme.Color(clrRecMenuTimerConflictOverlap));
+
+ cString strConflStart = TimeString(conflictStart);
+ cString strConflStop = TimeString(conflictStop);
+ cString strOverlapStart = TimeString(overlapStart);
+ cString strOverlapStop = TimeString(overlapStop);
+ int y1 = 5;
+ int y2 = yOverlap;
+ int xConflStart = xConfl + 2;
+ int xConflStop = width - fontSmall->Width(*strConflStop) - 2;
+ int xOverlapStart = xOverlap - fontSmall->Width(*strOverlapStart) - 2;
+ int xOverlapStop = xOverlap + widthOverlap + 2;
+ pixmap->DrawText(cPoint(xConflStart, y1), *strConflStart, theme.Color(clrRecMenuTimerConflictBar), clrTransparent, fontSmall);
+ pixmap->DrawText(cPoint(xConflStop, y1), *strConflStop, theme.Color(clrRecMenuTimerConflictBar), clrTransparent, fontSmall);
+ pixmap->DrawText(cPoint(xOverlapStart, y2), *strOverlapStart, theme.Color(clrRecMenuTimerConflictOverlap), clrTransparent, fontSmall);
+ pixmap->DrawText(cPoint(xOverlapStop, y2), *strOverlapStop, theme.Color(clrRecMenuTimerConflictOverlap), clrTransparent, fontSmall);
+}
+
+// --- cRecMenuItemEvent -------------------------------------------------------
+cRecMenuItemEvent::cRecMenuItemEvent(const cEvent *event,
+ eRecMenuState action1,
+ eRecMenuState action2,
+ bool active) {
+ selectable = true;
+ this->event = event;
+ this->action = action1;
+ this->action2 = action2;
+ iconActive = 0;
+ this->active = active;
+ height = font->Height() + 2*fontSmall->Height() + 10;
+ pixmapText = NULL;
+ pixmapIcons = NULL;
+}
+
+cRecMenuItemEvent::~cRecMenuItemEvent(void) {
+ if (pixmapIcons)
+ osdManager.releasePixmap(pixmapIcons);
+ if (pixmapText)
+ osdManager.releasePixmap(pixmapText);
+}
+
+void cRecMenuItemEvent::SetPixmaps(void) {
+ if (!pixmap) {
+ pixmap = osdManager.requestPixmap(4, cRect(x, y, width, height));
+ pixmapText = osdManager.requestPixmap(5, cRect(x, y, width, height));
+ pixmapText->Fill(clrTransparent);
+ pixmapIcons = osdManager.requestPixmap(6, cRect(x, y, width, height));
+ pixmapIcons->Fill(clrTransparent);
+ } else {
+ pixmap->SetViewPort(cRect(x, y, width, height));
+ pixmapText->SetViewPort(cRect(x, y, width, height));
+ pixmapIcons->SetViewPort(cRect(x, y, width, height));
+ }
+}
+
+void cRecMenuItemEvent::Draw(void) {
+ if (!event)
+ return;
+ int logoX = DrawIcons();
+ const cChannel *channel = Channels.GetByChannelID(event->ChannelID());
+ cString channelName("");
+ if (channel) {
+ channelName = channel->Name();
+ }
+ int logoWidth = height * tvguideConfig.logoWidthRatio / tvguideConfig.logoHeightRatio;
+ cImageLoader imgLoader;
+ if (!tvguideConfig.hideChannelLogos) {
+ if (imgLoader.LoadLogo(*channelName, logoWidth, height)) {
+ cImage logo = imgLoader.GetImage();
+ pixmapText->DrawImage(cPoint(logoX, 0), logo);
+ logoX += logoWidth + 5;
+ }
+ }
+
+ int textX = logoX;
+ int textHeightLine1 = 5;
+ int textHeightLine2 = 5 + fontSmall->Height();
+ int textHeightLine3 = height - fontSmall->Height() - 5;
+
+ cString title = event->Title();
+ cString desc = event->ShortText();
+ cString start = DayDateTime(event->StartTime());
+ cString end = event->GetEndTimeString();
+
+ colorText = active?theme.Color(clrFontActive):theme.Color(clrFont);
+ cString info = cString::sprintf("%s - %s, %s", *start, *end, *channelName);
+ pixmapText->DrawText(cPoint(textX, textHeightLine1), *info, colorText, clrTransparent, fontSmall);
+ pixmapText->DrawText(cPoint(textX, textHeightLine2), *title, colorText, clrTransparent, font);
+ pixmapText->DrawText(cPoint(textX, textHeightLine3), *desc, colorText, clrTransparent, fontSmall);
+}
+
+int cRecMenuItemEvent::DrawIcons(void) {
+ pixmapIcons->Fill(clrTransparent);
+ int iconsX = 10;
+ int iconSize = 64;
+ int iconY = (height - iconSize) / 2;
+ cString iconInfo, iconRecord;
+ if (active) {
+ iconInfo = (iconActive==0)?"info_active":"info_inactive";
+ if (action2 != rmsDisabled)
+ iconRecord = (iconActive==1)?"record_active":"record_inactive";
+ } else {
+ iconInfo = "info_inactive";
+ if (action2 != rmsDisabled)
+ iconRecord = "record_inactive";
+ }
+ cImageLoader imgLoader;
+ if (imgLoader.LoadIcon(iconInfo, iconSize)) {
+ cImage icon = imgLoader.GetImage();
+ pixmapIcons->DrawImage(cPoint(iconsX, iconY), icon);
+ iconsX += iconSize + 5;
+ }
+ if ((action2 != rmsDisabled) && imgLoader.LoadIcon(iconRecord, iconSize)) {
+ cImage icon = imgLoader.GetImage();
+ pixmapIcons->DrawImage(cPoint(iconsX, iconY), icon);
+ iconsX += iconSize + 5;
+ }
+ return iconsX;
+}
+
+void cRecMenuItemEvent::Hide(void) {
+ pixmap->SetLayer(-1);
+ pixmapText->SetLayer(-1);
+ pixmapIcons->SetLayer(-1);
+}
+
+void cRecMenuItemEvent::Show(void) {
+ pixmap->SetLayer(4);
+ pixmapText->SetLayer(5);
+ pixmapIcons->SetLayer(6);
+}
+
+eRecMenuState cRecMenuItemEvent::ProcessKey(eKeys Key) {
+ bool consumed = false;
+ switch (Key & ~k_Repeat) {
+ case kLeft:
+ if (action2 == rmsDisabled)
+ return rmsNotConsumed;
+ if (iconActive == 1) {
+ iconActive = 0;
+ consumed = true;
+ }
+ DrawIcons();
+ if (consumed)
+ return rmsConsumed;
+ else
+ return rmsNotConsumed;
+ break;
+ case kRight: {
+ if (action2 == rmsDisabled)
+ return rmsNotConsumed;
+ if (iconActive == 0) {
+ iconActive = 1;
+ consumed = true;
+ }
+ DrawIcons();
+ if (consumed)
+ return rmsConsumed;
+ else
+ return rmsNotConsumed;
+ break; }
+ case kOk:
+ if (iconActive == 0)
+ return action;
+ else if (iconActive == 1)
+ return action2;
+ break;
+ default:
+ break;
+ }
+ return rmsNotConsumed;
+}
+
+// --- cRecMenuItemChannelChooser -------------------------------------------------------
+cRecMenuItemChannelChooser::cRecMenuItemChannelChooser(cString text,
+ cChannel *initialChannel,
+ bool active) {
+ selectable = true;
+ this->text = text;
+ this->channel = initialChannel;
+ if (initialChannel)
+ initialChannelSet = true;
+ else
+ initialChannelSet = false;
+ channelNumber = 0;
+ fresh = true;
+ this->active = active;
+ height = 2 * font->Height();
+ pixmapChannel = NULL;
+}
+
+cRecMenuItemChannelChooser::~cRecMenuItemChannelChooser(void) {
+ if (pixmapChannel)
+ osdManager.releasePixmap(pixmapChannel);
+}
+
+void cRecMenuItemChannelChooser::SetPixmaps(void) {
+ if (!pixmap) {
+ pixmap = osdManager.requestPixmap(4, cRect(x, y, width, height));
+ pixmapChannel = osdManager.requestPixmap(5, cRect(x, y, width, height));
+ } else {
+ pixmap->SetViewPort(cRect(x, y, width, height));
+ pixmapChannel->SetViewPort(cRect(x, y, width, height));
+ }
+}
+
+void cRecMenuItemChannelChooser::Hide(void) {
+ pixmap->SetLayer(-1);
+ pixmapChannel->SetLayer(-1);
+}
+
+void cRecMenuItemChannelChooser::Show(void) {
+ pixmap->SetLayer(4);
+ pixmapChannel->SetLayer(5);
+}
+
+void cRecMenuItemChannelChooser::Draw(void) {
+ int textY = (height - font->Height()) / 2;
+ pixmap->DrawText(cPoint(10, textY), *text, colorText, colorTextBack, font);
+ DrawValue();
+}
+
+void cRecMenuItemChannelChooser::DrawValue(void) {
+ pixmapChannel->Fill(clrTransparent);
+ int textY = (height - font->Height()) / 2;
+ if (channel) {
+ cString textVal = cString::sprintf("%d - %s", channel->Number(), channel->Name());
+ int textX = width - font->Width(*textVal) - 10;
+ pixmapChannel->DrawText(cPoint(textX, textY), *textVal, colorText, clrTransparent, font);
+ int logoWidth = height * tvguideConfig.logoWidthRatio / tvguideConfig.logoHeightRatio;
+ int logoX = textX - logoWidth - 10;
+ cImageLoader imgLoader;
+ if (imgLoader.LoadLogo(channel->Name(), logoWidth, height)) {
+ cImage logo = imgLoader.GetImage();
+ pixmapChannel->DrawImage(cPoint(logoX, 0), logo);
+ }
+ } else {
+ cString textVal = tr("all Channels");
+ int textX = width - font->Width(*textVal) - 10;
+ pixmapChannel->DrawText(cPoint(textX, textY), *textVal, colorText, clrTransparent, font);
+ }
+}
+
+int cRecMenuItemChannelChooser::GetIntValue(void) {
+ if (channel)
+ return channel->Number();
+ return 0;
+}
+
+
+eRecMenuState cRecMenuItemChannelChooser::ProcessKey(eKeys Key) {
+ switch (Key & ~k_Repeat) {
+ case kLeft: {
+ fresh = true;
+ if (!channel)
+ return rmsConsumed;
+ cChannel *prev = channel;
+ cChannel *firstChannel = Channels.First();
+ if(firstChannel->GroupSep())
+ firstChannel = Channels.Next(firstChannel);
+ if (prev == firstChannel) {
+ if (!initialChannelSet)
+ channel = NULL;
+ } else {
+ while (prev = Channels.Prev(prev)) {
+ if(!prev->GroupSep()) {
+ channel = prev;
+ break;
+ }
+ }
+ }
+ DrawValue();
+ return rmsConsumed;
+ break; }
+ case kRight: {
+ fresh = true;
+ if (!channel) {
+ channel = Channels.First();
+ if(channel->GroupSep())
+ channel = Channels.Next(channel);
+ } else {
+ cChannel *next = channel;
+ while (next = Channels.Next(next)) {
+ if(!next->GroupSep()) {
+ channel = next;
+ break;
+ }
+ }
+ }
+ DrawValue();
+ return rmsConsumed;
+ break; }
+ case k0 ... k9: {
+ if (fresh) {
+ channelNumber = 0;
+ fresh = false;
+ }
+ channelNumber = channelNumber * 10 + (Key - k0);
+ cChannel *chanNew = Channels.GetByNumber(channelNumber);
+ if (chanNew) {
+ channel = chanNew;
+ DrawValue();
+ }
+ return rmsConsumed;
+ break; }
+ default:
+ break;
+ }
+ return rmsNotConsumed;
+}
+
+// --- cRecMenuItemDayChooser -------------------------------------------------------
+cRecMenuItemDayChooser::cRecMenuItemDayChooser(cString text,
+ int weekdays,
+ bool active) {
+ selectable = true;
+ this->text = text;
+ this->weekdays = weekdays;
+ this->active = active;
+ height = 2 * font->Height();
+ selectedDay = 0;
+ pixmapWeekdays = NULL;
+ pixmapWeekdaysSelect = NULL;
+}
+
+cRecMenuItemDayChooser::~cRecMenuItemDayChooser(void) {
+ if (pixmapWeekdays)
+ osdManager.releasePixmap(pixmapWeekdays);
+ if (pixmapWeekdaysSelect)
+ osdManager.releasePixmap(pixmapWeekdaysSelect);
+}
+
+void cRecMenuItemDayChooser::SetPixmaps(void) {
+ if (!pixmap) {
+ pixmap = osdManager.requestPixmap(4, cRect(x, y, width, height));
+ pixmapWeekdays = osdManager.requestPixmap(5, cRect(x, y, width, height));
+ pixmapWeekdaysSelect = osdManager.requestPixmap(6, cRect(x, y, width, height));
+ } else {
+ pixmap->SetViewPort(cRect(x, y, width, height));
+ pixmapWeekdays->SetViewPort(cRect(x, y, width, height));
+ pixmapWeekdaysSelect->SetViewPort(cRect(x, y, width, height));
+ }
+ SetSizes();
+}
+
+void cRecMenuItemDayChooser::Hide(void) {
+ pixmap->SetLayer(-1);
+ pixmapWeekdays->SetLayer(-1);
+ pixmapWeekdaysSelect->SetLayer(-1);
+}
+
+void cRecMenuItemDayChooser::Show(void) {
+ pixmap->SetLayer(4);
+ pixmapWeekdays->SetLayer(5);
+ pixmapWeekdaysSelect->SetLayer(6);
+}
+
+void cRecMenuItemDayChooser::SetSizes(void) {
+ days = trVDR("MTWTFSS");
+ int maxWidth = 0;
+ for (unsigned i=0; i<days.length(); ++i) {
+ int charWidth = font->Width(days.at(i));
+ if (charWidth > maxWidth)
+ maxWidth = charWidth;
+ }
+ daysSize = min(maxWidth + 15, height-4);
+ daysX = width - 10 - 7*daysSize;
+ daysY = (height - daysSize) / 2;
+}
+
+void cRecMenuItemDayChooser::setBackground() {
+ cRecMenuItem::setBackground();
+ if (active) {
+ DrawHighlight(selectedDay);
+ } else {
+ DrawHighlight(-1);
+ }
+}
+
+void cRecMenuItemDayChooser::Draw(void) {
+ int textY = (height - font->Height()) / 2;
+ pixmap->DrawText(cPoint(10, textY), *text, colorText, colorTextBack, font);
+ DrawDays();
+}
+
+void cRecMenuItemDayChooser::DrawDays(void) {
+ pixmapWeekdays->Fill(clrTransparent);
+ int textY = (height - font->Height()) / 2;
+ pixmapWeekdays->DrawRectangle(cRect(daysX, daysY, 7*daysSize, daysSize), theme.Color(clrBorder));
+ int currentX = daysX;
+ for (unsigned day=0; day<days.length(); ++day) {
+ cString strDay = cString::sprintf("%c", days.at(day));
+ pixmapWeekdays->DrawRectangle(cRect(currentX+2, daysY+2, daysSize-4, daysSize-4), theme.Color(clrBackground));
+ tColor colorDay = WeekDaySet(day)?theme.Color(clrRecMenuDayActive)
+ :theme.Color(clrRecMenuDayInactive);
+ int textX = currentX + (daysSize - font->Width(*strDay)) / 2;
+ pixmapWeekdays->DrawText(cPoint(textX, textY), *strDay, colorDay, clrTransparent, font);
+ currentX += daysSize;
+ }
+}
+
+void cRecMenuItemDayChooser::DrawHighlight(int day) {
+ pixmapWeekdaysSelect->Fill(clrTransparent);
+ if (day > -1) {
+ int currentX = daysX + day*daysSize;
+ pixmapWeekdaysSelect->DrawRectangle(cRect(currentX, daysY, daysSize, daysSize), theme.Color(clrRecMenuDayHighlight));
+ }
+}
+
+bool cRecMenuItemDayChooser::WeekDaySet(unsigned day) {
+ return weekdays & (1 << day);
+}
+
+void cRecMenuItemDayChooser::ToggleDay(void) {
+ bool dayActive = WeekDaySet(selectedDay);
+ int dayBit = pow(2, selectedDay);
+ if (dayActive) {
+ weekdays -= dayBit;
+ } else {
+ weekdays += dayBit;
+ }
+}
+
+eRecMenuState cRecMenuItemDayChooser::ProcessKey(eKeys Key) {
+ switch (Key & ~k_Repeat) {
+ case kLeft: {
+ selectedDay--;
+ if (selectedDay<0)
+ selectedDay += 7;
+ DrawHighlight(selectedDay);
+ return rmsConsumed;
+ break; }
+ case kRight: {
+ selectedDay = (selectedDay+1)%7;
+ DrawHighlight(selectedDay);
+ return rmsConsumed;
+ break; }
+ case kOk:
+ ToggleDay();
+ DrawDays();
+ return rmsConsumed;
+ break;
+ default:
+ break;
+ }
+ return rmsNotConsumed;
+}
+
+// --- cRecMenuItemRecording -------------------------------------------------------
+cRecMenuItemRecording::cRecMenuItemRecording(cRecording *recording, bool active) {
+ selectable = true;
+ this->recording = recording;
+ this->active = active;
+ height = font->Height() + 2*fontSmall->Height() + 10;
+ pixmapText = NULL;
+}
+
+cRecMenuItemRecording::~cRecMenuItemRecording(void) {
+ if (pixmapText)
+ osdManager.releasePixmap(pixmapText);
+}
+
+void cRecMenuItemRecording::SetPixmaps(void) {
+ if (!pixmap) {
+ pixmap = osdManager.requestPixmap(4, cRect(x, y, width, height));
+ pixmapText = osdManager.requestPixmap(5, cRect(x, y, width, height));
+ pixmapText->Fill(clrTransparent);
+ } else {
+ pixmap->SetViewPort(cRect(x, y, width, height));
+ pixmapText->SetViewPort(cRect(x, y, width, height));
+ }
+}
+
+void cRecMenuItemRecording::Draw(void) {
+ if (!recording)
+ return;
+ const cRecordingInfo *recInfo = recording->Info();
+ cChannel *channel = Channels.GetByChannelID(recInfo->ChannelID());
+ cString channelName = tr("unknown channel");
+ if (channel)
+ channelName = channel->Name();
+ cString name = recording->Name();
+ cString dateTime = cString::sprintf("%s, %s", *DateString(recording->Start()), *TimeString(recording->Start()));
+
+ int recDuration = recording->LengthInSeconds() / 60;
+
+ cString recDetails = cString::sprintf("%s: %d %s, %s %s %s \"%s\"", tr("Duration"), recDuration, tr("min"), tr("recorded at"), *dateTime, tr("from"), *channelName);
+ recDetails = CutText(*recDetails, width - 40, fontSmall).c_str();
+ int text1Y = (height/2 - font->Height()) / 2 + 5;
+ int text2Y = height/2 + (height/2 - fontSmall->Height())/2 - 5;
+ colorText = active?theme.Color(clrFontActive):theme.Color(clrFont);
+ pixmapText->DrawText(cPoint(10, text1Y), *name, colorText, clrTransparent, font);
+ pixmapText->DrawText(cPoint(10, text2Y), *recDetails, colorText, clrTransparent, fontSmall);
+}
+
+void cRecMenuItemRecording::Hide(void) {
+ pixmap->SetLayer(-1);
+ pixmapText->SetLayer(-1);
+}
+
+void cRecMenuItemRecording::Show(void) {
+ pixmap->SetLayer(4);
+ pixmapText->SetLayer(5);
+}
diff --git a/recmenuitem.h b/recmenuitem.h
new file mode 100644
index 0000000..780eac9
--- /dev/null
+++ b/recmenuitem.h
@@ -0,0 +1,465 @@
+#ifndef __TVGUIDE_RECMENUITEM_H
+#define __TVGUIDE_RECMENUITEM_H
+
+#define AUTO_ADVANCE_TIMEOUT 1500
+
+enum eRecMenuState {
+ rmsConsumed,
+ rmsNotConsumed,
+ rmsRefresh,
+ rmsContinue,
+ rmsClose,
+ rmsInstantRecord,
+ rmsIgnoreTimerConflict,
+ rmsDeleteTimerConflictMenu,
+ rmsEditTimerConflictMenu,
+ rmsSaveTimerConflictMenu,
+ rmsTimerConflictShowInfo,
+ rmsDeleteTimer,
+ rmsDeleteTimerConfirmation,
+ rmsEditTimer,
+ rmsSaveTimer,
+ rmsSearch,
+ rmsSearchWithOptions,
+ rmsSearchPerform,
+ rmsSearchShowInfo,
+ rmsSearchRecord,
+ rmsSearchRecordConfirm,
+ rmsSearchNothingFoundConfirm,
+ rmsSeriesTimer,
+ rmsSeriesTimerCreate,
+ rmsSearchTimer,
+ rmsSearchTimerOptions,
+ rmsSearchTimerOptionsReload,
+ rmsSearchTimerUseTemplate,
+ rmsSearchTimerOptionsManually,
+ rmsSearchTimerTestManually,
+ rmsSearchTimerTestTemplate,
+ rmsSearchTimerNothingFoundConfirm,
+ rmsSearchTimerCreateManually,
+ rmsSearchTimerCreateTemplate,
+ rmsSwitchTimer,
+ rmsSwitchTimerCreate,
+ rmsSwitchTimerDelete,
+ rmsRecordingSearch,
+ rmsRecordingSearchResult,
+ rmsTimerConflict,
+ rmsTimerConflicts,
+ rmsDisabled,
+};
+
+enum eDependend {
+ eGreater,
+ eLower,
+};
+// --- cRecMenuItem -------------------------------------------------------------
+class cRecMenuItem : public cListObject, public cStyledPixmap {
+protected:
+ int x, y;
+ int width, height;
+ bool selectable;
+ bool active;
+ bool drawn;
+ eRecMenuState action;
+ tColor colorText;
+ tColor colorTextBack;
+ const cFont *font;
+ const cFont *fontSmall;
+public:
+ cRecMenuItem(void);
+ virtual ~cRecMenuItem(void);
+ void SetGeometry(int x, int y, int width);
+ virtual void SetPixmaps(void);
+ virtual int GetHeight(void) { return height; };
+ virtual int GetWidth(void) { return 0; };
+ virtual void CalculateHeight(int textWidth) {};
+ void setActive(void) { this->active = true; }
+ void setInactive(void) { this->active = false; }
+ bool isSelectable(void) { return selectable; }
+ bool isActive(void) { return active; }
+ virtual void setBackground(void);
+ virtual void Draw(void) {};
+ virtual void Hide(void) { pixmap->SetLayer(-1);};
+ virtual void Show(void) { pixmap->SetLayer(4);};
+ virtual int GetIntValue(void) { return -1; };
+ virtual time_t GetTimeValue(void) { return 0; };
+ virtual bool GetBoolValue(void) { return false; };
+ virtual cString GetStringValue(void) { return cString(""); };
+ virtual const cEvent *GetEventValue(void) { return NULL; };
+ virtual eRecMenuState ProcessKey(eKeys Key) { return rmsNotConsumed; };
+
+};
+
+// --- cRecMenuItemButton -------------------------------------------------------
+class cRecMenuItemButton : public cRecMenuItem {
+private:
+ cString text;
+ bool halfWidth;
+public:
+ cRecMenuItemButton(const char *text, eRecMenuState action, bool active, bool halfWidth = false);
+ virtual ~cRecMenuItemButton(void);
+ int GetWidth(void);
+ void SetPixmaps(void);
+ void Draw(void);
+ eRecMenuState ProcessKey(eKeys Key);
+};
+
+// --- cRecMenuItemButtonYesNo -------------------------------------------------------
+class cRecMenuItemButtonYesNo : public cRecMenuItem {
+private:
+ cString textYes;
+ cString textNo;
+ eRecMenuState actionNo;
+ bool yesActive;
+ cStyledPixmap *pixmapNo;
+ tColor colorTextNo;
+public:
+ cRecMenuItemButtonYesNo(cString textYes,
+ cString textNo,
+ eRecMenuState actionYes,
+ eRecMenuState actionNo,
+ bool active);
+ virtual ~cRecMenuItemButtonYesNo(void);
+ void SetPixmaps(void);
+ void setBackground(void);
+ void Hide(void);
+ void Show(void);
+ eRecMenuState ProcessKey(eKeys Key);
+ void Draw(void);
+};
+
+// --- cRecMenuItemInfo -------------------------------------------------------
+class cRecMenuItemInfo : public cRecMenuItem {
+private:
+ cString text;
+ cTextWrapper wrapper;
+ int border;
+public:
+ cRecMenuItemInfo(const char *text);
+ virtual ~cRecMenuItemInfo(void);
+ void setBackground(void);
+ void CalculateHeight(int textWidth);
+ void Draw(void);
+};
+
+// --- cRecMenuItemInt -------------------------------------------------------
+class cRecMenuItemInt : public cRecMenuItem {
+private:
+ cString text;
+ int currentVal;
+ int minVal;
+ int maxVal;
+ cPixmap *pixmapVal;
+ bool fresh;
+ void DrawValue(void);
+public:
+ cRecMenuItemInt(cString text,
+ int initialVal,
+ int minVal,
+ int maxVal,
+ bool active);
+ virtual ~cRecMenuItemInt(void);
+ void SetPixmaps(void);
+ void Hide(void);
+ void Show(void);
+ void setBackground(void);
+ eRecMenuState ProcessKey(eKeys Key);
+ void Draw(void);
+ int GetIntValue(void) { return currentVal; };
+};
+
+// --- cRecMenuItemBool -------------------------------------------------------
+class cRecMenuItemBool : public cRecMenuItem {
+private:
+ cString text;
+ bool yes;
+ cPixmap *pixmapVal;
+ bool refresh;
+ void DrawValue(void);
+public:
+ cRecMenuItemBool(cString text,
+ bool initialVal,
+ bool refresh,
+ bool active);
+ virtual ~cRecMenuItemBool(void);
+ void SetPixmaps(void);
+ void Hide(void);
+ void Show(void);
+ eRecMenuState ProcessKey(eKeys Key);
+ void Draw(void);
+ bool GetBoolValue(void) { return yes; };
+};
+
+// --- cRecMenuItemSelect -------------------------------------------------------
+class cRecMenuItemSelect : public cRecMenuItem {
+private:
+ cString text;
+ int currentVal;
+ const char * const *strings;
+ int numValues;
+ cPixmap *pixmapVal;
+ void DrawValue(void);
+public:
+ cRecMenuItemSelect(cString text,
+ const char * const *Strings,
+ int initialVal,
+ int numValues,
+ bool active);
+ virtual ~cRecMenuItemSelect(void);
+ void SetPixmaps(void);
+ void Hide(void);
+ void Show(void);
+ eRecMenuState ProcessKey(eKeys Key);
+ void Draw(void);
+ int GetIntValue(void) { return currentVal; };
+ cString GetStringValue(void) { return strings[currentVal]; };
+};
+
+// --- cRecMenuItemText -------------------------------------------------------
+class cRecMenuItemText : public cRecMenuItem {
+private:
+ cString title;
+ char *value;
+ int length;
+ const char *allowed;
+ int pos, offset;
+ bool insert, newchar, uppercase;
+ int lengthUtf8;
+ uint *valueUtf8;
+ uint *allowedUtf8;
+ uint *charMapUtf8;
+ uint *currentCharUtf8;
+ eKeys lastKey;
+ cTimeMs autoAdvanceTimeout;
+ cPixmap *pixmapVal;
+ cStyledPixmap *pixmapKeyboard;
+ cPixmap *pixmapKeyboardHighlight;
+ cPixmap *pixmapKeyboardIcons;
+ int keyboardWidth;
+ int gridWidth;
+ int gridHeight;
+ int keyboardHeight;
+ bool keyboardDrawn;
+ uint *IsAllowed(uint c);
+ void AdvancePos(void);
+ uint Inc(uint c, bool Up);
+ void Type(uint c);
+ void Insert(void);
+ void Delete(void);
+ void EnterEditMode(void);
+ void LeaveEditMode(bool SaveValue = false);
+ bool InEditMode(void) { return valueUtf8 != NULL; };
+ void SetText(void);
+ void ActivateKeyboard(void);
+ void DeactivateKeyboard(void);
+ void HighlightSMSKey(int num);
+ void ClearSMSKey(void);
+ char *GetSMSKeys(int num);
+ void DrawValue(char *newValue);
+public:
+ cRecMenuItemText(cString title,
+ char *initialVal,
+ int length,
+ bool active);
+ virtual ~cRecMenuItemText(void);
+ void SetPixmaps(void);
+ void Hide(void);
+ void Show(void);
+ void setBackground(void);
+ eRecMenuState ProcessKey(eKeys Key);
+ void Draw(void);
+ cString GetStringValue(void) { return value; };
+};
+
+
+// --- cRecMenuItemTime -------------------------------------------------------
+class cRecMenuItemTime : public cRecMenuItem {
+private:
+ cString text;
+ int value;
+ int mm;
+ int hh;
+ int pos;
+ bool fresh;
+ cPixmap *pixmapVal;
+ void DrawValue(void);
+public:
+ cRecMenuItemTime(cString text,
+ int initialVal,
+ bool active);
+ virtual ~cRecMenuItemTime(void);
+ void SetPixmaps(void);
+ void Hide(void);
+ void Show(void);
+ eRecMenuState ProcessKey(eKeys Key);
+ void Draw(void);
+ int GetIntValue(void) { return value; };
+};
+
+// --- cRecMenuItemDay -------------------------------------------------------
+class cRecMenuItemDay : public cRecMenuItem {
+private:
+ cString text;
+ time_t currentVal;
+ cPixmap *pixmapVal;
+ void DrawValue(void);
+public:
+ cRecMenuItemDay(cString text,
+ time_t initialVal,
+ bool active);
+ virtual ~cRecMenuItemDay(void);
+ void SetPixmaps(void);
+ void Hide(void);
+ void Show(void);
+ eRecMenuState ProcessKey(eKeys Key);
+ void Draw(void);
+ time_t GetTimeValue(void) { return currentVal; };
+};
+
+// --- cRecMenuItemTimer -------------------------------------------------------
+class cRecMenuItemTimer : public cRecMenuItem {
+private:
+ const cTimer *timer;
+ eRecMenuState action2;
+ eRecMenuState action3;
+ int iconActive;
+ cPixmap *pixmapIcons;
+ cPixmap *pixmapStatus;
+ time_t conflictStart;
+ time_t conflictStop;
+ time_t overlapStart;
+ time_t overlapStop;
+ int DrawIcons(void);
+ void DrawTimerConflict(void);
+public:
+ cRecMenuItemTimer(const cTimer *timer,
+ eRecMenuState action1,
+ eRecMenuState action2,
+ eRecMenuState action3,
+ time_t conflictStart,
+ time_t conflictStop,
+ time_t overlapStart,
+ time_t overlapStop,
+ bool active);
+ virtual ~cRecMenuItemTimer(void);
+ void SetPixmaps(void);
+ void Hide(void);
+ void Show(void);
+ eRecMenuState ProcessKey(eKeys Key);
+ void Draw(void);
+};
+
+// --- cRecMenuItemTimerConflictHeader -------------------------------------------------------
+
+class cRecMenuItemTimerConflictHeader: public cRecMenuItem {
+private:
+ cPixmap *pixmapStatus;
+ time_t conflictStart;
+ time_t conflictStop;
+ time_t overlapStart;
+ time_t overlapStop;
+public:
+ cRecMenuItemTimerConflictHeader(time_t conflictStart,
+ time_t conflictStop,
+ time_t overlapStart,
+ time_t overlapStop);
+ virtual ~cRecMenuItemTimerConflictHeader(void);
+ void SetPixmaps(void);
+ void Hide(void);
+ void Show(void);
+ void setBackground(void);
+ void Draw(void);
+};
+
+// --- cRecMenuItemEvent -------------------------------------------------------
+class cRecMenuItemEvent : public cRecMenuItem {
+private:
+ const cEvent *event;
+ eRecMenuState action2;
+ int iconActive;
+ cPixmap *pixmapText;
+ cPixmap *pixmapIcons;
+ int DrawIcons(void);
+public:
+ cRecMenuItemEvent(const cEvent *event,
+ eRecMenuState action1,
+ eRecMenuState action2,
+ bool active);
+ virtual ~cRecMenuItemEvent(void);
+ void SetPixmaps(void);
+ void Hide(void);
+ void Show(void);
+ const cEvent *GetEventValue(void) { return event; };
+ eRecMenuState ProcessKey(eKeys Key);
+ void Draw(void);
+};
+
+// --- cRecMenuItemChannelChooser -------------------------------------------------------
+class cRecMenuItemChannelChooser : public cRecMenuItem {
+private:
+ cString text;
+ cChannel *channel;
+ int channelNumber;
+ bool initialChannelSet;
+ bool fresh;
+ cPixmap *pixmapChannel;
+ void DrawValue(void);
+public:
+ cRecMenuItemChannelChooser (cString text,
+ cChannel *initialChannel,
+ bool active);
+ virtual ~cRecMenuItemChannelChooser(void);
+ void SetPixmaps(void);
+ void Hide(void);
+ void Show(void);
+ eRecMenuState ProcessKey(eKeys Key);
+ void Draw(void);
+ int GetIntValue(void);
+};
+
+// --- cRecMenuItemDayChooser -------------------------------------------------------
+class cRecMenuItemDayChooser : public cRecMenuItem {
+private:
+ cString text;
+ int weekdays;
+ std::string days;
+ int daysX;
+ int daysY;
+ int daysSize;
+ int selectedDay;
+ cPixmap *pixmapWeekdays;
+ cPixmap *pixmapWeekdaysSelect;
+ void SetSizes(void);
+ void DrawDays(void);
+ void DrawHighlight(int day);
+ void ToggleDay(void);
+ bool WeekDaySet(unsigned day);
+public:
+ cRecMenuItemDayChooser (cString text,
+ int weekdays,
+ bool active);
+ virtual ~cRecMenuItemDayChooser(void);
+ void SetPixmaps(void);
+ void Hide(void);
+ void Show(void);
+ void setBackground(void);
+ eRecMenuState ProcessKey(eKeys Key);
+ void Draw(void);
+ int GetIntValue(void) { return weekdays;} ;
+};
+
+// --- cRecMenuItemRecording -------------------------------------------------------
+class cRecMenuItemRecording : public cRecMenuItem {
+private:
+ cRecording *recording;
+ cPixmap *pixmapText;
+public:
+ cRecMenuItemRecording(cRecording *recording, bool active);
+ virtual ~cRecMenuItemRecording(void);
+ void SetPixmaps(void);
+ void Hide(void);
+ void Show(void);
+ void Draw(void);
+};
+
+#endif //__TVGUIDE_RECMENUITEM_H \ No newline at end of file
diff --git a/recmenumanager.c b/recmenumanager.c
new file mode 100644
index 0000000..cd34c12
--- /dev/null
+++ b/recmenumanager.c
@@ -0,0 +1,521 @@
+#include "recmenumanager.h"
+
+cRecMenuManager::cRecMenuManager(void) {
+ active = false;
+ activeMenu = NULL;
+ activeMenuBuffer = NULL;
+ recManager = new cRecManager();
+ recManager->SetEPGSearchPlugin();
+ instantRecord = false;
+ currentConflict = -1;
+ templateID = -1;
+ timer = NULL;
+ searchWithOptions = false;
+ detailViewActive = false;
+}
+
+cRecMenuManager::~cRecMenuManager(void) {
+ if (activeMenu) {
+ active = false;
+ delete activeMenu;
+ activeMenu = NULL;
+ }
+ delete recManager;
+}
+
+void cRecMenuManager::Start(const cEvent *event) {
+ active = true;
+ activeMenuBuffer = NULL;
+ instantRecord = false;
+ currentConflict = -1;
+ templateID = -1;
+ timer = NULL;
+ searchWithOptions = false;
+ detailViewActive = false;
+ SetBackground();
+ this->event = event;
+ activeMenu = new cRecMenuMain(recManager->EpgSearchAvailable(), event->HasTimer(), SwitchTimers.EventInSwitchList(event));
+ activeMenu->Display();
+ osdManager.flush();
+}
+
+void cRecMenuManager::Close(void) {
+ event = NULL;
+ active = false;
+ if (activeMenu) {
+ delete activeMenu;
+ activeMenu = NULL;
+ }
+ DeleteBackground();
+}
+
+void cRecMenuManager::SetBackground(void) {
+ int backgroundWidth = tvguideConfig.osdWidth;
+ int backgroundHeight = tvguideConfig.osdHeight;
+ pixmapBackground = osdManager.requestPixmap(3, cRect(0, 0, backgroundWidth, backgroundHeight));
+ pixmapBackground->Fill(theme.Color(clrRecMenuBackground));
+ if (tvguideConfig.scaleVideo) {
+ int tvHeight = tvguideConfig.statusHeaderHeight;
+ int tvWidth = tvHeight * 16 / 9;
+ int tvX = tvguideConfig.osdWidth - tvWidth;
+ pixmapBackground->DrawRectangle(cRect(tvX, 0, tvWidth, tvHeight), clrTransparent);
+ }
+}
+
+void cRecMenuManager::DeleteBackground(void) {
+ osdManager.releasePixmap(pixmapBackground);
+}
+
+eOSState cRecMenuManager::StateMachine(eRecMenuState nextState) {
+ eOSState state = osContinue;
+ switch (nextState) {
+ /*
+ * --------- INSTANT RECORDING ---------------------------
+ */
+ case rmsInstantRecord: {
+ //Creating timer for active Event
+ //if no conflict, confirm and exit
+ instantRecord = true;
+ delete activeMenu;
+ cTimer *timer = recManager->createTimer(event);
+ if (!displayTimerConflict(timer)) {
+ activeMenu = new cRecMenuConfirmTimer(event);
+ activeMenu->Display();
+ }
+ break; }
+ case rmsIgnoreTimerConflict:
+ //Confirming created Timer
+ if (instantRecord) {
+ delete activeMenu;
+ activeMenu = new cRecMenuConfirmTimer(event);
+ activeMenu->Display();
+ } else {
+ state = osEnd;
+ Close();
+ }
+ break;
+ case rmsTimerConflictShowInfo: {
+ int timerIndex = activeMenu->GetActive(true);
+ int timerID = conflictList[currentConflict].timerIDs[timerIndex];
+ cTimer *t = Timers.Get(timerID);
+ if (t) {
+ const cEvent *ev = t->Event();
+ if (ev) {
+ activeMenu->Hide();
+ detailView = new cDetailView(ev);
+ detailView->drawHeader();
+ detailView->drawContent();
+ detailView->drawScrollbar();
+ detailViewActive = true;
+ }
+ }
+ break;}
+ case rmsDeleteTimerConflictMenu: {
+ //delete timer out of current timer conflict
+ //active menu: cRecMenuTimerConflict
+ int timerIndex = activeMenu->GetActive(true);
+ int timerID = conflictList[currentConflict].timerIDs[timerIndex];
+ recManager->DeleteTimer(timerID);
+ delete activeMenu;
+ if (!displayTimerConflict(timerID)) {
+ activeMenu = new cRecMenuConfirmTimer(event);
+ activeMenu->Display();
+ }
+ break; }
+ case rmsEditTimerConflictMenu: {
+ //edit timer out of current timer conflict
+ //active menu: cRecMenuTimerConflict
+ int activeItem = activeMenu->GetActive(true);
+ int timerID = conflictList[currentConflict].timerIDs[activeItem];
+ timer = Timers.Get(timerID);
+ if (timer) {
+ delete activeMenu;
+ activeMenu = new cRecMenuEditTimer(timer, rmsSaveTimerConflictMenu);
+ activeMenu->Display();
+ }
+ break; }
+ case rmsSaveTimerConflictMenu: {
+ //save timer from current timer conflict
+ recManager->SaveTimer(timer, activeMenu);
+ delete activeMenu;
+ if (!displayTimerConflict(timer)) {
+ activeMenu = new cRecMenuConfirmTimer(event);
+ activeMenu->Display();
+ }
+ break; }
+ case rmsDeleteTimer:
+ //delete timer for active event
+ delete activeMenu;
+ if (recManager->IsRecorded(event)) {
+ activeMenu = new cRecMenuAskDeleteTimer(event);
+ } else {
+ recManager->DeleteTimer(event);
+ activeMenu = new cRecMenuConfirmDeleteTimer(event);
+ }
+ activeMenu->Display();
+ break;
+ case rmsDeleteTimerConfirmation:
+ //delete running timer for active event
+ recManager->DeleteTimer(event);
+ delete activeMenu;
+ activeMenu = new cRecMenuConfirmDeleteTimer(event);
+ activeMenu->Display();
+ break;
+ case rmsEditTimer: {
+ //edit timer for active event
+ timer = Timers.GetMatch(event);
+ if (timer) {
+ delete activeMenu;
+ activeMenu = new cRecMenuEditTimer(timer, rmsSaveTimer);
+ activeMenu->Display();
+ }
+ break; }
+ case rmsSaveTimer: {
+ //save timer for active event
+ recManager->SaveTimer(timer, activeMenu);
+ state = osEnd;
+ Close();
+ break; }
+ /*
+ * --------- SERIES TIMER ---------------------------------
+ */
+ case rmsSeriesTimer: {
+ delete activeMenu;
+ cChannel *channel = Channels.GetByChannelID(event->ChannelID());
+ activeMenu = new cRecMenuSeriesTimer(channel, event);
+ activeMenu->Display();
+ break; }
+ case rmsSeriesTimerCreate: {
+ cTimer *seriesTimer = recManager->CreateSeriesTimer(activeMenu);
+ delete activeMenu;
+ activeMenu = new cRecMenuConfirmSeriesTimer(seriesTimer);
+ activeMenu->Display();
+ break; }
+ /*
+ * --------- SEARCH TIMER ---------------------------------
+ */
+ case rmsSearchTimer:
+ delete activeMenu;
+ activeMenu = new cRecMenuSearchTimer(event);
+ activeMenu->Display();
+ break;
+ case rmsSearchTimerOptions: {
+ searchString = *activeMenu->GetStringValue(1);
+ delete activeMenu;
+ if (isempty(*searchString)) {
+ activeMenu = new cRecMenuSearchTimer(event);
+ } else {
+ epgSearchTemplates = recManager->ReadEPGSearchTemplates();
+ int numTemplates = epgSearchTemplates.size();
+ if (numTemplates > 0) {
+ activeMenu = new cRecMenuSearchTimerTemplates(searchString, epgSearchTemplates);
+ } else {
+ activeMenu = new cRecMenuSearchTimerOptions(searchString);
+ }
+ }
+ activeMenu->Display();
+ break; }
+ case rmsSearchTimerOptionsReload: {
+ int numTemplates = epgSearchTemplates.size();
+ delete activeMenu;
+ activeMenu = new cRecMenuSearchTimerTemplates(searchString, epgSearchTemplates);
+ activeMenu->Display();
+ break; }
+ case rmsSearchTimerUseTemplate: {
+ templateID = activeMenu->GetActive(true) - 1;
+ delete activeMenu;
+ activeMenu = new cRecMenuSearchTimerTemplatesCreate(searchString, epgSearchTemplates[templateID].name.c_str());
+ activeMenu->Display();
+ break; }
+ case rmsSearchTimerOptionsManually:
+ delete activeMenu;
+ activeMenu = new cRecMenuSearchTimerOptions(searchString);
+ activeMenu->Display();
+ break;
+ case rmsSearchTimerTestTemplate: {
+ std::string epgSearchString = recManager->BuildEPGSearchString(searchString, epgSearchTemplates[templateID].templValue);
+ int numSearchResults = 0;
+ const cEvent **searchResult = recManager->PerformSearchTimerSearch(epgSearchString, numSearchResults);
+ if (searchResult) {
+ activeMenuBuffer = activeMenu;
+ activeMenuBuffer->Hide();
+ activeMenu = new cRecMenuSearchTimerResults(searchString, searchResult, numSearchResults, epgSearchTemplates[templateID].name);
+ activeMenu->Display();
+ } else {
+ activeMenuBuffer = activeMenu;
+ activeMenuBuffer->Hide();
+ activeMenu = new cRecMenuSearchTimerNothingFound(searchString, epgSearchTemplates[templateID].name);
+ activeMenu->Display();
+ }
+ break; }
+ case rmsSearchTimerTestManually: {
+ std::string epgSearchString = recManager->BuildEPGSearchString(searchString, activeMenu);
+ int numSearchResults = 0;
+ const cEvent **searchResult = recManager->PerformSearchTimerSearch(epgSearchString, numSearchResults);
+ if (searchResult) {
+ activeMenuBuffer = activeMenu;
+ activeMenuBuffer->Hide();
+ activeMenu = new cRecMenuSearchTimerResults(searchString, searchResult, numSearchResults, "");
+ activeMenu->Display();
+ } else {
+ activeMenuBuffer = activeMenu;
+ activeMenuBuffer->Hide();
+ activeMenu = new cRecMenuSearchTimerNothingFound(searchString, "");
+ activeMenu->Display();
+ }
+ break; }
+ case rmsSearchTimerNothingFoundConfirm:
+ delete activeMenu;
+ activeMenu = activeMenuBuffer;
+ activeMenuBuffer = NULL;
+ activeMenu->Show();
+ break;
+ case rmsSearchTimerCreateManually:
+ case rmsSearchTimerCreateTemplate: {
+ std::string epgSearchString;
+ if (nextState == rmsSearchTimerCreateManually) {
+ epgSearchString = recManager->BuildEPGSearchString(searchString, activeMenu);
+ } else if (nextState = rmsSearchTimerCreateTemplate) {
+ epgSearchString = recManager->BuildEPGSearchString(searchString, epgSearchTemplates[templateID].templValue);
+ }
+ bool success = createSearchTimer(epgSearchString);
+ delete activeMenu;
+ activeMenu = new cRecMenuSearchTimerCreateConfirm(success);
+ activeMenu->Display();
+ break; }
+ /*
+ * --------- SWITCH TIMER ---------------------------------
+ */
+ case rmsSwitchTimer:
+ delete activeMenu;
+ activeMenu = new cRecMenuSwitchTimer();
+ activeMenu->Display();
+ break;
+ case rmsSwitchTimerCreate: {
+ bool success = recManager->CreateSwitchTimer(event, activeMenu);
+ delete activeMenu;
+ activeMenu = new cRecMenuSwitchTimerConfirm(success);
+ activeMenu->Display();
+ break; }
+ case rmsSwitchTimerDelete:
+ recManager->DeleteSwitchTimer(event);
+ delete activeMenu;
+ activeMenu = new cRecMenuSwitchTimerDelete();
+ activeMenu->Display();
+ break;
+ /*
+ * --------- RECORDINGS SEARCH ---------------------------------
+ */
+ case rmsRecordingSearch:
+ delete activeMenu;
+ activeMenu = new cRecMenuRecordingSearch(event);
+ activeMenu->Display();
+ break;
+ case rmsRecordingSearchResult: {
+ searchString = activeMenu->GetStringValue(1);
+ delete activeMenu;
+ if (isempty(*searchString)) {
+ activeMenu = new cRecMenuRecordingSearch(event);
+ } else {
+ int numSearchResults = 0;
+ cRecording **searchResult = recManager->SearchForRecordings(searchString, numSearchResults);
+ if (numSearchResults == 0) {
+ activeMenu = new cRecMenuRecordingSearchNotFound(searchString);
+ } else {
+ activeMenu = new cRecMenuRecordingSearchResults(searchString, searchResult, numSearchResults);
+ }
+ }
+ activeMenu->Display();
+ break; }
+ /*
+ * --------- SEARCH ---------------------------------
+ */
+ case rmsSearch:
+ delete activeMenu;
+ activeMenu = new cRecMenuSearch(event);
+ activeMenu->Display();
+ searchWithOptions = false;
+ break;
+ case rmsSearchWithOptions: {
+ cString searchString = activeMenu->GetStringValue(1);
+ delete activeMenu;
+ if (isempty(*searchString)) {
+ activeMenu = new cRecMenuSearch(event);
+ } else {
+ activeMenu = new cRecMenuSearch(event, *searchString);
+ searchWithOptions = true;
+ }
+ activeMenu->Display();
+ break; }
+ case rmsSearchPerform: {
+ cString searchString = activeMenu->GetStringValue(1);
+ if (isempty(*searchString)) {
+ delete activeMenu;
+ activeMenu = new cRecMenuSearch(event);
+ } else {
+ int numSearchResults = 0;
+ const cEvent **searchResult = recManager->PerformSearch(activeMenu, searchWithOptions, numSearchResults);
+ if (searchResult) {
+ delete activeMenu;
+ activeMenu = new cRecMenuSearchResults(searchString, searchResult, numSearchResults);
+ } else {
+ activeMenuBuffer = activeMenu;
+ activeMenuBuffer->Hide();
+ activeMenu = new cRecMenuSearchNothingFound(searchString);
+ }
+ }
+ activeMenu->Display();
+ break; }
+ case rmsSearchNothingFoundConfirm:
+ delete activeMenu;
+ activeMenu = activeMenuBuffer;
+ activeMenuBuffer = NULL;
+ activeMenu->Show();
+ break;
+ case rmsSearchShowInfo: {
+ const cEvent *ev = activeMenu->GetEventValue(activeMenu->GetActive(false));
+ if (ev) {
+ activeMenu->Hide();
+ detailView = new cDetailView(ev);
+ detailView->drawHeader();
+ detailView->drawContent();
+ detailView->drawScrollbar();
+ detailViewActive = true;
+ }
+ break;}
+ case rmsSearchRecord: {
+ const cEvent *ev = activeMenu->GetEventValue(activeMenu->GetActive(false));
+ cTimer *timer = recManager->createTimer(ev);
+ activeMenuBuffer = activeMenu;
+ activeMenuBuffer->Hide();
+ activeMenu = new cRecMenuSearchConfirmTimer(ev);
+ activeMenu->Display();
+ break;}
+ case rmsSearchRecordConfirm:
+ delete activeMenu;
+ activeMenu = activeMenuBuffer;
+ activeMenuBuffer = NULL;
+ activeMenu->Show();
+ break;
+ /*
+ * --------- CHECK FOR TIMER CONFLICTS ---------------------------------
+ */
+ case rmsTimerConflicts: {
+ //Show timer conflict
+ //active menu: cRecMenuTimerConflicts
+ conflictList = recManager->CheckTimerConflict();
+ delete activeMenu;
+ int numConflicts = conflictList.size();
+ if (numConflicts > 0) {
+ activeMenu = new cRecMenuTimerConflicts(conflictList);
+ } else {
+ activeMenu = new cRecMenuNoTimerConflict();
+ }
+ activeMenu->Display();
+ break; }
+ case rmsTimerConflict:
+ //Show timer conflict
+ //active menu: cRecMenuTimerConflicts
+ currentConflict = activeMenu->GetActive(true);
+ delete activeMenu;
+ activeMenu = new cRecMenuTimerConflict(conflictList[currentConflict]);
+ activeMenu->Display();
+ break;
+
+ /*
+ * --------- COMMON ---------------------------------
+ */
+ case rmsClose: {
+ if (activeMenuBuffer == NULL) {
+ state = osEnd;
+ Close();
+ } else {
+ delete activeMenu;
+ activeMenu = activeMenuBuffer;
+ activeMenuBuffer = NULL;
+ activeMenu->Show();
+ state = osContinue;
+ }
+ break; }
+ default:
+ break;
+ }
+ return state;
+}
+
+bool cRecMenuManager::displayTimerConflict(cTimer *timer) {
+ int timerID = 0;
+ for (cTimer *t = Timers.First(); t; t = Timers.Next(t)) {
+ if (t == timer)
+ return displayTimerConflict(timerID);
+ timerID++;
+ }
+ return false;
+}
+
+bool cRecMenuManager::displayTimerConflict(int timerID) {
+ conflictList = recManager->CheckTimerConflict();
+ int numConflicts = conflictList.size();
+ int showTimerConflict = -1;
+ if (numConflicts > 0) {
+ for (int i=0; i<numConflicts; i++) {
+ if (conflictList[i].timerInvolved(timerID)) {
+ showTimerConflict = i;
+ break;
+ }
+ }
+ }
+ if (showTimerConflict > -1) {
+ currentConflict = showTimerConflict;
+ activeMenu = new cRecMenuTimerConflict(conflictList[currentConflict]);
+ activeMenu->Display();
+ return true;
+ }
+ return false;
+}
+
+bool cRecMenuManager::createSearchTimer(std::string epgSearchString) {
+ int newTimerID = recManager->CreateSearchTimer(epgSearchString);
+ bool success = false;
+ if (newTimerID > -1) {
+ recManager->UpdateSearchTimers();
+ success = true;
+ }
+ return success;
+}
+
+eOSState cRecMenuManager::ProcessKey(eKeys Key) {
+ eOSState state = osContinue;
+ eRecMenuState nextState = rmsContinue;
+ if (!activeMenu)
+ return state;
+ if (detailViewActive) {
+ state = detailView->ProcessKey(Key);
+ if (state == osEnd) {
+ delete detailView;
+ detailView = NULL;
+ detailViewActive = false;
+ activeMenu->Show();
+ state = osContinue;
+ }
+ } else {
+ nextState = activeMenu->ProcessKey(Key);
+ if ((nextState == rmsClose) || ((nextState == rmsNotConsumed)&&(Key == kBack))){
+ if (activeMenuBuffer == NULL) {
+ state = osEnd;
+ Close();
+ } else {
+ delete activeMenu;
+ activeMenu = activeMenuBuffer;
+ activeMenuBuffer = NULL;
+ activeMenu->Show();
+ state = osContinue;
+ osdManager.flush();
+ }
+ return state;
+ }
+ state = StateMachine(nextState);
+ }
+ osdManager.flush();
+ return state;
+} \ No newline at end of file
diff --git a/recmenumanager.h b/recmenumanager.h
new file mode 100644
index 0000000..cc9ac2c
--- /dev/null
+++ b/recmenumanager.h
@@ -0,0 +1,38 @@
+#ifndef __TVGUIDE_RECMENUMANAGER_H
+#define __TVGUIDE_RECMENUMANAGER_H
+
+// --- cRecMenuManager -------------------------------------------------------------
+class cRecMenuManager {
+private:
+ bool active;
+ cRecMenu *activeMenu;
+ cRecMenu *activeMenuBuffer;
+ const cEvent *event;
+ cRecManager *recManager;
+ std::vector<TVGuideTimerConflict> conflictList;
+ std::vector<TVGuideEPGSearchTemplate> epgSearchTemplates;
+ bool instantRecord;
+ int currentConflict;
+ int templateID;
+ bool searchWithOptions;
+ cTimer *timer;
+ cString searchString;
+ cDetailView *detailView;
+ cPixmap *pixmapBackground;
+ bool detailViewActive;
+ void SetBackground(void);
+ void DeleteBackground(void);
+ bool displayTimerConflict(cTimer *timer);
+ bool displayTimerConflict(int timerID);
+ bool createSearchTimer(std::string epgSearchString);
+public:
+ cRecMenuManager(void);
+ virtual ~cRecMenuManager(void);
+ bool isActive(void) { return active; };
+ void Start(const cEvent *event);
+ void Close(void);
+ eOSState StateMachine(eRecMenuState nextState);
+ eOSState ProcessKey(eKeys Key);
+};
+
+#endif //__TVGUIDE_RECMENUMANAGER_H \ No newline at end of file
diff --git a/services/epgsearch.h b/services/epgsearch.h
index de29299..2669da4 100644
--- a/services/epgsearch.h
+++ b/services/epgsearch.h
@@ -1,5 +1,5 @@
-/*
-Copyright (C) 2004-2007 Christian Wieninger
+/* -*- c++ -*-
+Copyright (C) 2004-2013 Christian Wieninger
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
@@ -24,10 +24,6 @@ The project's page is at http://winni.vdr-developer.org/epgsearch
#ifndef EPGSEARCHSERVICES_INC
#define EPGSEARCHSERVICES_INC
-// Added by Andreas Mair (mail _AT_ andreas _DOT_ vdr-developer _DOT_ org)
-#define EPGSEARCH_SEARCHRESULTS_SERVICE_STRING_ID "Epgsearch-searchresults-v1.0"
-#define EPGSEARCH_LASTCONFLICTINFO_SERVICE_STRING_ID "Epgsearch-lastconflictinfo-v1.0"
-
#include <string>
#include <list>
#include <memory>
@@ -59,6 +55,13 @@ struct Epgsearch_exttimeredit_v1_0
cOsdMenu* pTimerMenu; // pointer to the menu of results
};
+// Data structure for service "Epgsearch-enablesearchtimers-v1.0"
+struct Epgsearch_enablesearchtimers_v1_0
+{
+// in
+ bool enable; // enable search timer thread?
+};
+
// Data structure for service "Epgsearch-updatesearchtimers-v1.0"
struct Epgsearch_updatesearchtimers_v1_0
{
@@ -104,7 +107,7 @@ struct Epgsearch_searchresults_v1_0
bool useDescription; // search in description
// out
- class cServiceSearchResult : public cListObject
+ class cServiceSearchResult : public cListObject
{
public:
const cEvent* event;
@@ -119,11 +122,11 @@ struct Epgsearch_switchtimer_v1_0
{
// in
const cEvent* event;
- int mode; // mode (0=query existance, 1=add/modify, 2=delete)
+ int mode; // mode (0=query existence, 1=add/modify, 2=delete)
// in/out
int switchMinsBefore;
int announceOnly;
-// out
+// out
bool success; // result
};
@@ -132,7 +135,7 @@ class cServiceHandler
{
public:
virtual std::list<std::string> SearchTimerList() = 0;
- // returns a list of search timer entries in the same format as used in epgsearch.conf
+ // returns a list of search timer entries in the same format as used in epgsearch.conf
virtual int AddSearchTimer(const std::string&) = 0;
// adds a new search timer and returns its ID (-1 on error)
virtual bool ModSearchTimer(const std::string&) = 0;
@@ -140,11 +143,11 @@ class cServiceHandler
virtual bool DelSearchTimer(int) = 0;
// deletes search timer with given ID and returns success
virtual std::list<std::string> QuerySearchTimer(int) = 0;
- // returns the search result of the searchtimer with given ID in the same format as used in SVDRP command 'QRYS' (->MANUAL)
+ // returns the search result of the searchtimer with given ID in the same format as used in SVDRP command 'QRYS' (->MANUAL)
virtual std::list<std::string> QuerySearch(std::string) = 0;
- // returns the search result of the searchtimer with given settings in the same format as used in SVDRP command 'QRYS' (->MANUAL)
+ // returns the search result of the searchtimer with given settings in the same format as used in SVDRP command 'QRYS' (->MANUAL)
virtual std::list<std::string> ExtEPGInfoList() = 0;
- // returns a list of extended EPG categories in the same format as used in epgsearchcats.conf
+ // returns a list of extended EPG categories in the same format as used in epgsearchcats.conf
virtual std::list<std::string> ChanGrpList() = 0;
// returns a list of channel groups maintained by epgsearch
virtual std::list<std::string> BlackList() = 0;
@@ -164,4 +167,36 @@ struct Epgsearch_services_v1_0
std::auto_ptr<cServiceHandler> handler;
};
+// Data structures for service "Epgsearch-services-v1.1"
+class cServiceHandler_v1_1 : public cServiceHandler
+{
+ public:
+ // Get timer conflicts
+ virtual std::list<std::string> TimerConflictList(bool relOnly=false) = 0;
+ // Check if a conflict check is advised
+ virtual bool IsConflictCheckAdvised() = 0;
+};
+
+struct Epgsearch_services_v1_1
+{
+// in/out
+ std::auto_ptr<cServiceHandler_v1_1> handler;
+};
+
+// Data structures for service "Epgsearch-services-v1.2"
+class cServiceHandler_v1_2 : public cServiceHandler_v1_1
+{
+ public:
+ // List of all recording directories used in recordings, timers (and optionally search timers or in epgsearchdirs.conf)
+ virtual std::set<std::string> ShortDirectoryList() = 0;
+ // Evaluate an expression against an event
+ virtual std::string Evaluate(const std::string& expr, const cEvent* event) = 0;
+};
+
+struct Epgsearch_services_v1_2
+{
+// in/out
+ std::auto_ptr<cServiceHandler_v1_2> handler;
+};
+
#endif
diff --git a/setup.c b/setup.c
index a49106e..7368bb7 100644
--- a/setup.c
+++ b/setup.c
@@ -102,6 +102,8 @@ void cTvguideSetup::Store(void) {
SetupStore("FontGridHorizontalSmallDelta", tvguideConfig.FontGridHorizontalSmallDelta);
SetupStore("FontTimeLineDateHorizontalDelta", tvguideConfig.FontTimeLineDateHorizontalDelta);
SetupStore("FontTimeLineTimeHorizontalDelta", tvguideConfig.FontTimeLineTimeHorizontalDelta);
+ SetupStore("FontRecMenuItemDelta", tvguideConfig.FontRecMenuItemDelta);
+ SetupStore("FontRecMenuItemSmallDelta", tvguideConfig.FontRecMenuItemSmallDelta);
SetupStore("displayRerunsDetailEPGView", tvguideConfig.displayRerunsDetailEPGView);
SetupStore("numReruns", tvguideConfig.numReruns);
SetupStore("useSubtitleRerun", tvguideConfig.useSubtitleRerun);
@@ -301,7 +303,9 @@ void cMenuSetupFont::Set(void) {
Add(new cMenuEditIntItem(tr("Timeline Date Font Size"), &tmpTvguideConfig->FontTimeLineDateHorizontalDelta, -30, 30));
Add(new cMenuEditIntItem(tr("Timeline Time Font Size"), &tmpTvguideConfig->FontTimeLineTimeHorizontalDelta, -30, 30));
}
-
+
+ Add(new cMenuEditIntItem(tr("Search & Recording Menu Font Size"), &tmpTvguideConfig->FontRecMenuItemDelta, -30, 30));
+ Add(new cMenuEditIntItem(tr("Search & Recording Menu Small Font Size"), &tmpTvguideConfig->FontRecMenuItemSmallDelta, -30, 30));
SetCurrent(Get(currentItem));
Display();
diff --git a/styledpixmap.c b/styledpixmap.c
index 77e6450..d57ee54 100644
--- a/styledpixmap.c
+++ b/styledpixmap.c
@@ -132,3 +132,11 @@ void cStyledPixmap::DrawImage(const cPoint &Point, const cImage &Image) {
void cStyledPixmap::DrawRectangle(const cRect &Rect, tColor Color) {
pixmap->DrawRectangle(Rect,Color);
}
+
+void cStyledPixmap::DrawEllipse(const cRect &Rect, tColor Color, int Quadrant) {
+ pixmap->DrawEllipse(Rect,Color,Quadrant);
+}
+
+void cStyledPixmap::SetViewPort(const cRect &Rect) {
+ pixmap->SetViewPort(Rect);
+} \ No newline at end of file
diff --git a/styledpixmap.h b/styledpixmap.h
index ac974be..af09994 100644
--- a/styledpixmap.h
+++ b/styledpixmap.h
@@ -13,23 +13,26 @@ protected:
tColor colorBlending;
void setPixmap(cPixmap *pixmap);
public:
- cStyledPixmap(void);
- cStyledPixmap(cPixmap *pixmap);
- virtual ~cStyledPixmap(void);
- void drawBackground();
- void drawBlendedBackground();
- void drawSparsedBackground();
- void drawBorder();
- void drawBoldBorder();
- void drawDefaultBorder(int width, int height);
- void drawRoundedCorners(int width, int height, int radius);
- void setColor(tColor color, tColor colorBlending) {this->color = color; this->colorBlending = colorBlending;};
- void SetAlpha(int alpha) {pixmap->SetAlpha(alpha);};
- void DrawText(const cPoint &Point, const char *s, tColor ColorFg, tColor ColorBg, const cFont *Font);
- void DrawImage(const cPoint &Point, const cImage &Image);
- void DrawRectangle(const cRect &Rect, tColor Color);
- int Width() {return pixmap->ViewPort().Width();};
- int Height() {return pixmap->ViewPort().Height();};
+ cStyledPixmap(void);
+ cStyledPixmap(cPixmap *pixmap);
+ virtual ~cStyledPixmap(void);
+ void drawBackground();
+ void drawBlendedBackground();
+ void drawSparsedBackground();
+ void drawBorder();
+ void drawBoldBorder();
+ void drawDefaultBorder(int width, int height);
+ void drawRoundedCorners(int width, int height, int radius);
+ void setColor(tColor color, tColor colorBlending) {this->color = color; this->colorBlending = colorBlending;};
+ void SetAlpha(int alpha) {pixmap->SetAlpha(alpha);};
+ void SetLayer(int layer) {pixmap->SetLayer(layer);};
+ void DrawText(const cPoint &Point, const char *s, tColor ColorFg, tColor ColorBg, const cFont *Font);
+ void DrawImage(const cPoint &Point, const cImage &Image);
+ void DrawRectangle(const cRect &Rect, tColor Color);
+ void DrawEllipse(const cRect &Rect, tColor Color, int Quadrant);
+ void SetViewPort(const cRect &Rect);
+ int Width() {return pixmap->ViewPort().Width();};
+ int Height() {return pixmap->ViewPort().Height();};
};
#endif //__TVGUIDE_STYLEDPIXMAP_H \ No newline at end of file
diff --git a/switchtimer.c b/switchtimer.c
new file mode 100644
index 0000000..4ba7b45
--- /dev/null
+++ b/switchtimer.c
@@ -0,0 +1,109 @@
+#include "switchtimer.h"
+
+cSwitchTimers SwitchTimers;
+
+// -- cSwitchTimer -----------------------------------------------------------------
+cSwitchTimer::cSwitchTimer(void) {
+}
+
+cSwitchTimer::cSwitchTimer(const cEvent* Event) {
+ eventID = 0;
+ startTime = 0;
+ if (Event) {
+ eventID = Event->EventID();
+ channelID = Event->ChannelID();
+ startTime = Event->StartTime();
+ }
+}
+
+bool cSwitchTimer::Parse(const char *s) {
+ char *line;
+ char *pos;
+ char *pos_next;
+ int parameter = 1;
+ int valuelen;
+#define MAXVALUELEN (10 * MaxFileName)
+
+ char value[MAXVALUELEN];
+ startTime=0;
+
+ pos = line = strdup(s);
+ pos_next = pos + strlen(pos);
+ if (*pos_next == '\n') *pos_next = 0;
+ while (*pos) {
+ while (*pos == ' ')
+ pos++;
+ if (*pos) {
+ if (*pos != ':') {
+ pos_next = strchr(pos, ':');
+ if (!pos_next)
+ pos_next = pos + strlen(pos);
+ valuelen = pos_next - pos + 1;
+ if (valuelen > MAXVALUELEN)
+ valuelen = MAXVALUELEN;
+ strn0cpy(value, pos, valuelen);
+ pos = pos_next;
+ switch (parameter) {
+ case 1:
+ channelID = tChannelID::FromString(value);
+ break;
+ case 2:
+ eventID = atoi(value);
+ break;
+ case 3:
+ startTime = atol(value);
+ break;
+ default:
+ break;
+ }
+ }
+ parameter++;
+ }
+ if (*pos)
+ pos++;
+ }
+ free(line);
+ return (parameter >= 3) ? true : false;
+}
+
+bool cSwitchTimers::EventInSwitchList(const cEvent* event) {
+ if (!event) return false;
+ cMutexLock SwitchTimersLock(this);
+ cSwitchTimer* switchTimer = SwitchTimers.First();
+ while (switchTimer) {
+ if (switchTimer->eventID == event->EventID())
+ return true;
+ switchTimer = SwitchTimers.Next(switchTimer);
+ }
+ return false;
+}
+
+bool cSwitchTimers::ChannelInSwitchList(const cChannel* channel) {
+ if (!channel) return false;
+ cMutexLock SwitchTimersLock(this);
+ cSwitchTimer* switchTimer = SwitchTimers.First();
+ while (switchTimer) {
+ if (switchTimer->channelID == channel->GetChannelID())
+ return true;
+ switchTimer = SwitchTimers.Next(switchTimer);
+ }
+ return false;
+}
+
+void cSwitchTimers::DeleteSwitchTimer(const cEvent *event) {
+ if (!event) return;
+ cMutexLock SwitchTimersLock(this);
+ cSwitchTimer* switchTimer = SwitchTimers.First();
+ cSwitchTimer* delTimer = NULL;
+
+ while (switchTimer) {
+ if (switchTimer->eventID == event->EventID()) {
+ delTimer = switchTimer;
+ break;
+ }
+ switchTimer = SwitchTimers.Next(switchTimer);
+ }
+ if (delTimer) {
+ SwitchTimers.Del(delTimer, true);
+ }
+}
diff --git a/switchtimer.h b/switchtimer.h
new file mode 100644
index 0000000..8958b44
--- /dev/null
+++ b/switchtimer.h
@@ -0,0 +1,30 @@
+#ifndef __TVGUIDE_SWITCHTIMER_H
+#define __TVGUIDE_SWITCHTIMER_H
+
+#include <vdr/plugin.h>
+
+class cSwitchTimer : public cListObject
+{
+public:
+ tEventID eventID;
+ time_t startTime;
+ tChannelID channelID;
+
+ cSwitchTimer(void);
+ cSwitchTimer(const cEvent* Event);
+ bool Parse(const char *s);
+};
+
+class cSwitchTimers : public cConfig<cSwitchTimer>, public cMutex
+{
+public:
+ cSwitchTimers(void) {}
+ ~cSwitchTimers(void) {}
+ bool EventInSwitchList(const cEvent* event);
+ bool ChannelInSwitchList(const cChannel* channel);
+ void DeleteSwitchTimer(const cEvent *event);
+};
+
+extern cSwitchTimers SwitchTimers;
+
+#endif //__TVGUIDE_SWITCHTIMER_H
diff --git a/themes/tvguide-darkblue.theme b/themes/tvguide-darkblue.theme
index 90285ce..ec0a1b1 100644
--- a/themes/tvguide-darkblue.theme
+++ b/themes/tvguide-darkblue.theme
@@ -30,3 +30,15 @@ clrButtonYellowBorder = FFBBBB00
clrButtonBlue = 990000BB
clrButtonBlueBorder = FF0000BB
clrButtonBlend = DD000000
+clrRecMenuBackground = AA000000
+clrRecMenuTimerConflictBackground = FFCCCCCC
+clrRecMenuTimerConflictBar = FF222222
+clrRecMenuTimerConflictOverlap = AAFF0000
+clrRecMenuDayActive = FF00FF00
+clrRecMenuDayInactive = FFFF0000
+clrRecMenuDayHighlight = 44FFFFFF
+clrRecMenuTextBack = FF000000
+clrRecMenuTextActiveBack = FF404749
+clrRecMenuKeyboardBack = FF000000
+clrRecMenuKeyboardBorder = FFFFFFFF
+clrRecMenuKeyboardHigh = 40BB0000 \ No newline at end of file
diff --git a/themes/tvguide-default.theme b/themes/tvguide-default.theme
index 9704e65..05b2e47 100644
--- a/themes/tvguide-default.theme
+++ b/themes/tvguide-default.theme
@@ -30,3 +30,15 @@ clrButtonYellowBorder = FFBBBB00
clrButtonBlue = 990000BB
clrButtonBlueBorder = FF0000BB
clrButtonBlend = DD000000
+clrRecMenuBackground = AA000000
+clrRecMenuTimerConflictBackground = FFCCCCCC
+clrRecMenuTimerConflictBar = FF222222
+clrRecMenuTimerConflictOverlap = AAFF0000
+clrRecMenuDayActive = FF00FF00
+clrRecMenuDayInactive = FFFF0000
+clrRecMenuDayHighlight = 44FFFFFF
+clrRecMenuTextBack = FF000000
+clrRecMenuTextActiveBack = FF404749
+clrRecMenuKeyboardBack = FF000000
+clrRecMenuKeyboardBorder = FFFFFFFF
+clrRecMenuKeyboardHigh = 40BB0000 \ No newline at end of file
diff --git a/themes/tvguide-keepitsimple.theme b/themes/tvguide-keepitsimple.theme
index f88aa92..852d7c3 100644
--- a/themes/tvguide-keepitsimple.theme
+++ b/themes/tvguide-keepitsimple.theme
@@ -25,4 +25,16 @@ clrButtonYellow = 99BBBB00
clrButtonYellowBorder = FFBBBB00
clrButtonBlue = 990000BB
clrButtonBlueBorder = FF0000BB
-clrButtonBlend = DD000000 \ No newline at end of file
+clrButtonBlend = DD000000
+clrRecMenuBackground = AA000000
+clrRecMenuTimerConflictBackground = FFCCCCCC
+clrRecMenuTimerConflictBar = FF222222
+clrRecMenuTimerConflictOverlap = AAFF0000
+clrRecMenuDayActive = FF00FF00
+clrRecMenuDayInactive = FFFF0000
+clrRecMenuDayHighlight = 44FFFFFF
+clrRecMenuTextBack = FF000000
+clrRecMenuTextActiveBack = FF404749
+clrRecMenuKeyboardBack = FF000000
+clrRecMenuKeyboardBorder = BB555555
+clrRecMenuKeyboardHigh = 40BB0000 \ No newline at end of file
diff --git a/themes/tvguide-nOpacity.theme b/themes/tvguide-nOpacity.theme
index f492c2d..345d13a 100644
--- a/themes/tvguide-nOpacity.theme
+++ b/themes/tvguide-nOpacity.theme
@@ -30,3 +30,15 @@ clrButtonYellowBorder = FFBBBB00
clrButtonBlue = 990000BB
clrButtonBlueBorder = FF0000BB
clrButtonBlend = DD000000
+clrRecMenuBackground = AA000000
+clrRecMenuTimerConflictBackground = FFCCCCCC
+clrRecMenuTimerConflictBar = FF222222
+clrRecMenuTimerConflictOverlap = AAFF0000
+clrRecMenuDayActive = FF00FF00
+clrRecMenuDayInactive = FFFF0000
+clrRecMenuDayHighlight = 44FFFFFF
+clrRecMenuTextBack = FF000000
+clrRecMenuTextActiveBack = FF404749
+clrRecMenuKeyboardBack = FF000000
+clrRecMenuKeyboardBorder = FF003DF5
+clrRecMenuKeyboardHigh = 40BB0000 \ No newline at end of file
diff --git a/themes/tvguide-nOpacitydarkred.theme b/themes/tvguide-nOpacitydarkred.theme
index d0c73a0..b14f6ac 100644
--- a/themes/tvguide-nOpacitydarkred.theme
+++ b/themes/tvguide-nOpacitydarkred.theme
@@ -30,3 +30,15 @@ clrButtonYellowBorder = FFBBBB00
clrButtonBlue = 990000BB
clrButtonBlueBorder = FF0000BB
clrButtonBlend = DD000000
+clrRecMenuBackground = AA000000
+clrRecMenuTimerConflictBackground = FFCCCCCC
+clrRecMenuTimerConflictBar = FF222222
+clrRecMenuTimerConflictOverlap = AAFF0000
+clrRecMenuDayActive = FF00FF00
+clrRecMenuDayInactive = FFFF0000
+clrRecMenuDayHighlight = 44FFFFFF
+clrRecMenuTextBack = FF000000
+clrRecMenuTextActiveBack = FF404749
+clrRecMenuKeyboardBack = FF000000
+clrRecMenuKeyboardBorder = FF660000
+clrRecMenuKeyboardHigh = 40BB0000 \ No newline at end of file
diff --git a/themes/tvguide-nOpacitygreen.theme b/themes/tvguide-nOpacitygreen.theme
index e787d15..3042a84 100644
--- a/themes/tvguide-nOpacitygreen.theme
+++ b/themes/tvguide-nOpacitygreen.theme
@@ -30,3 +30,15 @@ clrButtonYellowBorder = FFBBBB00
clrButtonBlue = 990000BB
clrButtonBlueBorder = FF0000BB
clrButtonBlend = DD000000
+clrRecMenuBackground = AA000000
+clrRecMenuTimerConflictBackground = FFCCCCCC
+clrRecMenuTimerConflictBar = FF222222
+clrRecMenuTimerConflictOverlap = AAFF0000
+clrRecMenuDayActive = FF00FF00
+clrRecMenuDayInactive = FFFF0000
+clrRecMenuDayHighlight = 44FFFFFF
+clrRecMenuTextBack = FF000000
+clrRecMenuTextActiveBack = FF404749
+clrRecMenuKeyboardBack = FF000000
+clrRecMenuKeyboardBorder = EE006600
+clrRecMenuKeyboardHigh = 40BB0000 \ No newline at end of file
diff --git a/themes/tvguide-nOpacityiceblue.theme b/themes/tvguide-nOpacityiceblue.theme
index 2112974..ce5cb2c 100644
--- a/themes/tvguide-nOpacityiceblue.theme
+++ b/themes/tvguide-nOpacityiceblue.theme
@@ -25,3 +25,18 @@ clrButtonYellow = FFBBBB00
clrButtonYellowBorder = FFBBBB00
clrButtonBlue = FF0000BB
clrButtonBlueBorder = FF0000BB
+clrRecMenuBackground = AA000000
+clrRecMenuTimerConflictBackground = FFCCCCCC
+clrRecMenuTimerConflictBar = FF222222
+clrRecMenuTimerConflictOverlap = AAFF0000
+clrRecMenuDayActive = FF00FF00
+clrRecMenuDayInactive = FFFF0000
+clrRecMenuDayHighlight = 77000000
+clrRecMenuTextBack = FF3C3C3C
+clrRecMenuTextActiveBack = FF404749
+clrRecMenuKeyboardBack = FF000044
+clrRecMenuKeyboardBorder = FF3C3C3C
+clrRecMenuKeyboardHigh = 55FFFFFF
+clrButtonRedKeyboard = FFBB0000
+clrButtonGreenKeyboard = FF00BB00
+clrButtonYellowKeyboard = FFBBBB00
diff --git a/timeline.c b/timeline.c
index 454aa9c..4355352 100644
--- a/timeline.c
+++ b/timeline.c
@@ -3,11 +3,11 @@
cTimeLine::cTimeLine(cMyTime *myTime) {
this->myTime = myTime;
if (tvguideConfig.displayMode == eVertical) {
- dateViewer = new cStyledPixmap(osdManager.requestPixmap(3, cRect(0,
+ dateViewer = new cStyledPixmap(osdManager.requestPixmap(1, cRect(0,
tvguideConfig.statusHeaderHeight,
tvguideConfig.timeLineWidth,
tvguideConfig.channelHeaderHeight + tvguideConfig.channelGroupsHeight)));
- timeline = osdManager.requestPixmap(2, cRect(0,
+ timeline = osdManager.requestPixmap(1, cRect(0,
tvguideConfig.statusHeaderHeight + tvguideConfig.channelHeaderHeight + tvguideConfig.channelGroupsHeight,
tvguideConfig.timeLineWidth,
tvguideConfig.osdHeight - tvguideConfig.statusHeaderHeight - tvguideConfig.channelHeaderHeight - tvguideConfig.channelGroupsHeight - tvguideConfig.footerHeight)
@@ -16,11 +16,11 @@ cTimeLine::cTimeLine(cMyTime *myTime) {
tvguideConfig.timeLineWidth,
1440*tvguideConfig.minutePixel));
} else if (tvguideConfig.displayMode == eHorizontal) {
- dateViewer = new cStyledPixmap(osdManager.requestPixmap(3, cRect(0,
+ dateViewer = new cStyledPixmap(osdManager.requestPixmap(1, cRect(0,
tvguideConfig.statusHeaderHeight,
tvguideConfig.channelHeaderWidth + tvguideConfig.channelGroupsWidth,
tvguideConfig.timeLineHeight)));
- timeline = osdManager.requestPixmap(2, cRect(tvguideConfig.channelHeaderWidth + tvguideConfig.channelGroupsWidth,
+ timeline = osdManager.requestPixmap(1, cRect(tvguideConfig.channelHeaderWidth + tvguideConfig.channelGroupsWidth,
tvguideConfig.statusHeaderHeight,
tvguideConfig.osdWidth - tvguideConfig.channelHeaderWidth - tvguideConfig.channelGroupsWidth,
tvguideConfig.timeLineHeight)
@@ -29,7 +29,7 @@ cTimeLine::cTimeLine(cMyTime *myTime) {
1440*tvguideConfig.minutePixel,
tvguideConfig.timeLineWidth));
}
- clock = new cStyledPixmap(osdManager.requestPixmap(3, cRect(0,
+ clock = new cStyledPixmap(osdManager.requestPixmap(1, cRect(0,
tvguideConfig.osdHeight- tvguideConfig.footerHeight,
tvguideConfig.timeLineWidth,
tvguideConfig.footerHeight-9)));
diff --git a/timer.c b/timer.c
index 8e60c0e..f6d9925 100644
--- a/timer.c
+++ b/timer.c
@@ -120,3 +120,49 @@ time_t cMyTime::GetRounded() {
void cMyTime::debug() {
esyslog("t: %s, tStart: %s, tEnd: %s", *TimeString(t), *TimeString(tStart), *TimeString(tEnd));
}
+
+// --- cTimeInterval -------------------------------------------------------------
+
+cTimeInterval::cTimeInterval(time_t start, time_t stop) {
+ this->start = start;
+ this->stop = stop;
+}
+
+cTimeInterval::~cTimeInterval(void) {
+}
+
+cTimeInterval *cTimeInterval::Intersect(cTimeInterval *interval) {
+ time_t startIntersect, stopIntersect;
+
+ if ((stop <= interval->Start()) || (interval->Stop() <= start)) {
+ return NULL;
+ }
+
+ if (start <= interval->Start()) {
+ startIntersect = interval->Start();
+ } else {
+ startIntersect = start;
+ }
+ if (stop <= interval->Stop()) {
+ stopIntersect = stop;
+ } else {
+ stopIntersect = interval->Stop();
+ }
+ return new cTimeInterval(startIntersect, stopIntersect);
+}
+
+cTimeInterval *cTimeInterval::Union(cTimeInterval *interval) {
+ time_t startUnion, stopUnion;
+
+ if (start <= interval->Start()) {
+ startUnion = start;
+ } else {
+ startUnion = interval->Start();
+ }
+ if (stop <= interval->Stop()) {
+ stopUnion = interval->Stop();
+ } else {
+ stopUnion = stop;
+ }
+ return new cTimeInterval(startUnion, stopUnion);
+} \ No newline at end of file
diff --git a/timer.h b/timer.h
index e84f74c..2ab5045 100644
--- a/timer.h
+++ b/timer.h
@@ -30,4 +30,19 @@ class cMyTime {
void debug();
};
+// --- cTimeInterval -------------------------------------------------------------
+
+class cTimeInterval {
+ private:
+ time_t start;
+ time_t stop;
+ public:
+ cTimeInterval(time_t start, time_t stop);
+ virtual ~cTimeInterval(void);
+ time_t Start(void) { return start; };
+ time_t Stop(void) { return stop; };
+ cTimeInterval *Intersect(cTimeInterval *interval);
+ cTimeInterval *Union(cTimeInterval *interval);
+};
+
#endif //__TVGUIDE_TIMER_H \ No newline at end of file
diff --git a/tools.c b/tools.c
new file mode 100644
index 0000000..2a3815e
--- /dev/null
+++ b/tools.c
@@ -0,0 +1,370 @@
+#include <string>
+#include <vector>
+#include <sstream>
+
+/****************************************************************************************
+* CUTTEXT
+****************************************************************************************/
+static std::string CutText(std::string text, int width, const cFont *font) {
+ if (width <= font->Size())
+ return text.c_str();
+ if (font->Width(text.c_str()) < width)
+ return text.c_str();
+ cTextWrapper twText;
+ twText.Set(text.c_str(), font, width);
+ std::string cuttedTextNative = twText.GetLine(0);
+ std::stringstream sstrText;
+ sstrText << cuttedTextNative << "...";
+ std::string cuttedText = sstrText.str();
+ int actWidth = font->Width(cuttedText.c_str());
+ if (actWidth > width) {
+ int overlap = actWidth - width;
+ int charWidth = font->Width(".");
+ if (charWidth == 0)
+ charWidth = 1;
+ int cutChars = overlap / charWidth;
+ if (cutChars > 0) {
+ cuttedTextNative = cuttedTextNative.substr(0, cuttedTextNative.length() - cutChars);
+ std::stringstream sstrText2;
+ sstrText2 << cuttedTextNative << "...";
+ cuttedText = sstrText2.str();
+ }
+ }
+ return cuttedText;
+}
+/****************************************************************************************
+* SPLTSTRING
+****************************************************************************************/
+class splitstring : public std::string {
+ std::vector<std::string> flds;
+public:
+ splitstring(const char *s) : std::string(s) { };
+ std::vector<std::string>& split(char delim, int rep=0);
+};
+
+// split: receives a char delimiter; returns a vector of strings
+// By default ignores repeated delimiters, unless argument rep == 1.
+std::vector<std::string>& splitstring::split(char delim, int rep) {
+ if (!flds.empty()) flds.clear(); // empty vector if necessary
+ std::string work = data();
+ std::string buf = "";
+ int i = 0;
+ while (i < work.length()) {
+ if (work[i] != delim)
+ buf += work[i];
+ else if (rep == 1) {
+ flds.push_back(buf);
+ buf = "";
+ } else if (buf.length() > 0) {
+ flds.push_back(buf);
+ buf = "";
+ }
+ i++;
+ }
+ if (!buf.empty())
+ flds.push_back(buf);
+ return flds;
+}
+
+/****************************************************************************************
+* FINDIGNORECASE
+****************************************************************************************/
+int FindIgnoreCase(const std::string& expr, const std::string& query)
+{
+ const char *p = expr.c_str();
+ const char *r = strcasestr(p, query.c_str());
+
+ if (!r)
+ return -1;
+ return r - p;
+}
+
+/****************************************************************************************
+* FUZZYSEARCH
+****************************************************************************************/
+#include <ctype.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#ifndef _AFUZZY_H
+#define _AFUZZY_H
+
+// source from:
+/*
+ Leonid Boitsov 2002. (itman@narod.ru)
+ C version of Stas Namin.
+ This code is a GPL software and is distributed under GNU
+ public licence without any warranty.
+*/
+
+typedef unsigned int Uint;
+
+#define MaxPatSize (sizeof(Uint) * 8)
+
+typedef struct
+{
+ Uint *R,
+ *R1,
+ *RP,
+ *S,
+ *RI;
+ Uint *FilterS;
+
+ int Map[256];
+ int FilterMap[256];
+ int k;
+ Uint mask_ok;
+ Uint filter_ok;
+ Uint filter_shift;
+ int r_size;
+ int FilterSet;
+} AFUZZY;
+
+void afuzzy_init(const char *p, int kerr, int UseFilter, AFUZZY *fuzzy);
+void afuzzy_free(AFUZZY *fuzzy);
+int afuzzy_checkSUB(const char *t, AFUZZY *fuzzy);
+
+#endif
+
+
+static int afuzzy_checkFLT(const char *t, AFUZZY *fuzzy);
+
+/******************************************************************************
+FUNCTION afuzzy_init()
+ Initialization of the fuzzy search routine. This applies to the consequent
+ calls of the afuzzy_CheckRTR (whole string matching) and afuzzy_CheckSUB
+ (substring match) routines. afuzzy_init() should be called for each
+ new pattern or error length. The search is case sensitive
+
+ARGUMENTS:
+ p Pattern
+ kerr Number of possible errors. Shouldn't exceed pattern length
+ UseFilter Use agrep filter algorithm that speeds up search.
+ fuzzy pointer to the structure that will be later passes to Check*
+ (the first 6 elements should be NULLs for the first call)
+
+RETURN VALUE:
+ none
+
+ALGORITHM
+ see. the article on agrep algorithms.
+ The only change is accounting transpositions as one edit operation .
+******************************************************************************/
+void afuzzy_init(const char *p, int kerr, int UseFilter, AFUZZY *fuzzy)
+{
+ int cnt, p_len, i, j, l, d, m, dd;
+ char PatFilter[sizeof(Uint)*8 + 1];
+
+ fuzzy->k = kerr;
+ m = strlen(p);
+ fuzzy->FilterSet = 0;
+ memset(fuzzy->Map, 0 , sizeof(fuzzy->Map) );
+
+ if (fuzzy->S)
+ free(fuzzy->S);
+ if (fuzzy->R)
+ free(fuzzy->R);
+ if (fuzzy->R1)
+ free(fuzzy->R1);
+ if (fuzzy->RP)
+ free(fuzzy->RP);
+ if (fuzzy->RI)
+ free(fuzzy->RI);
+ if (fuzzy->FilterS)
+ free(fuzzy->FilterS);
+
+ fuzzy->FilterS = NULL;
+ fuzzy->S = (Uint *)calloc(m + 1, sizeof(Uint));
+ fuzzy->R = (Uint *)calloc(fuzzy->k + 1, sizeof(Uint));
+ fuzzy->R1 = (Uint *)calloc(fuzzy->k + 1, sizeof(Uint));
+ fuzzy->RI = (Uint *)calloc(fuzzy->k + 1, sizeof(Uint));
+ fuzzy->RP = (Uint *)calloc(fuzzy->k + 1, sizeof(Uint));
+
+ for (i = 0, cnt = 0; i < m; i++)
+ {
+ l = fuzzy->Map[(unsigned char)p[i]];
+ if (!l)
+ {
+ l = fuzzy->Map[(unsigned char)p[i]] = ++cnt;
+ fuzzy->S[l] = 0;
+ }
+ fuzzy->S[l] |= 1 << i;
+ }
+
+
+ for (d = 0; d <= fuzzy->k; d++)
+ fuzzy->RI[d] = (1 << d) - 1;
+
+ fuzzy->mask_ok = (1 << (m - 1));
+ fuzzy->r_size = sizeof(Uint) * (fuzzy->k + 1);
+ p_len = m;
+
+ if (p_len > (int) sizeof(Uint)*8)
+ p_len = (int) sizeof(Uint)*8;
+
+ /* If k is zero then no filter is needed! */
+ if (fuzzy->k && (p_len >= 2*(fuzzy->k + 1)) )
+ {
+ if (UseFilter)
+ {
+ fuzzy->FilterSet = 1;
+ memset(fuzzy->FilterMap, 0 , sizeof(fuzzy->FilterMap) );
+ fuzzy->FilterS = (Uint *)calloc(m + 1, sizeof(Uint));
+
+ /* Not let's fill the interleaved pattern */
+ dd = p_len / (fuzzy->k + 1);
+ p_len = dd * (fuzzy->k + 1);
+
+ for (i = 0, cnt = 0; i < dd; i++)
+ for (j = 0; j < fuzzy->k + 1; j++, cnt++)
+ PatFilter[cnt] = (unsigned char)p[j*dd + i];
+ PatFilter[p_len] = 0;
+
+ for (i = 0, cnt = 0; i < p_len; i++)
+ {
+ l = fuzzy->FilterMap[(unsigned char)PatFilter[i]];
+ if (!l)
+ {
+ l = fuzzy->FilterMap[(unsigned char)PatFilter[i]] = ++cnt;
+ fuzzy->FilterS[l] = 0;
+ }
+ fuzzy->FilterS[l] |= 1 << i;
+ }
+ fuzzy->filter_ok = 0;
+ for (i = p_len - fuzzy->k - 1; i <= p_len - 1; i++) /* k+1 times */
+ fuzzy->filter_ok |= 1 << i;
+
+ /* k+1 first bits set to 1 */
+ fuzzy->filter_shift = (1 << (fuzzy->k + 2)) - 1;
+ }
+ }
+}
+
+/******************************************************************************
+FUNCTION afuzzy_free()
+ Cleaning up after previous afuzzy_init() call.
+
+ARGUMENTS:
+ fuzzy pointer to the afuzzy parameters structure
+
+RETURN VALUE:
+ none
+******************************************************************************/
+void afuzzy_free(AFUZZY *fuzzy)
+{
+ if (fuzzy->S)
+ {
+ free(fuzzy->S);
+ fuzzy->S = NULL;
+ }
+ if (fuzzy->R)
+ {
+ free(fuzzy->R);
+ fuzzy->R = NULL;
+ }
+ if (fuzzy->R1)
+ {
+ free(fuzzy->R1);
+ fuzzy->R1 = NULL;
+ }
+ if (fuzzy->RP)
+ {
+ free(fuzzy->RP);
+ fuzzy->RP = NULL;
+ }
+ if (fuzzy->RI)
+ {
+ free(fuzzy->RI);
+ fuzzy->RI = NULL;
+ }
+ if (fuzzy->FilterS)
+ {
+ free(fuzzy->FilterS);
+ fuzzy->FilterS = NULL;
+ }
+}
+
+
+/******************************************************************************
+FUNCTION afuzzy_CheckSUB()
+ Perform a fuzzy pattern substring matching. afuzzy_init() should be
+ called previously to initialize the pattern and error length.
+ Positive result means that some part of the string given matches the
+ pattern with no more than afuzzy->k errors (1 error = 1 letter
+ replacement or transposition)
+
+ARGUMENTS:
+ t the string to test
+ fuzzy pointer to the afuzzy parameters structure
+
+RETURN VALUE:
+ 0 - no match
+ > 0 - strings match
+
+ALGORITHM
+ ????????????????
+******************************************************************************/
+int afuzzy_checkSUB(const char *t, AFUZZY *fuzzy)
+{
+ register char c;
+ register int j, d;
+
+ /* For eficciency this case should be little bit optimized */
+ if (!fuzzy->k)
+ {
+ Uint R = 0, R1;
+
+ for (j = 0; (c = t[j]) != '\0'; j++)
+ {
+ R1 = ( ((R<<1) | 1) & fuzzy->S[fuzzy->Map[(unsigned char)c]]);
+ R = R1;
+
+ if (R1 & fuzzy->mask_ok)
+ return 1;
+ } /* end for (register int j = 0 ... */
+ return 0;
+ }
+
+ if (fuzzy->FilterSet && !afuzzy_checkFLT(t, fuzzy))
+ return 0;
+
+ memcpy(fuzzy->R, fuzzy->RI, fuzzy->r_size); /* R = RI */
+
+ for (j = 0; (c = t[j]); j++)
+ {
+ for (d = 0; d <= fuzzy->k; d++)
+ {
+ fuzzy->R1[d] = (((fuzzy->R[d]<<1) | 1) &
+ fuzzy->S[fuzzy->Map[(unsigned char)c]]);
+ if (d > 0)
+ fuzzy->R1[d] |= ((fuzzy->R[d-1] | fuzzy->R1[d-1])<<1) | 1 |
+ fuzzy->R[d-1];
+ }
+ if (fuzzy->R1[fuzzy->k] & fuzzy->mask_ok)
+ return j;
+
+ memcpy(fuzzy->R, fuzzy->R1, fuzzy->r_size);
+
+ } /* end for (register int j = 0 ... */
+
+ return 0;
+}
+
+static int afuzzy_checkFLT(const char *t, AFUZZY *fuzzy)
+{
+ register Uint FilterR = 0;
+ register Uint FilterR1;
+ register int j;
+
+ for (j = 0; t[j] != '\0'; j++)
+ {
+ FilterR1 = ( ((FilterR<<(fuzzy->k+1)) | fuzzy->filter_shift) &
+ fuzzy->FilterS[fuzzy->FilterMap[(unsigned char)t[j]]]);
+ if (FilterR1 & fuzzy->filter_ok)
+ return 1;
+ FilterR = FilterR1;
+ } /* end for (register int j = 0 ... */
+
+ return 0;
+}
diff --git a/tvguide.c b/tvguide.c
index 806868b..f33c1e9 100644
--- a/tvguide.c
+++ b/tvguide.c
@@ -11,6 +11,7 @@
#include <vdr/osd.h>
#include <vdr/plugin.h>
#include <vdr/device.h>
+#include <vdr/menu.h>
#include "tvguideosd.c"
@@ -20,7 +21,7 @@
-static const char *VERSION = "0.0.5";
+static const char *VERSION = "0.0.6";
static const char *DESCRIPTION = "A fancy 2d EPG Viewer";
static const char *MAINMENUENTRY = "Tvguide";
@@ -28,6 +29,7 @@ class cPluginTvguide : public cPlugin {
private:
bool logoPathSet;
bool imagesPathSet;
+ bool iconsPathSet;
public:
cPluginTvguide(void);
virtual ~cPluginTvguide();
@@ -58,6 +60,7 @@ cPluginTvguide::cPluginTvguide(void)
// VDR OBJECTS TO EXIST OR PRODUCE ANY OUTPUT!
logoPathSet = false;
imagesPathSet = false;
+ iconsPathSet = false;
}
cPluginTvguide::~cPluginTvguide()
@@ -124,6 +127,13 @@ bool cPluginTvguide::Start(void)
tvguideConfig.SetImagesPath(path);
logoPathSet = true;
}
+
+ if (!iconsPathSet) {
+ cString path = cString::sprintf("%s/icons/", cPlugin::ConfigDirectory(PLUGIN_NAME_I18N));
+ tvguideConfig.SetIconsPath(path);
+ iconsPathSet = true;
+ }
+
return true;
}
diff --git a/tvguideosd.c b/tvguideosd.c
index 5aaa128..01fcbe6 100644
--- a/tvguideosd.c
+++ b/tvguideosd.c
@@ -37,6 +37,21 @@ THEME_CLR(theme, clrButtonYellowBorder, 0xFFBBBB00);
THEME_CLR(theme, clrButtonBlue, 0x990000BB);
THEME_CLR(theme, clrButtonBlueBorder, 0xFF0000BB);
THEME_CLR(theme, clrButtonBlend, 0xDD000000);
+THEME_CLR(theme, clrRecMenuBackground, 0xB0000000);
+THEME_CLR(theme, clrRecMenuTimerConflictBackground, 0xFFCCCCCC);
+THEME_CLR(theme, clrRecMenuTimerConflictBar, 0xFF222222);
+THEME_CLR(theme, clrRecMenuTimerConflictOverlap, 0xAAFF0000);
+THEME_CLR(theme, clrRecMenuDayActive, 0xFF00FF00);
+THEME_CLR(theme, clrRecMenuDayInactive, 0xFFFF0000);
+THEME_CLR(theme, clrRecMenuDayHighlight, 0x44FFFFFF);
+THEME_CLR(theme, clrRecMenuTextBack, 0xFF000000);
+THEME_CLR(theme, clrRecMenuTextActiveBack, 0xFF404749);
+THEME_CLR(theme, clrRecMenuKeyboardBack, 0xFF000000);
+THEME_CLR(theme, clrRecMenuKeyboardBorder, clrWhite);
+THEME_CLR(theme, clrRecMenuKeyboardHigh, 0x55FFFFFF);
+THEME_CLR(theme, clrButtonRedKeyboard, 0xFFBB0000);
+THEME_CLR(theme, clrButtonGreenKeyboard, 0xFF00BB00);
+THEME_CLR(theme, clrButtonYellowKeyboard, 0xFFBBBB00);
#include "config.c"
cTvguideConfig tvguideConfig;
@@ -44,11 +59,12 @@ cTvguideConfig tvguideConfig;
#include "osdmanager.c"
cOsdManager osdManager;
+#include "tools.c"
+#include "switchtimer.c"
#include "setup.c"
#include "imageloader.c"
#include "styledpixmap.c"
#include "timer.c"
-#include "messagebox.c"
#include "timeline.c"
#include "grid.c"
#include "headergrid.c"
@@ -60,6 +76,11 @@ cOsdManager osdManager;
#include "channelgroup.c"
#include "channelgroups.c"
#include "footer.c"
+#include "recmenuitem.c"
+#include "recmenu.c"
+#include "recmanager.c"
+#include "recmenus.c"
+#include "recmenumanager.c"
#include "tvguideosd.h"
#include <stdlib.h>
@@ -69,6 +90,7 @@ cTvGuideOsd::cTvGuideOsd(void) {
detailViewActive = false;
activeGrid = NULL;
timeLine = NULL;
+ recMenuManager = NULL;
}
cTvGuideOsd::~cTvGuideOsd() {
@@ -82,7 +104,7 @@ cTvGuideOsd::~cTvGuideOsd() {
delete timeLine;
delete channelGroups;
delete footer;
- cMessageBox::Destroy();
+ delete recMenuManager;
osdManager.deleteOsd();
}
@@ -97,6 +119,12 @@ void cTvGuideOsd::Show(void) {
osdManager.setBackground();
myTime = new cMyTime();
myTime->Now();
+ SwitchTimers.Load(AddDirectory(cPlugin::ConfigDirectory("epgsearch"), "epgsearchswitchtimers.conf"));
+ cSwitchTimer *st = NULL;
+ for (st = SwitchTimers.First(); st; st = SwitchTimers.Next(st)) {
+ esyslog("tvguide: switchtimer eventID %d time %ld", st->eventID, st->startTime);
+ }
+ recMenuManager = new cRecMenuManager();
drawOsd();
}
esyslog("tvguide: Rendering took %d ms", int(cTimeMs::Now()-start));
@@ -392,15 +420,10 @@ void cTvGuideOsd::processKeyUp() {
if (!activeGrid) {
return;
}
- if (detailViewActive) {
- detailView->scrollUp();
- osdManager.flush();
- } else {
- if (tvguideConfig.displayMode == eVertical) {
- timeBack();
- } else if (tvguideConfig.displayMode == eHorizontal) {
- channelBack();
- }
+ if (tvguideConfig.displayMode == eVertical) {
+ timeBack();
+ } else if (tvguideConfig.displayMode == eHorizontal) {
+ channelBack();
}
}
@@ -408,21 +431,14 @@ void cTvGuideOsd::processKeyDown() {
if (!activeGrid) {
return;
}
- if (detailViewActive) {
- detailView->scrollDown();
- osdManager.flush();
- } else {
- if (tvguideConfig.displayMode == eVertical) {
- timeForward();
- } else if (tvguideConfig.displayMode == eHorizontal) {
- channelForward();
- }
+ if (tvguideConfig.displayMode == eVertical) {
+ timeForward();
+ } else if (tvguideConfig.displayMode == eHorizontal) {
+ channelForward();
}
}
void cTvGuideOsd::processKeyLeft() {
- if (detailViewActive)
- return;
if (activeGrid == NULL)
return;
if (tvguideConfig.displayMode == eVertical) {
@@ -433,8 +449,6 @@ void cTvGuideOsd::processKeyLeft() {
}
void cTvGuideOsd::processKeyRight() {
- if (detailViewActive)
- return;
if (activeGrid == NULL)
return;
if (tvguideConfig.displayMode == eVertical) {
@@ -447,26 +461,7 @@ void cTvGuideOsd::processKeyRight() {
void cTvGuideOsd::processKeyRed() {
if ((activeGrid == NULL) || activeGrid->isDummy())
return;
- cTimer *timer = new cTimer(activeGrid->GetEvent());
- cTimer *t = Timers.GetTimer(timer);
- cString msg;
- if (t) {
- isyslog("timer %s already exists", *timer->ToDescr());
- delete timer;
- msg = cString::sprintf(tr("Timer not set! There is already a timer for this item."));
- } else {
- Timers.Add(timer);
- Timers.SetModified();
- msg = cString::sprintf("%s:\n%s (%s) %s - %s", tr("Timer set"), activeGrid->GetEvent()->Title(), timer->Channel()->Name(), *DayDateTime(timer->StartTime()), *TimeString(timer->StopTime()));
- timer->SetEvent(activeGrid->GetEvent());
- activeGrid->setTimer();
- activeGrid->column->setTimer();
- activeGrid->SetDirty();
- activeGrid->Draw();
- osdManager.flush();
- isyslog("timer %s added (active)", *timer->ToDescr());
- }
- cMessageBox::Start(4000, msg);
+ recMenuManager->Start(activeGrid->GetEvent());
}
void cTvGuideOsd::processKeyGreen() {
@@ -547,7 +542,7 @@ eOSState cTvGuideOsd::processKeyBlue() {
}
eOSState cTvGuideOsd::processKeyOk() {
- if ((tvguideConfig.blueKeyMode == 0) || detailViewActive ) {
+ if (tvguideConfig.blueKeyMode == 0) {
DetailedEPG();
} else if (tvguideConfig.blueKeyMode == 1) {
return ChannelSwitch();
@@ -567,17 +562,13 @@ eOSState cTvGuideOsd::ChannelSwitch() {
}
void cTvGuideOsd::DetailedEPG() {
- if (detailViewActive) {
- delete detailView;
- detailView = NULL;
- detailViewActive = false;
+ if (!activeGrid->isDummy()) {
+ detailViewActive = true;
+ detailView = new cDetailView(activeGrid->GetEvent());
+ detailView->drawHeader();
+ detailView->drawContent();
+ detailView->drawScrollbar();
osdManager.flush();
- } else {
- if (!activeGrid->isDummy()) {
- detailViewActive = true;
- detailView = new cDetailView(activeGrid);
- detailView->Start();
- }
}
}
@@ -646,11 +637,32 @@ void cTvGuideOsd::processKey9() {
osdManager.flush();
}
+void cTvGuideOsd::SetTimers() {
+ for (cChannelColumn *column = columns.First(); column; column = columns.Next(column)) {
+ column->SetTimers();
+ }
+}
+
eOSState cTvGuideOsd::ProcessKey(eKeys Key) {
- eOSState state = cOsdObject::ProcessKey(Key);
- if (state == osUnknown) {
- cPixmap::Lock();
+ eOSState state = osContinue;
+ cPixmap::Lock();
+ if (recMenuManager->isActive()) {
+ state = recMenuManager->ProcessKey(Key);
+ if (state == osEnd) {
+ SetTimers();
+ osdManager.flush();
+ }
state = osContinue;
+ } else if (detailViewActive) {
+ state = detailView->ProcessKey(Key);
+ if (state == osEnd) {
+ delete detailView;
+ detailView = NULL;
+ detailViewActive = false;
+ osdManager.flush();
+ state = osContinue;
+ }
+ } else {
switch (Key & ~k_Repeat) {
case kUp: processKeyUp(); break;
case kDown: processKeyDown(); break;
@@ -661,7 +673,7 @@ eOSState cTvGuideOsd::ProcessKey(eKeys Key) {
case kYellow: processKeyYellow(); break;
case kBlue: state = processKeyBlue(); break;
case kOk: state = processKeyOk(); break;
- case kBack: state=osEnd; break;
+ case kBack: state=osEnd; break;
case k1: processKey1(); break;
case k3: processKey3(); break;
case k4: processKey4(); break;
@@ -670,8 +682,8 @@ eOSState cTvGuideOsd::ProcessKey(eKeys Key) {
case k9: processKey9(); break;
default: break;
}
- cPixmap::Unlock();
}
+ cPixmap::Unlock();
return state;
}
diff --git a/tvguideosd.h b/tvguideosd.h
index bc46728..717ce10 100644
--- a/tvguideosd.h
+++ b/tvguideosd.h
@@ -13,6 +13,7 @@ private:
cTimeLine *timeLine;
cChannelGroups *channelGroups;
cFooter *footer;
+ cRecMenuManager *recMenuManager;
bool detailViewActive;
void drawOsd();
void readChannels(const cChannel *channelStart);
@@ -42,6 +43,7 @@ private:
void ScrollBack();
eOSState ChannelSwitch();
void DetailedEPG();
+ void SetTimers();
void dump();
public:
cTvGuideOsd(void);